File Coverage

blib/lib/AnyEvent/GnuPG.pm
Criterion Covered Total %
statement 435 625 69.6
branch 196 390 50.2
condition 25 68 36.7
subroutine 69 92 75.0
pod 21 21 100.0
total 746 1196 62.3


line stmt bran cond sub pod time code
1 1     1   34994 use strict;
  1         2  
  1         58  
2 1     1   7 use warnings;
  1         1  
  1         44  
3              
4             package AnyEvent::GnuPG;
5              
6             # ABSTRACT: AnyEvent-based interface to the GNU Privacy Guard
7              
8 1     1   4 use Exporter 'import';
  1         5  
  1         24  
9 1     1   1193 use AnyEvent;
  1         5449  
  1         82  
10 1     1   1007 use AnyEvent::Proc 0.104;
  1         77971  
  1         43  
11 1     1   565 use Email::Address;
  1         26315  
  1         118  
12 1     1   579 use Async::Chain;
  1         849  
  1         4  
13 1     1   31 use Try::Tiny;
  1         2  
  1         52  
14 1     1   4 use Carp qw(confess);
  1         2  
  1         75  
15              
16 1     1   8 use constant RSA_RSA => 1;
  1         1  
  1         68  
17 1     1   4 use constant DSA_ELGAMAL => 2;
  1         2  
  1         33  
18 1     1   4 use constant DSA => 3;
  1         1  
  1         30  
19 1     1   3 use constant RSA => 4;
  1         2  
  1         32  
20              
21 1     1   10 use constant TRUST_UNDEFINED => -1;
  1         1  
  1         31  
22 1     1   4 use constant TRUST_NEVER => 0;
  1         1  
  1         32  
23 1     1   6 use constant TRUST_MARGINAL => 1;
  1         1  
  1         54  
24 1     1   7 use constant TRUST_FULLY => 2;
  1         2  
  1         98  
25 1     1   7 use constant TRUST_ULTIMATE => 3;
  1         2  
  1         6248  
26              
27             our $VERSION = '1.001'; # VERSION
28              
29             our @EXPORT = qw();
30              
31             our %EXPORT_TAGS = (
32             algo => [qw[ RSA_RSA DSA_ELGAMAL DSA RSA ]],
33             trust => [
34             qw[ TRUST_UNDEFINED TRUST_NEVER TRUST_MARGINAL TRUST_FULLY TRUST_ULTIMATE ]
35             ],
36             );
37              
38             Exporter::export_ok_tags(qw( algo trust ));
39              
40             sub _options {
41 46     46   76 my $self = shift;
42 46 100       172 $self->{cmd_options} = shift if ( $_[0] );
43 46         131 $self->{cmd_options};
44             }
45              
46             sub _command {
47 46     46   75 my $self = shift;
48 46 100       208 $self->{command} = shift if ( $_[0] );
49 46         198 $self->{command};
50             }
51              
52             sub _args {
53 46     46   73 my $self = shift;
54 46 100       146 $self->{args} = shift if ( $_[0] );
55 46         100 $self->{args};
56             }
57              
58             sub _cmdline {
59 23     23   42 my $self = shift;
60 23         89 my $args = [ $self->{gnupg_path} ];
61              
62             # Default options
63 23         115 push @$args, "--no-tty", "--no-greeting", "--yes";
64              
65             # Check for homedir and options file
66 23 50       134 push @$args, "--homedir", $self->{homedir} if $self->{homedir};
67 23 50       83 push @$args, "--options", $self->{options} if $self->{options};
68              
69             # Command options
70 23         55 push @$args, @{ $self->_options };
  23         57  
71              
72             # Command and arguments
73 23         89 push @$args, "--" . $self->_command;
74 23         48 push @$args, @{ $self->_args };
  23         54  
75              
76 23         54 return $args;
77             }
78              
79             sub _condvar {
80 46     46   97 my $cb = shift;
81 46 100       262 return $cb if ref $cb eq 'AnyEvent::CondVar';
82 40         2730 my $cv = AE::cv;
83 40 100       4631 $cv->cb($cb) if ref $cb eq 'CODE';
84 40   100     432 $cb ||= '';
85 40         150 $cv;
86             }
87              
88             sub _croak {
89 0     0   0 my ( $cv, $msg ) = @_;
90 0         0 AE::log error => $msg;
91 0         0 $cv->croak($msg);
92 0         0 $cv;
93             }
94              
95             sub _catch {
96 6     6   16 my ( $cv1, $cb ) = @_;
97             AE::cv {
98 6     6   59 my $cv2 = shift;
99             try {
100 6         298 $cb->( $cv2->recv );
101             }
102             catch {
103 0         0 s{ at \S+ line \d+\.\s+$}{};
104 0         0 $cv1->croak($_)
105 6         103 };
106             }
107 6         348 }
108              
109 5227     5227   10997 sub _eq($_) { shift eq pop } ## no critic
110              
111             sub _parse_status {
112 19     19   209 my ( $self, $cv, %actions ) = @_;
113 19         50 my $commands;
114             $self->{status_fd}->readlines_cb(
115             sub {
116 125     125   9863963 my $line = shift;
117 125 50       357 unless ( defined $line ) {
118 0         0 AE::log debug => "end of status parsing";
119 0         0 $cv->send($commands);
120             }
121 125 50       1076 if ( my ( $cmd, $arg ) =
122             $line =~ m{^\[gnupg:\]\s+(\w+)\s*(.+)?\s*$}i )
123             {
124 125   100     514 $arg ||= '';
125 125 100       498 my @args = $arg ? ( split /\s+/, $arg ) : ();
126 125         691 AE::log debug => "got command: $cmd ($arg)";
127             try {
128 125         4715 for ( lc $cmd ) {
129 125 50       276 _eq('newsig') && do { last };
  0         0  
130 125 100       216 _eq('goodsig') && do { last };
  4         12  
131             _eq('expsig')
132 121 50       182 && do { die "the signature is expired ($arg)" };
  0         0  
133 121 50       213 _eq('expkeysig') && do {
134 0         0 die
135             "the signature was made by an expired key ($arg)";
136             };
137 121 50       208 _eq('revkeysig') && do {
138 0         0 die
139             "the signature was made by an revoked key ($arg)";
140             };
141 121 50       189 _eq('badsig') && do {
142 0         0 die
143             "the signature has not been verified okay ($arg)";
144             };
145 121 50       217 _eq('errsig') && do {
146 0         0 die "the signature could not be verified ($arg)";
147             };
148 121 100       211 _eq('validsig') && do { last };
  4         14  
149 117 100       174 _eq('sig_id') && do { last };
  4         21  
150 113 100       173 _eq('enc_to') && do { last };
  3         10  
151 110 50       180 _eq('nodata') && do {
152 0         0 for ($arg) {
153 0 0       0 _eq('1') && die "no armored data";
154 0 0       0 _eq('2')
155             && die
156             "expected a packet but did not found one";
157 0 0       0 _eq('3') && die "invalid packet found";
158 0 0       0 _eq('4')
159             && die "signature expected but not found";
160 0         0 die "no data has been found";
161             }
162             };
163             _eq('unexpected')
164 110 50       181 && do { die "unexpected data has been encountered" };
  0         0  
165             _eq('trust_undefined')
166 110 50       239 && do { die "signature trust undefined: $arg" };
  0         0  
167             _eq('trust_never')
168 110 50       180 && do { die "signature trust is never: $arg" };
  0         0  
169 110 50       188 _eq('trust_marginal') && do { last };
  0         0  
170 110 50       187 _eq('trust_fully') && do { last };
  0         0  
171 110 100       214 _eq('trust_ultimate') && do { last };
  4         11  
172 106 50       167 _eq('pka_trust_good') && do { last };
  0         0  
173 106 50       148 _eq('pka_trust_bad') && do { last };
  0         0  
174             _eq('sigexpired')
175 106 50 50     173 or _eq('keyexpired') && do {
176 0         0 die "the key has expired since "
177             . ( scalar localtime $arg );
178             };
179 106 50       178 _eq('keyrevoked') && do {
180 0         0 die "the used key has been revoked by its owner";
181             };
182             _eq('badarmor')
183 106 50       216 && do { die "the ASCII armor is corrupted" };
  0         0  
184 106 50       184 _eq('rsa_or_idea') && do { last };
  0         0  
185 106 50       238 _eq('shm_info') && do { last };
  0         0  
186 106 50       214 _eq('shm_get') && do { last };
  0         0  
187 106 50       171 _eq('shm_get_bool') && do { last };
  0         0  
188 106 50       159 _eq('shm_get_hidden') && do { last };
  0         0  
189 106 100       172 _eq('get_bool') && do { last };
  2         12  
190 104 50       159 _eq('get_line') && do { last };
  0         0  
191 104 100       173 _eq('get_hidden') && do { last };
  10         17  
192 94 100       142 _eq('got_it') && do { last };
  12         29  
193 82 100       127 _eq('need_passphrase') && do { last };
  8         23  
194 74 100       147 _eq('need_passphrase_sym') && do { last };
  2         19  
195 72 50       101 _eq('need_passphrase_pin') && do { last };
  0         0  
196             _eq('missing_passphrase')
197 72 50       146 && do { die "no passphrase was supplied" };
  0         0  
198 72 50       123 _eq('bad_passphrase') && do {
199 0         0 die
200             "the supplied passphrase was wrong or not given";
201             };
202 72 100       110 _eq('good_passphrase') && do { last };
  8         17  
203             _eq('decryption_failed')
204 64 50       141 && do { die "the symmetric decryption failed" };
  0         0  
205 64 100       94 _eq('decryption_okay') && do { last };
  4         7  
206 60 100       122 _eq('decryption_info') && do { last };
  4         8  
207             _eq('no_pubkey')
208 56 50       97 && do { die "the public key is not available" };
  0         0  
209             _eq('no_seckey')
210 56 50       92 && do { die "the private key is not available" };
  0         0  
211 56 50       102 _eq('import_check') && do { last };
  0         0  
212             _eq('imported')
213 56 50       103 && do { @args = split /\s+/, $arg, 2; last };
  0         0  
  0         0  
214 56 100       103 _eq('import_ok') && do { last };
  4         11  
215 52 50       119 _eq('import_problem') && do {
216              
217 0         0 for ($arg) {
218 0 0       0 _eq('0')
219             && die
220             "import failed with no specific reason";
221 0 0       0 _eq('1') && die "invalid certificate";
222 0 0       0 _eq('2') && die "issuer certificate missing";
223 0 0       0 _eq('3') && die "certificate chain too long";
224 0 0       0 _eq('4') && die "error storing certificate";
225 0         0 die "import failed";
226             }
227             };
228 52 100       109 _eq('import_res') && do { last };
  3         7  
229 49 50       124 _eq('file_start') && do { last };
  0         0  
230 49 50       116 _eq('file_done') && do { last };
  0         0  
231 49 100       216 _eq('begin_decryption') && do { last };
  4         9  
232 45 100       93 _eq('end_decryption') && do { last };
  4         7  
233 41 100       96 _eq('begin_encryption') && do { last };
  6         150  
234 35 100       60 _eq('end_encryption') && do { last };
  6         12  
235 29 100       68 _eq('begin_signing') && do { last };
  5         20  
236 24 50       53 _eq('delete_problem') && do {
237              
238 0         0 for ($arg) {
239 0 0       0 _eq('1') && die "delete failed: no such key";
240 0 0       0 _eq('2')
241             && die
242             "delete failed: must delete secret key first";
243 0 0       0 _eq('3')
244             && die
245             "delete failed: ambigious specification";
246 0         0 die "delete failed";
247             }
248             };
249 24 50       60 _eq('progress') && do { last };
  0         0  
250 24 100       51 _eq('sig_created') && do { last };
  5         19  
251 19 50       29 _eq('key_created') && do { last };
  0         0  
252 19 50       31 _eq('key_not_created') && do {
253 0         0 die "the key from batch run has not been created";
254             };
255 19 50       33 _eq('session_key') && do { last };
  0         0  
256 19 50       28 _eq('notation_name') && do { last };
  0         0  
257 19 50       30 _eq('notation_data') && do { last };
  0         0  
258 19 100       35 _eq('userid_hint') && do { last };
  8         17  
259 11 50       18 _eq('policy_url') && do { last };
  0         0  
260 11 50       16 _eq('begin_stream') && do { last };
  0         0  
261 11 50       18 _eq('end_stream') && do { last };
  0         0  
262 11 50 33     14 ( _eq('inv_recp') or _eq('inc_sgnr') ) && do {
263 0         0 my $prefix = 'invalid';
264 0         0 for ($cmd) {
265             _eq('inv_recp')
266 0 0       0 && do { $prefix .= ' recipient' };
  0         0  
267 0 0       0 _eq('inv_sgnr') && do { $prefix .= ' sender' };
  0         0  
268             }
269 0         0 $prefix .= ': ';
270 0         0 for ( shift(@args) ) {
271 0 0       0 _eq('0') && die $prefix . "no specific reason";
272 0 0       0 _eq('1') && die $prefix . "not found";
273 0 0       0 _eq('2')
274             && die $prefix . "ambigious specification";
275 0 0       0 _eq('3') && die $prefix . "wrong key usage";
276 0 0       0 _eq('4') && die $prefix . "key revoked";
277 0 0       0 _eq('5') && die $prefix . "key expired";
278 0 0       0 _eq('6') && die $prefix . "no CRL known";
279 0 0       0 _eq('7') && die $prefix . "CRL too old";
280 0 0       0 _eq('8') && die $prefix . "policy mismatch";
281 0 0       0 _eq('9') && die $prefix . "not a secret key";
282 0 0       0 _eq('10') && die $prefix . "key not trusted";
283 0 0       0 _eq('11')
284             && die $prefix . "missing certificate";
285 0 0       0 _eq('12')
286             && die $prefix . "missing issuer certificate";
287 0         0 die $prefix . '???';
288             }
289             };
290 11 50       20 _eq('no_recp') && do { die "no recipients are usable" };
  0         0  
291 11 50       16 _eq('no_sgnr') && do { die "no senders are usable" };
  0         0  
292 11 50       18 _eq('already_signed') && do { last };
  0         0  
293 11 50       17 _eq('truncated') && do { last };
  0         0  
294 11 50       22 _eq('error') && do { die $arg };
  0         0  
295 11 50       25 _eq('success') && do { last };
  0         0  
296 11 50       16 _eq('attribute') && do { last };
  0         0  
297 11 50       16 _eq('cardctrl') && do { last };
  0         0  
298 11 100       13 _eq('plaintext') && do { last };
  4         7  
299 7 100       11 _eq('plaintext_length') && do { last };
  4         7  
300 3 50       12 _eq('sig_subpacket') && do { last };
  0         0  
301             _eq('sc_op_failure')
302 3 50       5 && do { die "smartcard failure ($arg)" };
  0         0  
303 3 50       7 _eq('sc_op_success') && do { last };
  0         0  
304 3 50       4 _eq('backup_key_created') && do { last };
  0         0  
305 3 50       7 _eq('mountpoint') && do { last };
  0         0  
306 3         13 AE::log note => "unknown command: $cmd";
307             }
308 125         315 my $result;
309 125 100       370 if ( $actions{ lc($cmd) } ) {
310 52         159 $result = $actions{ lc($cmd) }->(@args);
311             }
312 125         2654 push @$commands => {
313             cmd => $cmd,
314             arg => $arg,
315             args => \@args,
316             result => $result
317             };
318             }
319             catch {
320 0         0 s{\s+$}{};
321 0         0 $self->_abort_gnupg( $_, $cv );
322             }
323             finally {
324 259         825 AE::log debug => "arguments parsed as: ["
325 125         2999 . ( join ', ', map { "'$_'" } @args ) . "]";
326             }
327 125         7811 }
328             else {
329 0         0 return $self->_abort_gnupg(
330             "error communicating with gnupg: bad status line: $line",
331             $cv );
332             }
333             }
334 19         330 );
335 19         1775 $cv;
336             }
337              
338             sub _abort_gnupg {
339 0     0   0 my ( $self, $msg, $cb ) = @_;
340 0         0 my $cv = _condvar($cb);
341 0 0       0 AE::log error => $msg if $msg;
342 0 0       0 if ( $self->{gnupg_proc} ) {
343             $self->{gnupg_proc}->fire_and_kill(
344             10,
345             sub {
346 0     0   0 AE::log debug => "fired and killed";
347             $self->_end_gnupg(
348             sub {
349 0         0 AE::log debug => "gnupg aborted";
350 0         0 $cv->croak($msg);
351             }
352 0         0 );
353             }
354 0         0 );
355             }
356 0         0 $cv;
357             }
358              
359             sub _end_gnupg {
360 23     23   269 my ( $self, $cb ) = @_;
361 23         139 my $cv = _condvar($cb);
362              
363 23 100       139 if ( ref $self->{input} eq 'GLOB' ) {
364 17         449 close $self->{input};
365             }
366              
367 23 50       151 if ( $self->{command_fd} ) {
368 23         256 $self->{command_fd}->finish;
369             }
370              
371 23         2009 if ( 0 && $self->{status_fd} ) {
372             $self->{status_fd}->A->destroy;
373             }
374              
375 23 50       130 if ( $self->{gnupg_proc} ) {
376              
377             $self->{gnupg_proc}->wait(
378             sub {
379 23 100   23   1530712 if ( ref $self->{output} eq 'GLOB' ) {
380 16         2253 close $self->{output};
381             }
382              
383 23         244 for (
384             qw(protocol proc command options args status_fd command_fd input output next_status )
385             )
386             {
387 230         768 delete $self->{$_};
388             }
389              
390 23         110 AE::log debug => "gnupg exited";
391 23         1062 $cv->send;
392             }
393 23         313 );
394              
395             }
396             else {
397 0         0 $cv->send;
398             }
399 23         2107 $cv;
400             }
401              
402             sub _run_gnupg {
403 23     23   56 my ( $self, $cv ) = @_;
404              
405 23 100 100     236 if ( defined $self->{input} and not ref $self->{input} ) {
406 16         41 my $file = $self->{input};
407 16 50       927 open( my $fh, '<', $file ) or die "cannot open file $file: $!";
408 16         156 AE::log info => "input file $file opened at $fh";
409 16         1376 $self->{input} = $fh;
410             }
411              
412 23 100 100     218 if ( defined $self->{output} and not ref $self->{output} ) {
413 15         60 my $file = $self->{output};
414 15 50       13821 open( my $fh, '>', $file ) or die "cannot open file $file: $!";
415 15         169 AE::log info => "output file $file opened at $fh";
416 15         807 $self->{output} = $fh;
417             }
418              
419 23         120 my $cmdline = $self->_cmdline;
420              
421 23         47 my $gpg = shift @$cmdline;
422              
423 23         118 my $status = AnyEvent::Proc::reader();
424 23         4415 my $command = AnyEvent::Proc::writer();
425              
426 23         2532 unshift @$cmdline, '--status-fd' => $status;
427 23         64 unshift @$cmdline, '--command-fd' => $command;
428              
429 23         33 my $err;
430              
431 23         279 AE::log debug => "running $gpg " . join( ' ' => @$cmdline );
432             my $proc = AnyEvent::Proc->new(
433             bin => $gpg,
434             args => $cmdline,
435             extras => [ $status, $command ],
436             ttl => 600,
437 0     0   0 on_ttl_exceed => sub { $self->_abort_gnupg( 'ttl exceeded', $cv ) },
438 23         6772 errstr => \$err,
439             );
440              
441 23 100       68469 if ( defined $self->{input} ) {
442 17         316 $proc->pull( $self->{input} );
443             }
444              
445 23 100       6819 if ( defined $self->{output} ) {
446 16         175 $proc->pipe( out => $self->{output} );
447             }
448              
449 23         2250 $self->{command_fd} = $command;
450 23         158 $self->{status_fd} = $status;
451 23         70 $self->{gnupg_proc} = $proc;
452              
453 23         2820 AE::log debug => "gnupg ready";
454              
455 23         2192 $proc;
456             }
457              
458             sub _send_command {
459 12     12   113 shift->{command_fd}->writeln(pop);
460             }
461              
462             sub DESTROY {
463 0     0   0 my $self = shift;
464              
465 0 0       0 $self->{gnupg_proc}->kill if $self->{gnupg_proc};
466             }
467              
468             sub new {
469 1     1 1 599 my $proto = shift;
470 1   33     8 my $class = ref $proto || $proto;
471              
472 1         3 my %args = @_;
473              
474 1         2 my $self = {};
475 1 50       4 if ( $args{homedir} ) {
476 1 50 33     17 confess("Invalid home directory: $args{homedir}")
477             unless -d $args{homedir} && -x _;
478 1         3 $self->{homedir} = $args{homedir};
479             }
480 1 50       3 if ( $args{options} ) {
481 0 0       0 confess("Invalid options file: $args{options}")
482             unless -r $args{options};
483 0         0 $self->{options} = $args{options};
484             }
485 1 50       3 if ( $args{gnupg_path} ) {
486 0 0       0 confess("Invalid gpg path: $args{gnupg_path}")
487             unless -x $args{gnupg_path};
488 0         0 $self->{gnupg_path} = $args{gnupg_path};
489             }
490             else {
491 1         6 my ($path) = grep { -x "$_/gpg" } split /:/, $ENV{PATH};
  7         45  
492 1 50       4 confess("Couldn't find gpg in PATH ($ENV{PATH})") unless $path;
493 1         19 $self->{gnupg_path} = "$path/gpg";
494             }
495              
496 1         4 bless $self, $class;
497             }
498              
499             sub version {
500 1     1 1 599 shift->version_cb(@_)->recv;
501             }
502              
503             sub version_cb {
504 1     1 1 3 my ( $self, $cb ) = @_;
505 1         4 my $cv = _condvar($cb);
506              
507 1         6 $self->_command("version");
508 1         7 $self->_options( [] );
509 1         6 $self->_args( [] );
510              
511 1         2 my $version;
512              
513 1         6 my $proc = $self->_run_gnupg($cv);
514              
515 1         7 $proc->pipe( \$version );
516              
517 1         96 $proc->finish;
518              
519             $self->_end_gnupg(
520             sub {
521 1 50   1   18 if ( $version =~ m{\d(?:\.\d)*} ) {
522 1         9 $cv->send( split m{\.} => $& );
523             }
524             else {
525 0         0 $cv->croak(
526             "cannot obtain version number from string: '$version'");
527             }
528             }
529 1         106 );
530              
531 1         30 $cv;
532             }
533              
534             sub gen_key {
535 0     0 1 0 shift->gen_key_cb(@_)->recv;
536             }
537              
538             sub gen_key_cb {
539 0     0 1 0 my ( $self, %args ) = @_;
540 0         0 my $cv = _condvar( delete $args{cb} );
541 0         0 my $cmd;
542             my $arg;
543              
544 0         0 my $algo = $args{algo};
545 0   0     0 $algo ||= RSA_RSA;
546              
547 0         0 my $size = $args{size};
548 0   0     0 $size ||= 1024;
549 0 0       0 return _croak( $cv, "Keysize is too small: $size" ) if $size < 768;
550 0 0       0 return _croak( $cv, "Keysize is too big: $size" ) if $size > 2048;
551              
552 0         0 my $expire = $args{valid};
553 0   0     0 $expire ||= 0;
554              
555 0   0     0 my $passphrase = $args{passphrase} || "";
556 0         0 my $name = $args{name};
557              
558 0 0       0 return _croak( $cv, "Missing key name" ) unless $name;
559 0 0       0 return _croak( $cv, "Invalid name: $name" )
560             unless $name =~ /^\s*[^0-9\<\(\[\]\)\>][^\<\(\[\]\)\>]+$/;
561              
562 0         0 my $email = $args{email};
563 0 0       0 if ($email) {
564 0 0       0 ($email) = Email::Address->parse($email)
565             or _croak( $cv, "Invalid email address: $email" );
566             }
567             else {
568 0         0 $email = "";
569             }
570              
571 0         0 my $comment = $args{comment};
572 0 0       0 if ($comment) {
573 0 0       0 _croak( $cv, "Invalid characters in comment" ) if $comment =~ /[\(\)]/;
574             }
575             else {
576 0         0 $comment = "";
577             }
578              
579 0         0 $self->_command("gen-key");
580 0         0 $self->_options( [] );
581 0         0 $self->_args( [] );
582              
583 0         0 my $proc = $self->_run_gnupg($cv);
584 0 0       0 $proc->finish unless $self->{input};
585              
586             $self->_parse_status(
587             $cv,
588             progress => $args{progress},
589             get_line => sub {
590 0     0   0 my ($key) = @_;
591 0         0 for ($key) {
592 0 0 0     0 _eq('keygen.algo')
593             && $self->_send_command($algo)
594             && last;
595 0 0 0     0 _eq('keygen.size')
596             && $self->_send_command($size)
597             && last;
598 0 0 0     0 _eq('keygen.valid')
599             && $self->_send_command($expire)
600             && last;
601 0 0 0     0 _eq('keygen.name')
602             && $self->_send_command($name)
603             && last;
604 0 0 0     0 _eq('keygen.email')
605             && $self->_send_command($email)
606             && last;
607 0 0 0     0 _eq('keygen.comment')
608             && $self->_send_command($comment)
609             && last;
610 0         0 $self->_abort_gnupg( "unknown key: $key", $cv );
611             }
612             },
613             need_passphrase_sym => sub {
614 0 0   0   0 unless ( defined $passphrase ) {
615 0         0 return $self->_abort_gnupg( "passphrase required", $cv );
616             }
617             },
618             get_hidden => sub {
619 0     0   0 $self->_send_command($passphrase);
620             },
621             key_created => sub {
622 0     0   0 my $fingerprint = $_[1];
623 0         0 $self->_end_gnupg( sub { $cv->send($fingerprint) } );
  0         0  
624             }
625 0         0 );
626              
627 0         0 $cv;
628             }
629              
630             sub import_keys {
631 3     3 1 11153 shift->import_keys_cb(@_)->recv->{count};
632             }
633              
634             sub import_keys_cb {
635 3     3 1 24 my ( $self, %args ) = @_;
636 3         18 my $cv = _condvar( delete $args{cb} );
637              
638 3         25 $self->_command("import");
639 3         13 $self->_options( [] );
640              
641 3         8 my $count = 0;
642 3 100       17 if ( ref $args{keys} eq 'ARRAY' ) {
643 1         11 $self->_args( $args{keys} );
644             }
645             else {
646 2         11 $self->{input} = $args{keys};
647 2         9 $self->_args( [] );
648             }
649              
650 3         15 my $proc = $self->_run_gnupg($cv);
651 3 100       37 $proc->finish unless $self->{input};
652              
653 3 100       178 my $num_files = ref $args{keys} ? @{ $args{keys} } : 1;
  1         7  
654              
655             $self->_parse_status(
656             $cv,
657 0     0   0 imported => sub { $count++ },
658             import_res => sub {
659             $self->_end_gnupg(
660             _catch(
661             $cv,
662             sub {
663 3         51 $cv->send( { count => $count } );
664             }
665             )
666 3     3   27 );
667             }
668 3         79 );
669              
670 3         90 $cv;
671             }
672              
673             sub import_key {
674 0     0 1 0 shift->import_key_cb(@_)->recv;
675             }
676              
677             sub import_key_cb {
678 0     0 1 0 my ( $self, $keystr, $cb ) = @_;
679 0         0 $self->import_keys_cb( keys => \"$keystr", cb => $cb );
680             }
681              
682             sub export_keys {
683 3     3 1 10132 shift->export_keys_cb(@_)->recv;
684             }
685              
686             sub export_keys_cb {
687 3     3 1 25 my ( $self, %args ) = @_;
688 3         17 my $cv = _condvar( delete $args{cb} );
689              
690 3         13 my $options = [];
691 3 50       26 push @$options, "--armor" if $args{armor};
692              
693 3         13 $self->{output} = $args{output};
694              
695 3         9 my $keys = [];
696 3 100       13 if ( $args{keys} ) {
697 1 50       7 push @$keys, ref $args{keys} ? @{ $args{keys} } : $args{keys};
  0         0  
698             }
699              
700 3 100       29 if ( $args{secret} ) {
    50          
701 1         12 $self->_command("export-secret-keys");
702             }
703             elsif ( $args{all} ) {
704 0         0 $self->_command("export-all");
705             }
706             else {
707 2         13 $self->_command("export");
708             }
709              
710 3         15 $self->_options($options);
711 3         14 $self->_args($keys);
712              
713 3         13 my $proc = $self->_run_gnupg($cv);
714              
715 3 50       71 $proc->finish unless $self->{input};
716              
717 3     3   496 $self->_end_gnupg( _catch( $cv, sub { $cv->send( {} ) } ) );
  3         38  
718              
719 3         115 $cv;
720             }
721              
722             sub encrypt {
723 6     6 1 17487 shift->encrypt_cb(@_)->recv;
724             }
725              
726             sub encrypt_cb {
727 6     6 1 86 my ( $self, %args ) = @_;
728 6         39 my $cv = _condvar( delete $args{cb} );
729              
730 6         19 my $options = [];
731 6 50 66     38 croak("no recipient specified")
732             unless $args{recipient} or $args{symmetric};
733              
734 6 100       47 for my $recipient (
  1         11  
735             grep defined,
736             (
737             ref $args{recipient} eq 'ARRAY'
738             ? @{ $args{recipient} }
739             : $args{recipient}
740             )
741             )
742             {
743             # Escape spaces in the recipient. This fills some strange edge case
744 6         55 $recipient =~ s/ /\ /g;
745 6         45 push @$options, "--recipient" => $recipient;
746             }
747              
748 6 100       33 push @$options, "--sign" if $args{sign};
749 6 50 66     44 croak("can't sign an symmetric encrypted message")
750             if $args{sign} and $args{symmetric};
751              
752 6   100     44 my $passphrase = $args{passphrase} || "";
753              
754 6 50       26 push @$options, "--armor" if $args{armor};
755 6 50       202 push @$options, "--local-user", $args{"local-user"}
756             if defined $args{"local-user"};
757              
758 6 50       23 push @$options, "--auto-key-locate", $args{"auto-key-locate"}
759             if defined $args{"auto-key-locate"};
760              
761 6 50       20 push @$options, "--keyserver", $args{"keyserver"}
762             if defined $args{"keyserver"};
763              
764 6   33     39 $self->{input} = $args{plaintext} || $args{input};
765 6         21 $self->{output} = $args{output};
766 6 100       99 if ( $args{symmetric} ) {
767 1         6 $self->_command("symmetric");
768             }
769             else {
770 5         36 $self->_command("encrypt");
771             }
772 6         24 $self->_options($options);
773 6         39 $self->_args( [] );
774              
775 6         25 my $proc = $self->_run_gnupg($cv);
776 6 50       51 $proc->finish unless $self->{input};
777              
778             $self->_parse_status(
779             $cv,
780             end_encryption => sub {
781             $self->_end_gnupg(
782             sub {
783 6         58 $cv->send;
784             }
785 6     6   569 );
786             },
787             need_passphrase => sub {
788 2 50   2   14 unless ( defined $passphrase ) {
789 0         0 return $self->_abort_gnupg( "passphrase required", $cv );
790             }
791             },
792             get_hidden => sub {
793 3     3   17 $self->_send_command($passphrase);
794             },
795             get_bool => sub {
796 2     2   7 for (shift) {
797             _eq('untrusted_key.override')
798 2 50       15 && do { $self->_send_command('y'); last }
  2         9  
  2         249  
799             }
800             },
801 6         202 );
802              
803 6         276 $cv;
804             }
805              
806             sub sign {
807 3     3 1 4746 shift->sign_cb(@_)->recv;
808             }
809              
810             sub sign_cb {
811 3     3 1 38 my ( $self, %args ) = @_;
812 3         21 my $cv = _condvar( delete $args{cb} );
813              
814 3         8 my $options = [];
815 3   50     15 my $passphrase = $args{passphrase} || "";
816              
817 3 50       17 push @$options, "--armor" if $args{armor};
818 3 50       14 push @$options, "--local-user", $args{"local-user"}
819             if defined $args{"local-user"};
820              
821 3   33     14 $self->{input} = $args{plaintext} || $args{input};
822 3         9 $self->{output} = $args{output};
823 3 100       17 if ( $args{clearsign} ) {
    100          
824 1         6 $self->_command("clearsign");
825             }
826             elsif ( $args{"detach-sign"} ) {
827 1         11 $self->_command("detach-sign");
828             }
829             else {
830 1         5 $self->_command("sign");
831             }
832 3         14 $self->_options($options);
833 3         12 $self->_args( [] );
834              
835 3         11 my $proc = $self->_run_gnupg($cv);
836 3 50       35 $proc->finish unless $self->{input};
837              
838             $self->_parse_status(
839             $cv,
840             need_passphrase => sub {
841 3 50   3   21 unless ( defined $passphrase ) {
842 0         0 return $self->_abort_gnupg( "passphrase required", $cv );
843             }
844             },
845             get_hidden => sub {
846 3     3   26 $self->_send_command($passphrase);
847             },
848             sig_created => sub {
849 3     3   42 $self->_end_gnupg( sub { $cv->send } );
  3         36  
850             },
851 3         152 );
852              
853 3         179 $cv;
854             }
855              
856             sub clearsign {
857 1     1 1 2387 my $self = shift;
858 1         8 $self->sign( @_, clearsign => 1 );
859             }
860              
861             sub clearsign_cb {
862 0     0 1 0 my $self = shift;
863 0         0 $self->sign_cb( @_, clearsign => 1 );
864             }
865              
866             sub verify {
867 3     3 1 7797 shift->verify_cb(@_)->recv;
868             }
869              
870             sub verify_cb {
871 3     3 1 20 my ( $self, %args ) = @_;
872 3         15 my $cv = _condvar( delete $args{cb} );
873              
874 3 50       13 return _croak( $cv, "missing signature argument" ) unless $args{signature};
875 3         7 my $files = [];
876 3 100       18 if ( $args{file} ) {
877 1 50       9 $args{file} = [ $args{file} ] unless ref $args{file};
878 1         4 @$files = ( $args{signature}, @{ $args{file} } );
  1         3  
879             }
880             else {
881 2         10 $self->{input} = $args{signature};
882             }
883              
884 3         8 my $options = [];
885              
886 3 50       15 push @$options, "--auto-key-locate", $args{"auto-key-locate"}
887             if defined $args{"auto-key-locate"};
888              
889 3 50       13 push @$options, "--keyserver", $args{"keyserver"}
890             if defined $args{"keyserver"};
891              
892 3         7 my @verify_options = ();
893              
894 3 50       10 push @verify_options => 'pka-lookups' if $args{'pka-loopups'};
895 3 50       10 push @verify_options => 'pka-trust-increase' if $args{'pka-trust-increase'};
896              
897 3 50       9 push @$options => ( '--verify-options' => join( ',' => @verify_options ) )
898             if @verify_options;
899              
900 3         14 $self->_command("verify");
901 3         10 $self->_options($options);
902 3         10 $self->_args($files);
903              
904 3         12 my $proc = $self->_run_gnupg($cv);
905 3 100       61 $proc->finish unless $self->{input};
906              
907 3         119 my $sig = { trust => TRUST_UNDEFINED, };
908              
909             $self->_parse_status(
910             $cv,
911             sig_id => sub {
912 3     3   24 ( $sig->{sigid}, $sig->{data}, $sig->{timestamp} ) = @_;
913             },
914             goodsig => sub {
915 3     3   19 ( $sig->{keyid}, $sig->{user} ) = @_;
916             },
917             validsig => sub {
918 3     3   21 ( $sig->{fingerprint} ) = @_;
919 3         40 $self->_end_gnupg( sub { $cv->send } );
  3         32  
920             },
921             policy_url => sub {
922 0     0   0 ( $sig->{policy_url} ) = @_;
923             },
924             trust_never => sub {
925 0     0   0 $sig->{trust} = TRUST_NEVER;
926             },
927             trust_marginal => sub {
928 0     0   0 $sig->{trust} = TRUST_MARGINAL;
929             },
930             trust_fully => sub {
931 0     0   0 $sig->{trust} = TRUST_FULLY;
932             },
933             trust_ultimate => sub {
934 3     3   11 $sig->{trust} = TRUST_ULTIMATE;
935             },
936 3         116 );
937              
938 3         93 $cv;
939             }
940              
941             sub decrypt {
942 4     4 1 13448 shift->decrypt_cb(@_)->recv;
943             }
944              
945             sub decrypt_cb {
946 4     4 1 52 my ( $self, %args ) = @_;
947 4         29 my $cv = _condvar( delete $args{cb} );
948              
949 4   33     32 $self->{input} = $args{ciphertext} || $args{input};
950 4         16 $self->{output} = $args{output};
951 4         23 $self->_command("decrypt");
952 4         18 $self->_options( [] );
953 4         16 $self->_args( [] );
954              
955 4         18 my $proc = $self->_run_gnupg($cv);
956 4 50       42 $proc->finish unless $self->{input};
957              
958 4   50     49 my $passphrase = $args{passphrase} || "";
959              
960 4         43 my $sig = { trust => TRUST_UNDEFINED, };
961              
962             $self->_parse_status(
963             $cv,
964             need_passphrase => sub {
965 3 50   3   12 unless ( defined $passphrase ) {
966 0         0 return $self->_abort_gnupg( "passphrase required", $cv );
967             }
968             },
969             get_hidden => sub {
970 4     4   17 $self->_send_command($passphrase);
971             },
972             end_decryption => sub {
973 4     4   36 $self->_end_gnupg( sub { $cv->send } );
  4         34  
974             },
975             sig_id => sub {
976 1     1   11 ( $sig->{sigid}, $sig->{data}, $sig->{timestamp} ) = @_;
977             },
978             goodsig => sub {
979 1     1   10 ( $sig->{keyid}, $sig->{user} ) = @_;
980             },
981             validsig => sub {
982 1     1   13 ( $sig->{fingerprint} ) = @_;
983             },
984             policy_url => sub {
985 0     0   0 ( $sig->{policy_url} ) = @_;
986             },
987             trust_never => sub {
988 0     0   0 $sig->{trust} = TRUST_NEVER;
989             },
990             trust_marginal => sub {
991 0     0   0 $sig->{trust} = TRUST_MARGINAL;
992             },
993             trust_fully => sub {
994 0     0   0 $sig->{trust} = TRUST_FULLY;
995             },
996             trust_ultimate => sub {
997 1     1   7 $sig->{trust} = TRUST_ULTIMATE;
998             },
999 4         267 );
1000              
1001 4         167 $cv;
1002             }
1003              
1004             1;
1005              
1006             __END__