Commit ed5c3b39 authored by Max Kanat-Alexander's avatar Max Kanat-Alexander

Bug 457373: Refactor the permissions system in Bugzilla::Install::Filesystem

to use constants instead of local variables. Also, change the permissions so that they are stricter in general, and work better under suexec. This also fixes the problem that dependency graphs didn't work under suexec, and adds a "web" directory by default to Extensions created with extension/create.pl. r=mkanat, a=mkanat (module owner)
parent 92adf6a5
...@@ -649,6 +649,17 @@ case your templates should probably be in a directory like ...@@ -649,6 +649,17 @@ case your templates should probably be in a directory like
F<extensions/Foo/template/en/default/page/foo/> so as not to conflict with F<extensions/Foo/template/en/default/page/foo/> so as not to conflict with
other pages that other extensions might add. other pages that other extensions might add.
=head2 CSS, JavaScript, and Images
If you include CSS, JavaScript, and images in your extension that are
served directly to the user (that is, they're not read by a script and
then printed--they're just linked directly in your HTML), they should go
into the F<web/> subdirectory of your extension.
So, for example, if you had a CSS file called F<style.css> and your
extension was called F<Foo>, your file would go into
F<extensions/Foo/web/style.css>.
=head2 Disabling Your Extension =head2 Disabling Your Extension
If you want your extension to be totally ignored by Bugzilla (it will If you want your extension to be totally ignored by Bugzilla (it will
......
...@@ -54,6 +54,53 @@ use constant HT_DEFAULT_DENY => <<EOT; ...@@ -54,6 +54,53 @@ use constant HT_DEFAULT_DENY => <<EOT;
deny from all deny from all
EOT EOT
###############
# Permissions #
###############
# Used by the permissions "constants" below.
sub _suexec { Bugzilla->localconfig->{'use_suexec'} };
sub _group { Bugzilla->localconfig->{'webservergroup'} };
# Writeable by the owner only.
use constant OWNER_WRITE => 0600;
# Executable by the owner only.
use constant OWNER_EXECUTE => 0700;
# A directory which is only writeable by the owner.
use constant DIR_OWNER_WRITE => 0700;
# A cgi script that the webserver can execute.
sub WS_EXECUTE { _group() ? 0750 : 0755 };
# A file that is read by cgi scripts, but is not ever read
# directly by the webserver.
sub CGI_READ { _group() ? 0640 : 0644 };
# A file that is written to by cgi scripts, but is not ever
# read or written directly by the webserver.
sub CGI_WRITE { _group() ? 0660 : 0666 };
# A file that is served directly by the web server.
sub WS_SERVE { (_group() and !_suexec()) ? 0640 : 0644 };
# A directory whose contents can be read or served by the
# webserver (so even directories containing cgi scripts
# would have this permission).
sub DIR_WS_SERVE { (_group() and !_suexec()) ? 0750 : 0755 };
# A directory that is read by cgi scripts, but is never accessed
# directly by the webserver
sub DIR_CGI_READ { _group() ? 0750 : 0755 };
# A directory that is written to by cgi scripts, but where the
# scripts never needs to overwrite files created by other
# users.
sub DIR_CGI_WRITE { _group() ? 0770 : 01777 };
# A directory that is written to by cgi scripts, where the
# scripts need to overwrite files created by other users.
sub DIR_CGI_OVERWRITE { _group() ? 0770 : 0777 };
# This can be combined (using "|") with other permissions for
# directories that, in addition to their normal permissions (such
# as DIR_CGI_WRITE) also have content served directly from them
# (or their subdirectories) to the user, via the webserver.
sub DIR_ALSO_WS_SERVE { _suexec() ? 0001 : 0 };
# This looks like a constant because it effectively is, but # This looks like a constant because it effectively is, but
# it has to call other subroutines and read the current filesystem, # it has to call other subroutines and read the current filesystem,
# so it's defined as a sub. This is not exported, so it doesn't have # so it's defined as a sub. This is not exported, so it doesn't have
...@@ -82,37 +129,6 @@ sub FILESYSTEM { ...@@ -82,37 +129,6 @@ sub FILESYSTEM {
$localconfig =~ s/\.\Q$ENV{PROJECT}\E$//; $localconfig =~ s/\.\Q$ENV{PROJECT}\E$//;
} }
my $ws_group = Bugzilla->localconfig->{'webservergroup'};
my $use_suexec = Bugzilla->localconfig->{'use_suexec'};
# The set of permissions that we use:
# FILES
# Executable by the web server
my $ws_executable = $ws_group ? 0750 : 0755;
# Executable by the owner only.
my $owner_executable = 0700;
# Readable by the web server.
my $ws_readable = ($ws_group && !$use_suexec) ? 0640 : 0644;
# Readable by the owner only.
my $owner_readable = 0600;
# Writeable by the web server.
my $ws_writeable = $ws_group ? 0660 : 0666;
# Script-readable files that should not be world-readable under suexec.
my $script_readable = $use_suexec ? 0640 : $ws_readable;
# DIRECTORIES
# Readable by the web server.
my $ws_dir_readable = ($ws_group && !$use_suexec) ? 0750 : 0755;
# Readable only by the owner.
my $owner_dir_readable = 0700;
# Writeable by the web server.
my $ws_dir_writeable = $ws_group ? 0770 : 01777;
# The web server can overwrite files owned by other users,
# in this directory.
my $ws_dir_full_control = $ws_group ? 0770 : 0777;
# Note: When being processed by checksetup, these have their permissions # Note: When being processed by checksetup, these have their permissions
# set in this order: %all_dirs, %recurse_dirs, %all_files. # set in this order: %all_dirs, %recurse_dirs, %all_files.
# #
...@@ -123,45 +139,48 @@ sub FILESYSTEM { ...@@ -123,45 +139,48 @@ sub FILESYSTEM {
# --- FILE PERMISSIONS (Non-created files) --- # # --- FILE PERMISSIONS (Non-created files) --- #
my %files = ( my %files = (
'*' => { perms => $ws_readable }, '*' => { perms => OWNER_WRITE },
'*.cgi' => { perms => $ws_executable }, # Some .pl files are WS_EXECUTE because we want
'whineatnews.pl' => { perms => $ws_executable }, # users to be able to cron them or otherwise run
'collectstats.pl' => { perms => $ws_executable }, # them as a secure user, like the webserver owner.
'checksetup.pl' => { perms => $owner_executable }, '*.cgi' => { perms => WS_EXECUTE },
'importxml.pl' => { perms => $ws_executable }, 'whineatnews.pl' => { perms => WS_EXECUTE },
'runtests.pl' => { perms => $owner_executable }, 'collectstats.pl' => { perms => WS_EXECUTE },
'testserver.pl' => { perms => $ws_executable }, 'importxml.pl' => { perms => WS_EXECUTE },
'whine.pl' => { perms => $ws_executable }, 'testserver.pl' => { perms => WS_EXECUTE },
'customfield.pl' => { perms => $owner_executable }, 'whine.pl' => { perms => WS_EXECUTE },
'email_in.pl' => { perms => $ws_executable }, 'email_in.pl' => { perms => WS_EXECUTE },
'sanitycheck.pl' => { perms => $ws_executable }, 'sanitycheck.pl' => { perms => WS_EXECUTE },
'jobqueue.pl' => { perms => $owner_executable }, 'checksetup.pl' => { perms => OWNER_EXECUTE },
'migrate.pl' => { perms => $owner_executable }, 'runtests.pl' => { perms => OWNER_EXECUTE },
'install-module.pl' => { perms => $owner_executable }, 'jobqueue.pl' => { perms => OWNER_EXECUTE },
'migrate.pl' => { perms => OWNER_EXECUTE },
# Set the permissions for localconfig the same across all 'install-module.pl' => { perms => OWNER_EXECUTE },
# PROJECTs.
$localconfig => { perms => $script_readable }, 'Bugzilla.pm' => { perms => CGI_READ },
"$localconfig.*" => { perms => $script_readable }, "$localconfig*" => { perms => CGI_READ },
"$localconfig.old" => { perms => $owner_readable }, 'bugzilla.dtd' => { perms => WS_SERVE },
'mod_perl.pl' => { perms => WS_SERVE },
'contrib/README' => { perms => $owner_readable }, 'robots.txt' => { perms => WS_SERVE },
'contrib/*/README' => { perms => $owner_readable },
'docs/makedocs.pl' => { perms => $owner_executable }, 'contrib/README' => { perms => OWNER_WRITE },
'docs/style.css' => { perms => $ws_readable }, 'contrib/*/README' => { perms => OWNER_WRITE },
'docs/*/rel_notes.txt' => { perms => $ws_readable }, 'docs/bugzilla.ent' => { perms => OWNER_WRITE },
'docs/*/README.docs' => { perms => $owner_readable }, 'docs/makedocs.pl' => { perms => OWNER_EXECUTE },
"$datadir/params" => { perms => $ws_writeable }, 'docs/style.css' => { perms => WS_SERVE },
"$datadir/old-params.txt" => { perms => $owner_readable }, 'docs/*/rel_notes.txt' => { perms => WS_SERVE },
"$extensionsdir/create.pl" => { perms => $owner_executable }, 'docs/*/README.docs' => { perms => OWNER_WRITE },
"$datadir/params" => { perms => CGI_WRITE },
"$datadir/old-params.txt" => { perms => OWNER_WRITE },
"$extensionsdir/create.pl" => { perms => OWNER_EXECUTE },
); );
# Directories that we want to set the perms on, but not # Directories that we want to set the perms on, but not
# recurse through. These are directories we didn't create # recurse through. These are directories we didn't create
# in checkesetup.pl. # in checkesetup.pl.
my %non_recurse_dirs = ( my %non_recurse_dirs = (
'.' => $ws_dir_readable, '.' => DIR_WS_SERVE,
docs => $ws_dir_readable, docs => DIR_WS_SERVE,
); );
# This sets the permissions for each item inside each of these # This sets the permissions for each item inside each of these
...@@ -170,50 +189,64 @@ sub FILESYSTEM { ...@@ -170,50 +189,64 @@ sub FILESYSTEM {
# the webserver. # the webserver.
my %recurse_dirs = ( my %recurse_dirs = (
# Writeable directories # Writeable directories
"$datadir/template" => { files => $ws_readable, "$datadir/template" => { files => CGI_READ,
dirs => $ws_dir_full_control }, dirs => DIR_CGI_OVERWRITE },
$attachdir => { files => $ws_writeable, $attachdir => { files => CGI_WRITE,
dirs => $ws_dir_writeable }, dirs => DIR_CGI_WRITE },
$webdotdir => { files => $ws_writeable, $webdotdir => { files => WS_SERVE,
dirs => $ws_dir_writeable }, dirs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE },
graphs => { files => $ws_writeable, graphs => { files => WS_SERVE,
dirs => $ws_dir_writeable }, dirs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE },
# Readable directories # Readable directories
"$datadir/mining" => { files => $ws_readable, "$datadir/mining" => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
"$libdir/Bugzilla" => { files => $ws_readable, "$libdir/Bugzilla" => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
$extlib => { files => $ws_readable, $extlib => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
$templatedir => { files => $ws_readable, $templatedir => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
$extensionsdir => { files => $ws_readable, # Directories in the extensions/ dir are WS_SERVE so that
dirs => $ws_dir_readable }, # the web/ directories can be served by the web server.
images => { files => $ws_readable, # But, for extra security, we deny direct webserver access to
dirs => $ws_dir_readable }, # the lib/ and template/ directories of extensions.
css => { files => $ws_readable, $extensionsdir => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_WS_SERVE },
js => { files => $ws_readable, "$extensionsdir/*/lib" => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
$skinsdir => { files => $ws_readable, "$extensionsdir/*/template" => { files => CGI_READ,
dirs => $ws_dir_readable }, dirs => DIR_CGI_READ },
t => { files => $owner_readable,
dirs => $owner_dir_readable }, # Content served directly by the webserver
'docs/*/html' => { files => $ws_readable, images => { files => WS_SERVE,
dirs => $ws_dir_readable }, dirs => DIR_WS_SERVE },
'docs/*/pdf' => { files => $ws_readable, js => { files => WS_SERVE,
dirs => $ws_dir_readable }, dirs => DIR_WS_SERVE },
'docs/*/txt' => { files => $ws_readable, $skinsdir => { files => WS_SERVE,
dirs => $ws_dir_readable }, dirs => DIR_WS_SERVE },
'docs/*/images' => { files => $ws_readable, 'docs/*/html' => { files => WS_SERVE,
dirs => $ws_dir_readable }, dirs => DIR_WS_SERVE },
'docs/lib' => { files => $owner_readable, 'docs/*/pdf' => { files => WS_SERVE,
dirs => $owner_dir_readable }, dirs => DIR_WS_SERVE },
'docs/*/xml' => { files => $owner_readable, 'docs/*/txt' => { files => WS_SERVE,
dirs => $owner_dir_readable }, dirs => DIR_WS_SERVE },
'contrib' => { files => $owner_executable, 'docs/*/images' => { files => WS_SERVE,
dirs => $owner_dir_readable, }, dirs => DIR_WS_SERVE },
"$extensionsdir/*/web" => { files => WS_SERVE,
dirs => DIR_WS_SERVE },
# Directories only for the owner, not for the webserver.
'.bzr' => { files => OWNER_WRITE,
dirs => DIR_OWNER_WRITE },
t => { files => OWNER_WRITE,
dirs => DIR_OWNER_WRITE },
'docs/lib' => { files => OWNER_WRITE,
dirs => DIR_OWNER_WRITE },
'docs/*/xml' => { files => OWNER_WRITE,
dirs => DIR_OWNER_WRITE },
'contrib' => { files => OWNER_EXECUTE,
dirs => DIR_OWNER_WRITE, },
); );
# --- FILES TO CREATE --- # # --- FILES TO CREATE --- #
...@@ -221,27 +254,31 @@ sub FILESYSTEM { ...@@ -221,27 +254,31 @@ sub FILESYSTEM {
# The name of each directory that we should actually *create*, # The name of each directory that we should actually *create*,
# pointing at its default permissions. # pointing at its default permissions.
my %create_dirs = ( my %create_dirs = (
$datadir => $ws_dir_full_control, # This is DIR_ALSO_WS_SERVE because it contains $webdotdir.
"$datadir/mining" => $ws_dir_readable, $datadir => DIR_CGI_OVERWRITE | DIR_ALSO_WS_SERVE,
"$datadir/extensions" => $ws_dir_readable, # Directories that are read-only for cgi scripts
$attachdir => $ws_dir_writeable, "$datadir/mining" => DIR_CGI_READ,
$extensionsdir => $ws_dir_readable, "$datadir/extensions" => DIR_CGI_READ,
graphs => $ws_dir_writeable, $extensionsdir => DIR_CGI_READ,
$webdotdir => $ws_dir_writeable, # Directories that cgi scripts can write to.
"$skinsdir/custom" => $ws_dir_readable, $attachdir => DIR_CGI_WRITE,
"$skinsdir/contrib" => $ws_dir_readable, graphs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE,
$webdotdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE,
# Directories that contain content served directly by the web server.
"$skinsdir/custom" => DIR_WS_SERVE,
"$skinsdir/contrib" => DIR_WS_SERVE,
); );
# The name of each file, pointing at its default permissions and # The name of each file, pointing at its default permissions and
# default contents. # default contents.
my %create_files = ( my %create_files = (
"$datadir/extensions/additional" => { perms => $ws_readable, "$datadir/extensions/additional" => { perms => CGI_READ,
contents => '' }, contents => '' },
# We create this file so that it always has the right owner # We create this file so that it always has the right owner
# and permissions. Otherwise, the webserver creates it as # and permissions. Otherwise, the webserver creates it as
# owned by itself, which can cause problems if jobqueue.pl # owned by itself, which can cause problems if jobqueue.pl
# or something else is not running as the webserver or root. # or something else is not running as the webserver or root.
"$datadir/mailer.testfile" => { perms => $ws_writeable, "$datadir/mailer.testfile" => { perms => CGI_WRITE,
contents => '' }, contents => '' },
); );
...@@ -251,18 +288,18 @@ sub FILESYSTEM { ...@@ -251,18 +288,18 @@ sub FILESYSTEM {
foreach my $skin_dir ("$skinsdir/custom", <$skinsdir/contrib/*>) { foreach my $skin_dir ("$skinsdir/custom", <$skinsdir/contrib/*>) {
next if basename($skin_dir) =~ /^cvs$/i; next if basename($skin_dir) =~ /^cvs$/i;
foreach my $base_css (<$skinsdir/standard/*.css>) { foreach my $base_css (<$skinsdir/standard/*.css>) {
_add_custom_css($skin_dir, basename($base_css), \%create_files, $ws_readable); _add_custom_css($skin_dir, basename($base_css), \%create_files);
} }
foreach my $dir_css (<$skinsdir/standard/*/*.css>) { foreach my $dir_css (<$skinsdir/standard/*/*.css>) {
$dir_css =~ s{.+?([^/]+/[^/]+)$}{$1}; $dir_css =~ s{.+?([^/]+/[^/]+)$}{$1};
_add_custom_css($skin_dir, $dir_css, \%create_files, $ws_readable); _add_custom_css($skin_dir, $dir_css, \%create_files);
} }
} }
# Because checksetup controls the creation of index.html separately # Because checksetup controls the creation of index.html separately
# from all other files, it gets its very own hash. # from all other files, it gets its very own hash.
my %index_html = ( my %index_html = (
'index.html' => { perms => $ws_readable, contents => <<EOT 'index.html' => { perms => WS_SERVE, contents => <<EOT
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <html>
<head> <head>
...@@ -279,23 +316,27 @@ EOT ...@@ -279,23 +316,27 @@ EOT
# Because checksetup controls the .htaccess creation separately # Because checksetup controls the .htaccess creation separately
# by a localconfig variable, these go in a separate variable from # by a localconfig variable, these go in a separate variable from
# %create_files. # %create_files.
#
# Note that these get WS_SERVE as their permission
# because they're *read* by the webserver, even though they're not
# actually, themselves, served.
my %htaccess = ( my %htaccess = (
"$attachdir/.htaccess" => { perms => $ws_readable, "$attachdir/.htaccess" => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
"$libdir/Bugzilla/.htaccess" => { perms => $ws_readable, "$libdir/Bugzilla/.htaccess" => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
"$extlib/.htaccess" => { perms => $ws_readable, "$extlib/.htaccess" => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
"$templatedir/.htaccess" => { perms => $ws_readable, "$templatedir/.htaccess" => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
'contrib/.htaccess' => { perms => $ws_readable, 'contrib/.htaccess' => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
't/.htaccess' => { perms => $ws_readable, 't/.htaccess' => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
"$datadir/.htaccess" => { perms => $ws_readable, "$datadir/.htaccess" => { perms => WS_SERVE,
contents => HT_DEFAULT_DENY }, contents => HT_DEFAULT_DENY },
"$webdotdir/.htaccess" => { perms => $ws_readable, contents => <<EOT "$webdotdir/.htaccess" => { perms => WS_SERVE, contents => <<EOT
# Restrict access to .dot files to the public webdot server at research.att.com # Restrict access to .dot files to the public webdot server at research.att.com
# if research.att.com ever changes their IP, or if you use a different # if research.att.com ever changes their IP, or if you use a different
# webdot server, you'll need to edit this # webdot server, you'll need to edit this
...@@ -414,8 +455,8 @@ EOT ...@@ -414,8 +455,8 @@ EOT
# A simple helper for creating "empty" CSS files. # A simple helper for creating "empty" CSS files.
sub _add_custom_css { sub _add_custom_css {
my ($skin_dir, $path, $create_files, $perms) = @_; my ($skin_dir, $path, $create_files) = @_;
$create_files->{"$skin_dir/$path"} = { perms => $perms, contents => <<EOT $create_files->{"$skin_dir/$path"} = { perms => WS_SERVE, contents => <<EOT
/* /*
* Custom rules for $path. * Custom rules for $path.
* The rules you put here override rules in that stylesheet. * The rules you put here override rules in that stylesheet.
......
...@@ -41,7 +41,7 @@ mkpath($extension_dir) ...@@ -41,7 +41,7 @@ mkpath($extension_dir)
|| die "$extension_dir already exists or cannot be created.\n"; || die "$extension_dir already exists or cannot be created.\n";
my $lcname = lc($name); my $lcname = lc($name);
foreach my $path (qw(lib template/en/default/hook), foreach my $path (qw(lib web template/en/default/hook),
"template/en/default/$lcname") "template/en/default/$lcname")
{ {
mkpath("$extension_dir/$path") || die "$extension_dir/$path: $!"; mkpath("$extension_dir/$path") || die "$extension_dir/$path: $!";
...@@ -55,6 +55,7 @@ my %create_files = ( ...@@ -55,6 +55,7 @@ my %create_files = (
'config.pm.tmpl' => 'Config.pm', 'config.pm.tmpl' => 'Config.pm',
'extension.pm.tmpl' => 'Extension.pm', 'extension.pm.tmpl' => 'Extension.pm',
'util.pm.tmpl' => 'lib/Util.pm', 'util.pm.tmpl' => 'lib/Util.pm',
'web-readme.txt.tmpl' => 'web/README',
'hook-readme.txt.tmpl' => 'template/en/default/hook/README', 'hook-readme.txt.tmpl' => 'template/en/default/hook/README',
'name-readme.txt.tmpl' => "template/en/default/$lcname/README", 'name-readme.txt.tmpl' => "template/en/default/$lcname/README",
); );
......
...@@ -29,6 +29,7 @@ use File::Temp; ...@@ -29,6 +29,7 @@ use File::Temp;
use Bugzilla; use Bugzilla;
use Bugzilla::Constants; use Bugzilla::Constants;
use Bugzilla::Install::Filesystem;
use Bugzilla::Util; use Bugzilla::Util;
use Bugzilla::Error; use Bugzilla::Error;
use Bugzilla::Bug; use Bugzilla::Bug;
...@@ -114,7 +115,13 @@ if (!defined $cgi->param('id') && $display ne 'doall') { ...@@ -114,7 +115,13 @@ if (!defined $cgi->param('id') && $display ne 'doall') {
my ($fh, $filename) = File::Temp::tempfile("XXXXXXXXXX", my ($fh, $filename) = File::Temp::tempfile("XXXXXXXXXX",
SUFFIX => '.dot', SUFFIX => '.dot',
DIR => $webdotdir); DIR => $webdotdir,
UNLINK => 1);
chmod Bugzilla::Install::Filesystem::CGI_WRITE, $filename
or warn install_string('chmod_failed', { path => $filename,
error => $! });
my $urlbase = Bugzilla->params->{'urlbase'}; my $urlbase = Bugzilla->params->{'urlbase'};
print $fh "digraph G {"; print $fh "digraph G {";
...@@ -244,8 +251,6 @@ foreach my $k (keys(%seen)) { ...@@ -244,8 +251,6 @@ foreach my $k (keys(%seen)) {
print $fh "}\n"; print $fh "}\n";
close $fh; close $fh;
chmod 0777, $filename;
my $webdotbase = Bugzilla->params->{'webdotbase'}; my $webdotbase = Bugzilla->params->{'webdotbase'};
if ($webdotbase =~ /^https?:/) { if ($webdotbase =~ /^https?:/) {
...@@ -263,6 +268,11 @@ if ($webdotbase =~ /^https?:/) { ...@@ -263,6 +268,11 @@ if ($webdotbase =~ /^https?:/) {
my ($pngfh, $pngfilename) = File::Temp::tempfile("XXXXXXXXXX", my ($pngfh, $pngfilename) = File::Temp::tempfile("XXXXXXXXXX",
SUFFIX => '.png', SUFFIX => '.png',
DIR => $webdotdir); DIR => $webdotdir);
chmod Bugzilla::Install::Filesystem::WS_SERVE, $pngfilename
or warn install_string('chmod_failed', { path => $pngfilename,
error => $! });
binmode $pngfh; binmode $pngfh;
open(DOT, "\"$webdotbase\" -Tpng $filename|"); open(DOT, "\"$webdotbase\" -Tpng $filename|");
binmode DOT; binmode DOT;
...@@ -287,12 +297,18 @@ if ($webdotbase =~ /^https?:/) { ...@@ -287,12 +297,18 @@ if ($webdotbase =~ /^https?:/) {
my ($mapfh, $mapfilename) = File::Temp::tempfile("XXXXXXXXXX", my ($mapfh, $mapfilename) = File::Temp::tempfile("XXXXXXXXXX",
SUFFIX => '.map', SUFFIX => '.map',
DIR => $webdotdir); DIR => $webdotdir);
chmod Bugzilla::Install::Filesystem::WS_SERVE, $mapfilename
or warn install_string('chmod_failed', { path => $mapfilename,
error => $! });
binmode $mapfh; binmode $mapfh;
open(DOT, "\"$webdotbase\" -Tismap $filename|"); open(DOT, "\"$webdotbase\" -Tismap $filename|");
binmode DOT; binmode DOT;
print $mapfh $_ while <DOT>; print $mapfh $_ while <DOT>;
close DOT; close DOT;
close $mapfh; close $mapfh;
$vars->{'image_map'} = CreateImagemap($mapfilename); $vars->{'image_map'} = CreateImagemap($mapfilename);
} }
......
[%# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Everything Solved, Inc.
# Portions created by the Initial Developer are Copyright (C) 2010 the
# Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Max Kanat-Alexander <mkanat@bugzilla.org>
#%]
[% PROCESS global/variables.none.tmpl %]
Web-accessible files, like JavaScript, CSS, and images go in this
directory. You can reference them directly in your HTML. For example,
if you have a file called "style.css" and your extension is called
"Foo", you would put it in "extensions/Foo/web/style.css", and then
you could link to it in HTML like:
<link href="extensions/Foo/web/style.css" rel="stylesheet" type="text/css">
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment