File Coverage

blib/lib/Net/ACME/Authorization/Pending.pm
Criterion Covered Total %
statement 51 53 96.2
branch 5 8 62.5
condition 3 5 60.0
subroutine 11 11 100.0
pod 0 2 0.0
total 70 79 88.6


line stmt bran cond sub pod time code
1             package Net::ACME::Authorization::Pending;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Net::ACME::Authorization::Pending - pending ACME authorization
8              
9             =head1 SYNOPSIS
10              
11             use Net::ACME::Authorization::Pending ();
12              
13             my $authz_p = Net::ACME::Authorization::Pending->new(
14             uri => 'http://url/to/poll/for/authz',
15             challenges => \@challenge_objects,
16             combinations => [
17             [ 2 ],
18             [ 1 ],
19             [ 0 ],
20             ],
21             );
22              
23             for my $cmb ( $authz_p->combinations() ) {
24              
25             #An example of only doing “http-01”:
26             next if @$cmb > 1;
27             next if $cmb->[0]->type() ne 'http-01';
28              
29             #Prepare for the challenge …
30              
31             #Assume we instantiated Net::ACME above …
32             $acme->do_challenge($cmb->[0]);
33              
34             while (1) {
35             if ($authz_p->is_time_to_poll()) {
36             my $poll = $authz_p->poll();
37              
38             last if $poll->status() eq 'valid';
39              
40             if ($poll->status() eq 'invalid') {
41             my $completed_challenge = ($poll->challenges())[0];
42             print $completed_challenge->error()->detail() . $/;
43             die "Failed authorization!$/";
44             }
45              
46             }
47              
48             sleep 1;
49             }
50              
51             last;
52             }
53              
54             =cut
55              
56             #NOTE: For now, this assumes a domain name.
57             #Might be useful moving forward to separate out other types
58             #of authz as per ACME spec expansion. (As of April 2016 only
59             #domain names are handled.)
60              
61 7     7   49 use strict;
  7         15  
  7         205  
62 7     7   112 use warnings;
  7         19  
  7         201  
63              
64 7     7   412 use parent qw( Net::ACME::RetryAfter );
  7         264  
  7         42  
65              
66 7     7   1515 use Call::Context ();
  7         1522  
  7         119  
67              
68 7     7   2792 use Net::ACME::Authorization ();
  7         19  
  7         136  
69 7     7   2707 use Net::ACME::Challenge ();
  7         21  
  7         135  
70 7     7   43 use Net::ACME::Error ();
  7         14  
  7         163  
71 7     7   33 use Net::ACME::X ();
  7         57  
  7         3083  
72              
73             my $PENDING_CLASS = 'Net::ACME::Challenge::Pending';
74              
75             sub new {
76 3     3 0 2134 my ( $class, %opts ) = @_;
77              
78             my $self = {
79             _uri => $opts{'uri'} || die('Need “uri”!'),
80             _challenges => $opts{'challenges'},
81 3   50     24 _combinations => $opts{'combinations'},
82             };
83              
84 3 50       9 if ( !@{ $opts{'challenges'} } ) {
  3         14  
85 0         0 die Net::ACME::X::create( 'Empty', { name => 'challenges' } );
86             }
87              
88 3         8 for my $c ( 0 .. $#{ $opts{'challenges'} } ) {
  3         15  
89 4         13 my $challenge = $opts{'challenges'}[$c];
90              
91 4 50       34 if ( !$challenge->isa($PENDING_CLASS) ) {
92 0         0 die "Challenge $c ($challenge) is not an instance of “$PENDING_CLASS”!";
93             }
94             }
95              
96 3         9 bless $self, $class;
97              
98 3         16 return $self;
99             }
100              
101             sub combinations {
102 1     1 0 858 my ($self) = @_;
103              
104 1         7 Call::Context::must_be_list();
105              
106             return map {
107 2         6 [ map { $self->{'_challenges'}[$_] } @$_ ]
  2         11  
108 1         15 } @{ $self->{'_combinations'} };
  1         4  
109             }
110              
111             sub _handle_non_202_poll {
112 3     3   9 my ( $self, $resp ) = @_;
113              
114 3 100       58 $resp->die_because_unexpected() if $resp->status() != 200;
115              
116 2         17 my $payload = $resp->content_struct();
117              
118 2         38 my @challenge_objs;
119              
120 2         4 for my $c ( @{ $payload->{'challenges'} } ) {
  2         8  
121              
122             #We only care here about challenges that have been resolved.
123 2 50       11 next if $c->{'status'} eq 'pending';
124              
125 2         4 my $err = $c->{'error'};
126 2   66     19 $err &&= Net::ACME::Error->new(%$err);
127              
128             push @challenge_objs, Net::ACME::Challenge->new(
129 2         16 status => $c->{'status'},
130             error => $err,
131             );
132             }
133              
134             return Net::ACME::Authorization->new(
135 2         15 status => $payload->{'status'},
136             challenges => \@challenge_objs,
137             );
138             }
139              
140             1;