lib/PublicInbox/Config.pm | 2 +- lib/PublicInbox/Feed.pm | 2 +- lib/PublicInbox/Filter/RubyLang.pm | 2 +- lib/PublicInbox/GitHTTPBackend.pm | 8 ++++---- lib/PublicInbox/HTTP.pm | 2 +- lib/PublicInbox/Hval.pm | 3 +++ lib/PublicInbox/Inbox.pm | 6 +++--- lib/PublicInbox/Linkify.pm | 5 +++-- lib/PublicInbox/MID.pm | 4 ++-- lib/PublicInbox/MsgTime.pm | 7 ++++--- lib/PublicInbox/NNTP.pm | 16 ++++++++-------- lib/PublicInbox/NewsWWW.pm | 2 +- lib/PublicInbox/Search.pm | 2 +- lib/PublicInbox/SearchView.pm | 4 ++-- lib/PublicInbox/SolverGit.pm | 2 +- lib/PublicInbox/V2Writable.pm | 4 ++-- lib/PublicInbox/View.pm | 6 +++--- lib/PublicInbox/ViewDiff.pm | 4 ++-- lib/PublicInbox/WWW.pm | 20 +++++++++++++------- lib/PublicInbox/WwwAttach.pm | 2 +- lib/PublicInbox/WwwListing.pm | 4 ++-- lib/PublicInbox/Xapcmd.pm | 6 +++--- script/public-inbox-purge | 2 +- t/linkify.t | 12 ++++++++++++ diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm index 09f9179b085a4dd90aed20e0d8b277ede66cc870..6e85750a7832fc927631847199fd5d447d76574a 100644 --- a/lib/PublicInbox/Config.pm +++ b/lib/PublicInbox/Config.pm @@ -307,7 +307,7 @@ warn "$_ without repo.url\n"; } } elsif (m!\Ainclude=(.+)\z!) { parse_cgitrc($self, $1, $nesting + 1); - } elsif (m!\A(scan-hidden-path|remove-suffix)=(\d+)\z!) { + } elsif (m!\A(scan-hidden-path|remove-suffix)=([0-9]+)\z!) { my ($k, $v) = ($1, $2); $k =~ tr/-/_/; $self->{"-cgit_$k"} = $v; diff --git a/lib/PublicInbox/Feed.pm b/lib/PublicInbox/Feed.pm index a04838a1a608948cbc096af61413337bd0f9444e..ae07189504327530290eb986bede736ae25c25cd 100644 --- a/lib/PublicInbox/Feed.pm +++ b/lib/PublicInbox/Feed.pm @@ -102,7 +102,7 @@ my $hex = '[a-f0-9]'; my $addmsg = qr!^:000000 100644 \S+ (\S+) A\t${hex}{2}/${hex}{38}$!; my $delmsg = qr!^:100644 000000 (\S+) \S+ D\t(${hex}{2}/${hex}{38})$!; - my $refhex = qr/(?:HEAD|${hex}{4,40})(?:~\d+)?/; + my $refhex = qr/(?:HEAD|${hex}{4,40})(?:~[0-9]+)?/; # revision ranges may be specified my $range = 'HEAD'; diff --git a/lib/PublicInbox/Filter/RubyLang.pm b/lib/PublicInbox/Filter/RubyLang.pm index a43d67a9352e4ea6ab71aad954b3fe44933d55e3..d40705b74e0757f4772b399da73a3c66bda8c55a 100644 --- a/lib/PublicInbox/Filter/RubyLang.pm +++ b/lib/PublicInbox/Filter/RubyLang.pm @@ -50,7 +50,7 @@ return $self->REJECT('Message-ID missing') unless (@$mids); my @v = $hdr->header_raw('X-Mail-Count'); my $n; foreach (@v) { - /\A\s*(\d+)\s*\z/ or next; + /\A\s*([0-9]+)\s*\z/ or next; $n = $1; last; } diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm index 09411048db25a8d4fcb41237d4285fa46abd9960..a2a81f8ea66a2dbe3ed81f885a5fda945e71bb38 100644 --- a/lib/PublicInbox/GitHTTPBackend.pm +++ b/lib/PublicInbox/GitHTTPBackend.pm @@ -51,8 +51,8 @@ $git = PublicInbox::Git->new($git) unless ref($git); # Documentation/technical/http-protocol.txt in git.git # requires one and exactly one query parameter: - if ($env->{QUERY_STRING} =~ /\Aservice=git-\w+-pack\z/ || - $path =~ /\Agit-\w+-pack\z/) { + if ($env->{QUERY_STRING} =~ /\Aservice=git-[A-Za-z0-9_]+-pack\z/ || + $path =~ /\Agit-[A-Za-z0-9_]+-pack\z/) { my $ok = serve_smart($env, $git, $path); return $ok if $ok; } @@ -90,7 +90,7 @@ my $size = -s $in; my $len = $size; my $code = 200; push @$h, 'Content-Type', $type; - if (($env->{HTTP_RANGE} || '') =~ /\bbytes=(\d*)-(\d*)\z/) { + if (($env->{HTTP_RANGE} || '') =~ /\bbytes=([0-9]*)-([0-9]*)\z/) { ($code, $len) = prepare_range($env, $in, $h, $1, $2, $size); if ($code == 416) { push @$h, 'Content-Range', "bytes */$size"; @@ -260,7 +260,7 @@ my @h; foreach my $l (split(/\r?\n/, $h)) { my ($k, $v) = split(/:\s*/, $l, 2); if ($k =~ /\AStatus\z/i) { - ($code) = ($v =~ /\b(\d+)\b/); + ($code) = ($v =~ /\b([0-9]+)\b/); } else { push @h, $k, $v; } diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm index 10e6d6a43b518115c7eece8a5f11e67ebe613fb2..977614b489d80143c75ebe366513194e5d4977cb 100644 --- a/lib/PublicInbox/HTTP.pm +++ b/lib/PublicInbox/HTTP.pm @@ -142,7 +142,7 @@ my $env = $self->{env}; $env->{REMOTE_ADDR} = $self->{remote_addr}; $env->{REMOTE_PORT} = $self->{remote_port}; if (my $host = $env->{HTTP_HOST}) { - $host =~ s/:(\d+)\z// and $env->{SERVER_PORT} = $1; + $host =~ s/:([0-9]+)\z// and $env->{SERVER_PORT} = $1; $env->{SERVER_NAME} = $host; } if (defined $input) { diff --git a/lib/PublicInbox/Hval.pm b/lib/PublicInbox/Hval.pm index 95a0f7095b59f2a6683b3921f06cfb07b13939f0..2b4439703f59b692e9c6c80a628c809185c103fa 100644 --- a/lib/PublicInbox/Hval.pm +++ b/lib/PublicInbox/Hval.pm @@ -13,6 +13,9 @@ our @EXPORT_OK = qw/ascii_html obfuscate_addrs to_filename src_escape to_attr from_attr/; my $enc_ascii = find_encoding('us-ascii'); +# safe-ish acceptable filename pattern for portability +our $FN = '[a-zA-Z0-9][a-zA-Z0-9_\-\.]+[a-zA-Z0-9]'; # needs \z anchor + sub new { my ($class, $raw, $href) = @_; diff --git a/lib/PublicInbox/Inbox.pm b/lib/PublicInbox/Inbox.pm index b3178b987a7a031dc96d134fa7be13423fda1866..c93303322194e024b8125b8d8b64ca014fe00483 100644 --- a/lib/PublicInbox/Inbox.pm +++ b/lib/PublicInbox/Inbox.pm @@ -74,7 +74,7 @@ my ($opts, $field, $default) = @_; my $val = $opts->{$field}; if (defined $val) { $val = $val->[-1] if ref($val) eq 'ARRAY'; - $val = undef if $val !~ /\A\d+\z/; + $val = undef if $val !~ /\A[0-9]+\z/; } $opts->{$field} = $val || $default; } @@ -87,7 +87,7 @@ # full key is: publicinbox.$NAME.httpbackendmax my $mkey = $pfx.'max'; my $val = $self->{$mkey} or return; my $lim; - if ($val =~ /\A\d+\z/) { + if ($val =~ /\A[0-9]+\z/) { require PublicInbox::Qspawn; $lim = PublicInbox::Qspawn::Limiter->new($val); } elsif ($val =~ /\A[a-z][a-z0-9]*\z/) { @@ -161,7 +161,7 @@ my $gits = "$self->{mainrepo}/git"; if (opendir my $dh, $gits) { my $max = -1; while (defined(my $git_dir = readdir($dh))) { - $git_dir =~ m!\A(\d+)\.git\z! or next; + $git_dir =~ m!\A([0-9]+)\.git\z! or next; $max = $1 if $1 > $max; } $part = $self->{-max_git_part} = $max if $max >= 0; diff --git a/lib/PublicInbox/Linkify.pm b/lib/PublicInbox/Linkify.pm index d4778e7de371ecc5c3059363bb0d0ec1cc334686..84960a98889fd4c53cc68aa5fce72eac1094084f 100644 --- a/lib/PublicInbox/Linkify.pm +++ b/lib/PublicInbox/Linkify.pm @@ -13,6 +13,7 @@ package PublicInbox::Linkify; use strict; use warnings; use Digest::SHA qw/sha1_hex/; +use PublicInbox::Hval qw(ascii_html); my $SALT = rand; my $LINK_RE = qr{([\('!])?\b((?:ftps?|https?|nntps?|gopher):// @@ -61,12 +62,12 @@ } elsif ($url !~ /\(/ && $url =~ s/\)\z//) { $end = ')'; } + $url = ascii_html($url); # for IDN + # salt this, as this could be exploited to show # links in the HTML which don't show up in the raw mail. my $key = sha1_hex($url . $SALT); - # only escape ampersands, others do not match LINK_RE - $url =~ s/&/&/g; $_[0]->{$key} = $url; $beg . 'PI-LINK-'. $key . $end; ^ge; diff --git a/lib/PublicInbox/MID.pm b/lib/PublicInbox/MID.pm index 7f1ab15ea731db8f0f70304662afe338754b5c6c..6904d61a0303bb0edd2b17b479c85e6bd13e76ff 100644 --- a/lib/PublicInbox/MID.pm +++ b/lib/PublicInbox/MID.pm @@ -26,11 +26,11 @@ } $mid; } -# this is idempotent +# this is idempotent, used for HTML anchor/ids and such sub id_compress { my ($id, $force) = @_; - if ($force || $id =~ /[^\w\-]/ || length($id) > MID_MAX) { + if ($force || $id =~ /[^a-zA-Z0-9_\-]/ || length($id) > MID_MAX) { utf8::encode($id); return sha1_hex($id); } diff --git a/lib/PublicInbox/MsgTime.pm b/lib/PublicInbox/MsgTime.pm index 62160233f78d627d0bfc9c2e24b72f634d42005b..12412825800952c35f1d189841758fe0e7a02128 100644 --- a/lib/PublicInbox/MsgTime.pm +++ b/lib/PublicInbox/MsgTime.pm @@ -44,8 +44,9 @@ my ($hdr) = @_; # Email::MIME::Header my @recvd = $hdr->header_raw('Received'); my ($ts); foreach my $r (@recvd) { - $r =~ /\s*(\d+\s+[[:alpha:]]+\s+\d{2,4}\s+ - \d+\D\d+(?:\D\d+)\s+([\+\-]\d+))/sx or next; + $r =~ /\s*([0-9]+\s+[a-zA-Z]+\s+[0-9]{2,4}\s+ + [0-9]+[^0-9][0-9]+(?:[^0-9][0-9]+) + \s+([\+\-][0-9]+))/sx or next; $ts = eval { str2date_zone($1) } and return $ts; my $mid = $hdr->header_raw('Message-ID'); warn "no date in $mid Received: $r\n"; @@ -59,7 +60,7 @@ my @date = $hdr->header_raw('Date'); my ($ts); foreach my $d (@date) { # Y2K problems: 3-digit years - $d =~ s!([A-Za-z]{3}) (\d{3}) (\d\d:\d\d:\d\d)! + $d =~ s!([A-Za-z]{3}) ([0-9]{3}) ([0-9]{2}:[0-9]{2}:[0-9]{2})! my $yyyy = $2 + 1900; "$1 $yyyy $3"!e; $ts = eval { str2date_zone($d) } and return $ts; if ($@) { diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm index 8cb6c56de82ba765a1fa2474408fb3002de16fb8..be80560ffa4a965a02e597796790ad7082d08f4d 100644 --- a/lib/PublicInbox/NNTP.pm +++ b/lib/PublicInbox/NNTP.pm @@ -121,7 +121,7 @@ # returns 1 if we can continue, 0 if not due to buffered writes or disconnect sub process_line ($$) { my ($self, $l) = @_; - my ($req, @args) = split(/\s+/, $l); + my ($req, @args) = split(/[ \t]/, $l); return 1 unless defined($req); # skip blank line $req = lc($req); $req = eval { @@ -437,7 +437,7 @@ # clobber some my $xref = xref($self, $ng, $n, $mid); $hdr->header_set('Xref', $xref); - $xref =~ s/:\d+//g; + $xref =~ s/:[0-9]+//g; $hdr->header_set('Newsgroups', (split(/ /, $xref, 2))[1]); header_append($hdr, 'List-Post', "{-primary_address}>"); if (my $url = $ng->base_url) { @@ -453,7 +453,7 @@ my $ng = $self->{ng}; my ($n, $mid); my $err; if (defined $art) { - if ($art =~ /\A\d+\z/o) { + if ($art =~ /\A[0-9]+\z/) { $err = '423 no such article number in this group'; $n = int($art); goto find_mid; @@ -508,7 +508,7 @@ } sub set_art { my ($self, $art) = @_; - $self->{article} = $art if defined $art && $art =~ /\A\d+\z/; + $self->{article} = $art if defined $art && $art =~ /\A[0-9]+\z/; } sub _header ($) { @@ -576,11 +576,11 @@ my $ng = $self->{ng} or return '412 no news group has been selected'; defined $range or return '420 No article(s) selected'; my ($beg, $end); my ($min, $max) = $ng->mm->minmax; - if ($range =~ /\A(\d+)\z/) { + if ($range =~ /\A([0-9]+)\z/) { $beg = $end = $1; - } elsif ($range =~ /\A(\d+)-\z/) { + } elsif ($range =~ /\A([0-9]+)-\z/) { ($beg, $end) = ($1, $max); - } elsif ($range =~ /\A(\d+)-(\d+)\z/) { + } elsif ($range =~ /\A([0-9]+)-([0-9]+)\z/) { ($beg, $end) = ($1, $2); } else { return r501; @@ -959,7 +959,7 @@ my $buf = $self->read(LINE_MAX) or return $self->close; $self->{rbuf} .= $$buf; } my $r = 1; - while ($r > 0 && $self->{rbuf} =~ s/\A\s*([^\r\n]*)\r?\n//) { + while ($r > 0 && $self->{rbuf} =~ s/\A[ \t\r\n]*([^\r\n]*)\r?\n//) { my $line = $1; return $self->close if $line =~ /[[:cntrl:]]/s; my $t0 = now(); diff --git a/lib/PublicInbox/NewsWWW.pm b/lib/PublicInbox/NewsWWW.pm index 8626cf96eaba44acee92a10a2aa3d84fcb7ab788..80bb488622f41095fc619bdcc5ee0b5682513ffe 100644 --- a/lib/PublicInbox/NewsWWW.pm +++ b/lib/PublicInbox/NewsWWW.pm @@ -47,7 +47,7 @@ my $pi_config = $self->{pi_config}; if (my $ibx = $pi_config->lookup_newsgroup($ng)) { my $url = PublicInbox::Hval::prurl($env, $ibx->{url}); my $code = 301; - if (defined $article && $article =~ /\A\d+\z/) { + if (defined $article && $article =~ /\A[0-9]+\z/) { my $mid = eval { $ibx->mm->mid_for($article) }; if (defined $mid) { # article IDs are not stable across clones, diff --git a/lib/PublicInbox/Search.pm b/lib/PublicInbox/Search.pm index c054a87497c400f3a2b2053b94f828eff78400d0..9903f427013bebeee9bbd1f427965a8c6cd84ede 100644 --- a/lib/PublicInbox/Search.pm +++ b/lib/PublicInbox/Search.pm @@ -144,7 +144,7 @@ my ($xdb, $slow_phrase); my $qpf = \($self->{qp_flags} ||= $QP_FLAGS); if ($self->{version} >= 2) { foreach my $part (<$dir/*>) { - -d $part && $part =~ m!/\d+\z! or next; + -d $part && $part =~ m!/[0-9]+\z! or next; my $sub = Search::Xapian::Database->new($part); if ($xdb) { $xdb->add_database($sub); diff --git a/lib/PublicInbox/SearchView.pm b/lib/PublicInbox/SearchView.pm index 6592b3b28e27363c769c381d510d3e318535ce90..b089de9c91412cb1e4e42a431256b97c8ebafa63 100644 --- a/lib/PublicInbox/SearchView.pm +++ b/lib/PublicInbox/SearchView.pm @@ -308,12 +308,12 @@ sub new { my ($class, $qp) = @_; my $r = $qp->{r}; - my ($l) = (($qp->{l} || '') =~ /(\d+)/); + my ($l) = (($qp->{l} || '') =~ /([0-9]+)/); $l = $LIM if !$l || $l > $LIM; bless { q => $qp->{'q'}, x => $qp->{x} || '', - o => (($qp->{o} || '0') =~ /(\d+)/), + o => (($qp->{o} || '0') =~ /([0-9]+)/), l => $l, r => (defined $r && $r ne '0'), }, $class; diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm index 3841c56719932a7c5ea4988b38bed549c3c9200d..81f99025cb08d7a881f60d72c2467889c5c94d61 100644 --- a/lib/PublicInbox/SolverGit.pm +++ b/lib/PublicInbox/SolverGit.pm @@ -206,7 +206,7 @@ } } my $msgs = $srch->query($q, { relevance => 1 }); - my $re = qr/\Aindex ($pre[a-f0-9]*)\.\.($post[a-f0-9]*)(?: (\d+))?/; + my $re = qr/\Aindex ($pre[a-f0-9]*)\.\.($post[a-f0-9]*)(?: ([0-9]+))?/; my $di; foreach my $smsg (@$msgs) { diff --git a/lib/PublicInbox/V2Writable.pm b/lib/PublicInbox/V2Writable.pm index 76844cd45a0f046b91a35263e9de046899f37f77..a8c33ef4f8f1d09848e6e12f3a9b625a0d1baa85 100644 --- a/lib/PublicInbox/V2Writable.pm +++ b/lib/PublicInbox/V2Writable.pm @@ -48,7 +48,7 @@ # Also, partition count may change while -watch is running # due to -compact if (-d $xpfx) { foreach my $part (<$xpfx/*>) { - -d $part && $part =~ m!/\d+\z! or next; + -d $part && $part =~ m!/[0-9]+\z! or next; eval { Search::Xapian::Database->new($part)->close; $nparts++; @@ -574,7 +574,7 @@ return unless -d $pfx; my $latest; opendir my $dh, $pfx or die "opendir $pfx: $!\n"; while (defined(my $git_dir = readdir($dh))) { - $git_dir =~ m!\A(\d+)\.git\z! or next; + $git_dir =~ m!\A([0-9]+)\.git\z! or next; if ($1 > $$max) { $$max = $1; $latest = "$pfx/$git_dir"; diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm index 09afdaf1bd15aa728766eb3104ff32d43057567c..1b52bf86c550e889f996f0b380640f76dd1124ac 100644 --- a/lib/PublicInbox/View.pm +++ b/lib/PublicInbox/View.pm @@ -528,7 +528,7 @@ my $desc = $part->header('Content-Description'); $desc = $fn unless defined $desc; $desc = '' unless defined $desc; my $sfn; - if (defined $fn && $fn =~ /\A[[:alnum:]][\w\.-]+[[:alnum:]]\z/) { + if (defined $fn && $fn =~ /\A$PublicInbox::Hval::FN\z/o) { $sfn = $fn; } elsif ($ct eq 'text/plain') { $sfn = 'a.txt'; @@ -1160,8 +1160,8 @@ # Xapian uses '..' but '-' is perhaps friendier to URL linkifiers # if only $after exists "YYYYMMDD.." because "." could be skipped # if interpreted as an end-of-sentence - $t =~ s/\A(\d{8,14})-// and $after = str2ts($1); - $t =~ /\A(\d{8,14})\z/ and $before = str2ts($1); + $t =~ s/\A([0-9]{8,14})-// and $after = str2ts($1); + $t =~ /\A([0-9]{8,14})\z/ and $before = str2ts($1); my $ibx = $ctx->{-inbox}; my $msgs = $ibx->recent($opts, $after, $before); diff --git a/lib/PublicInbox/ViewDiff.pm b/lib/PublicInbox/ViewDiff.pm index 411ed2bb7d4fb53d1b811a2bcf29c76c4265ae01..b7dab81946efe9372fa0a433740d1bd331b206a1 100644 --- a/lib/PublicInbox/ViewDiff.pm +++ b/lib/PublicInbox/ViewDiff.pm @@ -55,12 +55,12 @@ (defined($spfx) && defined($oid_a) && defined($oid_b)) or return "@@ $ca $cb @@"; - my ($n) = ($ca =~ /^-(\d+)/); + my ($n) = ($ca =~ /^-([0-9]+)/); $n = defined($n) ? do { ++$n; "#n$n" } : ''; my $rv = qq(@@ {Q}$n">$ca); - ($n) = ($cb =~ /^\+(\d+)/); + ($n) = ($cb =~ /^\+([0-9]+)/); $n = defined($n) ? do { ++$n; "#n$n" } : ''; $rv .= qq( {Q}$n">$cb @@); diff --git a/lib/PublicInbox/WWW.pm b/lib/PublicInbox/WWW.pm index b6f18f8d8140e130afdc637b4af277b10dc446c2..7ea982041b7daede1c9ddb567995136f12fa7a50 100644 --- a/lib/PublicInbox/WWW.pm +++ b/lib/PublicInbox/WWW.pm @@ -28,7 +28,7 @@ # TODO: consider a routing tree now that we have more endpoints: our $INBOX_RE = qr!\A/([\w\-][\w\.\-]*)!; our $MID_RE = qr!([^/]+)!; our $END_RE = qr!(T/|t/|t\.mbox(?:\.gz)?|t\.atom|raw|)!; -our $ATTACH_RE = qr!(\d[\.\d]*)-([[:alnum:]][\w\.-]+[[:alnum:]])!i; +our $ATTACH_RE = qr!([0-9][0-9\.]*)-($PublicInbox::Hval::FN)!; our $OID_RE = qr![a-f0-9]{7,40}!; sub new { @@ -74,7 +74,8 @@ $path_info //= $env->{PATH_INFO}; my $method = $env->{REQUEST_METHOD}; if ($method eq 'POST') { - if ($path_info =~ m!$INBOX_RE/(?:(\d+)/)?(git-upload-pack)\z!) { + if ($path_info =~ m!$INBOX_RE/(?:([0-9]+)/)? + (git-upload-pack)\z!x) { my ($part, $path) = ($2, $3); return invalid_inbox($ctx, $1) || serve_git($ctx, $part, $path); @@ -97,11 +98,11 @@ } elsif ($path_info =~ m!$INBOX_RE/(?:atom\.xml|new\.atom)\z!o) { invalid_inbox($ctx, $1) || get_atom($ctx); } elsif ($path_info =~ m!$INBOX_RE/new\.html\z!o) { invalid_inbox($ctx, $1) || get_new($ctx); - } elsif ($path_info =~ m!$INBOX_RE/(?:(\d+)/)? + } elsif ($path_info =~ m!$INBOX_RE/(?:([0-9]+)/)? ($PublicInbox::GitHTTPBackend::ANY)\z!ox) { my ($part, $path) = ($2, $3); invalid_inbox($ctx, $1) || serve_git($ctx, $part, $path); - } elsif ($path_info =~ m!$INBOX_RE/([\w-]+).mbox\.gz\z!o) { + } elsif ($path_info =~ m!$INBOX_RE/([a-zA-Z0-9_\-]+).mbox\.gz\z!o) { serve_mbox_range($ctx, $1, $2); } elsif ($path_info =~ m!$INBOX_RE/$MID_RE/$END_RE\z!o) { msg_page($ctx, $1, $2, $3); @@ -123,11 +124,12 @@ } elsif ($path_info =~ m!$INBOX_RE/$MID_RE/f/?\z!o) { r301($ctx, $1, $2); } elsif ($path_info =~ m!$INBOX_RE/_/text(?:/(.*))?\z!o) { get_text($ctx, $1, $2); - } elsif ($path_info =~ m!$INBOX_RE/([\w\-\.]+)\.css\z!o) { + } elsif ($path_info =~ m!$INBOX_RE/([a-zA-Z0-9_\-\.]+)\.css\z!o) { get_css($ctx, $1, $2); } elsif ($path_info =~ m!$INBOX_RE/($OID_RE)/s/\z!o) { get_vcs_object($ctx, $1, $2); - } elsif ($path_info =~ m!$INBOX_RE/($OID_RE)/s/([\w\.\-]+)\z!o) { + } elsif ($path_info =~ m!$INBOX_RE/($OID_RE)/s/ + ($PublicInbox::Hval::FN)\z!ox) { get_vcs_object($ctx, $1, $2, $3); } elsif ($path_info =~ m!$INBOX_RE/($OID_RE)/s\z!o) { r301($ctx, $1, $2, 's/'); @@ -534,11 +536,15 @@ if (defined $attr->{href}) { $inline_ok = 0; } else { my $fn = $_; + my ($key) = (m!([^/]+?)(?:\.css)?\z!i); + if ($key !~ /\A[a-zA-Z0-9_\-\.]+\z/) { + warn "ignoring $fn, non-ASCII word character\n"; + next; + } open(my $fh, '<', $fn) or do { warn "failed to open $fn: $!\n"; next; }; - my ($key) = (m!([^/]+?)(?:\.css)?\z!i); my $ctime = 0; my $local = do { local $/; <$fh> }; if ($local =~ /\S/) { diff --git a/lib/PublicInbox/WwwAttach.pm b/lib/PublicInbox/WwwAttach.pm index d690ce411921b5fa40820b98923b53d23c1f001a..96103cb028e09b014e4bf29fb7e711c4e567ec08 100644 --- a/lib/PublicInbox/WwwAttach.pm +++ b/lib/PublicInbox/WwwAttach.pm @@ -27,7 +27,7 @@ # discrete == type, we remain Debian wheezy-compatible if ($ct && (($ct->{discrete} || '') eq 'text')) { # display all text as text/plain: my $cset = $ct->{attributes}->{charset}; - if ($cset && ($cset =~ /\A[\w-]+\z/)) { + if ($cset && ($cset =~ /\A[a-zA-Z0-9_\-]+\z/)) { $res->[1]->[1] .= qq(; charset=$cset); } } else { # TODO: allow user to configure safe types diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm index e8dad4b892f50aceac866ef0956338edbb569ab0..e1473b3deec7135b4aa9557a65371ce9dd469d7a 100644 --- a/lib/PublicInbox/WwwListing.pm +++ b/lib/PublicInbox/WwwListing.pm @@ -24,8 +24,8 @@ sub list_match_domain ($$) { my ($self, $env) = @_; my @list; my $host = $env->{HTTP_HOST} // $env->{SERVER_NAME}; - $host =~ s/:\d+\z//; - my $re = qr!\A(?:https?:)?//\Q$host\E(?::\d+)?/!i; + $host =~ s/:[0-9]+\z//; + my $re = qr!\A(?:https?:)?//\Q$host\E(?::[0-9]+)?/!i; $self->{pi_config}->each_inbox(sub { my ($ibx) = @_; push @list, $ibx if !$ibx->{-hide}->{www} && $ibx->{url} =~ $re; diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm index 906723104d553d2cb25465c4dfd488e213914a0f..dad080c83bd724ff4998cfd459465a58b2b0b2f3 100644 --- a/lib/PublicInbox/Xapcmd.pm +++ b/lib/PublicInbox/Xapcmd.pm @@ -150,7 +150,7 @@ push @q, [ $old, $tmp->{$old} ]; } else { opendir my $dh, $old or die "Failed to opendir $old: $!\n"; while (defined(my $dn = readdir($dh))) { - if ($dn =~ /\A\d+\z/) { + if ($dn =~ /\A[0-9]+\z/) { my $tmpl = "$dn-XXXXXXXX"; my $dst = tempdir($tmpl, DIR => $old); same_fs_or_die($old, $dst); @@ -200,7 +200,7 @@ sub progress_pfx ($) { my @p = split('/', $_[0]); # return "xap15/0" for v2, or "xapian15" for v1: - ($p[-1] =~ /\A\d+\z/) ? "$p[-2]/$p[-1]" : $p[-1]; + ($p[-1] =~ /\A[0-9]+\z/) ? "$p[-2]/$p[-1]" : $p[-1]; } # xapian-compact wrapper @@ -276,7 +276,7 @@ my $lc = $src->get_metadata('last_commit'); $dst->set_metadata('last_commit', $lc) if $lc; # only the first xapian partition (0) gets 'indexlevel' - if ($old =~ m!(?:xapian\d+|xap\d+/0)\z!) { + if ($old =~ m!(?:xapian[0-9]+|xap[0-9]+/0)\z!) { my $l = $src->get_metadata('indexlevel'); if ($l eq 'medium') { $dst->set_metadata('indexlevel', $l); diff --git a/script/public-inbox-purge b/script/public-inbox-purge index 381826dc440c8ca43546aa823dd0b4aab93e39c2..25e6cc9b782451a5774acde97d7454d70f8d5a3e 100755 --- a/script/public-inbox-purge +++ b/script/public-inbox-purge @@ -91,7 +91,7 @@ # $ibx->{search} is populated by $ibx->over call my $xdir_ro = $ibx->{search}->xdir(1); my $npart = 0; foreach my $part (<$xdir_ro/*>) { - if (-d $part && $part =~ m!/\d+\z!) { + if (-d $part && $part =~ m!/[0-9]+\z!) { my $bytes = 0; $bytes += -s $_ foreach glob("$part/*"); $npart++ if $bytes; diff --git a/t/linkify.t b/t/linkify.t index fe218b91f95c4a89e0d3eaea0e6a2d6052b39c53..c492358257525fab99487f8e53bde3e55e209896 100644 --- a/t/linkify.t +++ b/t/linkify.t @@ -132,4 +132,16 @@ like($s, qr!\(see ]+>http://example\.com/\)\.!s, 'punctuation with unpaired ) OK') } +if ('IDN example: ') { + my $hc = '月'; + my $u = "http://www.\x{6708}.example.com/"; + my $s = $u; + my $l = PublicInbox::Linkify->new; + $s = $l->linkify_1($s); + $s = $l->linkify_2($s); + my $expect = qq{http://www.$hc.example.com/}; + is($s, $expect, 'IDN message escaped properly'); +} + done_testing();