—package
Net::ACME::Authorization::Pending;
=encoding utf-8
=head1 NAME
Net::ACME::Authorization::Pending - pending ACME authorization
=head1 SYNOPSIS
use Net::ACME::Authorization::Pending ();
my $authz_p = Net::ACME::Authorization::Pending->new(
uri => 'http://url/to/poll/for/authz',
challenges => \@challenge_objects,
combinations => [
[ 2 ],
[ 1 ],
[ 0 ],
],
);
for my $cmb ( $authz_p->combinations() ) {
#An example of only doing “http-01”:
next if @$cmb > 1;
next if $cmb->[0]->type() ne 'http-01';
#Prepare for the challenge …
#Assume we instantiated Net::ACME above …
$acme->do_challenge($cmb->[0]);
while (1) {
if ($authz_p->is_time_to_poll()) {
my $poll = $authz_p->poll();
last if $poll->status() eq 'valid';
if ($poll->status() eq 'invalid') {
my $completed_challenge = ($poll->challenges())[0];
print $completed_challenge->error()->detail() . $/;
die "Failed authorization!$/";
}
}
sleep 1;
}
last;
}
=cut
#NOTE: For now, this assumes a domain name.
#Might be useful moving forward to separate out other types
#of authz as per ACME spec expansion. (As of April 2016 only
#domain names are handled.)
use
strict;
use
warnings;
use
Call::Context ();
use
Net::ACME::Authorization ();
use
Net::ACME::Challenge ();
use
Net::ACME::Error ();
use
Net::ACME::X ();
my
$PENDING_CLASS
=
'Net::ACME::Challenge::Pending'
;
sub
new {
my
(
$class
,
%opts
) =
@_
;
my
$self
= {
_uri
=>
$opts
{
'uri'
} ||
die
(
'Need “uri”!'
),
_challenges
=>
$opts
{
'challenges'
},
_combinations
=>
$opts
{
'combinations'
},
};
if
( !@{
$opts
{
'challenges'
} } ) {
die
Net::ACME::X::create(
'Empty'
, {
name
=>
'challenges'
} );
}
for
my
$c
( 0 .. $
#{ $opts{'challenges'} } ) {
my
$challenge
=
$opts
{
'challenges'
}[
$c
];
if
( !
$challenge
->isa(
$PENDING_CLASS
) ) {
die
"Challenge $c ($challenge) is not an instance of “$PENDING_CLASS”!"
;
}
}
bless
$self
,
$class
;
return
$self
;
}
sub
combinations {
my
(
$self
) =
@_
;
Call::Context::must_be_list();
return
map
{
[
map
{
$self
->{
'_challenges'
}[
$_
] }
@$_
]
} @{
$self
->{
'_combinations'
} };
}
sub
_handle_non_202_poll {
my
(
$self
,
$resp
) =
@_
;
$resp
->die_because_unexpected()
if
$resp
->status() != 200;
my
$payload
=
$resp
->content_struct();
my
@challenge_objs
;
for
my
$c
( @{
$payload
->{
'challenges'
} } ) {
#We only care here about challenges that have been resolved.
next
if
$c
->{
'status'
} eq
'pending'
;
my
$err
=
$c
->{
'error'
};
$err
&&= Net::ACME::Error->new(
%$err
);
push
@challenge_objs
, Net::ACME::Challenge->new(
status
=>
$c
->{
'status'
},
error
=>
$err
,
);
}
return
Net::ACME::Authorization->new(
status
=>
$payload
->{
'status'
},
challenges
=> \
@challenge_objs
,
);
}
1;