summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
4c4de00)
We need to escape ampersands (and some other characters for href
attributes), so introduce a `mid_href' sub to do just that.
'<', '>' and '"' were always escaped, so there's no risk of tag
or attribute injection, but creative Message-IDs could cause
confusion for some parsers and generate invalid URLs.
Start getting rid of the bloated, over-engineered OO Hval API
while we're at it, I only noticed this bug because I started
killing off Hval->new* callers.
package PublicInbox::ExtMsg;
use strict;
use warnings;
package PublicInbox::ExtMsg;
use strict;
use warnings;
-use PublicInbox::Hval qw(ascii_html prurl);
+use PublicInbox::Hval qw(ascii_html prurl mid_href);
use PublicInbox::WwwStream;
our $MIN_PARTIAL_LEN = 16;
use PublicInbox::WwwStream;
our $MIN_PARTIAL_LEN = 16;
- my $h = PublicInbox::Hval->new_msgid($mid);
- my $href = $h->{href};
- my $html = $h->as_html;
+ my $href = mid_href($mid);
+ my $html = ascii_html($mid);
my $title = "<$html> not found";
my $s = "<pre>Message-ID <$html>\nnot found\n";
if ($n_partial) {
my $title = "<$html> not found";
my $s = "<pre>Message-ID <$html>\nnot found\n";
if ($n_partial) {
my $env = $ctx->{env} if $ibx->{name} eq $cur_name;
my $u = $ibx->base_url($env) or next;
foreach my $m (@$res) {
my $env = $ctx->{env} if $ibx->{name} eq $cur_name;
my $u = $ibx->base_url($env) or next;
foreach my $m (@$res) {
- my $p = PublicInbox::Hval->new_msgid($m);
- my $r = $p->{href};
- my $t = $p->as_html;
- $s .= qq{<a\nhref="$u$r/">$u$t/</a>\n};
+ my $href = mid_href($m);
+ my $html = ascii_html($m);
+ $s .= qq{<a\nhref="$u$href/">$u$html/</a>\n};
sub exact {
my ($ctx, $found, $mid) = @_;
sub exact {
my ($ctx, $found, $mid) = @_;
- my $h = PublicInbox::Hval->new_msgid($mid);
- my $href = $h->{href};
- my $html = $h->as_html;
+ my $href = mid_href($mid);
+ my $html = ascii_html($mid);
my $title = "<$html> found in ";
my $end = @$found == 1 ? 'another inbox' : 'other inboxes';
$ctx->{-title_html} = $title . $end;
my $title = "<$html> found in ";
my $end = @$found == 1 ? 'another inbox' : 'other inboxes';
$ctx->{-title_html} = $title . $end;
use PublicInbox::MID qw/mid_clean mid_escape/;
use base qw/Exporter/;
our @EXPORT_OK = qw/ascii_html obfuscate_addrs to_filename src_escape
use PublicInbox::MID qw/mid_clean mid_escape/;
use base qw/Exporter/;
our @EXPORT_OK = qw/ascii_html obfuscate_addrs to_filename src_escape
+ to_attr prurl mid_href/;
my $enc_ascii = find_encoding('us-ascii');
# safe-ish acceptable filename pattern for portability
my $enc_ascii = find_encoding('us-ascii');
# safe-ish acceptable filename pattern for portability
-sub new_msgid {
- my ($class, $msgid) = @_;
- $class->new($msgid, mid_escape($msgid));
-}
+sub mid_href { ascii_html(mid_escape($_[0])) }
# some of these overrides are standard C escapes so they're
# easy-to-understand when rendered.
# some of these overrides are standard C escapes so they're
# easy-to-understand when rendered.
use strict;
use warnings;
use Digest::SHA qw/sha1_hex/;
use strict;
use warnings;
use Digest::SHA qw/sha1_hex/;
-use PublicInbox::Hval qw(ascii_html);
+use PublicInbox::Hval qw(ascii_html mid_href);
my $SALT = rand;
my $LINK_RE = qr{([\('!])?\b((?:ftps?|https?|nntps?|gopher)://
my $SALT = rand;
my $LINK_RE = qr{([\('!])?\b((?:ftps?|https?|nntps?|gopher)://
sub linkify_mids {
my ($self, $pfx, $str, $raw) = @_;
$$str =~ s!<([^>]+)>!
sub linkify_mids {
my ($self, $pfx, $str, $raw) = @_;
$$str =~ s!<([^>]+)>!
- my $msgid = PublicInbox::Hval->new_msgid($1);
- my $html = $msgid->as_html;
- my $href = $msgid->{href};
- $href = ascii_html($href); # for IDN
+ my $mid = $1;
+ my $html = ascii_html($mid);
+ my $href = mid_href($mid);
# salt this, as this could be exploited to show
# links in the HTML which don't show up in the raw mail.
# salt this, as this could be exploited to show
# links in the HTML which don't show up in the raw mail.
use strict;
use warnings;
use URI::Escape qw/uri_escape_utf8/;
use strict;
use warnings;
use URI::Escape qw/uri_escape_utf8/;
-use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
+use PublicInbox::Hval qw(ascii_html obfuscate_addrs mid_href);
use PublicInbox::Address;
use PublicInbox::Address;
-use PublicInbox::MID qw/mid_clean mid_escape/;
+use PublicInbox::MID qw(mid_clean);
sub squote_maybe ($) {
my ($val) = @_;
sub squote_maybe ($) {
my ($val) = @_;
$subj = "Re: $subj" unless $subj =~ /\bRe:/i;
my $mid = $hdr->header_raw('Message-ID');
push @arg, '--in-reply-to='.squote_maybe(mid_clean($mid));
$subj = "Re: $subj" unless $subj =~ /\bRe:/i;
my $mid = $hdr->header_raw('Message-ID');
push @arg, '--in-reply-to='.squote_maybe(mid_clean($mid));
- my $irt = mid_escape($mid);
+ my $irt = mid_href($mid);
delete $cc->{$to};
if ($obfs) {
my $arg_to = $to;
delete $cc->{$to};
if ($obfs) {
my $arg_to = $to;
use warnings;
use URI::Escape qw(uri_unescape uri_escape);
use PublicInbox::SearchMsg;
use warnings;
use URI::Escape qw(uri_unescape uri_escape);
use PublicInbox::SearchMsg;
-use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
+use PublicInbox::Hval qw(ascii_html obfuscate_addrs mid_href);
use PublicInbox::View;
use PublicInbox::WwwAtomStream;
use PublicInbox::SearchThread;
use PublicInbox::View;
use PublicInbox::WwwAtomStream;
use PublicInbox::SearchThread;
obfuscate_addrs($obfs_ibx, $f);
}
my $date = PublicInbox::View::fmt_ts($smsg->{ds});
obfuscate_addrs($obfs_ibx, $f);
}
my $date = PublicInbox::View::fmt_ts($smsg->{ds});
- my $mid = PublicInbox::Hval->new_msgid($smsg->{mid})->{href};
+ my $mid = mid_href($smsg->{mid});
$s = '(no subject)' if $s eq '';
$$res .= qq{$rank. <b><a\nhref="$mid/">}.
$s . "</a></b>\n";
$s = '(no subject)' if $s eq '';
$$res .= qq{$rank. <b><a\nhref="$mid/">}.
$s . "</a></b>\n";
use warnings;
use bytes (); # only for bytes::length
use PublicInbox::MsgTime qw(msg_datestamp);
use warnings;
use bytes (); # only for bytes::length
use PublicInbox::MsgTime qw(msg_datestamp);
-use PublicInbox::Hval qw(ascii_html obfuscate_addrs prurl);
+use PublicInbox::Hval qw(ascii_html obfuscate_addrs prurl mid_href);
use PublicInbox::Linkify;
use PublicInbox::Linkify;
-use PublicInbox::MID qw/id_compress mid_escape mids mids_for_index references/;
+use PublicInbox::MID qw/id_compress mids mids_for_index references/;
use PublicInbox::MsgIter;
use PublicInbox::Address;
use PublicInbox::WwwStream;
use PublicInbox::MsgIter;
use PublicInbox::Address;
use PublicInbox::WwwStream;
my $more = $ctx->{more};
if ($nr == 1) {
# $more cannot be true w/o $smsg being defined:
my $more = $ctx->{more};
if ($nr == 1) {
# $more cannot be true w/o $smsg being defined:
- $ctx->{mhref} = $more ? '../'.mid_escape($ctx->{smsg}->mid).'/'
+ $ctx->{mhref} = $more ? '../'.mid_href($ctx->{smsg}->{mid}).'/'
: '';
multipart_text_as_html(delete $ctx->{mime}, $ctx);
${delete $ctx->{obuf}} .= '</pre><hr>';
: '';
multipart_text_as_html(delete $ctx->{mime}, $ctx);
${delete $ctx->{obuf}} .= '</pre><hr>';
my $next = $ibx->over->next_by_mid($ctx->{mid}, \$id, \$prev);
$ctx->{more} = $next ? [ $id, $prev, $next ] : undef;
return '' unless $smsg;
my $next = $ibx->over->next_by_mid($ctx->{mid}, \$id, \$prev);
$ctx->{more} = $next ? [ $id, $prev, $next ] : undef;
return '' unless $smsg;
- $ctx->{mhref} = '../' . mid_escape($smsg->{mid}) . '/';
+ $ctx->{mhref} = '../' . mid_href($smsg->{mid}) . '/';
my $mime = delete $smsg->{mime};
_msg_page_prepare_obuf($mime->header_obj, $ctx, $nr);
multipart_text_as_html($mime, $ctx);
my $mime = delete $smsg->{mime};
_msg_page_prepare_obuf($mime->header_obj, $ctx, $nr);
multipart_text_as_html($mime, $ctx);
obfuscate_addrs($obfs_ibx, $from) if $obfs_ibx;
$rv .= "From: $from @ ".fmt_ts($ds)." UTC";
my $upfx = $ctx->{-upfx};
obfuscate_addrs($obfs_ibx, $from) if $obfs_ibx;
$rv .= "From: $from @ ".fmt_ts($ds)." UTC";
my $upfx = $ctx->{-upfx};
- my $mhref = $upfx . mid_escape($mid_raw) . '/';
+ my $mhref = $upfx . mid_href($mid_raw) . '/';
$rv .= qq{ (<a\nhref="$mhref">permalink</a> / };
$rv .= qq{<a\nhref="${mhref}raw">raw</a>)\n};
my $to = fold_addresses(_hdr_names_html($hdr, 'To'));
$rv .= qq{ (<a\nhref="$mhref">permalink</a> / };
$rv .= qq{<a\nhref="${mhref}raw">raw</a>)\n};
my $to = fold_addresses(_hdr_names_html($hdr, 'To'));
my $mapping = $ctx->{mapping};
if (!$mapping && (defined($irt) || defined($irt = in_reply_to($hdr)))) {
my $mapping = $ctx->{mapping};
if (!$mapping && (defined($irt) || defined($irt = in_reply_to($hdr)))) {
- my $mirt = PublicInbox::Hval->new_msgid($irt);
- my $href = $upfx . $mirt->{href}. '/';
- my $html = $mirt->as_html;
+ my $href = $upfx . mid_href($irt) . '/';
+ my $html = ascii_html($irt);
$rv .= qq(In-Reply-To: <<a\nhref="$href">$html</a>>\n)
}
$rv .= "\n";
$rv .= qq(In-Reply-To: <<a\nhref="$href">$html</a>>\n)
}
$rv .= "\n";
}
$ctx->{-title_html} = join(' - ', @title);
if (scalar(@$mids) == 1) { # common case
}
$ctx->{-title_html} = join(' - ', @title);
if (scalar(@$mids) == 1) { # common case
- my $mid = PublicInbox::Hval->new_msgid($mids->[0]);
- my $mhtml = $mid->as_html;
+ my $mhtml = ascii_html($mids->[0]);
$rv .= "Message-ID: <$mhtml> ";
$rv .= "(<a\nhref=\"raw\">raw</a>)\n";
} else {
$rv .= "Message-ID: <$mhtml> ";
$rv .= "(<a\nhref=\"raw\">raw</a>)\n";
} else {
$refs = references($hdr);
my $irt = pop @$refs;
if (defined $irt) {
$refs = references($hdr);
my $irt = pop @$refs;
if (defined $irt) {
- my $v = PublicInbox::Hval->new_msgid($irt);
- my $html = $v->as_html;
- my $href = $v->{href};
+ my $html = ascii_html($irt);
+ my $href = mid_href($irt);
$rv .= "In-Reply-To: <";
$rv .= "<a\nhref=\"../$href/\">$html</a>>\n";
}
$rv .= "In-Reply-To: <";
$rv .= "<a\nhref=\"../$href/\">$html</a>>\n";
}
$next = $prev = ' ';
if (my $n = $ctx->{next_msg}) {
$next = $prev = ' ';
if (my $n = $ctx->{next_msg}) {
- $n = PublicInbox::Hval->new_msgid($n)->{href};
$next = "<a\nhref=\"$upfx$n/\"\nrel=next>next</a>";
}
my $u;
my $par = $ctx->{parent_msg};
if ($par) {
$next = "<a\nhref=\"$upfx$n/\"\nrel=next>next</a>";
}
my $u;
my $par = $ctx->{parent_msg};
if ($par) {
- $u = PublicInbox::Hval->new_msgid($par)->{href};
$u = "$upfx$u/";
}
if (my $p = $ctx->{prev_msg}) {
$u = "$upfx$u/";
}
if (my $p = $ctx->{prev_msg}) {
- $prev = PublicInbox::Hval->new_msgid($p)->{href};
if ($p && $par && $p eq $par) {
$prev = "<a\nhref=\"$upfx$prev/\"\n" .
'rel=prev>prev parent</a>';
if ($p && $par && $p eq $par) {
$prev = "<a\nhref=\"$upfx$prev/\"\n" .
'rel=prev>prev parent</a>';
}
sub linkify_ref_no_over {
}
sub linkify_ref_no_over {
- my $v = PublicInbox::Hval->new_msgid($_[0]);
- my $html = $v->as_html;
- my $href = $v->{href};
+ my ($mid) = @_;
+ my $href = mid_href($mid);
+ my $html = ascii_html($mid);
"<<a\nhref=\"../$href/\">$html</a>>";
}
"<<a\nhref=\"../$href/\">$html</a>>";
}
sub ghost_parent {
my ($upfx, $mid) = @_;
sub ghost_parent {
my ($upfx, $mid) = @_;
- $mid = PublicInbox::Hval->new_msgid($mid);
- my $href = $mid->{href};
- my $html = $mid->as_html;
+ my $href = mid_href($mid);
+ my $html = ascii_html($mid);
qq{[parent not found: <<a\nhref="$upfx$href/">$html</a>>]};
}
qq{[parent not found: <<a\nhref="$upfx$href/">$html</a>>]};
}
$map->[0] = "$d<a\nhref=\"$m\">$end";
$id = "\nid=r".$id;
} else {
$map->[0] = "$d<a\nhref=\"$m\">$end";
$id = "\nid=r".$id;
} else {
- $m = $ctx->{-upfx}.mid_escape($mid).'/';
+ $m = $ctx->{-upfx}.mid_href($mid).'/';
}
$$skel .= $d . "<a\nhref=\"$m\"$id>" . $end;
1;
}
$$skel .= $d . "<a\nhref=\"$m\"$id>" . $end;
1;
$d .= ' ' if exists $ctx->{searchview};
$d .= indent_for($level) . th_pfx($level);
my $upfx = $ctx->{-upfx};
$d .= ' ' if exists $ctx->{searchview};
$d .= indent_for($level) . th_pfx($level);
my $upfx = $ctx->{-upfx};
- my $m = PublicInbox::Hval->new_msgid($mid);
- my $href = $upfx . $m->{href} . '/';
- my $html = $m->as_html;
+ my $href = $upfx . mid_href($mid) . '/';
+ my $html = ascii_html($mid);
my $mapping = $ctx->{mapping};
my $map = $mapping->{$mid} if $mapping;
my $mapping = $ctx->{mapping};
my $map = $mapping->{$mid} if $mapping;
@$topic = ();
next unless defined $top_subj; # ghost topic
my $mid = delete $seen->{$top_subj};
@$topic = ();
next unless defined $top_subj; # ghost topic
my $mid = delete $seen->{$top_subj};
- my $href = mid_escape($mid);
+ my $href = mid_href($mid);
my $prev_subj = [ split(/ /, $top_subj) ];
$top_subj = ascii_html($top_subj);
$ds = fmt_ts($ds);
my $prev_subj = [ split(/ /, $top_subj) ];
$top_subj = ascii_html($top_subj);
$ds = fmt_ts($ds);
$prev_subj = \@next_prev;
$subj = ascii_html($subj);
obfuscate_addrs($obfs_ibx, $subj) if $obfs_ibx;
$prev_subj = \@next_prev;
$subj = ascii_html($subj);
obfuscate_addrs($obfs_ibx, $subj) if $obfs_ibx;
- $href = mid_escape($mid);
+ $href = mid_href($mid);
$s .= indent_for($level) . TCHILD;
$s .= qq(<a\nhref="$href/T/#u">$subj</a>$omit\n);
}
$s .= indent_for($level) . TCHILD;
$s .= qq(<a\nhref="$href/T/#u">$subj</a>$omit\n);
}
use POSIX qw(strftime);
use Digest::SHA qw(sha1_hex);
use PublicInbox::Address;
use POSIX qw(strftime);
use Digest::SHA qw(sha1_hex);
use PublicInbox::Address;
-use PublicInbox::Hval qw(ascii_html);
-use PublicInbox::MID qw(mid_escape);
+use PublicInbox::Hval qw(ascii_html mid_href);
use PublicInbox::MsgTime qw(msg_timestamp);
# called by PSGI server after getline:
use PublicInbox::MsgTime qw(msg_timestamp);
# called by PSGI server after getline:
my $mid = $ctx->{mid};
my $page_id;
if (defined $mid) { # per-thread
my $mid = $ctx->{mid};
my $page_id;
if (defined $mid) { # per-thread
- $self_url .= mid_escape($mid).'/t.atom';
+ $self_url .= mid_href($mid).'/t.atom';
$page_id = to_uuid("t\n".$mid)
} elsif (defined $search_q) {
my $query = $search_q->{'q'};
$page_id = to_uuid("t\n".$mid)
} elsif (defined $search_q) {
my $query = $search_q->{'q'};
my $base = $ctx->{feed_base_url};
if (defined $irt) {
my $irt_uuid = to_uuid($irt);
my $base = $ctx->{feed_base_url};
if (defined $irt) {
my $irt_uuid = to_uuid($irt);
- $irt = mid_escape($irt);
$irt = qq(<thr:in-reply-to\nref="$irt_uuid"\n).
qq(href="$base$irt/"/>);
} else {
$irt = '';
}
$irt = qq(<thr:in-reply-to\nref="$irt_uuid"\n).
qq(href="$base$irt/"/>);
} else {
$irt = '';
}
- my $href = $base . mid_escape($mid) . '/';
+ my $href = $base . mid_href($mid) . '/';
my $t = msg_timestamp($hdr);
my @t = gmtime(defined $t ? $t : time);
my $updated = feed_updated(@t);
my $t = msg_timestamp($hdr);
my @t = gmtime(defined $t ? $t : time);
my $updated = feed_updated(@t);
my $msgs = <<'';
F1V5OR6NMF.3M649JTLO9IXD@tux.localdomain/hehe1"'<foo
F1V5NB0PTU.3U0DCVGAJ750Z@tux.localdomain"'<>/foo
my $msgs = <<'';
F1V5OR6NMF.3M649JTLO9IXD@tux.localdomain/hehe1"'<foo
F1V5NB0PTU.3U0DCVGAJ750Z@tux.localdomain"'<>/foo
+F1V5NB0PTU.3U0DCVGAJ750Z@tux&.ampersand
F1V5MIHGCU.2ABINKW6WBE8N@tux.localdomain/raw
F1V5LF9D9C.2QT5PGXZQ050E@tux.localdomain/t.atom
F1V58X3CMU.2DCCVAKQZGADV@tux.localdomain/../../../../foo
F1V5MIHGCU.2ABINKW6WBE8N@tux.localdomain/raw
F1V5LF9D9C.2QT5PGXZQ050E@tux.localdomain/t.atom
F1V58X3CMU.2DCCVAKQZGADV@tux.localdomain/../../../../foo
'got escaped links to all messages');
@xmids = reverse @xmids;
'got escaped links to all messages');
@xmids = reverse @xmids;
+ my %uxs = ( gt => '>', lt => '<' );
foreach my $i (0..$#xmids) {
foreach my $i (0..$#xmids) {
- $res = $cb->(GET("/bad-mids/$xmids[$i]/raw"));
- is($res->code, 200, 'got 200 OK raw message');
+ my $uri = $xmids[$i];
+ $uri =~ s/&#([0-9]+);/sprintf("%c", $1)/sge;
+ $uri =~ s/&(lt|gt);/$uxs{$1}/sge;
+ $res = $cb->(GET("/bad-mids/$uri/raw"));
+ is($res->code, 200, 'got 200 OK raw message '.$uri);
like($res->content, qr/Message-ID: <\Q$mids[$i]\E>/s,
'retrieved correct message');
}
like($res->content, qr/Message-ID: <\Q$mids[$i]\E>/s,
'retrieved correct message');
}