Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor encryption app commands #39692

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 23 additions & 37 deletions apps/encryption/lib/Command/DisableMasterKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,15 @@
use Symfony\Component\Console\Question\ConfirmationQuestion;

class DisableMasterKey extends Command {

/** @var Util */
protected $util;

/** @var IConfig */
protected $config;

/** @var QuestionHelper */
protected $questionHelper;

/**
* @param Util $util
* @param IConfig $config
* @param QuestionHelper $questionHelper
*/
public function __construct(Util $util,
IConfig $config,
QuestionHelper $questionHelper) {
$this->util = $util;
$this->config = $config;
$this->questionHelper = $questionHelper;
public function __construct(
protected Util $util,
protected IConfig $config,
protected QuestionHelper $questionHelper,
) {
parent::__construct();
}

protected function configure() {
protected function configure(): void {
$this
->setName('encryption:disable-master-key')
->setDescription('Disable the master key and use per-user keys instead. Only available for fresh installations with no existing encrypted data! There is no way to enable it again.');
Expand All @@ -49,21 +33,23 @@

if (!$isMasterKeyEnabled) {
$output->writeln('Master key already disabled');
} else {
$question = new ConfirmationQuestion(
'Warning: Only perform this operation for a fresh installations with no existing encrypted data! '
. 'There is no way to enable the master key again. '
. 'We strongly recommend to keep the master key, it provides significant performance improvements '
. 'and is easier to handle for both, users and administrators. '
. 'Do you really want to switch to per-user keys? (y/n) ', false);
if ($this->questionHelper->ask($input, $output, $question)) {
$this->config->setAppValue('encryption', 'useMasterKey', '0');
$output->writeln('Master key successfully disabled.');
} else {
$output->writeln('aborted.');
return 1;
}
return self::SUCCESS;
}
return 0;

$question = new ConfirmationQuestion(
'Warning: Only perform this operation for a fresh installations with no existing encrypted data! '
. 'There is no way to enable the master key again. '
. 'We strongly recommend to keep the master key, it provides significant performance improvements '
. 'and is easier to handle for both, users and administrators. '
. 'Do you really want to switch to per-user keys? (y/n) ', false);

if ($this->questionHelper->ask($input, $output, $question)) {
$this->config->setAppValue('encryption', 'useMasterKey', '0');

Check notice

Code scanning / Psalm

DeprecatedMethod Note

The method OCP\IConfig::setAppValue has been marked as deprecated
$output->writeln('Master key successfully disabled.');
return self::SUCCESS;
}

$output->writeln('aborted.');
return self::FAILURE;
}
}
4 changes: 2 additions & 2 deletions apps/encryption/lib/Command/DropLegacyFileKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int

if ($result) {
$output->writeln('All scanned files are properly encrypted.');
return 0;
return self::SUCCESS;
}

return 1;
return self::FAILURE;
}

private function scanFolder(OutputInterface $output, string $folder): bool {
Expand Down
52 changes: 19 additions & 33 deletions apps/encryption/lib/Command/EnableMasterKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,15 @@
use Symfony\Component\Console\Question\ConfirmationQuestion;

class EnableMasterKey extends Command {

/** @var Util */
protected $util;

/** @var IConfig */
protected $config;

/** @var QuestionHelper */
protected $questionHelper;

/**
* @param Util $util
* @param IConfig $config
* @param QuestionHelper $questionHelper
*/
public function __construct(Util $util,
IConfig $config,
QuestionHelper $questionHelper) {
$this->util = $util;
$this->config = $config;
$this->questionHelper = $questionHelper;
public function __construct(
protected Util $util,
protected IConfig $config,
protected QuestionHelper $questionHelper,
) {
parent::__construct();
}

protected function configure() {
protected function configure(): void {
$this
->setName('encryption:enable-master-key')
->setDescription('Enable the master key. Only available for fresh installations with no existing encrypted data! There is also no way to disable it again.');
Expand All @@ -51,18 +35,20 @@

if ($isAlreadyEnabled) {
$output->writeln('Master key already enabled');
} else {
$question = new ConfirmationQuestion(
'Warning: Only available for fresh installations with no existing encrypted data! '
return self::SUCCESS;
}

$question = new ConfirmationQuestion(
'Warning: Only available for fresh installations with no existing encrypted data! '
. 'There is also no way to disable it again. Do you want to continue? (y/n) ', false);
if ($this->questionHelper->ask($input, $output, $question)) {
$this->config->setAppValue('encryption', 'useMasterKey', '1');
$output->writeln('Master key successfully enabled.');
} else {
$output->writeln('aborted.');
return 1;
}

if ($this->questionHelper->ask($input, $output, $question)) {
$this->config->setAppValue('encryption', 'useMasterKey', '1');

Check notice

Code scanning / Psalm

DeprecatedMethod Note

The method OCP\IConfig::setAppValue has been marked as deprecated
$output->writeln('Master key successfully enabled.');
return self::SUCCESS;
}
return 0;

$output->writeln('aborted.');
return self::FAILURE;
}
}
42 changes: 21 additions & 21 deletions apps/encryption/lib/Command/FixEncryptedVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
use Symfony\Component\Console\Output\OutputInterface;

class FixEncryptedVersion extends Command {
private bool $supportLegacy;
private bool $supportLegacy = false;

public function __construct(
private IConfig $config,
Expand All @@ -35,8 +35,6 @@ public function __construct(
private Util $util,
private View $view,
) {
$this->supportLegacy = false;

parent::__construct();
}

Expand Down Expand Up @@ -69,42 +67,44 @@ protected function execute(InputInterface $input, OutputInterface $output): int

if ($skipSignatureCheck) {
$output->writeln("<error>Repairing is not possible when \"encryption_skip_signature_check\" is set. Please disable this flag in the configuration.</error>\n");
return 1;
return self::FAILURE;
}

if (!$this->util->isMasterKeyEnabled()) {
$output->writeln("<error>Repairing only works with master key encryption.</error>\n");
return 1;
return self::FAILURE;
}

$user = $input->getArgument('user');
$all = $input->getOption('all');
$pathOption = \trim(($input->getOption('path') ?? ''), '/');

if (!$user && !$all) {
$output->writeln("Either a user id or --all needs to be provided");
return self::FAILURE;
}

if ($user) {
if ($all) {
$output->writeln("Specifying a user id and --all are mutually exclusive");
return 1;
return self::FAILURE;
}

if ($this->userManager->get($user) === null) {
$output->writeln("<error>User id $user does not exist. Please provide a valid user id</error>");
return 1;
return self::FAILURE;
}

return $this->runForUser($user, $pathOption, $output);
} elseif ($all) {
$result = 0;
$this->userManager->callForSeenUsers(function (IUser $user) use ($pathOption, $output, &$result) {
$output->writeln("Processing files for " . $user->getUID());
$result = $this->runForUser($user->getUID(), $pathOption, $output);
return $result === 0;
});
return $result;
} else {
$output->writeln("Either a user id or --all needs to be provided");
return 1;
}

$result = 0;
$this->userManager->callForSeenUsers(function (IUser $user) use ($pathOption, $output, &$result) {
$output->writeln("Processing files for " . $user->getUID());
$result = $this->runForUser($user->getUID(), $pathOption, $output);
return $result === 0;
});
return $result;
}

private function runForUser(string $user, string $pathOption, OutputInterface $output): int {
Expand All @@ -122,13 +122,13 @@ private function walkPathOfUser(string $user, string $path, OutputInterface $out
$this->setupUserFs($user);
if (!$this->view->file_exists($path)) {
$output->writeln("<error>Path \"$path\" does not exist. Please provide a valid path.</error>");
return 1;
return self::FAILURE;
}

if ($this->view->is_file($path)) {
$output->writeln("Verifying the content of file \"$path\"");
$this->verifyFileContent($path, $output);
return 0;
return self::SUCCESS;
}
$directories = [];
$directories[] = $path;
Expand All @@ -144,7 +144,7 @@ private function walkPathOfUser(string $user, string $path, OutputInterface $out
}
}
}
return 0;
return self::SUCCESS;
}

/**
Expand Down
46 changes: 7 additions & 39 deletions apps/encryption/lib/Command/FixKeyLocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,17 @@
use Symfony\Component\Console\Output\OutputInterface;

class FixKeyLocation extends Command {
private IUserManager $userManager;
private IUserMountCache $userMountCache;
private Util $encryptionUtil;
private IRootFolder $rootFolder;
private string $keyRootDirectory;
private View $rootView;
private Manager $encryptionManager;

public function __construct(
IUserManager $userManager,
IUserMountCache $userMountCache,
Util $encryptionUtil,
IRootFolder $rootFolder,
IManager $encryptionManager
private IUserManager $userManager,
private IUserMountCache $userMountCache,
private Util $encryptionUtil,
private IRootFolder $rootFolder,
IManager $encryptionManager,
) {
$this->userManager = $userManager;
$this->userMountCache = $userMountCache;
$this->encryptionUtil = $encryptionUtil;
$this->rootFolder = $rootFolder;
$this->keyRootDirectory = rtrim($this->encryptionUtil->getKeyStorageRoot(), '/');
$this->rootView = new View();
if (!$encryptionManager instanceof Manager) {
Expand Down Expand Up @@ -74,7 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$user = $this->userManager->get($userId);
if (!$user) {
$output->writeln("<error>User $userId not found</error>");
return 1;
return self::FAILURE;
}

\OC_Util::setupFS($user->getUID());
Expand Down Expand Up @@ -158,7 +150,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
}

return 0;
return self::SUCCESS;
}

private function getUserRelativePath(string $path): string {
Expand All @@ -171,7 +163,6 @@ private function getUserRelativePath(string $path): string {
}

/**
* @param IUser $user
* @return ICachedMountInfo[]
*/
private function getSystemMountsForUser(IUser $user): array {
Expand All @@ -186,7 +177,6 @@ private function getSystemMountsForUser(IUser $user): array {
/**
* Get all files in a folder which are marked as encrypted
*
* @param Folder $folder
* @return \Generator<File>
*/
private function getAllEncryptedFiles(Folder $folder) {
Expand Down Expand Up @@ -227,10 +217,6 @@ private function hasUserKey(IUser $user, Node $node): bool {

/**
* Check that the user key stored for a file can decrypt the file
*
* @param IUser $user
* @param File $node
* @return bool
*/
private function copyUserKeyToSystemAndValidate(IUser $user, File $node): bool {
$path = trim(substr($node->getPath(), strlen($user->getUID()) + 1), '/');
Expand Down Expand Up @@ -267,7 +253,6 @@ private function tryReadFile(File $node): bool {
/**
* Get the contents of a file without decrypting it
*
* @param File $node
* @return resource
*/
private function openWithoutDecryption(File $node, string $mode) {
Expand Down Expand Up @@ -295,9 +280,6 @@ private function openWithoutDecryption(File $node, string $mode) {

/**
* Check if the data stored for a file is encrypted, regardless of it's metadata
*
* @param File $node
* @return bool
*/
private function isDataEncrypted(File $node): bool {
$handle = $this->openWithoutDecryption($node, 'r');
Expand All @@ -310,9 +292,6 @@ private function isDataEncrypted(File $node): bool {

/**
* Attempt to find a key (stored for user) for a file (that needs a system key) even when it's not stored in the expected location
*
* @param File $node
* @return string
*/
private function findUserKeyForSystemFile(IUser $user, File $node): ?string {
$userKeyPath = $this->getUserBaseKeyPath($user);
Expand All @@ -328,8 +307,6 @@ private function findUserKeyForSystemFile(IUser $user, File $node): ?string {
/**
* Attempt to find a key for a file even when it's not stored in the expected location
*
* @param string $basePath
* @param string $name
* @return \Generator<string>
*/
private function findKeysByFileName(string $basePath, string $name) {
Expand All @@ -356,11 +333,6 @@ private function findKeysByFileName(string $basePath, string $name) {

/**
* Test if the provided key is valid as a system key for the file
*
* @param IUser $user
* @param string $key
* @param File $node
* @return bool
*/
private function testSystemKey(IUser $user, string $key, File $node): bool {
$systemKeyPath = $this->getSystemKeyPath($node);
Expand All @@ -378,10 +350,6 @@ private function testSystemKey(IUser $user, string $key, File $node): bool {

/**
* Decrypt a file with the specified system key and mark the key as not-encrypted
*
* @param File $node
* @param string $key
* @return void
*/
private function decryptWithSystemKey(File $node, string $key): void {
$storage = $node->getStorage();
Expand Down
Loading
Loading