Commit b1ef63e5 authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 206037: [SECURITY] Fix escaping/quoting in edit*.cgi scripts - Patch by…

Bug 206037: [SECURITY] Fix escaping/quoting in edit*.cgi scripts - Patch by Frédéric Buclin <LpSolit@gmail.com> r=justdave a=justdave
parent 40aae68e
...@@ -123,6 +123,8 @@ use File::Basename; ...@@ -123,6 +123,8 @@ use File::Basename;
ON_WINDOWS ON_WINDOWS
MAX_TOKEN_AGE MAX_TOKEN_AGE
SAFE_PROTOCOLS
); );
@Bugzilla::Constants::EXPORT_OK = qw(contenttypes); @Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
...@@ -302,6 +304,11 @@ use constant FIELD_TYPE_SINGLE_SELECT => 2; ...@@ -302,6 +304,11 @@ use constant FIELD_TYPE_SINGLE_SELECT => 2;
# The maximum number of days a token will remain valid. # The maximum number of days a token will remain valid.
use constant MAX_TOKEN_AGE => 3; 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. # States that are considered to be "open" for bugs.
use constant BUG_STATE_OPEN => ('NEW', 'REOPENED', 'ASSIGNED', use constant BUG_STATE_OPEN => ('NEW', 'REOPENED', 'ASSIGNED',
'UNCONFIRMED'); 'UNCONFIRMED');
......
...@@ -125,6 +125,18 @@ use constant OPTIONAL_MODULES => [ ...@@ -125,6 +125,18 @@ use constant OPTIONAL_MODULES => [
name => 'SOAP::Lite', name => 'SOAP::Lite',
version => 0 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 # These are only required if you want to use Bugzilla with
...@@ -305,6 +317,17 @@ sub check_requirements { ...@@ -305,6 +317,17 @@ sub check_requirements {
" " . install_command('Net::LDAP') . "\n\n"; " " . 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 # mod_perl
if (!$have_mod{'mod_perl2'}) { if (!$have_mod{'mod_perl2'}) {
print "If you would like mod_perl support, you must install at", print "If you would like mod_perl support, you must install at",
......
...@@ -289,7 +289,8 @@ sub quoteUrls { ...@@ -289,7 +289,8 @@ sub quoteUrls {
~egox; ~egox;
# non-mailto protocols # 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: $text =~ s~\b(${protocol_re}: # The protocol:
[^\s<>\"]+ # Any non-whitespace [^\s<>\"]+ # Any non-whitespace
...@@ -735,6 +736,8 @@ sub create { ...@@ -735,6 +736,8 @@ sub create {
return $var; return $var;
}, },
html_light => \&Bugzilla::Util::html_light_quote,
# iCalendar contentline filter # iCalendar contentline filter
ics => [ sub { ics => [ sub {
my ($context, @args) = @_; my ($context, @args) = @_;
......
...@@ -34,7 +34,7 @@ use base qw(Exporter); ...@@ -34,7 +34,7 @@ use base qw(Exporter);
@Bugzilla::Util::EXPORT = qw(is_tainted trick_taint detaint_natural @Bugzilla::Util::EXPORT = qw(is_tainted trick_taint detaint_natural
detaint_signed detaint_signed
html_quote url_quote value_quote xml_quote html_quote url_quote value_quote xml_quote
css_class_quote css_class_quote html_light_quote
i_am_cgi get_netaddr correct_urlbase i_am_cgi get_netaddr correct_urlbase
lsearch lsearch
diff_arrays diff_strings diff_arrays diff_strings
...@@ -95,6 +95,93 @@ sub html_quote { ...@@ -95,6 +95,93 @@ sub html_quote {
return $var; 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 # This originally came from CGI.pm, by Lincoln D. Stein
sub url_quote { sub url_quote {
my ($toencode) = (@_); my ($toencode) = (@_);
...@@ -553,6 +640,12 @@ be done in the template where possible. ...@@ -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 Returns a value quoted for use in HTML, with &, E<lt>, E<gt>, and E<34> being
replaced with their appropriate HTML entities. 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)> =item C<url_quote($val)>
Quotes characters so that they may be included as part of a url. Quotes characters so that they may be included as part of a url.
......
...@@ -50,3 +50,8 @@ table.groups td.checkbox { ...@@ -50,3 +50,8 @@ table.groups td.checkbox {
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
} }
.missing {
color: red;
border-color: inherit;
}
...@@ -223,7 +223,7 @@ sub directive_ok { ...@@ -223,7 +223,7 @@ sub directive_ok {
# Note: If a single directive prints two things, and only one is # Note: If a single directive prints two things, and only one is
# filtered, we may not catch that case. # filtered, we may not catch that case.
return 1 if $directive =~ /FILTER\ (html|csv|js|base64|url_quote|css_class_quote| 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| obsolete|inactive|closed|unitconvert|
txt|none)\b/x; txt|none)\b/x;
......
...@@ -42,8 +42,8 @@ ...@@ -42,8 +42,8 @@
<table align="center"> <table align="center">
[% FOREACH bit_description = has_bits %] [% FOREACH bit_description = has_bits %]
<tr> <tr>
<td>[% bit_description.name %]</td> <td>[% bit_description.name FILTER html %]</td>
<td>[% bit_description.desc %]</td> <td>[% bit_description.desc FILTER html_light %]</td>
</tr> </tr>
[% END %] [% END %]
</table> </table>
...@@ -63,8 +63,8 @@ ...@@ -63,8 +63,8 @@
<table align="center"> <table align="center">
[% FOREACH bit_description = set_bits %] [% FOREACH bit_description = set_bits %]
<tr> <tr>
<td>[% bit_description.name %]</td> <td>[% bit_description.name FILTER html %]</td>
<td>[% bit_description.desc %]</td> <td>[% bit_description.desc FILTER html_light %]</td>
</tr> </tr>
[% END %] [% END %]
</table> </table>
......
...@@ -49,8 +49,8 @@ ...@@ -49,8 +49,8 @@
</td> </td>
<td> <td>
[% IF settings.${name}.is_enabled %] [% IF settings.${name}.is_enabled %]
<select name="[% name %]" id="[% name %]"> <select name="[% name FILTER html %]" id="[% name FILTER html %]">
<option value="[% default_name %]" <option value="[% default_name FILTER html %]"
[% ' selected="selected"' IF settings.${name}.is_default %]> [% ' selected="selected"' IF settings.${name}.is_default %]>
Site Default ([% setting_descs.${default_val} OR default_val FILTER html %]) Site Default ([% setting_descs.${default_val} OR default_val FILTER html %])
</option> </option>
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
[% END %] [% END %]
</select> </select>
[% ELSE %] [% ELSE %]
<select name="[% name %]" id="[% name %]" disabled="disabled"> <select name="[% name FILTER html %]" id="[% name FILTER html %]" disabled="disabled">
<option value="[% default_name %]"> <option value="[% default_name FILTER html %]">
Site Default ([% setting_descs.${default_val} OR default_val FILTER html %]) Site Default ([% setting_descs.${default_val} OR default_val FILTER html %])
</option> </option>
</select> </select>
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<td valign="top">Description:</td> <td valign="top">Description:</td>
<td valign="top"> <td valign="top">
[% IF classification.description %] [% IF classification.description %]
[% classification.description FILTER none %] [% classification.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<font color="red">description missing</font> <font color="red">description missing</font>
[% END %] [% END %]
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
<th align=right valign=top>[% product.name FILTER html %]</th> <th align=right valign=top>[% product.name FILTER html %]</th>
<td valign=top> <td valign=top>
[% IF product.description %] [% IF product.description %]
[% product.description FILTER none %] [% product.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<font color="red">description missing</font> <font color="red">description missing</font>
[% END %] [% END %]
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
<td valign="top">Description:</td> <td valign="top">Description:</td>
<td valign="top" colspan=3> <td valign="top" colspan=3>
[% IF classification.description %] [% IF classification.description %]
[% classification.description FILTER none %] [% classification.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<font color="red">description missing</font> <font color="red">description missing</font>
[% END %] [% END %]
......
...@@ -37,7 +37,7 @@ ...@@ -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"><a href="editclassifications.cgi?action=edit&amp;classification=[% cl.name FILTER url_quote %]"><b>[% cl.name FILTER html %]</b></a></td>
<td valign="top"> <td valign="top">
[% IF cl.description %] [% IF cl.description %]
[% cl.description %] [% cl.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<font color="red">none</font> <font color="red">none</font>
[% END %] [% END %]
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
</tr> </tr>
<tr> <tr>
<td valign="top">Component Description:</td> <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>
<tr> <tr>
<td valign="top">Default assignee:</td> <td valign="top">Default assignee:</td>
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
</tr> </tr>
<tr> <tr>
<td valign="top">Product Description:</td> <td valign="top">Product Description:</td>
<td valign="top">[% product.description FILTER html %]</td> <td valign="top">[% product.description FILTER html_light %]</td>
[% END %] [% END %]
[% IF Param('usetargetmilestone') %] [% IF Param('usetargetmilestone') %]
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<table> <table>
<tr> <tr>
<td>Updated description to:</td> <td>Updated description to:</td>
<td>'[% comp.description FILTER html %]'</td> <td>'[% comp.description FILTER html_light %]'</td>
</tr> </tr>
</table> </table>
[% END %] [% END %]
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
<tr> <tr>
<td>[% gid FILTER html %]</td> <td>[% gid FILTER html %]</td>
<td>[% name FILTER html %]</td> <td>[% name FILTER html %]</td>
<td>[% description FILTER html %]</td> <td>[% description FILTER html_light %]</td>
</tr> </tr>
</table> </table>
......
...@@ -165,7 +165,7 @@ ...@@ -165,7 +165,7 @@
[% group.grpnam FILTER html %] [% group.grpnam FILTER html %]
</a> </a>
</td> </td>
<td align="left" class="groupdesc">[% group.grpdesc FILTER html %]</td> <td align="left" class="groupdesc">[% group.grpdesc FILTER html_light %]</td>
</tr> </tr>
[% END %] [% END %]
</table> </table>
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
} }
{name => 'description' {name => 'description'
heading => 'Description' heading => 'Description'
allow_html_content => 1
} }
{name => 'userregexp' {name => 'userregexp'
heading => 'User RegExp' heading => 'User RegExp'
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
{ {
name => "description" name => "description"
heading => "Description" heading => "Description"
allow_html_content => 1
}, },
{ {
name => "bug_count" name => "bug_count"
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
[%# descriptions are intentionally not filtered to allow html content %] [%# descriptions are intentionally not filtered to allow html content %]
<td> <td>
[% IF classification.description %] [% IF classification.description %]
[% classification.description FILTER none %] [% classification.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<span style="color: red">missing</span> <span style="color: red">missing</span>
[% END %] [% END %]
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
[%# descriptions are intentionally not filtered to allow html content %] [%# descriptions are intentionally not filtered to allow html content %]
<td valign="top"> <td valign="top">
[% IF product.description %] [% IF product.description %]
[% product.description FILTER none %] [% product.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<span style="color: red">missing</span> <span style="color: red">missing</span>
[% END %] [% END %]
...@@ -132,7 +132,7 @@ ...@@ -132,7 +132,7 @@
[%# descriptions are intentionally not filtered to allow html content %] [%# descriptions are intentionally not filtered to allow html content %]
<td> <td>
[% IF c.description %] [% IF c.description %]
[% c.description FILTER none %] [% c.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<span style="color: red">missing</span> <span style="color: red">missing</span>
[% END %] [% END %]
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<tr> <tr>
<th align="right">Description:</th> <th align="right">Description:</th>
<td><textarea rows="4" cols="64" wrap="virtual" name="description"> <td><textarea rows="4" cols="64" wrap="virtual" name="description">
[% product.description FILTER none %]</textarea> [% product.description FILTER html %]</textarea>
</td> </td>
</tr> </tr>
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
[% FOREACH component = product.components %] [% FOREACH component = product.components %]
<b>[% component.name FILTER html %]:</b>&nbsp; <b>[% component.name FILTER html %]:</b>&nbsp;
[% IF component.description %] [% IF component.description %]
[% component.description FILTER none %] [% component.description FILTER html_light %]
[% ELSE %] [% ELSE %]
<font color="red">description missing</font> <font color="red">description missing</font>
[% END %] [% END %]
......
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
<p> <p>
Updated description to:</p> Updated description to:</p>
</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 %] [% updated = 1 %]
[% END %] [% END %]
......
...@@ -64,7 +64,7 @@ page, and the Default Value will automatically apply to everyone. ...@@ -64,7 +64,7 @@ page, and the Default Value will automatically apply to everyone.
[% setting_descs.$name OR name FILTER html %] [% setting_descs.$name OR name FILTER html %]
</td> </td>
<td> <td>
<select name="[% name %]" id="[% name %]"> <select name="[% name FILTER html %]" id="[% name FILTER html %]">
[% FOREACH x = settings.${name}.legal_values %] [% FOREACH x = settings.${name}.legal_values %]
<option value="[% x FILTER html %]" <option value="[% x FILTER html %]"
[% " selected=\"selected\"" IF x == settings.${name}.default_value %]> [% " selected=\"selected\"" IF x == settings.${name}.default_value %]>
...@@ -75,8 +75,8 @@ page, and the Default Value will automatically apply to everyone. ...@@ -75,8 +75,8 @@ page, and the Default Value will automatically apply to everyone.
</td> </td>
<td align="center"> <td align="center">
<input type="checkbox" <input type="checkbox"
name="[% checkbox_name %]" name="[% checkbox_name FILTER html %]"
id="[% checkbox_name %]" id="[% checkbox_name FILTER html %]"
[% " checked=\"checked\"" IF settings.${name}.is_enabled %]> [% " checked=\"checked\"" IF settings.${name}.is_enabled %]>
<br> <br>
</td> </td>
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
# with the key xxx in data hash of the current row. # with the key xxx in data hash of the current row.
# content: If specified, the content of this variable is used # content: If specified, the content of this variable is used
# instead of the data pulled from the current row. # 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 # content_use_field: If defined and true, then each value in the
# column corresponds with a key in the # column corresponds with a key in the
# field_descs field, and that value from the # field_descs field, and that value from the
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
# This content WILL be HTML-filtered in this case. # This content WILL be HTML-filtered in this case.
# align: left/center/right. Controls the horizontal alignment of the # align: left/center/right. Controls the horizontal alignment of the
# text in the column. # text in the column.
# allow_html_content: if defined, then this column allows html content # allow_html_content: if defined, then this column allows some html content
# so it will not be filtered # and so it will be only partially filtered.
# yesno_field: Turn the data from 0/!0 into Yes/No # yesno_field: Turn the data from 0/!0 into Yes/No
# #
# data: # data:
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
content = c.content content = c.content
content_use_field = c.content_use_field content_use_field = c.content_use_field
align = c.align align = c.align
class = c.class
allow_html_content = c.allow_html_content allow_html_content = c.allow_html_content
yesno_field = c.yesno_field yesno_field = c.yesno_field
%] %]
...@@ -112,6 +113,8 @@ ...@@ -112,6 +113,8 @@
IF override.override_content_use_field %] IF override.override_content_use_field %]
[% SET align = override.align [% SET align = override.align
IF override.override_align %] IF override.override_align %]
[% SET class = override.class
IF override.override_class %]
[% SET allow_html_content = override.allow_html_content [% SET allow_html_content = override.allow_html_content
IF override.override_allow_html_content %] IF override.override_allow_html_content %]
[% SET yesno_field = override.yesno_field [% SET yesno_field = override.yesno_field
...@@ -122,7 +125,8 @@ ...@@ -122,7 +125,8 @@
[% END %] [% END %]
[% 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 %] [% IF contentlink %]
[% link_uri = contentlink %] [% link_uri = contentlink %]
...@@ -143,7 +147,7 @@ ...@@ -143,7 +147,7 @@
[% colname = row.${c.name} %] [% colname = row.${c.name} %]
[% field_descs.${colname} FILTER html %] [% field_descs.${colname} FILTER html %]
[% ELSIF content %] [% ELSIF content %]
[% content FILTER none %] [% content FILTER html_light %]
[% ELSE %] [% ELSE %]
[% IF yesno_field %] [% IF yesno_field %]
[% IF row.${c.name} %] [% IF row.${c.name} %]
...@@ -153,7 +157,7 @@ ...@@ -153,7 +157,7 @@
[% END %] [% END %]
[% ELSE %] [% ELSE %]
[% IF allow_html_content %] [% IF allow_html_content %]
[% row.${c.name} FILTER none %] [% row.${c.name} FILTER html_light %]
[% ELSE %] [% ELSE %]
[% row.${c.name} FILTER html %] [% row.${c.name} FILTER html %]
[% END %] [% END %]
......
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
<td class="groupname"> <td class="groupname">
<label for="group_[% group.id %]"> <label for="group_[% group.id %]">
<strong>[% group.name FILTER html %]:</strong> <strong>[% group.name FILTER html %]:</strong>
[%+ group.description FILTER html %] [%+ group.description FILTER html_light %]
</label> </label>
</td> </td>
</tr> </tr>
......
...@@ -38,11 +38,9 @@ ...@@ -38,11 +38,9 @@
heading => 'Edit user...' heading => 'Edit user...'
contentlink => 'editusers.cgi?action=edit&amp;userid=%%userid%%' _ contentlink => 'editusers.cgi?action=edit&amp;userid=%%userid%%' _
listselectionurlparams listselectionurlparams
allow_html_content => 1
} }
{name => 'realname' {name => 'realname'
heading => 'Real name' heading => 'Real name'
allow_html_content => 1
} }
{heading => 'User Account Log' {heading => 'User Account Log'
content => 'View' content => 'View'
...@@ -64,23 +62,38 @@ ...@@ -64,23 +62,38 @@
%] %]
[% END %] [% END %]
[%# Disabled users are crossed out. Missing realnames are noticed in red. %]
[% overrides.login_name = [] %]
[% overrides.realname = [] %]
[% FOREACH thisuser = users %] [% FOREACH thisuser = users %]
[%# We FILTER html here because we need admin/table.html.tmpl to accept HTML [% IF !thisuser.realname %]
# for styling, so we cannot let admin/table.html.tmpl do the FILTER. [%# We cannot pass one class now and one class later. %]
#%] [% SET classes = (thisuser.disabledtext ? "bz_inactive missing" : "missing") %]
[% thisuser.login_name = BLOCK %] [% overrides.realname.push({
[% thisuser.login_name FILTER html %] match_value => "$thisuser.login_name"
[% END %] match_field => 'login_name'
[% IF thisuser.realname %] content => "missing"
[% thisuser.realname = BLOCK %] override_content => 1
[% thisuser.realname FILTER html %] class => "$classes"
[% END %] override_class => 1 })
[% ELSE %] %]
[% SET thisuser.realname = '<span style="color: red">missing</span>' %]
[% END %] [% END %]
[% IF thisuser.disabledtext %] [% IF thisuser.disabledtext %]
[% thisuser.login_name = "<span class=\"bz_inactive\">$thisuser.login_name</span>" %] [% overrides.login_name.push({
[% thisuser.realname = "<span class=\"bz_inactive\">$thisuser.realname</span>" %] 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 %]
[% END %] [% END %]
...@@ -89,6 +102,7 @@ ...@@ -89,6 +102,7 @@
[% PROCESS admin/table.html.tmpl [% PROCESS admin/table.html.tmpl
columns = columns columns = columns
data = users data = users
overrides = overrides
%] %]
<p> <p>
......
...@@ -526,7 +526,7 @@ function handleWantsAttachment(wants_attachment) { ...@@ -526,7 +526,7 @@ function handleWantsAttachment(wants_attachment) {
<input type="checkbox" id="bit-[% g.bit %]" <input type="checkbox" id="bit-[% g.bit %]"
name="bit-[% g.bit %]" value="1" name="bit-[% g.bit %]" value="1"
[% " checked=\"checked\"" IF g.checked %]> [% " 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 %] [% END %]
<br> <br>
[% END %] [% END %]
......
...@@ -198,7 +198,7 @@ ...@@ -198,7 +198,7 @@
<td> <td>
[% get_resolution(bug.resolution) FILTER html %] [% get_resolution(bug.resolution) FILTER html %]
[% IF bug.resolution == "DUPLICATE" %] [% 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 %] [% END %]
</td> </td>
</tr> </tr>
...@@ -619,7 +619,7 @@ ...@@ -619,7 +619,7 @@
name="bit-[% group.bit %]" id="bit-[% group.bit %]" name="bit-[% group.bit %]" id="bit-[% group.bit %]"
[% " checked=\"checked\"" IF group.ison %] [% " checked=\"checked\"" IF group.ison %]
[% " disabled=\"disabled\"" IF NOT group.ingroup %]> [% " 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> <br>
[% END %] [% END %]
[% END %] [% END %]
...@@ -683,7 +683,7 @@ ...@@ -683,7 +683,7 @@
</th> </th>
<td> <td>
[% FOREACH depbug = bug.${dep.fieldname} %] [% FOREACH depbug = bug.${dep.fieldname} %]
[% depbug FILTER bug_link(depbug) %][% " " %] [% depbug FILTER bug_link(depbug) FILTER none %][% " " %]
[% END %] [% END %]
</td> </td>
<td> <td>
......
...@@ -303,7 +303,7 @@ ...@@ -303,7 +303,7 @@
<th>[% terms.Bug %] [%+ field_descs.${name} FILTER html %]:</th> <th>[% terms.Bug %] [%+ field_descs.${name} FILTER html %]:</th>
<td> <td>
[% FOREACH depbug = bug.${name} %] [% 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 %] [% END %]
</td> </td>
......
...@@ -112,7 +112,6 @@ ...@@ -112,7 +112,6 @@
], ],
'reports/keywords.html.tmpl' => [ 'reports/keywords.html.tmpl' => [
'keyword.description',
'keyword.bug_count', 'keyword.bug_count',
], ],
...@@ -189,16 +188,10 @@ ...@@ -189,16 +188,10 @@
'list/edit-multiple.html.tmpl' => [ 'list/edit-multiple.html.tmpl' => [
'group.id', 'group.id',
'group.description',
'group.description FILTER inactive',
'knum', 'knum',
'menuname', 'menuname',
], ],
'list/list-simple.html.tmpl' => [
'title',
],
'list/list.rdf.tmpl' => [ 'list/list.rdf.tmpl' => [
'template_version', 'template_version',
'bug.bug_id', 'bug.bug_id',
...@@ -225,10 +218,6 @@ ...@@ -225,10 +218,6 @@
'h.html', 'h.html',
], ],
'global/choose-classification.html.tmpl' => [
'class.description',
],
'global/choose-product.html.tmpl' => [ 'global/choose-product.html.tmpl' => [
'target', 'target',
], ],
...@@ -314,13 +303,10 @@ ...@@ -314,13 +303,10 @@
'bug.bug_id', 'bug.bug_id',
'bug.votes', 'bug.votes',
'group.bit', 'group.bit',
'group.description',
'dep.title', 'dep.title',
'dep.fieldname', 'dep.fieldname',
'bug.${dep.fieldname}.join(\', \')', 'bug.${dep.fieldname}.join(\', \')',
'selname', 'selname',
'depbug FILTER bug_link(depbug)',
'"${bug.dup_id}" FILTER bug_link(bug.dup_id)',
'" accesskey=\"$accesskey\"" IF accesskey', '" accesskey=\"$accesskey\"" IF accesskey',
'inputname', 'inputname',
'" colspan=\"$colspan\"" IF $colspan', '" colspan=\"$colspan\"" IF $colspan',
...@@ -342,7 +328,6 @@ ...@@ -342,7 +328,6 @@
'bug/show-multiple.html.tmpl' => [ 'bug/show-multiple.html.tmpl' => [
'bug.bug_id', 'bug.bug_id',
'depbug FILTER bug_link(depbug)',
'attachment.id', 'attachment.id',
'flag.status', 'flag.status',
], ],
...@@ -402,7 +387,6 @@ ...@@ -402,7 +387,6 @@
'bug/create/create.html.tmpl' => [ 'bug/create/create.html.tmpl' => [
'g.bit', 'g.bit',
'g.description',
'sel.name', 'sel.name',
'sel.description', 'sel.description',
'cloned_bug_id', 'cloned_bug_id',
...@@ -484,10 +468,6 @@ ...@@ -484,10 +468,6 @@
'link_uri' 'link_uri'
], ],
'admin/classifications/select.html.tmpl' => [
'cl.description',
],
'admin/products/groupcontrol/confirm-edit.html.tmpl' => [ 'admin/products/groupcontrol/confirm-edit.html.tmpl' => [
'group.count', 'group.count',
], ],
...@@ -572,11 +552,6 @@ ...@@ -572,11 +552,6 @@
'comp.bug_count' 'comp.bug_count'
], ],
'admin/settings/edit.html.tmpl' => [
'name',
'checkbox_name'
],
'account/login.html.tmpl' => [ 'account/login.html.tmpl' => [
'target', 'target',
], ],
...@@ -587,11 +562,6 @@ ...@@ -587,11 +562,6 @@
'prefname', 'prefname',
], ],
'account/prefs/permissions.html.tmpl' => [
'bit_description.name',
'bit_description.desc',
],
'account/prefs/prefs.html.tmpl' => [ 'account/prefs/prefs.html.tmpl' => [
'current_tab.label', 'current_tab.label',
'current_tab.name', 'current_tab.name',
...@@ -601,9 +571,4 @@ ...@@ -601,9 +571,4 @@
'group.id', 'group.id',
], ],
'account/prefs/settings.html.tmpl' => [
'name',
'default_name'
],
); );
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</th> </th>
[% IF class.description %] [% IF class.description %]
<td valign="top">&nbsp;[% class.description %]</td> <td valign="top">&nbsp;[% class.description FILTER html_light %]</td>
[% END %] [% END %]
</tr> </tr>
[% END %] [% END %]
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
[% p.name FILTER html %]</a>:&nbsp; [% p.name FILTER html %]</a>:&nbsp;
</th> </th>
<td valign="top">[% p.description FILTER none %]</td> <td valign="top">[% p.description FILTER html_light %]</td>
</tr> </tr>
[% END %] [% END %]
......
...@@ -256,11 +256,8 @@ ...@@ -256,11 +256,8 @@
[% END %] [% END %]
<td> <td>
[% IF group.isactive %] [% SET inactive = !group.isactive %]
[% group.description %] [% group.description FILTER html_light FILTER inactive(inactive) %]
[% ELSE %]
[% group.description FILTER inactive %]
[% END %]
</td> </td>
</tr> </tr>
......
...@@ -30,8 +30,6 @@ ...@@ -30,8 +30,6 @@
[%############################################################################%] [%############################################################################%]
[% DEFAULT title = "$terms.Bug List" %] [% DEFAULT title = "$terms.Bug List" %]
[% title = title FILTER html %]
[%############################################################################%] [%############################################################################%]
[%# Bug Table #%] [%# Bug Table #%]
...@@ -40,7 +38,7 @@ ...@@ -40,7 +38,7 @@
<html> <html>
<head> <head>
<title>[% title %]</title> <title>[% title FILTER html %]</title>
<base href="[% Param("urlbase") %]"> <base href="[% Param("urlbase") %]">
<link href="skins/standard/buglist.css" rel="stylesheet" type="text/css"> <link href="skins/standard/buglist.css" rel="stylesheet" type="text/css">
</head> </head>
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
[% END %] [% END %]
<p> <p>
[% product.description FILTER none %] [% product.description FILTER html_light %]
</p> </p>
<table> <table>
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="[% numcols - 1 %]"> <td colspan="[% numcols - 1 %]">
[% comp.description FILTER none %] [% comp.description FILTER html_light %]
</td> </td>
</tr> </tr>
[% END %] [% END %]
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
# keywords: array keyword objects. May be empty. Each has has four members: # keywords: array keyword objects. May be empty. Each has has four members:
# id: id of the keyword # id: id of the keyword
# name: the name 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 # bug_count: number of bugs with that keyword
# caneditkeywords: boolean. True if this user can edit keywords # caneditkeywords: boolean. True if this user can edit keywords
%] %]
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<a name="[% keyword.name FILTER html %]"> <a name="[% keyword.name FILTER html %]">
[% keyword.name FILTER html %]</a> [% keyword.name FILTER html %]</a>
</th> </th>
<td>[% keyword.description %]</td> <td>[% keyword.description FILTER html_light %]</td>
<td align="center"> <td align="center">
[% IF keyword.bug_count > 0 %] [% IF keyword.bug_count > 0 %]
<a href="buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&amp;resolution=---"> <a href="buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&amp;resolution=---">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment