File Coverage

blib/lib/Net/ACME/Error.pm
Criterion Covered Total %
statement 28 28 100.0
branch 6 6 100.0
condition 3 5 60.0
subroutine 8 8 100.0
pod 0 3 0.0
total 45 50 90.0


line stmt bran cond sub pod time code
1             package Net::ACME::Error;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Net::ACME::Error - error parsing logic for ACME
8              
9             =head1 SYNOPSIS
10              
11             use Net::ACME::Error;
12              
13             my $err = Net::ACME::Error->new( { type => '..', .. } );
14              
15             =head1 DESCRIPTION
16              
17             This simple module interfaces with ACME “error” objects,
18             which are described in section 5.5 of the protocol spec.
19             (cf. L)
20              
21             =head1 NOTES
22              
23             ACME’s errors are basically just HTTP API problem detail documents,
24             which are described in more detail at L.
25              
26             =cut
27              
28 8     8   218540 use strict;
  8         27  
  8         236  
29 8     8   38 use warnings;
  8         15  
  8         231  
30              
31 8     8   38 use parent qw( Net::ACME::AccessorBase );
  8         15  
  8         55  
32              
33             #require.pm fails weirdly here.
34             our ( %TYPE_DESCRIPTION );
35              
36 8         881 use constant _ACCESSORS => qw(
37             detail
38             instance
39             status
40             title
41             type
42 8     8   597 );
  8         19  
43              
44             BEGIN {
45              
46             #cf. https://ietf-wg-acme.github.io/acme/#errors
47 8     8   2205 %TYPE_DESCRIPTION = (
48             badCSR => 'The CSR is unacceptable (e.g., due to a short key)',
49             badNonce => 'The client sent an unacceptable anti-replay nonce',
50             connection => 'The server could not connect to the client for validation',
51             dnssec => 'The server could not validate a DNSSEC signed domain',
52             caa => 'CAA records forbid the CA from issuing',
53             malformed => 'The request message was malformed',
54             serverInternal => 'The server experienced an internal error',
55             tls => 'The server experienced a TLS error during validation',
56             unauthorized => 'The client lacks sufficient authorization',
57             unknownHost => 'The server could not resolve a domain name',
58             rateLimited => 'The request exceeds a rate limit',
59             invalidContact => 'The provided contact URI for a registration was invalid',
60             rejectedIdentifier => 'The server will not issue for the identifier',
61             unsupportedIdentifier => 'Identifier is not supported, but may be in the future',
62             agreementRequired => 'The client must agree to terms before proceeding',
63             );
64             }
65              
66             sub type {
67 17     17 0 7056 my ($self) = @_;
68              
69 17   50     89 return $self->SUPER::type() || 'about:blank';
70             }
71              
72             sub description {
73 8     8 0 86 my ($self) = @_;
74              
75 8         25 my $type = $self->type();
76              
77             #The spec describes errors in the “urn:ietf:params:acme:error:”
78             #namespace; however, Boulder/LE gives them in “urn:acme:error:”.
79             #
80             #This is because Boulder implements an older version of the spec:
81             #https://github.com/letsencrypt/boulder/issues/1769
82 8 100       30 if ( !( $type =~ s<\Aurn:ietf:params:acme:error:><> ) ) {
83 4         9 $type =~ s<\Aurn:acme:error:><>;
84             }
85              
86 8         31 return $TYPE_DESCRIPTION{$type};
87             }
88              
89             #This might warrant expansion?
90             sub to_string {
91 3     3 0 173 my ($self) = @_;
92              
93 3         5 my $type = $self->type();
94 3 100       6 if ( my $desc = $self->description() ) {
95 2         9 $type = sprintf "%s (%s)", $desc, $type;
96             }
97              
98 3         9 my $detail = $self->detail();
99 3 100 66     15 if ( defined $detail && length $detail ) {
100 2         16 return sprintf "%s (%s)", $self->detail(), $type;
101             }
102              
103 1         3 return $type;
104             }
105              
106             1;