App-Eduard
view release on metacpan or search on metacpan
lib/App/Eduard.pm view on Meta::CPAN
}
if ($gpg->is_encrypted($msg)) {
debug 'This mail looks encrypted';
my ($code, $keyid, $email) = $gpg->decrypt($msg);
return encrypt_error => (
message => stringify $gpg->{last_message}) if $code;
return encrypt => (
plaintext => stringify $gpg->{plaintext},
decrypted => $gpg->{decrypted},
message => stringify $gpg->{last_message}) unless defined $keyid;
return signencrypt => (
keyid => $keyid,
email => $email,
plaintext => stringify $gpg->{plaintext},
decrypted => $gpg->{decrypted},
message => stringify $gpg->{last_message});
}
debug 'This mail doesn\'t seem to be signed or encrypted';
return 'plain', message => ''
}
sub run {
GetOptions(
'always-trust!' => \$ENV{EDUARD_ALWAYS_TRUST},
'debug!' => \$ENV{EDUARD_DEBUG},
'from=s' => \$ENV{EDUARD_FROM},
'key=s' => \$ENV{EDUARD_KEY},
'keydir=s' => \$ENV{EDUARD_KEYDIR},
'logfile=s' => \$ENV{EDUARD_LOGFILE},
'passphrase=s' => \$ENV{EDUARD_PASSPHRASE},
'tmpl-path=s' => \$ENV{EDUARD_TMPL_PATH},
'use-agent!' => \$ENV{EDUARD_USE_AGENT},
);
my $tmpl_path = $ENV{EDUARD_TMPL_PATH} // 'en';
open STDERR, '>>', $ENV{EDUARD_LOGFILE} if $ENV{EDUARD_LOGFILE};
my $in = mp->parse(\*STDIN);
debug 'Received mail from ', $in->get('From');
my @keys = import_pubkeys $in, mg;
say 'Found keys: ', join ' ', @keys if @keys;
my ($tmpl, %params);
try {
($tmpl, %params) = process_message $in
} catch {
($tmpl, %params) = (error => message => $_)
};
debug "Result is $tmpl, GnuPG said:\n", $params{message};
$params{plaintext} = first_part $params{decrypted} if $params{decrypted};
my $tt = Template->new(INCLUDE_PATH => rel2abs $tmpl_path, dist_file 'App-Eduard', 'tmpl');
my ($keys, $result) = ('', '');
$tt->process('keys', {keys => \@keys}, \$keys) if @keys;
$tt->process($tmpl, \%params, \$result);
my $email = MIME::Entity->build(
From => $ENV{EDUARD_FROM},
To => $in->get('From'),
Type => 'text/plain; charset=UTF-8',
Encoding=> '-SUGGEST',
Subject => 'Re: ' . $in->get('Subject'),
Data => $keys.$result);
my $email_unencrypted = $email->dup;
my $mg = mg always_trust => 1;
my $encrypt_failed = $mg->mime_signencrypt($email, $in->get('From') =~ /<(.*)>/);
debug 'Could not encrypt message, sending unencrypted. GnuPG said:', "\n", stringify $mg->{last_message} if $encrypt_failed;
sendmail $encrypt_failed ? $email_unencrypted : $email
}
1;
__END__
=encoding utf-8
=head1 NAME
App::Eduard - GnuPG email sign/encrypt testing bot
=head1 SYNOPSIS
use App::Eduard;
my ($status, %params) = process_message '/path/to/message';
if ($status eq 'signencrypt') {
say 'This message is encrypted and signed with key ', $params{keyid}, ' from ', $params{email};
say 'Its contents are: ', $params{plaintext};
} elsif ($status eq 'encrypt') {
say 'This message is encrypted but not signed';
say 'Its contents are: ', $params{plaintext};
} elsif ($status eq 'encrypt_error') {
say 'This message is encrypted but I was unable to decrypt it. GnuPG output: ', $params{message};
} elsif ($status eq 'sign') {
say 'This message is signed with key ', $params{keyid}, ' from ', $params{email};
} elsif ($status eq 'sign_error') {
say 'This message is signed but I was unable to verify the signature. GnuPG output: ', $params{message};
} elsif ($status eq 'plain') {
say 'This message is neither signed nor encrypted';
} elsif ($status eq 'error') {
say 'There was an error processing the message: ', $params{message};
}
=head1 DESCRIPTION
Eduard is Ceata's reimplementation of the Edward reply bot referenced in L<https://emailselfdefense.fsf.org/>.
=head1 EXPORTS
None by default.
=head2 B<import_keys>(I<$entity>, I<$gpg>)
Scan a message for PGP public keys, and import them. I<$entity> is a L<MIME::Entity> to scan, I<$gpg> is a L<Mail::GnuPG> instance.
Returns a list of fingerprints of keys found.
=head2 B<process_message>(I<$message>)
Analyze a message, looking for PGP signatures and encryption. I<$message> can be:
( run in 1.940 second using v1.01-cache-2.11-cpan-99c4e6809bf )