diff --git a/bin/acme b/bin/acme
index be8da69..9f5cc89 100755
--- a/bin/acme
+++ b/bin/acme
@@ -1,6 +1,7 @@
#!/usr/bin/env php
"Setup, issue and renew based on a single configuration file.",
- "setup" => "Setup and register account.",
- "issue" => "Issue a new certificate.",
- "check" => "Check if a certificate is still valid long enough.",
- "revoke" => "Revoke a certificate.",
- "status" => "Show status about local certificates.",
- "version" => "Print version information.",
- "help" => "Print this help information.",
+ 'auto' => 'Setup, issue and renew based on a single configuration file.',
+ 'setup' => 'Setup and register account.',
+ 'issue' => 'Issue a new certificate.',
+ 'check' => 'Check if a certificate is still valid long enough.',
+ 'revoke' => 'Revoke a certificate.',
+ 'status' => 'Show status about local certificates.',
+ 'version' => 'Print version information.',
+ 'help' => 'Print this help information.',
];
$binary = \Kelunik\AcmeClient\getBinary();
@@ -75,22 +76,22 @@ EOT;
$climate = new CLImate;
-if (!in_array(PHP_SAPI, ["cli", "phpdbg"], true)) {
- $climate->error("Please run this script on the command line!");
+if (!in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) {
+ $climate->error('Please run this script on the command line!');
exit(1);
}
-if (PHP_VERSION_ID < 50600) {
- $climate->yellow("You're using an older version of PHP which is no longer supported and will not even receive security fixes anymore. Have a look at http://php.net/supported-versions.php and upgrade now!");
+if (PHP_VERSION_ID < 70000) {
+ $climate->yellow("You're using an older version of PHP which is no longer supported by this client. Have a look at http://php.net/supported-versions.php and upgrade at least to PHP 7.0!");
$climate->br(2);
}
-if (count($argv) === 1 || in_array($argv[1], ["-h", "help", "--help"], true)) {
+if (count($argv) === 1 || in_array($argv[1], ['-h', 'help', '--help'], true)) {
$climate->out($logo . $help);
exit(0);
}
-if (!in_array($argv[1], array_keys($commands))) {
+if (!array_key_exists($argv[1], $commands)) {
$climate->error("Unknown command '{$argv[1]}'. Use --help for a list of available commands.");
$suggestion = \Kelunik\AcmeClient\suggestCommand($argv[1], array_keys($commands));
@@ -114,14 +115,14 @@ try {
$climate->arguments->add($definition);
- if (count($argv) === 3 && in_array($argv[2], ["-h", "--help"], true)) {
+ if (count($argv) === 3 && in_array($argv[2], ['-h', '--help'], true)) {
$climate->usage(["{$binary} {$argv[1]}"]);
$climate->br();
exit(0);
- } else {
- $climate->arguments->parse(array_values($args));
}
+
+ $climate->arguments->parse(array_values($args));
} catch (Exception $e) {
$climate->usage(["{$binary} {$argv[1]}"]);
$climate->br();
@@ -135,16 +136,16 @@ try {
$injector = new Injector;
$injector->share($climate);
$injector->share(new AcmeFactory);
-$injector->share(new Amp\Artax\Client(new Amp\Artax\Cookie\NullCookieJar));
+$injector->share(new Amp\Artax\DefaultClient);
$command = $injector->make($class);
-Amp\run(function () use ($command, $climate) {
+Loop::run(function () use ($command, $climate) {
$handler = function ($e) use ($climate) {
$error = (string) $e;
$lines = explode("\n", $error);
$lines = array_filter($lines, function ($line) {
- return strlen($line) && $line[0] !== "#" && $line !== "Stack trace:";
+ return $line !== '' && $line[0] !== '#' && $line !== 'Stack trace:';
});
foreach ($lines as $line) {
@@ -155,7 +156,7 @@ Amp\run(function () use ($command, $climate) {
};
try {
- $exitCode = (yield $command->execute($climate->arguments));
+ $exitCode = yield $command->execute($climate->arguments);
if ($exitCode === null) {
exit(0);
@@ -164,9 +165,7 @@ Amp\run(function () use ($command, $climate) {
exit($exitCode);
} catch (Throwable $e) {
$handler($e);
- } catch (Exception $e) {
- $handler($e);
}
- Amp\stop();
+ Loop::stop();
});
diff --git a/composer.json b/composer.json
index a86fe67..f12bf74 100644
--- a/composer.json
+++ b/composer.json
@@ -11,20 +11,20 @@
"tls"
],
"require": {
- "php": "^5.5|^7",
+ "php": ">=7",
"ext-openssl": "*",
- "amphp/process": "^0.1.1",
- "kelunik/acme": "^0.3",
+ "amphp/process": "^0.2",
+ "kelunik/acme": "^0.5",
"kelunik/certificate": "^1",
- "league/climate": "^3",
- "rdlowrey/auryn": "^1",
- "webmozart/assert": "^1",
+ "league/climate": "^3.2",
+ "rdlowrey/auryn": "^1.4.2",
+ "webmozart/assert": "^1.2",
"symfony/yaml": "^3.0"
},
"require-dev": {
- "phpunit/phpunit": "^4|^5",
- "friendsofphp/php-cs-fixer": "^1.9",
- "macfja/phar-builder": "^0.2.5"
+ "phpunit/phpunit": "^6",
+ "friendsofphp/php-cs-fixer": "^2.9",
+ "macfja/phar-builder": "^0.2.6"
},
"license": "MIT",
"authors": [
@@ -33,8 +33,6 @@
"email": "me@kelunik.com"
}
],
- "minimum-stability": "dev",
- "prefer-stable": true,
"autoload": {
"psr-4": {
"Kelunik\\AcmeClient\\": "src"
@@ -43,12 +41,6 @@
"src/functions.php"
]
},
- "repositories": [
- {
- "type": "vcs",
- "url": "https://github.com/kelunik/pharbuilder"
- }
- ],
"extra": {
"phar-builder": {
"compression": "GZip",
diff --git a/composer.lock b/composer.lock
index ea71c5d..40814e1 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,41 +4,45 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "9989cd58e3ed427161a28dc22d81993a",
+ "content-hash": "453e56fe6bb9de302a96b94f70baa09a",
"packages": [
{
"name": "amphp/amp",
- "version": "v1.2.2",
+ "version": "v2.0.5",
"source": {
"type": "git",
"url": "https://github.com/amphp/amp.git",
- "reference": "4f2161da5f68f274f116985635aea63b5c0f54d2"
+ "reference": "502b4be0008ed2f9479ad598187e49683ce6ef39"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/amp/zipball/4f2161da5f68f274f116985635aea63b5c0f54d2",
- "reference": "4f2161da5f68f274f116985635aea63b5c0f54d2",
+ "url": "https://api.github.com/repos/amphp/amp/zipball/502b4be0008ed2f9479ad598187e49683ce6ef39",
+ "reference": "502b4be0008ed2f9479ad598187e49683ce6ef39",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": ">=7"
},
"require-dev": {
- "fabpot/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "~4.8"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpstan/phpstan": "^0.8.5",
+ "phpunit/phpunit": "^6.0.9",
+ "react/promise": "^2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
- "Amp\\": "lib/"
+ "Amp\\": "lib"
},
"files": [
- "lib/functions.php"
+ "lib/functions.php",
+ "lib/Internal/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -46,56 +50,70 @@
"MIT"
],
"authors": [
+ {
+ "name": "Bob Weinand",
+ "email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
{
"name": "Daniel Lowrey",
- "email": "rdlowrey@php.net",
- "role": "Creator / Lead Developer"
+ "email": "rdlowrey@php.net"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
}
],
- "description": "A non-blocking concurrency framework for PHP applications",
- "homepage": "https://github.com/amphp/amp",
+ "description": "A non-blocking concurrency framework for PHP applications.",
+ "homepage": "http://amphp.org/amp",
"keywords": [
"async",
+ "asynchronous",
+ "awaitable",
"concurrency",
"event",
+ "event-loop",
+ "future",
"non-blocking",
"promise"
],
- "time": "2016-05-12T12:54:59+00:00"
+ "time": "2017-12-19T17:27:18+00:00"
},
{
"name": "amphp/artax",
- "version": "v2.0.6",
+ "version": "v3.0.13",
"source": {
"type": "git",
"url": "https://github.com/amphp/artax.git",
- "reference": "8ed34eb97685432b603fdf5b9279bd908333c814"
+ "reference": "340bd11600b5c77a2ab136d4300a776a02a85cc9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/artax/zipball/8ed34eb97685432b603fdf5b9279bd908333c814",
- "reference": "8ed34eb97685432b603fdf5b9279bd908333c814",
+ "url": "https://api.github.com/repos/amphp/artax/zipball/340bd11600b5c77a2ab136d4300a776a02a85cc9",
+ "reference": "340bd11600b5c77a2ab136d4300a776a02a85cc9",
"shasum": ""
},
"require": {
- "amphp/amp": "^1",
- "amphp/socket": "^0.9",
- "php": ">=5.5.0"
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1.1.6",
+ "amphp/file": "^0.2 || ^0.3",
+ "amphp/socket": "^0.10",
+ "amphp/uri": "^0.1",
+ "kelunik/certificate": "^1.1",
+ "php": ">=7.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "~4.8"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.x-dev",
- "dev-1.x": "1.x-dev"
- }
- },
"autoload": {
"psr-4": {
- "Amp\\Artax\\": "lib/"
+ "Amp\\Artax\\": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -103,10 +121,13 @@
"MIT"
],
"authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
{
"name": "Daniel Lowrey",
- "email": "rdlowrey@gmail.com",
- "role": "Creator / Lead Developer"
+ "email": "rdlowrey@gmail.com"
}
],
"description": "Asynchronous parallel HTTP/1.1 client built on the Amp concurrency framework",
@@ -119,36 +140,91 @@
"parallel",
"rest"
],
- "time": "2017-05-09T19:47:08+00:00"
+ "time": "2017-12-19T13:45:05+00:00"
},
{
- "name": "amphp/cache",
- "version": "v0.1.0",
+ "name": "amphp/byte-stream",
+ "version": "v1.2.1",
"source": {
"type": "git",
- "url": "https://github.com/amphp/cache.git",
- "reference": "26709c198dcee686557801eda6d9345f3cfa8874"
+ "url": "https://github.com/amphp/byte-stream.git",
+ "reference": "0c059ba0e6aa7a1ebdce0ba92c77be1ec5dd9143"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/cache/zipball/26709c198dcee686557801eda6d9345f3cfa8874",
- "reference": "26709c198dcee686557801eda6d9345f3cfa8874",
+ "url": "https://api.github.com/repos/amphp/byte-stream/zipball/0c059ba0e6aa7a1ebdce0ba92c77be1ec5dd9143",
+ "reference": "0c059ba0e6aa7a1ebdce0ba92c77be1ec5dd9143",
"shasum": ""
},
"require": {
- "amphp/amp": "^1"
+ "amphp/amp": "^2"
},
"require-dev": {
- "fabpot/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "~4.8"
- },
- "suggest": {
- "amphp/redis": "For redis cache driver support"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
"psr-4": {
- "Amp\\Cache\\": "lib/"
+ "Amp\\ByteStream\\": "lib"
+ },
+ "files": [
+ "lib/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ }
+ ],
+ "description": "A stream abstraction to make working with non-blocking I/O simple.",
+ "homepage": "http://amphp.org/byte-stream",
+ "keywords": [
+ "amp",
+ "amphp",
+ "async",
+ "io",
+ "non-blocking",
+ "stream"
+ ],
+ "time": "2017-12-10T16:40:58+00:00"
+ },
+ {
+ "name": "amphp/cache",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/cache.git",
+ "reference": "ab2339e465d9d383dc748f288d530fd7cd7aadea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/cache/zipball/ab2339e465d9d383dc748f288d530fd7cd7aadea",
+ "reference": "ab2339e465d9d383dc748f288d530fd7cd7aadea",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2"
+ },
+ "require-dev": {
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Cache\\": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -165,36 +241,39 @@
"email": "rdlowrey@php.net"
}
],
- "description": "A promise-aware caching API built on the amp concurrency framework",
+ "description": "A promise-aware caching API for Amp.",
"homepage": "https://github.com/amphp/cache",
- "time": "2015-09-08T22:26:20+00:00"
+ "time": "2017-10-04T19:22:12+00:00"
},
{
"name": "amphp/dns",
- "version": "v0.8.14",
+ "version": "v0.9.11",
"source": {
"type": "git",
"url": "https://github.com/amphp/dns.git",
- "reference": "5fc1cde2d29e94d731ab96d5ef5f9f20958315cc"
+ "reference": "16e6d6c22f293370a8d6120744aa04181cd92766"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/dns/zipball/5fc1cde2d29e94d731ab96d5ef5f9f20958315cc",
- "reference": "5fc1cde2d29e94d731ab96d5ef5f9f20958315cc",
+ "url": "https://api.github.com/repos/amphp/dns/zipball/16e6d6c22f293370a8d6120744aa04181cd92766",
+ "reference": "16e6d6c22f293370a8d6120744aa04181cd92766",
"shasum": ""
},
"require": {
- "amphp/amp": "^1",
- "amphp/cache": "^0.1",
- "amphp/file": "^0.1",
- "amphp/windows-registry": "^0.2.2",
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1.1",
+ "amphp/cache": "^1.2",
+ "amphp/file": "^0.2 || ^0.3",
+ "amphp/parser": "^1",
+ "amphp/uri": "^0.1",
+ "amphp/windows-registry": "^0.3",
"daverandom/libdns": "^1",
- "php": ">=5.5"
+ "php": ">=7.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^1.9",
- "phpunit/php-code-coverage": ">=2.2",
- "phpunit/phpunit": "^4.8|^5.1.3"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
@@ -202,7 +281,6 @@
"Amp\\Dns\\": "lib"
},
"files": [
- "lib/constants.php",
"lib/functions.php"
]
},
@@ -226,48 +304,49 @@
{
"name": "Chris Wright",
"email": "addr@daverandom.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
}
],
- "description": "Async DNS resolution built on the amp concurrency framework",
+ "description": "Async DNS resolution for Amp.",
"homepage": "https://github.com/amphp/dns",
"keywords": [
"amp",
+ "amphp",
"async",
"client",
"dns",
"resolve"
],
- "time": "2017-02-05T22:17:40+00:00"
+ "time": "2017-12-16T18:59:47+00:00"
},
{
"name": "amphp/file",
- "version": "v0.1.3",
+ "version": "v0.3.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/file.git",
- "reference": "6612ae6757d4719492ed8b34ea6181ff67cfbed1"
+ "reference": "fb58fe8dd5d1eeae5af152bf9e37731de5423caf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/file/zipball/6612ae6757d4719492ed8b34ea6181ff67cfbed1",
- "reference": "6612ae6757d4719492ed8b34ea6181ff67cfbed1",
+ "url": "https://api.github.com/repos/amphp/file/zipball/fb58fe8dd5d1eeae5af152bf9e37731de5423caf",
+ "reference": "fb58fe8dd5d1eeae5af152bf9e37731de5423caf",
"shasum": ""
},
"require": {
- "amphp/amp": "^1",
- "php": ">=5.5"
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1",
+ "amphp/parallel": "^0.2"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "~4.8"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "0.1.0-dev",
- "dev-amp_v2": "0.2.0-dev"
- }
- },
"autoload": {
"psr-4": {
"Amp\\File\\": "lib"
@@ -281,12 +360,20 @@
"MIT"
],
"authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
{
"name": "Daniel Lowrey",
"email": "rdlowrey@php.net"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
}
],
- "description": "An async filesystem library built on the amp concurrency framework",
+ "description": "Allows non-blocking access to the filesystem for Amp.",
"homepage": "https://github.com/amphp/file",
"keywords": [
"amp",
@@ -294,81 +381,268 @@
"async",
"disk",
"file",
+ "filesystem",
+ "io",
"non-blocking",
"static"
],
- "time": "2016-10-01T17:43:52+00:00"
+ "time": "2017-12-15T04:36:16+00:00"
},
{
- "name": "amphp/process",
- "version": "v0.1.3",
+ "name": "amphp/parallel",
+ "version": "v0.2.1",
"source": {
"type": "git",
- "url": "https://github.com/amphp/process.git",
- "reference": "f22cca2af36e442b771c0de2e24e8025550d8ffc"
+ "url": "https://github.com/amphp/parallel.git",
+ "reference": "0d40e6da980d56de8bbd292668becef6ed45a2a7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/process/zipball/f22cca2af36e442b771c0de2e24e8025550d8ffc",
- "reference": "f22cca2af36e442b771c0de2e24e8025550d8ffc",
+ "url": "https://api.github.com/repos/amphp/parallel/zipball/0d40e6da980d56de8bbd292668becef6ed45a2a7",
+ "reference": "0d40e6da980d56de8bbd292668becef6ed45a2a7",
"shasum": ""
},
"require": {
- "amphp/amp": "^1"
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1.2",
+ "amphp/parser": "^1",
+ "amphp/process": "^0.2 || ^0.3",
+ "amphp/sync": "^1.0.1"
},
"require-dev": {
- "fabpot/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "^4.8"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
+ },
+ "suggest": {
+ "ext-pthreads": "Required for thread contexts"
},
"type": "library",
"autoload": {
- "classmap": [
- {
- "Amp\\Process": "Process.php"
- }
+ "psr-4": {
+ "Amp\\Parallel\\": "lib"
+ },
+ "files": [
+ "lib/Worker/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
+ "authors": [
+ {
+ "name": "Stephen Coakley",
+ "email": "me@stephencoakley.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ }
+ ],
+ "description": "Parallel processing component for Amp.",
+ "homepage": "https://github.com/amphp/parallel",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "concurrent",
+ "multi-processing",
+ "multi-threading"
+ ],
+ "time": "2017-12-27T18:36:28+00:00"
+ },
+ {
+ "name": "amphp/parser",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/parser.git",
+ "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/parser/zipball/f83e68f03d5b8e8e0365b8792985a7f341c57ae1",
+ "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Parser\\": "lib"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ }
+ ],
+ "description": "A generator parser to make streaming parsers simple.",
+ "homepage": "https://github.com/amphp/parser",
+ "keywords": [
+ "async",
+ "non-blocking",
+ "parser",
+ "stream"
+ ],
+ "time": "2017-06-06T05:29:10+00:00"
+ },
+ {
+ "name": "amphp/process",
+ "version": "v0.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/process.git",
+ "reference": "5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/process/zipball/5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a",
+ "reference": "5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1"
+ },
+ "require-dev": {
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "kelunik/fqn-check": "^0.1.3",
+ "phpunit/phpunit": "^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Process\\": "lib"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
"authors": [
{
"name": "Bob Weinand",
"email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
}
],
"description": "Asynchronous process manager",
"homepage": "https://github.com/amphp/process",
- "time": "2016-09-24T10:49:26+00:00"
+ "time": "2017-07-18T03:37:19+00:00"
},
{
"name": "amphp/socket",
- "version": "v0.9.9",
+ "version": "v0.10.5",
"source": {
"type": "git",
"url": "https://github.com/amphp/socket.git",
- "reference": "722614608c1de7099661187fad4e15c876816db1"
+ "reference": "937aff6eaa08cd4da03d475d98bcf911bbb854ab"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/socket/zipball/722614608c1de7099661187fad4e15c876816db1",
- "reference": "722614608c1de7099661187fad4e15c876816db1",
+ "url": "https://api.github.com/repos/amphp/socket/zipball/937aff6eaa08cd4da03d475d98bcf911bbb854ab",
+ "reference": "937aff6eaa08cd4da03d475d98bcf911bbb854ab",
"shasum": ""
},
"require": {
- "amphp/amp": "^1",
- "amphp/dns": "^0.8",
- "php": ">=5.5"
+ "amphp/amp": "^2",
+ "amphp/byte-stream": "^1.1",
+ "amphp/dns": "^0.9",
+ "amphp/uri": "^0.1",
+ "php": ">=7.0"
},
"require-dev": {
- "fabpot/php-cs-fixer": "~1.9",
- "phpunit/phpunit": "~4.8"
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
"psr-4": {
- "Amp\\Socket\\": "lib/"
+ "Amp\\Socket\\": "lib"
+ },
+ "files": [
+ "lib/functions.php",
+ "lib/Internal/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@gmail.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ }
+ ],
+ "description": "Async socket connection / server tools for Amp.",
+ "homepage": "https://github.com/amphp/socket",
+ "keywords": [
+ "amp",
+ "async",
+ "encryption",
+ "non-blocking",
+ "sockets",
+ "tcp",
+ "tls"
+ ],
+ "time": "2017-12-19T18:19:46+00:00"
+ },
+ {
+ "name": "amphp/sync",
+ "version": "v1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/sync.git",
+ "reference": "a1d8f244eb19e3e2a96abc4686cebc80995bbc90"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/sync/zipball/a1d8f244eb19e3e2a96abc4686cebc80995bbc90",
+ "reference": "a1d8f244eb19e3e2a96abc4686cebc80995bbc90",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2"
+ },
+ "require-dev": {
+ "amphp/phpunit-util": "^1",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Sync\\": "lib"
},
"files": [
"lib/functions.php"
@@ -380,46 +654,94 @@
],
"authors": [
{
- "name": "Daniel Lowrey",
- "email": "rdlowrey@gmail.com"
+ "name": "Stephen Coakley",
+ "email": "me@stephencoakley.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
}
],
- "description": "Async socket connection tools for the amp concurrency framework",
- "homepage": "https://github.com/amphp/socket",
+ "description": "Mutex, Semaphore, and other synchronization tools for Amp.",
+ "homepage": "https://github.com/amphp/sync",
"keywords": [
- "amp",
"async",
- "encryption",
- "non-blocking",
- "sockets",
- "tcp",
- "tls"
+ "asynchronous",
+ "mutex",
+ "semaphore",
+ "synchronization"
],
- "time": "2016-07-18T22:03:24+00:00"
+ "time": "2017-11-29T21:48:53+00:00"
},
{
- "name": "amphp/windows-registry",
- "version": "v0.2.2",
+ "name": "amphp/uri",
+ "version": "v0.1.3",
"source": {
"type": "git",
- "url": "https://github.com/amphp/windows-registry.git",
- "reference": "e4420eb368008c8fe81c0b481506306272cc3d21"
+ "url": "https://github.com/amphp/uri.git",
+ "reference": "b857ba4df3cf0852302ba1637fccce4ce1205241"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/windows-registry/zipball/e4420eb368008c8fe81c0b481506306272cc3d21",
- "reference": "e4420eb368008c8fe81c0b481506306272cc3d21",
+ "url": "https://api.github.com/repos/amphp/uri/zipball/b857ba4df3cf0852302ba1637fccce4ce1205241",
+ "reference": "b857ba4df3cf0852302ba1637fccce4ce1205241",
"shasum": ""
},
- "require": {
- "amphp/amp": "^1.2",
- "amphp/process": "^0.1.3",
- "php": ">=5.5"
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
"psr-4": {
- "Amp\\WindowsRegistry\\": "src"
+ "Amp\\Uri\\": "src"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Daniel Lowrey"
+ }
+ ],
+ "description": "Uri Parser and Resolver.",
+ "homepage": "https://github.com/amphp/uri",
+ "time": "2017-10-23T12:40:35+00:00"
+ },
+ {
+ "name": "amphp/windows-registry",
+ "version": "v0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/windows-registry.git",
+ "reference": "46ba1463dfffc8081b4b483fac05d3f51ecb1d87"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/windows-registry/zipball/46ba1463dfffc8081b4b483fac05d3f51ecb1d87",
+ "reference": "46ba1463dfffc8081b4b483fac05d3f51ecb1d87",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2",
+ "amphp/process": "^0.2 || ^0.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\WindowsRegistry\\": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -433,7 +755,7 @@
}
],
"description": "Windows Registry Reader.",
- "time": "2017-01-04T23:52:31+00:00"
+ "time": "2017-12-11T08:35:51+00:00"
},
{
"name": "daverandom/libdns",
@@ -470,38 +792,41 @@
},
{
"name": "kelunik/acme",
- "version": "v0.3.3",
+ "version": "v0.5.0",
"source": {
"type": "git",
"url": "https://github.com/kelunik/acme.git",
- "reference": "69a94a00e6c02f57a051ec962bdd1fc9649a96dd"
+ "reference": "496c9189f37ab512664cb12dc7b994c1ca6965cb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/kelunik/acme/zipball/69a94a00e6c02f57a051ec962bdd1fc9649a96dd",
- "reference": "69a94a00e6c02f57a051ec962bdd1fc9649a96dd",
+ "url": "https://api.github.com/repos/kelunik/acme/zipball/496c9189f37ab512664cb12dc7b994c1ca6965cb",
+ "reference": "496c9189f37ab512664cb12dc7b994c1ca6965cb",
"shasum": ""
},
"require": {
- "amphp/artax": "^2",
- "namshi/jose": "^6",
+ "amphp/amp": "^2",
+ "amphp/artax": "^3",
+ "namshi/jose": "^7",
"sabre/uri": "^1"
},
"require-dev": {
- "fabpot/php-cs-fixer": "^1.9",
- "phpdocumentor/phpdocumentor": "^2",
- "phpunit/phpunit": "^5"
+ "amphp/phpunit-util": "^1.0",
+ "phpunit/phpunit": "^6"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "0.3-dev"
+ "dev-master": "0.5-dev"
}
},
"autoload": {
"psr-4": {
"Kelunik\\Acme\\": "lib"
- }
+ },
+ "files": [
+ "lib/functions.php"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -523,20 +848,20 @@
"ssl",
"tls"
],
- "time": "2016-03-23T19:49:15+00:00"
+ "time": "2017-11-28T14:26:01+00:00"
},
{
"name": "kelunik/certificate",
- "version": "v1.0.0",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/kelunik/certificate.git",
- "reference": "b4ea243fbedc56813c74ba5b00bf8c69c6892a80"
+ "reference": "524fa432ed1b5f50efbe7749f3c19e28a9866bc7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/kelunik/certificate/zipball/b4ea243fbedc56813c74ba5b00bf8c69c6892a80",
- "reference": "b4ea243fbedc56813c74ba5b00bf8c69c6892a80",
+ "url": "https://api.github.com/repos/kelunik/certificate/zipball/524fa432ed1b5f50efbe7749f3c19e28a9866bc7",
+ "reference": "524fa432ed1b5f50efbe7749f3c19e28a9866bc7",
"shasum": ""
},
"require": {
@@ -572,7 +897,7 @@
"pem",
"x509"
],
- "time": "2016-01-27T08:46:30+00:00"
+ "time": "2017-07-04T19:37:30+00:00"
},
{
"name": "league/climate",
@@ -627,33 +952,36 @@
},
{
"name": "namshi/jose",
- "version": "6.1.1",
+ "version": "7.2.3",
"source": {
"type": "git",
"url": "https://github.com/namshi/jose.git",
- "reference": "d234ab5da058bda234efbfc231a4ff68f9c984be"
+ "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/namshi/jose/zipball/d234ab5da058bda234efbfc231a4ff68f9c984be",
- "reference": "d234ab5da058bda234efbfc231a4ff68f9c984be",
+ "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff",
+ "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff",
"shasum": ""
},
"require": {
"ext-date": "*",
"ext-hash": "*",
"ext-json": "*",
- "ext-openssl": "*",
"ext-pcre": "*",
"ext-spl": "*",
"php": ">=5.5",
- "phpseclib/phpseclib": "^2.0",
"symfony/polyfill-php56": "^1.0"
},
"require-dev": {
+ "phpseclib/phpseclib": "^2.0",
"phpunit/phpunit": "^4.5|^5.0",
"satooshi/php-coveralls": "^1.0"
},
+ "suggest": {
+ "ext-openssl": "Allows to use OpenSSL as crypto engine.",
+ "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0."
+ },
"type": "library",
"autoload": {
"psr-4": {
@@ -683,112 +1011,20 @@
"jwt",
"token"
],
- "time": "2016-01-24T11:10:26+00:00"
- },
- {
- "name": "phpseclib/phpseclib",
- "version": "2.0.5",
- "source": {
- "type": "git",
- "url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "f8dd0e18d2328c447dd4190fecd11ef52680d968"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/f8dd0e18d2328c447dd4190fecd11ef52680d968",
- "reference": "f8dd0e18d2328c447dd4190fecd11ef52680d968",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "phing/phing": "~2.7",
- "phpunit/phpunit": "~4.0",
- "sami/sami": "~2.0",
- "squizlabs/php_codesniffer": "~2.0"
- },
- "suggest": {
- "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
- "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
- "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
- "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
- },
- "type": "library",
- "autoload": {
- "files": [
- "phpseclib/bootstrap.php"
- ],
- "psr-4": {
- "phpseclib\\": "phpseclib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jim Wigginton",
- "email": "terrafrost@php.net",
- "role": "Lead Developer"
- },
- {
- "name": "Patrick Monnerat",
- "email": "pm@datasphere.ch",
- "role": "Developer"
- },
- {
- "name": "Andreas Fischer",
- "email": "bantu@phpbb.com",
- "role": "Developer"
- },
- {
- "name": "Hans-Jürgen Petrich",
- "email": "petrich@tronic-media.com",
- "role": "Developer"
- },
- {
- "name": "Graham Campbell",
- "email": "graham@alt-three.com",
- "role": "Developer"
- }
- ],
- "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
- "homepage": "http://phpseclib.sourceforge.net",
- "keywords": [
- "BigInteger",
- "aes",
- "asn.1",
- "asn1",
- "blowfish",
- "crypto",
- "cryptography",
- "encryption",
- "rsa",
- "security",
- "sftp",
- "signature",
- "signing",
- "ssh",
- "twofish",
- "x.509",
- "x509"
- ],
- "time": "2017-05-08T05:58:35+00:00"
+ "time": "2016-12-05T07:27:31+00:00"
},
{
"name": "rdlowrey/auryn",
- "version": "v1.4.1",
+ "version": "v1.4.2",
"source": {
"type": "git",
"url": "https://github.com/rdlowrey/auryn.git",
- "reference": "c6c92ec081c707f7e9e0a69185665147b30d66de"
+ "reference": "8c4dc07943599ba84f4f89eab8cf43efeef80395"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rdlowrey/auryn/zipball/c6c92ec081c707f7e9e0a69185665147b30d66de",
- "reference": "c6c92ec081c707f7e9e0a69185665147b30d66de",
+ "url": "https://api.github.com/repos/rdlowrey/auryn/zipball/8c4dc07943599ba84f4f89eab8cf43efeef80395",
+ "reference": "8c4dc07943599ba84f4f89eab8cf43efeef80395",
"shasum": ""
},
"require": {
@@ -836,19 +1072,19 @@
"dic",
"ioc"
],
- "time": "2017-04-07T16:12:28+00:00"
+ "time": "2017-05-15T06:26:46+00:00"
},
{
"name": "sabre/uri",
"version": "1.2.1",
"source": {
"type": "git",
- "url": "https://github.com/fruux/sabre-uri.git",
+ "url": "https://github.com/sabre-io/uri.git",
"reference": "ada354d83579565949d80b2e15593c2371225e61"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/fruux/sabre-uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
+ "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
"reference": "ada354d83579565949d80b2e15593c2371225e61",
"shasum": ""
},
@@ -939,16 +1175,16 @@
},
{
"name": "symfony/polyfill-php56",
- "version": "v1.3.0",
+ "version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php56.git",
- "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c"
+ "reference": "265fc96795492430762c29be291a371494ba3a5b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c",
- "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c",
+ "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/265fc96795492430762c29be291a371494ba3a5b",
+ "reference": "265fc96795492430762c29be291a371494ba3a5b",
"shasum": ""
},
"require": {
@@ -958,7 +1194,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3-dev"
+ "dev-master": "1.6-dev"
}
},
"autoload": {
@@ -991,20 +1227,20 @@
"portable",
"shim"
],
- "time": "2016-11-14T01:06:16+00:00"
+ "time": "2017-10-11T12:05:26+00:00"
},
{
"name": "symfony/polyfill-util",
- "version": "v1.3.0",
+ "version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-util.git",
- "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb"
+ "reference": "6e719200c8e540e0c0effeb31f96bdb344b94176"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb",
- "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb",
+ "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/6e719200c8e540e0c0effeb31f96bdb344b94176",
+ "reference": "6e719200c8e540e0c0effeb31f96bdb344b94176",
"shasum": ""
},
"require": {
@@ -1013,7 +1249,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3-dev"
+ "dev-master": "1.6-dev"
}
},
"autoload": {
@@ -1043,27 +1279,30 @@
"polyfill",
"shim"
],
- "time": "2016-11-14T01:06:16+00:00"
+ "time": "2017-10-11T12:05:26+00:00"
},
{
"name": "symfony/yaml",
- "version": "v3.2.8",
+ "version": "v3.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6"
+ "reference": "afe0cd38486505c9703707707d91450cfc1bd536"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6",
- "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/afe0cd38486505c9703707707d91450cfc1bd536",
+ "reference": "afe0cd38486505c9703707707d91450cfc1bd536",
"shasum": ""
},
"require": {
- "php": ">=5.5.9"
+ "php": "^5.5.9|>=7.0.8"
+ },
+ "conflict": {
+ "symfony/console": "<3.4"
},
"require-dev": {
- "symfony/console": "~2.8|~3.0"
+ "symfony/console": "~3.4|~4.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
@@ -1071,7 +1310,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -1098,7 +1337,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2017-05-01T14:55:58+00:00"
+ "time": "2017-12-11T20:38:23+00:00"
},
{
"name": "webmozart/assert",
@@ -1153,33 +1392,163 @@
],
"packages-dev": [
{
- "name": "doctrine/instantiator",
- "version": "1.0.5",
+ "name": "composer/semver",
+ "version": "1.4.2",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/instantiator.git",
- "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+ "url": "https://github.com/composer/semver.git",
+ "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
- "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
+ "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
"shasum": ""
},
"require": {
- "php": ">=5.3,<8.0-DEV"
+ "php": "^5.3.2 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.5 || ^5.0.5",
+ "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "time": "2016-08-30T16:08:34+00:00"
+ },
+ {
+ "name": "doctrine/annotations",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/annotations.git",
+ "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
+ "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/lexer": "1.*",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "doctrine/cache": "1.*",
+ "phpunit/phpunit": "^6.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "Docblock Annotations Parser",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "annotations",
+ "docblock",
+ "parser"
+ ],
+ "time": "2017-12-06T07:11:42+00:00"
+ },
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
- "phpunit/phpunit": "~4.0",
- "squizlabs/php_codesniffer": "~2.0"
+ "phpunit/phpunit": "^6.2.3",
+ "squizlabs/php_codesniffer": "^3.0.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.2.x-dev"
}
},
"autoload": {
@@ -1204,39 +1573,109 @@
"constructor",
"instantiate"
],
- "time": "2015-06-14T21:17:01+00:00"
+ "time": "2017-07-22T11:58:36+00:00"
},
{
- "name": "friendsofphp/php-cs-fixer",
- "version": "v1.13.1",
+ "name": "doctrine/lexer",
+ "version": "v1.0.1",
"source": {
"type": "git",
- "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
- "reference": "0ea4f7ed06ca55da1d8fc45da26ff87f261c4088"
+ "url": "https://github.com/doctrine/lexer.git",
+ "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/0ea4f7ed06ca55da1d8fc45da26ff87f261c4088",
- "reference": "0ea4f7ed06ca55da1d8fc45da26ff87f261c4088",
+ "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
+ "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Lexer\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "lexer",
+ "parser"
+ ],
+ "time": "2014-09-09T13:34:57+00:00"
+ },
+ {
+ "name": "friendsofphp/php-cs-fixer",
+ "version": "v2.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
+ "reference": "454ddbe65da6a9297446f442bad244e8a99a9a38"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/454ddbe65da6a9297446f442bad244e8a99a9a38",
+ "reference": "454ddbe65da6a9297446f442bad244e8a99a9a38",
+ "shasum": ""
+ },
+ "require": {
+ "composer/semver": "^1.4",
+ "doctrine/annotations": "^1.2",
+ "ext-json": "*",
"ext-tokenizer": "*",
- "php": "^5.3.6 || >=7.0 <7.2",
- "sebastian/diff": "^1.1",
- "symfony/console": "^2.3 || ^3.0",
- "symfony/event-dispatcher": "^2.1 || ^3.0",
- "symfony/filesystem": "^2.1 || ^3.0",
- "symfony/finder": "^2.1 || ^3.0",
- "symfony/process": "^2.3 || ^3.0",
- "symfony/stopwatch": "^2.5 || ^3.0"
+ "gecko-packages/gecko-php-unit": "^2.0 || ^3.0",
+ "php": "^5.6 || >=7.0 <7.3",
+ "php-cs-fixer/diff": "^1.2",
+ "symfony/console": "^3.2 || ^4.0",
+ "symfony/event-dispatcher": "^3.0 || ^4.0",
+ "symfony/filesystem": "^3.0 || ^4.0",
+ "symfony/finder": "^3.0 || ^4.0",
+ "symfony/options-resolver": "^3.0 || ^4.0",
+ "symfony/polyfill-php70": "^1.0",
+ "symfony/polyfill-php72": "^1.4",
+ "symfony/process": "^3.0 || ^4.0",
+ "symfony/stopwatch": "^3.0 || ^4.0"
},
"conflict": {
- "hhvm": "<3.9"
+ "hhvm": "*"
},
"require-dev": {
- "phpunit/phpunit": "^4.5|^5",
- "satooshi/php-coveralls": "^1.0"
+ "johnkary/phpunit-speedtrap": "^1.1 || ^2.0@dev",
+ "justinrainbow/json-schema": "^5.0",
+ "mikey179/vfsstream": "^1.6",
+ "php-coveralls/php-coveralls": "^2.0",
+ "php-cs-fixer/accessible-object": "^1.0",
+ "phpunit/phpunit": "^5.7.23 || ^6.4.3",
+ "symfony/phpunit-bridge": "^3.2.2 || ^4.0"
+ },
+ "suggest": {
+ "ext-mbstring": "For handling non-UTF8 characters in cache signature.",
+ "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
},
"bin": [
"php-cs-fixer"
@@ -1244,8 +1683,15 @@
"type": "application",
"autoload": {
"psr-4": {
- "Symfony\\CS\\": "Symfony/CS/"
- }
+ "PhpCsFixer\\": "src/"
+ },
+ "classmap": [
+ "tests/Test/Assert/AssertTokensTrait.php",
+ "tests/Test/AbstractFixerTestCase.php",
+ "tests/Test/AbstractIntegrationTestCase.php",
+ "tests/Test/IntegrationCase.php",
+ "tests/Test/IntegrationCaseFactory.php"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -1262,7 +1708,56 @@
}
],
"description": "A tool to automatically fix PHP code style",
- "time": "2016-12-01T00:05:05+00:00"
+ "time": "2017-12-08T16:36:20+00:00"
+ },
+ {
+ "name": "gecko-packages/gecko-php-unit",
+ "version": "v3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/GeckoPackages/GeckoPHPUnit.git",
+ "reference": "6a866551dffc2154c1b091bae3a7877d39c25ca3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/GeckoPackages/GeckoPHPUnit/zipball/6a866551dffc2154c1b091bae3a7877d39c25ca3",
+ "reference": "6a866551dffc2154c1b091bae3a7877d39c25ca3",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "suggest": {
+ "ext-dom": "When testing with xml.",
+ "ext-libxml": "When testing with xml.",
+ "phpunit/phpunit": "This is an extension for it so make sure you have it some way."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GeckoPackages\\PHPUnit\\": "src/PHPUnit"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Additional PHPUnit asserts and constraints.",
+ "homepage": "https://github.com/GeckoPackages",
+ "keywords": [
+ "extension",
+ "filesystem",
+ "phpunit"
+ ],
+ "time": "2017-08-23T07:46:41+00:00"
},
{
"name": "league/event",
@@ -1316,25 +1811,25 @@
},
{
"name": "macfja/phar-builder",
- "version": "0.2.5",
+ "version": "0.2.6",
"source": {
"type": "git",
"url": "https://github.com/MacFJA/PharBuilder.git",
- "reference": "0a5270b565242a99371ff94d2ebecb85b2854a1d"
+ "reference": "ab3d6f2089e1dc908b545627ab857861bdf2891c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/MacFJA/PharBuilder/zipball/0a5270b565242a99371ff94d2ebecb85b2854a1d",
- "reference": "0a5270b565242a99371ff94d2ebecb85b2854a1d",
+ "url": "https://api.github.com/repos/MacFJA/PharBuilder/zipball/ab3d6f2089e1dc908b545627ab857861bdf2891c",
+ "reference": "ab3d6f2089e1dc908b545627ab857861bdf2891c",
"shasum": ""
},
"require": {
"league/event": "^2.1",
- "macfja/symfony-console-filechooser": "0.1",
+ "macfja/symfony-console-filechooser": "~0.2",
"neutron/signal-handler": "^1.0",
"php": ">=5.4.0",
"rych/bytesize": "~1.0",
- "symfony/console": "~2.7",
+ "symfony/console": "~2.7 || ^3.0",
"symfony/process": "^2.7 || ^3.0",
"webignition/readable-duration": "^0.2"
},
@@ -1350,6 +1845,8 @@
"type": "library",
"extra": {
"phar-builder": {
+ "skip-shebang": false,
+ "include-dev": false,
"entry-point": "bin/phar-builder.php",
"compression": "None",
"name": "phar-builder.phar",
@@ -1374,25 +1871,25 @@
}
],
"description": "CLI tool for create phar of your composer based project",
- "time": "2016-08-07T12:35:14+00:00"
+ "time": "2017-09-30T12:15:07+00:00"
},
{
"name": "macfja/symfony-console-filechooser",
- "version": "0.1",
+ "version": "0.2",
"source": {
"type": "git",
"url": "https://github.com/MacFJA/Symfony-Console-Filechooser.git",
- "reference": "9d9db462a02d3dba1b1499e9f88d06a3aea40e2a"
+ "reference": "abed2593d4a75130b4472cb9de62936a8498e096"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/MacFJA/Symfony-Console-Filechooser/zipball/9d9db462a02d3dba1b1499e9f88d06a3aea40e2a",
- "reference": "9d9db462a02d3dba1b1499e9f88d06a3aea40e2a",
+ "url": "https://api.github.com/repos/MacFJA/Symfony-Console-Filechooser/zipball/abed2593d4a75130b4472cb9de62936a8498e096",
+ "reference": "abed2593d4a75130b4472cb9de62936a8498e096",
"shasum": ""
},
"require": {
- "symfony/console": "~2.6",
- "symfony/finder": "~2.6"
+ "symfony/console": "~2.6 || ^3.0",
+ "symfony/finder": "~2.6 || ^3.0"
},
"type": "library",
"autoload": {
@@ -1420,41 +1917,44 @@
"interactive",
"symfony"
],
- "time": "2015-09-23T18:04:52+00:00"
+ "time": "2017-08-05T19:16:50+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.6.1",
+ "version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102"
+ "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102",
- "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+ "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
"shasum": ""
},
"require": {
- "php": ">=5.4.0"
+ "php": "^5.6 || ^7.0"
},
"require-dev": {
- "doctrine/collections": "1.*",
- "phpunit/phpunit": "~4.1"
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^4.1"
},
"type": "library",
"autoload": {
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
- }
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Create deep copies (clones) of your objects",
- "homepage": "https://github.com/myclabs/DeepCopy",
"keywords": [
"clone",
"copy",
@@ -1462,7 +1962,7 @@
"object",
"object graph"
],
- "time": "2017-04-12T18:52:22+00:00"
+ "time": "2017-10-19T19:58:43+00:00"
},
{
"name": "neutron/signal-handler",
@@ -1508,17 +2008,215 @@
"time": "2014-01-15T17:24:13+00:00"
},
{
- "name": "phpdocumentor/reflection-common",
- "version": "1.0",
+ "name": "paragonie/random_compat",
+ "version": "v2.0.11",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
- "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8",
+ "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/random.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "pseudorandom",
+ "random"
+ ],
+ "time": "2017-09-27T21:40:39+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
+ "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "phar-io/version": "^1.0.1",
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "time": "2017-03-05T18:14:27+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
+ "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "time": "2017-03-05T17:38:23+00:00"
+ },
+ {
+ "name": "php-cs-fixer/diff",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHP-CS-Fixer/diff.git",
+ "reference": "f0ef6133d674137e902fdf8a6f2e8e97e14a087b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/f0ef6133d674137e902fdf8a6f2e8e97e14a087b",
+ "reference": "f0ef6133d674137e902fdf8a6f2e8e97e14a087b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.4.3",
+ "symfony/process": "^3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "SpacePossum"
+ }
+ ],
+ "description": "sebastian/diff v2 backport support for PHP5.6",
+ "homepage": "https://github.com/PHP-CS-Fixer",
+ "keywords": [
+ "diff"
+ ],
+ "time": "2017-10-19T09:58:18+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+ "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
"shasum": ""
},
"require": {
@@ -1559,33 +2257,39 @@
"reflection",
"static analysis"
],
- "time": "2015-12-27T11:43:31+00:00"
+ "time": "2017-09-11T18:02:19+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "3.1.1",
+ "version": "4.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
+ "reference": "66465776cfc249844bde6d117abff1d22e06c2da"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
- "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da",
+ "reference": "66465776cfc249844bde6d117abff1d22e06c2da",
"shasum": ""
},
"require": {
- "php": ">=5.5",
- "phpdocumentor/reflection-common": "^1.0@dev",
- "phpdocumentor/type-resolver": "^0.2.0",
+ "php": "^7.0",
+ "phpdocumentor/reflection-common": "^1.0.0",
+ "phpdocumentor/type-resolver": "^0.4.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
- "mockery/mockery": "^0.9.4",
- "phpunit/phpunit": "^4.4"
+ "doctrine/instantiator": "~1.0.5",
+ "mockery/mockery": "^1.0",
+ "phpunit/phpunit": "^6.4"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.x-dev"
+ }
+ },
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
@@ -1604,24 +2308,24 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2016-09-30T07:12:33+00:00"
+ "time": "2017-11-27T17:38:31+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "0.2.1",
+ "version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
+ "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
- "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
+ "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
"shasum": ""
},
"require": {
- "php": ">=5.5",
+ "php": "^5.5 || ^7.0",
"phpdocumentor/reflection-common": "^1.0"
},
"require-dev": {
@@ -1651,37 +2355,37 @@
"email": "me@mikevanriel.com"
}
],
- "time": "2016-11-25T06:54:22+00:00"
+ "time": "2017-07-14T14:27:02+00:00"
},
{
"name": "phpspec/prophecy",
- "version": "v1.7.0",
+ "version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
+ "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
- "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
+ "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
"sebastian/comparator": "^1.1|^2.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
- "phpunit/phpunit": "^4.8 || ^5.6.5"
+ "phpunit/phpunit": "^4.8.35 || ^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.6.x-dev"
+ "dev-master": "1.7.x-dev"
}
},
"autoload": {
@@ -1714,44 +2418,44 @@
"spy",
"stub"
],
- "time": "2017-03-02T20:05:34+00:00"
+ "time": "2017-11-24T13:59:53+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "4.0.8",
+ "version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
+ "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
- "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1",
+ "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
- "php": "^5.6 || ^7.0",
- "phpunit/php-file-iterator": "^1.3",
- "phpunit/php-text-template": "^1.2",
- "phpunit/php-token-stream": "^1.4.2 || ^2.0",
- "sebastian/code-unit-reverse-lookup": "^1.0",
- "sebastian/environment": "^1.3.2 || ^2.0",
- "sebastian/version": "^1.0 || ^2.0"
+ "php": "^7.0",
+ "phpunit/php-file-iterator": "^1.4.2",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-token-stream": "^2.0.1",
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
+ "sebastian/environment": "^3.0",
+ "sebastian/version": "^2.0.1",
+ "theseer/tokenizer": "^1.1"
},
"require-dev": {
- "ext-xdebug": "^2.1.4",
- "phpunit/phpunit": "^5.7"
+ "phpunit/phpunit": "^6.0"
},
"suggest": {
- "ext-xdebug": "^2.5.1"
+ "ext-xdebug": "^2.5.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0.x-dev"
+ "dev-master": "5.3.x-dev"
}
},
"autoload": {
@@ -1766,7 +2470,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -1777,20 +2481,20 @@
"testing",
"xunit"
],
- "time": "2017-04-02T07:44:40+00:00"
+ "time": "2017-12-06T09:29:45+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.4.2",
+ "version": "1.4.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
"shasum": ""
},
"require": {
@@ -1824,7 +2528,7 @@
"filesystem",
"iterator"
],
- "time": "2016-10-03T07:40:28+00:00"
+ "time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -1918,29 +2622,29 @@
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.11",
+ "version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
+ "reference": "791198a2c6254db10131eecfe8c06670700904db"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
+ "reference": "791198a2c6254db10131eecfe8c06670700904db",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
- "php": ">=5.3.3"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.2"
+ "phpunit/phpunit": "^6.2.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -1963,20 +2667,20 @@
"keywords": [
"tokenizer"
],
- "time": "2017-02-27T10:12:30+00:00"
+ "time": "2017-11-27T05:48:46+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "5.7.19",
+ "version": "6.5.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1"
+ "reference": "83d27937a310f2984fd575686138597147bdc7df"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69c4f49ff376af2692bad9cebd883d17ebaa98a1",
- "reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d27937a310f2984fd575686138597147bdc7df",
+ "reference": "83d27937a310f2984fd575686138597147bdc7df",
"shasum": ""
},
"require": {
@@ -1985,33 +2689,35 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
- "myclabs/deep-copy": "~1.3",
- "php": "^5.6 || ^7.0",
- "phpspec/prophecy": "^1.6.2",
- "phpunit/php-code-coverage": "^4.0.4",
- "phpunit/php-file-iterator": "~1.4",
- "phpunit/php-text-template": "~1.2",
- "phpunit/php-timer": "^1.0.6",
- "phpunit/phpunit-mock-objects": "^3.2",
- "sebastian/comparator": "^1.2.4",
- "sebastian/diff": "~1.2",
- "sebastian/environment": "^1.3.4 || ^2.0",
- "sebastian/exporter": "~2.0",
- "sebastian/global-state": "^1.1",
- "sebastian/object-enumerator": "~2.0",
- "sebastian/resource-operations": "~1.0",
- "sebastian/version": "~1.0.3|~2.0",
- "symfony/yaml": "~2.1|~3.0"
+ "myclabs/deep-copy": "^1.6.1",
+ "phar-io/manifest": "^1.0.1",
+ "phar-io/version": "^1.0",
+ "php": "^7.0",
+ "phpspec/prophecy": "^1.7",
+ "phpunit/php-code-coverage": "^5.3",
+ "phpunit/php-file-iterator": "^1.4.3",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-timer": "^1.0.9",
+ "phpunit/phpunit-mock-objects": "^5.0.5",
+ "sebastian/comparator": "^2.1",
+ "sebastian/diff": "^2.0",
+ "sebastian/environment": "^3.1",
+ "sebastian/exporter": "^3.1",
+ "sebastian/global-state": "^2.0",
+ "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/resource-operations": "^1.0",
+ "sebastian/version": "^2.0.1"
},
"conflict": {
- "phpdocumentor/reflection-docblock": "3.0.2"
+ "phpdocumentor/reflection-docblock": "3.0.2",
+ "phpunit/dbunit": "<3.0"
},
"require-dev": {
"ext-pdo": "*"
},
"suggest": {
"ext-xdebug": "*",
- "phpunit/php-invoker": "~1.1"
+ "phpunit/php-invoker": "^1.1"
},
"bin": [
"phpunit"
@@ -2019,7 +2725,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.7.x-dev"
+ "dev-master": "6.5.x-dev"
}
},
"autoload": {
@@ -2045,33 +2751,33 @@
"testing",
"xunit"
],
- "time": "2017-04-03T02:22:27+00:00"
+ "time": "2017-12-17T06:31:19+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "3.4.3",
+ "version": "5.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24"
+ "reference": "283b9f4f670e3a6fd6c4ff95c51a952eb5c75933"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
- "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/283b9f4f670e3a6fd6c4ff95c51a952eb5c75933",
+ "reference": "283b9f4f670e3a6fd6c4ff95c51a952eb5c75933",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.2",
- "php": "^5.6 || ^7.0",
- "phpunit/php-text-template": "^1.2",
- "sebastian/exporter": "^1.2 || ^2.0"
+ "doctrine/instantiator": "^1.0.5",
+ "php": "^7.0",
+ "phpunit/php-text-template": "^1.2.1",
+ "sebastian/exporter": "^3.1"
},
"conflict": {
- "phpunit/phpunit": "<5.4.0"
+ "phpunit/phpunit": "<6.0"
},
"require-dev": {
- "phpunit/phpunit": "^5.4"
+ "phpunit/phpunit": "^6.5"
},
"suggest": {
"ext-soap": "*"
@@ -2079,7 +2785,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2.x-dev"
+ "dev-master": "5.0.x-dev"
}
},
"autoload": {
@@ -2094,7 +2800,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -2104,7 +2810,7 @@
"mock",
"xunit"
],
- "time": "2016-12-08T20:27:08+00:00"
+ "time": "2017-12-10T08:01:53+00:00"
},
{
"name": "psr/log",
@@ -2245,30 +2951,30 @@
},
{
"name": "sebastian/comparator",
- "version": "1.2.4",
+ "version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
+ "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
- "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b11c729f95109b56a0fe9650c6a63a0fcd8c439f",
+ "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "sebastian/diff": "~1.2",
- "sebastian/exporter": "~1.2 || ~2.0"
+ "php": "^7.0",
+ "sebastian/diff": "^2.0",
+ "sebastian/exporter": "^3.1"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^6.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2.x-dev"
+ "dev-master": "2.1.x-dev"
}
},
"autoload": {
@@ -2299,38 +3005,38 @@
}
],
"description": "Provides the functionality to compare PHP values for equality",
- "homepage": "http://www.github.com/sebastianbergmann/comparator",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
- "time": "2017-01-29T09:50:25+00:00"
+ "time": "2017-12-22T14:50:35+00:00"
},
{
"name": "sebastian/diff",
- "version": "1.4.1",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
+ "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
- "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
+ "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.8"
+ "phpunit/phpunit": "^6.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -2357,32 +3063,32 @@
"keywords": [
"diff"
],
- "time": "2015-12-08T07:14:41+00:00"
+ "time": "2017-08-03T08:09:46+00:00"
},
{
"name": "sebastian/environment",
- "version": "2.0.0",
+ "version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
+ "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
- "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+ "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
"shasum": ""
},
"require": {
- "php": "^5.6 || ^7.0"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^5.0"
+ "phpunit/phpunit": "^6.1"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.1.x-dev"
}
},
"autoload": {
@@ -2407,34 +3113,34 @@
"environment",
"hhvm"
],
- "time": "2016-11-26T07:53:53+00:00"
+ "time": "2017-07-01T08:51:00+00:00"
},
{
"name": "sebastian/exporter",
- "version": "2.0.0",
+ "version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
+ "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
- "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
+ "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "sebastian/recursion-context": "~2.0"
+ "php": "^7.0",
+ "sebastian/recursion-context": "^3.0"
},
"require-dev": {
"ext-mbstring": "*",
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.1.x-dev"
}
},
"autoload": {
@@ -2474,27 +3180,27 @@
"export",
"exporter"
],
- "time": "2016-11-19T08:54:04+00:00"
+ "time": "2017-04-03T13:19:02+00:00"
},
{
"name": "sebastian/global-state",
- "version": "1.1.1",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
- "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.2"
+ "phpunit/phpunit": "^6.0"
},
"suggest": {
"ext-uopz": "*"
@@ -2502,7 +3208,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -2525,33 +3231,34 @@
"keywords": [
"global state"
],
- "time": "2015-10-12T03:26:01+00:00"
+ "time": "2017-04-27T15:39:26+00:00"
},
{
"name": "sebastian/object-enumerator",
- "version": "2.0.1",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
- "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
"shasum": ""
},
"require": {
- "php": ">=5.6",
- "sebastian/recursion-context": "~2.0"
+ "php": "^7.0",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
},
"require-dev": {
- "phpunit/phpunit": "~5"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.0.x-dev"
}
},
"autoload": {
@@ -2571,32 +3278,77 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
- "time": "2017-02-18T15:18:39+00:00"
+ "time": "2017-08-03T12:35:26+00:00"
},
{
- "name": "sebastian/recursion-context",
- "version": "2.0.0",
+ "name": "sebastian/object-reflector",
+ "version": "1.1.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
- "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "time": "2017-03-29T09:07:27+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
}
},
"autoload": {
@@ -2624,7 +3376,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2016-11-19T07:33:16+00:00"
+ "time": "2017-03-03T06:23:57+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -2713,37 +3465,45 @@
},
{
"name": "symfony/console",
- "version": "v2.8.20",
+ "version": "v3.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e"
+ "reference": "9f21adfb92a9315b73ae2ed43138988ee4913d4e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e",
- "reference": "2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e",
+ "url": "https://api.github.com/repos/symfony/console/zipball/9f21adfb92a9315b73ae2ed43138988ee4913d4e",
+ "reference": "9f21adfb92a9315b73ae2ed43138988ee4913d4e",
"shasum": ""
},
"require": {
- "php": ">=5.3.9",
- "symfony/debug": "^2.7.2|~3.0.0",
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/debug": "~2.8|~3.0|~4.0",
"symfony/polyfill-mbstring": "~1.0"
},
+ "conflict": {
+ "symfony/dependency-injection": "<3.4",
+ "symfony/process": "<3.3"
+ },
"require-dev": {
"psr/log": "~1.0",
- "symfony/event-dispatcher": "~2.1|~3.0.0",
- "symfony/process": "~2.1|~3.0.0"
+ "symfony/config": "~3.3|~4.0",
+ "symfony/dependency-injection": "~3.4|~4.0",
+ "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
+ "symfony/lock": "~3.4|~4.0",
+ "symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
+ "symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.8-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2770,37 +3530,36 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2017-04-26T01:38:53+00:00"
+ "time": "2017-12-14T19:40:10+00:00"
},
{
"name": "symfony/debug",
- "version": "v3.0.9",
+ "version": "v4.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a"
+ "reference": "8c3e709209ce3b952a31c0f4a31ac7703c3d0226"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a",
- "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/8c3e709209ce3b952a31c0f4a31ac7703c3d0226",
+ "reference": "8c3e709209ce3b952a31c0f4a31ac7703c3d0226",
"shasum": ""
},
"require": {
- "php": ">=5.5.9",
+ "php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
- "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
+ "symfony/http-kernel": "<3.4"
},
"require-dev": {
- "symfony/class-loader": "~2.8|~3.0",
- "symfony/http-kernel": "~2.8|~3.0"
+ "symfony/http-kernel": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -2827,31 +3586,34 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2016-07-30T07:22:48+00:00"
+ "time": "2017-12-12T08:41:51+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.2.8",
+ "version": "v4.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "b8a401f733b43251e1d088c589368b2a94155e40"
+ "reference": "d4face19ed8002eec8280bc1c5ec18130472bf43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b8a401f733b43251e1d088c589368b2a94155e40",
- "reference": "b8a401f733b43251e1d088c589368b2a94155e40",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d4face19ed8002eec8280bc1c5ec18130472bf43",
+ "reference": "d4face19ed8002eec8280bc1c5ec18130472bf43",
"shasum": ""
},
"require": {
- "php": ">=5.5.9"
+ "php": "^7.1.3"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<3.4"
},
"require-dev": {
"psr/log": "~1.0",
- "symfony/config": "~2.8|~3.0",
- "symfony/dependency-injection": "~2.8|~3.0",
- "symfony/expression-language": "~2.8|~3.0",
- "symfony/stopwatch": "~2.8|~3.0"
+ "symfony/config": "~3.4|~4.0",
+ "symfony/dependency-injection": "~3.4|~4.0",
+ "symfony/expression-language": "~3.4|~4.0",
+ "symfony/stopwatch": "~3.4|~4.0"
},
"suggest": {
"symfony/dependency-injection": "",
@@ -2860,7 +3622,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -2887,29 +3649,29 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2017-05-01T14:58:48+00:00"
+ "time": "2017-12-14T19:48:22+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v3.2.8",
+ "version": "v4.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "040651db13cf061827a460cc10f6e36a445c45b4"
+ "reference": "8c2868641d0c4885eee9c12a89c2b695eb1985cd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/040651db13cf061827a460cc10f6e36a445c45b4",
- "reference": "040651db13cf061827a460cc10f6e36a445c45b4",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/8c2868641d0c4885eee9c12a89c2b695eb1985cd",
+ "reference": "8c2868641d0c4885eee9c12a89c2b695eb1985cd",
"shasum": ""
},
"require": {
- "php": ">=5.5.9"
+ "php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -2936,29 +3698,29 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2017-04-12T14:13:17+00:00"
+ "time": "2017-12-14T19:48:22+00:00"
},
{
"name": "symfony/finder",
- "version": "v2.8.20",
+ "version": "v3.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "16d55394b31547e4a8494551b85c9b9915545347"
+ "reference": "dac8d7db537bac7ad8143eb11360a8c2231f251a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/16d55394b31547e4a8494551b85c9b9915545347",
- "reference": "16d55394b31547e4a8494551b85c9b9915545347",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/dac8d7db537bac7ad8143eb11360a8c2231f251a",
+ "reference": "dac8d7db537bac7ad8143eb11360a8c2231f251a",
"shasum": ""
},
"require": {
- "php": ">=5.3.9"
+ "php": "^5.5.9|>=7.0.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.8-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2985,20 +3747,74 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2017-04-12T14:07:15+00:00"
+ "time": "2017-11-05T16:10:10+00:00"
},
{
- "name": "symfony/polyfill-mbstring",
- "version": "v1.3.0",
+ "name": "symfony/options-resolver",
+ "version": "v4.0.2",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
+ "url": "https://github.com/symfony/options-resolver.git",
+ "reference": "75fdda335eb0adbd464089e8a0184c61097808e0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
- "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/75fdda335eb0adbd464089e8a0184c61097808e0",
+ "reference": "75fdda335eb0adbd464089e8a0184c61097808e0",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\OptionsResolver\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony OptionsResolver Component",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "config",
+ "configuration",
+ "options"
+ ],
+ "time": "2017-12-14T19:48:22+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
+ "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
"shasum": ""
},
"require": {
@@ -3010,7 +3826,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3-dev"
+ "dev-master": "1.6-dev"
}
},
"autoload": {
@@ -3044,29 +3860,143 @@
"portable",
"shim"
],
- "time": "2016-11-14T01:06:16+00:00"
+ "time": "2017-10-11T12:05:26+00:00"
},
{
- "name": "symfony/process",
- "version": "v3.2.8",
+ "name": "symfony/polyfill-php70",
+ "version": "v1.6.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0"
+ "url": "https://github.com/symfony/polyfill-php70.git",
+ "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
- "reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
+ "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff",
+ "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff",
"shasum": ""
},
"require": {
- "php": ">=5.5.9"
+ "paragonie/random_compat": "~1.0|~2.0",
+ "php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "1.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php70\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2017-10-11T12:05:26+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php72",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php72.git",
+ "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/6de4f4884b97abbbed9f0a84a95ff2ff77254254",
+ "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php72\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2017-10-11T12:05:26+00:00"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v3.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/process.git",
+ "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/process/zipball/bb3ef65d493a6d57297cad6c560ee04e2a8f5098",
+ "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.5.9|>=7.0.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -3093,29 +4023,29 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2017-04-12T14:13:17+00:00"
+ "time": "2017-12-14T19:40:10+00:00"
},
{
"name": "symfony/stopwatch",
- "version": "v3.2.8",
+ "version": "v4.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
- "reference": "5a0105afb670dbd38f521105c444de1b8e10cfe3"
+ "reference": "ac0e49150555c703fef6b696d8eaba1db7a3ca03"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a0105afb670dbd38f521105c444de1b8e10cfe3",
- "reference": "5a0105afb670dbd38f521105c444de1b8e10cfe3",
+ "url": "https://api.github.com/repos/symfony/stopwatch/zipball/ac0e49150555c703fef6b696d8eaba1db7a3ca03",
+ "reference": "ac0e49150555c703fef6b696d8eaba1db7a3ca03",
"shasum": ""
},
"require": {
- "php": ">=5.5.9"
+ "php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -3142,7 +4072,47 @@
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
- "time": "2017-04-12T14:13:17+00:00"
+ "time": "2017-11-09T12:45:29+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+ "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "time": "2017-04-07T12:08:54+00:00"
},
{
"name": "webignition/readable-duration",
@@ -3189,12 +4159,12 @@
}
],
"aliases": [],
- "minimum-stability": "dev",
+ "minimum-stability": "stable",
"stability-flags": [],
- "prefer-stable": true,
+ "prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "^5.5|^7",
+ "php": ">=7",
"ext-openssl": "*"
},
"platform-dev": []
diff --git a/doc/migrations/0.3.0.md b/doc/migrations/0.3.0.md
new file mode 100644
index 0000000..142ec12
--- /dev/null
+++ b/doc/migrations/0.3.0.md
@@ -0,0 +1,5 @@
+# Migration from 0.2.x to 0.3.x
+
+If you used this client before `0.3.0` via the command line, nothing should change with this release. It is an internal rewrite to Amp v2, which is the underlying concurrency framework.
+
+If you're depending on this package's internals, some things might have changed slightly. A detailed changelog can't be provided. My focus is the public command line API.
\ No newline at end of file
diff --git a/src/AcmeFactory.php b/src/AcmeFactory.php
index c037ada..427e5a1 100644
--- a/src/AcmeFactory.php
+++ b/src/AcmeFactory.php
@@ -4,13 +4,10 @@ namespace Kelunik\AcmeClient;
use Kelunik\Acme\AcmeClient;
use Kelunik\Acme\AcmeService;
-use Kelunik\Acme\KeyPair;
-use Webmozart\Assert\Assert;
+use Kelunik\Acme\Crypto\PrivateKey;
class AcmeFactory {
- public function build($directory, KeyPair $keyPair) {
- Assert::string($directory);
-
+ public function build(string $directory, PrivateKey $keyPair): AcmeService {
return new AcmeService(new AcmeClient($directory, $keyPair));
}
}
\ No newline at end of file
diff --git a/src/Commands/Auto.php b/src/Commands/Auto.php
index ca6a9a8..13caf94 100644
--- a/src/Commands/Auto.php
+++ b/src/Commands/Auto.php
@@ -2,15 +2,19 @@
namespace Kelunik\AcmeClient\Commands;
-use Amp\CoroutineResult;
+use Amp\ByteStream\Message;
+use Amp\File;
use Amp\File\FilesystemException;
-use Amp\Process;
+use Amp\Process\Process;
+use Amp\Promise;
use Kelunik\Acme\AcmeException;
+use Kelunik\AcmeClient;
use Kelunik\AcmeClient\ConfigException;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
+use function Amp\call;
class Auto implements Command {
const EXIT_CONFIG_ERROR = 1;
@@ -28,230 +32,221 @@ class Auto implements Command {
$this->climate = $climate;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
- }
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $configPath = $args->get('config');
- /**
- * @param Manager $args
- * @return \Generator
- */
- private function doExecute(Manager $args) {
- $configPath = $args->get("config");
-
- try {
- $config = Yaml::parse(
- yield \Amp\File\get($configPath)
- );
- } catch (FilesystemException $e) {
- $this->climate->error("Config file ({$configPath}) not found.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- } catch (ParseException $e) {
- $this->climate->error("Config file ({$configPath}) had an invalid format and couldn't be parsed.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- if ($args->defined("server")) {
- $config["server"] = $args->get("server");
- } else if (!isset($config["server"]) && $args->exists("server")) {
- $config["server"] = $args->get("server");
- }
-
- if ($args->defined("storage")) {
- $config["storage"] = $args->get("storage");
- } else if (!isset($config["storage"]) && $args->exists("storage")) {
- $config["storage"] = $args->get("storage");
- }
-
- if (!isset($config["server"])) {
- $this->climate->error("Config file ({$configPath}) didn't have a 'server' set nor was it passed as command line argument.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- if (!isset($config["storage"])) {
- $this->climate->error("Config file ({$configPath}) didn't have a 'storage' set nor was it passed as command line argument.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- if (!isset($config["email"])) {
- $this->climate->error("Config file ({$configPath}) didn't have a 'email' set.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- if (!isset($config["certificates"]) || !is_array($config["certificates"])) {
- $this->climate->error("Config file ({$configPath}) didn't have a 'certificates' section that's an array.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- if (isset($config["challenge-concurrency"]) && !is_numeric($config["challenge-concurrency"])) {
- $this->climate->error("Config file ({$configPath}) defines an invalid 'challenge-concurrency' value.");
- yield new CoroutineResult(self::EXIT_CONFIG_ERROR);
- return;
- }
-
- $concurrency = isset($config["challenge-concurrency"]) ? (int) $config["challenge-concurrency"] : null;
-
- $command = implode(" ", array_map("escapeshellarg", [
- PHP_BINARY,
- $GLOBALS["argv"][0],
- "setup",
- "--server",
- $config["server"],
- "--storage",
- $config["storage"],
- "--email",
- $config["email"],
- ]));
-
- $process = new Process($command);
- $result = (yield $process->exec(Process::BUFFER_ALL));
-
- if ($result->exit !== 0) {
- $this->climate->error("Registration failed ({$result->exit})");
- $this->climate->error($command);
- $this->climate->br()->out($result->stdout);
- $this->climate->br()->error($result->stderr);
- yield new CoroutineResult(self::EXIT_SETUP_ERROR);
- return;
- }
-
- $errors = [];
- $values = [];
-
- foreach ($config["certificates"] as $i => $certificate) {
try {
- $result = (yield \Amp\resolve($this->checkAndIssue($certificate, $config["server"], $config["storage"], $concurrency)));
- $values[$i] = $result;
- } catch (\Exception $e) {
- $errors[$i] = $e;
+ /** @var array $config */
+ $config = Yaml::parse(
+ yield File\get($configPath)
+ );
+ } catch (FilesystemException $e) {
+ $this->climate->error("Config file ({$configPath}) not found.");
+ return self::EXIT_CONFIG_ERROR;
+ } catch (ParseException $e) {
+ $this->climate->error("Config file ({$configPath}) had an invalid format and couldn't be parsed.");
+ return self::EXIT_CONFIG_ERROR;
}
- }
- $status = [
- "no_change" => count(array_filter($values, function($value) { return $value === self::STATUS_NO_CHANGE; })),
- "renewed" => count(array_filter($values, function($value) { return $value === self::STATUS_RENEWED; })),
- "failure" => count($errors),
- ];
+ if ($args->defined('server')) {
+ $config['server'] = $args->get('server');
+ } else if (!isset($config['server']) && $args->exists('server')) {
+ $config['server'] = $args->get('server');
+ }
- if ($status["renewed"] > 0) {
- foreach ($values as $i => $value) {
- if ($value === self::STATUS_RENEWED) {
- $certificate = $config["certificates"][$i];
- $this->climate->info("Certificate for " . implode(", ", array_keys($this->toDomainPathMap($certificate["paths"]))) . " successfully renewed.");
+ if ($args->defined('storage')) {
+ $config['storage'] = $args->get('storage');
+ } else if (!isset($config['storage']) && $args->exists('storage')) {
+ $config['storage'] = $args->get('storage');
+ }
+
+ if (!isset($config['server'])) {
+ $this->climate->error("Config file ({$configPath}) didn't have a 'server' set nor was it passed as command line argument.");
+ return self::EXIT_CONFIG_ERROR;
+ }
+
+ if (!isset($config['storage'])) {
+ $this->climate->error("Config file ({$configPath}) didn't have a 'storage' set nor was it passed as command line argument.");
+ return self::EXIT_CONFIG_ERROR;
+ }
+
+ if (!isset($config['email'])) {
+ $this->climate->error("Config file ({$configPath}) didn't have a 'email' set.");
+ return self::EXIT_CONFIG_ERROR;
+ }
+
+ if (!isset($config['certificates']) || !\is_array($config['certificates'])) {
+ $this->climate->error("Config file ({$configPath}) didn't have a 'certificates' section that's an array.");
+ return self::EXIT_CONFIG_ERROR;
+ }
+
+ if (isset($config['challenge-concurrency']) && !is_numeric($config['challenge-concurrency'])) {
+ $this->climate->error("Config file ({$configPath}) defines an invalid 'challenge-concurrency' value.");
+ return self::EXIT_CONFIG_ERROR;
+ }
+
+ $concurrency = isset($config['challenge-concurrency']) ? (int) $config['challenge-concurrency'] : null;
+
+ $process = new Process([
+ PHP_BINARY,
+ $GLOBALS['argv'][0],
+ 'setup',
+ '--server',
+ $config['server'],
+ '--storage',
+ $config['storage'],
+ '--email',
+ $config['email'],
+ ]);
+
+ $process->start();
+ $exit = yield $process->join();
+
+ if ($exit !== 0) {
+ $this->climate->error("Registration failed ({$exit})");
+ $this->climate->br()->out(yield new Message($process->getStdout()));
+ $this->climate->br()->error(yield new Message($process->getStderr()));
+
+ return self::EXIT_SETUP_ERROR;
+ }
+
+ $errors = [];
+ $values = [];
+
+ foreach ($config['certificates'] as $i => $certificate) {
+ try {
+ $exit = yield call(function () use ($certificate, $config, $concurrency) {
+ return $this->checkAndIssue($certificate, $config['server'], $config['storage'], $concurrency);
+ });
+
+ $values[$i] = $exit;
+ } catch (\Exception $e) {
+ $errors[$i] = $e;
}
}
- }
- if ($status["failure"] > 0) {
- foreach ($errors as $i => $error) {
- $certificate = $config["certificates"][$i];
- $this->climate->error("Issuance for the following domains failed: " . implode(", ", array_keys($this->toDomainPathMap($certificate["paths"]))));
- $this->climate->error("Reason: {$error}");
+ $status = [
+ 'no_change' => \count(\array_filter($values, function ($value) {
+ return $value === self::STATUS_NO_CHANGE;
+ })),
+ 'renewed' => \count(\array_filter($values, function ($value) {
+ return $value === self::STATUS_RENEWED;
+ })),
+ 'failure' => \count($errors),
+ ];
+
+ if ($status['renewed'] > 0) {
+ foreach ($values as $i => $value) {
+ if ($value === self::STATUS_RENEWED) {
+ $certificate = $config['certificates'][$i];
+ $this->climate->info('Certificate for ' . implode(', ', array_keys($this->toDomainPathMap($certificate['paths']))) . ' successfully renewed.');
+ }
+ }
}
- $exitCode = $status["renewed"] > 0
- ? self::EXIT_ISSUANCE_PARTIAL
- : self::EXIT_ISSUANCE_ERROR;
+ if ($status['failure'] > 0) {
+ foreach ($errors as $i => $error) {
+ $certificate = $config['certificates'][$i];
+ $this->climate->error('Issuance for the following domains failed: ' . implode(', ', array_keys($this->toDomainPathMap($certificate['paths']))));
+ $this->climate->error("Reason: {$error}");
+ }
- yield new CoroutineResult($exitCode);
- return;
- }
+ $exitCode = $status['renewed'] > 0
+ ? self::EXIT_ISSUANCE_PARTIAL
+ : self::EXIT_ISSUANCE_ERROR;
- if ($status["renewed"] > 0) {
- yield new CoroutineResult(self::EXIT_ISSUANCE_OK);
- return;
- }
+ return $exitCode;
+ }
+
+ if ($status['renewed'] > 0) {
+ return self::EXIT_ISSUANCE_OK;
+ }
+ });
}
/**
- * @param array $certificate certificate configuration
- * @param string $server server to use for issuance
- * @param string $storage storage directory
+ * @param array $certificate certificate configuration
+ * @param string $server server to use for issuance
+ * @param string $storage storage directory
* @param int|null $concurrency concurrent challenges
+ *
* @return \Generator
* @throws AcmeException if something does wrong
+ * @throws \Throwable
*/
- private function checkAndIssue(array $certificate, $server, $storage, $concurrency = null) {
- $domainPathMap = $this->toDomainPathMap($certificate["paths"]);
+ private function checkAndIssue(array $certificate, string $server, string $storage, int $concurrency = null): \Generator {
+ $domainPathMap = $this->toDomainPathMap($certificate['paths']);
$domains = array_keys($domainPathMap);
$commonName = reset($domains);
- $args = [
+ $process = new Process([
PHP_BINARY,
- $GLOBALS["argv"][0],
- "check",
- "--server",
+ $GLOBALS['argv'][0],
+ 'check',
+ '--server',
$server,
- "--storage",
+ '--storage',
$storage,
- "--name",
+ '--name',
$commonName,
- "--names",
- implode(",", $domains),
- ];
+ '--names',
+ implode(',', $domains),
+ ]);
- $command = implode(" ", array_map("escapeshellarg", $args));
+ $process->start();
+ $exit = yield $process->join();
- $process = new Process($command);
- $result = (yield $process->exec(Process::BUFFER_ALL));
-
- if ($result->exit === 0) {
+ if ($exit === 0) {
// No need for renewal
- yield new CoroutineResult(self::STATUS_NO_CHANGE);
- return;
+ return self::STATUS_NO_CHANGE;
}
- if ($result->exit === 1) {
+ if ($exit === 1) {
// Renew certificate
$args = [
PHP_BINARY,
- $GLOBALS["argv"][0],
- "issue",
- "--server",
+ $GLOBALS['argv'][0],
+ 'issue',
+ '--server',
$server,
- "--storage",
+ '--storage',
$storage,
- "--domains",
- implode(",", $domains),
- "--path",
+ '--domains',
+ implode(',', $domains),
+ '--path',
implode(PATH_SEPARATOR, array_values($domainPathMap)),
];
- if (isset($certificate["user"])) {
- $args[] = "--user";
- $args[] = $certificate["user"];
+ if (isset($certificate['user'])) {
+ $args[] = '--user';
+ $args[] = $certificate['user'];
}
- if (isset($certificate["bits"])) {
- $args[] = "--bits";
- $args[] = $certificate["bits"];
+ if (isset($certificate['bits'])) {
+ $args[] = '--bits';
+ $args[] = $certificate['bits'];
}
if ($concurrency) {
- $args[] = "--challenge-concurrency";
+ $args[] = '--challenge-concurrency';
$args[] = $concurrency;
}
- $command = implode(" ", array_map("escapeshellarg", $args));
+ $process = new Process($args);
+ $process->start();
+ $exit = yield $process->join();
- $process = new Process($command);
- $result = (yield $process->exec(Process::BUFFER_ALL));
-
- if ($result->exit !== 0) {
- throw new AcmeException("Unexpected exit code ({$result->exit}) for '{$command}'." . PHP_EOL . $result->stdout . PHP_EOL . PHP_EOL . $result->stderr);
+ if ($exit !== 0) {
+ // TODO: Print STDOUT and STDERR to file
+ throw new AcmeException("Unexpected exit code ({$exit}) for '{$process->getCommand()}'.");
}
- yield new CoroutineResult(self::STATUS_RENEWED);
- return;
+ return self::STATUS_RENEWED;
}
- throw new AcmeException("Unexpected exit code ({$result->exit}) for '{$command}'." . PHP_EOL . $result->stdout . PHP_EOL . PHP_EOL . $result->stderr);
+ // TODO: Print STDOUT and STDERR to file
+ throw new AcmeException("Unexpected exit code ({$exit}) for '{$process->getCommand()}'.");
}
private function toDomainPathMap(array $paths) {
@@ -308,29 +303,29 @@ MESSAGE;
return $result;
}
- public static function getDefinition() {
- $server = \Kelunik\AcmeClient\getArgumentDescription("server");
- $storage = \Kelunik\AcmeClient\getArgumentDescription("storage");
+ public static function getDefinition(): array {
+ $server = AcmeClient\getArgumentDescription('server');
+ $storage = AcmeClient\getArgumentDescription('storage');
- $server["required"] = false;
- $storage["required"] = false;
+ $server['required'] = false;
+ $storage['required'] = false;
$args = [
- "server" => $server,
- "storage" => $storage,
- "config" => [
- "prefix" => "c",
- "longPrefix" => "config",
- "description" => "Configuration file to read.",
- "required" => true,
+ 'server' => $server,
+ 'storage' => $storage,
+ 'config' => [
+ 'prefix' => 'c',
+ 'longPrefix' => 'config',
+ 'description' => 'Configuration file to read.',
+ 'required' => true,
],
];
- $configPath = \Kelunik\AcmeClient\getConfigPath();
+ $configPath = AcmeClient\getConfigPath();
if ($configPath) {
- $args["config"]["required"] = false;
- $args["config"]["defaultValue"] = $configPath;
+ $args['config']['required'] = false;
+ $args['config']['defaultValue'] = $configPath;
}
return $args;
diff --git a/src/Commands/Check.php b/src/Commands/Check.php
index a1bc930..90c6c24 100644
--- a/src/Commands/Check.php
+++ b/src/Commands/Check.php
@@ -2,12 +2,14 @@
namespace Kelunik\AcmeClient\Commands;
-use Amp\CoroutineResult;
+use Amp\Promise;
+use Kelunik\AcmeClient;
use Kelunik\AcmeClient\Stores\CertificateStore;
use Kelunik\AcmeClient\Stores\CertificateStoreException;
use Kelunik\Certificate\Certificate;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
+use function Amp\call;
class Check implements Command {
private $climate;
@@ -16,76 +18,67 @@ class Check implements Command {
$this->climate = $climate;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
- }
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $server = AcmeClient\resolveServer($args->get('server'));
+ $server = AcmeClient\serverToKeyname($server);
- /**
- * @param Manager $args
- * @return \Generator
- */
- private function doExecute(Manager $args) {
- $server = \Kelunik\AcmeClient\resolveServer($args->get("server"));
- $server = \Kelunik\AcmeClient\serverToKeyname($server);
+ $path = AcmeClient\normalizePath($args->get('storage')) . '/certs/' . $server;
+ $certificateStore = new CertificateStore($path);
- $path = \Kelunik\AcmeClient\normalizePath($args->get("storage")) . "/certs/" . $server;
- $certificateStore = new CertificateStore($path);
+ try {
+ $pem = yield $certificateStore->get($args->get('name'));
+ } catch (CertificateStoreException $e) {
+ $this->climate->br()->error(' Certificate not found.')->br();
- try {
- $pem = (yield $certificateStore->get($args->get("name")));
- } catch (CertificateStoreException $e) {
- $this->climate->br()->error(" Certificate not found.")->br();
-
- yield new CoroutineResult(1);
- return;
- }
-
- $cert = new Certificate($pem);
-
- $this->climate->br();
- $this->climate->whisper(" Certificate is valid until " . date("d.m.Y", $cert->getValidTo()))->br();
-
- if ($args->defined("names")) {
- $names = array_map("trim", explode(",", $args->get("names")));
- $missingNames = array_diff($names, $cert->getNames());
-
- if ($missingNames) {
- $this->climate->comment(" The following names are not covered: " . implode(", ", $missingNames))->br();
-
- yield new CoroutineResult(1);
- return;
+ return 1;
}
- }
- if ($cert->getValidTo() > time() + $args->get("ttl") * 24 * 60 * 60) {
- yield new CoroutineResult(0);
- return;
- }
+ $cert = new Certificate($pem);
- $this->climate->comment(" Certificate is going to expire within the specified " . $args->get("ttl") . " days.")->br();
+ $this->climate->br();
+ $this->climate->whisper(' Certificate is valid until ' . date('d.m.Y', $cert->getValidTo()))->br();
- yield new CoroutineResult(1);
+ if ($args->defined('names')) {
+ $names = array_map('trim', explode(',', $args->get('names')));
+ $missingNames = array_diff($names, $cert->getNames());
+
+ if ($missingNames) {
+ $this->climate->comment(' The following names are not covered: ' . implode(', ', $missingNames))->br();
+
+ return 1;
+ }
+ }
+
+ if ($cert->getValidTo() > time() + $args->get('ttl') * 24 * 60 * 60) {
+ return 0;
+ }
+
+ $this->climate->comment(' Certificate is going to expire within the specified ' . $args->get('ttl') . ' days.')->br();
+
+ return 1;
+ });
}
- public static function getDefinition() {
+ public static function getDefinition(): array {
return [
- "server" => \Kelunik\AcmeClient\getArgumentDescription("server"),
- "storage" => \Kelunik\AcmeClient\getArgumentDescription("storage"),
- "name" => [
- "longPrefix" => "name",
- "description" => "Common name of the certificate to check.",
- "required" => true,
+ 'server' => \Kelunik\AcmeClient\getArgumentDescription('server'),
+ 'storage' => \Kelunik\AcmeClient\getArgumentDescription('storage'),
+ 'name' => [
+ 'longPrefix' => 'name',
+ 'description' => 'Common name of the certificate to check.',
+ 'required' => true,
],
- "ttl" => [
- "longPrefix" => "ttl",
- "description" => "Minimum valid time in days.",
- "defaultValue" => 30,
- "castTo" => "int",
+ 'ttl' => [
+ 'longPrefix' => 'ttl',
+ 'description' => 'Minimum valid time in days.',
+ 'defaultValue' => 30,
+ 'castTo' => 'int',
],
- "names" => [
- "longPrefix" => "names",
- "description" => "Names that must be covered by the certificate identified based on the common name. Names have to be separated by commas.",
- "required" => false,
+ 'names' => [
+ 'longPrefix' => 'names',
+ 'description' => 'Names that must be covered by the certificate identified based on the common name. Names have to be separated by commas.',
+ 'required' => false,
],
];
}
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index c151ba9..b505344 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -2,10 +2,11 @@
namespace Kelunik\AcmeClient\Commands;
+use Amp\Promise;
use League\CLImate\Argument\Manager;
interface Command {
- public function execute(Manager $args);
+ public function execute(Manager $args): Promise;
- public static function getDefinition();
+ public static function getDefinition(): array;
}
\ No newline at end of file
diff --git a/src/Commands/Issue.php b/src/Commands/Issue.php
index bdd69db..4b757e6 100644
--- a/src/Commands/Issue.php
+++ b/src/Commands/Issue.php
@@ -2,13 +2,15 @@
namespace Kelunik\AcmeClient\Commands;
-use Amp\CoroutineResult;
-use Amp\Dns\Record;
-use Exception;
+use Amp\Promise;
use Kelunik\Acme\AcmeException;
use Kelunik\Acme\AcmeService;
-use Kelunik\Acme\KeyPair;
-use Kelunik\Acme\OpenSSLKeyGenerator;
+use Kelunik\Acme\Crypto\Backend\OpensslBackend;
+use Kelunik\Acme\Crypto\PrivateKey;
+use Kelunik\Acme\Crypto\RsaKeyGenerator;
+use Kelunik\Acme\Csr\OpensslCsrGenerator;
+use Kelunik\Acme\Verifiers\Http01;
+use Kelunik\AcmeClient;
use Kelunik\AcmeClient\AcmeFactory;
use Kelunik\AcmeClient\Stores\CertificateStore;
use Kelunik\AcmeClient\Stores\ChallengeStore;
@@ -16,8 +18,8 @@ use Kelunik\AcmeClient\Stores\KeyStore;
use Kelunik\AcmeClient\Stores\KeyStoreException;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
-use stdClass;
-use Throwable;
+use function Amp\call;
+use function Kelunik\Acme\generateKeyAuthorization;
class Issue implements Command {
private $climate;
@@ -28,113 +30,104 @@ class Issue implements Command {
$this->acmeFactory = $acmeFactory;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
- }
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $user = null;
- private function doExecute(Manager $args) {
- if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
- if (posix_geteuid() !== 0) {
- $processUser = posix_getpwnam(posix_geteuid());
- $currentUsername = $processUser["name"];
- $user = $args->get("user") ?: $currentUsername;
+ if (0 !== stripos(PHP_OS, 'WIN')) {
+ if (posix_geteuid() !== 0) {
+ $processUser = posix_getpwnam(posix_geteuid());
+ $currentUsername = $processUser['name'];
+ $user = $args->get('user') ?: $currentUsername;
- if ($currentUsername !== $user) {
- throw new AcmeException("Running this script with --user only works as root!");
+ if ($currentUsername !== $user) {
+ throw new AcmeException('Running this script with --user only works as root!');
+ }
+ } else {
+ $user = $args->get('user') ?: 'www-data';
}
- } else {
- $user = $args->get("user") ?: "www-data";
- }
- }
-
- $domains = array_map("trim", explode(":", str_replace([",", ";"], ":", $args->get("domains"))));
- yield \Amp\resolve($this->checkDnsRecords($domains));
-
- $docRoots = explode(PATH_SEPARATOR, str_replace("\\", "/", $args->get("path")));
- $docRoots = array_map(function ($root) {
- return rtrim($root, "/");
- }, $docRoots);
-
- if (count($domains) < count($docRoots)) {
- throw new AcmeException("Specified more document roots than domains.");
- }
-
- if (count($domains) > count($docRoots)) {
- $docRoots = array_merge(
- $docRoots,
- array_fill(count($docRoots), count($domains) - count($docRoots), end($docRoots))
- );
- }
-
- $keyStore = new KeyStore(\Kelunik\AcmeClient\normalizePath($args->get("storage")));
-
- $server = \Kelunik\AcmeClient\resolveServer($args->get("server"));
- $keyFile = \Kelunik\AcmeClient\serverToKeyname($server);
-
- try {
- $keyPair = (yield $keyStore->get("accounts/{$keyFile}.pem"));
- } catch (KeyStoreException $e) {
- throw new AcmeException("Account key not found, did you run 'bin/acme setup'?", 0, $e);
- }
-
- $this->climate->br();
-
- $acme = $this->acmeFactory->build($server, $keyPair);
- $errors = [];
-
- $concurrency = $args->get("challenge-concurrency");
-
- $domainChunks = array_chunk($domains, \min(20, \max($concurrency, 1)), true);
-
- foreach ($domainChunks as $domainChunk) {
- $promises = [];
-
- foreach ($domainChunk as $i => $domain) {
- $promises[] = \Amp\resolve($this->solveChallenge($acme, $keyPair, $domain, $docRoots[$i]));
}
- list($chunkErrors) = (yield \Amp\any($promises));
+ $domains = array_map('trim', explode(':', str_replace([',', ';'], ':', $args->get('domains'))));
+ yield from $this->checkDnsRecords($domains);
- $errors += $chunkErrors;
- }
+ $docRoots = explode(PATH_SEPARATOR, str_replace("\\", '/', $args->get('path')));
+ $docRoots = array_map(function ($root) {
+ return rtrim($root, '/');
+ }, $docRoots);
- if (!empty($errors)) {
- foreach ($errors as $error) {
- $this->climate->error($error->getMessage());
+ if (\count($domains) < \count($docRoots)) {
+ throw new AcmeException('Specified more document roots than domains.');
}
- throw new AcmeException("Issuance failed, not all challenges could be solved.");
- }
+ if (\count($domains) > \count($docRoots)) {
+ $docRoots = array_merge(
+ $docRoots,
+ array_fill(\count($docRoots), \count($domains) - \count($docRoots), end($docRoots))
+ );
+ }
- $path = "certs/" . $keyFile . "/" . reset($domains) . "/key.pem";
- $bits = $args->get("bits");
+ $keyStore = new KeyStore(\Kelunik\AcmeClient\normalizePath($args->get('storage')));
- try {
- $keyPair = (yield $keyStore->get($path));
- } catch (KeyStoreException $e) {
- $keyPair = (new OpenSSLKeyGenerator)->generate($bits);
- $keyPair = (yield $keyStore->put($path, $keyPair));
- }
+ $server = \Kelunik\AcmeClient\resolveServer($args->get('server'));
+ $keyFile = \Kelunik\AcmeClient\serverToKeyname($server);
- $this->climate->br();
- $this->climate->whisper(" Requesting certificate ...");
+ try {
+ $key = yield $keyStore->get("accounts/{$keyFile}.pem");
+ } catch (KeyStoreException $e) {
+ throw new AcmeException("Account key not found, did you run 'bin/acme setup'?", 0, $e);
+ }
- $location = (yield $acme->requestCertificate($keyPair, $domains));
- $certificates = (yield $acme->pollForCertificate($location));
+ $this->climate->br();
- $path = \Kelunik\AcmeClient\normalizePath($args->get("storage")) . "/certs/" . $keyFile;
- $certificateStore = new CertificateStore($path);
- yield $certificateStore->put($certificates);
+ $acme = $this->acmeFactory->build($server, $key);
+ $concurrency = \min(20, \max($args->get('challenge-concurrency'), 1));
- $this->climate->info(" Successfully issued certificate.");
- $this->climate->info(" See {$path}/" . reset($domains));
- $this->climate->br();
+ /** @var \Throwable[] $errors */
+ list($errors) = yield AcmeClient\concurrentMap($concurrency, $domains, function ($domain, $i) use ($acme, $key, $docRoots, $user) {
+ return $this->solveChallenge($acme, $key, $domain, $docRoots[$i], $user);
+ });
- yield new CoroutineResult(0);
+ if ($errors) {
+ foreach ($errors as $error) {
+ $this->climate->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 {
+ $key = yield $keyStore->get($path);
+ } catch (KeyStoreException $e) {
+ $key = (new RsaKeyGenerator($bits))->generateKey();
+ $key = yield $keyStore->put($path, $key);
+ }
+
+ $this->climate->br();
+ $this->climate->whisper(' Requesting certificate ...');
+
+ $csr = (new OpensslCsrGenerator)->generateCsr($key, $domains);
+
+ $location = yield $acme->requestCertificate($csr);
+ $certificates = yield $acme->pollForCertificate($location);
+
+ $path = AcmeClient\normalizePath($args->get('storage')) . '/certs/' . $keyFile;
+ $certificateStore = new CertificateStore($path);
+ yield $certificateStore->put($certificates);
+
+ $this->climate->info(' Successfully issued certificate.');
+ $this->climate->info(" See {$path}/" . reset($domains));
+ $this->climate->br();
+
+ return 0;
+ });
}
- private function solveChallenge(AcmeService $acme, KeyPair $keyPair, $domain, $path) {
- list($location, $challenges) = (yield $acme->requestChallenges($domain));
+ private function solveChallenge(AcmeService $acme, PrivateKey $key, string $domain, string $path, string $user = null): \Generator {
+ list($location, $challenges) = yield $acme->requestChallenges($domain);
$goodChallenges = $this->findSuitableCombination($challenges);
if (empty($goodChallenges)) {
@@ -144,81 +137,57 @@ class Issue implements Command {
$challenge = $challenges->challenges[reset($goodChallenges)];
$token = $challenge->token;
- if (!preg_match("#^[a-zA-Z0-9-_]+$#", $token)) {
- throw new AcmeException("Protocol violation: Invalid Token!");
+ if (!preg_match('#^[a-zA-Z0-9-_]+$#', $token)) {
+ throw new AcmeException('Protocol violation: Invalid Token!');
}
- $payload = $acme->generateHttp01Payload($keyPair, $token);
+ $payload = generateKeyAuthorization($key, $token, new OpensslBackend);
$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 $challengeStore->put($token, $payload, $user);
- yield $acme->verifyHttp01Challenge($domain, $token, $payload);
+ yield (new Http01)->verifyChallenge($domain, $token, $payload);
yield $acme->answerChallenge($challenge->uri, $payload);
yield $acme->pollForChallenge($location);
$this->climate->comment(" {$domain} is now authorized.");
-
+ } finally {
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;
}
}
- private function checkDnsRecords($domains) {
- $errors = [];
+ private function checkDnsRecords(array $domains): \Generator {
+ $promises = AcmeClient\concurrentMap(10, \array_combine($domains, $domains), 'Amp\Dns\resolve');
+ list($errors) = yield Promise\any($promises);
- $domainChunks = array_chunk($domains, 10, true);
-
- foreach ($domainChunks as $domainChunk) {
- $promises = [];
-
- foreach ($domainChunk as $domain) {
- $promises[$domain] = \Amp\Dns\resolve($domain, [
- "types" => [Record::A, Record::AAAA],
- "hosts" => false,
- ]);
- }
-
- list($chunkErrors) = (yield \Amp\any($promises));
-
- $errors += $chunkErrors;
- }
-
- if (!empty($errors)) {
- $failedDomains = implode(", ", array_keys($errors));
+ if ($errors) {
+ $failedDomains = implode(', ', array_keys($errors));
$reasons = implode("\n\n", array_map(function ($exception) {
- /** @var \Exception|\Throwable $exception */
- return get_class($exception) . ": " . $exception->getMessage();
+ /** @var \Throwable $exception */
+ return \get_class($exception) . ': ' . $exception->getMessage();
}, $errors));
throw new AcmeException("Couldn't resolve the following domains to an IPv4 nor IPv6 record: {$failedDomains}\n\n{$reasons}");
}
}
- private function findSuitableCombination(stdClass $response) {
- $challenges = isset($response->challenges) ? $response->challenges : [];
- $combinations = isset($response->combinations) ? $response->combinations : [];
+ private function findSuitableCombination(\stdClass $response): array {
+ $challenges = $response->challenges ?? [];
+ $combinations = $response->combinations ?? [];
$goodChallenges = [];
foreach ($challenges as $i => $challenge) {
- if ($challenge->type === "http-01") {
+ if ($challenge->type === 'http-01') {
$goodChallenges[] = $i;
}
}
foreach ($goodChallenges as $i => $challenge) {
- if (!in_array([$challenge], $combinations)) {
+ if (!\in_array([$challenge], $combinations, true)) {
unset($goodChallenges[$i]);
}
}
@@ -226,38 +195,38 @@ class Issue implements Command {
return $goodChallenges;
}
- public static function getDefinition() {
+ public static function getDefinition(): array {
return [
- "server" => \Kelunik\AcmeClient\getArgumentDescription("server"),
- "storage" => \Kelunik\AcmeClient\getArgumentDescription("storage"),
- "domains" => [
- "prefix" => "d",
- "longPrefix" => "domains",
- "description" => "Colon / Semicolon / Comma separated list of domains to request a certificate for.",
- "required" => true,
+ 'server' => AcmeClient\getArgumentDescription('server'),
+ 'storage' => AcmeClient\getArgumentDescription('storage'),
+ 'domains' => [
+ 'prefix' => 'd',
+ 'longPrefix' => 'domains',
+ 'description' => 'Colon / Semicolon / Comma separated list of domains to request a certificate for.',
+ 'required' => true,
],
- "path" => [
- "prefix" => "p",
- "longPrefix" => "path",
- "description" => "Colon (Unix) / Semicolon (Windows) separated list of paths to the document roots. The last one will be used for all remaining ones if fewer than the amount of domains is given.",
- "required" => true,
+ 'path' => [
+ 'prefix' => 'p',
+ 'longPrefix' => 'path',
+ 'description' => 'Colon (Unix) / Semicolon (Windows) separated list of paths to the document roots. The last one will be used for all remaining ones if fewer than the amount of domains is given.',
+ 'required' => true,
],
- "user" => [
- "prefix" => "u",
- "longPrefix" => "user",
- "description" => "User running the web server.",
+ 'user' => [
+ 'prefix' => 'u',
+ 'longPrefix' => 'user',
+ 'description' => 'User running the web server.',
],
- "bits" => [
- "longPrefix" => "bits",
- "description" => "Length of the private key in bit.",
- "defaultValue" => 2048,
- "castTo" => "int",
+ 'bits' => [
+ 'longPrefix' => 'bits',
+ 'description' => 'Length of the private key in bit.',
+ 'defaultValue' => 2048,
+ 'castTo' => 'int',
],
- "challenge-concurrency" => [
- "longPrefix" => "challenge-concurrency",
- "description" => "Number of challenges to be solved concurrently.",
- "defaultValue" => 10,
- "castTo" => "int",
+ 'challenge-concurrency' => [
+ 'longPrefix' => 'challenge-concurrency',
+ 'description' => 'Number of challenges to be solved concurrently.',
+ 'defaultValue' => 10,
+ 'castTo' => 'int',
],
];
}
diff --git a/src/Commands/Revoke.php b/src/Commands/Revoke.php
index 1c4e2f3..ebc3709 100644
--- a/src/Commands/Revoke.php
+++ b/src/Commands/Revoke.php
@@ -2,14 +2,17 @@
namespace Kelunik\AcmeClient\Commands;
-use Amp\CoroutineResult;
+use Amp\File;
use Amp\File\FilesystemException;
+use Amp\Promise;
+use Kelunik\AcmeClient;
use Kelunik\AcmeClient\AcmeFactory;
use Kelunik\AcmeClient\Stores\CertificateStore;
use Kelunik\AcmeClient\Stores\KeyStore;
use Kelunik\Certificate\Certificate;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
+use function Amp\call;
class Revoke implements Command {
private $climate;
@@ -20,57 +23,55 @@ class Revoke implements Command {
$this->acmeFactory = $acmeFactory;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $keyStore = new KeyStore(AcmeClient\normalizePath($args->get('storage')));
+
+ $server = AcmeClient\resolveServer($args->get('server'));
+ $keyFile = AcmeClient\serverToKeyname($server);
+
+ $keyPair = yield $keyStore->get("accounts/{$keyFile}.pem");
+ $acme = $this->acmeFactory->build($server, $keyPair);
+
+ $this->climate->br();
+ $this->climate->whisper(' Revoking certificate ...');
+
+ $path = AcmeClient\normalizePath($args->get('storage')) . '/certs/' . $keyFile . '/' . $args->get('name') . '/cert.pem';
+
+ try {
+ $pem = yield File\get($path);
+ $cert = new Certificate($pem);
+ } catch (FilesystemException $e) {
+ throw new \RuntimeException("There's no such certificate (" . $path . ')');
+ }
+
+ if ($cert->getValidTo() < time()) {
+ $this->climate->comment(' Certificate did already expire, no need to revoke it.');
+ }
+
+ $names = $cert->getNames();
+ $this->climate->whisper(' Certificate was valid for ' . \count($names) . ' domains.');
+ $this->climate->whisper(' - ' . implode(PHP_EOL . ' - ', $names) . PHP_EOL);
+
+ yield $acme->revokeCertificate($pem);
+
+ $this->climate->br();
+ $this->climate->info(' Certificate has been revoked.');
+
+ yield (new CertificateStore(AcmeClient\normalizePath($args->get('storage')) . '/certs/' . $keyFile))->delete($args->get('name'));
+
+ return 0;
+ });
}
- private function doExecute(Manager $args) {
- $keyStore = new KeyStore(\Kelunik\AcmeClient\normalizePath($args->get("storage")));
-
- $server = \Kelunik\AcmeClient\resolveServer($args->get("server"));
- $keyFile = \Kelunik\AcmeClient\serverToKeyname($server);
-
- $keyPair = (yield $keyStore->get("accounts/{$keyFile}.pem"));
- $acme = $this->acmeFactory->build($server, $keyPair);
-
- $this->climate->br();
- $this->climate->whisper(" Revoking certificate ...");
-
- $path = \Kelunik\AcmeClient\normalizePath($args->get("storage")) . "/certs/" . $keyFile . "/" . $args->get("name") . "/cert.pem";
-
- try {
- $pem = (yield \Amp\File\get($path));
- $cert = new Certificate($pem);
- } catch (FilesystemException $e) {
- throw new \RuntimeException("There's no such certificate (" . $path . ")");
- }
-
- if ($cert->getValidTo() < time()) {
- $this->climate->comment(" Certificate did already expire, no need to revoke it.");
- }
-
- $names = $cert->getNames();
- $this->climate->whisper(" Certificate was valid for " . count($names) . " domains.");
- $this->climate->whisper(" - " . implode(PHP_EOL . " - ", $names) . PHP_EOL);
-
- yield $acme->revokeCertificate($pem);
-
- $this->climate->br();
- $this->climate->info(" Certificate has been revoked.");
-
- yield (new CertificateStore(\Kelunik\AcmeClient\normalizePath($args->get("storage")) . "/certs/" . $keyFile))->delete($args->get("name"));
-
- yield new CoroutineResult(0);
- }
-
- public static function getDefinition() {
+ public static function getDefinition(): array {
return [
- "server" => \Kelunik\AcmeClient\getArgumentDescription("server"),
- "storage" => \Kelunik\AcmeClient\getArgumentDescription("storage"),
- "name" => [
- "longPrefix" => "name",
- "description" => "Common name of the certificate to be revoked.",
- "required" => true,
+ 'server' => AcmeClient\getArgumentDescription('server'),
+ 'storage' => AcmeClient\getArgumentDescription('storage'),
+ 'name' => [
+ 'longPrefix' => 'name',
+ 'description' => 'Common name of the certificate to be revoked.',
+ 'required' => true,
],
];
}
diff --git a/src/Commands/Setup.php b/src/Commands/Setup.php
index c40bf51..d3d13c0 100644
--- a/src/Commands/Setup.php
+++ b/src/Commands/Setup.php
@@ -2,20 +2,22 @@
namespace Kelunik\AcmeClient\Commands;
-use Amp\CoroutineResult;
+use Amp\Dns;
use Amp\Dns\NoRecordException;
use Amp\Dns\Record;
use Amp\Dns\ResolutionException;
-use InvalidArgumentException;
+use Amp\Promise;
use Kelunik\Acme\AcmeException;
-use Kelunik\Acme\OpenSSLKeyGenerator;
+use Kelunik\Acme\Crypto\RsaKeyGenerator;
use Kelunik\Acme\Registration;
+use Kelunik\AcmeClient;
use Kelunik\AcmeClient\AcmeFactory;
use Kelunik\AcmeClient\Stores\KeyStore;
use Kelunik\AcmeClient\Stores\KeyStoreException;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
use Symfony\Component\Yaml\Yaml;
+use function Amp\call;
class Setup implements Command {
private $climate;
@@ -26,61 +28,55 @@ class Setup implements Command {
$this->acmeFactory = $acmeFactory;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $email = $args->get('email');
+ yield from $this->checkEmail($email);
+
+ $server = AcmeClient\resolveServer($args->get('server'));
+ $keyFile = AcmeClient\serverToKeyname($server);
+
+ $path = "accounts/{$keyFile}.pem";
+ $bits = 4096;
+
+ $keyStore = new KeyStore(\Kelunik\AcmeClient\normalizePath($args->get('storage')));
+
+ $this->climate->br();
+
+ try {
+ $keyPair = yield $keyStore->get($path);
+ $this->climate->whisper(' Using existing private key ...');
+ } catch (KeyStoreException $e) {
+ $this->climate->whisper(' No private key found, generating new one ...');
+
+ $keyPair = (new RsaKeyGenerator($bits))->generateKey();
+ $keyPair = yield $keyStore->put($path, $keyPair);
+
+ $this->climate->whisper(" Generated new private key with {$bits} bits.");
+ }
+
+ $acme = $this->acmeFactory->build($server, $keyPair);
+
+ $this->climate->whisper(' Registering with ' . substr($server, 8) . ' ...');
+
+ /** @var Registration $registration */
+ $registration = yield $acme->register($email);
+ $this->climate->info(' Registration successful. Contacts: ' . implode(', ', $registration->getContact()));
+ $this->climate->br();
+
+ return 0;
+ });
}
- public function doExecute(Manager $args) {
- $email = $args->get("email");
- yield \Amp\resolve($this->checkEmail($email));
-
- $server = \Kelunik\AcmeClient\resolveServer($args->get("server"));
- $keyFile = \Kelunik\AcmeClient\serverToKeyname($server);
-
- $path = "accounts/{$keyFile}.pem";
- $bits = 4096;
-
- $keyStore = new KeyStore(\Kelunik\AcmeClient\normalizePath($args->get("storage")));
-
- $this->climate->br();
-
- try {
- $keyPair = (yield $keyStore->get($path));
- $this->climate->whisper(" Using existing private key ...");
- } catch (KeyStoreException $e) {
- $this->climate->whisper(" No private key found, generating new one ...");
-
- $keyPair = (new OpenSSLKeyGenerator)->generate($bits);
- $keyPair = (yield $keyStore->put($path, $keyPair));
-
- $this->climate->whisper(" Generated new private key with {$bits} bits.");
- }
-
- $acme = $this->acmeFactory->build($server, $keyPair);
-
- $this->climate->whisper(" Registering with " . substr($server, 8) . " ...");
-
- /** @var Registration $registration */
- $registration = (yield $acme->register($email));
- $this->climate->info(" Registration successful. Contacts: " . implode(", ", $registration->getContact()));
- $this->climate->br();
-
- yield new CoroutineResult(0);
- }
-
- 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);
+ private function checkEmail(string $email) {
+ $host = substr($email, strrpos($email, '@') + 1);
if (!$host) {
throw new AcmeException("Invalid contact email: '{$email}'");
}
try {
- yield \Amp\Dns\query($host, Record::MX);
+ yield Dns\query($host, Record::MX);
} catch (NoRecordException $e) {
throw new AcmeException("No MX record defined for '{$host}'");
} catch (ResolutionException $e) {
@@ -88,25 +84,25 @@ class Setup implements Command {
}
}
- public static function getDefinition() {
+ public static function getDefinition(): array {
$args = [
- "server" => \Kelunik\AcmeClient\getArgumentDescription("server"),
- "storage" => \Kelunik\AcmeClient\getArgumentDescription("storage"),
- "email" => [
- "longPrefix" => "email",
- "description" => "E-mail for important issues, will be sent to the ACME server.",
- "required" => true,
+ 'server' => AcmeClient\getArgumentDescription('server'),
+ 'storage' => AcmeClient\getArgumentDescription('storage'),
+ 'email' => [
+ 'longPrefix' => 'email',
+ 'description' => 'E-mail for important issues, will be sent to the ACME server.',
+ 'required' => true,
],
];
- $configPath = \Kelunik\AcmeClient\getConfigPath();
+ $configPath = AcmeClient\getConfigPath();
if ($configPath) {
$config = Yaml::parse(file_get_contents($configPath));
- if (isset($config["email"]) && is_string($config["email"])) {
- $args["email"]["required"] = false;
- $args["email"]["defaultValue"] = $config["email"];
+ if (isset($config['email']) && \is_string($config['email'])) {
+ $args['email']['required'] = false;
+ $args['email']['defaultValue'] = $config['email'];
}
}
diff --git a/src/Commands/Status.php b/src/Commands/Status.php
index 4931aac..1b6bf2b 100644
--- a/src/Commands/Status.php
+++ b/src/Commands/Status.php
@@ -2,12 +2,16 @@
namespace Kelunik\AcmeClient\Commands;
+use Amp\File;
+use Amp\Promise;
use Kelunik\AcmeClient\Stores\CertificateStore;
use Kelunik\AcmeClient\Stores\KeyStore;
use Kelunik\AcmeClient\Stores\KeyStoreException;
use Kelunik\Certificate\Certificate;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
+use function Amp\call;
+use function Kelunik\AcmeClient\getArgumentDescription;
class Status {
private $climate;
@@ -16,64 +20,59 @@ class Status {
$this->climate = $climate;
}
- public function execute(Manager $args) {
- return \Amp\resolve($this->doExecute($args));
- }
+ public function execute(Manager $args): Promise {
+ return call(function () use ($args) {
+ $server = \Kelunik\AcmeClient\resolveServer($args->get('server'));
+ $keyName = \Kelunik\AcmeClient\serverToKeyname($server);
- /**
- * @param Manager $args
- * @return \Generator
- */
- private function doExecute(Manager $args) {
- $server = \Kelunik\AcmeClient\resolveServer($args->get("server"));
- $keyName = \Kelunik\AcmeClient\serverToKeyname($server);
+ $storage = \Kelunik\AcmeClient\normalizePath($args->get('storage'));
- $storage = \Kelunik\AcmeClient\normalizePath($args->get("storage"));
+ try {
+ $keyStore = new KeyStore($storage);
+ yield $keyStore->get("accounts/{$keyName}.pem");
- try {
- $keyStore = new KeyStore($storage);
- yield $keyStore->get("accounts/{$keyName}.pem");
-
- $setup = true;
- } catch (KeyStoreException $e) {
- $setup = false;
- }
-
- $this->climate->br();
- $this->climate->out(" [" . ($setup ? " ✓ " : " ✗ ") . "] " . ($setup ? "Registered on " : "Not yet registered on ") . $server);
- $this->climate->br();
-
- if (yield \Amp\File\exists($storage . "/certs/{$keyName}")) {
- $certificateStore = new CertificateStore($storage . "/certs/{$keyName}");
-
- $domains = (yield \Amp\File\scandir($storage . "/certs/{$keyName}"));
-
- foreach ($domains as $domain) {
- $pem = (yield $certificateStore->get($domain));
- $cert = new Certificate($pem);
-
- $symbol = time() > $cert->getValidTo() ? " ✗ " : " ✓ ";
-
- if (time() < $cert->getValidTo() && time() + $args->get("ttl") * 24 * 60 * 60 > $cert->getValidTo()) {
- $symbol = " ⭮ ";
- }
-
- $this->climate->out(" [" . $symbol . "] " . implode(", ", $cert->getNames()));
+ $setup = true;
+ } catch (KeyStoreException $e) {
+ $setup = false;
}
$this->climate->br();
- }
+ $this->climate->out(' [' . ($setup ? ' ✓ ' : ' ✗ ') . '] ' . ($setup ? 'Registered on ' : 'Not yet registered on ') . $server);
+ $this->climate->br();
+
+ if (yield File\exists($storage . "/certs/{$keyName}")) {
+ $certificateStore = new CertificateStore($storage . "/certs/{$keyName}");
+
+ /** @var array $domains */
+ $domains = yield File\scandir($storage . "/certs/{$keyName}");
+
+ foreach ($domains as $domain) {
+ $pem = yield $certificateStore->get($domain);
+ $cert = new Certificate($pem);
+
+ $symbol = time() > $cert->getValidTo() ? ' ✗ ' : ' ✓ ';
+
+ if (time() < $cert->getValidTo() && time() + $args->get('ttl') * 24 * 60 * 60 > $cert->getValidTo()) {
+ $symbol = ' ⭮ ';
+ }
+
+ $this->climate->out(' [' . $symbol . '] ' . implode(', ', $cert->getNames()));
+ }
+
+ $this->climate->br();
+ }
+ });
}
- public static function getDefinition() {
+ public static function getDefinition(): array {
return [
- "server" => \Kelunik\AcmeClient\getArgumentDescription("server"),
- "storage" => \Kelunik\AcmeClient\getArgumentDescription("storage"),
- "ttl" => [
- "longPrefix" => "ttl",
- "description" => "Minimum valid time in days, shows ⭮ if renewal is required.",
- "defaultValue" => 30,
- "castTo" => "int",
+ 'server' => getArgumentDescription('server'),
+ 'storage' => getArgumentDescription('storage'),
+ 'ttl' => [
+ 'longPrefix' => 'ttl',
+ 'description' => 'Minimum valid time in days, shows ⭮ if renewal is required.',
+ 'defaultValue' => 30,
+ 'castTo' => 'int',
],
];
}
diff --git a/src/Commands/Version.php b/src/Commands/Version.php
index 1ab87c3..8a87201 100644
--- a/src/Commands/Version.php
+++ b/src/Commands/Version.php
@@ -2,9 +2,10 @@
namespace Kelunik\AcmeClient\Commands;
+use Amp\Promise;
+use Amp\Success;
use League\CLImate\Argument\Manager;
use League\CLImate\CLImate;
-use RuntimeException;
class Version implements Command {
private $climate;
@@ -13,63 +14,65 @@ class Version implements Command {
$this->climate = $climate;
}
- public function execute(Manager $args) {
+ public function execute(Manager $args): Promise {
$version = $this->getVersion();
- $buildTime = $this->readFileOr("info/build.time", time());
+ $buildTime = $this->readFileOr('info/build.time', time());
$buildDate = date('M jS Y H:i:s T', (int) trim($buildTime));
- $package = json_decode($this->readFileOr("composer.json", new RuntimeException("No composer.json found.")));
+ $package = json_decode($this->readFileOr('composer.json', new \Exception('No composer.json found.')));
$this->climate->out("┌ kelunik/acme-client @ {$version} (built: {$buildDate})");
- $this->climate->out(($args->defined("deps") ? "│" : "└") . " " . $this->getDescription($package));
+ $this->climate->out(($args->defined('deps') ? '│' : '└') . ' ' . $this->getDescription($package));
- if ($args->defined("deps")) {
- $lockFile = json_decode($this->readFileOr("composer.lock", new RuntimeException("No composer.lock found.")));
+ if ($args->defined('deps')) {
+ $lockFile = json_decode($this->readFileOr('composer.lock', new \Exception('No composer.lock found.')));
$packages = $lockFile->packages;
- for ($i = 0; $i < count($packages); $i++) {
- $link = $i === count($packages) - 1 ? "└──" : "├──";
+ for ($i = 0, $count = \count($packages); $i < $count; $i++) {
+ $link = $i === $count - 1 ? '└──' : '├──';
$this->climate->out("{$link} {$packages[$i]->name} @ {$packages[$i]->version}");
- $link = $i === count($packages) - 1 ? " " : "│ ";
+ $link = $i === $count - 1 ? ' ' : '│ ';
$this->climate->out("{$link} " . $this->getDescription($packages[$i]));
}
}
+
+ return new Success;
}
private function getDescription($package) {
- return \Kelunik\AcmeClient\ellipsis(isset($package->description) ? $package->description : "");
+ return \Kelunik\AcmeClient\ellipsis($package->description ?? '');
}
private function getVersion() {
- if (file_exists(__DIR__ . "/../../.git")) {
+ if (file_exists(__DIR__ . '/../../.git')) {
$version = `git describe --tags`;
} else {
- $version = $this->readFileOr("info/build.version", "-unknown");
+ $version = $this->readFileOr('info/build.version', '-unknown');
}
return substr(trim($version), 1);
}
- private function readFileOr($file, $default = "") {
- if (file_exists(__DIR__ . "/../../" . $file)) {
- return file_get_contents(__DIR__ . "/../../" . $file);
- } else {
- if ($default instanceof \Exception || $default instanceof \Throwable) {
- throw $default;
- }
-
- return $default;
+ private function readFileOr($file, $default = '') {
+ if (file_exists(__DIR__ . '/../../' . $file)) {
+ return file_get_contents(__DIR__ . '/../../' . $file);
}
+
+ if ($default instanceof \Throwable) {
+ throw $default;
+ }
+
+ return $default;
}
- public static function getDefinition() {
+ public static function getDefinition(): array {
return [
- "deps" => [
- "longPrefix" => "deps",
- "description" => "Show also the bundled dependency versions.",
- "noValue" => true,
+ 'deps' => [
+ 'longPrefix' => 'deps',
+ 'description' => 'Show also the bundled dependency versions.',
+ 'noValue' => true,
],
];
}
diff --git a/src/ConfigException.php b/src/ConfigException.php
index e7b9308..f1f88bb 100644
--- a/src/ConfigException.php
+++ b/src/ConfigException.php
@@ -2,4 +2,5 @@
namespace Kelunik\AcmeClient;
-class ConfigException extends \Exception { }
\ No newline at end of file
+class ConfigException extends \Exception {
+}
\ No newline at end of file
diff --git a/src/Stores/CertificateStore.php b/src/Stores/CertificateStore.php
index 42f6033..6404cd1 100644
--- a/src/Stores/CertificateStore.php
+++ b/src/Stores/CertificateStore.php
@@ -2,92 +2,79 @@
namespace Kelunik\AcmeClient\Stores;
-use Amp\CoroutineResult;
+use Amp\File;
use Amp\File\FilesystemException;
-use InvalidArgumentException;
+use Amp\Promise;
use Kelunik\Certificate\Certificate;
-use Webmozart\Assert\Assert;
+use function Amp\call;
+use function Amp\Uri\isValidDnsName;
class CertificateStore {
private $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 __construct(string $root) {
+ $this->root = rtrim(str_replace("\\", '/', $root), '/');
}
- public function get($name) {
- return \Amp\resolve($this->doGet($name));
+ public function get(string $name): Promise {
+ return call(function () use ($name) {
+ try {
+ return yield File\get($this->root . '/' . $name . '/cert.pem');
+ } catch (FilesystemException $e) {
+ throw new CertificateStoreException('Failed to load certificate.', 0, $e);
+ }
+ });
}
- private function doGet($name) {
- Assert::string($name, "Name must be a string. Got: %s");
-
- try {
- $contents = (yield \Amp\File\get($this->root . "/" . $name . "/cert.pem"));
- yield new CoroutineResult($contents);
- } catch (FilesystemException $e) {
- throw new CertificateStoreException("Failed to load certificate.", 0, $e);
- }
- }
-
- public function put(array $certificates) {
- return \Amp\resolve($this->doPut($certificates));
- }
-
- private function doPut(array $certificates) {
- if (empty($certificates)) {
- throw new InvalidArgumentException("Empty array not allowed");
- }
-
- $cert = new Certificate($certificates[0]);
- $commonName = $cert->getSubject()->getCommonName();
-
- if (!$commonName) {
- throw new CertificateStoreException("Certificate doesn't have a common name.");
- }
-
- // See https://github.com/amphp/dns/blob/4c4d450d4af26fc55dc56dcf45ec7977373a38bf/lib/functions.php#L83
- if (isset($commonName[253]) || !preg_match("~^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9]){0,1})(?:\\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9])*$~i", $commonName)) {
- throw new CertificateStoreException("Invalid common name: '{$commonName}'");
- }
-
- try {
- $chain = array_slice($certificates, 1);
- $path = $this->root . "/" . $commonName;
- $realpath = realpath($path);
-
- if (!$realpath && !mkdir($path, 0775, true)) {
- throw new FilesystemException("Couldn't create certificate directory: '{$path}'");
+ public function put(array $certificates): Promise {
+ return call(function () use ($certificates) {
+ if (empty($certificates)) {
+ throw new \Error('Empty array not allowed');
}
- yield \Amp\File\put($path . "/cert.pem", $certificates[0]);
- yield \Amp\File\chmod($path . "/cert.pem", 0644);
+ $cert = new Certificate($certificates[0]);
+ $commonName = $cert->getSubject()->getCommonName();
- yield \Amp\File\put($path . "/fullchain.pem", implode("\n", $certificates));
- yield \Amp\File\chmod($path . "/fullchain.pem", 0644);
+ if (!$commonName) {
+ throw new CertificateStoreException("Certificate doesn't have a common name.");
+ }
- yield \Amp\File\put($path . "/chain.pem", implode("\n", $chain));
- yield \Amp\File\chmod($path . "/chain.pem", 0644);
- } catch (FilesystemException $e) {
- throw new CertificateStoreException("Couldn't save certificates for '{$commonName}'", 0, $e);
- }
+ if (!isValidDnsName($commonName)) {
+ throw new CertificateStoreException("Invalid common name: '{$commonName}'");
+ }
+
+ try {
+ $chain = \array_slice($certificates, 1);
+ $path = $this->root . '/' . $commonName;
+
+ if (!yield File\isdir($path) && !yield File\mkdir($path, 0644, true) && !yield File\isdir($path)) {
+ throw new FilesystemException("Couldn't create certificate directory: '{$path}'");
+ }
+
+ yield File\put($path . '/cert.pem', $certificates[0]);
+ yield File\chmod($path . '/cert.pem', 0644);
+
+ yield File\put($path . '/fullchain.pem', implode("\n", $certificates));
+ yield File\chmod($path . '/fullchain.pem', 0644);
+
+ yield File\put($path . '/chain.pem', implode("\n", $chain));
+ yield File\chmod($path . '/chain.pem', 0644);
+ } catch (FilesystemException $e) {
+ throw new CertificateStoreException("Couldn't save certificates for '{$commonName}'", 0, $e);
+ }
+ });
}
- public function delete($name) {
- return \Amp\resolve($this->doDelete($name));
- }
+ public function delete(string $name): Promise {
+ return call(function () use ($name) {
+ /** @var array $files */
+ $files = yield File\scandir($this->root . '/' . $name);
- private function doDelete($name) {
- Assert::string($name, "Name must be a string. Got: %s");
+ foreach ($files as $file) {
+ yield File\unlink($this->root . '/' . $name . '/' . $file);
+ }
- 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);
+ yield File\rmdir($this->root . '/' . $name);
+ });
}
}
diff --git a/src/Stores/CertificateStoreException.php b/src/Stores/CertificateStoreException.php
index 4ead16f..7d51bf3 100644
--- a/src/Stores/CertificateStoreException.php
+++ b/src/Stores/CertificateStoreException.php
@@ -2,8 +2,5 @@
namespace Kelunik\AcmeClient\Stores;
-use RuntimeException;
-
-class CertificateStoreException extends RuntimeException {
-
+class CertificateStoreException extends \Exception {
}
\ No newline at end of file
diff --git a/src/Stores/ChallengeStore.php b/src/Stores/ChallengeStore.php
index b9a9b1e..d0598c7 100644
--- a/src/Stores/ChallengeStore.php
+++ b/src/Stores/ChallengeStore.php
@@ -2,72 +2,56 @@
namespace Kelunik\AcmeClient\Stores;
-use InvalidArgumentException;
-use Webmozart\Assert\Assert;
+use Amp\File;
+use Amp\Promise;
+use function Amp\call;
class ChallengeStore {
private $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 __construct(string $docroot) {
+ $this->docroot = rtrim(str_replace("\\", '/', $docroot), '/');
}
- public function put($token, $payload, $user = null) {
- return \Amp\resolve($this->doPut($token, $payload, $user));
- }
+ public function put(string $token, string $payload, string $user = null): Promise {
+ return call(function () use ($token, $payload, $user) {
+ $path = $this->docroot . '/.well-known/acme-challenge';
+ $userInfo = null;
- private function doPut($token, $payload, $user = null) {
- Assert::string($token, "Token must be a string. Got: %s");
- Assert::string($payload, "Payload must be a string. Got: %s");
- Assert::nullOrString($user, "User must be a string or null. Got: %s");
+ if (!yield File\exists($this->docroot)) {
+ throw new ChallengeStoreException("Document root doesn't exist: '{$this->docroot}'");
+ }
- $path = $this->docroot . "/.well-known/acme-challenge";
- $realpath = realpath($path);
+ if (!yield File\isdir($path) && !yield File\mkdir($path, 0644, true) && !yield File\isdir($path)) {
+ throw new ChallengeStoreException("Couldn't create key directory: '{$path}'");
+ }
- if (!realpath($this->docroot)) {
- throw new ChallengeStoreException("Document root doesn't exist: '{$this->docroot}'");
- }
-
- if (!$realpath && !@mkdir($path, 0755, true)) {
- throw new ChallengeStoreException("Couldn't create public directory to serve the challenges: '{$path}'");
- }
-
- if ($user) {
- if (!$userInfo = posix_getpwnam($user)) {
+ if ($user && !$userInfo = posix_getpwnam($user)) {
throw new ChallengeStoreException("Unknown user: '{$user}'");
}
- }
- if (isset($userInfo)) {
- yield \Amp\File\chown($this->docroot . "/.well-known", $userInfo["uid"], -1);
- yield \Amp\File\chown($this->docroot . "/.well-known/acme-challenge", $userInfo["uid"], -1);
- }
+ if ($userInfo !== null) {
+ yield File\chown($this->docroot . '/.well-known', $userInfo['uid'], -1);
+ yield File\chown($this->docroot . '/.well-known/acme-challenge', $userInfo['uid'], -1);
+ }
- yield \Amp\File\put("{$path}/{$token}", $payload);
+ yield \Amp\File\put("{$path}/{$token}", $payload);
- if (isset($userInfo)) {
- yield \Amp\File\chown("{$path}/{$token}", $userInfo["uid"], -1);
- }
+ if ($userInfo !== null) {
+ yield \Amp\File\chown("{$path}/{$token}", $userInfo['uid'], -1);
+ }
- yield \Amp\File\chmod("{$path}/{$token}", 0644);
+ yield \Amp\File\chmod("{$path}/{$token}", 0644);
+ });
}
- public function delete($token) {
- return \Amp\resolve($this->doDelete($token));
- }
+ public function delete(string $token): Promise {
+ return call(function () use ($token) {
+ $path = $this->docroot . "/.well-known/acme-challenge/{$token}";
- private function doDelete($token) {
- Assert::string($token, "Token must be a string. Got: %s");
-
- $path = $this->docroot . "/.well-known/acme-challenge/{$token}";
- $realpath = realpath($path);
-
- if ($realpath) {
- yield \Amp\File\unlink($realpath);
- }
+ if (yield File\exists($path)) {
+ yield \Amp\File\unlink($path);
+ }
+ });
}
}
\ No newline at end of file
diff --git a/src/Stores/ChallengeStoreException.php b/src/Stores/ChallengeStoreException.php
index 9b754e9..fc7356b 100644
--- a/src/Stores/ChallengeStoreException.php
+++ b/src/Stores/ChallengeStoreException.php
@@ -2,8 +2,5 @@
namespace Kelunik\AcmeClient\Stores;
-use RuntimeException;
-
-class ChallengeStoreException extends RuntimeException {
-
+class ChallengeStoreException extends \Exception {
}
\ No newline at end of file
diff --git a/src/Stores/KeyStore.php b/src/Stores/KeyStore.php
index 78a6e21..ffa0f16 100644
--- a/src/Stores/KeyStore.php
+++ b/src/Stores/KeyStore.php
@@ -2,85 +2,53 @@
namespace Kelunik\AcmeClient\Stores;
-use Amp\CoroutineResult;
+use Amp\File;
use Amp\File\FilesystemException;
-use InvalidArgumentException;
-use Kelunik\Acme\KeyPair;
+use Amp\Promise;
+use Kelunik\Acme\Crypto\PrivateKey;
+use function Amp\call;
class KeyStore {
private $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 __construct(string $root = '') {
+ $this->root = rtrim(str_replace("\\", '/', $root), '/');
}
- public function get($path) {
- if (!is_string($path)) {
- throw new InvalidArgumentException(sprintf("\$root must be of type string, %s given.", gettype($path)));
- }
+ public function get(string $path): Promise {
+ return call(function () use ($path) {
+ $file = $this->root . '/' . $path;
+ $privateKey = yield File\get($file);
- return \Amp\resolve($this->doGet($path));
- }
+ // Check key here to be valid, PrivateKey doesn't do that, we fail early here
+ $res = openssl_pkey_get_private($privateKey);
- 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);
-
- if (!$realpath) {
- throw new KeyStoreException("File not found: '{$file}'");
- }
-
- $privateKey = (yield \Amp\File\get($realpath));
- $res = openssl_pkey_get_private($privateKey);
-
- if ($res === false) {
- throw new KeyStoreException("Invalid private key: '{$file}'");
- }
-
- $publicKey = openssl_pkey_get_details($res)["key"];
-
- yield new CoroutineResult(new KeyPair($privateKey, $publicKey));
- }
-
- 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($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
- if (!file_exists(dirname($file))) {
- $success = mkdir(dirname($file), 0755, true);
-
- if (!$success) {
- throw new KeyStoreException("Could not create key store directory.");
- }
+ if ($res === false) {
+ throw new KeyStoreException("Invalid private key: '{$file}'");
}
- yield \Amp\File\put($file, $keyPair->getPrivate());
- yield \Amp\File\chmod($file, 0600);
- } catch (FilesystemException $e) {
- throw new KeyStoreException("Could not save key.", 0, $e);
- }
+ return new PrivateKey($privateKey);
+ });
+ }
- yield new CoroutineResult($keyPair);
+ public function put(string $path, PrivateKey $key): Promise {
+ return call(function () use ($path, $key) {
+ $file = $this->root . '/' . $path;
+
+ try {
+ $dir = \dirname($file);
+
+ if (!yield File\isdir($dir) && !yield File\mkdir($dir, 0644, true) && !yield File\isdir($dir)) {
+ throw new FilesystemException("Couldn't create key directory: '{$path}'");
+ }
+
+ yield File\put($file, $key->toPem());
+ yield File\chmod($file, 0600);
+ } catch (FilesystemException $e) {
+ throw new KeyStoreException('Could not save key: ' . $e->getMessage(), 0, $e);
+ }
+
+ return $key;
+ });
}
}
\ No newline at end of file
diff --git a/src/Stores/KeyStoreException.php b/src/Stores/KeyStoreException.php
index 999cf29..7b32bb6 100644
--- a/src/Stores/KeyStoreException.php
+++ b/src/Stores/KeyStoreException.php
@@ -2,8 +2,5 @@
namespace Kelunik\AcmeClient\Stores;
-use RuntimeException;
-
-class KeyStoreException extends RuntimeException {
-
+class KeyStoreException extends \Exception {
}
\ No newline at end of file
diff --git a/src/functions.php b/src/functions.php
index b0c6c74..feb54df 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -2,12 +2,30 @@
namespace Kelunik\AcmeClient;
+use Amp\Sync\LocalSemaphore;
+use Amp\Sync\Lock;
use InvalidArgumentException;
use Kelunik\Acme\AcmeException;
use Phar;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
-use Webmozart\Assert\Assert;
+use function Amp\call;
+use function Amp\coroutine;
+
+function concurrentMap(int $concurrency, array $values, callable $functor): array {
+ $semaphore = new LocalSemaphore($concurrency);
+
+ return \array_map(coroutine(function ($value, $key) use ($semaphore, $functor) {
+ /** @var Lock $lock */
+ $lock = yield $semaphore->acquire();
+
+ try {
+ return yield call($functor, $value, $key);
+ } finally {
+ $lock->release();
+ }
+ }), $values, array_keys($values));
+}
/**
* Suggests a command based on similarity in a list of available commands.
@@ -15,15 +33,13 @@ use Webmozart\Assert\Assert;
* @param string $badCommand invalid command
* @param array $commands list of available commands
* @param int $suggestThreshold similarity threshold
+ *
* @return string suggestion or empty string if no command is similar enough
*/
-function suggestCommand($badCommand, array $commands, $suggestThreshold = 70) {
- Assert::string($badCommand, "Bad command must be a string. Got: %s");
- Assert::integer($suggestThreshold, "Suggest threshold must be an integer. Got: %s");
-
+function suggestCommand(string $badCommand, array $commands, int $suggestThreshold = 70): string {
$badCommand = strtolower($badCommand);
- $bestMatch = "";
+ $bestMatch = '';
$bestMatchPercentage = 0;
$byRefPercentage = 0;
@@ -36,7 +52,7 @@ function suggestCommand($badCommand, array $commands, $suggestThreshold = 70) {
}
}
- return $bestMatchPercentage >= $suggestThreshold ? $bestMatch : "";
+ return $bestMatchPercentage >= $suggestThreshold ? $bestMatch : '';
}
/**
@@ -44,46 +60,46 @@ function suggestCommand($badCommand, array $commands, $suggestThreshold = 70) {
* protocol is passed, it will default to HTTPS.
*
* @param string $uri URI to resolve
+ *
* @return string resolved URI
*/
-function resolveServer($uri) {
- Assert::string($uri, "URI must be a string. Got: %s");
-
+function resolveServer(string $uri): string {
$shortcuts = [
- "letsencrypt" => "https://acme-v01.api.letsencrypt.org/directory",
- "letsencrypt:production" => "https://acme-v01.api.letsencrypt.org/directory",
- "letsencrypt:staging" => "https://acme-staging.api.letsencrypt.org/directory",
+ 'letsencrypt' => 'https://acme-v01.api.letsencrypt.org/directory',
+ 'letsencrypt:production' => 'https://acme-v01.api.letsencrypt.org/directory',
+ 'letsencrypt:staging' => 'https://acme-staging.api.letsencrypt.org/directory',
];
if (isset($shortcuts[$uri])) {
return $shortcuts[$uri];
}
- if (strpos($uri, "/") === false) {
- throw new InvalidArgumentException("Invalid server URI: " . $uri);
+ if (strpos($uri, '/') === false) {
+ throw new InvalidArgumentException('Invalid server URI: ' . $uri);
}
- $protocol = substr($uri, 0, strpos($uri, "://"));
+ $protocol = substr($uri, 0, strpos($uri, '://'));
if (!$protocol || $protocol === $uri) {
return "https://{$uri}";
- } else {
- return $uri;
}
+
+ return $uri;
}
/**
* Transforms a directory URI to a valid filename for usage as key file name.
*
* @param string $server URI to the directory
+ *
* @return string identifier usable as file name
*/
-function serverToKeyname($server) {
- $server = substr($server, strpos($server, "://") + 3);
+function serverToKeyname(string $server): string {
+ $server = substr($server, strpos($server, '://') + 3);
- $keyFile = str_replace("/", ".", $server);
- $keyFile = preg_replace("@[^a-z0-9._-]@", "", $keyFile);
- $keyFile = preg_replace("@\\.+@", ".", $keyFile);
+ $keyFile = str_replace('/', '.', $server);
+ $keyFile = preg_replace('@[^a-z0-9._-]@', '', $keyFile);
+ $keyFile = preg_replace("@\\.+@", '.', $keyFile);
return $keyFile;
}
@@ -93,22 +109,23 @@ function serverToKeyname($server) {
*
* @return bool {@code true} if running as Phar, {@code false} otherwise
*/
-function isPhar() {
- if (!class_exists("Phar")) {
+function isPhar(): bool {
+ if (!class_exists('Phar')) {
return false;
}
- return Phar::running(true) !== "";
+ return Phar::running() !== '';
}
/**
* Normalizes a path. Replaces all backslashes with slashes and removes trailing slashes.
*
* @param string $path path to normalize
+ *
* @return string normalized path
*/
-function normalizePath($path) {
- return rtrim(str_replace("\\", "/", $path), "/");
+function normalizePath(string $path): string {
+ return rtrim(str_replace("\\", '/', $path), '/');
}
/**
@@ -117,14 +134,14 @@ function normalizePath($path) {
* @return string|null Resolves to the config path or null.
*/
function getConfigPath() {
- $paths = isPhar() ? [substr(dirname(Phar::running(true)), strlen("phar://")) . "/acme-client.yml"] : [];
+ $paths = isPhar() ? [\substr(\dirname(Phar::running()), \strlen('phar://')) . '/acme-client.yml'] : [];
- if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
- if ($home = getenv("HOME")) {
- $paths[] = $home . "/.acme-client.yml";
+ if (0 !== stripos(PHP_OS, 'WIN')) {
+ if ($home = getenv('HOME')) {
+ $paths[] = $home . '/.acme-client.yml';
}
- $paths[] = "/etc/acme-client.yml";
+ $paths[] = '/etc/acme-client.yml';
}
do {
@@ -133,7 +150,7 @@ function getConfigPath() {
if (file_exists($path)) {
return $path;
}
- } while (count($paths));
+ } while (\count($paths));
return null;
}
@@ -142,11 +159,12 @@ function getConfigPath() {
* Returns a consistent argument description for CLIMate. Valid arguments are "server" and "storage".
*
* @param string $argument argument name
+ *
* @return array CLIMate argument description
* @throws AcmeException if the provided acme-client.yml file is invalid
* @throws ConfigException if the provided configuration file is invalid
*/
-function getArgumentDescription($argument) {
+function getArgumentDescription($argument): array {
$config = [];
if ($configPath = getConfigPath()) {
@@ -155,11 +173,11 @@ function getArgumentDescription($argument) {
try {
$config = Yaml::parse($configContent);
- if (isset($config["server"]) && !is_string($config["server"])) {
+ if (isset($config['server']) && !\is_string($config['server'])) {
throw new ConfigException("'server' set, but not a string.");
}
- if (isset($config["storage"]) && !is_string($config["storage"])) {
+ if (isset($config['storage']) && !\is_string($config['storage'])) {
throw new ConfigException("'storage' set, but not a string.");
}
} catch (ParseException $e) {
@@ -168,41 +186,41 @@ function getArgumentDescription($argument) {
}
switch ($argument) {
- case "server":
- $argument = [
- "prefix" => "s",
- "longPrefix" => "server",
- "description" => "ACME server to use for registration and issuance of certificates.",
- "required" => true,
+ case 'server':
+ $desc = [
+ 'prefix' => 's',
+ 'longPrefix' => 'server',
+ 'description' => 'ACME server to use for registration and issuance of certificates.',
+ 'required' => true,
];
- if (isset($config["server"])) {
- $argument["required"] = false;
- $argument["defaultValue"] = $config["server"];
+ if (isset($config['server'])) {
+ $desc['required'] = false;
+ $desc['defaultValue'] = $config['server'];
}
- return $argument;
+ return $desc;
- case "storage":
+ case 'storage':
$isPhar = isPhar();
- $argument = [
- "longPrefix" => "storage",
- "description" => "Storage directory for account keys and certificates.",
- "required" => $isPhar,
+ $desc = [
+ 'longPrefix' => 'storage',
+ 'description' => 'Storage directory for account keys and certificates.',
+ 'required' => $isPhar,
];
if (!$isPhar) {
- $argument["defaultValue"] = dirname(__DIR__) . "/data";
- } else if (isset($config["storage"])) {
- $argument["required"] = false;
- $argument["defaultValue"] = $config["storage"];
+ $desc['defaultValue'] = \dirname(__DIR__) . '/data';
+ } else if (isset($config['storage'])) {
+ $desc['required'] = false;
+ $desc['defaultValue'] = $config['storage'];
}
- return $argument;
+ return $desc;
default:
- throw new InvalidArgumentException("Unknown argument: " . $argument);
+ throw new InvalidArgumentException('Unknown argument: ' . $argument);
}
}
@@ -211,27 +229,27 @@ function getArgumentDescription($argument) {
*
* @return string binary callable, shortened based on PATH and CWD
*/
-function getBinary() {
- $binary = "bin/acme";
+function getBinary(): string {
+ $binary = 'bin/acme';
if (isPhar()) {
- $binary = substr(Phar::running(true), strlen("phar://"));
+ $binary = substr(Phar::running(), \strlen('phar://'));
- $path = getenv("PATH");
+ $path = getenv('PATH');
$locations = explode(PATH_SEPARATOR, $path);
- $binaryPath = dirname($binary);
+ $binaryPath = \dirname($binary);
foreach ($locations as $location) {
if ($location === $binaryPath) {
- return substr($binary, strlen($binaryPath) + 1);
+ return substr($binary, \strlen($binaryPath) + 1);
}
}
$cwd = getcwd();
if ($cwd && strpos($binary, $cwd) === 0) {
- $binary = "." . substr($binary, strlen($cwd));
+ $binary = '.' . substr($binary, \strlen($cwd));
}
}
@@ -244,18 +262,19 @@ function getBinary() {
* @param string $text text to shorten
* @param int $max maximum length
* @param string $append appendix when too long
+ *
* @return string shortened string
*/
-function ellipsis($text, $max = 70, $append = "…") {
- if (strlen($text) <= $max) {
+function ellipsis($text, $max = 70, $append = '…'): string {
+ if (\strlen($text) <= $max) {
return $text;
}
$out = substr($text, 0, $max);
- if (strpos($text, " ") === false) {
+ if (strpos($text, ' ') === false) {
return $out . $append;
}
- return preg_replace("/\\w+$/", "", $out) . $append;
+ return preg_replace("/\\w+$/", '', $out) . $append;
}
\ No newline at end of file
diff --git a/test/FunctionsTest.php b/test/FunctionsTest.php
index 4013eea..d86e219 100644
--- a/test/FunctionsTest.php
+++ b/test/FunctionsTest.php
@@ -2,18 +2,20 @@
namespace Kelunik\AcmeClient;
-class FunctionsTest extends \PHPUnit_Framework_TestCase {
+use PHPUnit\Framework\TestCase;
+
+class FunctionsTest extends TestCase {
public function testResolveServer() {
- $this->assertSame("https://acme-v01.api.letsencrypt.org/directory", resolveServer("letsencrypt"));
- $this->assertSame("https://acme-v01.api.letsencrypt.org/directory", resolveServer("letsencrypt:production"));
- $this->assertSame("https://acme-staging.api.letsencrypt.org/directory", resolveServer("letsencrypt:staging"));
- $this->assertSame("https://acme-v01.api.letsencrypt.org/directory", resolveServer("acme-v01.api.letsencrypt.org/directory"));
- $this->assertSame("https://acme-v01.api.letsencrypt.org/directory", resolveServer("https://acme-v01.api.letsencrypt.org/directory"));
+ $this->assertSame('https://acme-v01.api.letsencrypt.org/directory', resolveServer('letsencrypt'));
+ $this->assertSame('https://acme-v01.api.letsencrypt.org/directory', resolveServer('letsencrypt:production'));
+ $this->assertSame('https://acme-staging.api.letsencrypt.org/directory', resolveServer('letsencrypt:staging'));
+ $this->assertSame('https://acme-v01.api.letsencrypt.org/directory', resolveServer('acme-v01.api.letsencrypt.org/directory'));
+ $this->assertSame('https://acme-v01.api.letsencrypt.org/directory', resolveServer('https://acme-v01.api.letsencrypt.org/directory'));
}
public function testSuggestCommand() {
- $this->assertSame("acme", suggestCommand("acme!", ["acme"]));
- $this->assertSame("", suggestCommand("issue", ["acme"]));
+ $this->assertSame('acme', suggestCommand('acme!', ['acme']));
+ $this->assertSame('', suggestCommand('issue', ['acme']));
}
public function testIsPhar() {
@@ -21,9 +23,9 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
}
public function testNormalizePath() {
- $this->assertSame("/etc/foobar", normalizePath("/etc/foobar"));
- $this->assertSame("/etc/foobar", normalizePath("/etc/foobar/"));
- $this->assertSame("/etc/foobar", normalizePath("/etc/foobar/"));
- $this->assertSame("C:/etc/foobar", normalizePath("C:\\etc\\foobar\\"));
+ $this->assertSame('/etc/foobar', normalizePath('/etc/foobar'));
+ $this->assertSame('/etc/foobar', normalizePath('/etc/foobar/'));
+ $this->assertSame('/etc/foobar', normalizePath('/etc/foobar/'));
+ $this->assertSame('C:/etc/foobar', normalizePath("C:\\etc\\foobar\\"));
}
}
\ No newline at end of file