From 2d1c4057b09845dbe8aef711052b0438e98bafcd Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 8 Apr 2014 01:36:53 +0000 Subject: [PATCH] ssoma-mda: duplicate prevention This is mainly for public-inbox, as duplicate message IDs are usually evidence something is suspicious or a misconfigured SMTP server/client. --- Documentation/ssoma-mda.txt | 8 +++++++- lib/Ssoma/MDA.pm | 10 +++++++--- ssoma-mda | 9 +++++---- t/all.t | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Documentation/ssoma-mda.txt b/Documentation/ssoma-mda.txt index 0ef1501..07cfd12 100644 --- a/Documentation/ssoma-mda.txt +++ b/Documentation/ssoma-mda.txt @@ -6,7 +6,7 @@ ssoma-mda - mail delivery agent for ssoma # SYNOPSIS -ssoma-mda /path/to/ssoma/repository.git < message +ssoma-mda [-1] /path/to/ssoma/repository.git < message # DESCRIPTION @@ -20,6 +20,12 @@ ssoma-mda takes no command-line options and does not alter its own permissions. This must be done by the MTA or MDA which invokes ssoma-mda. +# OPTIONS + +-1 +: Only allow a Message-ID to appear once in the database. + Future messages with an identical Message-ID will not be allowed. + # FILES See ssoma_repository(5) for details. diff --git a/lib/Ssoma/MDA.pm b/lib/Ssoma/MDA.pm index 25d0fd6..3fe7e0b 100644 --- a/lib/Ssoma/MDA.pm +++ b/lib/Ssoma/MDA.pm @@ -68,7 +68,7 @@ sub tree_update { # this appends the given message-id to the git repo, requires locking # (Ssoma::Git::sync_do) sub append { - my ($self, $path, $simple) = @_; + my ($self, $path, $simple, $once) = @_; my $git = $self->{git}; my $ref = $self->{ref}; @@ -82,6 +82,10 @@ sub append { if ($? == 0) { # rare, object already exists chomp $type; + if ($once) { + my $mid = $simple->header("Message-ID"); + die "CONFLICT: Message-ID: $mid exists ($path)\n"; + } # we return undef here if the message already exists if ($type eq "blob") { @@ -103,7 +107,7 @@ sub append { # the main entry point takes an Email::Simple object sub deliver { - my ($self, $simple) = @_; + my ($self, $simple, $once) = @_; my $git = $self->{git}; # convert the Message-ID into a path @@ -124,7 +128,7 @@ sub deliver { my $sub = sub { $git->tmp_index_do(sub { - $self->append($path, $simple); + $self->append($path, $simple, $once); }); }; $git->sync_do(sub { $git->tmp_git_do($sub) }); diff --git a/ssoma-mda b/ssoma-mda index af5f63f..d763224 100755 --- a/ssoma-mda +++ b/ssoma-mda @@ -4,18 +4,19 @@ # This is the command-line mail delivery agent for servers. # Try to keep this small as it may be invoked frequently for each message # delivered. -my $usage = "ssoma-mda /path/to/git/repo < /path/to/rfc2822_message"; +my $usage = "ssoma-mda [-1] /path/to/git/repo < /path/to/rfc2822_message"; use strict; use warnings; use Ssoma::MDA; use Ssoma::Git; use Email::Simple; -my $repo = shift @ARGV or die "Usage: $usage\n"; +my $once = $ARGV[0] eq "-1"; +my $repo = pop @ARGV or die "Usage: $usage\n"; my $git = Ssoma::Git->new($repo); my $mda = Ssoma::MDA->new($git); my $simple; { local $/; - $simple = Email::Simple->new(<>); + $simple = Email::Simple->new(); } -$mda->deliver($simple); +$mda->deliver($simple, $once); diff --git a/t/all.t b/t/all.t index 9c14d59..bd71713 100644 --- a/t/all.t +++ b/t/all.t @@ -11,6 +11,7 @@ my $rm = "blib/script/ssoma-rm"; my $tmp = tempdir(CLEANUP => 1); use File::Temp qw/tempdir/; use Email::Simple; +use IPC::Run qw(run); ok(-x $mda, "$mda is executable"); ok(-x $cli, "$cli is executable"); @@ -195,4 +196,21 @@ EOF is(scalar @tree, 2, "two messages sitting in a tree"); } +# duplicate detection +{ + my $simple = Email::Simple->new(<<'EOF'); +From: moi@example.com +To: you@example.com +Message-Id: <666666@example.com> +Subject: xxx + +OMFG +EOF + $simple = $simple->as_string; + my ($out, $err) = ("", ""); + run([$mda, "-1", "$tmp/input.git"], \$simple, \$out, \$err); + isnt($?, 0, "$mda exited with failure"); + like($err, qr/CONFLICT/, "conflict message detected"); +} + done_testing(); -- 2.26.2