File Coverage

blib/lib/Net/ACME/Challenge/Pending/http_01/Handler.pm
Criterion Covered Total %
statement 52 57 91.2
branch 3 6 50.0
condition 2 6 33.3
subroutine 10 12 83.3
pod 0 3 0.0
total 67 84 79.7


line stmt bran cond sub pod time code
1             package Net::ACME::Challenge::Pending::http_01::Handler;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Net::ACME::Challenge::Pending::http_01::Handler - http-01 challenge handler
8              
9             =head1 DESCRIPTION
10              
11             This module handles the creation and removal of a domain control file for
12             http-01 challenges. Creation happens on instantiation; removal happens
13             when the object is destroyed.
14              
15             See C’s documentation for more
16             information, including a usage example.
17              
18             To handle challenges that have been unhandled (successfully or not),
19             see C.
20              
21             =cut
22              
23 10     10   66 use strict;
  10         23  
  10         310  
24 10     10   48 use warnings;
  10         19  
  10         268  
25              
26 10     10   863 use autodie;
  10         13314  
  10         103  
27              
28 10     10   67312 use Errno ();
  10         34  
  10         188  
29 10     10   56 use File::Spec ();
  10         22  
  10         206  
30              
31 10     10   1507 use Net::ACME::Constants ();
  10         24  
  10         6546  
32              
33             #docroot, token, key_authz
34             sub new {
35 3     3 0 24 my ( $class, %opts ) = @_;
36              
37 3         15 my $docroot_relative_path = "$Net::ACME::Constants::HTTP_01_CHALLENGE_DCV_DIR_IN_DOCROOT/$opts{'token'}";
38              
39 3         13 my $file_path = "$opts{'docroot'}/$docroot_relative_path";
40              
41 3         18 _mkdir_if_not_exists("$opts{'docroot'}/$Net::ACME::Constants::HTTP_01_CHALLENGE_DCV_DIR_IN_DOCROOT");
42              
43 3         22 local ( $!, $^E );
44              
45 3         18 open my $wfh, '>', $file_path;
46 3         5863 chmod 0644, $file_path;
47 3         1038 syswrite $wfh, $opts{'key_authz'};
48 3         4364 close $wfh;
49              
50             my $self = {
51             _euid => $>,
52             _path => $file_path,
53             _docroot_relative_path => $docroot_relative_path,
54 3         2684 _content => $opts{'key_authz'},
55             };
56              
57 3         45 return bless $self, $class;
58             }
59              
60             sub expected_content {
61 0     0 0 0 my ($self) = @_;
62              
63 0         0 return $self->{'_content'};
64             }
65              
66             sub verification_path {
67 0     0 0 0 my ($self) = @_;
68              
69 0         0 return "/$self->{'_docroot_relative_path'}";
70             }
71              
72             sub DESTROY {
73 3     3   3078 my ($self) = @_;
74              
75 3 50       62 if ( $> != $self->{'_euid'} ) {
76 0         0 die "XXX attempt to delete “$self->{'_path'}” with EUID $>; created with EUID $self->{'_euid'}!";
77             }
78              
79 3         18 _unlink_if_exists( $self->{'_path'} );
80              
81 3         18 return;
82             }
83              
84             sub _mkdir_if_not_exists {
85 3     3   10 my ($path) = @_;
86              
87             #cf. eval_bug.readme
88 3         7 my $eval_err = $@;
89              
90 3         68 local ( $!, $^E );
91              
92 3         43 my @ppath = File::Spec->splitdir($path);
93 3         8 pop @ppath;
94 3         37 my $ppath_str = File::Spec->catdir(@ppath);
95              
96 3         12 for my $p ($ppath_str, $path) {
97 6         15 eval { mkdir $p };
  6         30  
98 6 50 33     6544 die if $@ && $@->errno() != Errno::EEXIST();
99             }
100              
101 3         9 $@ = $eval_err;
102              
103 3         22 return;
104             }
105              
106             sub _unlink_if_exists {
107 3     3   59 my ($path) = @_;
108              
109 3         6 local $@;
110 3         16 local ( $!, $^E );
111 3         7 eval { unlink $path };
  3         23  
112 3 50 33     1158 die if $@ && $@->errno() != Errno::ENOENT();
113              
114 3         17 return;
115             }
116              
117             1;