X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;ds=inline;f=lib%2FApp%2FEdwardNG.pm;h=7d32be127d0b01d11a209b852d3eb2cd93af4658;hb=2601b44a11d012215c88c8683178a933da63c422;hp=6ccc05942f977b6e118406d2e70877fa1c1d4989;hpb=2f9e679a099ab2e59aed109e1d5e3555b5c23b57;p=app-edwardng.git
diff --git a/lib/App/EdwardNG.pm b/lib/App/EdwardNG.pm
index 6ccc059..7d32be1 100644
--- a/lib/App/EdwardNG.pm
+++ b/lib/App/EdwardNG.pm
@@ -5,10 +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;
@@ -29,32 +32,47 @@ 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 ($msg) = @_;
- my $parser = MIME::Parser->new;
- $parser->decode_bodies(0);
- $parser->output_to_core(1);
+ my ($in) = @_;
+ my $msg;
+ my $parser = mp;
- if (ref $msg eq 'MIME::Entity') {
- debug 'Got MIME::Entity';
- } elsif (ref $msg eq 'IO') {
- debug 'Parsing from filehandle';
- $msg = $parser->parse($msg)
- } elsif (ref $msg eq 'SCALAR') {
- debug 'Parsing from string';
- $msg = $parser->parse_data($$msg)
- } elsif (!ref $msg) {
- debug "Parsing from file $msg";
- $msg = $parser->parse_open($msg)
- } else {
- die "Don't know how to parse $msg"
- }
+ $msg = $in if ref $in eq 'MIME::Entity';
+ $msg = $parser->parse ($in) if ref $in eq 'IO';
+ $msg = $parser->parse_data ($in) if ref $in eq 'SCALAR';
+ $msg = $parser->parse_open ($in) unless ref $in;
+ die "Don't know how to parse $in" unless $msg;
if ($msg->mime_type ne 'multipart/signed' && $msg->mime_type ne 'multipart/encrypted') {
# PGP/Inline requires decoding
@@ -92,7 +110,7 @@ sub process_message {
}
debug 'This mail doesn\'t seem to be signed or encrypted';
- return 'plain'
+ return 'plain', message => ''
}
sub run {
@@ -102,14 +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 {
@@ -117,22 +139,25 @@ 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 => 'tmpl/en');
- my ($data, $subject);
- $tt->process($tmpl, \%params, \$data);
- $tt->process('subject', undef, \$subject);
+ 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'),
- Subject => $subject,
- Data => $data);
+ Subject => 'Re: ' . $in->get('Subject'),
+ Data => $keys.$result);
+ my $email_unencrypted = $email->dup;
my $mg = mg always_trust => 1;
- $mg->mime_signencrypt($email, $in->get('From') =~ /<(.*)>/) and debug 'Could not encrypt message. GnuPG said ', stringify $mg->{last_message};
- sendmail $email
+ 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;
@@ -170,9 +195,19 @@ App::EdwardNG - GnuPG email sign/encrypt testing bot
EdwardNG is a reimplementation of the Edward reply bot referenced in L.
-It takes mail messages, checks them for PGP signatures and encryption, then replies appropriately.
+=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>)
-This module exports a single function, B, which takes a single parameter representing the message. This parameter can be:
+Analyze a message, looking for PGP signatures and encryption. I<$message> can be:
=over
@@ -182,7 +217,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
@@ -234,7 +269,7 @@ Marius Gavrilescu, Emarius@ieval.roE
=head1 COPYRIGHT AND LICENSE
-Copyright (C) 2014 by Marius Gavrilescu
+Copyright (C) 2014 by FundaÈia Ceata
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.18.2 or,