Skip to content

Commit edaa436

Browse files
committed
add key location to info:file output
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 82e02a7 commit edaa436

5 files changed

Lines changed: 83 additions & 58 deletions

File tree

core/Command/Info/File.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace OC\Core\Command\Info;
66

77
use OC\Files\ObjectStore\ObjectStoreStorage;
8+
use OC\Files\View;
89
use OCA\Files_External\Config\ExternalMountPoint;
910
use OCA\GroupFolders\Mount\GroupMountPoint;
1011
use OCP\Files\Folder;
@@ -23,13 +24,16 @@
2324

2425
class File extends Command {
2526
private IL10N $l10n;
27+
private View $rootView;
2628

2729
public function __construct(
2830
IFactory $l10nFactory,
2931
private FileUtils $fileUtils,
32+
private \OC\Encryption\Util $encryptionUtil
3033
) {
3134
$this->l10n = $l10nFactory->get("core");
3235
parent::__construct();
36+
$this->rootView = new View();
3337
}
3438

3539
protected function configure(): void {
@@ -54,6 +58,14 @@ public function execute(InputInterface $input, OutputInterface $output): int {
5458
$output->writeln(" mimetype: " . $node->getMimetype());
5559
$output->writeln(" modified: " . (string)$this->l10n->l("datetime", $node->getMTime()));
5660
$output->writeln(" " . ($node->isEncrypted() ? "encrypted" : "not encrypted"));
61+
if ($node->isEncrypted()) {
62+
$keyPath = $this->encryptionUtil->getFileKeyDir('', $node->getPath());
63+
if ($this->rootView->file_exists($keyPath)) {
64+
$output->writeln(" encryption key at: " . $keyPath);
65+
} else {
66+
$output->writeln(" <error>encryption key not found</error> should be located at: " . $keyPath);
67+
}
68+
}
5769
$output->writeln(" size: " . Util::humanFileSize($node->getSize()));
5870
$output->writeln(" etag: " . $node->getEtag());
5971
if ($node instanceof Folder) {

lib/private/Encryption/Keys/Storage.php

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ public function getUserKey($uid, $keyId, $encryptionModuleId) {
9898
*/
9999
public function getFileKey($path, $keyId, $encryptionModuleId) {
100100
$realFile = $this->util->stripPartialFileExtension($path);
101-
$keyDir = $this->getFileKeyDir($encryptionModuleId, $realFile);
101+
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $realFile);
102102
$key = $this->getKey($keyDir . $keyId)['key'];
103103

104104
if ($key === '' && $realFile !== $path) {
105105
// Check if the part file has keys and use them, if no normal keys
106106
// exist. This is required to fix copyBetweenStorage() when we
107107
// rename a .part file over storage borders.
108-
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
108+
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
109109
$key = $this->getKey($keyDir . $keyId)['key'];
110110
}
111111

@@ -135,7 +135,7 @@ public function setUserKey($uid, $keyId, $key, $encryptionModuleId) {
135135
* @inheritdoc
136136
*/
137137
public function setFileKey($path, $keyId, $key, $encryptionModuleId) {
138-
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
138+
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
139139
return $this->setKey($keyDir . $keyId, [
140140
'key' => base64_encode($key),
141141
]);
@@ -177,15 +177,15 @@ public function deleteUserKey($uid, $keyId, $encryptionModuleId) {
177177
* @inheritdoc
178178
*/
179179
public function deleteFileKey($path, $keyId, $encryptionModuleId) {
180-
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
180+
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
181181
return !$this->view->file_exists($keyDir . $keyId) || $this->view->unlink($keyDir . $keyId);
182182
}
183183

184184
/**
185185
* @inheritdoc
186186
*/
187187
public function deleteAllFileKeys($path) {
188-
$keyDir = $this->getFileKeyDir('', $path);
188+
$keyDir = $this->util->getFileKeyDir('', $path);
189189
return !$this->view->file_exists($keyDir) || $this->view->deleteAll($keyDir);
190190
}
191191

@@ -355,26 +355,6 @@ private function setKey($path, $key) {
355355
return false;
356356
}
357357

358-
/**
359-
* get path to key folder for a given file
360-
*
361-
* @param string $encryptionModuleId
362-
* @param string $path path to the file, relative to data/
363-
* @return string
364-
*/
365-
private function getFileKeyDir($encryptionModuleId, $path) {
366-
[$owner, $filename] = $this->util->getUidAndFilename($path);
367-
368-
// in case of system wide mount points the keys are stored directly in the data directory
369-
if ($this->util->isSystemWideMountPoint($filename, $owner)) {
370-
$keyPath = $this->root_dir . '/' . $this->keys_base_dir . $filename . '/';
371-
} else {
372-
$keyPath = $this->root_dir . '/' . $owner . $this->keys_base_dir . $filename . '/';
373-
}
374-
375-
return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false);
376-
}
377-
378358
/**
379359
* move keys if a file was renamed
380360
*

lib/private/Encryption/Util.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,4 +385,25 @@ public function parseRawHeader(string $rawHeader) {
385385

386386
return $result;
387387
}
388+
389+
/**
390+
* get path to key folder for a given file
391+
*
392+
* @param string $encryptionModuleId
393+
* @param string $path path to the file, relative to data/
394+
* @return string
395+
*/
396+
public function getFileKeyDir(string $encryptionModuleId, string $path): string {
397+
[$owner, $filename] = $this->getUidAndFilename($path);
398+
$root = $this->getKeyStorageRoot();
399+
400+
// in case of system-wide mount points the keys are stored directly in the data directory
401+
if ($this->isSystemWideMountPoint($filename, $owner)) {
402+
$keyPath = $root . '/' . '/files_encryption/keys' . $filename . '/';
403+
} else {
404+
$keyPath = $root . '/' . $owner . '/files_encryption/keys' . $filename . '/';
405+
}
406+
407+
return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false);
408+
}
388409
}

tests/lib/Encryption/Keys/StorageTest.php

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ protected function setUp(): void {
5353

5454
$this->util = $this->getMockBuilder('OC\Encryption\Util')
5555
->disableOriginalConstructor()
56+
->setMethodsExcept(['getFileKeyDir'])
5657
->getMock();
5758

5859
$this->view = $this->getMockBuilder(View::class)
@@ -583,39 +584,6 @@ public function mkdirCallback() {
583584
$this->assertSame($expected, $args[0]);
584585
}
585586

586-
/**
587-
* @dataProvider dataTestGetFileKeyDir
588-
*
589-
* @param bool $isSystemWideMountPoint
590-
* @param string $storageRoot
591-
* @param string $expected
592-
*/
593-
public function testGetFileKeyDir($isSystemWideMountPoint, $storageRoot, $expected) {
594-
$path = '/user1/files/foo/bar.txt';
595-
$owner = 'user1';
596-
$relativePath = '/foo/bar.txt';
597-
598-
$this->invokePrivate($this->storage, 'root_dir', [$storageRoot]);
599-
600-
$this->util->expects($this->once())->method('isSystemWideMountPoint')
601-
->willReturn($isSystemWideMountPoint);
602-
$this->util->expects($this->once())->method('getUidAndFilename')
603-
->with($path)->willReturn([$owner, $relativePath]);
604-
605-
$this->assertSame($expected,
606-
$this->invokePrivate($this->storage, 'getFileKeyDir', ['OC_DEFAULT_MODULE', $path])
607-
);
608-
}
609-
610-
public function dataTestGetFileKeyDir() {
611-
return [
612-
[false, '', '/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
613-
[true, '', '/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
614-
[false, 'newStorageRoot', '/newStorageRoot/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
615-
[true, 'newStorageRoot', '/newStorageRoot/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
616-
];
617-
}
618-
619587

620588
/**
621589
* @dataProvider dataTestBackupUserKeys

tests/lib/Encryption/UtilTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
class UtilTest extends TestCase {
1414
/**
1515
* block size will always be 8192 for a PHP stream
16+
*
1617
* @see https://bugs.php.net/bug.php?id=21641
1718
*/
1819
protected int $headerSize = 8192;
@@ -205,4 +206,47 @@ public function dataTestParseRawHeader() {
205206
, []],
206207
];
207208
}
209+
210+
/**
211+
* @dataProvider dataTestGetFileKeyDir
212+
*
213+
* @param bool $isSystemWideMountPoint
214+
* @param string $storageRoot
215+
* @param string $expected
216+
*/
217+
public function testGetFileKeyDir($isSystemWideMountPoint, $storageRoot, $expected) {
218+
$path = '/user1/files/foo/bar.txt';
219+
$owner = 'user1';
220+
$relativePath = '/foo/bar.txt';
221+
222+
$util = $this->getMockBuilder(Util::class)
223+
->onlyMethods(['isSystemWideMountPoint', 'getUidAndFilename', 'getKeyStorageRoot'])
224+
->setConstructorArgs([
225+
$this->view,
226+
$this->userManager,
227+
$this->groupManager,
228+
$this->config
229+
])
230+
->getMock();
231+
232+
$util->expects($this->once())->method('getKeyStorageRoot')
233+
->willReturn($storageRoot);
234+
$util->expects($this->once())->method('isSystemWideMountPoint')
235+
->willReturn($isSystemWideMountPoint);
236+
$util->expects($this->once())->method('getUidAndFilename')
237+
->with($path)->willReturn([$owner, $relativePath]);
238+
239+
$this->assertSame($expected,
240+
$util->getFileKeyDir('OC_DEFAULT_MODULE', $path)
241+
);
242+
}
243+
244+
public function dataTestGetFileKeyDir() {
245+
return [
246+
[false, '', '/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
247+
[true, '', '/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
248+
[false, 'newStorageRoot', '/newStorageRoot/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
249+
[true, 'newStorageRoot', '/newStorageRoot/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
250+
];
251+
}
208252
}

0 commit comments

Comments
 (0)