diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f92e5bc54..6ef46f5ce 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -21,6 +21,7 @@ use OCA\EndToEndEncryption\KeyStorage; use OCA\EndToEndEncryption\Listener\AllowBlobMediaInCSPListener; use OCA\EndToEndEncryption\Listener\LoadAdditionalListener; +use OCA\EndToEndEncryption\Listener\ShareDeletedListener; use OCA\EndToEndEncryption\Listener\UserDeletedListener; use OCA\EndToEndEncryption\MetaDataStorage; use OCA\EndToEndEncryption\MetaDataStorageV1; @@ -28,6 +29,7 @@ use OCA\EndToEndEncryption\Middleware\ClientHasCapabilityMiddleware; use OCA\EndToEndEncryption\Middleware\UserAgentCheckMiddleware; use OCA\Files\Event\LoadAdditionalScriptsEvent; +use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; use OCA\Files_Trashbin\Events\MoveToTrashEvent; use OCA\Files_Versions\Events\CreateVersionEvent; use OCP\AppFramework\App; @@ -36,6 +38,7 @@ use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\EventDispatcher\IEventDispatcher; use OCP\Security\CSP\AddContentSecurityPolicyEvent; +use OCP\Share\Events\ShareDeletedEvent; use OCP\User\Events\UserDeletedEvent; use Override; @@ -61,6 +64,8 @@ public function register(IRegistrationContext $context): void { $context->registerServiceAlias(IMetaDataStorageV1::class, MetaDataStorageV1::class); $context->registerServiceAlias(IMetaDataStorage::class, MetaDataStorage::class); $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); + $context->registerEventListener(ShareDeletedEvent::class, ShareDeletedListener::class); + $context->registerEventListener(BeforeTemplateRenderedEvent::class, LoadAdditionalListener::class); $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); $context->registerEventListener(AddContentSecurityPolicyEvent::class, AllowBlobMediaInCSPListener::class); $context->registerPublicShareTemplateProvider(E2EEPublicShareTemplateProvider::class); diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 108e3ad4a..0ab5be890 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -45,7 +45,7 @@ public function getCapabilities(): array { return [ 'end-to-end-encryption' => [ 'enabled' => true, - 'api-version' => '2.0', + 'api-version' => '2.1', 'keys-exist' => $keysExist, ] ]; diff --git a/lib/Connector/Sabre/PropFindPlugin.php b/lib/Connector/Sabre/PropFindPlugin.php index 66c0565ff..81887141a 100644 --- a/lib/Connector/Sabre/PropFindPlugin.php +++ b/lib/Connector/Sabre/PropFindPlugin.php @@ -14,7 +14,6 @@ use OCA\DAV\Connector\Sabre\File; use OCA\EndToEndEncryption\IMetaDataStorage; use OCA\EndToEndEncryption\UserAgentManager; -use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\IRequest; use OCP\IUserSession; @@ -37,7 +36,6 @@ public function __construct( private UserAgentManager $userAgentManager, private IRequest $request, private IMetaDataStorage $metaDataStorage, - private ?Folder $userFolder, ) { parent::__construct($rootFolder, $userSession); } @@ -68,7 +66,7 @@ public function setE2EEProperties(PropFind $propFind, \Sabre\DAV\INode $node) { $propFind->handle(self::E2EE_METADATA_PROPERTYNAME, function () use ($node) { if ($this->isE2EEnabledPath($node)) { return $this->metaDataStorage->getMetaData( - $this->userSession->getUser()->getUID(), + ($this->userSession->getUser() ?? $node->getNode()->getOwner())->getUID(), $node->getId(), ); } @@ -82,11 +80,9 @@ public function setE2EEProperties(PropFind $propFind, \Sabre\DAV\INode $node) { } // This property was introduced to expose encryption status for both files and folders. - if ($this->userFolder !== null) { - $propFind->handle(self::E2EE_IS_ENCRYPTED, function () use ($node) { - return $this->isE2EEnabledPath($node) ? '1' : '0'; - }); - } + $propFind->handle(self::E2EE_IS_ENCRYPTED, function () use ($node) { + return $this->isE2EEnabledPath($node) ? '1' : '0'; + }); } /** diff --git a/lib/Controller/KeyController.php b/lib/Controller/KeyController.php index b625b4562..5490d9077 100644 --- a/lib/Controller/KeyController.php +++ b/lib/Controller/KeyController.php @@ -9,10 +9,13 @@ use BadMethodCallException; use Exception; +use OCA\EndToEndEncryption\AppInfo\Application; use OCA\EndToEndEncryption\Exceptions\KeyExistsException; use OCA\EndToEndEncryption\IKeyStorage; use OCA\EndToEndEncryption\SignatureHandler; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSForbiddenException; @@ -23,37 +26,29 @@ use OCP\Files\NotPermittedException; use OCP\IL10N; use OCP\IRequest; +use OCP\Share\IManager; use Psr\Log\LoggerInterface; class KeyController extends OCSController { - private ?string $userId; - private IKeyStorage $keyStorage; - private SignatureHandler $signatureHandler; - private LoggerInterface $logger; - private IL10N $l10n; - public function __construct(string $AppName, + public function __construct( IRequest $request, - ?string $userId, - IKeyStorage $keyStorage, - SignatureHandler $signatureHandler, - LoggerInterface $logger, - IL10N $l10n, + private ?string $userId, + private IKeyStorage $keyStorage, + private SignatureHandler $signatureHandler, + private LoggerInterface $logger, + private IL10N $l10n, + private IManager $shareManager, ) { - parent::__construct($AppName, $request); - $this->userId = $userId; - $this->keyStorage = $keyStorage; - $this->signatureHandler = $signatureHandler; - $this->logger = $logger; - $this->l10n = $l10n; + parent::__construct(Application::APP_ID, $request); } /** * Get private key * - * @NoAdminRequired * @E2ERestrictUserAgent * + * @param ?string $shareToken - Optional share token to get a private key associated with a share * @return DataResponse * @throws OCSBadRequestException Internal error * @throws OCSForbiddenException Not allowed to get private key @@ -61,9 +56,15 @@ public function __construct(string $AppName, * * 200: Private key returned */ - public function getPrivateKey(): DataResponse { + #[NoAdminRequired] + #[PublicPage] + public function getPrivateKey(?string $shareToken = null): DataResponse { + if ($this->userId === null && $shareToken === null) { + throw new OCSForbiddenException($this->l10n->t('Not allowed to get private key')); + } + try { - $privateKey = $this->keyStorage->getPrivateKey($this->userId); + $privateKey = $this->keyStorage->getPrivateKey($this->userId ?? '', $shareToken); return new DataResponse(['private-key' => $privateKey]); } catch (ForbiddenException $e) { throw new OCSForbiddenException($this->l10n->t('This is someone else\'s private key')); @@ -81,6 +82,7 @@ public function getPrivateKey(): DataResponse { * * @NoAdminRequired * + * @param ?string $shareToken - Optional share token to delete a private key associated with a share * @return DataResponse, array{}> * @throws OCSBadRequestException Internal error * @throws OCSForbiddenException Not allowed to delete public key @@ -88,9 +90,9 @@ public function getPrivateKey(): DataResponse { * * 200: Private key deleted successfully */ - public function deletePrivateKey(): DataResponse { + public function deletePrivateKey(?string $shareToken = null): DataResponse { try { - $this->keyStorage->deletePrivateKey($this->userId); + $this->keyStorage->deletePrivateKey($this->userId, $shareToken); return new DataResponse(); } catch (NotPermittedException $e) { throw new OCSForbiddenException($this->l10n->t('You are not allowed to delete this private key')); @@ -109,16 +111,17 @@ public function deletePrivateKey(): DataResponse { * @NoAdminRequired * @E2ERestrictUserAgent * - * @param string $privateKey The new private key + * @param string $privateKey - The new private key + * @param ?string $shareToken - Optional share token to set a private key associated with a share * @return DataResponse|DataResponse, array{}> * @throws OCSBadRequestException Internal error * * 200: Private key set successfully * 409: Private key already exists */ - public function setPrivateKey(string $privateKey): DataResponse { + public function setPrivateKey(string $privateKey, ?string $shareToken = null): DataResponse { try { - $this->keyStorage->setPrivateKey($privateKey, $this->userId); + $this->keyStorage->setPrivateKey($privateKey, $this->userId, $shareToken); } catch (KeyExistsException $e) { return new DataResponse([], Http::STATUS_CONFLICT); } catch (Exception $e) { @@ -132,7 +135,6 @@ public function setPrivateKey(string $privateKey): DataResponse { /** * Get public key * - * @NoAdminRequired * @E2ERestrictUserAgent * @param string $users a json encoded list of users * @return DataResponse}, array{}> @@ -141,9 +143,10 @@ public function setPrivateKey(string $privateKey): DataResponse { * * 200: Public keys returned */ + #[NoAdminRequired] + #[PublicPage] public function getPublicKeys(string $users = ''): DataResponse { $usersArray = $this->jsonDecode($users); - $result = ['public-keys' => []]; foreach ($usersArray as $uid) { try { @@ -170,6 +173,7 @@ public function getPublicKeys(string $users = ''): DataResponse { * @E2ERestrictUserAgent * * @param string $csr request to create a valid public key + * @param ?string $shareToken - optional share token to create a public key associated with a share * * @return DataResponse|DataResponse, array{}> * @throws OCSForbiddenException Common name (CN) does not match the current user @@ -178,13 +182,29 @@ public function getPublicKeys(string $users = ''): DataResponse { * 200: Public key created successfully * 409: Public key already exists */ - public function createPublicKey(string $csr): DataResponse { - if ($this->keyStorage->publicKeyExists($this->userId)) { + public function createPublicKey(string $csr, ?string $shareToken = null): DataResponse { + if ($this->keyStorage->publicKeyExists($this->userId, $shareToken)) { return new DataResponse([], Http::STATUS_CONFLICT); } + $subject = openssl_csr_get_subject($csr); + if ($subject === false) { + throw new OCSBadRequestException($this->l10n->t('Could not parse the CSR, please make sure to submit a valid CSR')); + } + $cn = isset($subject['CN']) ? $subject['CN'] : ''; + if ($shareToken !== null) { + if ($cn !== "s:$shareToken") { + throw new OCSForbiddenException($this->l10n->t('Common name (CN) does not match the share token')); + } + $share = $this->shareManager->getShareByToken($shareToken); + if ($share->getShareOwner() !== $this->userId) { + throw new OCSForbiddenException($this->l10n->t('You are not the owner of the share')); + } + } elseif ($this->userId !== $cn) { + throw new OCSForbiddenException($this->l10n->t('Common name (CN) does not match the current user')); + } + try { - $subject = openssl_csr_get_subject($csr); $publicKey = $this->signatureHandler->sign($csr); } catch (BadMethodCallException $e) { $this->logger->critical($e->getMessage(), ['exception' => $e, 'app' => $this->appName]); @@ -194,13 +214,7 @@ public function createPublicKey(string $csr): DataResponse { throw new OCSBadRequestException($this->l10n->t('Internal error')); } - $cn = isset($subject['CN']) ? $subject['CN'] : ''; - if ($cn !== $this->userId) { - throw new OCSForbiddenException($this->l10n->t('Common name (CN) does not match the current user')); - } - - $this->keyStorage->setPublicKey($publicKey, $this->userId); - + $this->keyStorage->setPublicKey($publicKey, $this->userId, $shareToken); return new DataResponse(['public-key' => $publicKey]); } @@ -235,6 +249,7 @@ public function setPublicKey(string $publicKey): DataResponse { * * @NoAdminRequired * + * @param ?string $shareToken - Optional share token to delete a public key associated with a share * @return DataResponse, array{}> * * @throws OCSForbiddenException Not allowed to delete public key @@ -243,9 +258,9 @@ public function setPublicKey(string $publicKey): DataResponse { * * 200: Public key deleted successfully */ - public function deletePublicKey(): ?DataResponse { + public function deletePublicKey(?string $shareToken = null): ?DataResponse { try { - $this->keyStorage->deletePublicKey($this->userId); + $this->keyStorage->deletePublicKey($this->userId, $shareToken); return new DataResponse(); } catch (NotFoundException $e) { throw new OCSNotFoundException($this->l10n->t('Could not find the public key belonging to %s', [$this->userId])); @@ -259,7 +274,6 @@ public function deletePublicKey(): ?DataResponse { /** - * @NoAdminRequired * @E2ERestrictUserAgent * * Get the public server key so that the clients can verify the @@ -271,6 +285,8 @@ public function deletePublicKey(): ?DataResponse { * * 200: Server public key returned */ + #[NoAdminRequired] + #[PublicPage] public function getPublicServerKey(): DataResponse { try { $publicKey = $this->signatureHandler->getPublicServerKey(); @@ -300,7 +316,7 @@ private function jsonDecode(string $users): array { } } - if (!in_array($this->userId, $usersArray, true)) { + if ($this->userId !== null && !in_array($this->userId, $usersArray, true)) { $usersArray[] = $this->userId; } diff --git a/lib/E2EEPublicShareTemplateProvider.php b/lib/E2EEPublicShareTemplateProvider.php index d0305deba..05fb1cb6e 100644 --- a/lib/E2EEPublicShareTemplateProvider.php +++ b/lib/E2EEPublicShareTemplateProvider.php @@ -12,6 +12,7 @@ use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; +use OCP\Constants; use OCP\Defaults; use OCP\Files\FileInfo; use OCP\Files\NotFoundException; @@ -38,7 +39,10 @@ public function __construct( public function shouldRespond(IShare $share): bool { $node = $share->getNode(); - return $node->getType() === FileInfo::TYPE_FOLDER && $node->isEncrypted(); + + return $node->getType() === FileInfo::TYPE_FOLDER + && $node->isEncrypted() + && ($share->getPermissions() & Constants::PERMISSION_READ) === 0; } protected function getMetadata(IShare $share): array { diff --git a/lib/IKeyStorage.php b/lib/IKeyStorage.php index 9edc51381..8b84ce63b 100644 --- a/lib/IKeyStorage.php +++ b/lib/IKeyStorage.php @@ -34,7 +34,7 @@ public function getPublicKey(string $uid): string; * @throws NotFoundException * @throws NotPermittedException */ - public function publicKeyExists(string $uid): bool; + public function publicKeyExists(string $uid, ?string $shareToken = null): bool; /** * Store public key @@ -43,7 +43,7 @@ public function publicKeyExists(string $uid): bool; * @throws NotFoundException * @throws NotPermittedException */ - public function setPublicKey(string $publicKey, string $uid): void; + public function setPublicKey(string $publicKey, string $uid, ?string $shareToken = null): void; /** * Delete the users public key @@ -51,7 +51,7 @@ public function setPublicKey(string $publicKey, string $uid): void; * @throws NotPermittedException * @throws NotFoundException */ - public function deletePublicKey(string $uid): void; + public function deletePublicKey(string $uid, ?string $shareToken = null): void; /** * Get users private key @@ -60,7 +60,7 @@ public function deletePublicKey(string $uid): void; * @throws NotPermittedException * @throws ForbiddenException */ - public function getPrivateKey(string $uid): string; + public function getPrivateKey(string $uid, ?string $shareToken = null): string; /** * Check if a private key exists @@ -69,7 +69,7 @@ public function getPrivateKey(string $uid): string; * @throws NotPermittedException * @throws ForbiddenException */ - public function privateKeyExists(string $uid): bool; + public function privateKeyExists(string $uid, ?string $shareToken = null): bool; /** * Store private key @@ -79,7 +79,7 @@ public function privateKeyExists(string $uid): bool; * @throws NotPermittedException * @throws ForbiddenException */ - public function setPrivateKey(string $privateKey, string $uid): void; + public function setPrivateKey(string $privateKey, string $uid, ?string $shareToken = null): void; /** * Get users private key @@ -87,7 +87,7 @@ public function setPrivateKey(string $privateKey, string $uid): void; * @throws NotPermittedException * @throws NotFoundException */ - public function deletePrivateKey(string $uid): void; + public function deletePrivateKey(string $uid, ?string $shareToken = null): void; /** * Delete all user private and public key permanently diff --git a/lib/KeyStorage.php b/lib/KeyStorage.php index e05c0ea4c..629f18bbb 100644 --- a/lib/KeyStorage.php +++ b/lib/KeyStorage.php @@ -17,6 +17,7 @@ use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IUser; use OCP\IUserSession; +use OCP\Share\IManager; /** * Class KeyStorage @@ -26,18 +27,17 @@ * @package OCA\EndToEndEncryption */ class KeyStorage implements IKeyStorage { - private IAppData $appData; - private IUserSession $userSession; private string $privateKeysRoot = '/private-keys'; private string $publicKeysRoot = '/public-keys'; private ?ISimpleFolder $privateKeysRootFolder = null; private ?ISimpleFolder $publicKeysRootFolder = null; - public function __construct(IAppData $appData, - IUserSession $userSession) { - $this->appData = $appData; - $this->userSession = $userSession; + public function __construct( + private IAppData $appData, + private IUserSession $userSession, + private IManager $shareManager, + ) { } /** @@ -53,20 +53,20 @@ public function getPublicKey(string $uid): string { /** * @inheritDoc */ - public function publicKeyExists(string $uid): bool { + public function publicKeyExists(string $uid, ?string $shareToken = null): bool { $publicKeysRoot = $this->getPublicKeysRootFolder(); - $fileName = $this->getFileNameForPublicKey($uid); + $fileName = $this->getFileNameForPublicKey($uid, $shareToken); return $publicKeysRoot->fileExists($fileName); } /** * @inheritDoc */ - public function setPublicKey(string $publicKey, string $uid): void { + public function setPublicKey(string $publicKey, string $uid, ?string $shareToken = null): void { $publicKeysRoot = $this->getPublicKeysRootFolder(); - $fileName = $this->getFileNameForPublicKey($uid); + $fileName = $this->getFileNameForPublicKey($uid, $shareToken); if ($publicKeysRoot->fileExists($fileName)) { throw new KeyExistsException('Public key already exists'); } @@ -79,15 +79,21 @@ public function setPublicKey(string $publicKey, string $uid): void { /** * @inheritDoc */ - public function deletePublicKey(string $uid): void { + public function deletePublicKey(string $uid, ?string $shareToken = null): void { $publicKeysRoot = $this->getPublicKeysRootFolder(); $user = $this->userSession->getUser(); if ($user === null || $user->getUID() !== $uid) { throw new NotPermittedException('You are not allowed to delete the public key'); } + if ($shareToken !== null) { + $share = $this->shareManager->getShareByToken($shareToken); + if ($share->getShareOwner() !== $user->getUID()) { + throw new NotPermittedException('You are not allowed to delete the public key'); + } + } - $fileName = $this->getFileNameForPublicKey($uid); + $fileName = $this->getFileNameForPublicKey($uid, $shareToken); try { $file = $publicKeysRoot->getFile($fileName); } catch (NotFoundException $ex) { @@ -100,45 +106,51 @@ public function deletePublicKey(string $uid): void { /** * @inheritDoc */ - public function getPrivateKey(string $uid): string { + public function getPrivateKey(string $uid, ?string $shareToken = null): string { $privateKeysRoot = $this->getPrivateKeysRootFolder(); $user = $this->userSession->getUser(); - if ($user === null || $user->getUID() !== $uid) { + if ($shareToken === null && ($user === null || $user->getUID() !== $uid)) { throw new ForbiddenException('You are not allowed to access the private key', false); } - $fileName = $this->getFileNameForPrivateKey($uid); + $fileName = $this->getFileNameForPrivateKey($uid, $shareToken); return $privateKeysRoot->getFile($fileName)->getContent(); } /** * @inheritDoc */ - public function privateKeyExists(string $uid): bool { + public function privateKeyExists(string $uid, ?string $shareToken = null): bool { $privateKeysRoot = $this->getPrivateKeysRootFolder(); $user = $this->userSession->getUser(); - if ($user === null || $user->getUID() !== $uid) { + if (($user === null && $shareToken === null) || ($shareToken === null && $user->getUID() !== $uid)) { throw new ForbiddenException('You are not allowed to access the private key', false); } - $fileName = $this->getFileNameForPrivateKey($uid); + $fileName = $this->getFileNameForPrivateKey($uid, $shareToken); return $privateKeysRoot->fileExists($fileName); } /** * @inheritDoc */ - public function setPrivateKey(string $privateKey, string $uid): void { + public function setPrivateKey(string $privateKey, string $uid, ?string $shareToken = null): void { $privateKeysRoot = $this->getPrivateKeysRootFolder(); $user = $this->userSession->getUser(); if ($user === null || $user->getUID() !== $uid) { throw new ForbiddenException('You are not allowed to write the private key', false); } + if ($shareToken !== null) { + $share = $this->shareManager->getShareByToken($shareToken); + if ($share->getShareOwner() !== $user->getUID()) { + throw new ForbiddenException('You are not allowed to write the private key', false); + } + } - $fileName = $this->getFileNameForPrivateKey($uid); + $fileName = $this->getFileNameForPrivateKey($uid, $shareToken); if ($privateKeysRoot->fileExists($fileName)) { throw new KeyExistsException('Private key already exists'); } @@ -151,13 +163,19 @@ public function setPrivateKey(string $privateKey, string $uid): void { /** * @inheritDoc */ - public function deletePrivateKey(string $uid): void { + public function deletePrivateKey(string $uid, ?string $shareToken = null): void { $privateKeysRoot = $this->getPrivateKeysRootFolder(); $user = $this->userSession->getUser(); if ($user === null || $user->getUID() !== $uid) { throw new NotPermittedException('You are not allowed to delete the private key'); } + if ($shareToken !== null) { + $share = $this->shareManager->getShareByToken($shareToken); + if ($share->getShareOwner() !== $user->getUID()) { + throw new NotPermittedException('You are not allowed to delete the private key'); + } + } $fileName = $this->getFileNameForPrivateKey($uid); try { @@ -243,11 +261,21 @@ protected function getPublicKeysRootFolder(): ISimpleFolder { return $this->publicKeysRootFolder; } - private function getFileNameForPublicKey(string $uid): string { + private function getFileNameForPublicKey(string $uid, ?string $shareToken = null): string { + if (str_starts_with($uid, 's:')) { + $shareToken = substr($uid, 2); + } + + if ($shareToken !== null) { + return $shareToken . '.share.public.key'; + } return $uid . '.public.key'; } - private function getFileNameForPrivateKey(string $uid): string { + private function getFileNameForPrivateKey(string $uid, ?string $shareToken = null): string { + if ($shareToken !== null) { + return $shareToken . '.share.private.key'; + } return $uid . '.private.key'; } } diff --git a/lib/Listener/LoadAdditionalListener.php b/lib/Listener/LoadAdditionalListener.php index 9058ffaed..ba3ffcd17 100644 --- a/lib/Listener/LoadAdditionalListener.php +++ b/lib/Listener/LoadAdditionalListener.php @@ -10,6 +10,7 @@ use OCA\EndToEndEncryption\AppInfo\Application; use OCA\Files\Event\LoadAdditionalScriptsEvent; +use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; @@ -17,7 +18,7 @@ use OCP\Util; /** - * @template-implements IEventListener + * @template-implements IEventListener */ class LoadAdditionalListener implements IEventListener { @@ -29,14 +30,21 @@ public function __construct( } public function handle(Event $event): void { - if (!($event instanceof LoadAdditionalScriptsEvent)) { + if (!($event instanceof LoadAdditionalScriptsEvent) && !($event instanceof BeforeTemplateRenderedEvent)) { return; } + if (($event instanceof BeforeTemplateRenderedEvent) && $event->getScope() === BeforeTemplateRenderedEvent::SCOPE_PUBLIC_SHARE_AUTH) { + return; + } + + $browserE2eeEnabled = $this->userId === null + || $this->config->getUserValue($this->userId, 'end_to_end_encryption', 'e2eeInBrowserEnabled', 'false') === 'true'; + $this->initialState->provideInitialState( 'userConfig', [ - 'e2eeInBrowserEnabled' => $this->config->getUserValue($this->userId, 'end_to_end_encryption', 'e2eeInBrowserEnabled', 'false') === 'true', + 'e2eeInBrowserEnabled' => $browserE2eeEnabled, ] ); diff --git a/lib/Listener/ShareDeletedListener.php b/lib/Listener/ShareDeletedListener.php new file mode 100644 index 000000000..0baf4b726 --- /dev/null +++ b/lib/Listener/ShareDeletedListener.php @@ -0,0 +1,51 @@ + + */ +class ShareDeletedListener implements IEventListener { + + public function __construct( + private IKeyStorage $keyStorage, + private LoggerInterface $logger, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof ShareDeletedEvent)) { + return; + } + + $share = $event->getShare(); + $shareToken = $share->getToken(); + if ($shareToken === null) { + return; + } + + try { + $this->keyStorage->deletePrivateKey($share->getShareOwner(), $shareToken); + $this->keyStorage->deletePublicKey($share->getShareOwner(), $shareToken); + } catch (\Exception $e) { + $this->logger->info( + 'Failed to delete keys for deleted share', + ['shareToken' => $shareToken, 'exception' => $e], + ); + } + } + +} diff --git a/openapi.json b/openapi.json index 1533882be..2e6b607e6 100644 --- a/openapi.json +++ b/openapi.json @@ -101,7 +101,13 @@ "properties": { "privateKey": { "type": "string", - "description": "The new private key" + "description": "- The new private key" + }, + "shareToken": { + "type": "string", + "nullable": true, + "default": null, + "description": "- Optional share token to set a private key associated with a share" } } } @@ -265,6 +271,7 @@ "key" ], "security": [ + {}, { "bearer_auth": [] }, @@ -286,6 +293,16 @@ "default": "2" } }, + { + "name": "shareToken", + "in": "query", + "description": "- Optional share token to get a private key associated with a share", + "schema": { + "type": "string", + "nullable": true, + "default": null + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -419,34 +436,6 @@ } } } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } } } }, @@ -478,6 +467,16 @@ "default": "2" } }, + { + "name": "shareToken", + "in": "query", + "description": "- Optional share token to delete a private key associated with a share", + "schema": { + "type": "string", + "nullable": true, + "default": null + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -845,6 +844,12 @@ "csr": { "type": "string", "description": "request to create a valid public key" + }, + "shareToken": { + "type": "string", + "nullable": true, + "default": null, + "description": "- optional share token to create a public key associated with a share" } } } @@ -1036,6 +1041,7 @@ "key" ], "security": [ + {}, { "bearer_auth": [] }, @@ -1174,34 +1180,6 @@ } } } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } } } }, @@ -1233,6 +1211,16 @@ "default": "2" } }, + { + "name": "shareToken", + "in": "query", + "description": "- Optional share token to delete a public key associated with a share", + "schema": { + "type": "string", + "nullable": true, + "default": null + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -1396,6 +1384,7 @@ "key" ], "security": [ + {}, { "bearer_auth": [] }, @@ -1494,34 +1483,6 @@ } } } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } } } } diff --git a/tests/Unit/CapabilitiesTest.php b/tests/Unit/CapabilitiesTest.php index 6b8dd04e9..2a89183e6 100644 --- a/tests/Unit/CapabilitiesTest.php +++ b/tests/Unit/CapabilitiesTest.php @@ -60,7 +60,7 @@ public function testGetCapabilities(): void { $this->assertEquals([ 'end-to-end-encryption' => [ 'enabled' => true, - 'api-version' => '2.0', + 'api-version' => '2.1', 'keys-exist' => true ] ], $this->capabilities->getCapabilities()); diff --git a/tests/Unit/Controller/KeyControllerTest.php b/tests/Unit/Controller/KeyControllerTest.php index 962a2eb43..ef2e0bcb7 100644 --- a/tests/Unit/Controller/KeyControllerTest.php +++ b/tests/Unit/Controller/KeyControllerTest.php @@ -21,37 +21,24 @@ use OCP\Files\NotPermittedException; use OCP\IL10N; use OCP\IRequest; +use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Test\TestCase; class KeyControllerTest extends TestCase { - /** @var string */ - private $appName; - - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - - /** @var string */ - private $userId; - - /** @var IKeyStorage|\PHPUnit\Framework\MockObject\MockObject */ - private $keyStorage; - - /** @var SignatureHandler|\PHPUnit\Framework\MockObject\MockObject */ - private $signatureHandler; - - /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ - private $logger; - - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - private $l10n; - - /** @var KeyController */ - private $controller; - - /** @var string valid CSR (CN set to "admin") */ - private $validCSR = '-----BEGIN CERTIFICATE REQUEST----- + private string $userId; + private IRequest&MockObject $request; + private IKeyStorage&MockObject $keyStorage; + private SignatureHandler&MockObject $signatureHandler; + private LoggerInterface&MockObject $logger; + private IL10N&MockObject $l10n; + private IManager&MockObject $shareManager; + private KeyController $controller; + + /** valid CSR (CN set to "admin") */ + private string $validCSR = '-----BEGIN CERTIFICATE REQUEST----- MIIC7jCCAdYCAQAwgagxCzAJBgNVBAYTAlVLMREwDwYDVQQIDAhTb21lcnNldDEU MBIGA1UEBwwLR2xhc3RvbmJ1cnkxHzAdBgNVBAoMFlRoZSBCcmFpbiBSb29tIExp bWl0ZWQxHzAdBgNVBAsMFlBIUCBEb2N1bWVudGF0aW9uIFRlYW0xDjAMBgNVBAMM @@ -71,28 +58,28 @@ class KeyControllerTest extends TestCase { -----END CERTIFICATE REQUEST----- '; - /** @var string */ - private $invalidCSR = "-----BEGIN CERTIFICATE REQUEST-----\nMIIC7jCCAdYCAQAwgagxCzAJBgNVBAYTAlVLMREwDwYDVQQIDAhTb21lcnNldDEU\nMBIGA1UEBwwLR2xhc3RvbmJ1cnkxHzAdBgNVBAoMFlRoZSBCcmFpbiBSb29tIExp\nbWl0ZWQxHzAdBgNVBAsMFlBIUCBEb2N1bWVudGF0aW9uIFRlYW0xDjAMBgNVBAMM\nBWFkbWluMR4wHAYJKoZIhvcNAQkBFg93ZXpAZXhhbXBsZS5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHWU8rWlK3lud%2Fr5OQoilxypgIzbBf5pqM\nH0rpYwFv3uctnK5Lt3M%2BWY45XdJt98Pq8eQ0AbyAf3IuhnpF%2BX2Ej3QnCenZ0H%2BB\nJ6%2FmZXdo9f7IXa2wH5LtA2cmm1XWQWubN%2FJzr9psq%2BkxbocyGTQhNGeeB2OPcgyl\n73eddJNIbFVlNEzbdcBNNsSwKcB%2BLP%2FJyJ9e1HZ4af6CHdX2SG1HvO%2BdICdEuO2E\nmC9lM896MJFWwNns5mx453Y1FmxFmAi1zQAAP%2BAZ5Taqy6yCzqJ9Y4%2FFDRi1NC5V\nstnu9REuPYSS8YgsJwQE%2FDUd%2BI%2BUonkcDfac8PIH5p5YHpMq0ChvAgMBAAGgADAN\nBgkqhkiG9w0BAQUFAAOCAQEAh8YVAsAcPR5v7kv96UtkVI4xK6R9BdmVsnisxTpm\ng9JVbfji7kpxbSgXfRSozTG3bl9ynrck39%2F2SoFQGSGrW2iV%2BdrclftSk%2BuBFb1F\niXYEWJxYSz2CcUeijoBrBsarfmODgOHzmgXmCoOToz2DkdtM7g9INWkC06Do4pTQ\nfqA3PS2td1gWqQCQthF9IWOCIxNI16lokVTgNCZKewXsn9Bjm3hsLLeJU9jBXyVN\nw7829dr37SuA2kQb86aVpqdL50v3HjCclXd7PfWiYqajuHaIsokBV5ly2IdQo4Cz\nAYzYQFPtjsDZ4Tju4VZKM4YpF2GwQgT7zhzDBvywGPqvfw%3D%3D\n-----END+CERTIFICATE+REQUEST-----\n"; - + private string $invalidCSR = "-----BEGIN CERTIFICATE REQUEST-----\nMIIC7jCCAdYCAQAwgagxCzAJBgNVBAYTAlVLMREwDwYDVQQIDAhTb21lcnNldDEU\nMBIGA1UEBwwLR2xhc3RvbmJ1cnkxHzAdBgNVBAoMFlRoZSBCcmFpbiBSb29tIExp\nbWl0ZWQxHzAdBgNVBAsMFlBIUCBEb2N1bWVudGF0aW9uIFRlYW0xDjAMBgNVBAMM\nBWFkbWluMR4wHAYJKoZIhvcNAQkBFg93ZXpAZXhhbXBsZS5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHWU8rWlK3lud%2Fr5OQoilxypgIzbBf5pqM\nH0rpYwFv3uctnK5Lt3M%2BWY45XdJt98Pq8eQ0AbyAf3IuhnpF%2BX2Ej3QnCenZ0H%2BB\nJ6%2FmZXdo9f7IXa2wH5LtA2cmm1XWQWubN%2FJzr9psq%2BkxbocyGTQhNGeeB2OPcgyl\n73eddJNIbFVlNEzbdcBNNsSwKcB%2BLP%2FJyJ9e1HZ4af6CHdX2SG1HvO%2BdICdEuO2E\nmC9lM896MJFWwNns5mx453Y1FmxFmAi1zQAAP%2BAZ5Taqy6yCzqJ9Y4%2FFDRi1NC5V\nstnu9REuPYSS8YgsJwQE%2FDUd%2BI%2BUonkcDfac8PIH5p5YHpMq0ChvAgMBAAGgADAN\nBgkqhkiG9w0BAQUFAAOCAQEAh8YVAsAcPR5v7kv96UtkVI4xK6R9BdmVsnisxTpm\ng9JVbfji7kpxbSgXfRSozTG3bl9ynrck39%2F2SoFQGSGrW2iV%2BdrclftSk%2BuBFb1F\niXYEWJxYSz2CcUeijoBrBsarfmODgOHzmgXmCoOToz2DkdtM7g9INWkC06Do4pTQ\nfqA3PS2td1gWqQCQthF9IWOCIxNI16lokVTgNCZKewXsn9Bjm3hsLLeJU9jBXyVN\nw7829dr37SuA2kQb86aVpqdL50v3HjCclXd7PfWiYqajuHaIsokBV5ly2IdQo4Cz\nAYzYQFPtjsDZ4Tju4VZKM4YpF2GwQgT7zhzDBvywGPqvfw%3D%3D\n-----END+CERTIFICATE+REQUEST-----\n"; protected function setUp(): void { parent::setUp(); - $this->appName = 'end_to_end_encryption'; $this->request = $this->createMock(IRequest::class); $this->userId = 'admin'; $this->keyStorage = $this->createMock(IKeyStorage::class); $this->signatureHandler = $this->createMock(SignatureHandler::class); $this->logger = $this->createMock(LoggerInterface::class); $this->l10n = $this->createMock(IL10N::class); + $this->shareManager = $this->createMock(IManager::class); - $this->controller = new KeyController($this->appName, + $this->controller = new KeyController( $this->request, $this->userId, $this->keyStorage, $this->signatureHandler, $this->logger, - $this->l10n); + $this->l10n, + $this->shareManager, + ); } /** @@ -129,7 +116,7 @@ public function testGetPrivateKey(?\Exception $keyStorageException, if ($expectLogger) { $this->logger->expects($this->once()) ->method('critical') - ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => $this->appName]); + ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => 'end_to_end_encryption']); } if ($expectedException) { @@ -187,7 +174,7 @@ public function testDeletePrivateKey(?\Exception $keyStorageException, if ($expectLogger) { $this->logger->expects($this->once()) ->method('critical') - ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => $this->appName]); + ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => 'end_to_end_encryption']); } if ($expectedException) { @@ -248,7 +235,7 @@ public function testSetPrivateKey(?\Exception $keyStorageException, if ($expectLogger) { $this->logger->expects($this->once()) ->method('critical') - ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => $this->appName]); + ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => 'end_to_end_encryption']); } if ($expectedException) { @@ -296,6 +283,35 @@ public function testGetPublicKeys(): void { ], $response->getData()); } + public function testGetPublicKeysForShare(): void { + $users = '["user1","s:share-token"]'; + + $this->keyStorage->expects($this->exactly(2)) + ->method('getPublicKey') + ->willReturnMap([ + ['user1', 'USER1-PUBLIC-KEY'], + ['s:share-token', 'SHARE-PUBLIC-KEY'], + ]); + + $controller = new KeyController( + $this->request, + null, + $this->keyStorage, + $this->signatureHandler, + $this->logger, + $this->l10n, + $this->shareManager, + ); + $response = $controller->getPublicKeys($users); + $this->assertInstanceOf(DataResponse::class, $response); + $this->assertEquals([ + 'public-keys' => [ + 'user1' => 'USER1-PUBLIC-KEY', + 's:share-token' => 'SHARE-PUBLIC-KEY', + ] + ], $response->getData()); + } + public function testGetPublicKeysInvalidJSON(): void { $users = 'INVALID-JSON'; @@ -349,7 +365,7 @@ public function testGetPublicKeysGenericException(): void { $this->logger->expects($this->once()) ->method('critical') - ->with($exception->getMessage(), ['exception' => $exception, 'app' => $this->appName]); + ->with($exception->getMessage(), ['exception' => $exception, 'app' => 'end_to_end_encryption']); $this->expectException(OCSBadRequestException::class); $this->expectExceptionMessage('Internal error'); @@ -380,23 +396,23 @@ public function testCreatePublicKeySuccessful(): void { } public function testCreatePublicKeyInvalidCN(): void { - $controller = new KeyController($this->appName, + $controller = new KeyController( $this->request, 'user123', $this->keyStorage, $this->signatureHandler, $this->logger, - $this->l10n); + $this->l10n, + $this->shareManager, + ); $this->keyStorage->expects($this->once()) ->method('publicKeyExists') ->with('user123') ->willReturn(false); - $this->signatureHandler->expects($this->once()) - ->method('sign') - ->with($this->validCSR) - ->willReturn('MY-PUBLIC-KEY'); + $this->signatureHandler->expects($this->never()) + ->method('sign'); $this->keyStorage->expects($this->never()) ->method('setPublicKey'); @@ -419,10 +435,8 @@ public function testCreatePublicKeyInvalidCSR(): void { ->with('admin') ->willReturn(false); - $this->signatureHandler->expects($this->once()) - ->method('sign') - ->with($this->invalidCSR) - ->willThrowException(new \BadMethodCallException()); + $this->signatureHandler->expects($this->never()) + ->method('sign'); $this->expectException(OCSBadRequestException::class); @@ -473,7 +487,10 @@ public function testDeletePublicKey(?\Exception $keyStorageException, if ($expectLogger) { $this->logger->expects($this->once()) ->method('critical') - ->with($keyStorageException->getMessage(), ['exception' => $keyStorageException, 'app' => $this->appName]); + ->with( + $keyStorageException->getMessage(), + ['exception' => $keyStorageException, 'app' => 'end_to_end_encryption'], + ); } if ($expectedException) { diff --git a/tests/Unit/KeyStorageTest.php b/tests/Unit/KeyStorageTest.php index ba93e2511..a353bad17 100644 --- a/tests/Unit/KeyStorageTest.php +++ b/tests/Unit/KeyStorageTest.php @@ -18,26 +18,29 @@ use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IUser; use OCP\IUserSession; +use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class KeyStorageTest extends TestCase { - /** @var IAppData|\PHPUnit\Framework\MockObject\MockObject */ - private $appData; - - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - - /** @var KeyStorage */ - private $keyStorage; + private IAppData&MockObject $appData; + private IUserSession&MockObject $userSession; + private IManager&MockObject $shareManager; + private KeyStorage $keyStorage; protected function setUp(): void { parent::setUp(); $this->appData = $this->createMock(IAppData::class); $this->userSession = $this->createMock(IUserSession::class); + $this->shareManager = $this->createMock(IManager::class); - $this->keyStorage = new KeyStorage($this->appData, $this->userSession); + $this->keyStorage = new KeyStorage( + $this->appData, + $this->userSession, + $this->shareManager, + ); } public function testGetPublicKey(): void { @@ -67,8 +70,6 @@ public function testGetPublicKey(): void { * @param bool $expected */ public function testPublicKeyExists(bool $exists, bool $expected): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - $folder = $this->createMock(ISimpleFolder::class); $folder->expects($this->once()) ->method('fileExists') @@ -79,7 +80,7 @@ public function testPublicKeyExists(bool $exists, bool $expected): void { ->method('getFolder') ->willReturn($folder); - $actual = $keyStorage->publicKeyExists('jane'); + $actual = $this->keyStorage->publicKeyExists('jane'); $this->assertEquals($expected, $actual); } @@ -98,8 +99,6 @@ public function publicKeyExistsDataProvider(): array { * @param bool $expectsNewFile */ public function testSetPublicKey(bool $exists, bool $expectsKeyExistsException, bool $expectsNewFile): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - $folder = $this->createMock(ISimpleFolder::class); $folder->expects($this->once()) ->method('fileExists') @@ -127,7 +126,7 @@ public function testSetPublicKey(bool $exists, bool $expectsKeyExistsException, $this->expectExceptionMessage('Public key already exists'); } - $keyStorage->setPublicKey('public-key-content', 'jane'); + $this->keyStorage->setPublicKey('public-key-content', 'jane'); } public function setPublicKeyDataProvider(): array { @@ -147,8 +146,6 @@ public function setPublicKeyDataProvider(): array { * @param bool $expectDelete */ public function testDeletePublicKey(bool $getUserReturnsNull, string $userId, bool $notFoundException, bool $expectsNotPermittedException, bool $expectDelete): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - if ($getUserReturnsNull) { $this->userSession->expects($this->once()) ->method('getUser') @@ -197,7 +194,7 @@ public function testDeletePublicKey(bool $getUserReturnsNull, string $userId, bo $this->expectExceptionMessage('You are not allowed to delete the public key'); } - $keyStorage->deletePublicKey($userId); + $this->keyStorage->deletePublicKey($userId); } public function deletePublicKeyDataProvider(): array { @@ -217,8 +214,6 @@ public function deletePublicKeyDataProvider(): array { * @param bool $expectsForbiddenException */ public function testGetPrivateKey(bool $getUserReturnsNull, string $userId, bool $expectsForbiddenException): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - if ($getUserReturnsNull) { $this->userSession->expects($this->once()) ->method('getUser') @@ -256,9 +251,9 @@ public function testGetPrivateKey(bool $getUserReturnsNull, string $userId, bool $this->expectException(ForbiddenException::class); $this->expectExceptionMessage('You are not allowed to access the private key'); - $keyStorage->getPrivateKey($userId); + $this->keyStorage->getPrivateKey($userId); } else { - $actual = $keyStorage->getPrivateKey($userId); + $actual = $this->keyStorage->getPrivateKey($userId); $this->assertEquals('private-key-content', $actual); } } @@ -281,8 +276,6 @@ public function getPrivateKeyDataProvider(): array { * @param bool $expectsForbiddenException */ public function testPrivateKeyExists(bool $getUserReturnsNull, string $userId, bool $exists, bool $expected, bool $expectsForbiddenException): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - if ($getUserReturnsNull) { $this->userSession->expects($this->once()) ->method('getUser') @@ -314,9 +307,9 @@ public function testPrivateKeyExists(bool $getUserReturnsNull, string $userId, b $this->expectException(ForbiddenException::class); $this->expectExceptionMessage('You are not allowed to access the private key'); - $keyStorage->privateKeyExists($userId); + $this->keyStorage->privateKeyExists($userId); } else { - $actual = $keyStorage->privateKeyExists($userId); + $actual = $this->keyStorage->privateKeyExists($userId); $this->assertEquals($expected, $actual); } } @@ -341,8 +334,6 @@ public function privateKeyExistsDataProvider(): array { * @param bool $expectsPutContent */ public function testSetPrivateKey(bool $getUserReturnsNull, string $userId, bool $fileExists, bool $expectsForbiddenException, bool $expectsKeyExistsException, bool $expectsPutContent): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - if ($getUserReturnsNull) { $this->userSession->expects($this->once()) ->method('getUser') @@ -386,14 +377,14 @@ public function testSetPrivateKey(bool $getUserReturnsNull, string $userId, bool $this->expectException(ForbiddenException::class); $this->expectExceptionMessage('You are not allowed to write the private key'); - $keyStorage->setPrivateKey('private-key-content', $userId); + $this->keyStorage->setPrivateKey('private-key-content', $userId); } elseif ($expectsKeyExistsException) { $this->expectException(KeyExistsException::class); $this->expectExceptionMessage('Private key already exists'); - $keyStorage->setPrivateKey('private-key-content', $userId); + $this->keyStorage->setPrivateKey('private-key-content', $userId); } else { - $keyStorage->setPrivateKey('private-key-content', $userId); + $this->keyStorage->setPrivateKey('private-key-content', $userId); } } @@ -416,8 +407,6 @@ public function setPrivateKeyDataProvider(): array { * @param bool $expectsDelete */ public function testDeletePrivateKey(bool $getUserReturnsNull, string $userId, bool $fileExists, bool $expectsNotPermittedException, bool $expectsDelete): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - if ($getUserReturnsNull) { $this->userSession->expects($this->once()) ->method('getUser') @@ -462,9 +451,9 @@ public function testDeletePrivateKey(bool $getUserReturnsNull, string $userId, b $this->expectException(NotPermittedException::class); $this->expectExceptionMessage('You are not allowed to delete the private key'); - $keyStorage->deletePrivateKey($userId); + $this->keyStorage->deletePrivateKey($userId); } else { - $keyStorage->deletePrivateKey($userId); + $this->keyStorage->deletePrivateKey($userId); } } @@ -486,8 +475,6 @@ public function deletePrivateKeyDataProvider(): array { * @param bool $expectsPrivateDelete */ public function testDeleteUserKeys(bool $publicNotFound, bool $privateNotFound, bool $expectsPublicDelete, bool $expectsPrivateDelete): void { - $keyStorage = new KeyStorage($this->appData, $this->userSession); - $publicKeyFolder = $this->createMock(ISimpleFolder::class); $privateKeyFolder = $this->createMock(ISimpleFolder::class); @@ -548,7 +535,7 @@ public function testDeleteUserKeys(bool $publicNotFound, bool $privateNotFound, ->method('getUID') ->willReturn('jane'); - $keyStorage->deleteUserKeys($user); + $this->keyStorage->deleteUserKeys($user); } public function deleteUserKeysDataProvider(): array { diff --git a/tests/stub.phpstub b/tests/stub.phpstub index b52f2b25a..8617e405b 100644 --- a/tests/stub.phpstub +++ b/tests/stub.phpstub @@ -650,6 +650,7 @@ namespace OC\Files\Storage\Wrapper{ } namespace OCA\Files_Sharing { + interface ISharedStorage extends \OCP\Files\Storage\IStorage { } @@ -836,6 +837,20 @@ namespace OCA\Files_Sharing { } } +namespace OCA\Files_Sharing\Event { + + class BeforeTemplateRenderedEvent extends \OCP\EventDispatcher\Event { + public const SCOPE_PUBLIC_SHARE_AUTH = 'publicShareAuth'; + + public function getShare(): \OCP\Share\IShare { + } + + public function getScope(): ?string { + } + } + +} + namespace OCA\Files_Trashbin\Events { use OCP\EventDispatcher\Event;