]> git.proxmox.com Git - proxmox-acme.git/blob - src/PVE/ACME/StandAlone.pm
f48d6383b98065b3794f555eb570373e858b3020
[proxmox-acme.git] / src / PVE / ACME / StandAlone.pm
1 package PVE::ACME::StandAlone;
2
3 use strict;
4 use warnings;
5
6 use HTTP::Daemon;
7 use HTTP::Response;
8
9 use base qw(PVE::ACME::Challenge);
10
11 sub supported_challenge_types {
12 return { 'http-01' => 1 };
13 }
14
15 sub setup {
16 my ($class, $acme, $authorization) = @_;
17
18 my $challenges = $authorization->{challenges};
19 die "no challenges defined in authorization\n" if !$challenges;
20
21 my $http_challenges = [ grep {$_->{type} eq 'http-01'} @$challenges ];
22 die "no http-01 challenge defined in authorization\n"
23 if ! scalar $http_challenges;
24
25 my $http_challenge = $http_challenges->[0];
26
27 die "no token found in http-01 challenge\n" if !$http_challenge->{token};
28
29 my $key_authorization = $acme->key_authorization($http_challenge->{token});
30
31 my $server = HTTP::Daemon->new(
32 LocalPort => 80,
33 ReuseAddr => 1,
34 ) or die "Failed to initialize HTTP daemon\n";
35 my $pid = fork() // die "Failed to fork HTTP daemon - $!\n";
36 if ($pid) {
37 my $self = {
38 server => $server,
39 pid => $pid,
40 authorization => $authorization,
41 key_auth => $key_authorization,
42 url => $http_challenge->{url},
43 };
44
45 return bless $self, $class;
46 } else {
47 while (my $c = $server->accept()) {
48 while (my $r = $c->get_request()) {
49 if ($r->method() eq 'GET' and $r->uri->path eq "/.well-known/acme-challenge/$http_challenge->{token}") {
50 my $resp = HTTP::Response->new(200, 'OK', undef, $key_authorization);
51 $resp->request($r);
52 $c->send_response($resp);
53 } else {
54 $c->send_error(404, 'Not found.')
55 }
56 }
57 $c->close();
58 $c = undef;
59 }
60 }
61 }
62
63 sub teardown {
64 my ($self) = @_;
65
66 eval { $self->{server}->close() };
67 kill('KILL', $self->{pid});
68 waitpid($self->{pid}, 0);
69 }
70
71 1;