Refactor challenge solving so it can run in parallel

This commit is contained in:
Niklas Keller
2016-03-20 15:26:04 +01:00
parent 82578e4370
commit b1d24afad2

View File

@@ -2,11 +2,13 @@
namespace Kelunik\AcmeClient\Commands; namespace Kelunik\AcmeClient\Commands;
use Amp\CombinatorException;
use Amp\Dns\Record; use Amp\Dns\Record;
use Exception; use Exception;
use Kelunik\Acme\AcmeClient; use Kelunik\Acme\AcmeClient;
use Kelunik\Acme\AcmeException; use Kelunik\Acme\AcmeException;
use Kelunik\Acme\AcmeService; use Kelunik\Acme\AcmeService;
use Kelunik\Acme\KeyPair;
use Kelunik\Acme\OpenSSLKeyGenerator; use Kelunik\Acme\OpenSSLKeyGenerator;
use Kelunik\AcmeClient\Stores\CertificateStore; use Kelunik\AcmeClient\Stores\CertificateStore;
use Kelunik\AcmeClient\Stores\ChallengeStore; use Kelunik\AcmeClient\Stores\ChallengeStore;
@@ -77,7 +79,45 @@ class Issue implements Command {
$acme = new AcmeService(new AcmeClient($server, $keyPair)); $acme = new AcmeService(new AcmeClient($server, $keyPair));
$promises = [];
foreach ($domains as $i => $domain) { foreach ($domains as $i => $domain) {
$promises[] = \Amp\resolve($this->solveChallenge($acme, $keyPair, $domain, $docRoots[$i]));
}
list($errors) = (yield \Amp\any($promises));
if (!empty($errors)) {
foreach ($errors as $error) {
$this->logger->error($error->getMessage());
}
throw new AcmeException("Issuance failed, not all challenges could be solved.");
}
$path = "certs/" . $keyFile . "/" . reset($domains) . "/key.pem";
$bits = $args->get("bits");
try {
$keyPair = (yield $keyStore->get($path));
} catch (KeyStoreException $e) {
$keyPair = (new OpenSSLKeyGenerator)->generate($bits);
$keyPair = (yield $keyStore->put($path, $keyPair));
}
$this->logger->info("Requesting certificate ...");
$location = (yield $acme->requestCertificate($keyPair, $domains));
$certificates = (yield $acme->pollForCertificate($location));
$path = dirname(dirname(__DIR__)) . "/data/certs/" . $keyFile;
$certificateStore = new CertificateStore($path);
yield $certificateStore->put($certificates);
$this->logger->info("Successfully issued certificate, see {$path}/" . reset($domains));
}
private function solveChallenge(AcmeService $acme, KeyPair $keyPair, $domain, $path) {
list($location, $challenges) = (yield $acme->requestChallenges($domain)); list($location, $challenges) = (yield $acme->requestChallenges($domain));
$goodChallenges = $this->findSuitableCombination($challenges); $goodChallenges = $this->findSuitableCombination($challenges);
@@ -98,7 +138,7 @@ class Issue implements Command {
$this->logger->info("Providing payload at http://{$domain}/.well-known/acme-challenge/{$token}"); $this->logger->info("Providing payload at http://{$domain}/.well-known/acme-challenge/{$token}");
$challengeStore = new ChallengeStore($docRoots[$i]); $challengeStore = new ChallengeStore($path);
try { try {
$challengeStore->put($token, $payload, isset($user) ? $user : null); $challengeStore->put($token, $payload, isset($user) ? $user : null);
@@ -124,28 +164,6 @@ class Issue implements Command {
} }
} }
$path = "certs/" . $keyFile . "/" . reset($domains) . "/key.pem";
$bits = $args->get("bits");
try {
$keyPair = (yield $keyStore->get($path));
} catch (KeyStoreException $e) {
$keyPair = (new OpenSSLKeyGenerator)->generate($bits);
$keyPair = (yield $keyStore->put($path, $keyPair));
}
$this->logger->info("Requesting certificate ...");
$location = (yield $acme->requestCertificate($keyPair, $domains));
$certificates = (yield $acme->pollForCertificate($location));
$path = dirname(dirname(__DIR__)) . "/data/certs/" . $keyFile;
$certificateStore = new CertificateStore($path);
yield $certificateStore->put($certificates);
$this->logger->info("Successfully issued certificate, see {$path}/" . reset($domains));
}
private function checkDnsRecords($domains) { private function checkDnsRecords($domains) {
$promises = []; $promises = [];