summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjustdave%syndicomm.com <>2003-04-25 05:49:27 +0200
committerjustdave%syndicomm.com <>2003-04-25 05:49:27 +0200
commit29021b187f042f023584dd3986c086ca68bef0a2 (patch)
treed6c1c7c114ffe92462ef4f1817c6a87f18e4141c
parent2fac94504175f4964ad254f07e184e00e10eef08 (diff)
downloadbugzilla-29021b187f042f023584dd3986c086ca68bef0a2.tar.gz
bugzilla-29021b187f042f023584dd3986c086ca68bef0a2.tar.xz
Bug 192677: Add new test to flag failure-to-filter situations in the templates, and correct the XSS holes that were discovered as a
result of it. Patch by Gervase Markham <gerv@mozilla.org> r= myk, bbaetz, justdave a= justdave
-rwxr-xr-xduplicates.cgi10
-rw-r--r--t/008filter.t182
-rw-r--r--template/en/default/account/auth/login.html.tmpl2
-rw-r--r--template/en/default/attachment/edit.html.tmpl2
-rw-r--r--template/en/default/bug/create/create-guided.html.tmpl6
-rw-r--r--template/en/default/bug/create/create.html.tmpl3
-rw-r--r--template/en/default/bug/create/make-template.html.tmpl2
-rw-r--r--template/en/default/bug/show-multiple.html.tmpl3
-rw-r--r--template/en/default/filterexceptions.pl597
-rw-r--r--template/en/default/global/choose-product.html.tmpl2
-rw-r--r--template/en/default/global/code-error.html.tmpl2
-rw-r--r--template/en/default/global/hidden-fields.html.tmpl4
-rw-r--r--template/en/default/global/message.html.tmpl2
-rw-r--r--template/en/default/global/user-error.html.tmpl9
-rw-r--r--template/en/default/list/change-columns.html.tmpl4
-rw-r--r--template/en/default/list/list.html.tmpl13
-rw-r--r--template/en/default/list/table.html.tmpl5
-rw-r--r--template/en/default/reports/duplicates.html.tmpl2
-rw-r--r--template/en/default/search/form.html.tmpl2
19 files changed, 825 insertions, 27 deletions
diff --git a/duplicates.cgi b/duplicates.cgi
index 1a3c08a9f..64a3f7ab3 100755
--- a/duplicates.cgi
+++ b/duplicates.cgi
@@ -74,7 +74,7 @@ my $sortby = formvalue("sortby");
my $changedsince = formvalue("changedsince", 7);
my $maxrows = formvalue("maxrows", 100);
my $openonly = formvalue("openonly");
-my $reverse = formvalue("reverse");
+my $reverse = formvalue("reverse") ? 1 : 0;
my $product = formvalue("product");
my $sortvisible = formvalue("sortvisible");
my @buglist = (split(/[:,]/, formvalue("bug_id")));
@@ -159,8 +159,14 @@ if (!tie(%before, 'AnyDBM_File', "data/duplicates/dupes$whenever",
$dobefore = 1;
}
+my $origmaxrows = $maxrows;
detaint_natural($maxrows)
- || ThrowUserError("invalid_maxrows", { maxrows => $maxrows});
+ || ThrowUserError("invalid_maxrows", { maxrows => $origmaxrows});
+
+my $origchangedsince = $changedsince;
+detaint_natural($changedsince)
+ || ThrowUserError("invalid_changedsince",
+ { changedsince => $origchangedsince });
my @bugs;
my @bug_ids;
diff --git a/t/008filter.t b/t/008filter.t
new file mode 100644
index 000000000..10d7fc62c
--- /dev/null
+++ b/t/008filter.t
@@ -0,0 +1,182 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# 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 are the Bugzilla tests.
+#
+# The Initial Developer of the Original Code is Jacob Steenhagen.
+# Portions created by Jacob Steenhagen are
+# Copyright (C) 2001 Jacob Steenhagen. All
+# Rights Reserved.
+#
+# Contributor(s): Gervase Markham <gerv@gerv.net>
+
+#################
+#Bugzilla Test 8#
+#####filter######
+
+# This test scans all our templates for every directive. Having eliminated
+# those which cannot possibly cause XSS problems, it then checks the rest
+# against the safe list stored in the filterexceptions.pl file.
+
+# Sample exploit code: '>"><script>alert('Oh dear...')</script>
+
+use strict;
+use lib 't';
+
+use vars qw(%safe);
+
+use Support::Templates;
+use File::Spec 0.82;
+use Test::More tests => $Support::Templates::num_actual_files;
+use Cwd;
+
+# Undefine the record separator so we can read in whole files at once
+my $oldrecsep = $/;
+$/ = undef;
+my $topdir = cwd;
+
+foreach my $path (@Support::Templates::include_paths) {
+ $path =~ m|template/([^/]+)/|;
+ my $lang = $1;
+ chdir $topdir; # absolute path
+ my @testitems = Support::Templates::find_actual_files($path);
+
+ next unless @testitems;
+
+ # Some people require this, others don't. No-one knows why.
+ chdir $path; # relative path
+
+ # We load a %safe list of acceptable exceptions.
+ if (!-r "filterexceptions.pl") {
+ ok(0, "$path has templates but no filterexceptions.pl file. --ERROR");
+ next;
+ }
+ else {
+ do "filterexceptions.pl";
+ }
+
+ # We preprocess the %safe hash of lists into a hash of hashes. This allows
+ # us to flag which members were not found, and report that as a warning,
+ # thereby keeping the lists clean.
+ foreach my $file (keys %safe) {
+ my $list = $safe{$file};
+ $safe{$file} = {};
+ foreach my $directive (@$list) {
+ $safe{$file}{$directive} = 0;
+ }
+ }
+
+ foreach my $file (@testitems) {
+ # There are some files we don't check, because there is no need to
+ # filter their contents due to their content-type.
+ if ($file =~ /\.(txt|png)\.tmpl$/) {
+ ok(1, "($lang) $file is filter-safe");
+ next;
+ }
+
+ # Read the entire file into a string
+ open (FILE, "<$file") || die "Can't open $file: $!\n";
+ my $slurp = <FILE>;
+ close (FILE);
+
+ my @unfiltered;
+
+ # /g means we execute this loop for every match
+ # /s means we ignore linefeeds in the regexp matches
+ while ($slurp =~ /\[%(.*?)%\]/gs) {
+ my $directive = $1;
+
+ my @lineno = ($` =~ m/\n/gs);
+ my $lineno = scalar(@lineno) + 1;
+
+ # Comments
+ next if $directive =~ /^[+-]?#/;
+
+ # Remove any leading/trailing + or - and whitespace.
+ $directive =~ s/^[+-]?\s*//;
+ $directive =~ s/\s*[+-]?$//;
+
+ # Directives
+ next if $directive =~ /^(IF|END|UNLESS|FOREACH|PROCESS|INCLUDE|
+ BLOCK|USE|ELSE|NEXT|LAST|DEFAULT|FLUSH|
+ ELSIF|SET|SWITCH|CASE)/x;
+
+ # Simple assignments
+ next if $directive =~ /^[\w\.\$]+\s+=\s+/;
+
+ # Conditional literals with either sort of quotes
+ # There must be no $ in the string for it to be a literal
+ next if $directive =~ /^(["'])[^\$]*[^\\]\1/;
+
+ # Special values always used for numbers
+ next if $directive =~ /^[ijkn]$/;
+ next if $directive =~ /^count$/;
+
+ # Params
+ next if $directive =~ /^Param\(/;
+
+ # Other functions guaranteed to return OK output
+ next if $directive =~ /^(time2str|GetBugLink)\(/;
+
+ # Safe Template Toolkit virtual methods
+ next if $directive =~ /\.(size)$/;
+
+ # Special Template Toolkit loop variable
+ next if $directive =~ /^loop\.(index|count)$/;
+
+ # Things which are already filtered
+ # Note: If a single directive prints two things, and only one is
+ # filtered, we may not catch that case.
+ next if $directive =~ /FILTER\ (html|csv|js|url_quote|quoteUrls|
+ time|uri|xml)/x;
+
+ # Exclude those on the nofilter list
+ if (defined($safe{$file}{$directive})) {
+ $safe{$file}{$directive}++;
+ next;
+ };
+
+ # This intentionally makes no effort to eliminate duplicates; to do
+ # so would merely make it more likely that the user would not
+ # escape all instances when attempting to correct an error.
+ push(@unfiltered, "$lineno:$directive");
+ }
+
+ my $fullpath = File::Spec->catfile($path, $file);
+
+ if (@unfiltered) {
+ my $uflist = join("\n ", @unfiltered);
+ ok(0, "($lang) $fullpath has unfiltered directives:\n $uflist\n--ERROR");
+ }
+ else {
+ # Find any members of the exclusion list which were not found
+ my @notfound;
+ foreach my $directive (keys %{$safe{$file}}) {
+ push(@notfound, $directive) if ($safe{$file}{$directive} == 0);
+ }
+
+ if (@notfound) {
+ my $nflist = join("\n ", @notfound);
+ ok(0, "($lang) $fullpath - FEL has extra members:\n $nflist\n" .
+ "--WARNING");
+ }
+ else {
+ # Don't use the full path here - it's too long and unwieldy.
+ ok(1, "($lang) $file is filter-safe");
+ }
+ }
+ }
+}
+
+$/ = $oldrecsep;
+
+exit 0;
diff --git a/template/en/default/account/auth/login.html.tmpl b/template/en/default/account/auth/login.html.tmpl
index 6dbd6531f..f342b1791 100644
--- a/template/en/default/account/auth/login.html.tmpl
+++ b/template/en/default/account/auth/login.html.tmpl
@@ -34,7 +34,7 @@
I need a legitimate login and password to continue.
</p>
-<form action="[% target %]" method="POST">
+<form action="[% target FILTER html %]" method="POST">
<table>
<tr>
<td align="right">
diff --git a/template/en/default/attachment/edit.html.tmpl b/template/en/default/attachment/edit.html.tmpl
index 57d99f766..7cd682cd5 100644
--- a/template/en/default/attachment/edit.html.tmpl
+++ b/template/en/default/attachment/edit.html.tmpl
@@ -51,7 +51,7 @@
// If this is a plaintext document, remove cruft that Mozilla adds
// because it treats it as an HTML document with a big PRE section.
// http://bugzilla.mozilla.org/show_bug.cgi?id=86012
- var contentType = '[% contenttype %]';
+ var contentType = '[% contenttype FILTER js %]';
if ( contentType == 'text/plain' )
{
theContent = theContent.replace( /^<html><head\/?><body><pre>/i , "" );
diff --git a/template/en/default/bug/create/create-guided.html.tmpl b/template/en/default/bug/create/create-guided.html.tmpl
index a716ddca6..7ab7436a7 100644
--- a/template/en/default/bug/create/create-guided.html.tmpl
+++ b/template/en/default/bug/create/create-guided.html.tmpl
@@ -211,8 +211,10 @@ function PutDescription() {
<form method="post" action="post_bug.cgi">
<input type="hidden" name="format" value="guided">
<input type="hidden" name="assigned_to" value="">
- <input type="hidden" name="priority" value="[% default.priority %]">
- <input type="hidden" name="version" value="[% default.version %]">
+ <input type="hidden" name="priority"
+ value="[% default.priority FILTER html %]">
+ <input type="hidden" name="version"
+ value="[% default.version FILTER html %]">
<table valign="top" cellpadding="5" cellspacing="5" border="0">
diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl
index c59cd3a70..fcc894e1e 100644
--- a/template/en/default/bug/create/create.html.tmpl
+++ b/template/en/default/bug/create/create.html.tmpl
@@ -107,7 +107,8 @@
[% sel = { description => 'Priority', name => 'priority' } %]
[% INCLUDE select %]
[% ELSE %]
- <input type="hidden" name="priority" value="[% default.priority %]">
+ <input type="hidden" name="priority"
+ value="[% default.priority FILTER html %]">
[% END %]
[% sel = { description => 'Severity', name => 'bug_severity' } %]
diff --git a/template/en/default/bug/create/make-template.html.tmpl b/template/en/default/bug/create/make-template.html.tmpl
index 1e2495ff8..958d183cc 100644
--- a/template/en/default/bug/create/make-template.html.tmpl
+++ b/template/en/default/bug/create/make-template.html.tmpl
@@ -25,7 +25,7 @@
%]
<p>
-If you bookmark <a href="enter_bug.cgi?[% url %]">this link</a>,
+If you bookmark <a href="enter_bug.cgi?[% url FILTER html %]">this link</a>,
going to the bookmark will bring up the enter bug page with the fields
initialized as you've requested.
</p>
diff --git a/template/en/default/bug/show-multiple.html.tmpl b/template/en/default/bug/show-multiple.html.tmpl
index a5cdc4dc8..41d824eb3 100644
--- a/template/en/default/bug/show-multiple.html.tmpl
+++ b/template/en/default/bug/show-multiple.html.tmpl
@@ -106,7 +106,8 @@
<tr>
<td colspan="4">
<b>URL:</b>&nbsp;
- <a href="[% bug.bug_file_loc %]">[% bug.bug_file_loc FILTER html %]</a>
+ <a href="[% bug.bug_file_loc FILTER html %]">
+ [% bug.bug_file_loc FILTER html %]</a>
</tr>
<tr>
diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl
new file mode 100644
index 000000000..b462b7bcc
--- /dev/null
+++ b/template/en/default/filterexceptions.pl
@@ -0,0 +1,597 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# 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 are the Bugzilla tests.
+#
+# The Initial Developer of the Original Code is Jacob Steenhagen.
+# Portions created by Jacob Steenhagen are
+# Copyright (C) 2001 Jacob Steenhagen. All
+# Rights Reserved.
+#
+# Contributor(s): Gervase Markham <gerv@gerv.net>
+
+# Important! The following classes of directives are excluded in the test,
+# and so do not need to be added here. Doing so will cause warnings.
+# See 008filter.t for more details.
+#
+# Comments - [%#...
+# Directives - [% IF|ELSE|UNLESS|FOREACH...
+# Assignments - [% foo = ...
+# Simple literals - [% " selected" ...
+# Values always used for numbers - [% (i|j|k|n|count) %]
+# Params - [% Param(...
+# Safe functions - [% (time2str|GetBugLink)...
+# Safe vmethods - [% foo.size %]
+# TT loop variables - [% loop.count %]
+# Already-filtered stuff - [% wibble FILTER html %]
+# where the filter is one of html|csv|js|url_quote|quoteUrls|time|uri|xml
+
+# Key:
+#
+# "#": directive should be filtered, but not doing so is not a security hole
+# The plan is to come back and add filtering for all those marked "#" after
+# the security release.
+#
+# "# Email": as above; but noting that it's an email address.
+# Other sorts of comments denote cleanups noticed while doing this work;
+# they should be fixed in the very short term.
+
+%::safe = (
+
+'sidebar.xul.tmpl' => [
+ 'template_version',
+],
+
+'flag/list.html.tmpl' => [
+ 'flag.id',
+ 'flag.status',
+ 'type.id',
+],
+
+'search/boolean-charts.html.tmpl' => [
+ '"field${chartnum}-${rownum}-${colnum}"',
+ '"value${chartnum}-${rownum}-${colnum}"',
+ '"type${chartnum}-${rownum}-${colnum}"',
+ 'field.name',
+ 'field.description',
+ 'type.name',
+ 'type.description',
+ '"${chartnum}-${rownum}-${newor}"',
+ '"${chartnum}-${newand}-0"',
+ 'newchart',
+ 'jsmagic',
+],
+
+'search/form.html.tmpl' => [
+ 'qv.value',
+ 'qv.name',
+ 'qv.description',
+ 'field.name',
+ 'field.description',
+ 'field.accesskey',
+ 'sel.name',
+ 'sel.accesskey',
+ 'button_name', #
+],
+
+'search/knob.html.tmpl' => [
+ 'button_name', #
+],
+
+'search/search-report-graph.html.tmpl' => [
+ 'button_name', #
+],
+
+'search/search-report-table.html.tmpl' => [
+ 'button_name', #
+],
+
+'request/queue.html.tmpl' => [
+ 'column_headers.$group_field',
+ 'column_headers.$column',
+ 'request.status',
+ 'request.bug_id',
+ 'request.attach_id',
+],
+
+'reports/components.html.tmpl' => [
+ 'numcols',
+ 'numcols - 1',
+ 'comp.description',
+ 'comp.initialowner', # email address
+ 'comp.initialqacontact', # email address
+],
+
+'reports/duplicates-simple.html.tmpl' => [
+ 'title', #
+],
+
+'reports/duplicates-table.html.tmpl' => [
+ '"&maxrows=$maxrows" IF maxrows',
+ '"&changedsince=$changedsince" IF changedsince',
+ '"&product=$product" IF product', #
+ '"&format=$format" IF format', #
+ '"&bug_id=$bug_ids_string&sortvisible=1" IF sortvisible',
+ 'column.name',
+ 'column.description',
+ 'vis_bug_ids.push(bug.id)',
+ 'bug.id',
+ 'bug.count',
+ 'bug.delta',
+ 'bug.component', #
+ 'bug.bug_severity', #
+ 'bug.op_sys', #
+ 'bug.target_milestone', #
+],
+
+'reports/duplicates.html.tmpl' => [
+ 'bug_ids_string',
+ 'maxrows',
+ 'changedsince',
+ 'reverse',
+],
+
+'reports/keywords.html.tmpl' => [
+ 'keyword.description',
+ 'keyword.bugcount',
+],
+
+'reports/report-table.csv.tmpl' => [
+ '"$tbl_field_disp: $tbl\n" IF tbl_field', #
+ 'row_field_disp IF row_field', #
+ 'col_field_disp', #
+ 'num_bugs',
+ 'data.$tbl.$col.$row',
+ '', # This is not a bug in the filter exceptions - this template has an
+ # empty directive which is necessary for it to work properly.
+],
+
+'reports/report-table.html.tmpl' => [
+ 'buglistbase',
+ '"&amp;$tbl_vals" IF tbl_vals',
+ '"&amp;$col_vals" IF col_vals',
+ '"&amp;$row_vals" IF row_vals',
+ 'tbl_disp', #
+ 'classes.$row_idx.$col_idx',
+ 'urlbase',
+ 'data.$tbl.$col.$row',
+ 'row_total',
+ 'col_totals.$col',
+ 'grand_total',
+],
+
+'reports/report.html.tmpl' => [
+ 'tbl_field_disp IF tbl_field', #
+ 'row_field_disp IF row_field', #
+ 'col_field_disp', #
+ 'imagebase',
+ 'width',
+ 'height',
+ 'imageurl',
+ 'formaturl',
+ 'other_format.name',
+ 'other_format.description', #
+ 'sizeurl',
+ 'height + 100',
+ 'height - 100',
+ 'width + 100',
+ 'width - 100',
+ 'switchbase',
+ 'format',
+ 'cumulate',
+],
+
+'reports/duplicates.rdf.tmpl' => [
+ 'template_version',
+ 'bug.id',
+ 'bug.count',
+ 'bug.delta',
+],
+
+'list/change-columns.html.tmpl' => [
+ 'column',
+ 'field_descs.${column} || column', #
+],
+
+'list/edit-multiple.html.tmpl' => [
+ 'group.id',
+ 'group.description',
+ 'group.description FILTER strike',
+ 'knum',
+ 'menuname',
+],
+
+'list/list-simple.html.tmpl' => [
+ 'title',
+],
+
+'list/list.html.tmpl' => [
+ 'buglist',
+ 'bugowners', # email address
+],
+
+'list/list.rdf.tmpl' => [
+ 'template_version',
+ 'bug.bug_id',
+ 'column',
+],
+
+'list/table.html.tmpl' => [
+ 'id',
+ 'splitheader ? 2 : 1',
+ 'abbrev.$id.title || field_descs.$id || column.title', #
+ 'tableheader',
+ 'bug.bug_severity', #
+ 'bug.priority', #
+ 'bug.bug_id',
+],
+
+'list/list.csv.tmpl' => [
+ 'bug.bug_id',
+],
+
+'list/list.js.tmpl' => [
+ 'bug.bug_id',
+],
+
+'global/help.html.tmpl' => [
+ 'h.id',
+ 'h.html',
+],
+
+'global/banner.html.tmpl' => [
+ 'VERSION',
+],
+
+'global/choose-product.html.tmpl' => [
+ 'target',
+ 'proddesc.$p',
+],
+
+'global/code-error.html.tmpl' => [
+ 'parameters',
+ 'bug.bug_id',
+ 'field',
+ 'argument', #
+ 'function', #
+ 'bug_id', # Need to remove unused error no_bug_data
+ 'variables.id',
+ 'template_error_msg', # Should move filtering from CGI.pl to template
+ 'error',
+ 'error_message',
+],
+
+'global/header.html.tmpl' => [
+ 'javascript',
+ 'style',
+ 'style_url',
+ 'bgcolor',
+ 'onload',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'message',
+],
+'global/hidden-fields.html.tmpl' => [
+ 'mvalue | html | html_linebreak', # Need to eliminate | usage
+ 'field.value | html | html_linebreak',
+],
+
+'global/messages.html.tmpl' => [
+ 'parameters',
+ '# ---', # Work out what this is
+ 'namedcmd', #
+ 'old_email', # email address
+ 'new_email', # email address
+ 'message_tag',
+],
+
+'global/select-menu.html.tmpl' => [
+ 'options',
+ 'onchange', # Again, need to be certain where we are filtering
+ 'size',
+],
+
+'global/useful-links.html.tmpl' => [
+ 'email',
+ 'user.login', # Email address
+],
+
+# Need to change this and code-error to use a no-op filter, for safety
+'global/user-error.html.tmpl' => [
+ 'disabled_reason',
+ 'bug_link',
+ 'action', #
+ 'bug_id',
+ 'both',
+ 'filesize',
+ 'attach_id',
+ 'field',
+ 'field_descs.$field',
+ 'today',
+ 'product', #
+ 'max',
+ 'votes',
+ 'error_message',
+],
+
+'global/confirm-user-match.html.tmpl' => [
+ '# use the global field descs', # Need to fix commenting style here
+ 'script',
+ '# this is messy to allow later expansion',
+ '# ELSIF for things that don\'t belong in the field_descs hash here',
+ 'fields.${field_name}.flag_type.name',
+],
+
+'global/site-navigation.html.tmpl' => [
+ 'bug_list.first',
+ 'bug_list.$prev_bug',
+ 'bug_list.$next_bug',
+ 'bug_list.last',
+ 'bug.bug_id',
+ 'bug.votes',
+ 'PerformSubsts(Param(\'mybugstemplate\'), substs)',
+],
+
+'bug/comments.html.tmpl' => [
+ 'comment.isprivate',
+ 'comment.when',
+],
+
+'bug/dependency-graph.html.tmpl' => [
+ 'image_map', # We need to continue to make sure this is safe in the CGI
+ 'image_url',
+ 'map_url',
+ 'bug_id',
+],
+
+'bug/dependency-tree.html.tmpl' => [
+ 'hide_resolved ? "Open b" : "B"',
+ 'bugid',
+ 'maxdepth',
+ 'dependson_ids.join(",")',
+ 'blocked_ids.join(",")',
+ 'dep_id',
+ 'hide_resolved ? 0 : 1',
+ 'hide_resolved ? "Show" : "Hide"',
+ 'realdepth < 2 || maxdepth == 1 ? "disabled" : ""',
+ 'hide_resolved',
+ 'realdepth < 2 ? "disabled" : ""',
+ 'maxdepth + 1',
+ 'maxdepth == 0 || maxdepth == realdepth ? "disabled" : ""',
+ 'realdepth < 2 || ( maxdepth && maxdepth < 2 ) ? "disabled" : ""',
+ 'maxdepth > 0 && maxdepth <= realdepth ? maxdepth : ""',
+ 'maxdepth == 1 ? 1
+ : ( maxdepth ? maxdepth - 1 : realdepth - 1 )',
+ 'realdepth < 2 || ! maxdepth || maxdepth >= realdepth ?
+ "disabled" : ""',
+],
+
+'bug/edit.html.tmpl' => [
+ 'bug.remaining_time',
+ 'bug.delta_ts',
+ 'bug.bug_id',
+ 'bug.votes',
+ 'group.bit',
+ 'group.description',
+ 'knum',
+ 'dep.title',
+ 'dep.fieldname',
+ 'accesskey',
+ 'bug.${dep.fieldname}.join(\', \')',
+ 'selname',
+ 'depbug FILTER bug_link(depbug)',
+ '"bug ${bug.dup_id}" FILTER bug_link(bug.dup_id)',
+],
+
+'bug/navigate.html.tmpl' => [
+ 'this_bug_idx + 1',
+ 'bug_list.first',
+ 'bug_list.last',
+ 'bug_list.$prev_bug',
+ 'bug_list.$next_bug',
+],
+
+'bug/show-multiple.html.tmpl' => [
+ 'bug.bug_id',
+ 'bug.component', #
+ 'attr.description', #
+],
+
+'bug/show.xml.tmpl' => [
+ 'VERSION',
+ 'a.attachid',
+ 'field',
+],
+
+'bug/time.html.tmpl' => [
+ 'time_unit FILTER format(\'%.1f\')',
+ 'time_unit FILTER format(\'%.2f\')',
+ '(act / (act + rem)) * 100
+ FILTER format("%d")',
+],
+
+'bug/votes/list-for-bug.html.tmpl' => [
+ 'voter.count',
+ 'total',
+],
+
+'bug/votes/list-for-user.html.tmpl' => [
+ 'product.maxperbug',
+ 'bug.id',
+ 'bug.count',
+ 'product.total',
+ 'product.maxvotes',
+],
+# h2 = voting_user.name # Email
+
+'bug/process/confirm-duplicate.html.tmpl' => [
+ 'original_bug_id',
+ 'duplicate_bug_id',
+],
+
+'bug/process/midair.html.tmpl' => [
+ 'bug_id',
+],
+
+'bug/process/next.html.tmpl' => [
+ 'bug.bug_id',
+],
+
+'bug/process/results.html.tmpl' => [
+ 'title.$type',
+ 'id',
+],
+
+'bug/process/verify-new-product.html.tmpl' => [
+ 'form.product', #
+],
+
+'bug/process/bugmail.html.tmpl' => [
+ 'description',
+ 'name', # Email
+],
+
+'bug/create/comment.txt.tmpl' => [
+ 'form.comment',
+],
+
+'bug/create/create.html.tmpl' => [
+ 'default.bug_status', #
+ 'g.bit',
+ 'g.description',
+ 'sel.name',
+ 'sel.description',
+],
+
+'bug/create/create-guided.html.tmpl' => [
+ 'matches.0',
+ 'tablecolour',
+ 'product', #
+ 'buildid',
+ 'sel',
+],
+
+'bug/activity/show.html.tmpl' => [
+ 'bug_id',
+],
+
+'bug/activity/table.html.tmpl' => [
+ 'operation.who', # Email
+ 'change.attachid',
+ 'change.field',
+],
+
+'attachment/create.html.tmpl' => [
+ 'bugid',
+ 'attachment.id',
+],
+
+'attachment/created.html.tmpl' => [
+ 'attachid',
+ 'bugid',
+ 'contenttype',
+],
+
+'attachment/edit.html.tmpl' => [
+ 'attachid',
+ 'bugid',
+ 'a',
+],
+
+'attachment/list.html.tmpl' => [
+ 'attachment.attachid',
+ 'FOR flag = attachment.flags', # Bug? No FOR directive
+ 'flag.type.name',
+ 'flag.status',
+ 'flag.requestee.nick', # Email
+ 'show_attachment_flags ? 4 : 3',
+ 'bugid',
+],
+
+'attachment/show-multiple.html.tmpl' => [
+ 'a.attachid',
+],
+
+'attachment/updated.html.tmpl' => [
+ 'attachid',
+ 'bugid',
+],
+
+'admin/products/groupcontrol/confirm-edit.html.tmpl' => [
+ 'group.count',
+],
+
+'admin/products/groupcontrol/edit.html.tmpl' => [
+ 'filt_product',
+ 'group.bugcount',
+ 'group.id',
+ 'const.CONTROLMAPNA',
+ 'const.CONTROLMAPSHOWN',
+ 'const.CONTROLMAPDEFAULT',
+ 'const.CONTROLMAPMANDATORY',
+],
+
+'admin/flag-type/confirm-delete.html.tmpl' => [
+ 'flag_count',
+ 'name', #
+ 'flag_type.id',
+],
+
+'admin/flag-type/edit.html.tmpl' => [
+ 'action',
+ 'type.id',
+ 'type.target_type',
+ 'category', #
+ 'item', #
+ 'type.sortkey || 1',
+ '(last_action == "enter" || last_action == "copy") ? "Create" : "Save Changes"',
+],
+
+'admin/flag-type/list.html.tmpl' => [
+ 'type.is_active ? "active" : "inactive"',
+ 'type.id',
+ 'type.flag_count',
+],
+
+'account/login.html.tmpl' => [
+ 'target',
+],
+
+'account/prefs/account.html.tmpl' => [
+ 'login_change_date', #
+],
+
+'account/prefs/email.html.tmpl' => [
+ 'watchedusers', # Email
+ 'useqacontact ? \'5\' : \'4\'',
+ 'role',
+ 'reason.name',
+ 'reason.description',
+],
+
+'account/prefs/permissions.html.tmpl' => [
+ 'bit_description.name',
+ 'bit_description.desc',
+],
+
+'account/prefs/prefs.html.tmpl' => [
+ 'tab.name',
+ 'tab.description',
+ 'current_tab.name',
+ 'current_tab.description',
+ 'current_tab.description FILTER lower',
+],
+
+);
+
+# Should filter reports/report.html.tmpl:130 $format
diff --git a/template/en/default/global/choose-product.html.tmpl b/template/en/default/global/choose-product.html.tmpl
index de0ca0be7..e79f7820d 100644
--- a/template/en/default/global/choose-product.html.tmpl
+++ b/template/en/default/global/choose-product.html.tmpl
@@ -41,7 +41,7 @@
<tr>
<th align="right" valign="top">
<a href="[% target %]?product=[% p FILTER url_quote %]
- [%- "&amp;format=$format" IF format %]">
+ [% IF format %]&amp;format=[% format FILTER url_quote %][% END %]">
[% p FILTER html %]</a>:
</th>
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index b35bbb064..92836f4db 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.html.tmpl
@@ -86,7 +86,7 @@
[% ELSIF error == "field_type_mismatch" %]
Cannot seem to handle <code>[% field %]</code>
- and <code>[% type %]</code> together.
+ and <code>[% type FILTER html %]</code> together.
[% ELSIF error == "gd_not_installed" %]
Charts will not work without the GD Perl module being installed.
diff --git a/template/en/default/global/hidden-fields.html.tmpl b/template/en/default/global/hidden-fields.html.tmpl
index f968fab20..a824c3489 100644
--- a/template/en/default/global/hidden-fields.html.tmpl
+++ b/template/en/default/global/hidden-fields.html.tmpl
@@ -32,11 +32,11 @@
[% NEXT IF exclude && field.key.search(exclude) %]
[% IF mform.${field.key}.size > 1 %]
[% FOREACH mvalue = mform.${field.key} %]
- <input type="hidden" name="[% field.key %]"
+ <input type="hidden" name="[% field.key FILTER html %]"
value="[% mvalue | html | html_linebreak %]">
[% END %]
[% ELSE %]
- <input type="hidden" name="[% field.key %]"
+ <input type="hidden" name="[% field.key FILTER html %]"
value="[% field.value | html | html_linebreak %]">
[% END %]
[% END %]
diff --git a/template/en/default/global/message.html.tmpl b/template/en/default/global/message.html.tmpl
index f6cb321c6..58cd56908 100644
--- a/template/en/default/global/message.html.tmpl
+++ b/template/en/default/global/message.html.tmpl
@@ -34,7 +34,7 @@
[%# Display a URL if the calling script or message block has included one. %]
[% IF url && link %]
<p>
- <a href="[% url %]">[% link %]</a>
+ <a href="[% url FILTER html %]">[% link FILTER html %]</a>
</p>
[% END %]
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index fe1d9e223..934c0511f 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -235,7 +235,7 @@
[% ELSIF error == "illegal_date" %]
[% title = "Your Query Makes No Sense" %]
- '<tt>[% date %]</tt>' is not a legal date.
+ '<tt>[% date FILTER html %]</tt>' is not a legal date.
[% ELSIF error == "illegal_email_address" %]
[% title = "Invalid Email Address" %]
@@ -290,6 +290,11 @@
in your browser. To help us fix this limitation, add your comments to
<a href="http://bugzilla.mozilla.org/show_bug.cgi?id=70907">bug 70907</a>.
+ [% ELSIF error == "invalid_changedsince" %]
+ [% title = "Invalid 'Changed Since'" %]
+ The 'changed since' value, '[% changedsince FILTER html %]', must be an
+ integer >= 0.
+
[% ELSIF error == "invalid_content_type" %]
[% title = "Invalid Content-Type" %]
The content type <em>[% contenttype FILTER html %]</em> is invalid.
@@ -355,7 +360,7 @@
[% ELSIF error == "missing_email_type" %]
[% title = "Your Query Makes No Sense" %]
You must specify one or more fields in which to search for
- <tt>[% email %]</tt>.
+ <tt>[% email FILTER html %]</tt>.
[% ELSIF error == "missing_query" %]
[% title = "Missing Query" %]
diff --git a/template/en/default/list/change-columns.html.tmpl b/template/en/default/list/change-columns.html.tmpl
index 097a886bb..7730bf78c 100644
--- a/template/en/default/list/change-columns.html.tmpl
+++ b/template/en/default/list/change-columns.html.tmpl
@@ -36,7 +36,7 @@
[% field_descs.qa_contact_realname = "QA Contact Realname" %]
<form action="colchange.cgi">
- <input type="hidden" name="rememberedquery" value="[% buffer %]">
+ <input type="hidden" name="rememberedquery" value="[% buffer FILTER html %]">
[% FOREACH column = masterlist %]
<input type="checkbox" id="[% column %]" name="column_[% column %]"
[% "checked='checked'" IF lsearch(collist, column) != -1 %]>
@@ -65,7 +65,7 @@
</form>
<form action="colchange.cgi">
- <input type="hidden" name="rememberedquery" value="[% buffer %]">
+ <input type="hidden" name="rememberedquery" value="[% buffer FILTER html %]">
<input type="hidden" name="resetit" value="1">
<input type="submit" value="Reset to Bugzilla default">
</form>
diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl
index 9b9f099d3..91a5584cf 100644
--- a/template/en/default/list/list.html.tmpl
+++ b/template/en/default/list/list.html.tmpl
@@ -95,7 +95,7 @@
<p>
<a href="query.cgi">Query Page</a>
&nbsp;&nbsp;<a href="enter_bug.cgi">Enter New Bug</a>
- <a href="query.cgi?[% urlquerypart %]">Edit this query</a>
+ <a href="query.cgi?[% urlquerypart FILTER html %]">Edit this query</a>
</p>
[% ELSIF bugs.size == 1 %]
@@ -133,11 +133,13 @@
<input type="hidden" name="buglist" value="[% buglist %]">
<input type="submit" value="Long Format">
&nbsp;&nbsp;
- <a href="buglist.cgi?[% urlquerypart %]&amp;ctype=csv">CSV</a> &nbsp;&nbsp;
- <a href="colchange.cgi?[% urlquerypart %]">Change Columns</a> &nbsp;&nbsp;
+ <a href="buglist.cgi?
+ [% urlquerypart FILTER html %]&amp;ctype=csv">CSV</a> &nbsp;&nbsp;
+ <a href="colchange.cgi?
+ [% urlquerypart FILTER html %]">Change Columns</a> &nbsp;&nbsp;
[% IF bugs.size > 1 && caneditbugs && !dotweak %]
- <a href="buglist.cgi?[% urlquerypart %]
+ <a href="buglist.cgi?[% urlquerypart FILTER html %]
[%- "&order=$qorder" FILTER html IF order %]&amp;tweak=1">Change Several
Bugs at Once</a>
&nbsp;&nbsp;
@@ -147,7 +149,8 @@
<a href="mailto:[% bugowners %]">Send Mail to Bug Owners</a> &nbsp;&nbsp;
[% END %]
- <a href="query.cgi?[% urlquerypart %]">Edit this Query</a> &nbsp;&nbsp;
+ <a href="query.cgi?
+ [% urlquerypart FILTER html %]">Edit this Query</a> &nbsp;&nbsp;
</form>
diff --git a/template/en/default/list/table.html.tmpl b/template/en/default/list/table.html.tmpl
index 8a5d3ac57..53eb52b2d 100644
--- a/template/en/default/list/table.html.tmpl
+++ b/template/en/default/list/table.html.tmpl
@@ -82,7 +82,8 @@
<tr align="left">
<th colspan="[% splitheader ? 2 : 1 %]">
- <a href="buglist.cgi?[% urlquerypart %]&amp;order=bugs.bug_id">ID</a>
+ <a href="buglist.cgi?
+ [% urlquerypart FILTER html %]&amp;order=bugs.bug_id">ID</a>
</th>
[% IF splitheader %]
@@ -115,7 +116,7 @@
[% BLOCK columnheader %]
<th colspan="[% splitheader ? 2 : 1 %]">
- <a href="buglist.cgi?[% urlquerypart %]&amp;order=
+ <a href="buglist.cgi?[% urlquerypart FILTER html %]&amp;order=
[% column.name FILTER url_quote FILTER html %]
[% ",$qorder" FILTER html IF order %]">
[%- abbrev.$id.title || field_descs.$id || column.title -%]</a>
diff --git a/template/en/default/reports/duplicates.html.tmpl b/template/en/default/reports/duplicates.html.tmpl
index ce4d07001..a522c4db7 100644
--- a/template/en/default/reports/duplicates.html.tmpl
+++ b/template/en/default/reports/duplicates.html.tmpl
@@ -58,7 +58,7 @@
<h3><a name="params">Change Parameters</a></h3>
<form method="get" action="duplicates.cgi">
- <input type="hidden" name="sortby" value="[% sortby %]">
+ <input type="hidden" name="sortby" value="[% sortby FILTER html %]">
<input type="hidden" name="reverse" value="[% reverse %]">
<input type="hidden" name="bug_id" value="[% bug_ids_string %]">
<table>
diff --git a/template/en/default/search/form.html.tmpl b/template/en/default/search/form.html.tmpl
index 0b80bdb26..efc5dd0b2 100644
--- a/template/en/default/search/form.html.tmpl
+++ b/template/en/default/search/form.html.tmpl
@@ -330,7 +330,7 @@ function selectProduct(f) {
[% PROCESS "global/field-descs.none.tmpl" %]
[%# If we resubmit to ourselves, we need to know if we are using a format. %]
-<input type="hidden" name="query_format" value="[% format %]">
+<input type="hidden" name="query_format" value="[% format FILTER html %]">
[%# *** Summary *** %]