]> git.proxmox.com Git - proxmox-acme.git/blob - src/PVE/ACME/StandAlone.pm
0b4aaae0cd9618077a882bb7562d7bcf88e0e909
[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 type {
16 return 'standalone';
17 }
18
19 sub properties {
20 return {};
21 }
22
23 sub options {
24 return {
25 nodes => { optional => 1 },
26 disable => { optional => 1 },
27 };
28 }
29
30 sub extract_challenge {
31 my ($self, $challenge) = @_;
32
33 return PVE::ACME::Challenge->extract_challenge($challenge, 'http-01');
34 }
35
36 sub setup {
37 my ($class, $acme, $authorization) = @_;
38
39 my $challenges = $authorization->{challenges};
40 die "no challenges defined in authorization\n" if !$challenges;
41
42 my $http_challenges = [ grep {$_->{type} eq 'http-01'} @$challenges ];
43 die "no http-01 challenge defined in authorization\n"
44 if ! scalar $http_challenges;
45
46 my $http_challenge = $http_challenges->[0];
47
48 die "no token found in http-01 challenge\n" if !$http_challenge->{token};
49
50 my $key_authorization = $acme->key_authorization($http_challenge->{token});
51
52 my $server = HTTP::Daemon->new(
53 LocalPort => 80,
54 ReuseAddr => 1,
55 ) or die "Failed to initialize HTTP daemon\n";
56 my $pid = fork() // die "Failed to fork HTTP daemon - $!\n";
57 if ($pid) {
58 my $self = {
59 server => $server,
60 pid => $pid,
61 authorization => $authorization,
62 key_auth => $key_authorization,
63 url => $http_challenge->{url},
64 };
65
66 return bless $self, $class;
67 } else {
68 while (my $c = $server->accept()) {
69 while (my $r = $c->get_request()) {
70 if ($r->method() eq 'GET' and $r->uri->path eq "/.well-known/acme-challenge/$http_challenge->{token}") {
71 my $resp = HTTP::Response->new(200, 'OK', undef, $key_authorization);
72 $resp->request($r);
73 $c->send_response($resp);
74 } else {
75 $c->send_error(404, 'Not found.')
76 }
77 }
78 $c->close();
79 $c = undef;
80 }
81 }
82 }
83
84 sub teardown {
85 my ($self) = @_;
86
87 eval { $self->{server}->close() };
88 kill('KILL', $self->{pid});
89 waitpid($self->{pid}, 0);
90 }
91
92 1;