mirror of https://github.com/nextcloud/server
Merge pull request #42893 from nextcloud/file-info-key-location
This commit is contained in:
commit
edc35f74c7
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace OC\Core\Command\Info;
|
||||
|
||||
use OC\Files\ObjectStore\ObjectStoreStorage;
|
||||
use OC\Files\View;
|
||||
use OCA\Files_External\Config\ExternalMountPoint;
|
||||
use OCA\GroupFolders\Mount\GroupMountPoint;
|
||||
use OCP\Files\Folder;
|
||||
|
@ -23,13 +24,16 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
|
||||
class File extends Command {
|
||||
private IL10N $l10n;
|
||||
private View $rootView;
|
||||
|
||||
public function __construct(
|
||||
IFactory $l10nFactory,
|
||||
private FileUtils $fileUtils,
|
||||
private \OC\Encryption\Util $encryptionUtil
|
||||
) {
|
||||
$this->l10n = $l10nFactory->get("core");
|
||||
parent::__construct();
|
||||
$this->rootView = new View();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
|
@ -54,6 +58,14 @@ class File extends Command {
|
|||
$output->writeln(" mimetype: " . $node->getMimetype());
|
||||
$output->writeln(" modified: " . (string)$this->l10n->l("datetime", $node->getMTime()));
|
||||
$output->writeln(" " . ($node->isEncrypted() ? "encrypted" : "not encrypted"));
|
||||
if ($node->isEncrypted()) {
|
||||
$keyPath = $this->encryptionUtil->getFileKeyDir('', $node->getPath());
|
||||
if ($this->rootView->file_exists($keyPath)) {
|
||||
$output->writeln(" encryption key at: " . $keyPath);
|
||||
} else {
|
||||
$output->writeln(" <error>encryption key not found</error> should be located at: " . $keyPath);
|
||||
}
|
||||
}
|
||||
$output->writeln(" size: " . Util::humanFileSize($node->getSize()));
|
||||
$output->writeln(" etag: " . $node->getEtag());
|
||||
if ($node instanceof Folder) {
|
||||
|
|
|
@ -98,14 +98,14 @@ class Storage implements IStorage {
|
|||
*/
|
||||
public function getFileKey($path, $keyId, $encryptionModuleId) {
|
||||
$realFile = $this->util->stripPartialFileExtension($path);
|
||||
$keyDir = $this->getFileKeyDir($encryptionModuleId, $realFile);
|
||||
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $realFile);
|
||||
$key = $this->getKey($keyDir . $keyId)['key'];
|
||||
|
||||
if ($key === '' && $realFile !== $path) {
|
||||
// Check if the part file has keys and use them, if no normal keys
|
||||
// exist. This is required to fix copyBetweenStorage() when we
|
||||
// rename a .part file over storage borders.
|
||||
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
|
||||
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
|
||||
$key = $this->getKey($keyDir . $keyId)['key'];
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ class Storage implements IStorage {
|
|||
* @inheritdoc
|
||||
*/
|
||||
public function setFileKey($path, $keyId, $key, $encryptionModuleId) {
|
||||
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
|
||||
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
|
||||
return $this->setKey($keyDir . $keyId, [
|
||||
'key' => base64_encode($key),
|
||||
]);
|
||||
|
@ -177,7 +177,7 @@ class Storage implements IStorage {
|
|||
* @inheritdoc
|
||||
*/
|
||||
public function deleteFileKey($path, $keyId, $encryptionModuleId) {
|
||||
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
|
||||
$keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path);
|
||||
return !$this->view->file_exists($keyDir . $keyId) || $this->view->unlink($keyDir . $keyId);
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ class Storage implements IStorage {
|
|||
* @inheritdoc
|
||||
*/
|
||||
public function deleteAllFileKeys($path) {
|
||||
$keyDir = $this->getFileKeyDir('', $path);
|
||||
$keyDir = $this->util->getFileKeyDir('', $path);
|
||||
return !$this->view->file_exists($keyDir) || $this->view->deleteAll($keyDir);
|
||||
}
|
||||
|
||||
|
@ -355,26 +355,6 @@ class Storage implements IStorage {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get path to key folder for a given file
|
||||
*
|
||||
* @param string $encryptionModuleId
|
||||
* @param string $path path to the file, relative to data/
|
||||
* @return string
|
||||
*/
|
||||
private function getFileKeyDir($encryptionModuleId, $path) {
|
||||
[$owner, $filename] = $this->util->getUidAndFilename($path);
|
||||
|
||||
// in case of system wide mount points the keys are stored directly in the data directory
|
||||
if ($this->util->isSystemWideMountPoint($filename, $owner)) {
|
||||
$keyPath = $this->root_dir . '/' . $this->keys_base_dir . $filename . '/';
|
||||
} else {
|
||||
$keyPath = $this->root_dir . '/' . $owner . $this->keys_base_dir . $filename . '/';
|
||||
}
|
||||
|
||||
return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* move keys if a file was renamed
|
||||
*
|
||||
|
|
|
@ -385,4 +385,25 @@ class Util {
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get path to key folder for a given file
|
||||
*
|
||||
* @param string $encryptionModuleId
|
||||
* @param string $path path to the file, relative to data/
|
||||
* @return string
|
||||
*/
|
||||
public function getFileKeyDir(string $encryptionModuleId, string $path): string {
|
||||
[$owner, $filename] = $this->getUidAndFilename($path);
|
||||
$root = $this->getKeyStorageRoot();
|
||||
|
||||
// in case of system-wide mount points the keys are stored directly in the data directory
|
||||
if ($this->isSystemWideMountPoint($filename, $owner)) {
|
||||
$keyPath = $root . '/' . '/files_encryption/keys' . $filename . '/';
|
||||
} else {
|
||||
$keyPath = $root . '/' . $owner . '/files_encryption/keys' . $filename . '/';
|
||||
}
|
||||
|
||||
return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class StorageTest extends TestCase {
|
|||
|
||||
$this->util = $this->getMockBuilder('OC\Encryption\Util')
|
||||
->disableOriginalConstructor()
|
||||
->setMethodsExcept(['getFileKeyDir'])
|
||||
->getMock();
|
||||
|
||||
$this->view = $this->getMockBuilder(View::class)
|
||||
|
@ -583,39 +584,6 @@ class StorageTest extends TestCase {
|
|||
$this->assertSame($expected, $args[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestGetFileKeyDir
|
||||
*
|
||||
* @param bool $isSystemWideMountPoint
|
||||
* @param string $storageRoot
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testGetFileKeyDir($isSystemWideMountPoint, $storageRoot, $expected) {
|
||||
$path = '/user1/files/foo/bar.txt';
|
||||
$owner = 'user1';
|
||||
$relativePath = '/foo/bar.txt';
|
||||
|
||||
$this->invokePrivate($this->storage, 'root_dir', [$storageRoot]);
|
||||
|
||||
$this->util->expects($this->once())->method('isSystemWideMountPoint')
|
||||
->willReturn($isSystemWideMountPoint);
|
||||
$this->util->expects($this->once())->method('getUidAndFilename')
|
||||
->with($path)->willReturn([$owner, $relativePath]);
|
||||
|
||||
$this->assertSame($expected,
|
||||
$this->invokePrivate($this->storage, 'getFileKeyDir', ['OC_DEFAULT_MODULE', $path])
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestGetFileKeyDir() {
|
||||
return [
|
||||
[false, '', '/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[true, '', '/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[false, 'newStorageRoot', '/newStorageRoot/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[true, 'newStorageRoot', '/newStorageRoot/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestBackupUserKeys
|
||||
|
|
|
@ -13,6 +13,7 @@ use Test\TestCase;
|
|||
class UtilTest extends TestCase {
|
||||
/**
|
||||
* block size will always be 8192 for a PHP stream
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=21641
|
||||
*/
|
||||
protected int $headerSize = 8192;
|
||||
|
@ -205,4 +206,47 @@ class UtilTest extends TestCase {
|
|||
, []],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestGetFileKeyDir
|
||||
*
|
||||
* @param bool $isSystemWideMountPoint
|
||||
* @param string $storageRoot
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testGetFileKeyDir($isSystemWideMountPoint, $storageRoot, $expected) {
|
||||
$path = '/user1/files/foo/bar.txt';
|
||||
$owner = 'user1';
|
||||
$relativePath = '/foo/bar.txt';
|
||||
|
||||
$util = $this->getMockBuilder(Util::class)
|
||||
->onlyMethods(['isSystemWideMountPoint', 'getUidAndFilename', 'getKeyStorageRoot'])
|
||||
->setConstructorArgs([
|
||||
$this->view,
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->config
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$util->expects($this->once())->method('getKeyStorageRoot')
|
||||
->willReturn($storageRoot);
|
||||
$util->expects($this->once())->method('isSystemWideMountPoint')
|
||||
->willReturn($isSystemWideMountPoint);
|
||||
$util->expects($this->once())->method('getUidAndFilename')
|
||||
->with($path)->willReturn([$owner, $relativePath]);
|
||||
|
||||
$this->assertSame($expected,
|
||||
$util->getFileKeyDir('OC_DEFAULT_MODULE', $path)
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestGetFileKeyDir() {
|
||||
return [
|
||||
[false, '', '/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[true, '', '/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[false, 'newStorageRoot', '/newStorageRoot/user1/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
[true, 'newStorageRoot', '/newStorageRoot/files_encryption/keys/foo/bar.txt/OC_DEFAULT_MODULE/'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue