aboutsummaryrefslogtreecommitdiffstats
path: root/lib/unstable/Security/Signature/Model/Signatory.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/unstable/Security/Signature/Model/Signatory.php')
-rw-r--r--lib/unstable/Security/Signature/Model/Signatory.php200
1 files changed, 200 insertions, 0 deletions
diff --git a/lib/unstable/Security/Signature/Model/Signatory.php b/lib/unstable/Security/Signature/Model/Signatory.php
new file mode 100644
index 00000000000..6bd50bb1098
--- /dev/null
+++ b/lib/unstable/Security/Signature/Model/Signatory.php
@@ -0,0 +1,200 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace NCU\Security\Signature\Model;
+
+use JsonSerializable;
+use NCU\Security\Signature\Enum\SignatoryStatus;
+use NCU\Security\Signature\Enum\SignatoryType;
+use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
+use OCP\AppFramework\Db\Entity;
+
+/**
+ * model that store keys and details related to host and in use protocol
+ * mandatory details are providerId, host, keyId and public key.
+ * private key is only used for local signatory, used to sign outgoing request
+ *
+ * the pair providerId+host is unique, meaning only one signatory can exist for each host
+ * and protocol
+ *
+ * @experimental 31.0.0
+ *
+ * @method void setProviderId(string $providerId)
+ * @method string getProviderId()
+ * @method string getKeyId()
+ * @method void setKeyIdSum(string $keyIdSum)
+ * @method string getKeyIdSum()
+ * @method void setPublicKey(string $publicKey)
+ * @method string getPublicKey()
+ * @method void setPrivateKey(string $privateKey)
+ * @method string getPrivateKey()
+ * @method void setHost(string $host)
+ * @method string getHost()
+ * @method int getType()
+ * @method void setType(int $type)
+ * @method int getStatus()
+ * @method void setStatus(int $status)
+ * @method void setAccount(?string $account)
+ * @method void setMetadata(array $metadata)
+ * @method ?array getMetadata()
+ * @method void setCreation(int $creation)
+ * @method int getCreation()
+ * @method void setLastUpdated(int $creation)
+ * @method int getLastUpdated()
+ * @psalm-suppress PropertyNotSetInConstructor
+ */
+class Signatory extends Entity implements JsonSerializable {
+ protected string $keyId = '';
+ protected string $keyIdSum = '';
+ protected string $providerId = '';
+ protected string $host = '';
+ protected string $publicKey = '';
+ protected string $privateKey = '';
+ protected ?string $account = '';
+ protected int $type = 9;
+ protected int $status = 1;
+ protected ?array $metadata = null;
+ protected int $creation = 0;
+ protected int $lastUpdated = 0;
+
+ /**
+ * @param bool $local only set to TRUE when managing local signatory
+ *
+ * @experimental 31.0.0
+ */
+ public function __construct(
+ private readonly bool $local = false,
+ ) {
+ $this->addType('providerId', 'string');
+ $this->addType('host', 'string');
+ $this->addType('account', 'string');
+ $this->addType('keyId', 'string');
+ $this->addType('keyIdSum', 'string');
+ $this->addType('publicKey', 'string');
+ $this->addType('metadata', 'json');
+ $this->addType('type', 'integer');
+ $this->addType('status', 'integer');
+ $this->addType('creation', 'integer');
+ $this->addType('lastUpdated', 'integer');
+ }
+
+ /**
+ * @param string $keyId
+ *
+ * @experimental 31.0.0
+ * @throws IdentityNotFoundException if identity cannot be extracted from keyId
+ */
+ public function setKeyId(string $keyId): void {
+ // if set as local (for current instance), we apply some filters.
+ if ($this->local) {
+ // to avoid conflict with duplicate key pairs (ie generated url from the occ command), we enforce https as prefix
+ if (str_starts_with($keyId, 'http://')) {
+ $keyId = 'https://' . substr($keyId, 7);
+ }
+
+ // removing /index.php from generated url
+ $path = parse_url($keyId, PHP_URL_PATH);
+ if (str_starts_with($path, '/index.php/')) {
+ $pos = strpos($keyId, '/index.php');
+ if ($pos !== false) {
+ $keyId = substr_replace($keyId, '', $pos, 10);
+ }
+ }
+ }
+ $this->setter('keyId', [$keyId]); // needed to trigger the update in database
+ $this->setKeyIdSum(hash('sha256', $keyId));
+
+ $this->setHost(self::extractIdentityFromUri($this->getKeyId()));
+ }
+
+ /**
+ * @param SignatoryType $type
+ * @experimental 31.0.0
+ */
+ public function setSignatoryType(SignatoryType $type): void {
+ $this->setType($type->value);
+ }
+
+ /**
+ * @return SignatoryType
+ * @experimental 31.0.0
+ */
+ public function getSignatoryType(): SignatoryType {
+ return SignatoryType::from($this->getType());
+ }
+
+ /**
+ * @param SignatoryStatus $status
+ * @experimental 31.0.0
+ */
+ public function setSignatoryStatus(SignatoryStatus $status): void {
+ $this->setStatus($status->value);
+ }
+
+ /**
+ * @return SignatoryStatus
+ * @experimental 31.0.0
+ */
+ public function getSignatoryStatus(): SignatoryStatus {
+ return SignatoryStatus::from($this->getStatus());
+ }
+
+ /**
+ * @experimental 31.0.0
+ */
+ public function getAccount(): string {
+ return $this->account ?? '';
+ }
+
+ /**
+ * update an entry in metadata
+ *
+ * @param string $key
+ * @param string|int|float|bool|array $value
+ * @experimental 31.0.0
+ */
+ public function setMetaValue(string $key, string|int|float|bool|array $value): void {
+ $this->metadata[$key] = $value;
+ $this->setter('metadata', [$this->metadata]);
+ }
+
+ /**
+ * @return array
+ * @experimental 31.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'keyId' => $this->getKeyId(),
+ 'publicKeyPem' => $this->getPublicKey()
+ ];
+ }
+
+ /**
+ * static is needed to make this easily callable from outside the model
+ *
+ * @param string $uri
+ *
+ * @return string
+ * @throws IdentityNotFoundException if identity cannot be extracted
+ * @experimental 31.0.0
+ */
+ public static function extractIdentityFromUri(string $uri): string {
+ $identity = parse_url($uri, PHP_URL_HOST);
+ $port = parse_url($uri, PHP_URL_PORT);
+ if ($identity === null || $identity === false) {
+ throw new IdentityNotFoundException('cannot extract identity from ' . $uri);
+ }
+
+ if ($port !== null && $port !== false) {
+ $identity .= ':' . $port;
+ }
+
+ return $identity;
+ }
+
+}