Skip to content

Commit fc22188

Browse files
committed
feat(encryption): Migrate from hooks to events
Signed-off-by: Côme Chilliet <[email protected]>
1 parent 093ed1e commit fc22188

File tree

9 files changed

+133
-153
lines changed

9 files changed

+133
-153
lines changed

apps/files_versions/lib/Listener/FileEventsListener.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public function post_write_hook(Node $node): void {
241241
/**
242242
* Erase versions of deleted file
243243
*
244-
* This function is connected to the delete signal of OC_Filesystem
244+
* This function is connected to the NodeDeletedEvent event
245245
* cleanup the versions directory if the actual file gets deleted
246246
*/
247247
public function remove_hook(Node $node): void {
@@ -273,7 +273,7 @@ public function pre_remove_hook(Node $node): void {
273273
/**
274274
* rename/move versions of renamed/moved files
275275
*
276-
* This function is connected to the rename signal of OC_Filesystem and adjust the name and location
276+
* This function is connected to the NodeRenamedEvent event and adjust the name and location
277277
* of the stored versions along the actual file
278278
*/
279279
public function rename_hook(Node $source, Node $target): void {
@@ -292,7 +292,7 @@ public function rename_hook(Node $source, Node $target): void {
292292
/**
293293
* copy versions of copied files
294294
*
295-
* This function is connected to the copy signal of OC_Filesystem and copies the
295+
* This function is connected to the NodeCopiedEvent event and copies the
296296
* the stored versions to the new location
297297
*/
298298
public function copy_hook(Node $source, Node $target): void {

lib/base.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
* SPDX-FileCopyrightText: 2013-2016 ownCloud, Inc.
77
* SPDX-License-Identifier: AGPL-3.0-only
88
*/
9-
use OC\Encryption\HookManager;
109
use OC\Share20\Hooks;
1110
use OCP\EventDispatcher\IEventDispatcher;
11+
use OCP\Files\Events\BeforeFileSystemSetupEvent;
1212
use OCP\Group\Events\UserRemovedEvent;
1313
use OCP\ILogger;
1414
use OCP\IRequest;
1515
use OCP\IURLGenerator;
1616
use OCP\IUserSession;
1717
use OCP\Security\Bruteforce\IThrottler;
1818
use OCP\Server;
19-
use OCP\Share;
2019
use OCP\User\Events\UserChangedEvent;
2120
use Psr\Log\LoggerInterface;
2221
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
@@ -860,15 +859,16 @@ public static function registerCleanupHooks(\OC\SystemConfig $systemConfig): voi
860859
}
861860

862861
private static function registerEncryptionWrapperAndHooks(): void {
862+
/** @var \OC\Encryption\Manager */
863863
$manager = Server::get(\OCP\Encryption\IManager::class);
864-
\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
864+
Server::get(IEventDispatcher::class)->addListener(
865+
BeforeFileSystemSetupEvent::class,
866+
$manager->setupStorage(...),
867+
);
865868

866869
$enabled = $manager->isEnabled();
867870
if ($enabled) {
868-
\OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
869-
\OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
870-
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
871-
\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
871+
\OC\Encryption\EncryptionEventListener::register(Server::get(IEventDispatcher::class));
872872
}
873873
}
874874

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,7 @@
14631463
'OC\\DirectEditing\\Token' => $baseDir . '/lib/private/DirectEditing/Token.php',
14641464
'OC\\EmojiHelper' => $baseDir . '/lib/private/EmojiHelper.php',
14651465
'OC\\Encryption\\DecryptAll' => $baseDir . '/lib/private/Encryption/DecryptAll.php',
1466+
'OC\\Encryption\\EncryptionEventListener' => $baseDir . '/lib/private/Encryption/EncryptionEventListener.php',
14661467
'OC\\Encryption\\EncryptionWrapper' => $baseDir . '/lib/private/Encryption/EncryptionWrapper.php',
14671468
'OC\\Encryption\\Exceptions\\DecryptionFailedException' => $baseDir . '/lib/private/Encryption/Exceptions/DecryptionFailedException.php',
14681469
'OC\\Encryption\\Exceptions\\EmptyEncryptionDataException' => $baseDir . '/lib/private/Encryption/Exceptions/EmptyEncryptionDataException.php',
@@ -1473,7 +1474,6 @@
14731474
'OC\\Encryption\\Exceptions\\ModuleDoesNotExistsException' => $baseDir . '/lib/private/Encryption/Exceptions/ModuleDoesNotExistsException.php',
14741475
'OC\\Encryption\\Exceptions\\UnknownCipherException' => $baseDir . '/lib/private/Encryption/Exceptions/UnknownCipherException.php',
14751476
'OC\\Encryption\\File' => $baseDir . '/lib/private/Encryption/File.php',
1476-
'OC\\Encryption\\HookManager' => $baseDir . '/lib/private/Encryption/HookManager.php',
14771477
'OC\\Encryption\\Keys\\Storage' => $baseDir . '/lib/private/Encryption/Keys/Storage.php',
14781478
'OC\\Encryption\\Manager' => $baseDir . '/lib/private/Encryption/Manager.php',
14791479
'OC\\Encryption\\Update' => $baseDir . '/lib/private/Encryption/Update.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
14961496
'OC\\DirectEditing\\Token' => __DIR__ . '/../../..' . '/lib/private/DirectEditing/Token.php',
14971497
'OC\\EmojiHelper' => __DIR__ . '/../../..' . '/lib/private/EmojiHelper.php',
14981498
'OC\\Encryption\\DecryptAll' => __DIR__ . '/../../..' . '/lib/private/Encryption/DecryptAll.php',
1499+
'OC\\Encryption\\EncryptionEventListener' => __DIR__ . '/../../..' . '/lib/private/Encryption/EncryptionEventListener.php',
14991500
'OC\\Encryption\\EncryptionWrapper' => __DIR__ . '/../../..' . '/lib/private/Encryption/EncryptionWrapper.php',
15001501
'OC\\Encryption\\Exceptions\\DecryptionFailedException' => __DIR__ . '/../../..' . '/lib/private/Encryption/Exceptions/DecryptionFailedException.php',
15011502
'OC\\Encryption\\Exceptions\\EmptyEncryptionDataException' => __DIR__ . '/../../..' . '/lib/private/Encryption/Exceptions/EmptyEncryptionDataException.php',
@@ -1506,7 +1507,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
15061507
'OC\\Encryption\\Exceptions\\ModuleDoesNotExistsException' => __DIR__ . '/../../..' . '/lib/private/Encryption/Exceptions/ModuleDoesNotExistsException.php',
15071508
'OC\\Encryption\\Exceptions\\UnknownCipherException' => __DIR__ . '/../../..' . '/lib/private/Encryption/Exceptions/UnknownCipherException.php',
15081509
'OC\\Encryption\\File' => __DIR__ . '/../../..' . '/lib/private/Encryption/File.php',
1509-
'OC\\Encryption\\HookManager' => __DIR__ . '/../../..' . '/lib/private/Encryption/HookManager.php',
15101510
'OC\\Encryption\\Keys\\Storage' => __DIR__ . '/../../..' . '/lib/private/Encryption/Keys/Storage.php',
15111511
'OC\\Encryption\\Manager' => __DIR__ . '/../../..' . '/lib/private/Encryption/Manager.php',
15121512
'OC\\Encryption\\Update' => __DIR__ . '/../../..' . '/lib/private/Encryption/Update.php',
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-only
8+
*/
9+
10+
namespace OC\Encryption;
11+
12+
use OC\Files\Filesystem;
13+
use OC\Files\SetupManager;
14+
use OC\Files\View;
15+
use OCA\Files_Trashbin\Events\NodeRestoredEvent;
16+
use OCP\Encryption\IFile;
17+
use OCP\EventDispatcher\Event;
18+
use OCP\EventDispatcher\IEventDispatcher;
19+
use OCP\EventDispatcher\IEventListener;
20+
use OCP\Files\Events\Node\NodeRenamedEvent;
21+
use OCP\Files\Folder;
22+
use OCP\IUser;
23+
use OCP\IUserSession;
24+
use OCP\Share\Events\ShareCreatedEvent;
25+
use OCP\Share\Events\ShareDeletedEvent;
26+
use Psr\Log\LoggerInterface;
27+
28+
/** @template-implements IEventListener<NodeRenamedEvent|ShareCreatedEvent|ShareDeletedEvent|NodeRestoredEvent> */
29+
class EncryptionEventListener implements IEventListener {
30+
private ?Update $updater = null;
31+
32+
public function __construct(
33+
private IUserSession $userSession,
34+
private SetupManager $setupManager,
35+
) {
36+
}
37+
38+
public static function register(IEventDispatcher $dispatcher): void {
39+
$dispatcher->addServiceListener(NodeRenamedEvent::class, static::class);
40+
$dispatcher->addServiceListener(ShareCreatedEvent::class, static::class);
41+
$dispatcher->addServiceListener(ShareDeletedEvent::class, static::class);
42+
$dispatcher->addServiceListener(NodeRestoredEvent::class, static::class);
43+
}
44+
45+
public function handle(Event $event): void {
46+
if ($event instanceof NodeRenamedEvent) {
47+
$this->getUpdate()->postRename($event->getSource() instanceof Folder, $event->getSource()->getPath(), $event->getTarget()->getPath());
48+
} elseif ($event instanceof ShareCreatedEvent) {
49+
$this->getUpdate()->postShared($event->getShare()->getNodeType(), $event->getShare()->getNodeId());
50+
} elseif ($event instanceof ShareDeletedEvent) {
51+
// In case the unsharing happens in a background job, we don't have
52+
// a session and we load instead the user from the UserManager
53+
$owner = $event->getShare()->getNode()->getOwner();
54+
$this->getUpdate($owner)->postUnshared($event->getShare()->getNodeType(), $event->getShare()->getNodeId());
55+
} elseif ($event instanceof NodeRestoredEvent) {
56+
$this->getUpdate()->postRestore($event->getTarget() instanceof Folder, $event->getTarget()->getPath());
57+
}
58+
}
59+
60+
private function getUpdate(?IUser $owner = null): Update {
61+
if (is_null($this->updater)) {
62+
$user = $this->userSession->getUser();
63+
if (!$user && ($owner !== null)) {
64+
$user = $owner;
65+
}
66+
if (!$user) {
67+
throw new \Exception('Inconsistent data, File unshared, but owner not found. Should not happen');
68+
}
69+
70+
$uid = $user->getUID();
71+
72+
if (!$this->setupManager->isSetupComplete($user)) {
73+
$this->setupManager->setupForUser($user);
74+
}
75+
76+
$this->updater = new Update(
77+
new Util(
78+
new View(),
79+
\OC::$server->getUserManager(),
80+
\OC::$server->getGroupManager(),
81+
\OC::$server->getConfig()),
82+
Filesystem::getMountManager(),
83+
\OC::$server->getEncryptionManager(),
84+
\OC::$server->get(IFile::class),
85+
\OC::$server->get(LoggerInterface::class),
86+
$uid
87+
);
88+
}
89+
90+
return $this->updater;
91+
}
92+
}

lib/private/Encryption/EncryptionWrapper.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ public function wrapStorage(string $mountPoint, IStorage $storage, IMountPoint $
7676
\OC::$server->getConfig()
7777
);
7878
$update = new Update(
79-
new View(),
8079
$util,
8180
Filesystem::getMountManager(),
8281
$this->manager,

lib/private/Encryption/HookManager.php

Lines changed: 0 additions & 75 deletions
This file was deleted.

lib/private/Encryption/Update.php

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
* update encrypted files, e.g. because a file was shared
1919
*/
2020
class Update {
21-
/** @var View */
22-
protected $view;
23-
2421
/** @var Util */
2522
protected $util;
2623

@@ -43,15 +40,13 @@ class Update {
4340
* @param string $uid
4441
*/
4542
public function __construct(
46-
View $view,
4743
Util $util,
4844
Mount\Manager $mountManager,
4945
Manager $encryptionManager,
5046
File $file,
5147
LoggerInterface $logger,
5248
$uid,
5349
) {
54-
$this->view = $view;
5550
$this->util = $util;
5651
$this->mountManager = $mountManager;
5752
$this->encryptionManager = $encryptionManager;
@@ -62,65 +57,55 @@ public function __construct(
6257

6358
/**
6459
* hook after file was shared
65-
*
66-
* @param array $params
6760
*/
68-
public function postShared($params) {
61+
public function postShared(string $nodeType, int $nodeId): void {
6962
if ($this->encryptionManager->isEnabled()) {
70-
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
71-
$path = Filesystem::getPath($params['fileSource']);
63+
if ($nodeType === 'file' || $nodeType === 'folder') {
64+
$path = Filesystem::getPath($nodeId);
7265
[$owner, $ownerPath] = $this->getOwnerPath($path);
7366
$absPath = '/' . $owner . '/files/' . $ownerPath;
74-
$this->update($absPath);
67+
$this->update($nodeType === 'folder', $absPath);
7568
}
7669
}
7770
}
7871

7972
/**
8073
* hook after file was unshared
81-
*
82-
* @param array $params
8374
*/
84-
public function postUnshared($params) {
75+
public function postUnshared(string $nodeType, int $nodeId): void {
8576
if ($this->encryptionManager->isEnabled()) {
86-
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
87-
$path = Filesystem::getPath($params['fileSource']);
77+
if ($nodeType === 'file' || $nodeType === 'folder') {
78+
$path = Filesystem::getPath($nodeId);
8879
[$owner, $ownerPath] = $this->getOwnerPath($path);
8980
$absPath = '/' . $owner . '/files/' . $ownerPath;
90-
$this->update($absPath);
81+
$this->update($nodeType === 'folder', $absPath);
9182
}
9283
}
9384
}
9485

9586
/**
9687
* inform encryption module that a file was restored from the trash bin,
9788
* e.g. to update the encryption keys
98-
*
99-
* @param array $params
10089
*/
101-
public function postRestore($params) {
90+
public function postRestore(bool $directory, string $filePath): void {
10291
if ($this->encryptionManager->isEnabled()) {
103-
$path = Filesystem::normalizePath('/' . $this->uid . '/files/' . $params['filePath']);
104-
$this->update($path);
92+
$path = Filesystem::normalizePath('/' . $this->uid . '/files/' . $filePath);
93+
$this->update($directory, $path);
10594
}
10695
}
10796

10897
/**
10998
* inform encryption module that a file was renamed,
11099
* e.g. to update the encryption keys
111-
*
112-
* @param array $params
113100
*/
114-
public function postRename($params) {
115-
$source = $params['oldpath'];
116-
$target = $params['newpath'];
101+
public function postRename(bool $directory, string $source, string $target): void {
117102
if (
118103
$this->encryptionManager->isEnabled() &&
119104
dirname($source) !== dirname($target)
120105
) {
121106
[$owner, $ownerPath] = $this->getOwnerPath($target);
122107
$absPath = '/' . $owner . '/files/' . $ownerPath;
123-
$this->update($absPath);
108+
$this->update($directory, $absPath);
124109
}
125110
}
126111

@@ -149,7 +134,7 @@ protected function getOwnerPath($path) {
149134
* @param string $path relative to data/
150135
* @throws Exceptions\ModuleDoesNotExistsException
151136
*/
152-
public function update($path) {
137+
public function update(bool $directory, string $path): void {
153138
$encryptionModule = $this->encryptionManager->getEncryptionModule();
154139

155140
// if the encryption module doesn't encrypt the files on a per-user basis
@@ -159,7 +144,7 @@ public function update($path) {
159144
}
160145

161146
// if a folder was shared, get a list of all (sub-)folders
162-
if ($this->view->is_dir($path)) {
147+
if ($directory) {
163148
$allFiles = $this->util->getAllFiles($path);
164149
} else {
165150
$allFiles = [$path];

0 commit comments

Comments
 (0)