diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php
index 907a6437f5..6eff66e72b 100644
--- a/apps/encryption/lib/crypto/encryption.php
+++ b/apps/encryption/lib/crypto/encryption.php
@@ -547,4 +547,17 @@ class Encryption implements IEncryptionModule {
return $path;
}
+ /**
+ * Check if the module is ready to be used by that specific user.
+ * In case a module is not ready - because e.g. key pairs have not been generated
+ * upon login this method can return false before any operation starts and might
+ * cause issues during operations.
+ *
+ * @param string $user
+ * @return boolean
+ * @since 9.1.0
+ */
+ public function isReadyForUser($user) {
+ return $this->keyManager->userHasKeys($user);
+ }
}
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php
index 12fa5f92bd..0accfb7900 100644
--- a/apps/encryption/lib/keymanager.php
+++ b/apps/encryption/lib/keymanager.php
@@ -493,6 +493,7 @@ class KeyManager {
*/
public function userHasKeys($userId) {
$privateKey = $publicKey = true;
+ $exception = null;
try {
$this->getPrivateKey($userId);
diff --git a/apps/files/command/transferownership.php b/apps/files/command/transferownership.php
index 6bf2fae6bd..1f46efdde0 100644
--- a/apps/files/command/transferownership.php
+++ b/apps/files/command/transferownership.php
@@ -97,6 +97,12 @@ class TransferOwnership extends Command {
$output->writeln("Unknown destination user $this->destinationUser");
return;
}
+
+ // target user has to be ready
+ if (!\OC::$server->getEncryptionManager()->isReadyForUser($this->destinationUser)) {
+ $output->writeln("The target user is not ready to accept files. The user has at least to be logged in once.");
+ return;
+ }
$date = date('c');
$this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date";
diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php
index d45bbf07ee..8714d16180 100644
--- a/lib/private/encryption/manager.php
+++ b/lib/private/encryption/manager.php
@@ -117,6 +117,25 @@ class Manager implements IManager {
}
/**
+ * @param string $user
+ */
+ public function isReadyForUser($user) {
+ if (!$this->isReady()) {
+ return false;
+ }
+
+ foreach ($this->getEncryptionModules() as $module) {
+ /** @var IEncryptionModule $m */
+ $m = call_user_func($module['callback']);
+ if (!$m->isReadyForUser($user)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Registers an callback function which must return an encryption module instance
*
* @param string $id
diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php
index df30dd57ce..8d20a1ab57 100644
--- a/lib/public/encryption/iencryptionmodule.php
+++ b/lib/public/encryption/iencryptionmodule.php
@@ -168,4 +168,16 @@ interface IEncryptionModule {
*/
public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '');
+ /**
+ * Check if the module is ready to be used by that specific user.
+ * In case a module is not ready - because e.g. key pairs have not been generated
+ * upon login this method can return false before any operation starts and might
+ * cause issues during operations.
+ *
+ * @param string $user
+ * @return boolean
+ * @since 9.1.0
+ */
+ public function isReadyForUser($user);
+
}
diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php
index 651299a3ea..21f7d9f09b 100644
--- a/tests/lib/files/storage/wrapper/encryption.php
+++ b/tests/lib/files/storage/wrapper/encryption.php
@@ -5,6 +5,7 @@ namespace Test\Files\Storage\Wrapper;
use OC\Encryption\Util;
use OC\Files\Storage\Temporary;
use OC\Files\View;
+use OC\User\Manager;
use Test\Files\Storage\Storage;
class Encryption extends Storage {
@@ -118,7 +119,7 @@ class Encryption extends Storage {
$this->util = $this->getMock(
'\OC\Encryption\Util',
['getUidAndFilename', 'isFile', 'isExcluded'],
- [new View(), new \OC\User\Manager(), $this->groupManager, $this->config, $this->arrayCache]);
+ [new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache]);
$this->util->expects($this->any())
->method('getUidAndFilename')
->willReturnCallback(function ($path) {
@@ -200,7 +201,7 @@ class Encryption extends Storage {
protected function buildMockModule() {
$this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser'])
->getMock();
$this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
@@ -543,7 +544,7 @@ class Encryption extends Storage {
->setConstructorArgs(
[
new View(),
- new \OC\User\Manager(),
+ new Manager(),
$this->groupManager,
$this->config,
$this->arrayCache
@@ -608,7 +609,7 @@ class Encryption extends Storage {
->disableOriginalConstructor()->getMock();
$util = $this->getMockBuilder('\OC\Encryption\Util')
- ->setConstructorArgs([new View(), new \OC\User\Manager(), $this->groupManager, $this->config, $this->arrayCache])
+ ->setConstructorArgs([new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache])
->getMock();
$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
diff --git a/tests/lib/files/stream/encryption.php b/tests/lib/files/stream/encryption.php
index afb31f2822..20a4100d2f 100644
--- a/tests/lib/files/stream/encryption.php
+++ b/tests/lib/files/stream/encryption.php
@@ -311,7 +311,7 @@ class Encryption extends \Test\TestCase {
protected function buildMockModule() {
$encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser'])
->getMock();
$encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');