aboutsummaryrefslogtreecommitdiffstats
path: root/gitweb/gitweb.perl
diff options
context:
space:
mode:
Diffstat (limited to 'gitweb/gitweb.perl')
-rwxr-xr-xgitweb/gitweb.perl231
1 files changed, 146 insertions, 85 deletions
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2594a4badb..e66eb3d9ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -569,6 +569,15 @@ our %feature = (
'sub' => \&feature_extra_branch_refs,
'override' => 0,
'default' => []},
+
+ # Redact e-mail addresses.
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'email-privacy'}{'default'} = [1];
+ 'email-privacy' => {
+ 'sub' => sub { feature_bool('email-privacy', @_) },
+ 'override' => 1,
+ 'default' => [0]},
);
sub gitweb_get_feature {
@@ -741,7 +750,7 @@ sub evaluate_gitweb_config {
$GITWEB_CONFIG_SYSTEM = "" if ($GITWEB_CONFIG_SYSTEM eq $GITWEB_CONFIG_COMMON);
# Common system-wide settings for convenience.
- # Those settings can be ovverriden by GITWEB_CONFIG or GITWEB_CONFIG_SYSTEM.
+ # Those settings can be overridden by GITWEB_CONFIG or GITWEB_CONFIG_SYSTEM.
read_config_file($GITWEB_CONFIG_COMMON);
# Use first config file that exists. This means use the per-instance
@@ -788,6 +797,38 @@ sub check_loadavg {
# ======================================================================
# input validation and dispatch
+# Various hash size-related values.
+my $sha1_len = 40;
+my $sha256_extra_len = 24;
+my $sha256_len = $sha1_len + $sha256_extra_len;
+
+# A regex matching $len hex characters. $len may be a range (e.g. 7,64).
+sub oid_nlen_regex {
+ my $len = shift;
+ my $hchr = qr/[0-9a-fA-F]/;
+ return qr/(?:(?:$hchr){$len})/;
+}
+
+# A regex matching two sets of $nlen hex characters, prefixed by the literal
+# string $prefix and with the literal string $infix between them.
+sub oid_nlen_prefix_infix_regex {
+ my $nlen = shift;
+ my $prefix = shift;
+ my $infix = shift;
+
+ my $rx = oid_nlen_regex($nlen);
+
+ return qr/^\Q$prefix\E$rx\Q$infix\E$rx$/;
+}
+
+# A regex matching a valid object ID.
+our $oid_regex;
+{
+ my $x = oid_nlen_regex($sha1_len);
+ my $y = oid_nlen_regex($sha256_extra_len);
+ $oid_regex = qr/(?:$x(?:$y)?)/;
+}
+
# input parameters can be collected from a variety of sources (presently, CGI
# and PATH_INFO), so we define an %input_params hash that collects them all
# together during validation: this allows subsequent uses (e.g. href()) to be
@@ -1259,9 +1300,23 @@ our $is_last_request = sub { 1 };
our ($pre_dispatch_hook, $post_dispatch_hook, $pre_listen_hook);
our $CGI = 'CGI';
our $cgi;
+our $FCGI_Stream_PRINT_raw = \&FCGI::Stream::PRINT;
sub configure_as_fcgi {
require CGI::Fast;
our $CGI = 'CGI::Fast';
+ # FCGI is not Unicode aware hence the UTF-8 encoding must be done manually.
+ # However no encoding must be done within git_blob_plain() and git_snapshot()
+ # which must still output in raw binary mode.
+ no warnings 'redefine';
+ my $enc = Encode::find_encoding('UTF-8');
+ *FCGI::Stream::PRINT = sub {
+ my @OUTPUT = @_;
+ for (my $i = 1; $i < @_; $i++) {
+ $OUTPUT[$i] = $enc->encode($_[$i], Encode::FB_CROAK|Encode::LEAVE_SRC);
+ }
+ @_ = @OUTPUT;
+ goto $FCGI_Stream_PRINT_raw;
+ };
my $request_number = 0;
# let each child service 100 requests
@@ -1516,7 +1571,7 @@ sub is_valid_refname {
return undef unless defined $input;
# textual hashes are O.K.
- if ($input =~ m/^[0-9a-fA-F]{40}$/) {
+ if ($input =~ m/^$oid_regex$/) {
return 1;
}
# it must be correct pathname
@@ -1625,15 +1680,15 @@ sub quot_cec {
my $cntrl = shift;
my %opts = @_;
my %es = ( # character escape codes, aka escape sequences
- "\t" => '\t', # tab (HT)
- "\n" => '\n', # line feed (LF)
- "\r" => '\r', # carrige return (CR)
- "\f" => '\f', # form feed (FF)
- "\b" => '\b', # backspace (BS)
- "\a" => '\a', # alarm (bell) (BEL)
- "\e" => '\e', # escape (ESC)
- "\013" => '\v', # vertical tab (VT)
- "\000" => '\0', # nul character (NUL)
+ "\t" => '\t', # tab (HT)
+ "\n" => '\n', # line feed (LF)
+ "\r" => '\r', # carriage return (CR)
+ "\f" => '\f', # form feed (FF)
+ "\b" => '\b', # backspace (BS)
+ "\a" => '\a', # alarm (bell) (BEL)
+ "\e" => '\e', # escape (ESC)
+ "\013" => '\v', # vertical tab (VT)
+ "\000" => '\0', # nul character (NUL)
);
my $chr = ( (exists $es{$cntrl})
? $es{$cntrl}
@@ -2028,6 +2083,9 @@ sub file_type_long {
sub format_log_line_html {
my $line = shift;
+ # Potentially abbreviated OID.
+ my $regex = oid_nlen_regex("7,64");
+
$line = esc_html($line, -nbsp=>1);
$line =~ s{
\b
@@ -2037,10 +2095,10 @@ sub format_log_line_html {
(?<!-) # see strbuf_check_tag_ref(). Tags can't start with -
[A-Za-z0-9.-]+
(?!\.) # refs can't end with ".", see check_refname_format()
- -g[0-9a-fA-F]{7,40}
+ -g$regex
|
# Just a normal looking Git SHA1
- [0-9a-fA-F]{7,40}
+ $regex
)
\b
}{
@@ -2286,7 +2344,8 @@ sub format_extended_diff_header_line {
')</span>';
}
# match <hash>
- if ($line =~ m/^index [0-9a-fA-F]{40},[0-9a-fA-F]{40}/) {
+ if ($line =~ oid_nlen_prefix_infix_regex($sha1_len, "index ", ",") |
+ $line =~ oid_nlen_prefix_infix_regex($sha256_len, "index ", ",")) {
# can match only for combined diff
$line = 'index ';
for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
@@ -2308,7 +2367,8 @@ sub format_extended_diff_header_line {
$line .= '0' x 7;
}
- } elsif ($line =~ m/^index [0-9a-fA-F]{40}..[0-9a-fA-F]{40}/) {
+ } elsif ($line =~ oid_nlen_prefix_infix_regex($sha1_len, "index ", "..") |
+ $line =~ oid_nlen_prefix_infix_regex($sha256_len, "index ", "..")) {
# can match only for ordinary diff
my ($from_link, $to_link);
if ($from->{'href'}) {
@@ -2834,7 +2894,7 @@ sub git_get_hash_by_path {
}
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
- $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/;
+ $line =~ m/^([0-9]+) (.+) ($oid_regex)\t/;
if (defined $type && $type ne $2) {
# type doesn't match
return undef;
@@ -3333,7 +3393,7 @@ sub git_get_references {
while (my $line = <$fd>) {
chomp $line;
- if ($line =~ m!^([0-9a-fA-F]{40})\srefs/($type.*)$!) {
+ if ($line =~ m!^($oid_regex)\srefs/($type.*)$!) {
if (defined $refs{$1}) {
push @{$refs{$1}}, $2;
} else {
@@ -3398,6 +3458,13 @@ sub parse_date {
return %date;
}
+sub hide_mailaddrs_if_private {
+ my $line = shift;
+ return $line unless gitweb_check_feature('email-privacy');
+ $line =~ s/<[^@>]+@[^>]+>/<redacted>/g;
+ return $line;
+}
+
sub parse_tag {
my $tag_id = shift;
my %tag;
@@ -3407,14 +3474,14 @@ sub parse_tag {
$tag{'id'} = $tag_id;
while (my $line = <$fd>) {
chomp $line;
- if ($line =~ m/^object ([0-9a-fA-F]{40})$/) {
+ if ($line =~ m/^object ($oid_regex)$/) {
$tag{'object'} = $1;
} elsif ($line =~ m/^type (.+)$/) {
$tag{'type'} = $1;
} elsif ($line =~ m/^tag (.+)$/) {
$tag{'name'} = $1;
} elsif ($line =~ m/^tagger (.*) ([0-9]+) (.*)$/) {
- $tag{'author'} = $1;
+ $tag{'author'} = hide_mailaddrs_if_private($1);
$tag{'author_epoch'} = $2;
$tag{'author_tz'} = $3;
if ($tag{'author'} =~ m/^([^<]+) <([^>]*)>/) {
@@ -3451,18 +3518,18 @@ sub parse_commit_text {
}
my $header = shift @commit_lines;
- if ($header !~ m/^[0-9a-fA-F]{40}/) {
+ if ($header !~ m/^$oid_regex/) {
return;
}
($co{'id'}, my @parents) = split ' ', $header;
while (my $line = shift @commit_lines) {
last if $line eq "\n";
- if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
+ if ($line =~ m/^tree ($oid_regex)$/) {
$co{'tree'} = $1;
- } elsif ((!defined $withparents) && ($line =~ m/^parent ([0-9a-fA-F]{40})$/)) {
+ } elsif ((!defined $withparents) && ($line =~ m/^parent ($oid_regex)$/)) {
push @parents, $1;
} elsif ($line =~ m/^author (.*) ([0-9]+) (.*)$/) {
- $co{'author'} = to_utf8($1);
+ $co{'author'} = hide_mailaddrs_if_private(to_utf8($1));
$co{'author_epoch'} = $2;
$co{'author_tz'} = $3;
if ($co{'author'} =~ m/^([^<]+) <([^>]*)>/) {
@@ -3472,7 +3539,7 @@ sub parse_commit_text {
$co{'author_name'} = $co{'author'};
}
} elsif ($line =~ m/^committer (.*) ([0-9]+) (.*)$/) {
- $co{'committer'} = to_utf8($1);
+ $co{'committer'} = hide_mailaddrs_if_private(to_utf8($1));
$co{'committer_epoch'} = $2;
$co{'committer_tz'} = $3;
if ($co{'committer'} =~ m/^([^<]+) <([^>]*)>/) {
@@ -3493,23 +3560,6 @@ sub parse_commit_text {
$title =~ s/^ //;
if ($title ne "") {
$co{'title'} = chop_str($title, 80, 5);
- # remove leading stuff of merges to make the interesting part visible
- if (length($title) > 50) {
- $title =~ s/^Automatic //;
- $title =~ s/^merge (of|with) /Merge ... /i;
- if (length($title) > 50) {
- $title =~ s/(http|rsync):\/\///;
- }
- if (length($title) > 50) {
- $title =~ s/(master|www|rsync)\.//;
- }
- if (length($title) > 50) {
- $title =~ s/kernel.org:?//;
- }
- if (length($title) > 50) {
- $title =~ s/\/pub\/scm//;
- }
- }
$co{'title_short'} = chop_str($title, 50, 5);
last;
}
@@ -3517,9 +3567,10 @@ sub parse_commit_text {
if (! defined $co{'title'} || $co{'title'} eq "") {
$co{'title'} = $co{'title_short'} = '(no commit message)';
}
- # remove added spaces
+ # remove added spaces, redact e-mail addresses if applicable.
foreach my $line (@commit_lines) {
$line =~ s/^ //;
+ $line = hide_mailaddrs_if_private($line);
}
$co{'comment'} = \@commit_lines;
@@ -3591,7 +3642,7 @@ sub parse_difftree_raw_line {
# ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c'
# ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c'
- if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) {
+ if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ($oid_regex) ($oid_regex) (.)([0-9]{0,3})\t(.*)$/) {
$res{'from_mode'} = $1;
$res{'to_mode'} = $2;
$res{'from_id'} = $3;
@@ -3606,7 +3657,7 @@ sub parse_difftree_raw_line {
}
# '::100755 100755 100755 60e79ca1b01bc8b057abe17ddab484699a7f5fdb 94067cc5f73388f33722d52ae02f44692bc07490 94067cc5f73388f33722d52ae02f44692bc07490 MR git-gui/git-gui.sh'
# combined diff (for merge commit)
- elsif ($line =~ s/^(::+)((?:[0-7]{6} )+)((?:[0-9a-fA-F]{40} )+)([a-zA-Z]+)\t(.*)$//) {
+ elsif ($line =~ s/^(::+)((?:[0-7]{6} )+)((?:$oid_regex )+)([a-zA-Z]+)\t(.*)$//) {
$res{'nparents'} = length($1);
$res{'from_mode'} = [ split(' ', $2) ];
$res{'to_mode'} = pop @{$res{'from_mode'}};
@@ -3616,7 +3667,7 @@ sub parse_difftree_raw_line {
$res{'to_file'} = unquote($5);
}
# 'c512b523472485aef4fff9e57b229d9d243c967f'
- elsif ($line =~ m/^([0-9a-fA-F]{40})$/) {
+ elsif ($line =~ m/^($oid_regex)$/) {
$res{'commit'} = $1;
}
@@ -3644,7 +3695,7 @@ sub parse_ls_tree_line {
if ($opts{'-l'}) {
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa 16717 panic.c'
- $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40}) +(-|[0-9]+)\t(.+)$/s;
+ $line =~ m/^([0-9]+) (.+) ($oid_regex) +(-|[0-9]+)\t(.+)$/s;
$res{'mode'} = $1;
$res{'type'} = $2;
@@ -3657,7 +3708,7 @@ sub parse_ls_tree_line {
}
} else {
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
- $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s;
+ $line =~ m/^([0-9]+) (.+) ($oid_regex)\t(.+)$/s;
$res{'mode'} = $1;
$res{'type'} = $2;
@@ -3728,7 +3779,8 @@ sub git_get_heads_list {
my @headslist;
open my $fd, '-|', git_cmd(), 'for-each-ref',
- ($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
+ ($limit ? '--count='.($limit+1) : ()),
+ '--sort=-HEAD', '--sort=-committerdate',
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
@patterns
or return;
@@ -4011,7 +4063,7 @@ sub print_feed_meta {
$href_params{'extra_options'} = undef;
$href_params{'action'} = $type;
- $link_attr{'-href'} = href(%href_params);
+ $link_attr{'-href'} = esc_attr(href(%href_params));
print "<link ".
"rel=\"$link_attr{'-rel'}\" ".
"title=\"$link_attr{'-title'}\" ".
@@ -4020,7 +4072,7 @@ sub print_feed_meta {
"/>\n";
$href_params{'extra_options'} = '--no-merges';
- $link_attr{'-href'} = href(%href_params);
+ $link_attr{'-href'} = esc_attr(href(%href_params));
$link_attr{'-title'} .= ' (no merges)';
print "<link ".
"rel=\"$link_attr{'-rel'}\" ".
@@ -4033,10 +4085,12 @@ sub print_feed_meta {
} else {
printf('<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8" />'."\n",
- esc_attr($site_name), href(project=>undef, action=>"project_index"));
+ esc_attr($site_name),
+ esc_attr(href(project=>undef, action=>"project_index")));
printf('<link rel="alternate" title="%s projects feeds" '.
'href="%s" type="text/x-opml" />'."\n",
- esc_attr($site_name), href(project=>undef, action=>"opml"));
+ esc_attr($site_name),
+ esc_attr(href(project=>undef, action=>"opml")));
}
}
@@ -4142,19 +4196,20 @@ sub git_header_html {
my %opts = @_;
my $title = get_page_title();
- my $content_type = get_content_type_html();
- print $cgi->header(-type=>$content_type, -charset => 'utf-8',
+ print $cgi->header(-type=>get_content_type_html(), -charset => 'utf-8',
-status=> $status, -expires => $expires)
unless ($opts{'-no_http_header'});
my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
print <<EOF;
<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html [
+ <!ENTITY nbsp "&#xA0;">
+ <!ENTITY sdot "&#x22C5;">
+]>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<!-- git web interface version $version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
<!-- git core binaries version $git_version -->
<head>
-<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
<meta name="generator" content="gitweb/$version git/$git_version$mod_perl_version"/>
<meta name="robots" content="index, nofollow"/>
<title>$title</title>
@@ -4250,8 +4305,8 @@ sub git_footer_html {
if (defined $action &&
$action eq 'blame_incremental') {
print qq!<script type="text/javascript">\n!.
- qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
- qq! "!. href() .qq!");\n!.
+ qq!startBlame("!. esc_attr(href(action=>"blame_data", -replay=>1)) .qq!",\n!.
+ qq! "!. esc_attr(href()) .qq!");\n!.
qq!</script>\n!;
} else {
my ($jstimezone, $tz_cookie, $datetime_class) =
@@ -4588,7 +4643,7 @@ sub git_print_log {
# print log
my $skip_blank_line = 0;
foreach my $line (@$log) {
- if ($line =~ m/^\s*([A-Z][-A-Za-z]*-[Bb]y|C[Cc]): /) {
+ if ($line =~ m/^\s*([A-Z][-A-Za-z]*-([Bb]y|[Tt]o)|C[Cc]|(Clos|Fix)es): /) {
if (! $opts{'-remove_signoff'}) {
print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
$skip_blank_line = 1;
@@ -4799,7 +4854,7 @@ sub fill_from_file_info {
sub is_deleted {
my $diffinfo = shift;
- return $diffinfo->{'to_id'} eq ('0' x 40);
+ return $diffinfo->{'to_id'} eq ('0' x 40) || $diffinfo->{'to_id'} eq ('0' x 64);
}
# does patch correspond to [previous] difftree raw line
@@ -5246,7 +5301,7 @@ sub format_ctx_rem_add_lines {
# + c
# + d
#
- # Otherwise the highlightling would be confusing.
+ # Otherwise the highlighting would be confusing.
if ($is_combined) {
for (my $i = 0; $i < @$add; $i++) {
my $prefix_rem = substr($rem->[$i], 0, $num_parents);
@@ -6285,7 +6340,7 @@ sub git_search_changes {
-class => "list subject"},
chop_and_escape_str($co{'title'}, 50) . "<br/>");
} elsif (defined $set{'to_id'}) {
- next if ($set{'to_id'} =~ m/^0{40}$/);
+ next if is_deleted(\%set);
print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
hash=>$set{'to_id'}, file_name=>$set{'to_file'}),
@@ -6829,7 +6884,7 @@ sub git_blame_common {
# the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
# no <lines in group> for subsequent lines in group of lines
my ($full_rev, $orig_lineno, $lineno, $group_size) =
- ($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
+ ($line =~ /^($oid_regex) (\d+) (\d+)(?: (\d+))?$/);
if (!exists $metainfo{$full_rev}) {
$metainfo{$full_rev} = { 'nprevious' => 0 };
}
@@ -6879,7 +6934,7 @@ sub git_blame_common {
}
# 'previous' <sha1 of parent commit> <filename at commit>
if (exists $meta->{'previous'} &&
- $meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
+ $meta->{'previous'} =~ /^($oid_regex) (.*)$/) {
$meta->{'parent'} = $1;
$meta->{'file_parent'} = unquote($2);
}
@@ -6996,7 +7051,7 @@ sub git_blob_plain {
} else {
die_error(400, "No file name defined");
}
- } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+ } elsif ($hash =~ m/^$oid_regex$/) {
# blobs defined by non-textual hash id's can be cached
$expires = "+1d";
}
@@ -7040,6 +7095,7 @@ sub git_blob_plain {
($sandbox ? 'attachment' : 'inline')
. '; filename="' . $save_as . '"');
local $/ = undef;
+ local *FCGI::Stream::PRINT = $FCGI_Stream_PRINT_raw;
binmode STDOUT, ':raw';
print <$fd>;
binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@ -7057,7 +7113,7 @@ sub git_blob {
} else {
die_error(400, "No file name defined");
}
- } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+ } elsif ($hash =~ m/^$oid_regex$/) {
# blobs defined by non-textual hash id's can be cached
$expires = "+1d";
}
@@ -7118,8 +7174,8 @@ sub git_blob {
print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!;
}
print qq! src="! .
- href(action=>"blob_plain", hash=>$hash,
- hash_base=>$hash_base, file_name=>$file_name) .
+ esc_attr(href(action=>"blob_plain", hash=>$hash,
+ hash_base=>$hash_base, file_name=>$file_name)) .
qq!" />\n!;
} else {
my $nr;
@@ -7378,6 +7434,7 @@ sub git_snapshot {
open my $fd, "-|", $cmd
or die_error(500, "Execute git-archive failed");
+ local *FCGI::Stream::PRINT = $FCGI_Stream_PRINT_raw;
binmode STDOUT, ':raw';
print <$fd>;
binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@ -7434,7 +7491,8 @@ sub git_log_generic {
-accesskey => "n", -title => "Alt-n"}, "next");
}
my $patch_max = gitweb_get_feature('patches');
- if ($patch_max && !defined $file_name) {
+ if ($patch_max && !defined $file_name &&
+ !gitweb_check_feature('email-privacy')) {
if ($patch_max < 0 || @commitlist <= $patch_max) {
$paging_nav .= " &sdot; " .
$cgi->a({-href => href(action=>"patches", -replay=>1)},
@@ -7495,7 +7553,8 @@ sub git_commit {
} @$parents ) .
')';
}
- if (gitweb_check_feature('patches') && @$parents <= 1) {
+ if (gitweb_check_feature('patches') && @$parents <= 1 &&
+ !gitweb_check_feature('email-privacy')) {
$formats_nav .= " | " .
$cgi->a({-href => href(action=>"patch", -replay=>1)},
"patch");
@@ -7515,7 +7574,7 @@ sub git_commit {
# non-textual hash id's can be cached
my $expires;
- if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+ if ($hash =~ m/^$oid_regex$/) {
$expires = "+1d";
}
my $refs = git_get_references();
@@ -7609,7 +7668,7 @@ sub git_object {
close $fd;
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
- unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
+ unless ($line && $line =~ m/^([0-9]+) (.+) ($oid_regex)\t/) {
die_error(404, "File or directory for given base does not exist");
}
$type = $2;
@@ -7649,7 +7708,7 @@ sub git_blobdiff {
or die_error(404, "Blob diff not found");
} elsif (defined $hash &&
- $hash =~ /[0-9a-fA-F]{40}/) {
+ $hash =~ $oid_regex) {
# try to find filename from $hash
# read filtered raw output
@@ -7659,7 +7718,7 @@ sub git_blobdiff {
@difftree =
# ':100644 100644 03b21826... 3b93d5e7... M ls-files.c'
# $hash == to_id
- grep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ }
+ grep { /^:[0-7]{6} [0-7]{6} $oid_regex $hash/ }
map { chomp; $_ } <$fd>;
close $fd
or die_error(404, "Reading git-diff-tree failed");
@@ -7682,8 +7741,8 @@ sub git_blobdiff {
$hash ||= $diffinfo{'to_id'};
# non-textual hash id's can be cached
- if ($hash_base =~ m/^[0-9a-fA-F]{40}$/ &&
- $hash_parent_base =~ m/^[0-9a-fA-F]{40}$/) {
+ if ($hash_base =~ m/^$oid_regex$/ &&
+ $hash_parent_base =~ m/^$oid_regex$/) {
$expires = '+1d';
}
@@ -7808,7 +7867,8 @@ sub git_commitdiff {
$formats_nav =
$cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)},
"raw");
- if ($patch_max && @{$co{'parents'}} <= 1) {
+ if ($patch_max && @{$co{'parents'}} <= 1 &&
+ !gitweb_check_feature('email-privacy')) {
$formats_nav .= " | " .
$cgi->a({-href => href(action=>"patch", -replay=>1)},
"patch");
@@ -7819,7 +7879,7 @@ sub git_commitdiff {
$hash_parent ne '-c' && $hash_parent ne '--cc') {
# commitdiff with two commits given
my $hash_parent_short = $hash_parent;
- if ($hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
+ if ($hash_parent =~ m/^$oid_regex$/) {
$hash_parent_short = substr($hash_parent, 0, 7);
}
$formats_nav .=
@@ -7928,7 +7988,7 @@ sub git_commitdiff {
# non-textual hash id's can be cached
my $expires;
- if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+ if ($hash =~ m/^$oid_regex$/) {
$expires = "+1d";
}
@@ -8202,6 +8262,7 @@ sub git_feed {
} else {
$alt_url = href(-full=>1, action=>"summary");
}
+ $alt_url = esc_attr($alt_url);
print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
if ($format eq 'rss') {
print <<XML;
@@ -8239,7 +8300,7 @@ XML
$alt_url . '" />' . "\n" .
'<link rel="self" type="' . $content_type . '" href="' .
$cgi->self_url() . '" />' . "\n" .
- "<id>" . href(-full=>1) . "</id>\n" .
+ "<id>" . esc_url(href(-full=>1)) . "</id>\n" .
# use project owner for feed author
"<author><name>$owner</name></author>\n";
if (defined $favicon) {
@@ -8285,7 +8346,7 @@ XML
"<author>" . esc_html($co{'author'}) . "</author>\n" .
"<pubDate>$cd{'rfc2822'}</pubDate>\n" .
"<guid isPermaLink=\"true\">$co_url</guid>\n" .
- "<link>$co_url</link>\n" .
+ "<link>" . esc_html($co_url) . "</link>\n" .
"<description>" . esc_html($co{'title'}) . "</description>\n" .
"<content:encoded>" .
"<![CDATA[\n";
@@ -8307,8 +8368,8 @@ XML
}
print "</contributor>\n" .
"<published>$cd{'iso-8601'}</published>\n" .
- "<link rel=\"alternate\" type=\"text/html\" href=\"$co_url\" />\n" .
- "<id>$co_url</id>\n" .
+ "<link rel=\"alternate\" type=\"text/html\" href=\"" . esc_attr($co_url) . "\" />\n" .
+ "<id>" . esc_html($co_url) . "</id>\n" .
"<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
"<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
}
@@ -8415,8 +8476,8 @@ XML
}
my $path = esc_html(chop_str($proj{'path'}, 25, 5));
- my $rss = href('project' => $proj{'path'}, 'action' => 'rss', -full => 1);
- my $html = href('project' => $proj{'path'}, 'action' => 'summary', -full => 1);
+ my $rss = esc_attr(href('project' => $proj{'path'}, 'action' => 'rss', -full => 1));
+ my $html = esc_attr(href('project' => $proj{'path'}, 'action' => 'summary', -full => 1));
print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
}
print <<XML;