Mojolicious-Plugin-ACME-Command-acme-automate
view release on metacpan or search on metacpan
lib/Mojolicious/Plugin/ACME/Command/acme/automate.pm view on Meta::CPAN
'T|template=s' => \(my $template = 'nginx_default'),
'o|options=s' => \%options;
$name ||= $self->app->moniker;
$name .= 'test' if $test;
die 'an ssl directory name is required' unless my $ssldir = $self->app->config('ssldir');
my $host = $args[0] or die "no canonical host";
my $account = path($ssldir)->child("$name-account-$host.key")->to_string;
$name = path($ssldir)->child("$name-cert-$host")->to_string;
$self->app->log->info("generating $host certificate signed by the ACME service");
push @args, '-a', $account, ($test?'-t':());
my $acme = $self->build_acme(\@args);
sleep 3;
# Register account
unless ( -f $account ) {
my $response = eval { $acme->register };
print $@ if $@;
die "Account not registered" unless $response;
say $response;
my $key = $acme->account_key;
if ($key->generated) {
my $key_path = $key->path;
$self->app->log->info("Writing $key_path");
Mojo::File->new($key_path)->spurt($key->string);
}
sleep 3;
}
# Generate certificate
$acme->server_url($self->app->config('acme')->{challenge_url});
my $intermediate;
if ($full) {
my $msg = "No certificate generation was attempted. Use --no-full to proceed without it.\n";
$int_url ||= eval { $acme->ca->intermediate };
die "Intermediate certificate not specified. $msg"
unless $int_url;
my $tx = $acme->ua->get($int_url);
die "Failed to fetch intermediate cert. $msg"
unless $tx->result;
die "Intermediate cert was empty. $msg"
unless $intermediate = $tx->res->body;
}
$acme->new_authz($_) for @args;
my $cert;
Mojo::IOLoop->delay(
sub { $acme->check_all_challenges(shift->begin) },
sub {
my ($delay, $err) = @_;
die Mojo::Util::dumper($err) if $err;
my $bad = c(values %{ $acme->challenges })->grep(sub { $_->{status} ne 'valid' });
die 'The following challenges were not validated ' . Mojo::Util::dumper($bad->to_array) if $bad->size;
#TODO poll for cert when delayed
$cert = $acme->get_cert(@args);
},
)->catch(sub{ warn "$_[-1]\n" })->wait;
die "No cert was generated for $host" unless $cert;
my $key_path = "$name.key";
if ($acme->cert_key->generated) {
$self->app->log->info("Writing $key_path");
Mojo::File->new($key_path)->spurt($acme->cert_key->string);
}
if ($intermediate) {
$cert = $cert . $intermediate;
}
my $cert_path = "$name.crt";
$self->app->log->info("Writing $cert_path");
Mojo::File->new($cert_path)->spurt($cert);
if ( my $webdir = $self->app->config('webdir') ) {
path($webdir)->child($host)->spurt(
Mojo::Template->new->vars(1)->render_file(
$self->app->home->child('templates', "$template.ep"),
{%options, hosts => \@args, cert => $cert_path, key => $key_path}
)
) if $template && !$acme->ca->test_mode; # TODO: unless go+w
}
}
1;
=encoding utf8
=head1 NAME
Mojolicious::Plugin::ACME::Command::acme::automate - Automate ACME registration and signed certificate generation
=head1 SYNOPSIS
Usage: APPLICATION acme automate [OPTIONS]
myapp acme automate
myapp acme automate -t -a myaccount.key -T template -l http://*:8928 -o proxy_pass=http://127.0.0.1:3000 domain1.com {domain2.com, ...}
Options:
--full, --no-full Automatically chain the resulting
certificate with the intermediate
defaults to true, use --no-full to
disable
-h, --help Show this summary of available options
-i, --intermediate The url of the intermediate cert to
be chained if "full" is passed
-l, --listen <location> One or more locations you want to
listen on, defaults to the value of
MOJO_LISTEN or "http://*:3000"
-n, --name The name of the file(s) to be
generated, defaults to the app's
moniker
( run in 1.848 second using v1.01-cache-2.11-cpan-e1769b4cff6 )