about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2017-06-16 02:03:32 +0000
committerEric Wong <e@80x24.org>2017-06-16 02:03:32 +0000
commitef9ce6f2dfc9fcbb91e3cec0b7a2b7f7e359be5d (patch)
tree4db5b56762cf95c2164fb3815ee4d12fca7c6803 /lib/PublicInbox
parent61196e5b0645eb58b415b4c679fc36ecf602ad16 (diff)
downloadpublic-inbox-ef9ce6f2dfc9fcbb91e3cec0b7a2b7f7e359be5d.tar.gz
This is lightly-tested and seems to work.  I'm still
hesitant to support this, but the alternative of receiving death
threats for displaying unobfuscated addresses seems to
be not worth it.
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/Config.pm11
-rw-r--r--lib/PublicInbox/Hval.pm9
-rw-r--r--lib/PublicInbox/SearchView.pm10
-rw-r--r--lib/PublicInbox/View.pm87
4 files changed, 86 insertions, 31 deletions
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index 323f8a1a..0597a527 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -140,6 +140,17 @@ sub _fill {
                 my $v = $self->{"$pfx.$k"};
                 $rv->{$k} = $v if defined $v;
         }
+        foreach my $k (qw(obfuscate)) {
+                my $v = $self->{"$pfx.$k"};
+                defined $v or next;
+                if ($v =~ /\A(?:false|no|off|0)\z/) {
+                        $rv->{$k} = 0;
+                } elsif ($v =~ /\A(?:true|yes|on|1)\z/) {
+                        $rv->{$k} = 1;
+                } else {
+                        warn "Ignoring $pfx.$k=$v in config, not boolean\n";
+                }
+        }
 
         # TODO: more arrays, we should support multi-value for
         # more things to encourage decentralization
diff --git a/lib/PublicInbox/Hval.pm b/lib/PublicInbox/Hval.pm
index 77acecda..2379b918 100644
--- a/lib/PublicInbox/Hval.pm
+++ b/lib/PublicInbox/Hval.pm
@@ -9,7 +9,7 @@ use warnings;
 use Encode qw(find_encoding);
 use PublicInbox::MID qw/mid_clean mid_escape/;
 use base qw/Exporter/;
-our @EXPORT_OK = qw/ascii_html/;
+our @EXPORT_OK = qw/ascii_html obfuscate_addrs/;
 
 # for user-generated content (UGC) which may have excessively long lines
 # and screw up rendering on some browsers.  This is the only CSS style
@@ -86,4 +86,11 @@ sub prurl {
         index($u, '//') == 0 ? "$env->{'psgi.url_scheme'}:$u" : $u;
 }
 
+# for misguided people who believe in this stuff, give them a
+# substitution for '.'
+# &#8228; &#183; and &#890; were also candidates:
+#   https://public-inbox.org/meta/20170615015250.GA6484@starla/
+# However, &#8226; was chosen to make copy+paste errors more obvious
+sub obfuscate_addrs ($) { $_[0] =~ s/(\S+@[^\.]+)\./$1&#8226;/g }
+
 1;
diff --git a/lib/PublicInbox/SearchView.pm b/lib/PublicInbox/SearchView.pm
index f92790f4..777710e3 100644
--- a/lib/PublicInbox/SearchView.pm
+++ b/lib/PublicInbox/SearchView.pm
@@ -7,7 +7,7 @@ use strict;
 use warnings;
 use URI::Escape qw(uri_unescape uri_escape);
 use PublicInbox::SearchMsg;
-use PublicInbox::Hval qw/ascii_html/;
+use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
 use PublicInbox::View;
 use PublicInbox::WwwAtomStream;
 use PublicInbox::MID qw(mid2path mid_mime mid_clean mid_escape MID_ESC);
@@ -89,6 +89,7 @@ sub mset_summary {
         my $pfx = ' ' x $pad;
         my $res = \($ctx->{-html_tip});
         my $srch = $ctx->{srch};
+        my $obfs = $ctx->{-inbox}->{obfuscate};
         foreach my $m ($mset->items) {
                 my $rank = sprintf("%${pad}d", $m->get_rank + 1);
                 my $pct = $m->get_percent;
@@ -102,6 +103,10 @@ sub mset_summary {
                 }
                 my $s = ascii_html($smsg->subject);
                 my $f = ascii_html($smsg->from_name);
+                if ($obfs) {
+                        obfuscate_addrs($s);
+                        obfuscate_addrs($f);
+                }
                 my $ts = PublicInbox::View::fmt_ts($smsg->ts);
                 my $mid = PublicInbox::Hval->new_msgid($smsg->mid)->{href};
                 $$res .= qq{$rank. <b><a\nhref="$mid/">}.
@@ -223,8 +228,11 @@ sub mset_thread {
         $ctx->{seen} = {};
         $ctx->{s_nr} = scalar(@$msgs).'+ results';
 
+        # reduce hash lookups in skel_dump
+        $ctx->{-obfuscate} = $ctx->{-inbox}->{obfuscate};
         PublicInbox::View::walk_thread($rootset, $ctx,
                 *PublicInbox::View::pre_thread);
+
         @$msgs = reverse @$msgs if $r;
         my $mime;
         sub {
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 2d816408..687a0acb 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -7,7 +7,7 @@ package PublicInbox::View;
 use strict;
 use warnings;
 use Date::Parse qw/str2time/;
-use PublicInbox::Hval qw/ascii_html/;
+use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
 use PublicInbox::Linkify;
 use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape/;
 use PublicInbox::MsgIter;
@@ -24,11 +24,13 @@ sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD };
 sub msg_html {
         my ($ctx, $mime) = @_;
         my $hdr = $mime->header_obj;
-        my $tip = _msg_html_prepare($hdr, $ctx);
+        my $obfs = $ctx->{-inbox}->{obfuscate};
+        my $tip = _msg_html_prepare($hdr, $ctx, $obfs);
         PublicInbox::WwwStream->response($ctx, 200, sub {
                 my ($nr, undef) = @_;
                 if ($nr == 1) {
-                        $tip . multipart_text_as_html($mime, '') . '</pre><hr>'
+                        $tip . multipart_text_as_html($mime, '', $obfs) .
+                                '</pre><hr>'
                 } elsif ($nr == 2) {
                         # fake an EOF if generating the footer fails;
                         # we want to at least show the message if something
@@ -104,7 +106,7 @@ sub in_reply_to {
         undef;
 }
 
-sub _hdr_names ($$) {
+sub _hdr_names_html ($$) {
         my ($hdr, $field) = @_;
         my $val = $hdr->header($field) or return '';
         ascii_html(join(', ', PublicInbox::Address::names($val)));
@@ -129,18 +131,25 @@ sub index_entry {
 
         my $root_anchor = $ctx->{root_anchor} || '';
         my $irt;
+        my $obfs = $ctx->{-obfuscate};
 
         my $rv = "<a\nhref=#e$id\nid=m$id>*</a> ";
         $subj = '<b>'.ascii_html($subj).'</b>';
+        obfuscate_addrs($subj) if $obfs;
         $subj = "<u\nid=u>$subj</u>" if $root_anchor eq $id_m;
         $rv .= $subj . "\n";
         $rv .= _th_index_lite($mid_raw, \$irt, $id, $ctx);
         my @tocc;
         foreach my $f (qw(To Cc)) {
-                my $dst = _hdr_names($hdr, $f);
-                push @tocc, "$f: $dst" if $dst ne '';
+                my $dst = _hdr_names_html($hdr, $f);
+                if ($dst ne '') {
+                        obfuscate_addrs($dst) if $obfs;
+                        push @tocc, "$f: $dst";
+                }
         }
-        $rv .= "From: "._hdr_names($hdr, 'From').' @ '._msg_date($hdr)." UTC";
+        my $from = _hdr_names_html($hdr, 'From');
+        obfuscate_addrs($from) if $obfs;
+        $rv .= "From: $from @ "._msg_date($hdr)." UTC";
         my $upfx = $ctx->{-upfx};
         my $mhref = $upfx . mid_escape($mid_raw) . '/';
         $rv .= qq{ (<a\nhref="$mhref">permalink</a> / };
@@ -157,7 +166,7 @@ sub index_entry {
         $rv .= "\n";
 
         # scan through all parts, looking for displayable text
-        msg_iter($mime, sub { $rv .= add_text_body($mhref, $_[0]) });
+        msg_iter($mime, sub { $rv .= add_text_body($mhref, $obfs, $_[0]) });
 
         # add the footer
         $rv .= "\n<a\nhref=#$id_m\nid=e$id>^</a> ".
@@ -303,6 +312,7 @@ sub stream_thread ($$) {
         }
         return missing_thread($ctx) unless $mime;
 
+        $ctx->{-obfuscate} = $ctx->{-inbox}->{obfuscate};
         $mime = PublicInbox::MIME->new($mime);
         $ctx->{-title_html} = ascii_html($mime->header('Subject'));
         $ctx->{-html_tip} = thread_index_entry($ctx, $level, $mime);
@@ -355,7 +365,11 @@ sub thread_html {
         $ctx->{s_nr} = "$nr+ messages in thread";
 
         my $rootset = thread_results($msgs);
+
+        # reduce hash lookups in pre_thread->skel_dump
+        $ctx->{-obfuscate} = $ctx->{-inbox}->{obfuscate};
         walk_thread($rootset, $ctx, *pre_thread);
+
         $skel .= '</pre>';
         return stream_thread($rootset, $ctx) unless $ctx->{flat};
 
@@ -385,14 +399,11 @@ sub thread_html {
 }
 
 sub multipart_text_as_html {
-        my ($mime, $upfx) = @_;
+        my ($mime, $upfx, $obfs) = @_;
         my $rv = "";
 
         # scan through all parts, looking for displayable text
-        msg_iter($mime, sub {
-                my ($p) = @_;
-                $rv .= add_text_body($upfx, $p);
-        });
+        msg_iter($mime, sub { $rv .= add_text_body($upfx, $obfs, $_[0]) });
         $rv;
 }
 
@@ -445,7 +456,8 @@ sub attach_link ($$$$;$) {
 }
 
 sub add_text_body {
-        my ($upfx, $p) = @_; # from msg_iter: [ Email::MIME, depth, @idx ]
+        my ($upfx, $obfs, $p) = @_;
+        # $p - from msg_iter: [ Email::MIME, depth, @idx ]
         my ($part, $depth) = @$p; # attachment @idx is unused
         my $ct = $part->content_type || 'text/plain';
         my $fn = $part->filename;
@@ -496,15 +508,20 @@ sub add_text_body {
 
         if (@quot) { # ugh, top posted
                 flush_quote(\$s, $l, \@quot);
-        } elsif ($s =~ /\n\z/s) { # common, last line ends with a newline
+                obfuscate_addrs($s) if $obfs;
                 $s;
-        } else { # some editors don't do newlines...
-                $s .= "\n";
+        } else {
+                obfuscate_addrs($s) if $obfs;
+                if ($s =~ /\n\z/s) { # common, last line ends with a newline
+                        $s;
+                } else { # some editors don't do newlines...
+                        $s .= "\n";
+                }
         }
 }
 
 sub _msg_html_prepare {
-        my ($hdr, $ctx) = @_;
+        my ($hdr, $ctx, $obfs) = @_;
         my $srch = $ctx->{srch} if $ctx;
         my $atom = '';
         my $rv = "<pre\nid=b>"; # anchor for body start
@@ -523,6 +540,7 @@ sub _msg_html_prepare {
                 if ($h eq 'From') {
                         my @n = PublicInbox::Address::names($v->raw);
                         $title[1] = ascii_html(join(', ', @n));
+                        obfuscate_addrs($title[1]) if $obfs;
                 } elsif ($h eq 'Subject') {
                         $title[0] = $v->as_html;
                         if ($srch) {
@@ -532,7 +550,7 @@ sub _msg_html_prepare {
                         }
                 }
                 $v = $v->as_html;
-                $v =~ s/(\@[^,]+,) /$1\n\t/g if ($h eq 'Cc' || $h eq 'To');
+                obfuscate_addrs($v) if $obfs;
                 $rv .= "$h: $v\n";
 
         }
@@ -578,7 +596,11 @@ sub thread_skel {
         $ctx->{prev_level} = 0;
         $ctx->{dst} = $dst;
         $sres = load_results($srch, $sres);
+
+        # reduce hash lookups in skel_dump
+        $ctx->{-obfuscate} = $ctx->{-inbox}->{obfuscate};
         walk_thread(thread_results($sres), $ctx, *skel_dump);
+
         $ctx->{parent_msg} = $parent;
 }
 
@@ -732,7 +754,11 @@ sub skel_dump {
         my $dst = $ctx->{dst};
         my $cur = $ctx->{cur};
         my $mid = $smsg->{mid};
+
         my $f = ascii_html($smsg->from_name);
+        my $obfs = $ctx->{-obfuscate};
+        obfuscate_addrs($f) if $obfs;
+
         my $d = fmt_ts($smsg->{ts}) . ' ' . indent_for($level) . th_pfx($level);
         my $attr = $f;
         $ctx->{first_level} ||= $level;
@@ -758,19 +784,20 @@ sub skel_dump {
         # Subject is never undef, this mail was loaded from
         # our Xapian which would've resulted in '' if it were
         # really missing (and Filter rejects empty subjects)
-        my $s = $smsg->subject;
-        my $h = $ctx->{srch}->subject_path($s);
+        my $subj = $smsg->subject;
+        my $h = $ctx->{srch}->subject_path($subj);
         if ($ctx->{seen}->{$h}) {
-                $s = undef;
+                $subj = undef;
         } else {
                 $ctx->{seen}->{$h} = 1;
-                $s = PublicInbox::Hval->new($s);
-                $s = $s->as_html;
+                $subj = PublicInbox::Hval->new($subj);
+                $subj = $subj->as_html;
+                obfuscate_addrs($subj) if $obfs;
         }
         my $m;
         my $id = '';
         my $mapping = $ctx->{mapping};
-        my $end = defined($s) ? "$s</a> $f\n" : "$f</a>\n";
+        my $end = defined($subj) ? "$subj</a> $f\n" : "$f</a>\n";
         if ($mapping) {
                 my $map = $mapping->{$mid};
                 $id = id_compress($mid, 1);
@@ -862,6 +889,7 @@ sub dump_topics {
         }
 
         my @out;
+        my $obfs = $ctx->{-inbox}->{obfuscate};
 
         # sort by recency, this allows new posts to "bump" old topics...
         foreach my $topic (sort { $b->[0] <=> $a->[0] } @$order) {
@@ -890,12 +918,13 @@ sub dump_topics {
                         " $ts UTC $n - $mbox / $atom\n";
                 for (my $i = 0; $i < scalar(@ex); $i += 2) {
                         my $level = $ex[$i];
-                        my $sub = $ex[$i + 1];
-                        $mid = delete $seen->{$sub};
-                        $sub = PublicInbox::Hval->new($sub)->as_html;
+                        my $subj = $ex[$i + 1];
+                        $mid = delete $seen->{$subj};
+                        $subj = ascii_html($subj);
+                        obfuscate_addrs($subj) if $obfs;
                         $href = mid_escape($mid);
                         $s .= indent_for($level) . TCHILD;
-                        $s .= "<a\nhref=\"$href/T/#u\">$sub</a>\n";
+                        $s .= "<a\nhref=\"$href/T/#u\">$subj</a>\n";
                 }
                 push @out, $s;
         }