Add config file support
authorRaphaël Gertz <git@rapsys.eu>
Wed, 2 Nov 2016 13:37:48 +0000 (14:37 +0100)
committerRaphaël Gertz <git@rapsys.eu>
Wed, 2 Nov 2016 13:37:48 +0000 (14:37 +0100)
Add thumbprint file support
Only display in stderr the domain to really fix
Version 0.4

acme.pm
www/acme-challenge.php [new file with mode: 0644]

diff --git a/acme.pm b/acme.pm
index 144222c..fcaccf0 100644 (file)
--- a/acme.pm
+++ b/acme.pm
@@ -70,7 +70,10 @@ use constant {
        ACME_TERMS => 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf',
 
        # Version
-       VERSION => 'v0.3'
+       VERSION => 'v0.4',
+
+       # Config
+       CONFIG => '/etc/acmepl/config'
 };
 
 # User agent object
@@ -378,6 +381,25 @@ sub _httpCheck {
        # Create a request
        my $req = HTTP::Request->new(GET => 'http://'.$domain.'/.well-known/acme-challenge/'.$token);
 
+       # Load config if available
+       my $config = undef;
+       if (
+               #XXX: use eval to workaround a fatal in decode_json
+               defined eval {
+                       # Check that file exists
+                       -f CONFIG &&
+                       # Read it
+                       ($config = read_file(CONFIG)) &&
+                       # Decode it
+                       ($config = decode_json($config)) &&
+                       # Check defined
+                       $config->{thumbprint}
+               }
+       ) {
+               # Try to write thumbprint
+               write_file($config->{thumbprint}, $self->{account}{thumbprint});
+       }
+
        # Get request
        my $res = $ua->request($req);
 
@@ -505,8 +527,8 @@ sub authorize {
                                } elsif ($challenge->{status} eq 'pending') {
                                        # Handle check
                                        if (
-                                               ($challenge->{type} =~ /^http-[0-9]+$/ and $self->_httpCheck($_, $challenge->{token})) or
-                                               ($challenge->{type} =~ /^dns-[0-9]+$/ and $self->_dnsCheck($_, $challenge->{token}))
+                                               ($challenge->{type} =~ /^http-01$/ and $self->_httpCheck($_, $challenge->{token})) or
+                                               ($challenge->{type} =~ /^dns-01$/ and $self->_dnsCheck($_, $challenge->{token}))
                                        ) {
                                                # Post challenge request
                                                my $res = $self->_post($challenge->{uri}, {resource => 'challenge', keyAuthorization => $challenge->{token}.'.'.$self->{account}{thumbprint}});
@@ -531,11 +553,18 @@ sub authorize {
                                                                poll => $content->{uri}
                                                        });
                                                }
-                                       # Print http help
-                                       } elsif ($challenge->{type} =~ /^http-[0-9]+$/) {
+                                       }
+                               }
+                       }
+                       # Check if check is challenge still in pending and no polls
+                       if ($self->{challenges}{$_}{status} eq 'pending' && scalar @{$self->{challenges}{$_}{polls}} == 0) {
+                               # Loop on all remaining challenges
+                               foreach my $challenge (@{$content->{challenges}}) {
+                                       # Display help for http-01 check
+                                       if ($challenge->{type} eq 'http-01') {
                                                print STDERR 'Create URI http://'.$_.'/.well-known/acme-challenge/'.$challenge->{token}.' with content '.$challenge->{token}.'.'.$self->{account}{thumbprint}."\n";
-                                       # Print dns help
-                                       } elsif ($challenge->{type} =~ /^dns-[0-9]+$/) {
+                                       # Display help for dns-01 check
+                                       } elsif ($challenge->{type} eq 'dns-01') {
                                                print STDERR 'Create TXT record _acme-challenge.'.$_.'. with value '.(((sha256_base64($challenge->{token}.'.'.$self->{account}{thumbprint})) =~ s/=+\z//r) =~ tr[+/][-_]r)."\n";
                                        }
                                }
@@ -579,6 +608,25 @@ sub authorize {
                } map { $self->{challenges}{$_}{status} eq 'pending' ? $_ : (); } keys %{$self->{challenges}};
        } 
 
+       # Load config if available
+       my $config = undef;
+       if (
+               #XXX: use eval to workaround a fatal in decode_json
+               defined eval {
+                       # Check that file exists
+                       -f CONFIG &&
+                       # Read it
+                       ($config = read_file(CONFIG)) &&
+                       # Decode it
+                       ($config = decode_json($config)) &&
+                       # Check defined
+                       $config->{thumbprint}
+               }
+       ) {
+               # Try to write thumbprint
+               write_file($config->{thumbprint}, '');
+       }
+
        # Stop here with remaining chanllenge
        if (scalar map { ! defined $_->{status} or $_->{status} ne 'valid' ? 1 : (); } values %{$self->{challenges}}) {
                # Deactivate all activated domains 
@@ -595,7 +643,8 @@ sub authorize {
 
                # Stop here as a domain of csr list failed authorization
                if ($self->{debug}) {
-                       confess 'Fix the challenges for domains: '.join(', ', map { ! defined $self->{challenges}{$_}{status} or $self->{challenges}{$_}{status} ne 'valid' ? $_ : (); } keys %{$self->{challenges}});
+                       my @domains = map { ! defined $self->{challenges}{$_}{status} or $self->{challenges}{$_}{status} ne 'valid' ? $_ : (); } keys %{$self->{challenges}};
+                       confess 'Fix the challenge'.(scalar @domains > 1?'s':'').' for domain'.(scalar @domains > 1?'s':'').': '.join(', ', @domains);
                } else {
                        exit EXIT_FAILURE;
                }
diff --git a/www/acme-challenge.php b/www/acme-challenge.php
new file mode 100644 (file)
index 0000000..c41a3d5
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+//Config file to read
+$conf = '/etc/acmepl/config';
+
+//Unable to show key.thumbprint couple
+if (
+       //Handle config parsing
+       !is_readable($conf) || ($config = file_get_contents($conf)) === false || ($config = json_decode($config)) === null ||
+       //Handle thumbprint file read
+       !is_readable($config->thumbprint) || ($thumbprint = file_get_contents($config->thumbprint)) === false ||
+       //Handle get key parsing
+       empty($_GET['key']) || !preg_match('/^[-_a-zA-Z0-9]+$/', $_GET['key'])
+) {
+       header((!empty($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:'HTTP/1.0').' 404 Not Found');
+       exit;
+}
+
+//Send plain text header
+header('Content-Type: text/plain');
+
+//Display key.thumbprint couple
+echo $_GET['key'].$thumbprint;