aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@orbis-terrarum.net>2014-10-06 09:25:42 -0700
committerRobin H. Johnson <robbat2@orbis-terrarum.net>2014-10-06 09:25:42 -0700
commitcfa43fe21c342c5a7517edf0eae02a94404d4909 (patch)
tree5879d063f22533c17aba89114bc1305e23cd2161
parentIgnore the master config. (diff)
parentMerge tag 'bugzilla-4.4.6' into upstream (diff)
downloadbugzilla-cfa43fe21c342c5a7517edf0eae02a94404d4909.tar.gz
bugzilla-cfa43fe21c342c5a7517edf0eae02a94404d4909.tar.bz2
bugzilla-cfa43fe21c342c5a7517edf0eae02a94404d4909.zip
Merge branch 'upstream', takes 4.4.6 fixesgentoo-4.4.6
Conflicts: .gitignore Bugzilla/Constants.pm docs/bugzilla.ent.tmpl template/en/default/pages/release-notes.html.tmpl
-rw-r--r--.bzrignore32
-rw-r--r--.gitignore33
-rw-r--r--.travis.yml48
-rw-r--r--Bugzilla/Bug.pm15
-rw-r--r--Bugzilla/Chart.pm7
-rw-r--r--Bugzilla/Constants.pm3
-rw-r--r--Bugzilla/DB/Mysql.pm7
-rw-r--r--Bugzilla/Flag.pm33
-rw-r--r--Bugzilla/Group.pm2
-rw-r--r--Bugzilla/Template.pm4
-rw-r--r--Bugzilla/Util.pm10
-rw-r--r--Bugzilla/WebService.pm2
-rw-r--r--Build.PL61
-rw-r--r--MANIFEST.SKIP53
-rwxr-xr-xattachment.cgi10
-rwxr-xr-xbuglist.cgi2
-rw-r--r--docs/bugzilla.ent.tmpl4
-rwxr-xr-xeditflagtypes.cgi21
-rwxr-xr-xeditgroups.cgi7
-rwxr-xr-xeditusers.cgi4
-rw-r--r--js/field.js12
-rw-r--r--lib/README4
-rwxr-xr-xpost_bug.cgi9
-rwxr-xr-xrelogin.cgi31
-rw-r--r--t/002goodperl.t33
-rw-r--r--template/en/default/admin/groups/list.html.tmpl3
-rw-r--r--template/en/default/admin/products/edit.html.tmpl8
-rw-r--r--template/en/default/admin/users/responsibilities.html.tmpl14
-rw-r--r--template/en/default/config.rdf.tmpl14
-rw-r--r--template/en/default/email/flagmail.txt.tmpl13
-rw-r--r--template/en/default/filterexceptions.pl1
-rw-r--r--template/en/default/global/messages.html.tmpl2
-rw-r--r--template/en/default/pages/release-notes.html.tmpl6
-rw-r--r--template/en/default/reports/report-table.csv.tmpl8
-rw-r--r--template/en/default/search/search-specific.html.tmpl2
-rwxr-xr-xtestserver.pl2
-rwxr-xr-xtoken.cgi7
37 files changed, 415 insertions, 112 deletions
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 000000000..7ab83e7ad
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1,32 @@
+.htaccess
+/lib/*
+/template/en/custom
+/docs/bugzilla.ent
+/docs/en/xml/bugzilla.ent
+/docs/en/txt
+/docs/en/html
+/docs/en/pdf
+/skins/custom
+/graphs
+/data
+/localconfig
+/index.html
+
+/skins/contrib/Dusk/IE-fixes.css
+/skins/contrib/Dusk/admin.css
+/skins/contrib/Dusk/attachment.css
+/skins/contrib/Dusk/create_attachment.css
+/skins/contrib/Dusk/dependency-tree.css
+/skins/contrib/Dusk/duplicates.css
+/skins/contrib/Dusk/editusers.css
+/skins/contrib/Dusk/enter_bug.css
+/skins/contrib/Dusk/help.css
+/skins/contrib/Dusk/panel.css
+/skins/contrib/Dusk/page.css
+/skins/contrib/Dusk/params.css
+/skins/contrib/Dusk/reports.css
+/skins/contrib/Dusk/show_bug.css
+/skins/contrib/Dusk/search_form.css
+/skins/contrib/Dusk/show_multiple.css
+/skins/contrib/Dusk/summarize-time.css
+.DS_Store
diff --git a/.gitignore b/.gitignore
index 519f6c3b6..7ab83e7ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,32 @@
-localconfig
+.htaccess
+/lib/*
+/template/en/custom
+/docs/bugzilla.ent
+/docs/en/xml/bugzilla.ent
+/docs/en/txt
+/docs/en/html
+/docs/en/pdf
+/skins/custom
+/graphs
+/data
+/localconfig
+/index.html
+
+/skins/contrib/Dusk/IE-fixes.css
+/skins/contrib/Dusk/admin.css
+/skins/contrib/Dusk/attachment.css
+/skins/contrib/Dusk/create_attachment.css
+/skins/contrib/Dusk/dependency-tree.css
+/skins/contrib/Dusk/duplicates.css
+/skins/contrib/Dusk/editusers.css
+/skins/contrib/Dusk/enter_bug.css
+/skins/contrib/Dusk/help.css
+/skins/contrib/Dusk/panel.css
+/skins/contrib/Dusk/page.css
+/skins/contrib/Dusk/params.css
+/skins/contrib/Dusk/reports.css
+/skins/contrib/Dusk/show_bug.css
+/skins/contrib/Dusk/search_form.css
+/skins/contrib/Dusk/show_multiple.css
+/skins/contrib/Dusk/summarize-time.css
+.DS_Store
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..94c9ce1d2
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,48 @@
+language: perl
+perl:
+ - 5.10
+ - 5.12
+
+env:
+ - TEST_SUITE=sanity
+ - TEST_SUITE=docs
+ - TEST_SUITE=webservices DB=mysql
+ - TEST_SUITE=selenium DB=mysql
+ - TEST_SUITE=webservices DB=pg
+ - TEST_SUITE=selenium DB=pg
+
+matrix:
+ exclude:
+ - perl: 5.12
+ env: TEST_SUITE=docs
+ - perl: 5.10
+ env: TEST_SUITE=webservices DB=mysql
+ - perl: 5.12
+ env: TEST_SUITE=selenium DB=mysql
+ - perl: 5.10
+ env: TEST_SUITE=webservices DB=pg
+ - perl: 5.12
+ env: TEST_SUITE=selenium DB=pg
+
+before_install:
+ - git clone https://github.com/bugzilla/qa.git -b 4.4 qa
+
+install: true
+
+script: ./qa/travis.sh
+
+after_failure:
+ - sudo cat /var/log/apache2/error.log
+
+notifications:
+ irc:
+ channels:
+ - "irc.mozilla.org#qa-bugzilla"
+ - "irc.mozilla.org#bugzilla"
+ template:
+ - "Bugzilla %{branch} : %{author} : %{message}"
+ - "Commit Message : %{commit_message}"
+ - "Commit Link : %{compare_url}"
+ - "Build Link : %{build_url}"
+ on_success: change
+ on_failure: always
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index d4d94b23f..d0e8f462b 100644
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -911,12 +911,6 @@ sub update {
join(', ', @added_names)];
}
- # Flags
- my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_bug, $delta_ts);
- if ($removed || $added) {
- $changes->{'flagtypes.name'} = [$removed, $added];
- }
-
# Comments
foreach my $comment (@{$self->{added_comments} || []}) {
# Override the Comment's timestamp to be identical to the update
@@ -939,6 +933,9 @@ sub update {
Bugzilla->user->id, $delta_ts, $comment->id);
}
+ # Clear the cache of comments
+ delete $self->{comments};
+
# Insert the values into the multiselect value tables
my @multi_selects = grep {$_->type == FIELD_TYPE_MULTI_SELECT}
Bugzilla->active_custom_fields;
@@ -971,6 +968,12 @@ sub update {
join(', ', map { $_->name } @$added_see)];
}
+ # Flags
+ my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_bug, $delta_ts);
+ if ($removed || $added) {
+ $changes->{'flagtypes.name'} = [$removed, $added];
+ }
+
$_->update foreach @{ $self->{_update_ref_bugs} || [] };
delete $self->{_update_ref_bugs};
diff --git a/Bugzilla/Chart.pm b/Bugzilla/Chart.pm
index 0a655769f..e343a0535 100644
--- a/Bugzilla/Chart.pm
+++ b/Bugzilla/Chart.pm
@@ -94,10 +94,9 @@ sub init {
if ($self->{'datefrom'} && $self->{'dateto'} &&
$self->{'datefrom'} > $self->{'dateto'})
{
- ThrowUserError("misarranged_dates",
- {'datefrom' => $cgi->param('datefrom'),
- 'dateto' => $cgi->param('dateto')});
- }
+ ThrowUserError('misarranged_dates', { 'datefrom' => scalar $cgi->param('datefrom'),
+ 'dateto' => scalar $cgi->param('dateto') });
+ }
}
# Alter Chart so that the selected series are added to it.
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm
index 27887ae0d..314767251 100644
--- a/Bugzilla/Constants.pm
+++ b/Bugzilla/Constants.pm
@@ -182,8 +182,7 @@ use Memoize;
# CONSTANTS
#
# Bugzilla version
-use constant BUGZILLA_VERSION => "4.4.5";
-
+use constant BUGZILLA_VERSION => "4.4.6";
# Location of the remote and local XML files to track new releases.
use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml';
diff --git a/Bugzilla/DB/Mysql.pm b/Bugzilla/DB/Mysql.pm
index c7ce1927a..dc93b7406 100644
--- a/Bugzilla/DB/Mysql.pm
+++ b/Bugzilla/DB/Mysql.pm
@@ -70,17 +70,18 @@ sub new {
$self->{private_bz_dsn} = $dsn;
bless ($self, $class);
-
- # Bug 321645 - disable MySQL strict mode, if set
+
+ # Check for MySQL modes.
my ($var, $sql_mode) = $self->selectrow_array(
"SHOW VARIABLES LIKE 'sql\\_mode'");
+ # Disable ANSI and strict modes, else Bugzilla will crash.
if ($sql_mode) {
# STRICT_TRANS_TABLE or STRICT_ALL_TABLES enable MySQL strict mode,
# causing bug 321645. TRADITIONAL sets these modes (among others) as
# well, so it has to be stipped as well
my $new_sql_mode =
- join(",", grep {$_ !~ /^STRICT_(?:TRANS|ALL)_TABLES|TRADITIONAL$/}
+ join(",", grep {$_ !~ /^(?:ANSI|STRICT_(?:TRANS|ALL)_TABLES|TRADITIONAL)$/}
split(/,/, $sql_mode));
if ($sql_mode ne $new_sql_mode) {
diff --git a/Bugzilla/Flag.pm b/Bugzilla/Flag.pm
index 3cba94c88..affeaee68 100644
--- a/Bugzilla/Flag.pm
+++ b/Bugzilla/Flag.pm
@@ -455,14 +455,15 @@ sub create {
sub update {
my $self = shift;
my $dbh = Bugzilla->dbh;
- my $timestamp = shift || $dbh->selectrow_array('SELECT NOW()');
+ my $timestamp = shift || $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
my $changes = $self->SUPER::update(@_);
if (scalar(keys %$changes)) {
$dbh->do('UPDATE flags SET modification_date = ? WHERE id = ?',
undef, ($timestamp, $self->id));
- $self->{'modification_date'} = format_time($timestamp, '%Y.%m.%d %T');
+ $self->{'modification_date'} =
+ format_time($timestamp, '%Y.%m.%d %T', Bugzilla->local_timezone);
}
return $changes;
}
@@ -1006,18 +1007,32 @@ sub notify {
$default_lang = Bugzilla::User->new()->setting('lang');
}
+ # Get comments on the bug
+ my $all_comments = $bug->comments({ after => $bug->lastdiffed });
+ @$all_comments = grep { $_->type || $_->body =~ /\S/ } @$all_comments;
+
+ # Get public only comments
+ my $public_comments = [ grep { !$_->is_private } @$all_comments ];
+
foreach my $to (keys %recipients) {
# Add threadingmarker to allow flag notification emails to be the
# threaded similar to normal bug change emails.
my $thread_user_id = $recipients{$to} ? $recipients{$to}->id : 0;
- my $vars = { 'flag' => $flag,
- 'old_flag' => $old_flag,
- 'to' => $to,
- 'date' => $timestamp,
- 'bug' => $bug,
- 'attachment' => $attachment,
- 'threadingmarker' => build_thread_marker($bug->id, $thread_user_id) };
+ # We only want to show private comments to users in the is_insider group
+ my $comments = $recipients{$to} && $recipients{$to}->is_insider
+ ? $all_comments : $public_comments;
+
+ my $vars = {
+ flag => $flag,
+ old_flag => $old_flag,
+ to => $to,
+ date => $timestamp,
+ bug => $bug,
+ attachment => $attachment,
+ threadingmarker => build_thread_marker($bug->id, $thread_user_id),
+ new_comments => $comments,
+ };
my $lang = $recipients{$to} ?
$recipients{$to}->setting('lang') : $default_lang;
diff --git a/Bugzilla/Group.pm b/Bugzilla/Group.pm
index 04c36f694..5404dec7e 100644
--- a/Bugzilla/Group.pm
+++ b/Bugzilla/Group.pm
@@ -53,7 +53,7 @@ use constant UPDATE_COLUMNS => qw(
# Parameters that are lists of groups.
use constant GROUP_PARAMS => qw(chartgroup insidergroup timetrackinggroup
- querysharegroup);
+ querysharegroup debug_group);
###############################
#### Accessors ######
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index fab13b7e3..019809c60 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -720,10 +720,12 @@ sub create {
},
# In CSV, quotes are doubled, and any value containing a quote or a
- # comma is enclosed in quotes.
+ # comma is enclosed in quotes. If a field starts with an equals
+ # sign, it is proceed by a space.
csv => sub
{
my ($var) = @_;
+ $var = ' ' . $var if substr($var, 0, 1) eq '=';
$var =~ s/\"/\"\"/g;
if ($var !~ /^-?(\d+\.)?\d*$/) {
$var = "\"$var\"";
diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm
index 164ff40bf..4bd10e16c 100644
--- a/Bugzilla/Util.pm
+++ b/Bugzilla/Util.pm
@@ -569,10 +569,14 @@ sub datetime_from {
return undef if !@time;
- # strptime() counts years from 1900, and months from 0 (January).
- # We have to fix both values.
+ # strptime() counts years from 1900, except if they are older than 1901
+ # in which case it returns the full year (so 1890 -> 1890, but 1984 -> 84,
+ # and 3790 -> 1890). We make a guess and assume that 1100 <= year < 3000.
+ $time[5] += 1900 if $time[5] < 1100;
+
my %args = (
- year => $time[5] + 1900,
+ year => $time[5],
+ # Months start from 0 (January).
month => $time[4] + 1,
day => $time[3],
hour => $time[2],
diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm
index 2a0e8890f..ac4cd25ce 100644
--- a/Bugzilla/WebService.pm
+++ b/Bugzilla/WebService.pm
@@ -269,7 +269,7 @@ hashes.
Some RPC calls support specifying sub fields. If an RPC call states that
it support sub field restrictions, you can restrict what information is
-returned within the first field. For example, if you call Products.get
+returned within the first field. For example, if you call Product.get
with an include_fields of components.name, then only the component name
would be returned (and nothing else). You can include the main field,
and exclude a sub field.
diff --git a/Build.PL b/Build.PL
new file mode 100644
index 000000000..024a56024
--- /dev/null
+++ b/Build.PL
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use FindBin qw($RealBin);
+use lib ($RealBin, "$RealBin/lib");
+
+use Module::Build 0.36_14;
+
+use Bugzilla::Install::Requirements qw(REQUIRED_MODULES OPTIONAL_MODULES);
+use Bugzilla::Constants qw(BUGZILLA_VERSION);
+
+sub requires {
+ my $requirements = REQUIRED_MODULES();
+ my $hrequires = {};
+ foreach my $module (@$requirements) {
+ $hrequires->{$module->{module}} = $module->{version};
+ }
+ return $hrequires;
+};
+
+sub build_requires {
+ return requires();
+}
+
+sub recommends {
+ my $recommends = OPTIONAL_MODULES();
+ my @blacklist = ('Apache-SizeLimit', 'mod_perl'); # Does not compile properly on Travis
+ my $hrecommends = {};
+ foreach my $module (@$recommends) {
+ next if grep($_ eq $module->{package}, @blacklist);
+ $hrecommends->{$module->{module}} = $module->{version};
+ }
+ return $hrecommends;
+}
+
+my $build = Module::Build->new(
+ module_name => 'Bugzilla',
+ dist_abstract => <<END,
+Bugzilla is a free bug-tracking system that is developed by an active
+community of volunteers. You can install and use it without having to
+pay any license fee.
+END
+ dist_version_from => 'Bugzilla/Constants.pm',
+ dist_version => BUGZILLA_VERSION,
+ requires => requires(),
+ recommends => recommends(),
+ license => 'Mozilla_2_0',
+ create_readme => 0,
+ create_makefile_pl => 0
+);
+
+$build->create_build_script;
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644
index 000000000..69204e63f
--- /dev/null
+++ b/MANIFEST.SKIP
@@ -0,0 +1,53 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+#!start included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
+# Avoid version control files.
+\B\.git\b
+\B\.bzr\b
+\B\.bzrignore\b
+\B\.gitignore\b
+\B\.gitrev\b
+\B\.patch\b
+
+# Avoid Makemaker generated and utility files.
+\bMANIFEST\.bak
+\bMakefile$
+\bblib/
+\bMakeMaker-\d
+\bpm_to_blib\.ts$
+\bpm_to_blib$
+\bblibdirs\.ts$ # 6.18 through 6.25 generated this
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build/
+
+# Avoid temp and backup files.
+~$
+\.old$
+\#$
+\b\.#
+\.bak$
+\.swp$
+
+#!end included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\bBuild.bat$
+\b_build
+\bBuild.COM$
+\bBUILD.COM$
+\bbuild.com$
+
+# Avoid archives of this distribution
+\bBugzilla-[\d\.\_]+
+
+# Bugzilla specific avoids
+\bdata\/\b
+\blocalconfig$
diff --git a/attachment.cgi b/attachment.cgi
index 18d783bf4..9b5d66122 100755
--- a/attachment.cgi
+++ b/attachment.cgi
@@ -205,8 +205,9 @@ sub validateContext
{
my $context = $cgi->param('context') || "patch";
if ($context ne "file" && $context ne "patch") {
- detaint_natural($context)
- || ThrowUserError("invalid_context", { context => $cgi->param('context') });
+ my $orig_context = $context;
+ detaint_natural($context)
+ || ThrowUserError("invalid_context", { context => $orig_context });
}
return $context;
@@ -524,13 +525,14 @@ sub insert {
# Get the filehandle of the attachment.
my $data_fh = $cgi->upload('data');
+ my $attach_text = $cgi->param('attach_text');
my $attachment = Bugzilla::Attachment->create(
{bug => $bug,
creation_ts => $timestamp,
- data => scalar $cgi->param('attach_text') || $data_fh,
+ data => $attach_text || $data_fh,
description => scalar $cgi->param('description'),
- filename => $cgi->param('attach_text') ? "file_$bugid.txt" : scalar $cgi->upload('data'),
+ filename => $attach_text ? "file_$bugid.txt" : $data_fh,
ispatch => scalar $cgi->param('ispatch'),
isprivate => scalar $cgi->param('isprivate'),
mimetype => $content_type,
diff --git a/buglist.cgi b/buglist.cgi
index 81350dc81..e3d8fe711 100755
--- a/buglist.cgi
+++ b/buglist.cgi
@@ -916,7 +916,7 @@ if (scalar(@products) == 1) {
# This is used in the "Zarroo Boogs" case.
elsif (my @product_input = $cgi->param('product')) {
if (scalar(@product_input) == 1 and $product_input[0] ne '') {
- $one_product = new Bugzilla::Product({ name => $cgi->param('product') });
+ $one_product = new Bugzilla::Product({ name => $product_input[0] });
}
}
# We only want the template to use it if the user can actually
diff --git a/docs/bugzilla.ent.tmpl b/docs/bugzilla.ent.tmpl
index 98ec0a7ce..1ac67b7ed 100644
--- a/docs/bugzilla.ent.tmpl
+++ b/docs/bugzilla.ent.tmpl
@@ -1,5 +1,5 @@
-<!ENTITY bz-ver "4.4.5">
-<!ENTITY bz-date "2014-07-24">
+<!ENTITY bz-ver "4.4.6">
+<!ENTITY bz-date "2014-10-06">
<!ENTITY current-year "2014">
diff --git a/editflagtypes.cgi b/editflagtypes.cgi
index e9c430d7d..aa789fc74 100755
--- a/editflagtypes.cgi
+++ b/editflagtypes.cgi
@@ -44,23 +44,24 @@ my @products = @{$vars->{products}};
my $action = $cgi->param('action') || 'list';
my $token = $cgi->param('token');
-my $product = $cgi->param('product');
-my $component = $cgi->param('component');
+my $prod_name = $cgi->param('product');
+my $comp_name = $cgi->param('component');
my $flag_id = $cgi->param('id');
-if ($product) {
+my ($product, $component);
+
+if ($prod_name) {
# Make sure the user is allowed to view this product name.
# Users with global editcomponents privs can see all product names.
- ($product) = grep { lc($_->name) eq lc($product) } @products;
- $product || ThrowUserError('product_access_denied', { name => $cgi->param('product') });
+ ($product) = grep { lc($_->name) eq lc($prod_name) } @products;
+ $product || ThrowUserError('product_access_denied', { name => $prod_name });
}
-if ($component) {
- ($product && $product->id)
- || ThrowUserError('flag_type_component_without_product');
- ($component) = grep { lc($_->name) eq lc($component) } @{$product->components};
+if ($comp_name) {
+ $product || ThrowUserError('flag_type_component_without_product');
+ ($component) = grep { lc($_->name) eq lc($comp_name) } @{$product->components};
$component || ThrowUserError('product_unknown_component', { product => $product->name,
- comp => $cgi->param('component') });
+ comp => $comp_name });
}
# If 'categoryAction' is set, it has priority over 'action'.
diff --git a/editgroups.cgi b/editgroups.cgi
index d603ab183..e3b9f60d1 100755
--- a/editgroups.cgi
+++ b/editgroups.cgi
@@ -19,9 +19,6 @@ use Bugzilla::Product;
use Bugzilla::User;
use Bugzilla::Token;
-use constant SPECIAL_GROUPS => ('chartgroup', 'insidergroup',
- 'timetrackinggroup', 'querysharegroup');
-
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
my $template = Bugzilla->template;
@@ -224,7 +221,7 @@ if ($action eq 'new') {
if ($action eq 'del') {
# Check that an existing group ID is given
- my $group = Bugzilla::Group->check({ id => $cgi->param('group') });
+ my $group = Bugzilla::Group->check({ id => scalar $cgi->param('group') });
$group->check_remove({ test_only => 1 });
$vars->{'shared_queries'} =
$dbh->selectrow_array('SELECT COUNT(*)
@@ -248,7 +245,7 @@ if ($action eq 'del') {
if ($action eq 'delete') {
check_token_data($token, 'delete_group');
# Check that an existing group ID is given
- my $group = Bugzilla::Group->check({ id => $cgi->param('group') });
+ my $group = Bugzilla::Group->check({ id => scalar $cgi->param('group') });
$vars->{'name'} = $group->name;
$group->remove_from_db({
remove_from_users => scalar $cgi->param('removeusers'),
diff --git a/editusers.cgi b/editusers.cgi
index a5ba6d1e3..9778aa808 100755
--- a/editusers.cgi
+++ b/editusers.cgi
@@ -704,7 +704,9 @@ sub check_user {
sub mirrorListSelectionValues {
my $cgi = Bugzilla->cgi;
if (defined($cgi->param('matchtype'))) {
- foreach ('matchvalue', 'matchstr', 'matchtype', 'grouprestrict', 'groupid') {
+ foreach ('matchvalue', 'matchstr', 'matchtype',
+ 'grouprestrict', 'groupid', 'enabled_only')
+ {
$vars->{'listselectionvalues'}{$_} = $cgi->param($_);
}
}
diff --git a/js/field.js b/js/field.js
index c0d0aaa6e..356c0cd5a 100644
--- a/js/field.js
+++ b/js/field.js
@@ -46,10 +46,14 @@ function validateEnterBug(theform) {
_errorFor(attach_desc, 'attach_desc');
focus_me = attach_desc;
}
- var check_description = status_comment_required[bug_status.value];
- if (check_description && YAHOO.lang.trim(description.value) == '') {
- _errorFor(description, 'description');
- focus_me = description;
+ // bug_status can be undefined if the bug_status field is not editable by
+ // the currently logged in user.
+ if (bug_status) {
+ var check_description = status_comment_required[bug_status.value];
+ if (check_description && YAHOO.lang.trim(description.value) == '') {
+ _errorFor(description, 'description');
+ focus_me = description;
+ }
}
if (YAHOO.lang.trim(short_desc.value) == '') {
_errorFor(short_desc);
diff --git a/lib/README b/lib/README
new file mode 100644
index 000000000..5778a9a3f
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,4 @@
+This directory contains the Perl modules that Bugzilla requires to run.
+
+If you would rather have Bugzilla use the Perl modules installed on your
+system, you can delete everything in this directory.
diff --git a/post_bug.cgi b/post_bug.cgi
index 33f5652a5..0a0f8562c 100755
--- a/post_bug.cgi
+++ b/post_bug.cgi
@@ -150,7 +150,10 @@ if (defined $cgi->param('version')) {
# after the bug is filed.
# Add an attachment if requested.
-if (defined($cgi->upload('data')) || $cgi->param('attach_text')) {
+my $data_fh = $cgi->upload('data');
+my $attach_text = $cgi->param('attach_text');
+
+if ($data_fh || $attach_text) {
$cgi->param('isprivate', $cgi->param('comment_is_private'));
# Must be called before create() as it may alter $cgi->param('ispatch').
@@ -165,9 +168,9 @@ if (defined($cgi->upload('data')) || $cgi->param('attach_text')) {
$attachment = Bugzilla::Attachment->create(
{bug => $bug,
creation_ts => $timestamp,
- data => scalar $cgi->param('attach_text') || $cgi->upload('data'),
+ data => $attach_text || $data_fh,
description => scalar $cgi->param('description'),
- filename => $cgi->param('attach_text') ? "file_$id.txt" : scalar $cgi->upload('data'),
+ filename => $attach_text ? "file_$id.txt" : $data_fh,
ispatch => scalar $cgi->param('ispatch'),
isprivate => scalar $cgi->param('isprivate'),
mimetype => $content_type,
diff --git a/relogin.cgi b/relogin.cgi
index 4338c8ee0..337d1b208 100755
--- a/relogin.cgi
+++ b/relogin.cgi
@@ -84,19 +84,21 @@ elsif ($action eq 'begin-sudo') {
{
$credentials_provided = 1;
}
-
+
# Next, log in the user
my $user = Bugzilla->login(LOGIN_REQUIRED);
-
+
+ my $target_login = $cgi->param('target_login');
+ my $reason = $cgi->param('reason') || '';
+
# At this point, the user is logged in. However, if they used a method
# where they could have provided a username/password (i.e. CGI), but they
# did not provide a username/password, then throw an error.
if ($user->authorizer->can_login && !$credentials_provided) {
ThrowUserError('sudo_password_required',
- { target_login => $cgi->param('target_login'),
- reason => $cgi->param('reason')});
+ { target_login => $target_login, reason => $reason });
}
-
+
# The user must be in the 'bz_sudoers' group
unless ($user->in_group('bz_sudoers')) {
ThrowUserError('auth_failure', { group => 'bz_sudoers',
@@ -120,30 +122,22 @@ elsif ($action eq 'begin-sudo') {
&& ($token_data eq 'sudo_prepared'))
{
ThrowUserError('sudo_preparation_required',
- { target_login => scalar $cgi->param('target_login'),
- reason => scalar $cgi->param('reason')});
+ { target_login => $target_login, reason => $reason });
}
delete_token($cgi->param('token'));
# Get & verify the target user (the user who we will be impersonating)
- my $target_user =
- new Bugzilla::User({ name => $cgi->param('target_login') });
+ my $target_user = new Bugzilla::User({ name => $target_login });
unless (defined($target_user)
&& $target_user->id
&& $user->can_see_user($target_user))
{
- ThrowUserError('user_match_failed',
- { 'name' => $cgi->param('target_login') }
- );
+ ThrowUserError('user_match_failed', { name => $target_login });
}
if ($target_user->in_group('bz_sudo_protect')) {
ThrowUserError('sudo_protected', { login => $target_user->login });
}
- # If we have a reason passed in, keep it under 200 characters
- my $reason = $cgi->param('reason') || '';
- $reason = substr($reason, 0, 200);
-
# Calculate the session expiry time (T + 6 hours)
my $time_string = time2str('%a, %d-%b-%Y %T %Z', time + MAX_SUDO_TOKEN_AGE, 'GMT');
@@ -163,9 +157,12 @@ elsif ($action eq 'begin-sudo') {
# For the present, change the values of Bugzilla::user & Bugzilla::sudoer
Bugzilla->sudo_request($target_user, $user);
-
+
# NOTE: If you want to log the start of an sudo session, do it here.
+ # If we have a reason passed in, keep it under 200 characters
+ $reason = substr($reason, 0, 200);
+
# Go ahead and send out the message now
my $message;
my $mail_template = Bugzilla->template_inner($target_user->setting('lang'));
diff --git a/t/002goodperl.t b/t/002goodperl.t
index e691b39dd..2cbee8ef5 100644
--- a/t/002goodperl.t
+++ b/t/002goodperl.t
@@ -16,7 +16,7 @@ use lib 't';
use Support::Files;
-use Test::More tests => (scalar(@Support::Files::testitems) * 3);
+use Test::More tests => (scalar(@Support::Files::testitems) * 4);
my @testitems = @Support::Files::testitems; # get the files to test.
@@ -110,4 +110,35 @@ foreach my $file (@testitems) {
close(FILE);
}
+
+# Forbird the { foo => $cgi->param() } syntax, for security reasons.
+foreach my $file (@testitems) {
+ $file =~ s/\s.*$//; # nuke everything after the first space (#comment)
+ next unless $file; # skip null entries
+ if (!open(FILE, $file)) {
+ ok(0, "could not open $file --WARNING");
+ next;
+ }
+ my $lineno = 0;
+ my @unsafe_args;
+
+ while (my $file_line = <FILE>) {
+ $lineno++;
+ $file_line =~ s/^\s*(.+)\s*$/$1/; # Remove leading and trailing whitespaces.
+ if ($file_line =~ /^[^#]+=> \$cgi\->param/) {
+ push(@unsafe_args, "$file_line on line $lineno");
+ }
+ }
+
+ if (@unsafe_args) {
+ ok(0, "$file incorrectly passes a CGI argument to a hash --ERROR\n" .
+ join("\n", @unsafe_args));
+ }
+ else {
+ ok(1, "$file has no vulnerable hash syntax");
+ }
+
+ close(FILE);
+}
+
exit 0;
diff --git a/template/en/default/admin/groups/list.html.tmpl b/template/en/default/admin/groups/list.html.tmpl
index af7da33a6..859f26205 100644
--- a/template/en/default/admin/groups/list.html.tmpl
+++ b/template/en/default/admin/groups/list.html.tmpl
@@ -74,7 +74,8 @@
}
%]
-[% FOREACH group IN ["chartgroup", "insidergroup", "timetrackinggroup", "querysharegroup"] %]
+[% FOREACH group IN ["chartgroup", "insidergroup", "timetrackinggroup",
+ "querysharegroup", "debug_group"] %]
[% special_group = Param(group) %]
[% IF special_group %]
diff --git a/template/en/default/admin/products/edit.html.tmpl b/template/en/default/admin/products/edit.html.tmpl
index c38530125..a4fcd188f 100644
--- a/template/en/default/admin/products/edit.html.tmpl
+++ b/template/en/default/admin/products/edit.html.tmpl
@@ -42,12 +42,12 @@
</th>
<td>
[% IF product.components.size -%]
- [% FOREACH component = product.components %]
+ [% FOREACH comp = product.components %]
<a href="editcomponents.cgi?action=edit&product=
[%- product.name FILTER uri %]&component=
- [%- component.name FILTER uri %]">[% component.name FILTER html %]</a>:&nbsp;
- [% IF component.description %]
- [% component.description FILTER html_light %]
+ [%- comp.name FILTER uri %]">[% comp.name FILTER html %]</a>:&nbsp;
+ [% IF comp.description %]
+ [% comp.description FILTER html_light %]
[% ELSE %]
<font color="red">description missing</font>
[% END %]
diff --git a/template/en/default/admin/users/responsibilities.html.tmpl b/template/en/default/admin/users/responsibilities.html.tmpl
index 9e6e48c6a..67ea7d294 100644
--- a/template/en/default/admin/users/responsibilities.html.tmpl
+++ b/template/en/default/admin/users/responsibilities.html.tmpl
@@ -23,26 +23,26 @@
<th>Default QA Contact</th>
<th>Default CC</th>
</tr>
- [% FOREACH component = item.components %]
+ [% FOREACH comp = item.components %]
<tr>
<td>
- [% IF user.in_group("editcomponents", component.product_id) %]
+ [% IF user.in_group("editcomponents", comp.product_id) %]
<a href="editcomponents.cgi?action=edit&amp;product=
[% item.product.name FILTER uri %]&amp;component=
- [% component.name FILTER uri %]">
+ [% comp.name FILTER uri %]">
[% END %]
- [% component.name FILTER html %]
- [% IF user.in_group("editcomponents", component.product_id) %]
+ [% comp.name FILTER html %]
+ [% IF user.in_group("editcomponents", comp.product_id) %]
</a>
[% END %]
</td>
[% FOREACH responsibility = ['default_assignee', 'default_qa_contact'] %]
<td class="center">
- [% component.$responsibility.id == otheruser.id ? "X" : "&nbsp;" %]
+ [% comp.$responsibility.id == otheruser.id ? "X" : "&nbsp;" %]
</td>
[% END %]
<td class="center">
- [% component.initial_cc.contains(otheruser) ? "X" : "&nbsp;" %]
+ [% comp.initial_cc.contains(otheruser) ? "X" : "&nbsp;" %]
</td>
</tr>
[% END %]
diff --git a/template/en/default/config.rdf.tmpl b/template/en/default/config.rdf.tmpl
index b14d0d056..0d183cf56 100644
--- a/template/en/default/config.rdf.tmpl
+++ b/template/en/default/config.rdf.tmpl
@@ -139,8 +139,8 @@
[% END %]
<bz:components>
<Seq>
- [% FOREACH component = product.components %]
- <li resource="[% escaped_urlbase %]component.cgi?name=[% component.name FILTER uri
+ [% FOREACH comp = product.components %]
+ <li resource="[% escaped_urlbase %]component.cgi?name=[% comp.name FILTER uri
%]&amp;product=[% product.name FILTER uri %]"/>
[% END %]
</Seq>
@@ -176,16 +176,16 @@
<bz:components>
<Seq>
[% FOREACH product = products %]
- [% FOREACH component = product.components %]
+ [% FOREACH comp = product.components %]
<li>
- <bz:component rdf:about="[% escaped_urlbase %]component.cgi?name=[% component.name FILTER uri
+ <bz:component rdf:about="[% escaped_urlbase %]component.cgi?name=[% comp.name FILTER uri
%]&amp;product=[% product.name FILTER uri %]">
- <bz:name>[% component.name FILTER html %]</bz:name>
- <bz:is_active>[% component.is_active FILTER html %]</bz:is_active>
+ <bz:name>[% comp.name FILTER html %]</bz:name>
+ <bz:is_active>[% comp.is_active FILTER html %]</bz:is_active>
[% IF show_flags %]
<bz:flag_types>
<Seq>
- [% flag_types = component.flag_types.bug.merge(component.flag_types.attachment) %]
+ [% flag_types = comp.flag_types.bug.merge(comp.flag_types.attachment) %]
[% FOREACH flag_type = flag_types %]
[% NEXT UNLESS flag_type.is_active %]
[% all_visible_flag_types.${flag_type.id} = flag_type %]
diff --git a/template/en/default/email/flagmail.txt.tmpl b/template/en/default/email/flagmail.txt.tmpl
index 169dfa892..037673dfc 100644
--- a/template/en/default/email/flagmail.txt.tmpl
+++ b/template/en/default/email/flagmail.txt.tmpl
@@ -64,11 +64,14 @@ Attachment [% attidsummary %]
[%- FILTER bullet = wrap(80) %]
-[% USE Bugzilla %]
-[%-# .defined is necessary to avoid a taint issue in Perl < 5.10.1, see bug 509794. %]
-[% IF Bugzilla.cgi.param("comment").defined && Bugzilla.cgi.param("comment").length > 0 %]
-------- Additional Comments from [% user.identity %]
-[%+ Bugzilla.cgi.param("comment") FILTER strip_control_chars %]
+[% FOREACH comment = new_comments %]
+
+[%- IF comment.count %]
+--- Comment #[% comment.count %] from [% comment.author.identity %] ---
+[% ELSE %]
+--- Description ---
+[% END %]
+[%+ comment.body_full({ is_bugmail => 1, wrap => 1 }) FILTER strip_control_chars %]
[% END %]
[%- END %]
diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl
index 189862527..e37fec1a7 100644
--- a/template/en/default/filterexceptions.pl
+++ b/template/en/default/filterexceptions.pl
@@ -170,7 +170,6 @@
],
'global/messages.html.tmpl' => [
- 'message_tag',
'series.frequency * 2',
],
diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl
index f55ab92a4..ba961c392 100644
--- a/template/en/default/global/messages.html.tmpl
+++ b/template/en/default/global/messages.html.tmpl
@@ -918,7 +918,7 @@
[% IF !message %]
[% message = BLOCK %]
You are using [% terms.Bugzilla %]'s messaging functions incorrectly. You
- passed in the string '[% message_tag %]'. The correct use is to pass
+ passed in the string '[% message_tag FILTER html %]'. The correct use is to pass
in a tag, and define that tag in the file <kbd>messages.html.tmpl</kbd>.<br>
<br>
If you are a [% terms.Bugzilla %] end-user seeing this message, please
diff --git a/template/en/default/pages/release-notes.html.tmpl b/template/en/default/pages/release-notes.html.tmpl
index 16ddffbe4..5c11360f3 100644
--- a/template/en/default/pages/release-notes.html.tmpl
+++ b/template/en/default/pages/release-notes.html.tmpl
@@ -45,6 +45,12 @@
<h2 id="v44_point">Updates in this 4.4.x Release</h2>
+<h3>4.4.6</h3>
+
+<p>This release fixes several security issues. See the
+ <a href="http://www.bugzilla.org/security/4.0.14/">Security Advisory</a>
+ for details.</p>
+
<h3>4.4.5</h3>
<p>This release fixes a security issue. See the
diff --git a/template/en/default/reports/report-table.csv.tmpl b/template/en/default/reports/report-table.csv.tmpl
index e2a92b51d..e94014b92 100644
--- a/template/en/default/reports/report-table.csv.tmpl
+++ b/template/en/default/reports/report-table.csv.tmpl
@@ -23,11 +23,13 @@
[% END %]
[% tbl_field_disp FILTER csv %]: [% tbl_disp FILTER csv %]
[% END %]
-[% IF row_field %]
+[% IF row_field && col_field %]
+ [% row_field_disp _ ' / ' _ col_field_disp FILTER csv %]
+[% ELSIF row_field %]
[% row_field_disp FILTER csv %]
+[% ELSE %]
+ [% col_field_disp FILTER csv %]
[% END %]
-[% " / " IF col_field AND row_field %]
-[% col_field_disp FILTER csv %]
[% IF col_field -%]
[% FOREACH col = col_names -%]
[% colsepchar %]
diff --git a/template/en/default/search/search-specific.html.tmpl b/template/en/default/search/search-specific.html.tmpl
index 1093f70bc..f09d4bdc0 100644
--- a/template/en/default/search/search-specific.html.tmpl
+++ b/template/en/default/search/search-specific.html.tmpl
@@ -27,7 +27,7 @@ for "crash secure SSL flash".
<form name="queryform" method="get" action="buglist.cgi">
<input type="hidden" name="query_format" value="specific">
-<input type="hidden" name="order" value="relevance desc">
+<input type="hidden" name="order" value="Importance">
<input type="hidden" id="no_redirect" name="no_redirect" value="0">
<script type="text/javascript">
if (history && history.replaceState) {
diff --git a/testserver.pl b/testserver.pl
index d296b730f..77489d252 100755
--- a/testserver.pl
+++ b/testserver.pl
@@ -39,7 +39,7 @@ if (!ON_WINDOWS) {
foreach my $pscmd (@pscmds) {
open PH, "$pscmd 2>/dev/null |";
while (my $line = <PH>) {
- if ($line =~ /^(?:\S*\/)?(?:httpd|apache)2?\s+(\d+)$/) {
+ if ($line =~ /^(?:\S*\/)?(?:httpd|apache?)2?\s+(\d+)$/) {
$sgid = $1 if $1 > $sgid;
}
}
diff --git a/token.cgi b/token.cgi
index 62f1f5121..05cb30c9f 100755
--- a/token.cgi
+++ b/token.cgi
@@ -163,6 +163,7 @@ sub cancelChangePassword {
# password and that the new password is valid.
sub changePassword {
my ($user_id, $token) = @_;
+ my $dbh = Bugzilla->dbh;
my $password = $cgi->param('password');
(defined $password && defined $cgi->param('matchpassword'))
@@ -176,6 +177,8 @@ sub changePassword {
$user->set_password($password);
$user->update();
delete_token($token);
+ $dbh->do(q{DELETE FROM tokens WHERE userid = ?
+ AND tokentype = 'password'}, undef, $user_id);
Bugzilla->logout_user_by_id($user_id);
@@ -254,7 +257,7 @@ sub cancelChangeEmail {
# check to see if it has been altered
if ($user->login ne $old_email) {
$user->set_login($old_email);
- $user->update({ keep_session => 1 });
+ $user->update({ keep_tokens => 1 });
$vars->{'message'} = "email_change_canceled_reinstated";
}
@@ -306,7 +309,7 @@ sub confirm_create_account {
my $otheruser = Bugzilla::User->create({
login_name => $login_name,
- realname => $cgi->param('realname'),
+ realname => scalar $cgi->param('realname'),
cryptpassword => $password});
# Now delete this token.