]> Sergey Matveev's repositories - public-inbox.git/commitdiff
reject messages if ORIGINAL_RECIPIENT is not specified
authorEric Wong <e@80x24.org>
Fri, 10 Jan 2014 23:50:16 +0000 (23:50 +0000)
committerEric Wong <e@80x24.org>
Fri, 10 Jan 2014 23:50:16 +0000 (23:50 +0000)
SpamAssassin doesn't seem to have this heuristic, but the lack of
the intended email address in To:/Cc: headers cannot be a good
sign (especially when this is a _public_ inbox).

Makefile.PL
lib/PublicInbox.pm [new file with mode: 0644]
public-inbox-mda
t/recipient.t [new file with mode: 0644]

index b2fbb18fda4e52d8de62e75213344be94dca810d..5d3ee75c0133d40a04f76e250e512f8d93af600a 100644 (file)
@@ -15,6 +15,7 @@ WriteMakefile(
                'Email::MIME' => 0,
                'Email::MIME::ContentType' => 0,
                'Email::Filter' => 0,
+               'Email::Address' => 0,
        },
 );
 
diff --git a/lib/PublicInbox.pm b/lib/PublicInbox.pm
new file mode 100644 (file)
index 0000000..b51c000
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
+package PublicInbox;
+use strict;
+use warnings;
+use Email::Address;
+
+# drop plus addressing for matching
+sub __drop_plus {
+       my ($str_addr) = @_;
+       $str_addr =~ s/\+.*\@/\@/;
+       $str_addr;
+}
+
+# do not allow Bcc, only Cc and To if ORIGINAL_RECIPIENT (postfix) env is set
+sub recipient_specified {
+       my ($klass, $filter) = @_;
+       my $or = $ENV{ORIGINAL_RECIPIENT};
+       defined($or) or return 1; # for imports
+       my @or = Email::Address->parse($or);
+       my $oaddr = __drop_plus($or[0]->address);
+       $oaddr = qr/\b\Q$oaddr\E\b/i;
+       my @to = Email::Address->parse($filter->to);
+       my @cc = Email::Address->parse($filter->cc);
+       foreach my $addr (@to, @cc) {
+               if (__drop_plus($addr->address) =~ $oaddr) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+1;
index 177c891e593b4640946ee8d054f15cac67f4469b..72f1eac4b41f04b6f51eb2bd01bb1b4fc347c323 100755 (executable)
@@ -4,6 +4,7 @@
 use strict;
 use warnings;
 use Email::Filter;
+use Email::Address;
 use PublicInbox::Filter;
 use IPC::Run qw(run);
 my $usage = "public-inbox-mda main_repo fail_repo < rfc2822_message";
@@ -14,6 +15,7 @@ my $max = 1024 * 500; # same as spamc
 
 my $filtered;
 if (length($filter->simple->as_string) <= $max
+    && PublicInbox->recipient_specified($filter)
     && do_spamc($filter->simple, \$filtered)) {
        # update our message with SA headers (in case our filter rejects it)
        my $simple = Email::Simple->new($filtered);
diff --git a/t/recipient.t b/t/recipient.t
new file mode 100644 (file)
index 0000000..9cb1969
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) 2014, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
+use strict;
+use warnings;
+use Test::More;
+use Email::Simple;
+use Email::Filter;
+use PublicInbox;
+
+sub do_checks {
+       my ($s) = @_;
+
+       my $f = Email::Filter->new(data => $s->as_string);
+       local %ENV;
+       delete $ENV{ORIGINAL_RECIPIENT};
+
+       ok(PublicInbox->recipient_specified($f),
+               "ORIGINAL_RECIPIENT unset is OK");
+
+       $ENV{ORIGINAL_RECIPIENT} = 'foo@example.com';
+       ok(!PublicInbox->recipient_specified($f),
+               "wrong ORIGINAL_RECIPIENT rejected");
+
+       $ENV{ORIGINAL_RECIPIENT} = 'b@example.com';
+       ok(PublicInbox->recipient_specified($f),
+               "ORIGINAL_RECIPIENT in To: is OK");
+
+       $ENV{ORIGINAL_RECIPIENT} = 'c@example.com';
+       ok(PublicInbox->recipient_specified($f),
+               "ORIGINAL_RECIPIENT in Cc: is OK");
+}
+
+{
+       do_checks(Email::Simple->create(
+               header => [
+                       From => 'a@example.com',
+                       To => 'b@example.com',
+                       Cc => 'c@example.com',
+                       'Content-Type' => 'text/plain',
+                       Subject => 'this is a subject',
+               ],
+               body => "hello world\n",
+       ));
+}
+
+{
+       do_checks(Email::Simple->create(
+               header => [
+                       From => 'a@example.com',
+                       To => 'b+plus@example.com',
+                       Cc => 'John Doe <c@example.com>',
+                       'Content-Type' => 'text/plain',
+                       Subject => 'this is a subject',
+               ],
+               body => "hello world\n",
+       ));
+}
+
+done_testing();