fix #1819: fork_worker: ensure sync'ed workers control terminal
[pve-common.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;