Skip to content

Commit 6bda2c2

Browse files
authored
Merge pull request #22423 from nextcloud/bugfix/noid/direct-editing-encryption
Do not expose direct editing if no master key is available
2 parents 2b192e7 + e0ae377 commit 6bda2c2

5 files changed

Lines changed: 60 additions & 10 deletions

File tree

apps/files/lib/Controller/DirectEditingController.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ public function info(): DataResponse {
7676
* @NoAdminRequired
7777
*/
7878
public function create(string $path, string $editorId, string $creatorId, string $templateId = null): DataResponse {
79+
if (!$this->directEditingManager->isEnabled()) {
80+
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
81+
}
7982
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
8083

8184
try {
@@ -85,14 +88,17 @@ public function create(string $path, string $editorId, string $creatorId, string
8588
]);
8689
} catch (Exception $e) {
8790
$this->logger->logException($e, ['message' => 'Exception when creating a new file through direct editing']);
88-
return new DataResponse('Failed to create file: ' . $e->getMessage(), Http::STATUS_FORBIDDEN);
91+
return new DataResponse(['message' => 'Failed to create file: ' . $e->getMessage()], Http::STATUS_FORBIDDEN);
8992
}
9093
}
9194

9295
/**
9396
* @NoAdminRequired
9497
*/
9598
public function open(string $path, string $editorId = null): DataResponse {
99+
if (!$this->directEditingManager->isEnabled()) {
100+
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
101+
}
96102
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
97103

98104
try {
@@ -102,7 +108,7 @@ public function open(string $path, string $editorId = null): DataResponse {
102108
]);
103109
} catch (Exception $e) {
104110
$this->logger->logException($e, ['message' => 'Exception when opening a file through direct editing']);
105-
return new DataResponse('Failed to open file: ' . $e->getMessage(), Http::STATUS_FORBIDDEN);
111+
return new DataResponse(['message' => 'Failed to open file: ' . $e->getMessage()], Http::STATUS_FORBIDDEN);
106112
}
107113
}
108114

@@ -112,13 +118,16 @@ public function open(string $path, string $editorId = null): DataResponse {
112118
* @NoAdminRequired
113119
*/
114120
public function templates(string $editorId, string $creatorId): DataResponse {
121+
if (!$this->directEditingManager->isEnabled()) {
122+
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
123+
}
115124
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
116125

117126
try {
118127
return new DataResponse($this->directEditingManager->getTemplates($editorId, $creatorId));
119128
} catch (Exception $e) {
120129
$this->logger->logException($e);
121-
return new DataResponse('Failed to obtain template list: ' . $e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR);
130+
return new DataResponse(['message' => 'Failed to obtain template list: ' . $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
122131
}
123132
}
124133
}

apps/files/lib/Service/DirectEditingService.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public function getDirectEditingCapabilitites(): array {
5555
'creators' => []
5656
];
5757

58+
if (!$this->directEditingManager->isEnabled()) {
59+
return $capabilities;
60+
}
61+
5862
/**
5963
* @var string $id
6064
* @var IEditor $editor

lib/private/DirectEditing/Manager.php

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use OCP\DirectEditing\IEditor;
3636
use \OCP\DirectEditing\IManager;
3737
use OCP\DirectEditing\IToken;
38+
use OCP\Encryption\IManager as EncryptionManager;
3839
use OCP\Files\File;
3940
use OCP\Files\IRootFolder;
4041
use OCP\Files\Node;
@@ -45,6 +46,7 @@
4546
use OCP\L10N\IFactory;
4647
use OCP\Security\ISecureRandom;
4748
use OCP\Share\IShare;
49+
use Throwable;
4850
use function array_key_exists;
4951
use function in_array;
5052

@@ -55,30 +57,33 @@ class Manager implements IManager {
5557

5658
/** @var IEditor[] */
5759
private $editors = [];
58-
5960
/** @var IDBConnection */
6061
private $connection;
61-
/**
62-
* @var ISecureRandom
63-
*/
62+
/** @var ISecureRandom */
6463
private $random;
64+
/** @var string|null */
6565
private $userId;
66+
/** @var IRootFolder */
6667
private $rootFolder;
6768
/** @var IL10N */
6869
private $l10n;
70+
/** @var EncryptionManager */
71+
private $encryptionManager;
6972

7073
public function __construct(
7174
ISecureRandom $random,
7275
IDBConnection $connection,
7376
IUserSession $userSession,
7477
IRootFolder $rootFolder,
75-
IFactory $l10nFactory
78+
IFactory $l10nFactory,
79+
EncryptionManager $encryptionManager
7680
) {
7781
$this->random = $random;
7882
$this->connection = $connection;
7983
$this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null;
8084
$this->rootFolder = $rootFolder;
8185
$this->l10n = $l10nFactory->get('core');
86+
$this->encryptionManager = $encryptionManager;
8287
}
8388

8489
public function registerDirectEditor(IEditor $directEditor): void {
@@ -171,7 +176,7 @@ public function edit(string $token): Response {
171176
}
172177
$editor = $this->getEditor($tokenObject->getEditor());
173178
$this->accessToken($token);
174-
} catch (\Throwable $throwable) {
179+
} catch (Throwable $throwable) {
175180
$this->invalidateToken($token);
176181
return new NotFoundResponse();
177182
}
@@ -275,4 +280,22 @@ public function getFileForToken($userId, $fileId, $filePath = null): Node {
275280
}
276281
return $files[0];
277282
}
283+
284+
public function isEnabled(): bool {
285+
if (!$this->encryptionManager->isEnabled()) {
286+
return true;
287+
}
288+
289+
try {
290+
$moduleId = $this->encryptionManager->getDefaultEncryptionModuleId();
291+
$module = $this->encryptionManager->getEncryptionModule($moduleId);
292+
/** @var \OCA\Encryption\Util $util */
293+
$util = \OC::$server->get(\OCA\Encryption\Util::class);
294+
if ($module->isReadyForUser($this->userId) && $util->isMasterKeyEnabled()) {
295+
return true;
296+
}
297+
} catch (Throwable $e) {
298+
}
299+
return false;
300+
}
278301
}

lib/public/DirectEditing/IManager.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,12 @@ public function getToken(string $token): IToken;
8484
* @return int number of deleted tokens
8585
*/
8686
public function cleanup(): int;
87+
88+
/**
89+
* Check if direct editing is enabled
90+
*
91+
* @since 20.0.0
92+
* @return bool
93+
*/
94+
public function isEnabled(): bool;
8795
}

tests/lib/DirectEditing/ManagerTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use OCP\DirectEditing\ACreateEmpty;
1111
use OCP\DirectEditing\IEditor;
1212
use OCP\DirectEditing\IToken;
13+
use OCP\Encryption\IManager;
1314
use OCP\Files\Folder;
1415
use OCP\Files\IRootFolder;
1516
use OCP\IDBConnection;
@@ -104,6 +105,10 @@ class ManagerTest extends TestCase {
104105
* @var MockObject|Folder
105106
*/
106107
private $userFolder;
108+
/**
109+
* @var MockObject|IManager
110+
*/
111+
private $encryptionManager;
107112

108113
protected function setUp(): void {
109114
parent::setUp();
@@ -116,6 +121,7 @@ protected function setUp(): void {
116121
$this->rootFolder = $this->createMock(IRootFolder::class);
117122
$this->userFolder = $this->createMock(Folder::class);
118123
$this->l10n = $this->createMock(IL10N::class);
124+
$this->encryptionManager = $this->createMock(IManager::class);
119125

120126
$l10nFactory = $this->createMock(IFactory::class);
121127
$l10nFactory->expects($this->once())
@@ -128,7 +134,7 @@ protected function setUp(): void {
128134
->willReturn($this->userFolder);
129135

130136
$this->manager = new Manager(
131-
$this->random, $this->connection, $this->userSession, $this->rootFolder, $l10nFactory
137+
$this->random, $this->connection, $this->userSession, $this->rootFolder, $l10nFactory, $this->encryptionManager
132138
);
133139

134140
$this->manager->registerDirectEditor($this->editor);

0 commit comments

Comments
 (0)