From 088ffd05d7a60c5be2dbe8b56b6223a774b0822c Mon Sep 17 00:00:00 2001
From: Bjoern Schiessle <schiessle@owncloud.com>
Date: Wed, 2 Mar 2016 11:16:53 +0100
Subject: [PATCH] don't create a private-/public-key pair for each user if the
 master key is enabled

---
 apps/encryption/appinfo/application.php       |  1 +
 apps/encryption/lib/crypto/encryptall.php     | 81 ++++++++++++++-----
 .../tests/lib/crypto/encryptalltest.php       | 20 ++++-
 3 files changed, 78 insertions(+), 24 deletions(-)

diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php
index 6080a29d5f4..c7c8d2a3d31 100644
--- a/apps/encryption/appinfo/application.php
+++ b/apps/encryption/appinfo/application.php
@@ -242,6 +242,7 @@ class Application extends \OCP\AppFramework\App {
 					$c->getServer()->getUserManager(),
 					new View(),
 					$c->query('KeyManager'),
+					$c->query('Util'),
 					$server->getConfig(),
 					$server->getMailer(),
 					$server->getL10N('encryption'),
diff --git a/apps/encryption/lib/crypto/encryptall.php b/apps/encryption/lib/crypto/encryptall.php
index 18e93d2e120..0037c213265 100644
--- a/apps/encryption/lib/crypto/encryptall.php
+++ b/apps/encryption/lib/crypto/encryptall.php
@@ -28,12 +28,12 @@ use OC\Encryption\Exceptions\DecryptionFailedException;
 use OC\Files\View;
 use OCA\Encryption\KeyManager;
 use OCA\Encryption\Users\Setup;
+use OCA\Encryption\Util;
 use OCP\IConfig;
 use OCP\IL10N;
 use OCP\IUserManager;
 use OCP\Mail\IMailer;
 use OCP\Security\ISecureRandom;
-use OCP\Util;
 use Symfony\Component\Console\Helper\ProgressBar;
 use Symfony\Component\Console\Helper\QuestionHelper;
 use Symfony\Component\Console\Helper\Table;
@@ -55,6 +55,9 @@ class EncryptAll {
 	/** @var KeyManager */
 	protected $keyManager;
 
+	/** @var Util */
+	protected $util;
+
 	/** @var array  */
 	protected $userPasswords;
 
@@ -84,6 +87,7 @@ class EncryptAll {
 	 * @param IUserManager $userManager
 	 * @param View $rootView
 	 * @param KeyManager $keyManager
+	 * @param Util $util
 	 * @param IConfig $config
 	 * @param IMailer $mailer
 	 * @param IL10N $l
@@ -95,6 +99,7 @@ class EncryptAll {
 		IUserManager $userManager,
 		View $rootView,
 		KeyManager $keyManager,
+		Util $util,
 		IConfig $config,
 		IMailer $mailer,
 		IL10N $l,
@@ -105,6 +110,7 @@ class EncryptAll {
 		$this->userManager = $userManager;
 		$this->rootView = $rootView;
 		$this->keyManager = $keyManager;
+		$this->util = $util;
 		$this->config = $config;
 		$this->mailer = $mailer;
 		$this->l = $l;
@@ -129,16 +135,21 @@ class EncryptAll {
 		$this->output->writeln("\n");
 		$this->output->writeln($headline);
 		$this->output->writeln(str_pad('', strlen($headline), '='));
-
-		//create private/public keys for each user and store the private key password
 		$this->output->writeln("\n");
-		$this->output->writeln('Create key-pair for every user');
-		$this->output->writeln('------------------------------');
-		$this->output->writeln('');
-		$this->output->writeln('This module will encrypt all files in the users files folder initially.');
-		$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
-		$this->output->writeln('');
-		$this->createKeyPairs();
+
+		if ($this->util->isMasterKeyEnabled()) {
+			$this->output->writeln('Use master key to encrypt all files.');
+			$this->keyManager->validateMasterKey();
+		} else {
+			//create private/public keys for each user and store the private key password
+			$this->output->writeln('Create key-pair for every user');
+			$this->output->writeln('------------------------------');
+			$this->output->writeln('');
+			$this->output->writeln('This module will encrypt all files in the users files folder initially.');
+			$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
+			$this->output->writeln('');
+			$this->createKeyPairs();
+		}
 
 		//setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
 		$this->output->writeln("\n");
@@ -146,12 +157,14 @@ class EncryptAll {
 		$this->output->writeln('----------------------------');
 		$this->output->writeln('');
 		$this->encryptAllUsersFiles();
-		//send-out or display password list and write it to a file
-		$this->output->writeln("\n");
-		$this->output->writeln('Generated encryption key passwords');
-		$this->output->writeln('----------------------------------');
-		$this->output->writeln('');
-		$this->outputPasswords();
+		if ($this->util->isMasterKeyEnabled() === false) {
+			//send-out or display password list and write it to a file
+			$this->output->writeln("\n");
+			$this->output->writeln('Generated encryption key passwords');
+			$this->output->writeln('----------------------------------');
+			$this->output->writeln('');
+			$this->outputPasswords();
+		}
 		$this->output->writeln("\n");
 	}
 
@@ -200,16 +213,42 @@ class EncryptAll {
 		$progress->start();
 		$numberOfUsers = count($this->userPasswords);
 		$userNo = 1;
-		foreach ($this->userPasswords as $uid => $password) {
-			$userCount = "$uid ($userNo of $numberOfUsers)";
-			$this->encryptUsersFiles($uid, $progress, $userCount);
-			$userNo++;
+		if ($this->util->isMasterKeyEnabled()) {
+			$this->encryptAllUserFilesWithMasterKey($progress);
+		} else {
+			foreach ($this->userPasswords as $uid => $password) {
+				$userCount = "$uid ($userNo of $numberOfUsers)";
+				$this->encryptUsersFiles($uid, $progress, $userCount);
+				$userNo++;
+			}
 		}
 		$progress->setMessage("all files encrypted");
 		$progress->finish();
 
 	}
 
+	/**
+	 * encrypt all user files with the master key
+	 *
+	 * @param ProgressBar $progress
+	 */
+	protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
+		$userNo = 1;
+		foreach($this->userManager->getBackends() as $backend) {
+			$limit = 500;
+			$offset = 0;
+			do {
+				$users = $backend->getUsers('', $limit, $offset);
+				foreach ($users as $user) {
+					$userCount = "$user ($userNo)";
+					$this->encryptUsersFiles($user, $progress, $userCount);
+					$userNo++;
+				}
+				$offset += $limit;
+			} while(count($users) >= $limit);
+		}
+	}
+
 	/**
 	 * encrypt files from the given user
 	 *
@@ -384,7 +423,7 @@ class EncryptAll {
 					$message->setHtmlBody($htmlBody);
 					$message->setPlainBody($textBody);
 					$message->setFrom([
-						Util::getDefaultEmailAddress('admin-noreply')
+						\OCP\Util::getDefaultEmailAddress('admin-noreply')
 					]);
 
 					$this->mailer->send($message);
diff --git a/apps/encryption/tests/lib/crypto/encryptalltest.php b/apps/encryption/tests/lib/crypto/encryptalltest.php
index 04d931342a7..837883fded3 100644
--- a/apps/encryption/tests/lib/crypto/encryptalltest.php
+++ b/apps/encryption/tests/lib/crypto/encryptalltest.php
@@ -31,6 +31,9 @@ class EncryptAllTest extends TestCase {
 	/** @var  \PHPUnit_Framework_MockObject_MockObject | \OCA\Encryption\KeyManager */
 	protected $keyManager;
 
+	/** @var  \PHPUnit_Framework_MockObject_MockObject | \OCA\Encryption\Util */
+	protected $util;
+
 	/** @var  \PHPUnit_Framework_MockObject_MockObject | \OCP\IUserManager */
 	protected $userManager;
 
@@ -73,6 +76,8 @@ class EncryptAllTest extends TestCase {
 			->disableOriginalConstructor()->getMock();
 		$this->keyManager = $this->getMockBuilder('OCA\Encryption\KeyManager')
 			->disableOriginalConstructor()->getMock();
+		$this->util = $this->getMockBuilder('OCA\Encryption\Util')
+			->disableOriginalConstructor()->getMock();
 		$this->userManager = $this->getMockBuilder('OCP\IUserManager')
 			->disableOriginalConstructor()->getMock();
 		$this->view = $this->getMockBuilder('OC\Files\View')
@@ -110,6 +115,7 @@ class EncryptAllTest extends TestCase {
 			$this->userManager,
 			$this->view,
 			$this->keyManager,
+			$this->util,
 			$this->config,
 			$this->mailer,
 			$this->l,
@@ -127,6 +133,7 @@ class EncryptAllTest extends TestCase {
 					$this->userManager,
 					$this->view,
 					$this->keyManager,
+					$this->util,
 					$this->config,
 					$this->mailer,
 					$this->l,
@@ -137,6 +144,7 @@ class EncryptAllTest extends TestCase {
 			->setMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords'])
 			->getMock();
 
+		$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
 		$encryptAll->expects($this->at(0))->method('createKeyPairs')->with();
 		$encryptAll->expects($this->at(1))->method('encryptAllUsersFiles')->with();
 		$encryptAll->expects($this->at(2))->method('outputPasswords')->with();
@@ -154,6 +162,7 @@ class EncryptAllTest extends TestCase {
 					$this->userManager,
 					$this->view,
 					$this->keyManager,
+					$this->util,
 					$this->config,
 					$this->mailer,
 					$this->l,
@@ -202,6 +211,7 @@ class EncryptAllTest extends TestCase {
 					$this->userManager,
 					$this->view,
 					$this->keyManager,
+					$this->util,
 					$this->config,
 					$this->mailer,
 					$this->l,
@@ -212,6 +222,8 @@ class EncryptAllTest extends TestCase {
 			->setMethods(['encryptUsersFiles'])
 			->getMock();
 
+		$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
+
 		// set protected property $output
 		$this->invokePrivate($encryptAll, 'output', [$this->outputInterface]);
 		$this->invokePrivate($encryptAll, 'userPasswords', [['user1' => 'pwd1', 'user2' => 'pwd2']]);
@@ -232,6 +244,7 @@ class EncryptAllTest extends TestCase {
 					$this->userManager,
 					$this->view,
 					$this->keyManager,
+					$this->util,
 					$this->config,
 					$this->mailer,
 					$this->l,
@@ -239,9 +252,10 @@ class EncryptAllTest extends TestCase {
 					$this->secureRandom
 				]
 			)
-			->setMethods(['encryptFile'])
+			->setMethods(['encryptFile', 'setupUserFS'])
 			->getMock();
 
+		$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
 
 		$this->view->expects($this->at(0))->method('getDirectoryContent')
 			->with('/user1/files')->willReturn(
@@ -268,8 +282,8 @@ class EncryptAllTest extends TestCase {
 				}
 			);
 
-		$encryptAll->expects($this->at(0))->method('encryptFile')->with('/user1/files/bar');
-		$encryptAll->expects($this->at(1))->method('encryptFile')->with('/user1/files/foo/subfile');
+		$encryptAll->expects($this->at(1))->method('encryptFile')->with('/user1/files/bar');
+		$encryptAll->expects($this->at(2))->method('encryptFile')->with('/user1/files/foo/subfile');
 
 		$progressBar = $this->getMockBuilder('Symfony\Component\Console\Helper\ProgressBar')
 			->disableOriginalConstructor()->getMock();
-- 
GitLab