Polls until a challenge has been validated.
public pollForChallenge ( string $location ) : Amp\Promise | ||
$location | string | URI of the challenge |
리턴 | Amp\Promise | resolves to null |
/** * @param AcmeService $acme * @param KeyPair $keyPair * @param $domain * @return \Generator * @throws AcmeException * @throws \Exception * @throws \Throwable */ private function solveChallenge(AcmeService $acme, KeyPair $keyPair, $domain) { list($location, $challenges) = (yield $acme->requestChallenges($domain)); $goodChallenges = $this->findSuitableCombination($challenges); if (empty($goodChallenges)) { throw new AcmeException("Couldn't find any combination of challenges which this client can solve!"); } $challenge = $challenges->challenges[reset($goodChallenges)]; $token = $challenge->token; if (!preg_match("#^[a-zA-Z0-9-_]+\$#", $token)) { throw new AcmeException("Protocol violation: Invalid Token!"); } $payload = $acme->generateHttp01Payload($keyPair, $token); $challengeStore = $this->getChallengeStorage(); try { $challengeStore->put($token, $payload); (yield $acme->verifyHttp01Challenge($domain, $token, $payload)); (yield $acme->answerChallenge($challenge->uri, $payload)); (yield $acme->pollForChallenge($location)); $challengeStore->delete($token); } catch (\Exception $e) { // no finally because generators... $challengeStore->delete($token); throw $e; } catch (\Throwable $e) { // no finally because generators... $challengeStore->delete($token); throw $e; } }
private function doExecute(Manager $args) : Generator { if (posix_geteuid() !== 0) { throw new AcmeException("Please run this script as root!"); } $user = $args->get("user") ?? "www-data"; $server = $args->get("server"); $protocol = substr($server, 0, strpos("://", $server)); if (!$protocol || $protocol === $server) { $server = "https://" . $server; } elseif ($protocol !== "https") { throw new \InvalidArgumentException("Invalid server protocol, only HTTPS supported"); } $domains = $args->get("domains"); $domains = array_map("trim", explode(",", $domains)); yield from $this->checkDnsRecords($domains); $keyPair = $this->checkRegistration($args); $acme = new AcmeService(new AcmeClient($server, $keyPair), $keyPair); foreach ($domains as $domain) { list($location, $challenges) = (yield $acme->requestChallenges($domain)); $goodChallenges = $this->findSuitableCombination($challenges); if (empty($goodChallenges)) { throw new AcmeException("Couldn't find any combination of challenges which this server can solve!"); } $challenge = $challenges->challenges[reset($goodChallenges)]; $token = $challenge->token; if (!preg_match("#^[a-zA-Z0-9-_]+\$#", $token)) { throw new AcmeException("Protocol Violation: Invalid Token!"); } $this->logger->debug("Generating payload..."); $payload = $acme->generateHttp01Payload($token); $docRoot = rtrim($args->get("path") ?? __DIR__ . "/../../data/public", "/\\"); $path = $docRoot . "/.well-known/acme-challenge"; try { if (!file_exists($docRoot)) { throw new AcmeException("Document root doesn't exist: " . $docRoot); } if (!file_exists($path) && !@mkdir($path, 0770, true)) { throw new AcmeException("Couldn't create public dir to serve the challenges: " . $path); } if (!($userInfo = posix_getpwnam($user))) { throw new AcmeException("Unknown user: "******"/.well-known", $userInfo["uid"]); chown($docRoot . "/.well-known/acme-challenge", $userInfo["uid"]); $this->logger->info("Providing payload for {$domain} at {$path}/{$token}"); file_put_contents("{$path}/{$token}", $payload); chown("{$path}/{$token}", $userInfo["uid"]); chmod("{$path}/{$token}", 0660); (yield $acme->selfVerify($domain, $token, $payload)); $this->logger->info("Successfully self-verified challenge."); (yield $acme->answerChallenge($challenge->uri, $payload)); $this->logger->info("Answered challenge... waiting"); (yield $acme->pollForChallenge($location)); $this->logger->info("Challenge successful. {$domain} is now authorized."); @unlink("{$path}/{$token}"); } catch (Throwable $e) { // no finally because generators... @unlink("{$path}/{$token}"); throw $e; } } $path = __DIR__ . "/../../data/live/" . reset($domains); if (!file_exists($path) && !mkdir($path, 0700, true)) { throw new AcmeException("Couldn't create directory: {$path}"); } if (file_exists($path . "/private.pem") && file_exists($path . "/public.pem")) { $private = file_get_contents($path . "/private.pem"); $public = file_get_contents($path . "/public.pem"); $this->logger->info("Using existing domain key found at {$path}"); $domainKeys = new KeyPair($private, $public); } else { $domainKeys = (new OpenSSLKeyGenerator())->generate(2048); file_put_contents($path . "/private.pem", $domainKeys->getPrivate()); file_put_contents($path . "/public.pem", $domainKeys->getPublic()); $this->logger->info("Saved new domain key at {$path}"); chmod($path . "/private.pem", 0600); chmod($path . "/public.pem", 0600); } $this->logger->info("Requesting certificate ..."); $location = (yield $acme->requestCertificate($domainKeys, $domains)); $certificates = (yield $acme->pollForCertificate($location)); $this->logger->info("Saving certificate ..."); file_put_contents($path . "/cert.pem", reset($certificates)); file_put_contents($path . "/fullchain.pem", implode("\n", $certificates)); array_shift($certificates); file_put_contents($path . "/chain.pem", implode("\n", $certificates)); $this->logger->info("Successfully issued certificate."); }
private function solveChallenge(AcmeService $acme, KeyPair $keyPair, $domain, $path) { list($location, $challenges) = (yield $acme->requestChallenges($domain)); $goodChallenges = $this->findSuitableCombination($challenges); if (empty($goodChallenges)) { throw new AcmeException("Couldn't find any combination of challenges which this client can solve!"); } $challenge = $challenges->challenges[reset($goodChallenges)]; $token = $challenge->token; if (!preg_match("#^[a-zA-Z0-9-_]+\$#", $token)) { throw new AcmeException("Protocol violation: Invalid Token!"); } $payload = $acme->generateHttp01Payload($keyPair, $token); $this->climate->whisper(" Providing payload at http://{$domain}/.well-known/acme-challenge/{$token}"); $challengeStore = new ChallengeStore($path); try { (yield $challengeStore->put($token, $payload, isset($user) ? $user : null)); (yield $acme->verifyHttp01Challenge($domain, $token, $payload)); (yield $acme->answerChallenge($challenge->uri, $payload)); (yield $acme->pollForChallenge($location)); $this->climate->comment(" {$domain} is now authorized."); (yield $challengeStore->delete($token)); } catch (Exception $e) { // no finally because generators... (yield $challengeStore->delete($token)); throw $e; } catch (Throwable $e) { // no finally because generators... (yield $challengeStore->delete($token)); throw $e; } }