This commit is contained in:
2024-08-05 22:57:28 +08:00
commit 0efda6c02a
1779 changed files with 171774 additions and 0 deletions
@@ -0,0 +1,112 @@
<?php
/*
* This file is part of the Acme PHP project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AcmePhp\Core\Protocol;
/**
* Represent a ACME challenge.
*
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
class AuthorizationChallenge
{
/** @var string */
private $domain;
/** @var string */
private $status;
/** @var string */
private $type;
/** @var string */
private $url;
/** @var string */
private $token;
/** @var string */
private $payload;
public function __construct(string $domain, string $status, string $type, string $url, string $token, string $payload)
{
$this->domain = $domain;
$this->status = $status;
$this->type = $type;
$this->url = $url;
$this->token = $token;
$this->payload = $payload;
}
public function toArray(): array
{
return [
'domain' => $this->getDomain(),
'status' => $this->getStatus(),
'type' => $this->getType(),
'url' => $this->getUrl(),
'token' => $this->getToken(),
'payload' => $this->getPayload(),
];
}
public static function fromArray(array $data): self
{
return new self(
$data['domain'],
$data['status'],
$data['type'],
$data['url'],
$data['token'],
$data['payload']
);
}
public function getDomain(): string
{
return $this->domain;
}
public function getStatus(): string
{
return $this->status;
}
public function isValid(): bool
{
return 'valid' === $this->status;
}
public function isPending(): bool
{
return 'pending' === $this->status || 'processing' === $this->status;
}
public function getType(): string
{
return $this->type;
}
public function getUrl(): string
{
return $this->url;
}
public function getToken(): string
{
return $this->token;
}
public function getPayload(): string
{
return $this->payload;
}
}
+102
View File
@@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Acme PHP project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AcmePhp\Core\Protocol;
use AcmePhp\Core\Exception\AcmeCoreClientException;
/**
* Represent an ACME order.
*
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class CertificateOrder
{
/** @var AuthorizationChallenge[][] */
private $authorizationsChallenges;
/** @var string */
private $orderEndpoint;
/** @var string */
private $status;
public function __construct(array $authorizationsChallenges, string $orderEndpoint = null, string $status = null)
{
foreach ($authorizationsChallenges as &$authorizationChallenges) {
foreach ($authorizationChallenges as &$authorizationChallenge) {
if (\is_array($authorizationChallenge)) {
$authorizationChallenge = AuthorizationChallenge::fromArray($authorizationChallenge);
}
}
}
$this->authorizationsChallenges = $authorizationsChallenges;
$this->orderEndpoint = $orderEndpoint;
$this->status = $status;
}
public function toArray(): array
{
$authorizationsChallenges = array_map(
function ($challenges): array {
return array_map(
function ($challenge): array {
return $challenge->toArray();
},
$challenges
);
},
$this->getAuthorizationsChallenges()
);
return [
'authorizationsChallenges' => $authorizationsChallenges,
'orderEndpoint' => $this->getOrderEndpoint(),
'status' => $this->getStatus(),
];
}
public static function fromArray(array $data): self
{
return new self($data['authorizationsChallenges'], $data['orderEndpoint']);
}
/**
* @return AuthorizationChallenge[][]
*/
public function getAuthorizationsChallenges()
{
return $this->authorizationsChallenges;
}
/**
* @return AuthorizationChallenge[]
*/
public function getAuthorizationChallenges(string $domain): array
{
if (!isset($this->authorizationsChallenges[$domain])) {
throw new AcmeCoreClientException('The order does not contains any authorization challenge for the domain '.$domain);
}
return $this->authorizationsChallenges[$domain];
}
public function getOrderEndpoint(): string
{
return $this->orderEndpoint;
}
public function getStatus(): string
{
return $this->status;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Acme PHP project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AcmePhp\Core\Protocol;
/**
* Represent an ACME External Account to be used for External Account Binding.
*
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
class ExternalAccount
{
/** @var string */
private $id;
/** @var string */
private $hmacKey;
public function __construct(string $id, string $hmacKey)
{
$this->id = $id;
$this->hmacKey = $hmacKey;
}
public function getId(): string
{
return $this->id;
}
public function getHmacKey(): string
{
return $this->hmacKey;
}
}
@@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Acme PHP project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AcmePhp\Core\Protocol;
use Webmozart\Assert\Assert;
/**
* Represent a ACME resources directory.
*
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
class ResourcesDirectory
{
public const NEW_ACCOUNT = 'newAccount';
public const NEW_ORDER = 'newOrder';
public const NEW_NONCE = 'newNonce';
public const REVOKE_CERT = 'revokeCert';
/** @var array */
private $serverResources;
public function __construct(array $serverResources)
{
$this->serverResources = $serverResources;
}
/**
* @return string[]
*/
public static function getResourcesNames(): array
{
return [
self::NEW_ACCOUNT,
self::NEW_ORDER,
self::NEW_NONCE,
self::REVOKE_CERT,
];
}
/**
* Find a resource URL.
*/
public function getResourceUrl(string $resource): string
{
Assert::oneOf(
$resource,
array_keys($this->serverResources),
'Resource type "%s" is not supported by the ACME server (supported: %2$s)'
);
return $this->serverResources[$resource];
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Acme PHP project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AcmePhp\Core\Protocol;
use Webmozart\Assert\Assert;
/**
* @url https://github.com/certbot/certbot/blob/c326c021082dede7c3b2bd411cec3aec6dff0ac5/certbot/constants.py#L124
*/
class RevocationReason
{
public const DEFAULT_REASON = self::REASON_UNSPECIFIED;
public const REASON_UNSPECIFIED = 0;
public const REASON_KEY_COMPROMISE = 1;
public const REASON_AFFILLIATION_CHANGED = 3;
public const REASON_SUPERCEDED = 4;
public const REASON_CESSATION_OF_OPERATION = 5;
/** @var int|null */
private $reasonType;
public function __construct(int $reasonType)
{
Assert::oneOf($reasonType, self::getReasons(), 'Revocation reason type "%s" is not supported by the ACME server (supported: %2$s)');
$this->reasonType = $reasonType;
}
public function getReasonType(): int
{
return $this->reasonType;
}
public static function createDefaultReason(): self
{
return new static(self::DEFAULT_REASON);
}
public static function getFormattedReasons(): array
{
$formatted = [];
foreach (self::getReasonLabelMap() as $reason => $label) {
$formatted[] = $reason.' - '.$label;
}
return $formatted;
}
private static function getReasonLabelMap(): array
{
return [
self::REASON_UNSPECIFIED => 'unspecified',
self::REASON_KEY_COMPROMISE => 'key compromise',
self::REASON_AFFILLIATION_CHANGED => 'affiliation changed',
self::REASON_SUPERCEDED => 'superceded',
self::REASON_CESSATION_OF_OPERATION => 'cessation of operation',
];
}
public static function getReasons(): array
{
return [
self::REASON_UNSPECIFIED,
self::REASON_KEY_COMPROMISE,
self::REASON_AFFILLIATION_CHANGED,
self::REASON_SUPERCEDED,
self::REASON_CESSATION_OF_OPERATION,
];
}
}