]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat(signatory): switch to qbmapper enh/noid/signed-request 45979/head
authorMaxence Lange <maxence@artificial-owl.com>
Fri, 22 Nov 2024 17:20:06 +0000 (16:20 -0100)
committerMaxence Lange <maxence@artificial-owl.com>
Fri, 22 Nov 2024 17:20:14 +0000 (16:20 -0100)
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
29 files changed:
apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
lib/composer/composer/autoload_classmap.php
lib/composer/composer/autoload_static.php
lib/private/OCM/Model/OCMProvider.php
lib/private/OCM/OCMSignatoryManager.php
lib/private/Security/IdentityProof/Manager.php
lib/private/Security/Signature/Db/SignatoryMapper.php [new file with mode: 0644]
lib/private/Security/Signature/Model/IncomingSignedRequest.php
lib/private/Security/Signature/Model/OutgoingSignedRequest.php
lib/private/Security/Signature/Model/Signatory.php [deleted file]
lib/private/Security/Signature/Model/SignedRequest.php
lib/private/Security/Signature/SignatureManager.php
lib/public/OCM/IOCMProvider.php
lib/unstable/Security/Signature/Enum/SignatoryStatus.php [new file with mode: 0644]
lib/unstable/Security/Signature/Enum/SignatoryType.php [new file with mode: 0644]
lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php [new file with mode: 0644]
lib/unstable/Security/Signature/IIncomingSignedRequest.php [new file with mode: 0644]
lib/unstable/Security/Signature/IOutgoingSignedRequest.php [new file with mode: 0644]
lib/unstable/Security/Signature/ISignatoryManager.php
lib/unstable/Security/Signature/ISignatureManager.php
lib/unstable/Security/Signature/ISignedRequest.php [new file with mode: 0644]
lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php [deleted file]
lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php [deleted file]
lib/unstable/Security/Signature/Model/ISignatory.php [deleted file]
lib/unstable/Security/Signature/Model/ISignedRequest.php [deleted file]
lib/unstable/Security/Signature/Model/Signatory.php [new file with mode: 0644]
lib/unstable/Security/Signature/Model/SignatoryStatus.php [deleted file]
lib/unstable/Security/Signature/Model/SignatoryType.php [deleted file]
lib/unstable/Security/Signature/SignatureAlgorithm.php [deleted file]

index e277b9b63896477e55e31e902c0576ff85b8bb7f..a243d286c71b2bdc921d4093f0c69a8c27bbcc1d 100644 (file)
@@ -10,8 +10,8 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException;
 use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureException;
 use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
 use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
 use OC\OCM\OCMSignatoryManager;
 use OCA\CloudFederationAPI\Config;
 use OCA\CloudFederationAPI\ResponseDefinitions;
@@ -373,7 +373,7 @@ class RequestHandlerController extends Controller {
                if ($signedRequest === null) {
                        $instance = $this->getHostFromFederationId($value);
                        try {
-                               $this->signatureManager->searchSignatory($instance);
+                               $this->signatureManager->getSignatory($instance);
                                throw new IncomingRequestException('instance is supposed to sign its request');
                        } catch (SignatoryNotFoundException) {
                                return;
@@ -434,7 +434,7 @@ class RequestHandlerController extends Controller {
                $instance = $this->getHostFromFederationId($entry);
                if ($signedRequest === null) {
                        try {
-                               $this->signatureManager->searchSignatory($instance);
+                               $this->signatureManager->getSignatory($instance);
                                throw new IncomingRequestException('instance is supposed to sign its request');
                        } catch (SignatoryNotFoundException) {
                                return;
index 87e617ed4e6285e9f0e67ef432c6b4227b9eaf93..b3d4c92220cac5608efaab93643321e2069cc414 100644 (file)
@@ -12,6 +12,9 @@ return array(
     'NCU\\Config\\Exceptions\\UnknownKeyException' => $baseDir . '/lib/unstable/Config/Exceptions/UnknownKeyException.php',
     'NCU\\Config\\IUserConfig' => $baseDir . '/lib/unstable/Config/IUserConfig.php',
     'NCU\\Config\\ValueType' => $baseDir . '/lib/unstable/Config/ValueType.php',
+    'NCU\\Security\\Signature\\Enum\\SignatoryStatus' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatoryStatus.php',
+    'NCU\\Security\\Signature\\Enum\\SignatoryType' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatoryType.php',
+    'NCU\\Security\\Signature\\Enum\\SignatureAlgorithm' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php',
     'NCU\\Security\\Signature\\Exceptions\\IdentityNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php',
     'NCU\\Security\\Signature\\Exceptions\\IncomingRequestException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php',
     'NCU\\Security\\Signature\\Exceptions\\InvalidKeyOriginException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php',
@@ -22,15 +25,12 @@ return array(
     'NCU\\Security\\Signature\\Exceptions\\SignatureElementNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php',
     'NCU\\Security\\Signature\\Exceptions\\SignatureException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureException.php',
     'NCU\\Security\\Signature\\Exceptions\\SignatureNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php',
+    'NCU\\Security\\Signature\\IIncomingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/IIncomingSignedRequest.php',
+    'NCU\\Security\\Signature\\IOutgoingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/IOutgoingSignedRequest.php',
     'NCU\\Security\\Signature\\ISignatoryManager' => $baseDir . '/lib/unstable/Security/Signature/ISignatoryManager.php',
     'NCU\\Security\\Signature\\ISignatureManager' => $baseDir . '/lib/unstable/Security/Signature/ISignatureManager.php',
-    'NCU\\Security\\Signature\\Model\\IIncomingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php',
-    'NCU\\Security\\Signature\\Model\\IOutgoingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php',
-    'NCU\\Security\\Signature\\Model\\ISignatory' => $baseDir . '/lib/unstable/Security/Signature/Model/ISignatory.php',
-    'NCU\\Security\\Signature\\Model\\ISignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/ISignedRequest.php',
-    'NCU\\Security\\Signature\\Model\\SignatoryStatus' => $baseDir . '/lib/unstable/Security/Signature/Model/SignatoryStatus.php',
-    'NCU\\Security\\Signature\\Model\\SignatoryType' => $baseDir . '/lib/unstable/Security/Signature/Model/SignatoryType.php',
-    'NCU\\Security\\Signature\\SignatureAlgorithm' => $baseDir . '/lib/unstable/Security/Signature/SignatureAlgorithm.php',
+    'NCU\\Security\\Signature\\ISignedRequest' => $baseDir . '/lib/unstable/Security/Signature/ISignedRequest.php',
+    'NCU\\Security\\Signature\\Model\\Signatory' => $baseDir . '/lib/unstable/Security/Signature/Model/Signatory.php',
     'OCP\\Accounts\\IAccount' => $baseDir . '/lib/public/Accounts/IAccount.php',
     'OCP\\Accounts\\IAccountManager' => $baseDir . '/lib/public/Accounts/IAccountManager.php',
     'OCP\\Accounts\\IAccountProperty' => $baseDir . '/lib/public/Accounts/IAccountProperty.php',
@@ -1929,9 +1929,9 @@ return array(
     'OC\\Security\\RateLimiting\\Limiter' => $baseDir . '/lib/private/Security/RateLimiting/Limiter.php',
     'OC\\Security\\RemoteHostValidator' => $baseDir . '/lib/private/Security/RemoteHostValidator.php',
     'OC\\Security\\SecureRandom' => $baseDir . '/lib/private/Security/SecureRandom.php',
+    'OC\\Security\\Signature\\Db\\SignatoryMapper' => $baseDir . '/lib/private/Security/Signature/Db/SignatoryMapper.php',
     'OC\\Security\\Signature\\Model\\IncomingSignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/IncomingSignedRequest.php',
     'OC\\Security\\Signature\\Model\\OutgoingSignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/OutgoingSignedRequest.php',
-    'OC\\Security\\Signature\\Model\\Signatory' => $baseDir . '/lib/private/Security/Signature/Model/Signatory.php',
     'OC\\Security\\Signature\\Model\\SignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/SignedRequest.php',
     'OC\\Security\\Signature\\SignatureManager' => $baseDir . '/lib/private/Security/Signature/SignatureManager.php',
     'OC\\Security\\TrustedDomainHelper' => $baseDir . '/lib/private/Security/TrustedDomainHelper.php',
index 640924c6579ee9c60d13a909fd552532b81fdf50..31e93679086ec0b0efcbfbc7b737268ee49803b7 100644 (file)
@@ -53,6 +53,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'NCU\\Config\\Exceptions\\UnknownKeyException' => __DIR__ . '/../../..' . '/lib/unstable/Config/Exceptions/UnknownKeyException.php',
         'NCU\\Config\\IUserConfig' => __DIR__ . '/../../..' . '/lib/unstable/Config/IUserConfig.php',
         'NCU\\Config\\ValueType' => __DIR__ . '/../../..' . '/lib/unstable/Config/ValueType.php',
+        'NCU\\Security\\Signature\\Enum\\SignatoryStatus' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatoryStatus.php',
+        'NCU\\Security\\Signature\\Enum\\SignatoryType' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatoryType.php',
+        'NCU\\Security\\Signature\\Enum\\SignatureAlgorithm' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php',
         'NCU\\Security\\Signature\\Exceptions\\IdentityNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php',
         'NCU\\Security\\Signature\\Exceptions\\IncomingRequestException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php',
         'NCU\\Security\\Signature\\Exceptions\\InvalidKeyOriginException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php',
@@ -63,15 +66,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'NCU\\Security\\Signature\\Exceptions\\SignatureElementNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php',
         'NCU\\Security\\Signature\\Exceptions\\SignatureException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureException.php',
         'NCU\\Security\\Signature\\Exceptions\\SignatureNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php',
+        'NCU\\Security\\Signature\\IIncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/IIncomingSignedRequest.php',
+        'NCU\\Security\\Signature\\IOutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/IOutgoingSignedRequest.php',
         'NCU\\Security\\Signature\\ISignatoryManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignatoryManager.php',
         'NCU\\Security\\Signature\\ISignatureManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignatureManager.php',
-        'NCU\\Security\\Signature\\Model\\IIncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php',
-        'NCU\\Security\\Signature\\Model\\IOutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php',
-        'NCU\\Security\\Signature\\Model\\ISignatory' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/ISignatory.php',
-        'NCU\\Security\\Signature\\Model\\ISignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/ISignedRequest.php',
-        'NCU\\Security\\Signature\\Model\\SignatoryStatus' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/SignatoryStatus.php',
-        'NCU\\Security\\Signature\\Model\\SignatoryType' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/SignatoryType.php',
-        'NCU\\Security\\Signature\\SignatureAlgorithm' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/SignatureAlgorithm.php',
+        'NCU\\Security\\Signature\\ISignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignedRequest.php',
+        'NCU\\Security\\Signature\\Model\\Signatory' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/Signatory.php',
         'OCP\\Accounts\\IAccount' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccount.php',
         'OCP\\Accounts\\IAccountManager' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountManager.php',
         'OCP\\Accounts\\IAccountProperty' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountProperty.php',
@@ -1970,9 +1970,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OC\\Security\\RateLimiting\\Limiter' => __DIR__ . '/../../..' . '/lib/private/Security/RateLimiting/Limiter.php',
         'OC\\Security\\RemoteHostValidator' => __DIR__ . '/../../..' . '/lib/private/Security/RemoteHostValidator.php',
         'OC\\Security\\SecureRandom' => __DIR__ . '/../../..' . '/lib/private/Security/SecureRandom.php',
+        'OC\\Security\\Signature\\Db\\SignatoryMapper' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Db/SignatoryMapper.php',
         'OC\\Security\\Signature\\Model\\IncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/IncomingSignedRequest.php',
         'OC\\Security\\Signature\\Model\\OutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/OutgoingSignedRequest.php',
-        'OC\\Security\\Signature\\Model\\Signatory' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/Signatory.php',
         'OC\\Security\\Signature\\Model\\SignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/SignedRequest.php',
         'OC\\Security\\Signature\\SignatureManager' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/SignatureManager.php',
         'OC\\Security\\TrustedDomainHelper' => __DIR__ . '/../../..' . '/lib/private/Security/TrustedDomainHelper.php',
index 95ba83882f22bc242512c1cf9948a8d43dc4d666..32068efe3eb16c948f2a984e6c8f98087f999d48 100644 (file)
@@ -9,8 +9,7 @@ declare(strict_types=1);
 
 namespace OC\OCM\Model;
 
-use NCU\Security\Signature\Model\ISignatory;
-use OC\Security\Signature\Model\Signatory;
+use NCU\Security\Signature\Model\Signatory;
 use OCP\EventDispatcher\IEventDispatcher;
 use OCP\OCM\Events\ResourceTypeRegisterEvent;
 use OCP\OCM\Exceptions\OCMArgumentException;
@@ -27,7 +26,7 @@ class OCMProvider implements IOCMProvider {
        private string $endPoint = '';
        /** @var IOCMResource[] */
        private array $resourceTypes = [];
-       private ?ISignatory $signatory = null;
+       private ?Signatory $signatory = null;
        private bool $emittedEvent = false;
 
        public function __construct(
@@ -154,11 +153,11 @@ class OCMProvider implements IOCMProvider {
                throw new OCMArgumentException('resource not found');
        }
 
-       public function setSignatory(ISignatory $signatory): void {
+       public function setSignatory(Signatory $signatory): void {
                $this->signatory = $signatory;
        }
 
-       public function getSignatory(): ?ISignatory {
+       public function getSignatory(): ?Signatory {
                return $this->signatory;
        }
 
@@ -209,7 +208,7 @@ class OCMProvider implements IOCMProvider {
         *      enabled: bool,
         *      apiVersion: '1.0-proposal1',
         *      endPoint: string,
-        *      publicKey: ISignatory|null,
+        *      publicKey: Signatory|null,
         *      resourceTypes: list<array{
         *          name: string,
         *          shareTypes: list<string>,
index c7eb9ccda5aad8901f553d000c11a535a60f111e..ca0a295468f579dc77cacc513366a44a096611d1 100644 (file)
@@ -9,13 +9,12 @@ declare(strict_types=1);
 
 namespace OC\OCM;
 
+use NCU\Security\Signature\Enum\SignatoryType;
 use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
 use NCU\Security\Signature\ISignatoryManager;
 use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryType;
+use NCU\Security\Signature\Model\Signatory;
 use OC\Security\IdentityProof\Manager;
-use OC\Security\Signature\Model\Signatory;
 use OCP\IAppConfig;
 use OCP\IURLGenerator;
 use OCP\OCM\Exceptions\OCMProviderException;
@@ -68,11 +67,11 @@ class OCMSignatoryManager implements ISignatoryManager {
        /**
         * @inheritDoc
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws IdentityNotFoundException
         * @since 31.0.0
         */
-       public function getLocalSignatory(): ISignatory {
+       public function getLocalSignatory(): Signatory {
                /**
                 * TODO: manage multiple identity (external, internal, ...) to allow a limitation
                 * based on the requested interface (ie. only accept shares from globalscale)
@@ -125,10 +124,10 @@ class OCMSignatoryManager implements ISignatoryManager {
         *
         * @param string $remote
         *
-        * @return ISignatory|null must be NULL if no signatory is found
+        * @return Signatory|null must be NULL if no signatory is found
         * @since 31.0.0
         */
-       public function getRemoteSignatory(string $remote): ?ISignatory {
+       public function getRemoteSignatory(string $remote): ?Signatory {
                try {
                        return $this->getRemoteSignatoryFromHost($remote);
                } catch (OCMProviderException $e) {
@@ -142,11 +141,11 @@ class OCMSignatoryManager implements ISignatoryManager {
         *
         * @param string $host
         *
-        * @return ISignatory|null
+        * @return Signatory|null
         * @throws OCMProviderException on fail to discover ocm services
         * @since 31.0.0
         */
-       public function getRemoteSignatoryFromHost(string $host): ?ISignatory {
+       public function getRemoteSignatoryFromHost(string $host): ?Signatory {
                $ocmProvider = $this->ocmDiscoveryService->discover($host, true);
                $signatory = $ocmProvider->getSignatory();
 
index de0b3fe6bd16e401d244d94aafecda87778400b1..935c18bb81dc7641b6e05d7164e96b29d068850b 100644 (file)
@@ -133,8 +133,8 @@ class Manager {
        public function hasAppKey(string $app, string $name): bool {
                $id = $this->generateAppKeyId($app, $name);
                try {
-                       $this->appData->getFolder($id);
-                       return true;
+                       $folder = $this->appData->getFolder($id);
+                       return ($folder->fileExists('public') && $folder->fileExists('private'));
                } catch (NotFoundException) {
                        return false;
                }
@@ -151,11 +151,11 @@ class Manager {
        public function deleteAppKey(string $app, string $name): bool {
                try {
                        $folder = $this->appData->getFolder($this->generateAppKeyId($app, $name));
+                       $folder->delete();
+                       return true;
                } catch (NotFoundException) {
                        return false;
                }
-               $folder->delete();
-               return true;
        }
 
        private function generateAppKeyId(string $app, string $name): string {
diff --git a/lib/private/Security/Signature/Db/SignatoryMapper.php b/lib/private/Security/Signature/Db/SignatoryMapper.php
new file mode 100644 (file)
index 0000000..47b7932
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Security\Signature\Db;
+
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
+use NCU\Security\Signature\Model\Signatory;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\Exception;
+use OCP\IDBConnection;
+
+/**
+ * @template-extends QBMapper<Signatory>
+ */
+class SignatoryMapper extends QBMapper {
+       public const TABLE = 'sec_signatory';
+
+       public function __construct(
+               IDBConnection $db,
+       ) {
+               parent::__construct($db, self::TABLE, Signatory::class);
+       }
+
+       /**
+        *
+        */
+       public function getByHost(string $host, string $account = ''): Signatory {
+               $qb = $this->db->getQueryBuilder();
+               $qb->select('*')
+                       ->from($this->getTableName())
+                       ->where($qb->expr()->eq('host', $qb->createNamedParameter($host)))
+                       ->andWhere($qb->expr()->eq('account', $qb->createNamedParameter($account)));
+
+               try {
+                       return $this->findEntity($qb);
+               } catch (DoesNotExistException) {
+                       throw new SignatoryNotFoundException('no signatory found');
+               }
+       }
+
+       /**
+        */
+       public function getByKeyId(string $keyId): Signatory {
+               $qb = $this->db->getQueryBuilder();
+               $qb->select('*')
+                       ->from($this->getTableName())
+                       ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
+
+               try {
+                       return $this->findEntity($qb);
+               } catch (DoesNotExistException) {
+                       throw new SignatoryNotFoundException('no signatory found');
+               }
+       }
+
+       /**
+        * @param string $keyId
+        *
+        * @return int
+        * @throws Exception
+        */
+       public function deleteByKeyId(string $keyId): int {
+               $qb = $this->db->getQueryBuilder();
+               $qb->delete($this->getTableName())
+                       ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
+
+               return $qb->executeStatement();
+       }
+
+       /**
+        * @param Signatory $signatory
+        *
+        * @return int
+        */
+       public function updateMetadata(Signatory $signatory): int {
+               $qb = $this->db->getQueryBuilder();
+               $qb->update($this->getTableName())
+                       ->set('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
+                       ->set('last_updated', $qb->createNamedParameter(time()));
+               $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId()))));
+
+               return $qb->executeStatement();
+       }
+
+       /**
+        * @param Signatory $signator
+        */
+       public function updatePublicKey(Signatory $signatory): int {
+               $qb = $this->db->getQueryBuilder();
+               $qb->update($this->getTableName())
+                       ->set('signatory', $qb->createNamedParameter($signatory->getPublicKey()))
+                       ->set('last_updated', $qb->createNamedParameter(time()));
+               $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId()))));
+
+               return $qb->executeStatement();
+       }
+
+       /**
+        * returns a hash version for keyId for better index in the database
+        *
+        * @param string $keyId
+        *
+        * @return string
+        */
+       private function hashKeyId(string $keyId): string {
+               return hash('sha256', $keyId);
+       }
+}
index 77914d1e3b2dcceddd9804c171cc3a1114b451c0..a2bf9fd0bcce4dfac60fce577ed22d3e9cbe4f5a 100644 (file)
@@ -14,9 +14,9 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException;
 use NCU\Security\Signature\Exceptions\SignatoryException;
 use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
 use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
 use OC\Security\Signature\SignatureManager;
 use OCP\IRequest;
 
@@ -141,7 +141,7 @@ class IncomingSignedRequest extends SignedRequest implements
        /**
         * @inheritDoc
         *
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         *
         * @return $this
         * @throws IdentityNotFoundException
@@ -149,7 +149,7 @@ class IncomingSignedRequest extends SignedRequest implements
         * @throws SignatoryException
         * @since 31.0.0
         */
-       public function setSignatory(ISignatory $signatory): self {
+       public function setSignatory(Signatory $signatory): self {
                $identity = \OCP\Server::get(ISignatureManager::class)->extractIdentityFromUri($signatory->getKeyId());
                if ($identity !== $this->getOrigin()) {
                        throw new SignatoryException('keyId from provider is different from the one from signed request');
index d2d5b95e7b64462cfc0e6f774f992d1f719d5305..611a968d1d23ad6295e03c5e1ba033ba1ee5673b 100644 (file)
@@ -9,10 +9,10 @@ declare(strict_types=1);
 namespace OC\Security\Signature\Model;
 
 use JsonSerializable;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
+use NCU\Security\Signature\IOutgoingSignedRequest;
 use NCU\Security\Signature\ISignatoryManager;
 use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\SignatureAlgorithm;
 use OC\Security\Signature\SignatureManager;
 
 /**
@@ -53,7 +53,6 @@ class OutgoingSignedRequest extends SignedRequest implements
 
                $signing = $headerList = [];
                foreach ($headers as $element => $value) {
-                       $value = $headers[$element];
                        $signing[] = $element . ': ' . $value;
                        $headerList[] = $element;
                        if ($element !== '(request-target)') {
diff --git a/lib/private/Security/Signature/Model/Signatory.php b/lib/private/Security/Signature/Model/Signatory.php
deleted file mode 100644 (file)
index b28d2c0..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OC\Security\Signature\Model;
-
-use JsonSerializable;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryStatus;
-use NCU\Security\Signature\Model\SignatoryType;
-
-class Signatory implements ISignatory, JsonSerializable {
-       private string $providerId = '';
-       private string $account = '';
-       private SignatoryType $type = SignatoryType::STATIC;
-       private SignatoryStatus $status = SignatoryStatus::SYNCED;
-       private array $metadata = [];
-       private int $creation = 0;
-       private int $lastUpdated = 0;
-
-       public function __construct(
-               private string $keyId,
-               private readonly string $publicKey,
-               private readonly string $privateKey = '',
-               readonly bool $local = false,
-       ) {
-               // if set as local (for current instance), we apply some filters.
-               if ($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->keyId = $keyId;
-               }
-       }
-
-       public function setProviderId(string $providerId): self {
-               $this->providerId = $providerId;
-               return $this;
-       }
-
-       public function getProviderId(): string {
-               return $this->providerId;
-       }
-
-       public function setAccount(string $account): self {
-               $this->account = $account;
-               return $this;
-       }
-
-       public function getAccount(): string {
-               return $this->account;
-       }
-
-       public function getKeyId(): string {
-               return $this->keyId;
-       }
-
-       public function getPublicKey(): string {
-               return $this->publicKey;
-       }
-
-       public function getPrivateKey(): string {
-               return $this->privateKey;
-       }
-
-       public function setMetadata(array $metadata): self {
-               $this->metadata = $metadata;
-               return $this;
-       }
-
-       public function getMetadata(): array {
-               return $this->metadata;
-       }
-
-       public function setMetaValue(string $key, string|int $value): self {
-               $this->metadata[$key] = $value;
-               return $this;
-       }
-
-       public function setType(SignatoryType $type): self {
-               $this->type = $type;
-               return $this;
-       }
-       public function getType(): SignatoryType {
-               return $this->type;
-       }
-
-       public function setStatus(SignatoryStatus $status): self {
-               $this->status = $status;
-               return $this;
-       }
-
-       public function getStatus(): SignatoryStatus {
-               return $this->status;
-       }
-
-       public function setCreation(int $creation): self {
-               $this->creation = $creation;
-               return $this;
-       }
-
-       public function getCreation(): int {
-               return $this->creation;
-       }
-
-       public function setLastUpdated(int $lastUpdated): self {
-               $this->lastUpdated = $lastUpdated;
-               return $this;
-       }
-
-       public function getLastUpdated(): int {
-               return $this->lastUpdated;
-       }
-
-       public function importFromDatabase(array $row): self {
-               $this->setProviderId($row['provider_id'] ?? '')
-                       ->setAccount($row['account'] ?? '')
-                       ->setMetadata(json_decode($row['metadata'], true) ?? [])
-                       ->setType(SignatoryType::from($row['type'] ?? 9))
-                       ->setStatus(SignatoryStatus::from($row['status'] ?? 1))
-                       ->setCreation($row['creation'] ?? 0)
-                       ->setLastUpdated($row['last_updated'] ?? 0);
-               return $this;
-       }
-
-       public function jsonSerialize(): array {
-               return [
-                       'keyId' => $this->getKeyId(),
-                       'publicKeyPem' => $this->getPublicKey()
-               ];
-       }
-}
index 56853ebade3c5fdbbc5b8205a138f4422317cf44..e974942a9252d44a66ad9dba557a6c7ccdf85b2a 100644 (file)
@@ -11,8 +11,8 @@ namespace OC\Security\Signature\Model;
 use JsonSerializable;
 use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\ISignedRequest;
+use NCU\Security\Signature\ISignedRequest;
+use NCU\Security\Signature\Model\Signatory;
 
 /**
  * @inheritDoc
@@ -24,7 +24,7 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
        private array $signatureElements = [];
        private string $clearSignature = '';
        private string $signedSignature = '';
-       private ?ISignatory $signatory = null;
+       private ?Signatory $signatory = null;
 
        public function __construct(
                private readonly string $body,
@@ -140,11 +140,11 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
        /**
         * @inheritDoc
         *
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         * @return ISignedRequest
         * @since 31.0.0
         */
-       public function setSignatory(ISignatory $signatory): ISignedRequest {
+       public function setSignatory(Signatory $signatory): ISignedRequest {
                $this->signatory = $signatory;
                return $this;
        }
@@ -152,11 +152,11 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
        /**
         * @inheritDoc
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws SignatoryNotFoundException
         * @since 31.0.0
         */
-       public function getSignatory(): ISignatory {
+       public function getSignatory(): Signatory {
                if ($this->signatory === null) {
                        throw new SignatoryNotFoundException();
                }
index 2d895b465abebb81f3aee9bd295b051017ffc4b3..e4f4a2ed1a6122a3a3ca0f59df78b25844bc8f28 100644 (file)
@@ -8,6 +8,8 @@ declare(strict_types=1);
 
 namespace OC\Security\Signature;
 
+use NCU\Security\Signature\Enum\SignatoryType;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
 use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
 use NCU\Security\Signature\Exceptions\IncomingRequestException;
 use NCU\Security\Signature\Exceptions\InvalidKeyOriginException;
@@ -18,19 +20,16 @@ use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureException;
 use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
+use NCU\Security\Signature\IOutgoingSignedRequest;
 use NCU\Security\Signature\ISignatoryManager;
 use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryType;
-use NCU\Security\Signature\SignatureAlgorithm;
+use NCU\Security\Signature\Model\Signatory;
+use OC\Security\Signature\Db\SignatoryMapper;
 use OC\Security\Signature\Model\IncomingSignedRequest;
 use OC\Security\Signature\Model\OutgoingSignedRequest;
-use OC\Security\Signature\Model\Signatory;
 use OCP\DB\Exception as DBException;
 use OCP\IAppConfig;
-use OCP\IDBConnection;
 use OCP\IRequest;
 use Psr\Log\LoggerInterface;
 
@@ -69,13 +68,12 @@ class SignatureManager implements ISignatureManager {
        public const DATE_HEADER = 'D, d M Y H:i:s T';
        public const DATE_TTL = 300;
        public const SIGNATORY_TTL = 86400 * 3;
-       public const TABLE_SIGNATORIES = 'sec_signatory';
        public const BODY_MAXSIZE = 50000; // max size of the payload of the request
        public const APPCONFIG_IDENTITY = 'security.signature.identity';
 
        public function __construct(
                private readonly IRequest $request,
-               private readonly IDBConnection $connection,
+               private readonly SignatoryMapper $mapper,
                private readonly IAppConfig $appConfig,
                private readonly LoggerInterface $logger,
        ) {
@@ -307,31 +305,12 @@ class SignatureManager implements ISignatureManager {
         * @param string $account linked account, should be used when multiple signature can exist for the same
         *                        host
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws SignatoryNotFoundException if entry does not exist in local database
         * @since 31.0.0
         */
-       public function searchSignatory(string $host, string $account = ''): ISignatory {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->select(
-                       'id', 'provider_id', 'host', 'account', 'key_id', 'key_id_sum', 'public_key', 'metadata', 'type',
-                       'status', 'creation', 'last_updated'
-               );
-               $qb->from(self::TABLE_SIGNATORIES);
-               $qb->where($qb->expr()->eq('host', $qb->createNamedParameter($host)));
-               $qb->andWhere($qb->expr()->eq('account', $qb->createNamedParameter($account)));
-
-               $result = $qb->executeQuery();
-               $row = $result->fetch();
-               $result->closeCursor();
-
-               if (!$row) {
-                       throw new SignatoryNotFoundException('no signatory found');
-               }
-
-               $signature = new Signatory($row['key_id'], $row['public_key']);
-
-               return $signature->importFromDatabase($row);
+       public function getSignatory(string $host, string $account = ''): Signatory {
+               return $this->mapper->getByHost($host, $account);
        }
 
 
@@ -386,7 +365,7 @@ class SignatureManager implements ISignatureManager {
         * @param ISignatoryManager $signatoryManager
         * @param IIncomingSignedRequest $signedRequest
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws InvalidKeyOriginException
         * @throws SignatoryNotFoundException
         * @see ISignatoryManager::getRemoteSignatory
@@ -394,7 +373,7 @@ class SignatureManager implements ISignatureManager {
        private function getSaneRemoteSignatory(
                ISignatoryManager $signatoryManager,
                IIncomingSignedRequest $signedRequest,
-       ): ISignatory {
+       ): Signatory {
                $signatory = $signatoryManager->getRemoteSignatory($signedRequest->getOrigin());
                if ($signatory === null) {
                        throw new SignatoryNotFoundException('empty result from getRemoteSignatory');
@@ -406,14 +385,14 @@ class SignatureManager implements ISignatureManager {
                } catch (SignatureElementNotFoundException) {
                        throw new InvalidKeyOriginException('missing keyId');
                }
+               $signatory->setProviderId($signatoryManager->getProviderId());
 
-               return $signatory->setProviderId($signatoryManager->getProviderId());
+               return $signatory;
        }
 
        /**
         * @param IIncomingSignedRequest $signedRequest
         *
-        * @return void
         * @throws SignatureException
         * @throws SignatoryNotFoundException
         */
@@ -477,36 +456,17 @@ class SignatureManager implements ISignatureManager {
        /**
         * @param string $keyId
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws SignatoryNotFoundException
         */
-       private function getStoredSignatory(string $keyId): ISignatory {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->select(
-                       'id', 'provider_id', 'host', 'account', 'key_id', 'key_id_sum', 'public_key', 'metadata', 'type',
-                       'status', 'creation', 'last_updated'
-               );
-               $qb->from(self::TABLE_SIGNATORIES);
-               $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
-
-               $result = $qb->executeQuery();
-               $row = $result->fetch();
-               $result->closeCursor();
-
-               if (!$row) {
-                       throw new SignatoryNotFoundException('no signatory found in local');
-               }
-
-               $signature = new Signatory($row['key_id'], $row['public_key']);
-               $signature->importFromDatabase($row);
-
-               return $signature;
+       private function getStoredSignatory(string $keyId): Signatory {
+               return $this->mapper->getByKeyId($keyId);
        }
 
        /**
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         */
-       private function storeSignatory(ISignatory $signatory): void {
+       private function storeSignatory(Signatory $signatory): void {
                try {
                        $this->insertSignatory($signatory);
                } catch (DBException $e) {
@@ -524,34 +484,20 @@ class SignatureManager implements ISignatureManager {
        }
 
        /**
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         * @throws DBException
         */
-       private function insertSignatory(ISignatory $signatory): void {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->insert(self::TABLE_SIGNATORIES)
-                       ->setValue('provider_id', $qb->createNamedParameter($signatory->getProviderId()))
-                       ->setValue('host', $qb->createNamedParameter($this->extractIdentityFromUri($signatory->getKeyId())))
-                       ->setValue('account', $qb->createNamedParameter($signatory->getAccount()))
-                       ->setValue('key_id', $qb->createNamedParameter($signatory->getKeyId()))
-                       ->setValue('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
-                       ->setValue('public_key', $qb->createNamedParameter($signatory->getPublicKey()))
-                       ->setValue('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
-                       ->setValue('type', $qb->createNamedParameter($signatory->getType()->value))
-                       ->setValue('status', $qb->createNamedParameter($signatory->getStatus()->value))
-                       ->setValue('creation', $qb->createNamedParameter(time()))
-                       ->setValue('last_updated', $qb->createNamedParameter(time()));
-
-               $qb->executeStatement();
+       private function insertSignatory(Signatory $signatory): void {
+               $this->mapper->insert($signatory);
        }
 
        /**
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         *
         * @throws SignatoryNotFoundException
         * @throws SignatoryConflictException
         */
-       private function updateKnownSignatory(ISignatory $signatory): void {
+       private function updateKnownSignatory(Signatory $signatory): void {
                $knownSignatory = $this->getStoredSignatory($signatory->getKeyId());
                switch ($signatory->getType()) {
                        case SignatoryType::FORGIVABLE:
@@ -577,12 +523,12 @@ class SignatureManager implements ISignatureManager {
        /**
         * This is called when a remote signatory does not exist anymore
         *
-        * @param ISignatory|null $knownSignatory NULL is not known
+        * @param Signatory|null $knownSignatory NULL is not known
         *
         * @throws SignatoryConflictException
         * @throws SignatoryNotFoundException
         */
-       private function manageDeprecatedSignatory(?ISignatory $knownSignatory): void {
+       private function manageDeprecatedSignatory(?Signatory $knownSignatory): void {
                switch ($knownSignatory?->getType()) {
                        case null: // unknown in local database
                        case SignatoryType::FORGIVABLE: // who cares ?
@@ -600,38 +546,15 @@ class SignatureManager implements ISignatureManager {
        }
 
 
-       private function updateSignatoryPublicKey(ISignatory $signatory): void {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->update(self::TABLE_SIGNATORIES)
-                       ->set('signatory', $qb->createNamedParameter($signatory->getPublicKey()))
-                       ->set('last_updated', $qb->createNamedParameter(time()));
-
-               $qb->where(
-                       $qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
-               );
-               $qb->executeStatement();
+       private function updateSignatoryPublicKey(Signatory $signatory): void {
+               $this->mapper->updatePublicKey($signatory);
        }
 
-       private function updateSignatoryMetadata(ISignatory $signatory): void {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->update(self::TABLE_SIGNATORIES)
-                       ->set('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
-                       ->set('last_updated', $qb->createNamedParameter(time()));
-
-               $qb->where(
-                       $qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
-               );
-               $qb->executeStatement();
+       private function updateSignatoryMetadata(Signatory $signatory): void {
+               $this->mapper->updateMetadata($signatory);
        }
 
        private function deleteSignatory(string $keyId): void {
-               $qb = $this->connection->getQueryBuilder();
-               $qb->delete(self::TABLE_SIGNATORIES)
-                       ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
-               $qb->executeStatement();
-       }
-
-       private function hashKeyId(string $keyId): string {
-               return hash('sha256', $keyId);
+               $this->mapper->deleteByKeyId($keyId);
        }
 }
index dd36a1c6057154d09430633d83f97bf9670f879a..cd2a59ebd5e0a0f09c5959475bbbeec61ff52643 100644 (file)
@@ -6,11 +6,10 @@ declare(strict_types=1);
  * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  * SPDX-License-Identifier: AGPL-3.0-or-later
  */
-
 namespace OCP\OCM;
 
 use JsonSerializable;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
 use OCP\OCM\Exceptions\OCMArgumentException;
 use OCP\OCM\Exceptions\OCMProviderException;
 
@@ -124,18 +123,18 @@ interface IOCMProvider extends JsonSerializable {
        /**
         * store signatory (public/private key pair) to sign outgoing/incoming request
         *
-        * @param ISignatory $signatory
+        * @param Signatory $signatory
         * @since 31.0.0
         */
-       public function setSignatory(ISignatory $signatory): void;
+       public function setSignatory(Signatory $signatory): void;
 
        /**
         * signatory (public/private key pair) used to sign outgoing/incoming request
         *
-        * @return ISignatory|null returns null if no ISignatory available
+        * @return Signatory|null returns null if no Signatory available
         * @since 31.0.0
         */
-       public function getSignatory(): ?ISignatory;
+       public function getSignatory(): ?Signatory;
 
        /**
         * import data from an array
@@ -153,7 +152,7 @@ interface IOCMProvider extends JsonSerializable {
         *     enabled: bool,
         *     apiVersion: '1.0-proposal1',
         *     endPoint: string,
-        *     publicKey: ISignatory|null,
+        *     publicKey: Signatory|null,
         *     resourceTypes: list<array{
         *         name: string,
         *         shareTypes: list<string>,
diff --git a/lib/unstable/Security/Signature/Enum/SignatoryStatus.php b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
new file mode 100644 (file)
index 0000000..9c77cf9
--- /dev/null
@@ -0,0 +1,25 @@
+<?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\Enum;
+
+/**
+ * current status of signatory. is it trustable or not ?
+ *
+ * - SYNCED = the remote instance is trustable.
+ * - BROKEN = the remote instance does not use the same key pairs than previously
+ *
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+enum SignatoryStatus: int {
+       /** @since 31.0.0 */
+       case SYNCED = 1;
+       /** @since 31.0.0 */
+       case BROKEN = 9;
+}
diff --git a/lib/unstable/Security/Signature/Enum/SignatoryType.php b/lib/unstable/Security/Signature/Enum/SignatoryType.php
new file mode 100644 (file)
index 0000000..86a766d
--- /dev/null
@@ -0,0 +1,31 @@
+<?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\Enum;
+
+/**
+ * type of link between local and remote instance
+ *
+ * - FORGIVABLE = the keypair can be deleted and refreshed anytime; silently
+ * - REFRESHABLE = the keypair can be refreshed but a notice will be generated
+ * - TRUSTED = any changes of keypair will require human interaction, warning will be issued
+ * - STATIC = error will be issued on conflict,  assume keypair cannot be reset.
+ *
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+enum SignatoryType: int {
+       /** @since 31.0.0 */
+       case FORGIVABLE = 1; // no notice on refresh
+       /** @since 31.0.0 */
+       case REFRESHABLE = 4; // notice on refresh
+       /** @since 31.0.0 */
+       case TRUSTED = 8; // warning on refresh
+       /** @since 31.0.0 */
+       case STATIC = 9; // error on refresh
+}
diff --git a/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
new file mode 100644 (file)
index 0000000..94996d1
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace NCU\Security\Signature\Enum;
+
+/**
+ * list of available algorithm when signing payload
+ *
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+enum SignatureAlgorithm: string {
+       /** @since 31.0.0 */
+       case SHA256 = 'sha256';
+       /** @since 31.0.0 */
+       case SHA512 = 'sha512';
+}
diff --git a/lib/unstable/Security/Signature/IIncomingSignedRequest.php b/lib/unstable/Security/Signature/IIncomingSignedRequest.php
new file mode 100644 (file)
index 0000000..f6ab98d
--- /dev/null
@@ -0,0 +1,59 @@
+<?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;
+
+use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
+use OCP\IRequest;
+
+/**
+ * model wrapping an actual incoming request, adding details about the signature and the
+ * authenticity of the origin of the request.
+ *
+ * @see ISignatureManager for details on signature
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+interface IIncomingSignedRequest extends ISignedRequest {
+       /**
+        * returns the base IRequest
+        *
+        * @return IRequest
+        * @since 31.0.0
+        */
+       public function getRequest(): IRequest;
+
+       /**
+        * set the hostname at the source of the request,
+        * based on the keyId defined in the signature header.
+        *
+        * @param string $origin
+        * @return IIncomingSignedRequest
+        * @since 31.0.0
+        */
+       public function setOrigin(string $origin): IIncomingSignedRequest;
+
+       /**
+        * get the hostname at the source of the base request.
+        * based on the keyId defined in the signature header.
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getOrigin(): string;
+
+       /**
+        * returns the keyId extracted from the signature headers.
+        * keyId is a mandatory entry in the headers of a signed request.
+        *
+        * @return string
+        * @throws SignatureElementNotFoundException
+        * @since 31.0.0
+        */
+       public function getKeyId(): string;
+}
diff --git a/lib/unstable/Security/Signature/IOutgoingSignedRequest.php b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
new file mode 100644 (file)
index 0000000..7b5df25
--- /dev/null
@@ -0,0 +1,94 @@
+<?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;
+
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
+
+/**
+ * extends ISignedRequest to add info requested at the generation of the signature
+ *
+ * @see ISignatureManager for details on signature
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+interface IOutgoingSignedRequest extends ISignedRequest {
+       /**
+        * set the host of the recipient of the request.
+        *
+        * @param string $host
+        * @return IOutgoingSignedRequest
+        * @since 31.0.0
+        */
+       public function setHost(string $host): IOutgoingSignedRequest;
+
+       /**
+        * get the host of the recipient of the request.
+        * - on incoming request, this is the local hostname of current instance.
+        * - on outgoing request, this is the remote instance.
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getHost(): string;
+
+       /**
+        * add a key/value pair to the headers of the request
+        *
+        * @param string $key
+        * @param string|int|float $value
+        *
+        * @return IOutgoingSignedRequest
+        * @since 31.0.0
+        */
+       public function addHeader(string $key, string|int|float $value): IOutgoingSignedRequest;
+
+       /**
+        * returns list of headers value that will be added to the base request
+        *
+        * @return array
+        * @since 31.0.0
+        */
+       public function getHeaders(): array;
+
+       /**
+        * set the ordered list of used headers in the Signature
+        *
+        * @param list<string> $list
+        *
+        * @return IOutgoingSignedRequest
+        * @since 31.0.0
+        */
+       public function setHeaderList(array $list): IOutgoingSignedRequest;
+
+       /**
+        * returns ordered list of used headers in the Signature
+        *
+        * @return list<string>
+        * @since 31.0.0
+        */
+       public function getHeaderList(): array;
+
+       /**
+        * set algorithm to be used to sign the signature
+        *
+        * @param SignatureAlgorithm $algorithm
+        *
+        * @return IOutgoingSignedRequest
+        * @since 31.0.0
+        */
+       public function setAlgorithm(SignatureAlgorithm $algorithm): IOutgoingSignedRequest;
+
+       /**
+        * returns the algorithm set to sign the signature
+        *
+        * @return SignatureAlgorithm
+        * @since 31.0.0
+        */
+       public function getAlgorithm(): SignatureAlgorithm;
+}
index 19ba83a4206dd7cd1f43424b926334dd2eb318af..20133de4c9ce3c2caa5e321c56df4145ea422c74 100644 (file)
@@ -8,7 +8,7 @@ declare(strict_types=1);
  */
 namespace NCU\Security\Signature;
 
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
 
 /**
  * ISignatoryManager contains a group of method that will help
@@ -51,10 +51,10 @@ interface ISignatoryManager {
         *
         * Used to sign outgoing request
         *
-        * @return ISignatory
+        * @return Signatory
         * @since 31.0.0
         */
-       public function getLocalSignatory(): ISignatory;
+       public function getLocalSignatory(): Signatory;
 
        /**
         * retrieve details and generate signatory from remote instance.
@@ -64,8 +64,8 @@ interface ISignatoryManager {
         *
         * @param string $remote
         *
-        * @return ISignatory|null must be NULL if no signatory is found
+        * @return Signatory|null must be NULL if no signatory is found
         * @since 31.0.0
         */
-       public function getRemoteSignatory(string $remote): ?ISignatory;
+       public function getRemoteSignatory(string $remote): ?Signatory;
 }
index 1969b970aa68d152c2dc5ef29aad677929fc585d..c614a16cd92aa59849a774399241bea4ceaad116 100644 (file)
@@ -13,9 +13,7 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException;
 use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
 use NCU\Security\Signature\Exceptions\SignatureException;
 use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
 
 /**
  * ISignatureManager is a service integrated to core that provide tools
@@ -99,11 +97,11 @@ interface ISignatureManager {
         * @param string $host remote host
         * @param string $account linked account, should be used when multiple signature can exist for the same host
         *
-        * @return ISignatory
+        * @return Signatory
         * @throws SignatoryNotFoundException if entry does not exist in local database
         * @since 31.0.0
         */
-       public function searchSignatory(string $host, string $account = ''): ISignatory;
+       public function getSignatory(string $host, string $account = ''): Signatory;
 
        /**
         * returns a fully formatted keyId, based on a fix hostname and path
diff --git a/lib/unstable/Security/Signature/ISignedRequest.php b/lib/unstable/Security/Signature/ISignedRequest.php
new file mode 100644 (file)
index 0000000..be52b06
--- /dev/null
@@ -0,0 +1,128 @@
+<?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;
+
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
+use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
+use NCU\Security\Signature\Model\Signatory;
+
+/**
+ * model that store data related to a possible signature.
+ * those details will be used:
+ * - to confirm authenticity of a signed incoming request
+ * - to sign an outgoing request
+ *
+ * @experimental 31.0.0
+ * @since 31.0.0
+ */
+interface ISignedRequest {
+       /**
+        * payload of the request
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getBody(): string;
+
+       /**
+        * checksum of the payload of the request
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getDigest(): string;
+
+       /**
+        * set the list of headers related to the signature of the request
+        *
+        * @param array $elements
+        *
+        * @return ISignedRequest
+        * @since 31.0.0
+        */
+       public function setSignatureElements(array $elements): ISignedRequest;
+
+       /**
+        * get the list of elements in the Signature header of the request
+        *
+        * @return array
+        * @since 31.0.0
+        */
+       public function getSignatureElements(): array;
+
+       /**
+        * @param string $key
+        *
+        * @return string
+        * @throws SignatureElementNotFoundException
+        * @since 31.0.0
+        */
+       public function getSignatureElement(string $key): string;
+
+       /**
+        * store a clear version of the signature
+        *
+        * @param string $clearSignature
+        *
+        * @return ISignedRequest
+        * @since 31.0.0
+        */
+       public function setClearSignature(string $clearSignature): ISignedRequest;
+
+       /**
+        * returns the clear version of the signature
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getClearSignature(): string;
+
+       /**
+        * set the signed version of the signature
+        *
+        * @param string $signedSignature
+        * @return ISignedRequest
+        * @since 31.0.0
+        */
+       public function setSignedSignature(string $signedSignature): ISignedRequest;
+
+       /**
+        * get the signed version of the signature
+        *
+        * @return string
+        * @since 31.0.0
+        */
+       public function getSignedSignature(): string;
+
+       /**
+        * set the signatory, containing keys and details, related to this request
+        *
+        * @param Signatory $signatory
+        * @return ISignedRequest
+        * @since 31.0.0
+        */
+       public function setSignatory(Signatory $signatory): ISignedRequest;
+
+       /**
+        * get the signatory, containing keys and details, related to this request
+        *
+        * @return Signatory
+        * @throws SignatoryNotFoundException
+        * @since 31.0.0
+        */
+       public function getSignatory(): Signatory;
+
+       /**
+        * returns if a signatory related to this request have been found and defined
+        *
+        * @return bool
+        * @since 31.0.0
+        */
+       public function hasSignatory(): bool;
+}
diff --git a/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php b/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php
deleted file mode 100644 (file)
index 3e2ebb2..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?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 NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
-use NCU\Security\Signature\ISignatureManager;
-use OCP\IRequest;
-
-/**
- * model wrapping an actual incoming request, adding details about the signature and the
- * authenticity of the origin of the request.
- *
- * @see ISignatureManager for details on signature
- * @experimental 31.0.0
- * @since 31.0.0
- */
-interface IIncomingSignedRequest extends ISignedRequest {
-       /**
-        * returns the base IRequest
-        *
-        * @return IRequest
-        * @since 31.0.0
-        */
-       public function getRequest(): IRequest;
-
-       /**
-        * set the hostname at the source of the request,
-        * based on the keyId defined in the signature header.
-        *
-        * @param string $origin
-        * @return IIncomingSignedRequest
-        * @since 31.0.0
-        */
-       public function setOrigin(string $origin): IIncomingSignedRequest;
-
-       /**
-        * get the hostname at the source of the base request.
-        * based on the keyId defined in the signature header.
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getOrigin(): string;
-
-       /**
-        * returns the keyId extracted from the signature headers.
-        * keyId is a mandatory entry in the headers of a signed request.
-        *
-        * @return string
-        * @throws SignatureElementNotFoundException
-        * @since 31.0.0
-        */
-       public function getKeyId(): string;
-}
diff --git a/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php b/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php
deleted file mode 100644 (file)
index 3c9445a..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?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 NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\SignatureAlgorithm;
-
-/**
- * extends ISignedRequest to add info requested at the generation of the signature
- *
- * @see ISignatureManager for details on signature
- * @experimental 31.0.0
- * @since 31.0.0
- */
-interface IOutgoingSignedRequest extends ISignedRequest {
-       /**
-        * set the host of the recipient of the request.
-        *
-        * @param string $host
-        * @return IOutgoingSignedRequest
-        * @since 31.0.0
-        */
-       public function setHost(string $host): IOutgoingSignedRequest;
-
-       /**
-        * get the host of the recipient of the request.
-        * - on incoming request, this is the local hostname of current instance.
-        * - on outgoing request, this is the remote instance.
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getHost(): string;
-
-       /**
-        * add a key/value pair to the headers of the request
-        *
-        * @param string $key
-        * @param string|int|float $value
-        *
-        * @return IOutgoingSignedRequest
-        * @since 31.0.0
-        */
-       public function addHeader(string $key, string|int|float $value): IOutgoingSignedRequest;
-
-       /**
-        * returns list of headers value that will be added to the base request
-        *
-        * @return array
-        * @since 31.0.0
-        */
-       public function getHeaders(): array;
-
-       /**
-        * set the ordered list of used headers in the Signature
-        *
-        * @param list<string> $list
-        *
-        * @return IOutgoingSignedRequest
-        * @since 31.0.0
-        */
-       public function setHeaderList(array $list): IOutgoingSignedRequest;
-
-       /**
-        * returns ordered list of used headers in the Signature
-        *
-        * @return list<string>
-        * @since 31.0.0
-        */
-       public function getHeaderList(): array;
-
-       /**
-        * set algorithm to be used to sign the signature
-        *
-        * @param SignatureAlgorithm $algorithm
-        *
-        * @return IOutgoingSignedRequest
-        * @since 31.0.0
-        */
-       public function setAlgorithm(SignatureAlgorithm $algorithm): IOutgoingSignedRequest;
-
-       /**
-        * returns the algorithm set to sign the signature
-        *
-        * @return SignatureAlgorithm
-        * @since 31.0.0
-        */
-       public function getAlgorithm(): SignatureAlgorithm;
-}
diff --git a/lib/unstable/Security/Signature/Model/ISignatory.php b/lib/unstable/Security/Signature/Model/ISignatory.php
deleted file mode 100644 (file)
index e77b77e..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<?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 NCU\Security\Signature\ISignatoryManager;
-
-/**
- * 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
- *
- * @since 31.0.0
- * @experimental 31.0.0
- */
-interface ISignatory {
-       /**
-        * unique string, related to the ISignatoryManager
-        *
-        * @see ISignatoryManager::getProviderId
-        * @param string $providerId
-        *
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setProviderId(string $providerId): ISignatory;
-
-       /**
-        * returns the provider id, unique string related to the ISignatoryManager
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getProviderId(): string;
-
-       /**
-        * set account, in case your ISignatoryManager needs to manage multiple keys from same host
-        *
-        * @param string $account
-        *
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setAccount(string $account): ISignatory;
-
-       /**
-        * return account name, empty string if not set
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getAccount(): string;
-
-       /**
-        * returns key id
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getKeyId(): string;
-
-       /**
-        * returns public key
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPublicKey(): string;
-
-       /**
-        * returns private key, if available
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPrivateKey(): string;
-
-       /**
-        * set metadata
-        *
-        * @param array $metadata
-        *
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setMetadata(array $metadata): ISignatory;
-
-       /**
-        * returns metadata
-        *
-        * @return array
-        * @since 31.0.0
-        */
-       public function getMetadata(): array;
-
-       /**
-        * update an entry in metadata
-        *
-        * @param string $key
-        * @param string|int $value
-        *
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setMetaValue(string $key, string|int $value): ISignatory;
-
-       /**
-        * set SignatoryType
-        *
-        * @param SignatoryType $type
-        *
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setType(SignatoryType $type): ISignatory;
-
-       /**
-        * returns SignatoryType
-        *
-        * @return SignatoryType
-        * @since 31.0.0
-        */
-       public function getType(): SignatoryType;
-
-       /**
-        * set SignatoryStatus
-        *
-        * @param SignatoryStatus $status
-        *
-        * @see SignatoryStatus
-        * @return ISignatory
-        * @since 31.0.0
-        */
-       public function setStatus(SignatoryStatus $status): ISignatory;
-
-       /**
-        * get SignatoryStatus
-        *
-        * @see SignatoryStatus
-        * @return SignatoryStatus
-        * @since 31.0.0
-        */
-       public function getStatus(): SignatoryStatus;
-
-       /**
-        * get last timestamp this entry has been updated
-        *
-        * @return int
-        * @since 31.0.0
-        */
-       public function getLastUpdated(): int;
-}
diff --git a/lib/unstable/Security/Signature/Model/ISignedRequest.php b/lib/unstable/Security/Signature/Model/ISignedRequest.php
deleted file mode 100644 (file)
index 76c0339..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?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 NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
-use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
-
-/**
- * model that store data related to a possible signature.
- * those details will be used:
- * - to confirm authenticity of a signed incoming request
- * - to sign an outgoing request
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-interface ISignedRequest {
-       /**
-        * payload of the request
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getBody(): string;
-
-       /**
-        * checksum of the payload of the request
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getDigest(): string;
-
-       /**
-        * set the list of headers related to the signature of the request
-        *
-        * @param array $elements
-        *
-        * @return ISignedRequest
-        * @since 31.0.0
-        */
-       public function setSignatureElements(array $elements): ISignedRequest;
-
-       /**
-        * get the list of elements in the Signature header of the request
-        *
-        * @return array
-        * @since 31.0.0
-        */
-       public function getSignatureElements(): array;
-
-       /**
-        * @param string $key
-        *
-        * @return string
-        * @throws SignatureElementNotFoundException
-        * @since 31.0.0
-        */
-       public function getSignatureElement(string $key): string;
-
-       /**
-        * store a clear version of the signature
-        *
-        * @param string $clearSignature
-        *
-        * @return ISignedRequest
-        * @since 31.0.0
-        */
-       public function setClearSignature(string $clearSignature): ISignedRequest;
-
-       /**
-        * returns the clear version of the signature
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getClearSignature(): string;
-
-       /**
-        * set the signed version of the signature
-        *
-        * @param string $signedSignature
-        * @return ISignedRequest
-        * @since 31.0.0
-        */
-       public function setSignedSignature(string $signedSignature): ISignedRequest;
-
-       /**
-        * get the signed version of the signature
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getSignedSignature(): string;
-
-       /**
-        * set the signatory, containing keys and details, related to this request
-        *
-        * @param ISignatory $signatory
-        * @return ISignedRequest
-        * @since 31.0.0
-        */
-       public function setSignatory(ISignatory $signatory): ISignedRequest;
-
-       /**
-        * get the signatory, containing keys and details, related to this request
-        *
-        * @return ISignatory
-        * @throws SignatoryNotFoundException
-        * @since 31.0.0
-        */
-       public function getSignatory(): ISignatory;
-
-       /**
-        * returns if a signatory related to this request have been found and defined
-        *
-        * @return bool
-        * @since 31.0.0
-        */
-       public function hasSignatory(): bool;
-}
diff --git a/lib/unstable/Security/Signature/Model/Signatory.php b/lib/unstable/Security/Signature/Model/Signatory.php
new file mode 100644 (file)
index 0000000..621cd5a
--- /dev/null
@@ -0,0 +1,165 @@
+<?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 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
+ *
+ * @since 31.0.0
+ * @experimental 31.0.0
+ *
+ * @method void setProviderId(string $providerId)
+ * @method string getProviderId()
+ * @method string getKeyId()
+ * @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 void setAccount(string $account)
+ * @method string getAccount()
+ * @method void setMetadata(array $metadata)
+ * @method array getMetadata()
+ * @method void setCreation(int $creation)
+ * @method int getCreation()
+ * @method void setLastUpdated(int $creation)
+ * @method int getLastUpdated()
+ */
+class Signatory extends Entity implements JsonSerializable {
+       protected string $keyId = '';
+       protected string $keyIdSum = '';
+       protected string $providerId = '';
+       protected string $host = '';
+       protected string $account = '';
+       protected int $type = 9;
+       protected int $status = 1;
+       protected array $metadata = [];
+       protected int $creation = 0;
+       protected int $lastUpdated = 0;
+
+       /**
+        * @param string $keyId
+        * @param string $publicKey
+        * @param string $privateKey
+        * @param bool $local
+        *
+        * @since 31.0.0
+        */
+       public function __construct(
+               string $keyId = '',
+               protected string $publicKey = '',
+               protected string $privateKey = '',
+               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');
+
+               $this->setKeyId($keyId);
+       }
+
+       /**
+        * @param string $keyId
+        *
+        * @since 31.0.0
+        */
+       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->keyId = $keyId;
+               $this->keyIdSum = hash('sha256', $keyId);
+       }
+
+       /**
+        * @param SignatoryType $type
+        * @since 31.0.0
+        */
+       public function setType(SignatoryType $type): void {
+               $this->type = $type->value;
+       }
+
+       /**
+        * @return SignatoryType
+        * @since 31.0.0
+        */
+       public function getType(): SignatoryType {
+               return SignatoryType::from($this->type);
+       }
+
+       /**
+        * @param SignatoryStatus $status
+        * @since 31.0.0
+        */
+       public function setStatus(SignatoryStatus $status): void {
+               $this->status = $status->value;
+       }
+
+       /**
+        * @return SignatoryStatus
+        * @since 31.0.0
+        */
+       public function getStatus(): SignatoryStatus {
+               return SignatoryStatus::from($this->status);
+       }
+
+       /**
+        * update an entry in metadata
+        *
+        * @param string $key
+        * @param string|int|float|bool|array $value
+        * @since 31.0.0
+        */
+       public function setMetaValue(string $key, string|int|float|bool|array $value): void {
+               $this->metadata[$key] = $value;
+       }
+
+       /**
+        * @return array
+        * @since 31.0.0
+        */
+       public function jsonSerialize(): array {
+               return [
+                       'keyId' => $this->getKeyId(),
+                       'publicKeyPem' => $this->getPublicKey()
+               ];
+       }
+}
diff --git a/lib/unstable/Security/Signature/Model/SignatoryStatus.php b/lib/unstable/Security/Signature/Model/SignatoryStatus.php
deleted file mode 100644 (file)
index 4174102..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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;
-
-/**
- * current status of signatory. is it trustable or not ?
- *
- * - SYNCED = the remote instance is trustable.
- * - BROKEN = the remote instance does not use the same key pairs than previously
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-enum SignatoryStatus: int {
-       /** @since 31.0.0 */
-       case SYNCED = 1;
-       /** @since 31.0.0 */
-       case BROKEN = 9;
-}
diff --git a/lib/unstable/Security/Signature/Model/SignatoryType.php b/lib/unstable/Security/Signature/Model/SignatoryType.php
deleted file mode 100644 (file)
index 652bee2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace NCU\Security\Signature\Model;
-
-/**
- * type of link between local and remote instance
- *
- * - FORGIVABLE = the keypair can be deleted and refreshed anytime and silently
- * - REFRESHABLE = the keypair can be refreshed but a notice will be generated
- * - TRUSTED = any changes of keypair will require human interaction, warning will be issued
- * - STATIC = error will be issued on conflict,  assume keypair cannot be reset.
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-enum SignatoryType: int {
-       /** @since 31.0.0 */
-       case FORGIVABLE = 1; // no notice on refresh
-       /** @since 31.0.0 */
-       case REFRESHABLE = 4; // notice on refresh
-       /** @since 31.0.0 */
-       case TRUSTED = 8; // warning on refresh
-       /** @since 31.0.0 */
-       case STATIC = 9; // error on refresh
-}
diff --git a/lib/unstable/Security/Signature/SignatureAlgorithm.php b/lib/unstable/Security/Signature/SignatureAlgorithm.php
deleted file mode 100644 (file)
index c0a5a0c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace NCU\Security\Signature;
-
-/**
- * list of available algorithm when signing payload
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-enum SignatureAlgorithm: string {
-       /** @since 31.0.0 */
-       case SHA256 = 'sha256';
-       /** @since 31.0.0 */
-       case SHA512 = 'sha512';
-}