Skip to content

Commit e4aeea5

Browse files
committed
feat: Cache user keys
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
1 parent e4ed547 commit e4aeea5

File tree

2 files changed

+71
-18
lines changed

2 files changed

+71
-18
lines changed

lib/private/Security/IdentityProof/Manager.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use OC\Files\AppData\Factory;
1212
use OCP\Files\IAppData;
1313
use OCP\Files\NotFoundException;
14+
use OCP\ICache;
15+
use OCP\ICacheFactory;
1416
use OCP\IConfig;
1517
use OCP\IUser;
1618
use OCP\Security\ICrypto;
@@ -19,13 +21,17 @@
1921
class Manager {
2022
private IAppData $appData;
2123

24+
protected ICache $cache;
25+
2226
public function __construct(
2327
Factory $appDataFactory,
2428
private ICrypto $crypto,
2529
private IConfig $config,
2630
private LoggerInterface $logger,
31+
private ICacheFactory $cacheFactory,
2732
) {
2833
$this->appData = $appDataFactory->get('identityproof');
34+
$this->cache = $this->cacheFactory->createDistributed('identityproof::');
2935
}
3036

3137
/**
@@ -96,12 +102,24 @@ protected function generateKey(string $id, array $options = []): Key {
96102
*/
97103
protected function retrieveKey(string $id): Key {
98104
try {
105+
$cachedPublicKey = $this->cache->get($id . '-public');
106+
$cachedPrivateKey = $this->cache->get($id . '-private');
107+
108+
if ($cachedPublicKey !== null && $cachedPrivateKey !== null) {
109+
$decryptedPrivateKey = $this->crypto->decrypt($cachedPrivateKey);
110+
111+
return new Key($cachedPublicKey, $decryptedPrivateKey);
112+
}
113+
99114
$folder = $this->appData->getFolder($id);
100-
$privateKey = $this->crypto->decrypt(
101-
$folder->getFile('private')->getContent()
102-
);
115+
$privateKey = $folder->getFile('private')->getContent();
103116
$publicKey = $folder->getFile('public')->getContent();
104-
return new Key($publicKey, $privateKey);
117+
118+
$this->cache->set($id . '-public', $publicKey);
119+
$this->cache->set($id . '-private', $privateKey);
120+
121+
$decryptedPrivateKey = $this->crypto->decrypt($privateKey);
122+
return new Key($publicKey, $decryptedPrivateKey);
105123
} catch (\Exception $e) {
106124
return $this->generateKey($id);
107125
}

tests/lib/Security/IdentityProof/ManagerTest.php

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99

1010
namespace Test\Security\IdentityProof;
1111

12+
use Hoa\Iterator\Mock;
1213
use OC\Files\AppData\AppData;
1314
use OC\Files\AppData\Factory;
1415
use OC\Security\IdentityProof\Key;
1516
use OC\Security\IdentityProof\Manager;
17+
use OCA\WorkflowEngine\Service\Logger;
1618
use OCP\Files\IAppData;
1719
use OCP\Files\SimpleFS\ISimpleFile;
1820
use OCP\Files\SimpleFS\ISimpleFolder;
21+
use OCP\ICache;
22+
use OCP\ICacheFactory;
1923
use OCP\IConfig;
2024
use OCP\IUser;
2125
use OCP\Security\ICrypto;
@@ -24,18 +28,14 @@
2428
use Test\TestCase;
2529

2630
class ManagerTest extends TestCase {
27-
/** @var Factory|MockObject */
28-
private $factory;
29-
/** @var IAppData|MockObject */
30-
private $appData;
31-
/** @var ICrypto|MockObject */
32-
private $crypto;
33-
/** @var Manager|MockObject */
34-
private $manager;
35-
/** @var IConfig|MockObject */
36-
private $config;
37-
/** @var LoggerInterface|MockObject */
38-
private $logger;
31+
private Factory&MockObject $factory;
32+
private IAppData&MockObject $appData;
33+
private ICrypto&MockObject $crypto;
34+
private Manager&MockObject $manager;
35+
private IConfig&MockObject $config;
36+
private LoggerInterface&MockObject $logger;
37+
private ICacheFactory&MockObject $cacheFactory;
38+
private ICache&MockObject $cache;
3939

4040
protected function setUp(): void {
4141
parent::setUp();
@@ -49,6 +49,12 @@ protected function setUp(): void {
4949
->with('identityproof')
5050
->willReturn($this->appData);
5151
$this->logger = $this->createMock(LoggerInterface::class);
52+
$this->cacheFactory = $this->createMock(ICacheFactory::class);
53+
$this->cache = $this->createMock(ICache::class);
54+
55+
$this->cacheFactory->expects($this->any())
56+
->method('createDistributed')
57+
->willReturn($this->cache);
5258

5359
$this->crypto = $this->createMock(ICrypto::class);
5460
$this->manager = $this->getManager(['generateKeyPair']);
@@ -66,15 +72,17 @@ protected function getManager($setMethods = []) {
6672
$this->factory,
6773
$this->crypto,
6874
$this->config,
69-
$this->logger
75+
$this->logger,
76+
$this->cacheFactory,
7077
);
7178
} else {
7279
return $this->getMockBuilder(Manager::class)
7380
->setConstructorArgs([
7481
$this->factory,
7582
$this->crypto,
7683
$this->config,
77-
$this->logger
84+
$this->logger,
85+
$this->cacheFactory,
7886
])
7987
->onlyMethods($setMethods)
8088
->getMock();
@@ -115,6 +123,33 @@ public function testGetKeyWithExistingKey(): void {
115123
->method('getFolder')
116124
->with('user-MyUid')
117125
->willReturn($folder);
126+
$this->cache
127+
->expects($this->exactly(2))
128+
->method('get')
129+
->willReturn(null);
130+
131+
$expected = new Key('MyPublicKey', 'MyPrivateKey');
132+
$this->assertEquals($expected, $this->manager->getKey($user));
133+
}
134+
135+
public function testGetKeyWithExistingKeyCached(): void {
136+
$user = $this->createMock(IUser::class);
137+
$user
138+
->expects($this->once())
139+
->method('getUID')
140+
->willReturn('MyUid');
141+
$this->crypto
142+
->expects($this->once())
143+
->method('decrypt')
144+
->with('EncryptedPrivateKey')
145+
->willReturn('MyPrivateKey');
146+
$this->cache
147+
->expects($this->exactly(2))
148+
->method('get')
149+
->willReturnMap([
150+
['user-MyUid-public', 'MyPublicKey'],
151+
['user-MyUid-private', 'EncryptedPrivateKey'],
152+
]);
118153

119154
$expected = new Key('MyPublicKey', 'MyPrivateKey');
120155
$this->assertEquals($expected, $this->manager->getKey($user));

0 commit comments

Comments
 (0)