X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=lib%2FApp%2FEdwardNG.pm;h=e6cea876b36c13094f4a61f95749673a3cecd984;hb=HEAD;hp=6f6b3a0adc0abc8cd3b4fcebb93050bc963a0817;hpb=b65d84868bf813c43b91ee58bdf26671e28fa819;p=app-edwardng.git diff --git a/lib/App/EdwardNG.pm b/lib/App/EdwardNG.pm index 6f6b3a0..e6cea87 100644 --- a/lib/App/EdwardNG.pm +++ b/lib/App/EdwardNG.pm @@ -5,11 +5,13 @@ use strict; use warnings; use parent qw/Exporter/; our $VERSION = '0.001'; -our @EXPORT = qw/process_message/; +our @EXPORT_OK = qw/import_pubkeys process_message/; use Email::Sender::Simple qw/sendmail/; +use File::Share qw/dist_file/; use File::Slurp qw/read_file/; use File::Spec::Functions qw/rel2abs/; +use IO::Handle; use Getopt::Long; use MIME::Entity; use MIME::Parser; @@ -30,18 +32,41 @@ sub mg { @_); } +sub mp { + my $parser = MIME::Parser->new; + $parser->decode_bodies($_[0] // 0); + $parser->output_to_core(1); + $parser +} + sub first_part{ my ($ent) = @_; - return first_part $ent->parts(0) if $ent->parts; - $ent->bodyhandle->as_string + return first_part ($ent->parts(0)) if $ent->parts; + stringify [$ent->bodyhandle->as_lines] +} + +sub import_pubkeys { + my ($ent, $mg) = @_; + my @keys; + if ($ent->mime_type eq 'application/pgp-keys') { + $ent = mp(1)->parse_data($ent->stringify); + my $gpg = GnuPG::Interface->new; + $mg->_set_options($gpg); + $gpg->options->quiet(1); + my ($input, $status) = (IO::Handle->new, IO::Handle->new); + my $pid = $gpg->import_keys(handles => GnuPG::Handles->new(stdin => $input, status => $status)); + my $read = Mail::GnuPG::_communicate([$status], [$input], {$input => $ent->bodyhandle->as_string}); + push @keys, map { /IMPORT_OK \d+ (\w+)/ } $read->{$status}; + waitpid $pid, 0 + } + push @keys, import_pubkeys ($_, $mg) for $ent->parts; + @keys } sub process_message { my ($in) = @_; my $msg; - my $parser = MIME::Parser->new; - $parser->decode_bodies(0); - $parser->output_to_core(1); + my $parser = mp; $msg = $in if ref $in eq 'MIME::Entity'; $msg = $parser->parse ($in) if ref $in eq 'IO'; @@ -85,7 +110,7 @@ sub process_message { } debug 'This mail doesn\'t seem to be signed or encrypted'; - return 'plain' + return 'plain', message => '' } sub run { @@ -95,16 +120,18 @@ sub run { 'from=s' => \$ENV{EDWARDNG_FROM}, 'key=s' => \$ENV{EDWARDNG_KEY}, 'keydir=s' => \$ENV{EDWARDNG_KEYDIR}, + 'logfile=s' => \$ENV{EDWARDNG_LOGFILE}, 'passphrase=s' => \$ENV{EDWARDNG_PASSPHRASE}, 'tmpl-path=s' => \$ENV{EDWARDNG_TMPL_PATH}, 'use-agent!' => \$ENV{EDWARDNG_USE_AGENT}, ); my $tmpl_path = $ENV{EDWARDNG_TMPL_PATH} // 'en'; + open STDERR, '>>', $ENV{EDWARDNG_LOGFILE} if $ENV{EDWARDNG_LOGFILE}; - my $parser = MIME::Parser->new; - $parser->decode_bodies(0); - $parser->output_to_core(1); - my $in = $parser->parse(\*STDIN); + 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 { @@ -112,22 +139,26 @@ sub run { } 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, 'tmpl'); - my $data; - $tt->process($tmpl, \%params, \$data); + my $tt = Template->new(INCLUDE_PATH => rel2abs $tmpl_path, dist_file 'App-EdwardNG', 'tmpl'); + my ($keys, $result) = ('', ''); + $tt->process('keys', {keys => \@keys}, \$keys) if @keys; + $tt->process($tmpl, \%params, \$result); my $email = MIME::Entity->build( From => $ENV{EDWARDNG_FROM}, To => $in->get('From'), + Type => 'text/plain; charset=UTF-8', + Encoding=> '-SUGGEST', Subject => 'Re: ' . $in->get('Subject'), - Data => $data); + 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 ', stringify $mg->{last_message} if $encrypt_failed; + debug 'Could not encrypt message, sending unencrypted. GnuPG said:', "\n", stringify $mg->{last_message} if $encrypt_failed; sendmail $encrypt_failed ? $email_unencrypted : $email } @@ -166,7 +197,19 @@ App::EdwardNG - GnuPG email sign/encrypt testing bot EdwardNG is a reimplementation of the Edward reply bot referenced in L. -This module exports a single function, B, which takes a single parameter representing the message. This parameter can be: +=head1 EXPORTS + +None by default. + +=head2 B(I<$entity>, I<$gpg>) + +Scan a message for PGP public keys, and import them. I<$entity> is a L to scan, I<$gpg> is a L instance. + +Returns a list of fingerprints of keys found. + +=head2 B(I<$message>) + +Analyze a message, looking for PGP signatures and encryption. I<$message> can be: =over @@ -176,7 +219,7 @@ This module exports a single function, B, which takes a single =item A scalar which represents a path to a message. -=item A L object +=item A L object created with decode_bodies(0) =back