From 5a4ab4a410acfb57f6c982bf15f25bf07e264cbc Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 20 Dec 2015 21:49:23 +0100 Subject: [PATCH] Make PHP 5.5 compat --- bin/acme | 7 ++-- src/Commands/Command.php | 5 ++- src/Commands/Issue.php | 59 +++++++++++++++--------------- src/Commands/Renew.php | 25 +++++-------- src/Commands/Revoke.php | 19 ++++------ src/Commands/Setup.php | 31 ++++++++-------- src/Configuration.php | 6 ++-- src/Stores/CertificateStore.php | 63 +++++++++++++++++---------------- src/Stores/ChallengeStore.php | 58 +++++++++++++++++++++++------- src/Stores/KeyStore.php | 55 +++++++++++++++++----------- src/functions.php | 2 +- 11 files changed, 182 insertions(+), 148 deletions(-) diff --git a/bin/acme b/bin/acme index 1f907ab..9662ea4 100755 --- a/bin/acme +++ b/bin/acme @@ -8,7 +8,6 @@ use League\CLImate\CLImate; use Monolog\Handler\StreamHandler; use Monolog\Logger; use Psr\Log\LoggerInterface; -use function Kelunik\AcmeClient\commandToClass; require __DIR__ . "/../vendor/autoload.php"; @@ -57,9 +56,7 @@ if (!in_array($argv[1], $commands)) { exit(1); } -// TODO: Implement subcommand help - -$class = commandToClass($argv[1]); +$class = \Kelunik\AcmeClient\commandToClass($argv[1]); $definition = $class::getDefinition(); try { @@ -91,7 +88,7 @@ $logger->pushHandler($handler); $injector->alias(LoggerInterface::class, Logger::class); $injector->share($logger); -$command = $injector->make(commandToClass($argv[1])); +$command = $injector->make($class); Amp\run(function () use ($command, $climate, $logger) { try { diff --git a/src/Commands/Command.php b/src/Commands/Command.php index b505344..c151ba9 100644 --- a/src/Commands/Command.php +++ b/src/Commands/Command.php @@ -2,11 +2,10 @@ namespace Kelunik\AcmeClient\Commands; -use Amp\Promise; use League\CLImate\Argument\Manager; interface Command { - public function execute(Manager $args): Promise; + public function execute(Manager $args); - public static function getDefinition(): array; + public static function getDefinition(); } \ No newline at end of file diff --git a/src/Commands/Issue.php b/src/Commands/Issue.php index 932a9e2..349516a 100644 --- a/src/Commands/Issue.php +++ b/src/Commands/Issue.php @@ -2,11 +2,8 @@ namespace Kelunik\AcmeClient\Commands; -use Amp\Dns as dns; use Amp\Dns\Record; -use function Amp\File\put; -use Amp\Promise; -use Generator; +use Exception; use Kelunik\Acme\AcmeClient; use Kelunik\Acme\AcmeException; use Kelunik\Acme\AcmeService; @@ -19,10 +16,6 @@ use League\CLImate\Argument\Manager; use Psr\Log\LoggerInterface; use stdClass; use Throwable; -use function Amp\all; -use function Amp\any; -use function Amp\resolve; -use function Kelunik\AcmeClient\getServer; class Issue implements Command { private $logger; @@ -31,23 +24,23 @@ class Issue implements Command { $this->logger = $logger; } - public function execute(Manager $args): Promise { - return resolve($this->doExecute($args)); + public function execute(Manager $args) { + return \Amp\resolve($this->doExecute($args)); } - private function doExecute(Manager $args): Generator { + private function doExecute(Manager $args) { $domains = array_map("trim", explode(",", $args->get("domains"))); - yield resolve($this->checkDnsRecords($domains)); + yield \Amp\resolve($this->checkDnsRecords($domains)); - $user = $args->get("user") ?? "www-data"; + $user = $args->get("user") ?: "www-data"; $keyStore = new KeyStore(dirname(dirname(__DIR__)) . "/data"); - $keyPair = yield $keyStore->get("account/key.pem"); - $acme = new AcmeService(new AcmeClient(getServer(), $keyPair), $keyPair); + $keyPair = (yield $keyStore->get("account/key.pem")); + $acme = new AcmeService(new AcmeClient(\Kelunik\AcmeClient\getServer(), $keyPair), $keyPair); foreach ($domains as $domain) { - list($location, $challenges) = yield $acme->requestChallenges($domain); + list($location, $challenges) = (yield $acme->requestChallenges($domain)); $goodChallenges = $this->findSuitableCombination($challenges); if (empty($goodChallenges)) { @@ -82,6 +75,10 @@ class Issue implements Command { $this->logger->info("Challenge successful. {$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); @@ -90,42 +87,42 @@ class Issue implements Command { } $path = "certs/" . reset($domains) . "/key.pem"; - $bits = $args->get("bits") ?? 2048; + $bits = $args->get("bits") ?: 2048; try { - $keyPair = yield $keyStore->get($path); + $keyPair = (yield $keyStore->get($path)); } catch (KeyStoreException $e) { $keyPair = (new OpenSSLKeyGenerator)->generate($bits); - $keyPair = yield $keyStore->put($path, $keyPair); + $keyPair = (yield $keyStore->put($path, $keyPair)); } $this->logger->info("Requesting certificate ..."); - $location = yield $acme->requestCertificate($keyPair, $domains); - $certificates = yield $acme->pollForCertificate($location); + $location = (yield $acme->requestCertificate($keyPair, $domains)); + $certificates = (yield $acme->pollForCertificate($location)); $path = dirname(dirname(__DIR__)) . "/data/certs"; $certificateStore = new CertificateStore($path); yield $certificateStore->put($certificates); - yield put($path . "/" . reset($domains) . "/config.json", json_encode([ - "domains" => $domains, "path" => $args->get("path"), "user" => $user, "bits" => $bits - ], JSON_PRETTY_PRINT) . "\n"); + yield \Amp\File\put($path . "/" . reset($domains) . "/config.json", json_encode([ + "domains" => $domains, "path" => $args->get("path"), "user" => $user, "bits" => $bits, + ], JSON_PRETTY_PRINT) . "\n"); $this->logger->info("Successfully issued certificate, see {$path}/" . reset($domains)); } - private function checkDnsRecords($domains): Generator { + private function checkDnsRecords($domains) { $promises = []; foreach ($domains as $domain) { - $promises[$domain] = dns\resolve($domain, [ + $promises[$domain] = \Amp\Dns\resolve($domain, [ "types" => [Record::A], "hosts" => false, ]); } - list($errors) = yield any($promises); + list($errors) = (yield \Amp\any($promises)); if (!empty($errors)) { throw new AcmeException("Couldn't resolve the following domains to an IPv4 record: " . implode(array_keys($errors))); @@ -134,9 +131,9 @@ class Issue implements Command { $this->logger->info("Checked DNS records, all fine."); } - private function findSuitableCombination(stdClass $response): array { - $challenges = $response->challenges ?? []; - $combinations = $response->combinations ?? []; + private function findSuitableCombination(stdClass $response) { + $challenges = isset($response->challenges) ? $response->challenges : []; + $combinations = isset($response->combinations) ? $response->combinations : []; $goodChallenges = []; foreach ($challenges as $i => $challenge) { @@ -154,7 +151,7 @@ class Issue implements Command { return $goodChallenges; } - public static function getDefinition(): array { + public static function getDefinition() { return [ "domains" => [ "prefix" => "d", diff --git a/src/Commands/Renew.php b/src/Commands/Renew.php index 4576fd8..c43e4c2 100644 --- a/src/Commands/Renew.php +++ b/src/Commands/Renew.php @@ -3,16 +3,9 @@ namespace Kelunik\AcmeClient\Commands; use Amp\Process; -use Amp\Promise; -use Generator; use Kelunik\Certificate\Certificate; use League\CLImate\Argument\Manager; use Psr\Log\LoggerInterface; -use function Amp\all; -use function Amp\File\get; -use function Amp\File\scandir; -use function Amp\pipe; -use function Amp\resolve; class Renew implements Command { private $logger; @@ -21,22 +14,22 @@ class Renew implements Command { $this->logger = $logger; } - public function execute(Manager $args): Promise { - return resolve($this->doExecute($args)); + public function execute(Manager $args) { + return \Amp\resolve($this->doExecute($args)); } - private function doExecute(Manager $args): Generator { + private function doExecute(Manager $args) { $path = dirname(dirname(__DIR__)) . "/data/certs"; if (!realpath($path)) { throw new \RuntimeException("Certificate path doesn't exist: '{$path}'"); } - $domains = yield scandir($path); + $domains = (yield \Amp\File\scandir($path)); $promises = []; foreach ($domains as $domain) { - $pem = yield get($path . "/" . $domain . "/cert.pem"); + $pem = (yield \Amp\File\get($path . "/" . $domain . "/cert.pem")); $cert = new Certificate($pem); if ($cert->getValidTo() > time() + 30 * 24 * 60 * 60) { @@ -45,7 +38,7 @@ class Renew implements Command { continue; } - $json = yield get($path . "/" . $domain . "/config.json"); + $json = (yield \Amp\File\get($path . "/" . $domain . "/config.json")); $config = json_decode($json); $command = [ @@ -63,7 +56,7 @@ class Renew implements Command { $command = array_map("escapeshellarg", $command); $command = implode(" ", $command); - $promises[] = pipe((new Process($command))->exec()->watch(function ($update) { + $promises[] = \Amp\pipe((new Process($command))->exec()->watch(function ($update) { list($type, $data) = $update; if ($type === "err") { @@ -78,7 +71,7 @@ class Renew implements Command { }); } - $results = yield all($promises); + $results = (yield \Amp\all($promises)); foreach ($results as $result) { if ($result->exit !== 0) { @@ -87,7 +80,7 @@ class Renew implements Command { } } - public static function getDefinition(): array { + public static function getDefinition() { return []; } } \ No newline at end of file diff --git a/src/Commands/Revoke.php b/src/Commands/Revoke.php index 5747718..7bdcc31 100644 --- a/src/Commands/Revoke.php +++ b/src/Commands/Revoke.php @@ -8,16 +8,11 @@ use Generator; use Kelunik\Acme\AcmeClient; use Kelunik\Acme\AcmeException; use Kelunik\Acme\AcmeService; -use Kelunik\Acme\KeyPair; -use function Kelunik\AcmeClient\getServer; use Kelunik\AcmeClient\Stores\CertificateStore; use Kelunik\AcmeClient\Stores\KeyStore; use Kelunik\Certificate\Certificate; use League\CLImate\Argument\Manager; use Psr\Log\LoggerInterface; -use function Amp\File\exists; -use function Amp\File\get; -use function Amp\resolve; class Revoke implements Command { private $logger; @@ -26,24 +21,24 @@ class Revoke implements Command { $this->logger = $logger; } - public function execute(Manager $args): Promise { - return resolve($this->doExecute($args)); + public function execute(Manager $args) { + return \Amp\resolve($this->doExecute($args)); } - private function doExecute(Manager $args): Generator { + private function doExecute(Manager $args) { if (posix_geteuid() !== 0) { throw new AcmeException("Please run this script as root!"); } $keyStore = new KeyStore(dirname(dirname(__DIR__)) . "/data"); - $keyPair = yield $keyStore->get("account/key.pem"); - $acme = new AcmeService(new AcmeClient(getServer(), $keyPair), $keyPair); + $keyPair = (yield $keyStore->get("account/key.pem")); + $acme = new AcmeService(new AcmeClient(\Kelunik\AcmeClient\getServer(), $keyPair), $keyPair); $this->logger->info("Revoking certificate ..."); try { - $pem = yield get(dirname(dirname(__DIR__)) . "/data/certs/" . $args->get("name") . "/cert.pem"); + $pem = (yield \Amp\File\get(dirname(dirname(__DIR__)) . "/data/certs/" . $args->get("name") . "/cert.pem")); $cert = new Certificate($pem); } catch (FilesystemException $e) { throw new \RuntimeException("There's no such certificate!"); @@ -60,7 +55,7 @@ class Revoke implements Command { yield (new CertificateStore(dirname(dirname(__DIR__)) . "/data/certs"))->delete($args->get("name")); } - public static function getDefinition(): array { + public static function getDefinition() { return [ "name" => [ "longPrefix" => "name", diff --git a/src/Commands/Setup.php b/src/Commands/Setup.php index d880dff..283c56f 100644 --- a/src/Commands/Setup.php +++ b/src/Commands/Setup.php @@ -6,6 +6,7 @@ use Amp\Dns\Record; use Amp\Dns\ResolutionException; use Amp\Promise; use Generator; +use InvalidArgumentException; use Kelunik\Acme\AcmeClient; use Kelunik\Acme\AcmeException; use Kelunik\Acme\AcmeService; @@ -16,10 +17,6 @@ use Kelunik\AcmeClient\Stores\KeyStoreException; use League\CLImate\Argument\Manager; use Psr\Log\LoggerInterface; use RuntimeException; -use function Amp\File\exists; -use function Amp\File\put; -use function Amp\resolve; -use function Kelunik\AcmeClient\serverToIdentity; class Setup implements Command { private $logger; @@ -28,13 +25,13 @@ class Setup implements Command { $this->logger = $logger; } - public function execute(Manager $args): Promise { - return resolve($this->doExecute($args)); + public function execute(Manager $args) { + return \Amp\resolve($this->doExecute($args)); } - public function doExecute(Manager $args): Generator { + public function doExecute(Manager $args) { $email = $args->get("email"); - yield resolve($this->checkEmail($email)); + yield \Amp\resolve($this->checkEmail($email)); $server = $args->get("server"); $protocol = substr($server, 0, strpos("://", $server)); @@ -52,7 +49,7 @@ class Setup implements Command { try { $this->logger->info("Loading private key ..."); - $keyPair = yield $keyStore->get($path); + $keyPair = (yield $keyStore->get($path)); $this->logger->info("Existing private key successfully loaded."); } catch (KeyStoreException $e) { $this->logger->info("No existing private key found, generating new one ..."); @@ -60,11 +57,11 @@ class Setup implements Command { $this->logger->info("Generated new private key with {$bits} bits."); $this->logger->info("Saving new private key ..."); - $keyPair = yield $keyStore->put($path, $keyPair); + $keyPair = (yield $keyStore->put($path, $keyPair)); $this->logger->info("New private key successfully saved."); } - $user = $args->get("user") ?? "www-data"; + $user = $args->get("user") ?: "www-data"; $userInfo = posix_getpwnam($user); if (!$userInfo) { @@ -75,17 +72,21 @@ class Setup implements Command { $this->logger->info("Registering with ACME server " . substr($server, 8) . " ..."); /** @var Registration $registration */ - $registration = yield $acme->register($email); + $registration = (yield $acme->register($email)); $this->logger->notice("Registration successful with the following contact information: " . implode(", ", $registration->getContact())); - yield put(dirname(dirname(__DIR__)) . "/data/account/config.json", json_encode([ + yield \Amp\File\put(dirname(dirname(__DIR__)) . "/data/account/config.json", json_encode([ "version" => 1, "server" => $server, "email" => $email, ], JSON_PRETTY_PRINT) . "\n"); } - private function checkEmail(string $email): Generator { + private function checkEmail($email) { + if (!is_string($email)) { + throw new InvalidArgumentException(sprintf("\$email must be of type string, %s given.", gettype($email))); + } + $host = substr($email, strrpos($email, "@") + 1); if (!$host) { @@ -99,7 +100,7 @@ class Setup implements Command { } } - public static function getDefinition(): array { + public static function getDefinition() { return [ "server" => [ "prefix" => "s", diff --git a/src/Configuration.php b/src/Configuration.php index 84f6154..9c4d075 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -7,7 +7,7 @@ use RuntimeException; class Configuration { private $config; - public function __construct(string $file) { + public function __construct($file) { $json = file_get_contents($file); if (!$json) { @@ -21,7 +21,7 @@ class Configuration { } } - public function get(string $key) { - return $this->config->{$key} ?? null; + public function get($key) { + return isset($this->config->{$key}) ? $this->config->{$key} : null; } } \ No newline at end of file diff --git a/src/Stores/CertificateStore.php b/src/Stores/CertificateStore.php index 82f77f0..607f717 100644 --- a/src/Stores/CertificateStore.php +++ b/src/Stores/CertificateStore.php @@ -3,30 +3,25 @@ namespace Kelunik\AcmeClient\Stores; use Amp\File\FilesystemException; -use Amp\Promise; -use Generator; use InvalidArgumentException; use Kelunik\Certificate\Certificate; -use function Amp\File\put; -use function Amp\File\chmod; -use function Amp\File\chown; -use function Amp\File\scandir; -use function Amp\File\unlink; -use function Amp\resolve; -use function Amp\File\rmdir; class CertificateStore { private $root; - public function __construct(string $root) { + public function __construct($root) { + if (!is_string($root)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($root))); + } + $this->root = rtrim(str_replace("\\", "/", $root), "/"); } - public function put(array $certificates): Promise { - return resolve($this->doPut($certificates)); + public function put(array $certificates) { + return \Amp\resolve($this->doPut($certificates)); } - private function doPut(array $certificates): Generator { + private function doPut(array $certificates) { if (empty($certificates)) { throw new InvalidArgumentException("Empty array not allowed"); } @@ -52,31 +47,39 @@ class CertificateStore { throw new FilesystemException("Couldn't create certificate directory: '{$path}'"); } - yield put($path . "/cert.pem", $certificates[0]); - yield chown($path . "/cert.pem", 0, 0); - yield chmod($path . "/cert.pem", 0640); + yield \Amp\File\put($path . "/cert.pem", $certificates[0]); + yield \Amp\File\chown($path . "/cert.pem", 0, 0); + yield \Amp\File\chmod($path . "/cert.pem", 0640); - yield put($path . "/fullchain.pem", implode("\n", $certificates)); - yield chown($path . "/fullchain.pem", 0, 0); - yield chmod($path . "/fullchain.pem", 0640); + yield \Amp\File\put($path . "/fullchain.pem", implode("\n", $certificates)); + yield \Amp\File\chown($path . "/fullchain.pem", 0, 0); + yield \Amp\File\chmod($path . "/fullchain.pem", 0640); - yield put($path . "/chain.pem", implode("\n", $chain)); - yield chown($path . "/chain.pem", 0, 0); - yield chmod($path . "/chain.pem", 0640); + yield \Amp\File\put($path . "/chain.pem", implode("\n", $chain)); + yield \Amp\File\chown($path . "/chain.pem", 0, 0); + yield \Amp\File\chmod($path . "/chain.pem", 0640); } catch (FilesystemException $e) { throw new CertificateStoreException("Couldn't save certificates for '{$commonName}'", 0, $e); } } - public function delete(string $name): Promise { - return resolve($this->doDelete($name)); - } - - private function doDelete(string $name): Generator { - foreach ((yield scandir($this->root . "/" . $name)) as $file) { - yield unlink($this->root . "/" . $name . "/" . $file); + public function delete($name) { + if (!is_string($name)) { + throw new InvalidArgumentException(sprintf("\$name must be of type string, %s given.", gettype($name))); } - yield rmdir($this->root . "/" . $name); + return \Amp\resolve($this->doDelete($name)); + } + + private function doDelete($name) { + if (!is_string($name)) { + throw new InvalidArgumentException(sprintf("\$name must be of type string, %s given.", gettype($name))); + } + + foreach ((yield \Amp\File\scandir($this->root . "/" . $name)) as $file) { + yield \Amp\File\unlink($this->root . "/" . $name . "/" . $file); + } + + yield \Amp\File\rmdir($this->root . "/" . $name); } } \ No newline at end of file diff --git a/src/Stores/ChallengeStore.php b/src/Stores/ChallengeStore.php index 3ee657f..9d222d7 100644 --- a/src/Stores/ChallengeStore.php +++ b/src/Stores/ChallengeStore.php @@ -4,22 +4,48 @@ namespace Kelunik\AcmeClient\Stores; use Amp\Promise; use Generator; -use function Amp\File\put; -use function Amp\File\unlink; -use function Amp\resolve; +use InvalidArgumentException; class ChallengeStore { private $docroot; - public function __construct(string $docroot) { + public function __construct($docroot) { + if (!is_string($docroot)) { + throw new InvalidArgumentException(sprintf("\$docroot must be of type string, %s given.", gettype($docroot))); + } + $this->docroot = rtrim(str_replace("\\", "/", $docroot), "/"); } - public function put(string $token, string $payload, string $user): Promise { - return resolve($this->doPut($token, $payload, $user)); + public function put($token, $payload, $user) { + if (!is_string($token)) { + throw new InvalidArgumentException(sprintf("\$token must be of type string, %s given.", gettype($token))); + } + + if (!is_string($payload)) { + throw new InvalidArgumentException(sprintf("\$payload must be of type string, %s given.", gettype($payload))); + } + + if (!is_string($user)) { + throw new InvalidArgumentException(sprintf("\$user must be of type string, %s given.", gettype($user))); + } + + return \Amp\resolve($this->doPut($token, $payload, $user)); } - private function doPut(string $token, string $payload, string $user): Generator { + private function doPut($token, $payload, $user) { + if (!is_string($token)) { + throw new InvalidArgumentException(sprintf("\$token must be of type string, %s given.", gettype($token))); + } + + if (!is_string($payload)) { + throw new InvalidArgumentException(sprintf("\$payload must be of type string, %s given.", gettype($payload))); + } + + if (!is_string($user)) { + throw new InvalidArgumentException(sprintf("\$user must be of type string, %s given.", gettype($user))); + } + $path = $this->docroot . "/.well-known/acme-challenge"; $realpath = realpath($path); @@ -39,22 +65,30 @@ class ChallengeStore { chown($this->docroot . "/.well-known", $userInfo["uid"]); chown($this->docroot . "/.well-known/acme-challenge", $userInfo["uid"]); - yield put("{$path}/{$token}", $payload); + yield \Amp\File\put("{$path}/{$token}", $payload); chown("{$path}/{$token}", $userInfo["uid"]); chmod("{$path}/{$token}", 0660); } - public function delete(string $token): Promise { - return resolve($this->doDelete($token)); + public function delete($token) { + if (!is_string($token)) { + throw new InvalidArgumentException(sprintf("\$token must be of type string, %s given.", gettype($token))); + } + + return \Amp\resolve($this->doDelete($token)); } - private function doDelete(string $token): Generator { + private function doDelete($token) { + if (!is_string($token)) { + throw new InvalidArgumentException(sprintf("\$token must be of type string, %s given.", gettype($token))); + } + $path = $this->docroot . "/.well-known/acme-challenge/{$token}"; $realpath = realpath($path); if ($realpath) { - yield unlink($realpath); + yield \Amp\File\unlink($realpath); } } } \ No newline at end of file diff --git a/src/Stores/KeyStore.php b/src/Stores/KeyStore.php index e350170..9bbe776 100644 --- a/src/Stores/KeyStore.php +++ b/src/Stores/KeyStore.php @@ -2,28 +2,35 @@ namespace Kelunik\AcmeClient\Stores; +use Amp\CoroutineResult; use Amp\File\FilesystemException; -use Amp\Promise; -use Generator; +use InvalidArgumentException; use Kelunik\Acme\KeyPair; -use function Amp\File\chmod; -use function Amp\File\chown; -use function Amp\File\get; -use function Amp\File\put; -use function Amp\resolve; class KeyStore { private $root; - public function __construct(string $root = "") { + public function __construct($root = "") { + if (!is_string($root)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($root))); + } + $this->root = rtrim(str_replace("\\", "/", $root), "/"); } - public function get(string $path): Promise { - return resolve($this->doGet($path)); + public function get($path) { + if (!is_string($path)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($path))); + } + + return \Amp\resolve($this->doGet($path)); } - private function doGet(string $path): Generator { + private function doGet($path) { + if (!is_string($path)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($path))); + } + $file = $this->root . "/" . $path; $realpath = realpath($file); @@ -31,7 +38,7 @@ class KeyStore { throw new KeyStoreException("File not found: '{$file}'"); } - $privateKey = yield get($realpath); + $privateKey = (yield \Amp\File\get($realpath)); $res = openssl_pkey_get_private($privateKey); if ($res === false) { @@ -40,27 +47,35 @@ class KeyStore { $publicKey = openssl_pkey_get_details($res)["key"]; - return new KeyPair($privateKey, $publicKey); + yield new CoroutineResult(new KeyPair($privateKey, $publicKey)); } - public function put(string $path, KeyPair $keyPair): Promise { - return resolve($this->doPut($path, $keyPair)); + public function put($path, KeyPair $keyPair) { + if (!is_string($path)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($path))); + } + + return \Amp\resolve($this->doPut($path, $keyPair)); } - private function doPut(string $path, KeyPair $keyPair): Generator { + private function doPut($path, KeyPair $keyPair) { + if (!is_string($path)) { + throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($path))); + } + $file = $this->root . "/" . $path; try { // TODO: Replace with async version once available mkdir(dirname($file), 0770, true); - yield put($file, $keyPair->getPrivate()); - yield chmod($file, 0600); - yield chown($file, 0, 0); + yield \Amp\File\put($file, $keyPair->getPrivate()); + yield \Amp\File\chmod($file, 0600); + yield \Amp\File\chown($file, 0, 0); } catch (FilesystemException $e) { throw new KeyStoreException("Could not save key.", 0, $e); } - return $keyPair; + yield new CoroutineResult($keyPair); } } \ No newline at end of file diff --git a/src/functions.php b/src/functions.php index c139c67..656ac31 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,7 +2,7 @@ namespace Kelunik\AcmeClient; -function commandToClass(string $command): string { +function commandToClass($command) { return __NAMESPACE__ . "\\Commands\\" . ucfirst($command); }