GRANT_DIRECT
GRANT_DERIVED
GRANT_REGEXP
+
+ SAFE_PROTOCOLS
);
@Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
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;
$var =~ s/\@/\@/g;
return $var;
},
-
+
+ html_light => \&Bugzilla::Util::html_light_quote,
+
# iCalendar contentline filter
ics => [ sub {
my ($context, @args) = @_;
@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
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#<#<#g;
+ $text =~ s#>#>#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) = (@_);
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.
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;
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";
}
unless (TestProduct $prod) {
- print "Sorry, product '$prod' does not exist.";
+ print "Sorry, product '" . html_quote($prod) . "' does not exist.";
PutTrailer();
exit;
}
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;
}
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";
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';
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;
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;
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;
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;
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;
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';
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
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";
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;
}
# 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
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) . " </td>\n";
print "<td align=center>";
print "X" if (($isactive != 0) && ($isbuggroup != 0));
}
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) . "\">
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";
}
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";
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>
";
}
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";
}
unless (TestProduct $prod) {
- print "Sorry, product '$prod' does not exist.";
+ print "Sorry, product '" . html_quote($prod) . "' does not exist.";
PutTrailer();
exit;
}
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;
}
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";
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";
$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;
unlink "$datadir/versioncache";
print "OK, done.<p>\n";
- PutTrailer("<A HREF=\"editmilestones.cgi?product=$product&action=add\">add</a> another milestone or $localtrailer");
+ PutTrailer("<A HREF=\"editmilestones.cgi?product=" . url_quote($product) .
+ "&action=add\">add</a> another milestone or $localtrailer");
exit;
}
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";
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;
}
}
unless (TestProduct $prod) {
- print "Sorry, product '$prod' does not exist.";
+ print "Sorry, product '" . html_quote($prod) . "' does not exist.";
PutTrailer();
exit;
}
$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";
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;
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;
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';
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";
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 {
while ( MoreSQLData() ) {
my ($version) = FetchSQLData();
print "<BR>" if $br;
- print $version;
+ print html_quote($version);
$br = 1;
}
} else {
while ( MoreSQLData() ) {
my ($milestone) = FetchSQLData();
print "<BR>" if $br;
- print $milestone;
+ print html_quote($milestone);
$br = 1;
}
} else {
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);
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 {
while ( MoreSQLData() ) {
my ($version) = FetchSQLData();
print "<BR>" if $br;
- print $version;
+ print html_quote($version);
$br = 1;
}
} else {
while ( MoreSQLData() ) {
my ($milestone) = FetchSQLData();
print "<BR>" if $br;
- print $milestone;
+ print html_quote($milestone);
$br = 1;
}
} else {
"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;
}
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;
}
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";
}
}
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";
}
}
}
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";
"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 ";
}
unless (TestUser $user) {
- print "Sorry, user '$user' does not exist.";
+ print "Sorry, user '" . html_quote($user) . "' does not exist.";
PutTrailer();
exit;
}
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};
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";
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;
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";
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";
while ( MoreSQLData() ) {
my ($name) = FetchSQLData();
print "<br>\n" if $found;
- print ucfirst $name;
+ print html_quote(ucfirst($name));
$found = 1;
}
print "none" unless $found;
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';
}
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';
}
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;
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);
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";
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>";
}
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();
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();
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;
}
unless (TestProduct $prod) {
- print "Sorry, product '$prod' does not exist.";
+ print "Sorry, product '" . html_quote($prod) . "' does not exist.";
PutTrailer();
exit;
}
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;
}
$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";
}
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>";
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;
unlink "$datadir/versioncache";
print "OK, done.<p>\n";
- PutTrailer("<A HREF=\"editversions.cgi?product=$product&action=add\">add</a> another version or $localtrailer");
+ PutTrailer("<A HREF=\"editversions.cgi?product=" . url_quote($product) .
+ "&action=add\">add</a> another version or $localtrailer");
exit;
}
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";
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;
}
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
# 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;
<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>
<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>
#
# 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&id=%id%"
- },
- {
- name => "description"
- heading => "Description"
- },
- {
- name => "bug_count"
- heading => "Bugs"
- align => "right"
- },
- {
- heading => "Action"
- content => "Delete"
- contentlink => "editkeywords.cgi?action=delete&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&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&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 %]
<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 %]
<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 %]
'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',
</th>
[% IF proddesc.$p %]
- <td valign="top"> [% proddesc.$p %]</td>
+ <td valign="top"> [% proddesc.$p FILTER html_light %]</td>
[% END %]
</tr>
[% END %]
[% 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>
[%############################################################################%]
[% DEFAULT title = "$terms.Bug List" %]
-[% title = title FILTER html %]
-
[%############################################################################%]
[%# Bug Table #%]
<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>
# 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.
#%]
</tr>
<tr>
<td colspan="[% numcols - 1 %]">
- [% comp.description %]
+ [% comp.description FILTER html_light %]
</td>
</tr>
[% END %]
[%# 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
%]
<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 %]">