aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Müller <marcel-mueller@gmx.de>2025-08-01 20:50:52 +0200
committerMarcel Müller <marcel-mueller@gmx.de>2025-08-01 22:15:48 +0200
commit7e15dee9dfbbdf425ad3f3ef34fef2e6c38d8df9 (patch)
treeb272fba42bd273d01d0369085a51ebac8c349a1d
parente4ed547bc6ab597d640bdec3fa4b8d16df53f98e (diff)
downloadnextcloud-server-feat/noid/cache-user-keys.tar.gz
nextcloud-server-feat/noid/cache-user-keys.zip
feat: Cache user keysfeat/noid/cache-user-keys
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
-rw-r--r--lib/private/Security/IdentityProof/Manager.php26
-rw-r--r--tests/lib/Security/IdentityProof/ManagerTest.php40
2 files changed, 60 insertions, 6 deletions
diff --git a/lib/private/Security/IdentityProof/Manager.php b/lib/private/Security/IdentityProof/Manager.php
index 935c18bb81d..c16b8314beb 100644
--- a/lib/private/Security/IdentityProof/Manager.php
+++ b/lib/private/Security/IdentityProof/Manager.php
@@ -11,6 +11,8 @@ namespace OC\Security\IdentityProof;
use OC\Files\AppData\Factory;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
+use OCP\ICache;
+use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IUser;
use OCP\Security\ICrypto;
@@ -19,13 +21,17 @@ use Psr\Log\LoggerInterface;
class Manager {
private IAppData $appData;
+ protected ICache $cache;
+
public function __construct(
Factory $appDataFactory,
private ICrypto $crypto,
private IConfig $config,
private LoggerInterface $logger,
+ private ICacheFactory $cacheFactory,
) {
$this->appData = $appDataFactory->get('identityproof');
+ $this->cache = $this->cacheFactory->createDistributed('identityproof::');
}
/**
@@ -96,12 +102,24 @@ class Manager {
*/
protected function retrieveKey(string $id): Key {
try {
+ $cachedPublicKey = $this->cache->get($id . '-public');
+ $cachedPrivateKey = $this->cache->get($id . '-private');
+
+ if ($cachedPublicKey !== null && $cachedPrivateKey !== null) {
+ $decryptedPrivateKey = $this->crypto->decrypt($cachedPrivateKey);
+
+ return new Key($cachedPublicKey, $decryptedPrivateKey);
+ }
+
$folder = $this->appData->getFolder($id);
- $privateKey = $this->crypto->decrypt(
- $folder->getFile('private')->getContent()
- );
+ $privateKey = $folder->getFile('private')->getContent();
$publicKey = $folder->getFile('public')->getContent();
- return new Key($publicKey, $privateKey);
+
+ $this->cache->set($id . '-public', $publicKey);
+ $this->cache->set($id . '-private', $privateKey);
+
+ $decryptedPrivateKey = $this->crypto->decrypt($privateKey);
+ return new Key($publicKey, $decryptedPrivateKey);
} catch (\Exception $e) {
return $this->generateKey($id);
}
diff --git a/tests/lib/Security/IdentityProof/ManagerTest.php b/tests/lib/Security/IdentityProof/ManagerTest.php
index 445158e8a23..9703d09f506 100644
--- a/tests/lib/Security/IdentityProof/ManagerTest.php
+++ b/tests/lib/Security/IdentityProof/ManagerTest.php
@@ -16,6 +16,8 @@ use OC\Security\IdentityProof\Manager;
use OCP\Files\IAppData;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\ICache;
+use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IUser;
use OCP\Security\ICrypto;
@@ -36,6 +38,10 @@ class ManagerTest extends TestCase {
private $config;
/** @var LoggerInterface|MockObject */
private $logger;
+ /** @var LoggerInterface|ICacheFactory */
+ private $cacheFactory;
+ /** @var LoggerInterface|ICache */
+ private $cache;
protected function setUp(): void {
parent::setUp();
@@ -49,6 +55,12 @@ class ManagerTest extends TestCase {
->with('identityproof')
->willReturn($this->appData);
$this->logger = $this->createMock(LoggerInterface::class);
+ $this->cacheFactory = $this->createMock(ICacheFactory::class);
+ $this->cache = $this->createMock(ICache::class);
+
+ $this->cacheFactory->expects($this->any())
+ ->method('createDistributed')
+ ->willReturn($this->cache);
$this->crypto = $this->createMock(ICrypto::class);
$this->manager = $this->getManager(['generateKeyPair']);
@@ -66,7 +78,8 @@ class ManagerTest extends TestCase {
$this->factory,
$this->crypto,
$this->config,
- $this->logger
+ $this->logger,
+ $this->cacheFactory,
);
} else {
return $this->getMockBuilder(Manager::class)
@@ -74,7 +87,8 @@ class ManagerTest extends TestCase {
$this->factory,
$this->crypto,
$this->config,
- $this->logger
+ $this->logger,
+ $this->cacheFactory,
])
->onlyMethods($setMethods)
->getMock();
@@ -115,6 +129,28 @@ class ManagerTest extends TestCase {
->method('getFolder')
->with('user-MyUid')
->willReturn($folder);
+ $this->cache->expects($this->exactly(2))
+ ->method('get')
+ ->willReturnOnConsecutiveCalls(null, null);
+
+ $expected = new Key('MyPublicKey', 'MyPrivateKey');
+ $this->assertEquals($expected, $this->manager->getKey($user));
+ }
+
+ public function testGetKeyWithExistingKeyCached(): void {
+ $user = $this->createMock(IUser::class);
+ $user
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('MyUid');
+ $this->crypto
+ ->expects($this->once())
+ ->method('decrypt')
+ ->with('EncryptedPrivateKey')
+ ->willReturn('MyPrivateKey');
+ $this->cache->expects($this->exactly(2))
+ ->method('get')
+ ->willReturnOnConsecutiveCalls('MyPublicKey', 'EncryptedPrivateKey');
$expected = new Key('MyPublicKey', 'MyPrivateKey');
$this->assertEquals($expected, $this->manager->getKey($user));