]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 206037: [SECURITY] Fix escaping/quoting in edit*.cgi scripts - Patch by Frédéric...
authorlpsolit%gmail.com <>
Sun, 15 Oct 2006 03:37:48 +0000 (03:37 +0000)
committerlpsolit%gmail.com <>
Sun, 15 Oct 2006 03:37:48 +0000 (03:37 +0000)
22 files changed:
Bugzilla/Constants.pm
Bugzilla/Template.pm
Bugzilla/Util.pm
checksetup.pl
editcomponents.cgi
editgroups.cgi
editmilestones.cgi
editproducts.cgi
editusers.cgi
editversions.cgi
globals.pl
t/008filter.t
template/en/default/account/prefs/permissions.html.tmpl
template/en/default/admin/keywords/list.html.tmpl
template/en/default/bug/create/create.html.tmpl
template/en/default/bug/edit.html.tmpl
template/en/default/filterexceptions.pl
template/en/default/global/choose-product.html.tmpl
template/en/default/list/edit-multiple.html.tmpl
template/en/default/list/list-simple.html.tmpl
template/en/default/reports/components.html.tmpl
template/en/default/reports/keywords.html.tmpl

index ea8d246da5fc93496a29fc0744a5207c887d75f2..631176fc8b70e03811540cbbec95c0626d39a9dc 100644 (file)
@@ -57,6 +57,8 @@ use base qw(Exporter);
     GRANT_DIRECT
     GRANT_DERIVED
     GRANT_REGEXP
+
+    SAFE_PROTOCOLS
 );
 
 @Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
@@ -191,4 +193,9 @@ use constant GRANT_DIRECT => 0;
 use constant GRANT_DERIVED => 1;
 use constant GRANT_REGEXP => 2;
 
+# Protocols which are considered as safe.
+use constant SAFE_PROTOCOLS => ('afs', 'cid', 'ftp', 'gopher', 'http', 'https',
+                                'irc', 'mid', 'news', 'nntp', 'prospero', 'telnet',
+                                'view-source', 'wais');
+
 1;
index a25e95f1ef48ce5b0b39183daca9228e890b7640..c0e0bd6107c1aef083145dcac8c1bde51844cf7d 100644 (file)
@@ -319,7 +319,9 @@ sub create {
                 $var =~ s/\@/\&#64;/g;
                 return $var;
             },
-            
+
+            html_light => \&Bugzilla::Util::html_light_quote,
+
             # iCalendar contentline filter
             ics => [ sub {
                          my ($context, @args) = @_;
index bbbdc0f2fb1ae43e4fc3512e00d4595b573749cf..9713bbbcf554480633048b379d0d6ed5a537142c 100644 (file)
@@ -31,10 +31,11 @@ use base qw(Exporter);
 @Bugzilla::Util::EXPORT = qw(is_tainted trick_taint detaint_natural
                              detaint_signed
                              html_quote url_quote value_quote xml_quote
-                             css_class_quote
+                             css_class_quote html_light_quote
                              lsearch max min
                              trim format_time clean_text);
 
+use Bugzilla::Constants;
 use Bugzilla::Config;
 
 # This is from the perlsec page, slightly modifed to remove a warning
@@ -80,6 +81,93 @@ sub html_quote {
     return $var;
 }
 
+sub html_light_quote {
+    my ($text) = @_;
+
+    # List of allowed HTML elements having no attributes.
+    my @allow = qw(b strong em i u p br abbr acronym ins del cite code var
+                   dfn samp kbd big small sub sup tt dd dt dl ul li ol);
+
+    # Are HTML::Scrubber and HTML::Parser installed?
+    eval { require HTML::Scrubber;
+           require HTML::Parser;
+    };
+
+    # We need utf8_mode() from HTML::Parser 3.40 if running Perl >= 5.8.
+    if ($@ || ($] >= 5.008 && $HTML::Parser::VERSION < 3.40)) { # Package(s) not installed.
+        my $safe = join('|', @allow);
+        my $chr = chr(1);
+
+        # First, escape safe elements.
+        $text =~ s#<($safe)>#$chr$1$chr#go;
+        $text =~ s#</($safe)>#$chr/$1$chr#go;
+        # Now filter < and >.
+        $text =~ s#<#&lt;#g;
+        $text =~ s#>#&gt;#g;
+        # Restore safe elements.
+        $text =~ s#$chr/($safe)$chr#</$1>#go;
+        $text =~ s#$chr($safe)$chr#<$1>#go;
+        return $text;
+    }
+    else { # Packages installed.
+        # We can be less restrictive. We can accept elements with attributes.
+        push(@allow, qw(a blockquote q span));
+
+        # Allowed protocols.
+        my $safe_protocols = join('|', SAFE_PROTOCOLS);
+        my $protocol_regexp = qr{(^(?:$safe_protocols):|^[^:]+$)}i;
+
+        # Deny all elements and attributes unless explicitly authorized.
+        my @default = (0 => {
+                             id    => 1,
+                             name  => 1,
+                             class => 1,
+                             '*'   => 0, # Reject all other attributes.
+                            }
+                       );
+
+        # Specific rules for allowed elements. If no specific rule is set
+        # for a given element, then the default is used.
+        my @rules = (a => {
+                           href  => $protocol_regexp,
+                           title => 1,
+                           id    => 1,
+                           name  => 1,
+                           class => 1,
+                           '*'   => 0, # Reject all other attributes.
+                          },
+                     blockquote => {
+                                    cite => $protocol_regexp,
+                                    id    => 1,
+                                    name  => 1,
+                                    class => 1,
+                                    '*'  => 0, # Reject all other attributes.
+                                   },
+                     'q' => {
+                             cite => $protocol_regexp,
+                             id    => 1,
+                             name  => 1,
+                             class => 1,
+                             '*'  => 0, # Reject all other attributes.
+                          },
+                    );
+
+        my $scrubber = HTML::Scrubber->new(default => \@default,
+                                           allow   => \@allow,
+                                           rules   => \@rules,
+                                           comment => 0,
+                                           process => 0);
+
+        # Avoid filling the web server error log with Perl 5.8.x.
+        # In HTML::Scrubber 0.08, the HTML::Parser object is stored in
+        # the "_p" key, but this may change in future versions.
+        if ($] >= 5.008 && ref($scrubber->{_p}) eq 'HTML::Parser') {
+            $scrubber->{_p}->utf8_mode(1);
+        }
+        return $scrubber->scrub($text);
+    }
+}
+
 # This orignally came from CGI.pm, by Lincoln D. Stein
 sub url_quote {
     my ($toencode) = (@_);
@@ -294,6 +382,12 @@ be done in the template where possible.
 Returns a value quoted for use in HTML, with &, E<lt>, E<gt>, and E<34> being
 replaced with their appropriate HTML entities.
 
+=item C<html_light_quote($val)>
+
+Returns a string where only explicitly allowed HTML elements and attributes
+are kept. All HTML elements and attributes not being in the whitelist are either
+escaped (if HTML::Scrubber is not installed) or removed.
+
 =item C<url_quote($val)>
 
 Quotes characters so that they may be included as part of a url.
index e632c0fac2cd4fff3b39853f50705305d658fab5..ac8e98a9ee7a2cecf124da50001db56bf90b0a50 100755 (executable)
@@ -347,6 +347,8 @@ my $xmlparser   = have_vers("XML::Parser",0);
 my $gdgraph     = have_vers("GD::Graph",0);
 my $gdtextalign = have_vers("GD::Text::Align",0);
 my $patchreader = have_vers("PatchReader","0.9.4");
+my $html_parser = have_vers("HTML::Parser", ($] >= 5.008) ? "3.40" : 0);
+my $scrubber    = have_vers("HTML::Scrubber", 0);
 
 print "\n" unless $silent;
 
@@ -386,6 +388,15 @@ if (!$patchreader && !$silent) {
     print "install the \nPatchReader module:\n";
     print "PatchReader: " . install_command("PatchReader") . "\n";
 }
+if ((!$scrubber || !$html_parser) && !$silent) {
+    print "If you want additional HTML tags within product and group ";
+    print "descriptions,\nyou should install:\n";
+    print "HTML::Scrubber: " . install_command("HTML::Scrubber") . "\n"
+        if !$scrubber;
+    print "HTML::Parser: " . install_command("HTML::Parser") . "\n"
+        if !$html_parser;
+    print "\n";
+}
 
 if (%missing) {
     print "\n\n";
index 81d2ee9837d356d539ae85cf73197d0271f84e7b..5a1f125af7c6f3bb2deb478dd2f7671d98e7a46f 100755 (executable)
@@ -77,7 +77,7 @@ sub CheckProduct ($)
     }
 
     unless (TestProduct $prod) {
-        print "Sorry, product '$prod' does not exist.";
+        print "Sorry, product '" . html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -109,7 +109,8 @@ sub CheckComponent ($$)
     CheckProduct($prod);
 
     unless (TestComponent $prod,$comp) {
-        print "Sorry, component '$comp' for product '$prod' does not exist.";
+        print "Sorry, component '" . html_quote($comp) . "' for product '" .
+              html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -255,8 +256,8 @@ unless ($product) {
         my ($product, $description, $bugs) = FetchSQLData();
         $description ||= "<FONT COLOR=\"red\">missing</FONT>";
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
-        print "  <TD VALIGN=\"top\">$description</TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "\"><B>", html_quote($product), "</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_light_quote($description) . "</TD>\n";
         if ($dobugcounts) {
             $bugs ||= "none";
             print "  <TD VALIGN=\"top\">$bugs</TD>\n";
@@ -312,10 +313,10 @@ unless ($action) {
         my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "<FONT COLOR=\"red\">missing</FONT>";
         my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "<FONT COLOR=\"red\">missing</FONT>";
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=edit\"><B>$component</B></A></TD>\n";
-        print "  <TD VALIGN=\"top\">$desc</TD>\n";
-        print "  <TD VALIGN=\"top\">$initialowner</TD>\n";
-        print "  <TD VALIGN=\"top\">$initialqacontact</TD>\n"
+        print "  <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=edit\"><B>", html_quote($component), "</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_light_quote($desc) . "</TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_quote($initialowner) . "</TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_quote($initialqacontact) . "</TD>\n"
                 if Param('useqacontact');
         if ($dobugcounts) {
             $bugs ||= 'none';
@@ -391,7 +392,7 @@ if ($action eq 'new') {
         exit;
     }
     if (TestComponent($product,$component)) {
-        print "The component '$component' already exists. Please press\n";
+        print "The component '" . html_quote($component) . "' already exists. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -406,7 +407,8 @@ if ($action eq 'new') {
     my $description = trim($::FORM{description} || '');
 
     if ($description eq '') {
-        print "You must enter a description for the component '$component'. Please press\n";
+        print "You must enter a description for the component '" .
+              html_quote($component) . "'. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -415,7 +417,8 @@ if ($action eq 'new') {
     my $initialowner = trim($::FORM{initialowner} || '');
 
     if ($initialowner eq '') {
-        print "You must enter an initial owner for the component '$component'. Please press\n";
+        print "You must enter an initial owner for the component '" .
+              html_quote($component) . "'. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -423,8 +426,8 @@ if ($action eq 'new') {
 
     my $initialownerid = DBname_to_id ($initialowner);
     if (!$initialownerid) {
-        print "You must use an existing Bugzilla account as initial owner for the component
-'$component'. Please press\n";
+        print "You must use an existing Bugzilla account as initial owner for the component'" .
+              html_quote($component) . "'. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -434,7 +437,8 @@ if ($action eq 'new') {
     my $initialqacontactid = DBname_to_id ($initialqacontact);
     if (Param('useqacontact')) {
         if (!$initialqacontactid && $initialqacontact ne '') {
-            print "You must use an existing Bugzilla account as initial QA contact for the component '$component'. Please press\n";
+            print "You must use an existing Bugzilla account as initial QA contact for the component '" .
+                  html_quote($component) . "'. Please press\n";
             print "<b>Back</b> and try again.\n";
             PutTrailer($localtrailer);
             exit;
@@ -533,7 +537,8 @@ if ($action eq 'del') {
 
     my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "<FONT COLOR=\"red\">missing</FONT>";
     my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "<FONT COLOR=\"red\">missing</FONT>";
-    my $milestonelink = $milestoneurl ? "<A HREF=\"$milestoneurl\">$milestoneurl</A>"
+    my $milestonelink = $milestoneurl ? '<A HREF="' . html_quote($milestoneurl) . '">' .
+                                        html_quote($milestoneurl) . '</A>'
                                       : "<FONT COLOR=\"red\">missing</FONT>";
     $pdesc            ||= "<FONT COLOR=\"red\">missing</FONT>";
     $disallownew        = $disallownew ? 'closed' : 'open';
@@ -545,20 +550,20 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Component:</TD>\n";
-    print "  <TD VALIGN=\"top\">$component</TD>";
+    print "  <TD VALIGN=\"top\">" . html_quote($component) . "</TD>";
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Component description:</TD>\n";
-    print "  <TD VALIGN=\"top\">$cdesc</TD>";
+    print "  <TD VALIGN=\"top\">" . html_light_quote($cdesc) . "</TD>";
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Initial owner:</TD>\n";
-    print "  <TD VALIGN=\"top\">$initialowner</TD>";
+    print "  <TD VALIGN=\"top\">" . html_quote($initialowner) . "</TD>";
 
     if (Param('useqacontact')) {
         print "</TR><TR>\n";
         print "  <TD VALIGN=\"top\">Initial QA contact:</TD>\n";
-        print "  <TD VALIGN=\"top\">$initialqacontact</TD>";
+        print "  <TD VALIGN=\"top\">" . html_quote($initialqacontact) . "</TD>";
     }
     SendSQL("SELECT count(bug_id)
              FROM bugs
@@ -566,11 +571,11 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Component of product:</TD>\n";
-    print "  <TD VALIGN=\"top\">$product</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($product) . "</TD>\n";
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Description:</TD>\n";
-    print "  <TD VALIGN=\"top\">$pdesc</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_light_quote($pdesc) . "</TD>\n";
 
     if (Param('usetargetmilestone')) {
          print "</TR><TR>\n";
@@ -837,7 +842,7 @@ if ($action eq 'update') {
             exit;
         }
         if (TestComponent($product,$component)) {
-            print "Sorry, component name '$component' is already in use.";
+            print "Sorry, component name '" . html_quote($component) . "' is already in use.";
             PutTrailer($localtrailer);
             exit;
         }
index de7185ae16114262c4f739a8cd50b575f60b10bf..2d4911ec74e135dcc80cf213a8e535ed16e92908 100755 (executable)
@@ -22,7 +22,7 @@
 #                 Joel Peshkin <bugreport@peshkin.net>
 #                 Jacob Steenhagen <jake@bugzilla.org>
 #                 Vlad Dascalu <jocuri@softhome.net>
-#                 Frédéric Buclin <LpSolit@gmail.com>
+#                 Frédéric Buclin <LpSolit@gmail.com>
 
 # Code derived from editowners.cgi and editusers.cgi
 
@@ -222,7 +222,7 @@ unless ($action) {
         my ($groupid, $name, $desc, $regexp, $isactive, $isbuggroup) = FetchSQLData();
         print "<tr>\n";
         print "<td>" . html_quote($name) . "</td>\n";
-        print "<td>" . html_quote($desc) . "</td>\n";
+        print "<td>" . html_light_quote($desc) . "</td>\n";
         print "<td>" . html_quote($regexp) . "&nbsp</td>\n";
         print "<td align=center>";
         print "X" if (($isactive != 0) && ($isbuggroup != 0));
@@ -291,7 +291,7 @@ if ($action eq 'changeform') {
     }
     print "</TD></TR><TR><TH>Description:</TH><TD>";
     if ($isbuggroup == 0) {
-        print html_quote($description);
+        print html_light_quote($description);
     } else {
         print "<INPUT TYPE=HIDDEN NAME=\"olddesc\" VALUE=\"" .
         html_quote($description) . "\">
@@ -356,7 +356,7 @@ if ($action eq 'changeform') {
         print "<TD><INPUT TYPE=checkbox NAME=\"grp-$grpid\" $grpchecked VALUE=1>";
         print "<INPUT TYPE=HIDDEN NAME=\"oldgrp-$grpid\" VALUE=$grpmember></TD>";
         print "<TD><B>" . html_quote($grpnam) . "</B></TD>";
-        print "<TD>" . html_quote($grpdesc) . "</TD>";
+        print "<TD>" . html_light_quote($grpdesc) . "</TD>";
         print "</TR>\n";
     }
 
@@ -487,8 +487,8 @@ if ($action eq 'del') {
     print "</tr>\n";
     print "<tr>\n";
     print "<td>$gid</td>\n";
-    print "<td>$name</td>\n";
-    print "<td>$desc</td>\n";
+    print "<td>" . html_quote($name) . "</td>\n";
+    print "<td>" . html_light_quote($desc) . "</td>\n";
     print "</tr>\n";
     print "</table>\n";
 
@@ -529,10 +529,10 @@ group before checking the box.<P>
     if (MoreSQLData()) {
        $cantdelete = 1;
        print "
-<B>This group is tied to the <U>$name</U> product.
+<B>This group is tied to the <U>" . html_quote($name) . "</U> product.
 You cannot delete this group while it is tied to a product.</B><BR>
 <INPUT TYPE=CHECKBOX NAME=\"unbind\">Delete this group anyway, and make the
-<U>$name</U> product publicly visible.<BR>
+<U>" . html_quote($name) . "</U> product publicly visible.<BR>
 ";
     }
 
@@ -746,14 +746,14 @@ sub confirmRemove {
         print "<a href=\"editgroups.cgi\">return to the Edit Groups page</a>\n";
         return;
     }
-    print "from group $::FORM{name}.<p>\n";
+    print "from group " . html_quote($::FORM{name}) . ".<p>\n";
     print "Generally, you will only need to do this when upgrading groups ";
     print "created with Bugzilla versions 2.16 and prior. Use this option ";
     print "with <b>extreme care</b> and consult the Bugzilla Guide for ";
     print "further information.<p>\n";
     
     print "<FORM METHOD=POST ACTION=editgroups.cgi>\n";
-    print "<INPUT TYPE=HIDDEN NAME=\"group\" VALUE=$group>\n";
+    print "<INPUT TYPE=HIDDEN NAME=\"group\" VALUE=" . html_quote($group) . ">\n";
     
     if ($remove_regexp_only) {
         print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"remove_all_regexp\">\n";
index dce5e291d3eda1e76b7476f1adc9f4330baa150f..641e1026d9cbf9957c3fa1af0a997ba7e401eb2d 100755 (executable)
@@ -50,7 +50,7 @@ sub CheckProduct ($)
     }
 
     unless (TestProduct $prod) {
-        print "Sorry, product '$prod' does not exist.";
+        print "Sorry, product '" . html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -81,7 +81,8 @@ sub CheckMilestone ($$)
     CheckProduct($prod);
 
     unless (TestMilestone $prod,$mile) {
-        print "Sorry, milestone '$mile' for product '$prod' does not exist.";
+        print "Sorry, milestone '" . html_quote($mile) . "' for product '" .
+              html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -209,8 +210,8 @@ unless ($product) {
         my ($product, $description) = FetchSQLData();
         $description ||= "<FONT COLOR=\"red\">missing</FONT>";
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
-        print "  <TD VALIGN=\"top\">$description</TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\"><B>", html_quote($product), "</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_light_quote($description) . "</TD>\n";
     }
     print "</TR></TABLE>\n";
 
@@ -244,7 +245,7 @@ unless ($action) {
         my ($milestone,$sortkey,$bugs) = FetchSQLData();
         $bugs ||= 'none';
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=edit\"><B>$milestone</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=edit\"><B>", html_quote($milestone), "</B></A></TD>\n";
         #print "  <TD VALIGN=\"top\">$bugs</TD>\n";
         print "  <TD VALIGN=\"top\" ALIGN=\"right\">$sortkey</TD>\n";
         print "  <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=del\"><B>Delete</B></A></TD>\n";
@@ -314,7 +315,7 @@ if ($action eq 'new') {
     $sortkey = CheckSortkey($milestone,$sortkey);
 
     if (TestMilestone($product,$milestone)) {
-        print "The milestone '$milestone' already exists. Please press\n";
+        print "The milestone '" . html_quote($milestone) . "' already exists. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -330,7 +331,8 @@ if ($action eq 'new') {
     unlink "$datadir/versioncache";
 
     print "OK, done.<p>\n";
-    PutTrailer("<A HREF=\"editmilestones.cgi?product=$product&amp;action=add\">add</a> another milestone or $localtrailer");
+    PutTrailer("<A HREF=\"editmilestones.cgi?product=" . url_quote($product) .
+               "&amp;action=add\">add</a> another milestone or $localtrailer");
     exit;
 }
 
@@ -366,10 +368,10 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Product:</TH>\n";
-    print "  <TD VALIGN=\"top\">$product</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($product) . "</TD>\n";
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Milestone:</TH>\n";
-    print "  <TD VALIGN=\"top\">$milestone</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($milestone) . "</TD>\n";
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
     print "  <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
@@ -545,7 +547,7 @@ if ($action eq 'update') {
             exit;
         }
         if (TestMilestone($product,$milestone)) {
-            print "Sorry, milestone '$milestone' is already in use.";
+            print "Sorry, milestone '" . html_quote($milestone) . "' is already in use.";
             PutTrailer($localtrailer);
             exit;
         }
index b3e8fe04173d7f3a5330916e271d28431d2c8779..c9a5f149f31eb29cdeaea0f5f8113a1e8a823f51 100755 (executable)
@@ -80,7 +80,7 @@ sub CheckProduct ($)
     }
 
     unless (TestProduct $prod) {
-        print "Sorry, product '$prod' does not exist.";
+        print "Sorry, product '" . html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -231,8 +231,8 @@ unless ($action) {
         $disallownew = $disallownew ? 'closed' : 'open';
         $bugs        ||= 'none';
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=edit&product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
-        print "  <TD VALIGN=\"top\">$description</TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=edit&product=", url_quote($product), "\"><B>", html_quote($product), "</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_light_quote($description) . "</TD>\n";
         print "  <TD VALIGN=\"top\">$disallownew</TD>\n";
         print "  <TD VALIGN=\"top\" ALIGN=\"right\">$votesperuser</TD>\n";
         print "  <TD VALIGN=\"top\" ALIGN=\"right\">$maxvotesperbug</TD>\n";
@@ -308,7 +308,7 @@ if ($action eq 'new') {
         exit;
     }
     if (TestProduct($product)) {
-        print "The product '$product' already exists. Please press\n";
+        print "The product '" . html_quote($product) . "' already exists. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -317,7 +317,7 @@ if ($action eq 'new') {
     my $version = trim($::FORM{version} || '');
 
     if ($version eq '') {
-        print "You must enter a version for product '$product'. Please press\n";
+        print "You must enter a version for product '" . html_quote($product) . "'. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -460,7 +460,8 @@ if ($action eq 'del') {
              FROM products
              WHERE name=" . SqlQuote($product));
     my ($product_id, $description, $milestoneurl, $disallownew) = FetchSQLData();
-    my $milestonelink = $milestoneurl ? "<a href=\"$milestoneurl\">$milestoneurl</a>"
+    my $milestonelink = $milestoneurl ? '<a href="' . html_quote($milestoneurl) .'">' .
+                                        html_quote($milestoneurl) . '</a>'
                                       : "<font color=\"red\">missing</font>";
     $description ||= "<FONT COLOR=\"red\">description missing</FONT>";
     $disallownew = $disallownew ? 'closed' : 'open';
@@ -472,11 +473,11 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Product:</TD>\n";
-    print "  <TD VALIGN=\"top\">$product</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($product) . "</TD>\n";
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Description:</TD>\n";
-    print "  <TD VALIGN=\"top\">$description</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_light_quote($description) . "</TD>\n";
 
     if (Param('usetargetmilestone')) {
         print "</TR><TR>\n";
@@ -500,8 +501,8 @@ if ($action eq 'del') {
         while ( MoreSQLData() ) {
             my ($component, $description) = FetchSQLData();
             $description ||= "<FONT COLOR=\"red\">description missing</FONT>";
-            print "<tr><th align=right valign=top>$component:</th>";
-            print "<td valign=top>$description</td></tr>\n";
+            print "<tr><th align=right valign=top>" . html_quote($component) . ":</th>";
+            print "<td valign=top>" . html_light_quote($description) . "</td></tr>\n";
         }
         print "</table>\n";
     } else {
@@ -520,7 +521,7 @@ if ($action eq 'del') {
         while ( MoreSQLData() ) {
             my ($version) = FetchSQLData();
             print "<BR>" if $br;
-            print $version;
+            print html_quote($version);
             $br = 1;
         }
     } else {
@@ -543,7 +544,7 @@ if ($action eq 'del') {
             while ( MoreSQLData() ) {
                 my ($milestone) = FetchSQLData();
                 print "<BR>" if $br;
-                print $milestone;
+                print html_quote($milestone);
                 $br = 1;
             }
         } else {
@@ -672,7 +673,7 @@ if ($action eq 'delete') {
 
     SendSQL("DELETE FROM products
              WHERE id=$product_id");
-    print "Product '$product' deleted.<BR>\n";
+    print "Product '" . html_quote($product) . "' deleted.<BR>\n";
 
     unlink "$datadir/versioncache";
     PutTrailer($localtrailer);
@@ -718,8 +719,8 @@ if ($action eq 'edit') {
         while ( MoreSQLData() ) {
             my ($component, $description) = FetchSQLData();
             $description ||= "<FONT COLOR=\"red\">description missing</FONT>";
-            print "<tr><th align=right valign=top>$component:</th>";
-            print "<td valign=top>$description</td></tr>\n";
+            print "<tr><th align=right valign=top>" . html_quote($component) . ":</th>";
+            print "<td valign=top>" . html_light_quote($description) . "</td></tr>\n";
         }
         print "</table>\n";
     } else {
@@ -739,7 +740,7 @@ if ($action eq 'edit') {
         while ( MoreSQLData() ) {
             my ($version) = FetchSQLData();
             print "<BR>" if $br;
-            print $version;
+            print html_quote($version);
             $br = 1;
         }
     } else {
@@ -762,7 +763,7 @@ if ($action eq 'edit') {
             while ( MoreSQLData() ) {
                 my ($milestone) = FetchSQLData();
                 print "<BR>" if $br;
-                print $milestone;
+                print html_quote($milestone);
                 $br = 1;
             }
         } else {
@@ -1168,7 +1169,7 @@ if ($action eq 'update') {
                 "WHERE value = " . SqlQuote($defaultmilestone) .
                 "  AND product_id = $product_id");
         if (!FetchOneColumn()) {
-            print "Sorry, the milestone $defaultmilestone must be defined first.";
+            print "Sorry, the milestone " . html_quote($defaultmilestone) . " must be defined first.";
             PutTrailer($localtrailer);
             exit;
         }
@@ -1188,7 +1189,7 @@ if ($action eq 'update') {
             exit;
         }
         if (TestProduct($product)) {
-            print "Sorry, product name '$product' is already in use.";
+            print "Sorry, product name '" . html_quote($product) . "' is already in use.";
             PutTrailer($localtrailer);
             exit;
         }
@@ -1217,7 +1218,8 @@ if ($action eq 'update') {
                 my ($who, $id) = (@$ref);
                 RemoveVotes($id, $who, "The rules for voting on this product has changed;\nyou had too many votes for a single bug.");
                 my $name = DBID_to_name($who);
-                print qq{<br>Removed votes for bug <A HREF="show_bug.cgi?id=$id">$id</A> from $name\n};
+                print "<br>Removed votes for bug <A HREF=\"show_bug.cgi?id=$id\">$id</A> from " .
+                      html_quote($name) . "\n";
             }
         }
 
@@ -1249,7 +1251,8 @@ if ($action eq 'update') {
                     RemoveVotes($id, $who,
                                 "The rules for voting on this product has changed; you had too many\ntotal votes, so all votes have been removed.");
                     my $name = DBID_to_name($who);
-                    print qq{<br>Removed votes for bug <A HREF="show_bug.cgi?id=$id">$id</A> from $name\n};
+                    print "<br>Removed votes for bug <A HREF=\"show_bug.cgi?id=$id\">$id</A> from " .
+                          html_quote($name) . "\n";
                 }
             }
         }
@@ -1346,10 +1349,10 @@ if ($action eq 'editgroupcontrols') {
         print "</TR>\n";
         my ($groupid, $groupname, $entry, $membercontrol, $othercontrol, 
             $canedit) = FetchSQLData();
-        print "<TR id=\"row_$groupname\" class=\"hstyle\" ";
-        print "onload=\"document.row.row_$groupname.color=green\">\n";
+        print "<TR id=\"row_" . html_quote($groupname) . "\" class=\"hstyle\" ";
+        print "onload=\"document.row.row_" . html_quote($groupname) . ".color=green\">\n";
         print "  <TD>\n";
-        print "    $groupname\n";
+        print "    " . html_quote($groupname) . "\n";
         print "  </TD><TD>\n";
         $entry |= 0;
         print "    <INPUT TYPE=CHECKBOX NAME=\"entry_$groupid\" VALUE=1";
@@ -1407,14 +1410,14 @@ if ($action eq 'editgroupcontrols') {
             "ORDER BY name");
     while (MoreSQLData()) {
         my ($groupid, $groupname) = FetchSQLData();
-        print "<OPTION VALUE=\"$groupid\">$groupname</OPTION>\n";
+        print "<OPTION VALUE=\"$groupid\">" . html_quote($groupname) . "</OPTION>\n";
     }
     print "</SELECT><BR><BR>\n";
 
     print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
     print "<INPUT TYPE=RESET>\n";
     print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"updategroupcontrols\">\n";
-    print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"$product\">\n";
+    print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" . html_quote($product) . "\">\n";
     print "</FORM>\n";
     print "<P>note: Any group controls Set to NA/NA with no other checkboxes ";
     print "will automatically be removed from the panel the next time ";
index c7701656bd983ccc3a2972324ff24e7a348d0e63..2ec9e87e8accf5592690a4f90fcc32b214c08364 100755 (executable)
@@ -76,7 +76,7 @@ sub CheckUser ($)
     }
 
     unless (TestUser $user) {
-        print "Sorry, user '$user' does not exist.";
+        print "Sorry, user '" . html_quote($user) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -87,6 +87,7 @@ sub CheckUser ($)
 sub EmitElement ($$)
 {
     my ($name, $value) = (@_);
+    $name = html_quote($name);
     $value = value_quote($value);
     if ($editall) {
         print qq{<TD><INPUT SIZE=64 MAXLENGTH=255 NAME="$name" VALUE="$value"></TD>\n};
@@ -193,7 +194,7 @@ sub EmitFormElements ($$$$)
                 print ']' if ($isderived);
                 print '*' if ($isregexp);
                 print "</TD><TD><B>";
-                print ucfirst($name) . "</B>: $description</TD>\n";
+                print html_quote(ucfirst($name)) . "</B>: " . html_light_quote($description) . "</TD>\n";
             }
         }
         print "</TR></TABLE></TD>\n";
@@ -466,7 +467,7 @@ if ($action eq 'new') {
         exit;
     }
     if (!ValidateNewUser($user)) {
-        print "The user '$user' does already exist. Please press\n";
+        print "The user '" . html_quote($user) . "' does already exist. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -490,7 +491,7 @@ if ($action eq 'new') {
     SendSQL("SELECT last_insert_id()");
     my ($newuserid) = FetchSQLData();
 
-    print "To change ${user}'s permissions, go back and " .
+    print "To change " . html_quote($user) . "'s permissions, go back and " .
         "<a href=\"editusers.cgi?action=edit&user=" . url_quote($user) .
         "\">edit</a> this user.";
     print "<p>\n";
@@ -535,7 +536,7 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Login name:</TD>\n";
-    print "  <TD VALIGN=\"top\">$user</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($user) . "</TD>\n";
 
     print "</TR><TR>\n";
     print "  <TD VALIGN=\"top\">Real name:</TD>\n";
@@ -554,7 +555,7 @@ if ($action eq 'del') {
     while ( MoreSQLData() ) {
         my ($name) = FetchSQLData();
         print "<br>\n" if $found;
-        print ucfirst $name;
+        print html_quote(ucfirst($name));
         $found = 1;
     }
     print "none" unless $found;
@@ -580,7 +581,7 @@ if ($action eq 'del') {
         my ($product, $component) = FetchSQLData();
         print "<a href=\"editcomponents.cgi?product=", url_quote($product),
                 "&component=", url_quote($component),
-                "&action=edit\">$product: $component</a>";
+                "&action=edit\">" . html_quote($product) . ": " . html_quote($component) . "</a>";
         $found    = 1;
         $nodelete = 'initial bug owner';
     }
@@ -605,7 +606,7 @@ if ($action eq 'del') {
         my ($product, $component) = FetchSQLData();
         print "<a href=\"editcomponents.cgi?product=", url_quote($product),
                 "&component=", url_quote($component),
-                "&action=edit\">$product: $component</a>";
+                "&action=edit\">" . html_quote($product) . ": " . html_quote($component) . "</a>";
         $found    = 1;
         $nodelete = 'initial QA contact';
     }
@@ -615,7 +616,7 @@ if ($action eq 'del') {
 
 
     if ($nodelete) {
-        print "<P>You can't delete this user because '$user' is an $nodelete ",
+        print "<P>You can't delete this user because '" . html_quote($user) . "' is an $nodelete ",
               "for at least one product.";
         PutTrailer($localtrailer);
         exit;
@@ -628,7 +629,7 @@ if ($action eq 'del') {
     print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
     print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
     print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
-    print "<INPUT TYPE=HIDDEN NAME=\"user\" VALUE=\"$user\">\n";
+    print "<INPUT TYPE=HIDDEN NAME=\"user\" VALUE=\"" . html_quote($user) . "\">\n";
     print "</FORM>";
 
     PutTrailer($localtrailer);
@@ -700,8 +701,8 @@ if ($action eq 'edit') {
     EmitFormElements($thisuserid, $user, $realname, $disabledtext);
     
     print "</TR></TABLE>\n";
-    print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"$user\">\n";
-    print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"$realname\">\n";
+    print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"" . html_quote($user) . "\">\n";
+    print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"" . html_quote($realname) . "\">\n";
     print "<INPUT TYPE=HIDDEN NAME=\"disabledtextold\" VALUE=\"" .
         value_quote($disabledtext) . "\">\n";
     print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
@@ -720,7 +721,7 @@ if ($action eq 'edit') {
         print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
         print "<INPUT TYPE=SUBMIT VALUE=\"Delete User\">\n";
         print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"del\">\n";
-        print "<INPUT TYPE=HIDDEN NAME=\"user\" VALUE=\"$user\">\n";
+        print "<INPUT TYPE=HIDDEN NAME=\"user\" VALUE=\"" . html_quote($user) . "\">\n";
         print "</FORM>";
     }
 
@@ -777,10 +778,10 @@ if ($action eq 'update') {
                 SendSQL("INSERT INTO user_group_map 
                          (user_id, group_id, isbless, grant_type)
                          VALUES ($thisuserid, $groupid, 0," . GRANT_DIRECT . ")");
-                print "Added user to group $name<BR>\n";
+                print "Added user to group " . html_quote($name) . "<BR>\n";
                 push(@grpadd, $name);
             } else {
-                print "Dropped user from group $name<BR>\n";
+                print "Dropped user from group " . html_quote($name) . "<BR>\n";
                 push(@grpdel, $name);
             }
             PopGlobalSQLState();
@@ -797,9 +798,9 @@ if ($action eq 'update') {
                 SendSQL("INSERT INTO user_group_map 
                          (user_id, group_id, isbless, grant_type)
                          VALUES ($thisuserid, $groupid, 1," . GRANT_DIRECT . ")");
-                print "Granted user permission to bless group $name<BR>\n";
+                print "Granted user permission to bless group " . html_quote($name) . "<BR>\n";
             } else {
-                print "Revoked user's permission to bless group $name<BR>\n";
+                print "Revoked user's permission to bless group " . html_quote($name) . "<BR>\n";
             }
             PopGlobalSQLState();
             
@@ -859,7 +860,7 @@ if ($action eq 'update') {
             exit;
         }
         if (TestUser($user)) {
-            print "Sorry, user name '$user' is already in use.";
+            print "Sorry, user name '" . html_quote($user) . "' is already in use.";
             $userold = url_quote($userold);
             $localtrailer =~ s/XXX/$userold/;
             push @localtrailers, $localtrailer;
index c426891edf2ea349e690fa90ce9c0ad237f46682..b74338c8963f5937f78e5335e799fddadfc028f8 100755 (executable)
@@ -63,7 +63,7 @@ sub CheckProduct ($)
     }
 
     unless (TestProduct $prod) {
-        print "Sorry, product '$prod' does not exist.";
+        print "Sorry, product '" . html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -94,7 +94,8 @@ sub CheckVersion ($$)
     CheckProduct($prod);
 
     unless (TestVersion $prod,$ver) {
-        print "Sorry, version '$ver' for product '$prod' does not exist.";
+        print "Sorry, version '" . html_quote($ver) . "' for product '" .
+              html_quote($prod) . "' does not exist.";
         PutTrailer();
         exit;
     }
@@ -206,8 +207,8 @@ unless ($product) {
         $description ||= "<FONT COLOR=\"red\">missing</FONT>";
         $bugs ||= "none";
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
-        print "  <TD VALIGN=\"top\">$description</TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "\"><B>", html_quote($product), "</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\">" . html_light_quote($description) . "</TD>\n";
         print "  <TD VALIGN=\"top\">$bugs</TD>\n";
         #print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?action=edit&product=", url_quote($product), "\">Edit</A></TD>\n";
     }
@@ -239,7 +240,7 @@ unless ($action) {
     while ( MoreSQLData() ) {
         my $version = FetchOneColumn();
         print "<TR>\n";
-        print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "&version=", url_quote($version), "&action=edit\"><B>$version</B></A></TD>\n";
+        print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "&version=", url_quote($version), "&action=edit\"><B>" . html_quote($version) . "</B></A></TD>\n";
         #print "  <TD VALIGN=\"top\">$bugs</TD>\n";
         print "  <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "&version=", url_quote($version), "&action=del\"><B>Delete</B></A></TD>\n";
         print "</TR>";
@@ -305,7 +306,7 @@ if ($action eq 'new') {
         exit;
     }
     if (TestVersion($product,$version)) {
-        print "The version '$version' already exists. Please press\n";
+        print "The version '" . html_quote($version) . "' already exists. Please press\n";
         print "<b>Back</b> and try again.\n";
         PutTrailer($localtrailer);
         exit;
@@ -321,7 +322,8 @@ if ($action eq 'new') {
     unlink "$datadir/versioncache";
 
     print "OK, done.<p>\n";
-    PutTrailer("<A HREF=\"editversions.cgi?product=$product&amp;action=add\">add</a> another version or $localtrailer");
+    PutTrailer("<A HREF=\"editversions.cgi?product=" . url_quote($product) .
+               "&amp;action=add\">add</a> another version or $localtrailer");
     exit;
 }
 
@@ -352,10 +354,10 @@ if ($action eq 'del') {
 
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Product:</TH>\n";
-    print "  <TD VALIGN=\"top\">$product</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($product) . "</TD>\n";
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Version:</TH>\n";
-    print "  <TD VALIGN=\"top\">$version</TD>\n";
+    print "  <TD VALIGN=\"top\">" . html_quote($version) . "</TD>\n";
     print "</TR><TR>\n";
     print "  <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
     print "  <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
@@ -512,7 +514,7 @@ if ($action eq 'update') {
             exit;
         }
         if (TestVersion($product,$version)) {
-            print "Sorry, version '$version' is already in use.";
+            print "Sorry, version '" . html_quote($version) . "' is already in use.";
             PutTrailer($localtrailer);
             exit;
         }
index e01ef23fb2973dabfa86097aaf8b90801b5e4d0d..d403a03f8fc9a89eb9ea4b4fbd2a67cd7eda7f38 100644 (file)
@@ -915,7 +915,8 @@ sub quoteUrls {
     my $tmp;
 
     # non-mailto protocols
-    my $protocol_re = qr/(afs|cid|ftp|gopher|http|https|irc|mid|news|nntp|prospero|telnet|view-source|wais)/i;
+    my $safe_protocols = join('|', SAFE_PROTOCOLS);
+    my $protocol_re = qr/($safe_protocols)/i;
 
     $text =~ s~\b(${protocol_re}:  # The protocol:
                   [^\s<>\"]+       # Any non-whitespace
index 02456e73a53dda134c1e6cebcd1ba8121f72fe62..71006c85ce839976b9285389cf6834a6aceafb80 100644 (file)
@@ -219,7 +219,7 @@ sub directive_ok {
     # Note: If a single directive prints two things, and only one is 
     # filtered, we may not catch that case.
     return 1 if $directive =~ /FILTER\ (html|csv|js|url_quote|css_class_quote|
-                                        ics|quoteUrls|time|uri|xml|lower|
+                                        ics|quoteUrls|time|uri|xml|lower|html_light|
                                         obsolete|inactive|closed|unitconvert|
                                         none)\b/x;
 
index 46d4559ec866874bf1e37b31467dd252c14fce38..77cc70999f7ae28de96a8ad2501617775cfd0b00 100644 (file)
@@ -42,8 +42,8 @@
         <table align="center">
           [% FOREACH bit_description = has_bits %]
             <tr>
-              <td>[% bit_description.name %]</td>
-              <td>[% bit_description.desc %]</td>
+              <td>[% bit_description.name FILTER html %]</td>
+              <td>[% bit_description.desc FILTER html_light %]</td>
             </tr>
           [% END %]
         </table>
@@ -63,8 +63,8 @@
           <table align="center">
           [% FOREACH bit_description = set_bits %]
             <tr>
-              <td>[% bit_description.name %]</td>
-              <td>[% bit_description.desc %]</td>
+              <td>[% bit_description.name FILTER html %]</td>
+              <td>[% bit_description.desc FILTER html_light %]</td>
             </tr>
           [% END %]
           </table>
index fbfc921429e57861ab2c1d65d6052b01eaaea52e..8df11262febb06ec1290736ad78c4fb1a10d3f33 100755 (executable)
   #
   # Contributor(s): Terry Weissman <terry@mozilla.org>
   #                 Vlad Dascalu <jocuri@softhome.net>
-  #                 Jouni Heikniemi <jouni@heikniemi.net>
   #%]
 
 [%# INTERFACE:
+  # max_table_size: number. Determines the maximum number of
+  #                 rows in each keywords table.
   # keywords: array with keyword objects having the properties:
-  #   - id: number. The ID of the keyword.
+  #   - keyword_id: number. The ID of the keyword.
   #   - name: string. The name of the keyword.
   #   - description: string. The description of the keyword.
   #   - bug_count: number. The number of bugs with the keyword.
   title = "Select keyword"
 %]
 
-[% columns = [
-     { 
-       name => "name"
-       heading => "Edit keyword..."
-       contentlink => "editkeywords.cgi?action=edit&amp;id=%id%" 
-     },
-     { 
-       name => "description"
-       heading => "Description" 
-     },
-     { 
-       name => "bug_count"
-       heading => "Bugs"
-       align => "right"
-     },
-     { 
-       heading => "Action" 
-       content => "Delete"
-       contentlink => "editkeywords.cgi?action=delete&amp;id=%id%"
-     }
-   ]
-%]
+[% max_table_size = 50 %]
 
-[% PROCESS admin/table.html.tmpl
-     columns = columns
-     data = keywords
-     footer = footer_row
-%]
+[% BLOCK table_header %]
+  <table border="1" cellpadding="4" cellspacing="0">
+    <tr bgcolor="#6666FF">
+      <th align="left">Edit keyword ...</th>
+      <th align="left">Description</th>
+      <th align="left">[% terms.Bugs %]</th>
+      <th align="left">Action</th>
+    </tr>
+[% END %]
+
+[% BLOCK table_footer %]
+  </table>
+[% END %]
+
+[% PROCESS table_header %]
+
+[% FOREACH keyword = keywords %]
+  [% IF !loop.first() && loop.count() % max_table_size == 1 %]
+    [% PROCESS table_header %]
+  [% END %]
+
+  <tr>
+    <th valign="top">
+      <a href="editkeywords.cgi?action=edit&amp;id=[% keyword.id %]">[% keyword.name FILTER html %]</a>
+    </th>
+    <td valign="top">
+      [% IF keyword.description %]
+        [%  keyword.description FILTER html_light %]
+      [% ELSE %]
+        <font color="red">missing</font>
+      [% END %]
+    </td>
+    <td valign="top" align="right">
+      [% IF keyword.bug_count %]
+        [% keyword.bug_count %]
+      [% ELSE %]
+        none
+      [% END %]
+    </td>
+    <th valign="top">
+      <a href="editkeywords.cgi?action=delete&amp;id=[% keyword.id %]">Delete</a>
+    </th>
+  </tr>
+
+  [% IF !loop.last() && loop.count() % max_table_size == 0 %]
+    [% PROCESS table_footer %]
+  [% END %]
+[% END %]
+
+  <tr>
+    <td valign="top" colspan="3">Add a new keyword</td>
+    <td><a href="editkeywords.cgi?action=add">Add</a></td>
+  </tr>
 
-<p><a href="editkeywords.cgi?action=add">Add a new keyword</a></p>
+[% PROCESS table_footer %]
 
 [% PROCESS global/footer.html.tmpl %]
index 6745cd6f198f97a6e89f250b10c1c36300db094b..49162f3f8f336ec187affcd9c8a9bdf2b007a8e5 100644 (file)
@@ -306,7 +306,7 @@ function set_assign_to() {
         <input type="checkbox" id="bit-[% g.bit %]"
           name="bit-[% g.bit %]" value="1"
           [% " checked=\"checked\"" IF g.checked %]>
-          <label for="bit-[% g.bit %]">[% g.description %]</label><br>
+          <label for="bit-[% g.bit %]">[% g.description FILTER html_light %]</label><br>
       [% END %]
       <br>
     [% END %]
index fda1826964e5013baab45377619b908259e9ea95..d67afc8c8cadc7c20d08afc51b64c93b48de8c63 100644 (file)
       <input type="checkbox" name="bit-[% group.bit %]" value="1"
         [% " checked=\"checked\"" IF group.ison %]
         [% " disabled=\"disabled\"" IF NOT group.ingroup %]>
-      [% group.description %]
+      [% group.description FILTER html_light %]
       <br>
       [% END %]
     [% END %]
index 20c5a7823626c5570b6909a4e958d00350c09e7b..08f885175bbdc3ebf7c85213b34473668fdd6d88 100644 (file)
@@ -91,7 +91,6 @@
 
 'reports/components.html.tmpl' => [
   'numcols',
-  'comp.description', 
 ],
 
 'reports/duplicates-table.html.tmpl' => [
 ],
 
 'reports/keywords.html.tmpl' => [
-  'keyword.description', 
   'keyword.bugcount', 
 ],
 
 
 'list/edit-multiple.html.tmpl' => [
   'group.id', 
-  'group.description',
-  'group.description FILTER inactive', 
   'knum', 
   'menuname', 
 ],
 
-'list/list-simple.html.tmpl' => [
-  'title', 
-],
-
 'list/list.html.tmpl' => [
   'buglist', 
 ],
 
 'global/choose-product.html.tmpl' => [
   'target',
-  'proddesc.$p', 
 ],
 
 # You are not permitted to add any values here. Everything in this file should 
   'bug.bug_id', 
   'bug.votes', 
   'group.bit', 
-  'group.description', 
   'dep.title', 
   'dep.fieldname', 
   'accesskey', 
 
 'bug/create/create.html.tmpl' => [
   'g.bit',
-  'g.description',
   'sel.name',
   'sel.description',
 ],
   'reason.description',
 ],
 
-'account/prefs/permissions.html.tmpl' => [
-  'bit_description.name', 
-  'bit_description.desc', 
-],
-
 'account/prefs/prefs.html.tmpl' => [
   'tab.name', 
   'tab.description', 
index 138c354ae7c37f6dbe5e0778c1024bbbe557f4ed..ad9867919bb003b9822e5737875ec949abca90b8 100644 (file)
@@ -48,7 +48,7 @@
     </th>
 
     [% IF proddesc.$p %]
-      <td valign="top">&nbsp;[% proddesc.$p %]</td>
+      <td valign="top">&nbsp;[% proddesc.$p FILTER html_light %]</td>
     [% END %]
   </tr>
 [% END %]
index eda6d2fa183b506f84600a2caafa8ad64585c127..0b1f75e14164f5be19c05d36f28c05fe8ab2c12a 100644 (file)
       [% END %]
 
       <td>
-        [% IF group.isactive %]
-          [% group.description %]
-        [% ELSE %]
-          [% group.description FILTER inactive %]
-        [% END %]
+        [% SET inactive = !group.isactive %]
+        [% group.description FILTER html_light FILTER inactive(inactive) %]
       </td>
 
     </tr>
index 9c37e77f9502bb7eb7731e0f9f7d953286b94440..a25f42c1751c566106118a299d45f66164ee7240 100644 (file)
@@ -30,8 +30,6 @@
 [%############################################################################%]
 
 [% DEFAULT title = "$terms.Bug List" %]
-[% title = title FILTER html %]
-
 
 [%############################################################################%]
 [%# Bug Table                                                                #%]
@@ -40,7 +38,7 @@
 <html>
 
   <head>
-    <title>[% title %]</title>
+    <title>[% title FILTER html %]</title>
     <base href="[% Param("urlbase") %]">
     <link href="css/buglist.css" rel="stylesheet" type="text/css">
   </head>
index ae969171bf76a2672db72e9b9b56bd4fb3bc912f..c3a3ae5162e632a3d78be4ac9b6901df00f61428 100644 (file)
@@ -23,7 +23,7 @@
   # product: string. The product this is the components list for.
   # components: List of hashes. May be empty. Each hash has four members:
   #   name: string. Name of the component.
-  #   description: string. Description of the component. May contain HTML.
+  #   description: string. Description of the component. Can contain some limited HTML code.
   #   initialowner: string. Component's initial owner.
   #   initialqacontact: string. Component's initial QA contact.
   #%]
@@ -93,7 +93,7 @@
   </tr>
   <tr>
     <td colspan="[% numcols - 1 %]">
-      [% comp.description %]
+      [% comp.description FILTER html_light %]
     </td>
   </tr>
 [% END %]
index bd52cf6eca99c88a93847655057677024eceba9c..10bfe1e8730be514d9634132a049416a70062cd3 100644 (file)
@@ -22,7 +22,7 @@
 [%# INTERFACE:
   # keywords: array of hashes. May be empty. Each has has three members:
   #   name: the name of the keyword
-  #   description: keyword description. May be HTML.
+  #   description: keyword description. Can contain some limited HTML code.
   #   bugcount: number of bugs with that keyword
   # caneditkeywords: boolean. True if this user can edit keywords
  %]
@@ -52,7 +52,7 @@
       <a name="[% keyword.name FILTER html %]">
         [% keyword.name FILTER html %]</a>
     </th>
-    <td>[% keyword.description %]</td>
+    <td>[% keyword.description FILTER html_light %]</td>
     <td align="right">
       [% IF keyword.bugcount > 0 %]
         <a href="buglist.cgi?keywords=[% keyword.name FILTER url_quote %]">