]> 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:26:50 +0000 (03:26 +0000)
committerlpsolit%gmail.com <>
Sun, 15 Oct 2006 03:26:50 +0000 (03:26 +0000)
36 files changed:
Bugzilla/Constants.pm
Bugzilla/Install/Requirements.pm
Bugzilla/Template.pm
Bugzilla/Util.pm
skins/standard/editusers.css
t/008filter.t
template/en/default/account/prefs/permissions.html.tmpl
template/en/default/account/prefs/settings.html.tmpl
template/en/default/admin/classifications/del.html.tmpl
template/en/default/admin/classifications/edit.html.tmpl
template/en/default/admin/classifications/reclassify.html.tmpl
template/en/default/admin/classifications/select.html.tmpl
template/en/default/admin/components/confirm-delete.html.tmpl
template/en/default/admin/components/updated.html.tmpl
template/en/default/admin/groups/delete.html.tmpl
template/en/default/admin/groups/edit.html.tmpl
template/en/default/admin/groups/list.html.tmpl
template/en/default/admin/keywords/list.html.tmpl
template/en/default/admin/products/confirm-delete.html.tmpl
template/en/default/admin/products/edit-common.html.tmpl
template/en/default/admin/products/edit.html.tmpl
template/en/default/admin/products/updated.html.tmpl
template/en/default/admin/settings/edit.html.tmpl
template/en/default/admin/table.html.tmpl
template/en/default/admin/users/edit.html.tmpl
template/en/default/admin/users/list.html.tmpl
template/en/default/bug/create/create.html.tmpl
template/en/default/bug/edit.html.tmpl
template/en/default/bug/show-multiple.html.tmpl
template/en/default/filterexceptions.pl
template/en/default/global/choose-classification.html.tmpl
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 4ce2cbc0958722aac9992addbeeaf01e7cdb4d76..337405a6104fb506015f8166fdb284494828c04e 100644 (file)
@@ -123,6 +123,8 @@ use File::Basename;
     ON_WINDOWS
 
     MAX_TOKEN_AGE
+
+    SAFE_PROTOCOLS
 );
 
 @Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
@@ -302,6 +304,11 @@ use constant FIELD_TYPE_SINGLE_SELECT => 2;
 # The maximum number of days a token will remain valid.
 use constant MAX_TOKEN_AGE => 3;
 
+# 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');
+
 # States that are considered to be "open" for bugs.
 use constant BUG_STATE_OPEN => ('NEW', 'REOPENED', 'ASSIGNED', 
                                 'UNCONFIRMED');
index 06c8b557ba7c90d9cf4c0dc46bf8f4e88a8d73b0..7dddefd75a8b34a369efd57a04287168811b7bbb 100644 (file)
@@ -125,6 +125,18 @@ use constant OPTIONAL_MODULES => [
         name => 'SOAP::Lite',
         version => 0
     },
+    {
+        # Since Perl 5.8, we need the 'utf8_mode' method of HTML::Parser
+        # which has been introduced in version 3.39_92 and fixed in 3.40
+        # to not complain when running Perl 5.6.
+        # This module is required by HTML::Scrubber.
+        name => 'HTML::Parser',
+        version => ($] >= 5.008) ? '3.40' : 0
+    },
+    {
+        name => 'HTML::Scrubber',
+        version => 0
+    },
 ];
 
 # These are only required if you want to use Bugzilla with
@@ -305,6 +317,17 @@ sub check_requirements {
                   "    " . install_command('Net::LDAP') . "\n\n";
         }
 
+        # HTML filtering
+        if (!$have_mod{'HTML::Parser'} || !$have_mod{'HTML::Scrubber'}) {
+            print "If you want additional HTML tags within product and group",
+                  " descriptions,\nyou should install:\n\n";
+            print "    HTML::Scrubber: " . install_command('HTML::Scrubber') . "\n"
+                if !$have_mod{'HTML::Scrubber'};
+            print "    HTML::Parser: " . install_command('HTML::Parser') . "\n"
+                if !$have_mod{'HTML::Parser'};
+            print "\n";
+        }
+
         # mod_perl
         if (!$have_mod{'mod_perl2'}) {
             print "If you would like mod_perl support, you must install at",
index 7149828efa8ac73009ddb3824222bb6f15ffd6a5..915e3cdc6ba1107ba90bc2a45d67971cc36f25d3 100644 (file)
@@ -289,7 +289,8 @@ sub quoteUrls {
               ~egox;
 
     # 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
@@ -734,7 +735,9 @@ sub create {
                 }
                 return $var;
             },
-            
+
+            html_light => \&Bugzilla::Util::html_light_quote,
+
             # iCalendar contentline filter
             ics => [ sub {
                          my ($context, @args) = @_;
index 8457c8df83656798604b1fbd6c0286a61b9abff4..d346d254790180aa6a28af4289355c75ea109e20 100644 (file)
@@ -34,7 +34,7 @@ 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
                              i_am_cgi get_netaddr correct_urlbase
                              lsearch
                              diff_arrays diff_strings
@@ -95,6 +95,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 originally came from CGI.pm, by Lincoln D. Stein
 sub url_quote {
     my ($toencode) = (@_);
@@ -553,6 +640,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 a5bf4581fd6f08356b73977360a241c024e54850..55eb5c307f26d7f676be191046a7e9ce90036d1b 100644 (file)
@@ -50,3 +50,8 @@ table.groups td.checkbox {
     text-align: center;
     white-space: nowrap;
 }
+
+.missing {
+    color: red;
+    border-color: inherit;
+}
index 66f4b7c976a58e97b62cb1320ca4b6acdcbd3924..d4053461e75b7210986a36db72a0d3a796098148 100644 (file)
@@ -223,7 +223,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|base64|url_quote|css_class_quote|
-                                        ics|quoteUrls|time|uri|xml|lower|
+                                        ics|quoteUrls|time|uri|xml|lower|html_light|
                                         obsolete|inactive|closed|unitconvert|
                                         txt|none)\b/x;
 
index dd6e1785b9302cfdd6ac53b617fb5056a18a5d85..77dda1ce42ea1de0d91429b4f279faef9e177196 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 3ef9a5852e33a64deb8e961c050bf33f6e3c0f5d..568dac0cbda935305f42f6d58b6768132bfaca48 100644 (file)
@@ -49,8 +49,8 @@
         </td>
         <td>
           [% IF settings.${name}.is_enabled %]
-            <select name="[% name %]" id="[% name %]">
-              <option value="[% default_name %]"
+            <select name="[% name FILTER html %]" id="[% name FILTER html %]">
+              <option value="[% default_name FILTER html %]"
                 [% ' selected="selected"' IF settings.${name}.is_default %]>
                 Site Default ([% setting_descs.${default_val} OR default_val FILTER html %])
               </option>
@@ -64,8 +64,8 @@
               [% END %]
             </select>
           [% ELSE %]
-            <select name="[% name %]" id="[% name %]" disabled="disabled">
-              <option value="[% default_name %]">
+            <select name="[% name FILTER html %]" id="[% name FILTER html %]" disabled="disabled">
+              <option value="[% default_name FILTER html %]">
                 Site Default ([% setting_descs.${default_val} OR default_val FILTER html %])
               </option>
             </select>
index b450548b7c388d00d11079a3d39107b7b9a13f12..84c3cb197267132d5caffd6c4f3b31ae08945abc 100644 (file)
@@ -36,7 +36,7 @@
   <td valign="top">Description:</td>
   <td valign="top">
     [% IF classification.description %]
-      [% classification.description FILTER none %]
+      [% classification.description FILTER html_light %]
     [% ELSE %]
       <font color="red">description missing</font>
     [% END %]
index b1fc482c2abfa41bb65e4d5288f7519cf1a264f3..b56a401f484284ff6bdea3cd3a219d82eedbbe86 100644 (file)
@@ -59,7 +59,7 @@
                 <th align=right valign=top>[% product.name FILTER html %]</th>
                 <td valign=top>
                   [% IF product.description %]
-                    [% product.description FILTER none %]
+                    [% product.description FILTER html_light %]
                   [% ELSE %]
                     <font color="red">description missing</font>
                   [% END %]
index d45b88073d0221edf1f5233b108b37ea63e0e0b7..0db2fc265436d68f918f529c2550b02a9310e074 100644 (file)
@@ -33,7 +33,7 @@
       <td valign="top">Description:</td>
       <td valign="top" colspan=3>
         [% IF classification.description %]
-          [% classification.description FILTER none %]
+          [% classification.description FILTER html_light %]
         [% ELSE %]
           <font color="red">description missing</font>
         [% END %]
index eaa2149f0b65f22dcf233b2c58e741685fdc33dd..fd3aaf45d7970260ab2764762943363dfb3f31d8 100644 (file)
@@ -37,7 +37,7 @@
       <td valign="top"><a href="editclassifications.cgi?action=edit&amp;classification=[% cl.name FILTER url_quote %]"><b>[% cl.name FILTER html %]</b></a></td>
       <td valign="top"> 
       [% IF cl.description %]
-        [% cl.description %]
+        [% cl.description FILTER html_light %]
       [% ELSE %]
         <font color="red">none</font>
       [% END %]
index 4c94813fd46f2627cb95b13de1221bba92d04d31..e7e00636e06e778ac5373b2ff53ecf6eaffa3022 100644 (file)
@@ -44,7 +44,7 @@
 </tr>
 <tr>
   <td valign="top">Component Description:</td>
-  <td valign="top">[% comp.description FILTER html %]</td>
+  <td valign="top">[% comp.description FILTER html_light %]</td>
 </tr>
 <tr>
   <td valign="top">Default assignee:</td>
@@ -66,7 +66,7 @@
 </tr>
 <tr>
   <td valign="top">Product Description:</td>
-  <td valign="top">[% product.description FILTER html %]</td>
+  <td valign="top">[% product.description FILTER html_light %]</td>
 [% END %]
 
 [% IF Param('usetargetmilestone') %]
index a6f2c8b9def0b18fc2e73bf12da423dec40991b3..a4cbfdf5bac4442c587808b9da7aba686d4b1117 100644 (file)
@@ -56,7 +56,7 @@
   <table>
     <tr>
       <td>Updated description to:</td>
-      <td>'[% comp.description FILTER html %]'</td>
+      <td>'[% comp.description FILTER html_light %]'</td>
     </tr>
   </table>
 [% END %]
index d0c50f69a78142e5cf0767eb3e74776c24b95beb..f5aa7a9b43d3f1303757a9a008838a2e6197604f 100644 (file)
@@ -48,7 +48,7 @@
   <tr>
     <td>[% gid FILTER html %]</td>
     <td>[% name FILTER html %]</td>
-    <td>[% description FILTER html %]</td>
+    <td>[% description FILTER html_light %]</td>
   </tr>
 </table>
 
index 51aba7ffe19a44932cd31299c06d8a417a698db4..a66e78fde5e0454f5f87ebd1d50d8322cf04ef8c 100644 (file)
             [% group.grpnam FILTER html %]
           </a>
         </td>
-        <td align="left" class="groupdesc">[% group.grpdesc FILTER html %]</td>
+        <td align="left" class="groupdesc">[% group.grpdesc FILTER html_light %]</td>
       </tr>
     [% END %]
   </table>
index fe32bc53d7a5b9a980699f1eff5b6a19d96961ac..ef2c7486be58610d47e8a55d9dc7585bc9b1014e 100644 (file)
@@ -47,6 +47,7 @@
    }
    {name               => 'description'
     heading            => 'Description'
+    allow_html_content => 1
    }
    {name               => 'userregexp'
     heading            => 'User RegExp'
index 999538561c63b9b98830d1957a8bbcb86cbad505..1ffa0f27d14d409c339eae7ad63ae88cca4f0cbb 100755 (executable)
@@ -43,7 +43,8 @@
      },
      { 
        name => "description"
-       heading => "Description" 
+       heading => "Description"
+       allow_html_content => 1
      },
      { 
        name => "bug_count"
index e59dd8707db37cd434a70c31b9a6e67c4d520823..75aeb623acae0a118b2702cb57950e0c020e34f1 100644 (file)
@@ -56,7 +56,7 @@
       [%# descriptions are intentionally not filtered to allow html content %]
       <td>
         [% IF classification.description %]
-          [% classification.description FILTER none %]
+          [% classification.description FILTER html_light %]
         [% ELSE %]
           <span style="color: red">missing</span>
         [% END %]
@@ -78,7 +78,7 @@
     [%# descriptions are intentionally not filtered to allow html content %]
     <td valign="top">
       [% IF product.description %]
-        [% product.description FILTER none %]
+        [% product.description FILTER html_light %]
       [% ELSE %]
         <span style="color: red">missing</span>
       [% END %]
               [%# descriptions are intentionally not filtered to allow html content %]
               <td>
                 [% IF c.description %]
-                  [% c.description FILTER none %]
+                  [% c.description FILTER html_light %]
                 [% ELSE %]
                   <span style="color: red">missing</span>
                 [% END %]
index e3edadc9cd6eb090d0af6bf798f59c333a513238..afa15d73c90dc64d215a28abbe7f80abd978c523 100644 (file)
@@ -40,7 +40,7 @@
 <tr>
   <th align="right">Description:</th>
   <td><textarea rows="4" cols="64" wrap="virtual" name="description">
-        [% product.description FILTER none %]</textarea>
+        [% product.description FILTER html %]</textarea>
   </td>
 </tr>
 
index 4e8cc7b1955272bb70efc8bb2cc04d7137e56e1c..105ec6e7417b28d012b7a7fa6ce1e249204f2f2e 100644 (file)
@@ -50,7 +50,7 @@
           [% FOREACH component = product.components %]
             <b>[% component.name FILTER html %]:</b>&nbsp;
             [% IF component.description %]
-              [% component.description FILTER none %]
+              [% component.description FILTER html_light %]
             [% ELSE %]
               <font color="red">description missing</font>
             [% END %]
index e74720fed8f9d8df79da16ef6e930e813a156a73..8a0790d6ec70dcadde360406362a964767b5990c 100644 (file)
@@ -75,7 +75,7 @@
   <p>
     Updated description to:</p>
   </p>
-  <p style="margin: 1em 3em 1em 3em">[% product.description FILTER html %]</p>
+  <p style="margin: 1em 3em 1em 3em">[% product.description FILTER html_light %]</p>
   [% updated = 1 %]
 [% END %]
 
index 68c8577b0bd9ec098c661a8670edea79223a0425..9ca9226e779decf266aae66568c75d6a5a84b3fb 100644 (file)
@@ -64,7 +64,7 @@ page, and the Default Value will automatically apply to everyone.
               [% setting_descs.$name OR name FILTER html %]
             </td>
             <td>
-              <select name="[% name %]" id="[% name %]">
+              <select name="[% name FILTER html %]" id="[% name FILTER html %]">
                 [% FOREACH x = settings.${name}.legal_values %]
                     <option value="[% x FILTER html %]"
                       [% " selected=\"selected\"" IF x == settings.${name}.default_value %]>
@@ -75,8 +75,8 @@ page, and the Default Value will automatically apply to everyone.
             </td>
             <td align="center">
               <input type="checkbox"
-                name="[% checkbox_name %]"
-                id="[% checkbox_name %]"
+                name="[% checkbox_name FILTER html %]"
+                id="[% checkbox_name FILTER html %]"
                 [% " checked=\"checked\"" IF settings.${name}.is_enabled %]>
               <br>
             </td>
index 29108fd6c4d487f26d469daceca8679d1c7d7965..d13dceb66ae1af35cf438666a62632abc4432b61 100644 (file)
@@ -32,7 +32,7 @@
   #                  with the key xxx in data hash of the current row.
   #     content: If specified, the content of this variable is used
   #              instead of the data pulled from the current row. 
-  #              NOTE: This value is not HTML filtered at output!
+  #              NOTE: This value is only partially HTML filtered!
   #     content_use_field: If defined and true, then each value in the 
   #                        column corresponds with a key in the
   #                        field_descs field, and that value from the 
@@ -41,8 +41,8 @@
   #                        This content WILL be HTML-filtered in this case.
   #     align: left/center/right. Controls the horizontal alignment of the
   #            text in the column.
-  #     allow_html_content: if defined, then this column allows html content
-  #                         so it will not be filtered 
+  #     allow_html_content: if defined, then this column allows some html content
+  #                         and so it will be only partially filtered.
   #     yesno_field: Turn the data from 0/!0 into Yes/No
   #
   # data:
@@ -94,6 +94,7 @@
          content = c.content
          content_use_field = c.content_use_field
          align = c.align
+         class = c.class
          allow_html_content = c.allow_html_content
          yesno_field = c.yesno_field
        %]
              IF override.override_content_use_field %]
           [% SET align = override.align
              IF override.override_align %]
+          [% SET class = override.class
+             IF override.override_class %]
           [% SET allow_html_content = override.allow_html_content
              IF override.override_allow_html_content %]
           [% SET yesno_field = override.yesno_field
         [% END %]
       [% END %]
 
-      <td [% IF align %] align="[% align FILTER html %]" [% END %]>
+      <td [% IF align %] align="[% align FILTER html %]" [% END %]
+          [% IF class %] class="[% class FILTER html %]" [% END %]>
 
         [% IF contentlink %]
           [% link_uri = contentlink %]
            [% colname = row.${c.name} %]
            [% field_descs.${colname} FILTER html %]
         [% ELSIF content %]
-            [% content FILTER none %]
+            [% content FILTER html_light %]
         [% ELSE %]
           [% IF yesno_field %]
             [% IF row.${c.name} %]
             [% END %]
           [% ELSE %]
             [% IF allow_html_content %]
-              [% row.${c.name} FILTER none %]
+              [% row.${c.name} FILTER html_light %]
             [% ELSE %]
               [% row.${c.name} FILTER html %]
             [% END %]
index f92492472c6ea42653d7528c91ae3f6906af05c0..c35bb691f2152ad7d82b57b7043745cf0da69b41 100644 (file)
@@ -89,7 +89,7 @@
               <td class="groupname">
                 <label for="group_[% group.id %]">
                   <strong>[% group.name FILTER html %]:</strong>
-                  [%+ group.description FILTER html %]
+                  [%+ group.description FILTER html_light %]
                 </label>
               </td>
             </tr>
index 4b483e33d8164c83d4bf04ab074d119b7ac70cc4..41c5016f8e408cd6710ad87770592166225f814c 100644 (file)
     heading            => 'Edit user...'
     contentlink        => 'editusers.cgi?action=edit&amp;userid=%%userid%%' _
                           listselectionurlparams
-    allow_html_content => 1
    }
    {name               => 'realname'
     heading            => 'Real name'
-    allow_html_content => 1
    }
    {heading            => 'User Account Log'
     content            => 'View'
   %]
 [% END %]
 
+[%# Disabled users are crossed out. Missing realnames are noticed in red. %]
+[% overrides.login_name = [] %]
+[% overrides.realname = [] %]
+
 [% FOREACH thisuser = users %]
-  [%# We FILTER html here because we need admin/table.html.tmpl to accept HTML
-    # for styling, so we cannot let admin/table.html.tmpl do the FILTER.
-    #%]
-  [% thisuser.login_name = BLOCK %]
-    [% thisuser.login_name FILTER html %]
-  [% END %]
-  [% IF thisuser.realname %]
-    [% thisuser.realname = BLOCK %]
-      [% thisuser.realname FILTER html %]
-    [% END %]
-  [% ELSE %]
-    [% SET thisuser.realname = '<span style="color: red">missing</span>' %]
+  [% IF !thisuser.realname %]
+    [%# We cannot pass one class now and one class later. %]
+    [% SET classes = (thisuser.disabledtext ? "bz_inactive missing" : "missing") %]
+    [% overrides.realname.push({
+        match_value      => "$thisuser.login_name"
+        match_field      => 'login_name'
+        content          => "missing"
+        override_content => 1
+        class            => "$classes"
+        override_class   => 1 })
+    %]
   [% END %]
+
   [% IF thisuser.disabledtext %]
-    [% thisuser.login_name = "<span class=\"bz_inactive\">$thisuser.login_name</span>" %]
-    [% thisuser.realname = "<span class=\"bz_inactive\">$thisuser.realname</span>" %]
+    [% overrides.login_name.push({
+        match_value    => "$thisuser.login_name"
+        match_field    => 'login_name'
+        class          => "bz_inactive"
+        override_class => 1 })
+    %]
+
+    [% overrides.realname.push({
+        match_value    => "$thisuser.login_name"
+        match_field    => 'login_name'
+        class          => "bz_inactive"
+        override_class => 1 })
+    %]
   [% END %]
 [% END %]
 
 [% PROCESS admin/table.html.tmpl
   columns = columns
   data    = users
+  overrides = overrides
 %]
 
 <p>
index eb3aea2e4b0cc1651e0cb81538e9a0457bb84c8f..812abb075907df1003269ef8acc609a0e0db6e22 100644 (file)
@@ -526,7 +526,7 @@ function handleWantsAttachment(wants_attachment) {
         <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 c93d08c2bf1cd87ad89355e66c123329261754d9..12fcb05c8129b84a95808e6c26d220f4f13a11b1 100644 (file)
             <td>
               [% get_resolution(bug.resolution) FILTER html %]
               [% IF bug.resolution == "DUPLICATE" %]
-                of [% terms.bug %] [%+ "${bug.dup_id}" FILTER bug_link(bug.dup_id) %]
+                of [% terms.bug %] [%+ "${bug.dup_id}" FILTER bug_link(bug.dup_id) FILTER none %]
               [% END %]
             </td>
           </tr>
              name="bit-[% group.bit %]" id="bit-[% group.bit %]"
              [% " checked=\"checked\"" IF group.ison %]
              [% " disabled=\"disabled\"" IF NOT group.ingroup %]>
-      <label for="bit-[% group.bit %]">[% group.description %]</label>
+      <label for="bit-[% group.bit %]">[% group.description FILTER html_light %]</label>
       <br>
       [% END %]
     [% END %]
   </th>
   <td>
   [% FOREACH depbug = bug.${dep.fieldname} %]
-    [% depbug FILTER bug_link(depbug) %][% " " %]
+    [% depbug FILTER bug_link(depbug) FILTER none %][% " " %]
   [% END %]
   </td>
   <td>
index 2ebb3a21a3a375caecb3e355ef0069875dc16a47..e3d38c022bf97507ca5aa95274844cd8cf353b7a 100644 (file)
     <th>[% terms.Bug %] [%+ field_descs.${name} FILTER html %]:</th>
     <td>
       [% FOREACH depbug = bug.${name} %]
-        [% depbug FILTER bug_link(depbug) %][% ", " IF not loop.last() %]
+        [% depbug FILTER bug_link(depbug) FILTER none %][% ", " IF not loop.last() %]
       [% END %]
     </td>
 
index 70a4d28d0fbfd8a34dd9f6ec03d8b2c368453d57..c03704e72c17c901ea76130cd91acabfd52a9432 100644 (file)
 ],
 
 'reports/keywords.html.tmpl' => [
-  'keyword.description', 
   'keyword.bug_count', 
 ],
 
 
 'list/edit-multiple.html.tmpl' => [
   'group.id', 
-  'group.description',
-  'group.description FILTER inactive', 
   'knum', 
   'menuname', 
 ],
 
-'list/list-simple.html.tmpl' => [
-  'title', 
-],
-
 'list/list.rdf.tmpl' => [
   'template_version', 
   'bug.bug_id', 
   'h.html', 
 ],
 
-'global/choose-classification.html.tmpl' => [
-  'class.description', 
-],
-
 'global/choose-product.html.tmpl' => [
   'target',
 ],
   'bug.bug_id', 
   'bug.votes', 
   'group.bit', 
-  'group.description', 
   'dep.title', 
   'dep.fieldname', 
   'bug.${dep.fieldname}.join(\', \')', 
   'selname',
-  'depbug FILTER bug_link(depbug)',
-  '"${bug.dup_id}" FILTER bug_link(bug.dup_id)',
   '" accesskey=\"$accesskey\"" IF accesskey',
   'inputname',
   '" colspan=\"$colspan\"" IF $colspan',
 
 'bug/show-multiple.html.tmpl' => [
   'bug.bug_id', 
-  'depbug FILTER bug_link(depbug)',
   'attachment.id', 
   'flag.status',
 ],
 
 'bug/create/create.html.tmpl' => [
   'g.bit',
-  'g.description',
   'sel.name',
   'sel.description',
   'cloned_bug_id',
   'link_uri'
 ],
 
-'admin/classifications/select.html.tmpl' => [
-  'cl.description', 
-],
-
 'admin/products/groupcontrol/confirm-edit.html.tmpl' => [
   'group.count', 
 ],
   'comp.bug_count'
 ],
 
-'admin/settings/edit.html.tmpl' => [
-  'name',
-  'checkbox_name'
-],
-
 'account/login.html.tmpl' => [
   'target', 
 ],
   'prefname',
 ],
 
-'account/prefs/permissions.html.tmpl' => [
-  'bit_description.name', 
-  'bit_description.desc', 
-],
-
 'account/prefs/prefs.html.tmpl' => [
   'current_tab.label',
   'current_tab.name',
   'group.id',
 ],
 
-'account/prefs/settings.html.tmpl' => [
-  'name',
-  'default_name'
-],
-
 );
index 0a14fe44e9784fc80b9652116249cbf169404384..df0c379118dcfb4e034837ab1fb3a47ee710594f 100644 (file)
@@ -54,7 +54,7 @@
     </th>
 
     [% IF class.description %]
-      <td valign="top">&nbsp;[% class.description %]</td>
+      <td valign="top">&nbsp;[% class.description FILTER html_light %]</td>
     [% END %]
   </tr>
 [% END %]
index 346a537516c3d9177d3877bb561e73a86f1fffae..da47332c2b37132484c3b6f7b08fc1e21ceaa372 100644 (file)
@@ -51,7 +51,7 @@
       [% p.name FILTER html %]</a>:&nbsp;
     </th>
 
-    <td valign="top">[% p.description FILTER none %]</td>
+    <td valign="top">[% p.description FILTER html_light %]</td>
   </tr>
 [% END %]
 
index cf57bb651d101c63cce4d314f7ae4bb6c2958f3a..38e4e930f33c2756856c5c84ed27637191a28f39 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 9cdc1bed93828971d42c0d48df8e99356973bb38..8494baf6078cf01e7124320b1ec642a771d29305 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="skins/standard/buglist.css" rel="stylesheet" type="text/css">
   </head>
index 1e9065a78a3c2fb65ce98dc7de6cb551ac656cc9..d135a7ef8ac5cc59f70e2399198f2d39639158bb 100644 (file)
@@ -36,7 +36,7 @@
 [% END %]
 
 <p>
-  [% product.description FILTER none %]
+  [% product.description FILTER html_light %]
 </p>
 
 <table>
@@ -87,7 +87,7 @@
   </tr>
   <tr>
     <td colspan="[% numcols - 1 %]">
-      [% comp.description FILTER none %]
+      [% comp.description FILTER html_light %]
     </td>
   </tr>
 [% END %]
index 979c501638fd93fd4afd60876aa4e4f186b2225f..1a0ae0bf563438f882d46324ca7ff67b1c2e1dfa 100644 (file)
@@ -24,7 +24,7 @@
   # keywords: array keyword objects. May be empty. Each has has four members:
   #   id: id of the keyword
   #   name: the name of the keyword
-  #   description: keyword description. May be HTML.
+  #   description: keyword description. Can contain some limited HTML code.
   #   bug_count: number of bugs with that keyword
   # caneditkeywords: boolean. True if this user can edit keywords
  %]
@@ -55,7 +55,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="center">
       [% IF keyword.bug_count > 0 %]
         <a href="buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&amp;resolution=---">