diff options
Diffstat (limited to 'Bugzilla/Config.pm')
-rw-r--r-- | Bugzilla/Config.pm | 148 |
1 files changed, 93 insertions, 55 deletions
diff --git a/Bugzilla/Config.pm b/Bugzilla/Config.pm index 150996e05..1e22b5239 100644 --- a/Bugzilla/Config.pm +++ b/Bugzilla/Config.pm @@ -7,14 +7,21 @@ package Bugzilla::Config; +use 5.10.1; use strict; +use warnings; + +use parent qw(Exporter); +use autodie qw(:default); -use base qw(Exporter); use Bugzilla::Constants; use Bugzilla::Hook; -use Bugzilla::Install::Filesystem qw(fix_file_permissions); -use Data::Dumper; +use Bugzilla::Util qw(trick_taint); + +use JSON::XS; +use File::Slurp; use File::Temp; +use File::Basename; # Don't export localvars by default - people should have to explicitly # ask for it, as a (probably futile) attempt to stop code using it @@ -91,8 +98,35 @@ sub SetParam { sub update_params { my ($params) = @_; my $answer = Bugzilla->installation_answers; + my $datadir = bz_locations()->{'datadir'}; + my $param; + + # If the old data/params file using Data::Dumper output still exists, + # read it. It will be deleted once the parameters are stored in the new + # data/params.json file. + my $old_file = "$datadir/params"; + + if (-e $old_file) { + require Safe; + my $s = new Safe; + + $s->rdo($old_file); + die "Error reading $old_file: $!" if $!; + die "Error evaluating $old_file: $@" if $@; + + # Now read the param back out from the sandbox. + $param = \%{ $s->varglob('param') }; + } + else { + # Rename params.js to params.json if checksetup.pl + # was executed with an earlier version of this change + rename "$old_file.js", "$old_file.json" + if -e "$old_file.js" && !-e "$old_file.json"; + + # Read the new data/params.json file. + $param = read_param_file(); + } - my $param = read_param_file(); my %new_params; # If we didn't return any param values, then this is a new installation. @@ -151,16 +185,19 @@ sub update_params { } # Old mail_delivery_method choices contained no uppercase characters - if (exists $param->{'mail_delivery_method'} - && $param->{'mail_delivery_method'} !~ /[A-Z]/) { - my $method = $param->{'mail_delivery_method'}; - my %translation = ( - 'sendmail' => 'Sendmail', - 'smtp' => 'SMTP', - 'qmail' => 'Qmail', - 'testfile' => 'Test', - 'none' => 'None'); - $param->{'mail_delivery_method'} = $translation{$method}; + my $mta = $param->{'mail_delivery_method'}; + if ($mta) { + if ($mta !~ /[A-Z]/) { + my %translation = ( + 'sendmail' => 'Sendmail', + 'smtp' => 'SMTP', + 'qmail' => 'Qmail', + 'testfile' => 'Test', + 'none' => 'None'); + $param->{'mail_delivery_method'} = $translation{$mta}; + } + # This will force the parameter to be reset to its default value. + delete $param->{'mail_delivery_method'} if $param->{'mail_delivery_method'} eq 'Qmail'; } # Convert the old "ssl" parameter to the new "ssl_redirect" parameter. @@ -196,6 +233,9 @@ sub update_params { $param->{'utf8'} = 1 if $new_install; + # Bug 452525: OR based groups are on by default for new installations + $param->{'or_groups'} = 1 if $new_install; + # --- REMOVE OLD PARAMS --- my %oldparams; @@ -207,7 +247,6 @@ sub update_params { } # Write any old parameters to old-params.txt - my $datadir = bz_locations()->{'datadir'}; my $old_param_file = "$datadir/old-params.txt"; if (scalar(keys %oldparams)) { my $op_file = new IO::File($old_param_file, '>>', 0600) @@ -217,12 +256,9 @@ sub update_params { " and so have been\nmoved from your parameters file into", " $old_param_file:\n"; - local $Data::Dumper::Terse = 1; - local $Data::Dumper::Indent = 0; - my $comma = ""; foreach my $item (keys %oldparams) { - print $op_file "\n\n$item:\n" . Data::Dumper->Dump([$oldparams{$item}]) . "\n"; + print $op_file "\n\n$item:\n" . $oldparams{$item} . "\n"; print "${comma}$item"; $comma = ", "; } @@ -253,6 +289,11 @@ sub update_params { write_params($param); + if (-e $old_file) { + unlink $old_file; + say "$old_file has been converted into $old_file.json, using the JSON format."; + } + # Return deleted params and values so that checksetup.pl has a chance # to convert old params to new data. return %oldparams; @@ -261,24 +302,15 @@ sub update_params { sub write_params { my ($param_data) = @_; $param_data ||= Bugzilla->params; + my $param_file = bz_locations()->{'datadir'} . '/params.json'; - my $datadir = bz_locations()->{'datadir'}; - my $param_file = "$datadir/params"; - - local $Data::Dumper::Sortkeys = 1; - - my ($fh, $tmpname) = File::Temp::tempfile('params.XXXXX', - DIR => $datadir ); - - print $fh (Data::Dumper->Dump([$param_data], ['*param'])) - || die "Can't write param file: $!"; + my $json_data = JSON::XS->new->canonical->pretty->encode($param_data); + write_file($param_file, { binmode => ':utf8', atomic => 1 }, \$json_data); - close $fh; - - rename $tmpname, $param_file - or die "Can't rename $tmpname to $param_file: $!"; - - fix_file_permissions($param_file); + # It's not common to edit parameters and loading + # Bugzilla::Install::Filesystem is slow. + require Bugzilla::Install::Filesystem; + Bugzilla::Install::Filesystem::fix_file_permissions($param_file); # And now we have to reset the params cache so that Bugzilla will re-read # them. @@ -287,21 +319,25 @@ sub write_params { sub read_param_file { my %params; - my $datadir = bz_locations()->{'datadir'}; - if (-e "$datadir/params") { - # Note that checksetup.pl sets file permissions on '$datadir/params' - - # Using Safe mode is _not_ a guarantee of safety if someone does - # manage to write to the file. However, it won't hurt... - # See bug 165144 for not needing to eval this at all - my $s = new Safe; - - $s->rdo("$datadir/params"); - die "Error reading $datadir/params: $!" if $!; - die "Error evaluating $datadir/params: $@" if $@; - - # Now read the param back out from the sandbox - %params = %{$s->varglob('param')}; + my $file = bz_locations()->{'datadir'} . '/params.json'; + + if (-e $file) { + my $data; + read_file($file, binmode => ':utf8', buf_ref => \$data); + + # If params.json has been manually edited and e.g. some quotes are + # missing, we don't want JSON::XS to leak the content of the file + # to all users in its error message, so we have to eval'uate it. + %params = eval { %{JSON::XS->new->decode($data)} }; + if ($@) { + my $error_msg = (basename($0) eq 'checksetup.pl') ? + $@ : 'run checksetup.pl to see the details.'; + die "Error parsing $file: $error_msg"; + } + # JSON::XS doesn't detaint data for us. + foreach my $key (keys %params) { + trick_taint($params{$key}) if defined $params{$key}; + } } elsif ($ENV{'SERVER_SOFTWARE'}) { # We're in a CGI, but the params file doesn't exist. We can't @@ -311,7 +347,7 @@ sub read_param_file { # so that the user sees the error. require CGI::Carp; CGI::Carp->import('fatalsToBrowser'); - die "The $datadir/params file does not exist." + die "The $file file does not exist." . ' You probably need to run checksetup.pl.', } return \%params; @@ -367,7 +403,7 @@ specified. Description: Writes the parameters to disk. Params: C<$params> (optional) - A hashref to write to the disk - instead of C<Bugzilla->params>. Used only by + instead of C<Bugzilla-E<gt>params>. Used only by C<update_params>. Returns: nothing @@ -375,11 +411,13 @@ Returns: nothing =item C<read_param_file()> Description: Most callers should never need this. This is used - by C<Bugzilla->params> to directly read C<$datadir/params> - and load it into memory. Use C<Bugzilla->params> instead. + by C<Bugzilla-E<gt>params> to directly read C<$datadir/params.json> + and load it into memory. Use C<Bugzilla-E<gt>params> instead. Params: none -Returns: A hashref containing the current params in C<$datadir/params>. +Returns: A hashref containing the current params in C<$datadir/params.json>. + +=item C<param_panels()> =back |