aboutsummaryrefslogtreecommitdiffstats
path: root/apps/encryption/tests/Crypto/EncryptAllTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/encryption/tests/Crypto/EncryptAllTest.php')
-rw-r--r--apps/encryption/tests/Crypto/EncryptAllTest.php385
1 files changed, 385 insertions, 0 deletions
diff --git a/apps/encryption/tests/Crypto/EncryptAllTest.php b/apps/encryption/tests/Crypto/EncryptAllTest.php
new file mode 100644
index 00000000000..c56e3375a73
--- /dev/null
+++ b/apps/encryption/tests/Crypto/EncryptAllTest.php
@@ -0,0 +1,385 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Encryption\Tests\Crypto;
+
+use OC\Files\View;
+use OCA\Encryption\Crypto\EncryptAll;
+use OCA\Encryption\KeyManager;
+use OCA\Encryption\Users\Setup;
+use OCA\Encryption\Util;
+use OCP\Files\FileInfo;
+use OCP\IConfig;
+use OCP\IL10N;
+use OCP\IUserManager;
+use OCP\L10N\IFactory;
+use OCP\Mail\IMailer;
+use OCP\Security\ISecureRandom;
+use OCP\UserInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Console\Formatter\OutputFormatterInterface;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Helper\QuestionHelper;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Test\TestCase;
+
+class EncryptAllTest extends TestCase {
+
+ protected KeyManager&MockObject $keyManager;
+ protected Util&MockObject $util;
+ protected IUserManager&MockObject $userManager;
+ protected Setup&MockObject $setupUser;
+ protected View&MockObject $view;
+ protected IConfig&MockObject $config;
+ protected IMailer&MockObject $mailer;
+ protected IL10N&MockObject $l;
+ protected IFactory&MockObject $l10nFactory;
+ protected \Symfony\Component\Console\Helper\QuestionHelper&MockObject $questionHelper;
+ protected \Symfony\Component\Console\Input\InputInterface&MockObject $inputInterface;
+ protected \Symfony\Component\Console\Output\OutputInterface&MockObject $outputInterface;
+ protected UserInterface&MockObject $userInterface;
+ protected ISecureRandom&MockObject $secureRandom;
+ protected LoggerInterface&MockObject $logger;
+
+ protected EncryptAll $encryptAll;
+
+ protected function setUp(): void {
+ parent::setUp();
+ $this->setupUser = $this->getMockBuilder(Setup::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->keyManager = $this->getMockBuilder(KeyManager::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->util = $this->getMockBuilder(Util::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->userManager = $this->getMockBuilder(IUserManager::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->view = $this->getMockBuilder(View::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->config = $this->getMockBuilder(IConfig::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->mailer = $this->getMockBuilder(IMailer::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->l10nFactory = $this->createMock(IFactory::class);
+ $this->l = $this->getMockBuilder(IL10N::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->inputInterface = $this->getMockBuilder(InputInterface::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->outputInterface = $this->getMockBuilder(OutputInterface::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->userInterface = $this->getMockBuilder(UserInterface::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->logger = $this->createMock(LoggerInterface::class);
+
+ /**
+ * We need format method to return a string
+ * @var OutputFormatterInterface&MockObject
+ */
+ $outputFormatter = $this->createMock(OutputFormatterInterface::class);
+ $outputFormatter->method('isDecorated')->willReturn(false);
+ $outputFormatter->method('format')->willReturnArgument(0);
+
+ $this->outputInterface->expects($this->any())->method('getFormatter')
+ ->willReturn($outputFormatter);
+
+ $this->userManager->expects($this->any())->method('getBackends')->willReturn([$this->userInterface]);
+ $this->userInterface->expects($this->any())->method('getUsers')->willReturn(['user1', 'user2']);
+
+ $this->secureRandom = $this->getMockBuilder(ISecureRandom::class)->disableOriginalConstructor()->getMock();
+ $this->secureRandom->expects($this->any())->method('generate')->willReturn('12345678');
+
+
+ $this->encryptAll = new EncryptAll(
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ );
+ }
+
+ protected function createFileInfoMock($type, string $name): FileInfo&MockObject {
+ $fileInfo = $this->createMock(FileInfo::class);
+ $fileInfo->method('getType')->willReturn($type);
+ $fileInfo->method('getName')->willReturn($name);
+ return $fileInfo;
+ }
+
+ public function testEncryptAll(): void {
+ /** @var EncryptAll&MockObject $encryptAll */
+ $encryptAll = $this->getMockBuilder(EncryptAll::class)
+ ->setConstructorArgs(
+ [
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ ]
+ )
+ ->onlyMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords'])
+ ->getMock();
+
+ $this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
+ $encryptAll->expects($this->once())->method('createKeyPairs')->with();
+ $encryptAll->expects($this->once())->method('outputPasswords')->with();
+ $encryptAll->expects($this->once())->method('encryptAllUsersFiles')->with();
+
+ $encryptAll->encryptAll($this->inputInterface, $this->outputInterface);
+ }
+
+ public function testEncryptAllWithMasterKey(): void {
+ /** @var EncryptAll&MockObject $encryptAll */
+ $encryptAll = $this->getMockBuilder(EncryptAll::class)
+ ->setConstructorArgs(
+ [
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ ]
+ )
+ ->onlyMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords'])
+ ->getMock();
+
+ $this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(true);
+ $encryptAll->expects($this->never())->method('createKeyPairs');
+ $this->keyManager->expects($this->once())->method('validateMasterKey');
+ $encryptAll->expects($this->once())->method('encryptAllUsersFiles')->with();
+ $encryptAll->expects($this->never())->method('outputPasswords');
+
+ $encryptAll->encryptAll($this->inputInterface, $this->outputInterface);
+ }
+
+ public function testCreateKeyPairs(): void {
+ /** @var EncryptAll&MockObject $encryptAll */
+ $encryptAll = $this->getMockBuilder(EncryptAll::class)
+ ->setConstructorArgs(
+ [
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ ]
+ )
+ ->onlyMethods(['setupUserFS', 'generateOneTimePassword'])
+ ->getMock();
+
+
+ // set protected property $output
+ $this->invokePrivate($encryptAll, 'output', [$this->outputInterface]);
+
+ $this->keyManager->expects($this->exactly(2))->method('userHasKeys')
+ ->willReturnCallback(
+ function ($user) {
+ if ($user === 'user1') {
+ return false;
+ }
+ return true;
+ }
+ );
+
+ $encryptAll->expects($this->once())->method('setupUserFS')->with('user1');
+ $encryptAll->expects($this->once())->method('generateOneTimePassword')->with('user1')->willReturn('password');
+ $this->setupUser->expects($this->once())->method('setupUser')->with('user1', 'password');
+
+ $this->invokePrivate($encryptAll, 'createKeyPairs');
+
+ $userPasswords = $this->invokePrivate($encryptAll, 'userPasswords');
+
+ // we only expect the skipped user, because generateOneTimePassword which
+ // would set the user with the new password was mocked.
+ // This method will be tested separately
+ $this->assertSame(1, count($userPasswords));
+ $this->assertSame('', $userPasswords['user2']);
+ }
+
+ public function testEncryptAllUsersFiles(): void {
+ /** @var EncryptAll&MockObject $encryptAll */
+ $encryptAll = $this->getMockBuilder(EncryptAll::class)
+ ->setConstructorArgs(
+ [
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ ]
+ )
+ ->onlyMethods(['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']]);
+
+ $encryptAllCalls = [];
+ $encryptAll->expects($this->exactly(2))
+ ->method('encryptUsersFiles')
+ ->willReturnCallback(function ($uid) use (&$encryptAllCalls): void {
+ $encryptAllCalls[] = $uid;
+ });
+
+ $this->invokePrivate($encryptAll, 'encryptAllUsersFiles');
+ self::assertEquals([
+ 'user1',
+ 'user2',
+ ], $encryptAllCalls);
+ }
+
+ public function testEncryptUsersFiles(): void {
+ /** @var EncryptAll&MockObject $encryptAll */
+ $encryptAll = $this->getMockBuilder(EncryptAll::class)
+ ->setConstructorArgs(
+ [
+ $this->setupUser,
+ $this->userManager,
+ $this->view,
+ $this->keyManager,
+ $this->util,
+ $this->config,
+ $this->mailer,
+ $this->l,
+ $this->l10nFactory,
+ $this->questionHelper,
+ $this->secureRandom,
+ $this->logger,
+ ]
+ )
+ ->onlyMethods(['encryptFile', 'setupUserFS'])
+ ->getMock();
+
+ $this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
+
+ $this->view->expects($this->exactly(2))->method('getDirectoryContent')
+ ->willReturnMap([
+ [
+ '/user1/files',
+ '',
+ null,
+ [
+ $this->createFileInfoMock(FileInfo::TYPE_FOLDER, 'foo'),
+ $this->createFileInfoMock(FileInfo::TYPE_FILE, 'bar'),
+ ],
+ ],
+ [
+ '/user1/files/foo',
+ '',
+ null,
+ [
+ $this->createFileInfoMock(FileInfo::TYPE_FILE, 'subfile'),
+ ],
+ ],
+ ]);
+
+ $encryptAllCalls = [];
+ $encryptAll->expects($this->exactly(2))
+ ->method('encryptFile')
+ ->willReturnCallback(function (FileInfo $file, string $path) use (&$encryptAllCalls): bool {
+ $encryptAllCalls[] = $path;
+ return true;
+ });
+
+ $outputFormatter = $this->createMock(OutputFormatterInterface::class);
+ $outputFormatter->method('isDecorated')->willReturn(false);
+ $this->outputInterface->expects($this->any())
+ ->method('getFormatter')
+ ->willReturn($outputFormatter);
+ $progressBar = new ProgressBar($this->outputInterface);
+
+ $this->invokePrivate($encryptAll, 'encryptUsersFiles', ['user1', $progressBar, '']);
+ self::assertEquals([
+ '/user1/files/bar',
+ '/user1/files/foo/subfile',
+ ], $encryptAllCalls);
+ }
+
+ public function testGenerateOneTimePassword(): void {
+ $password = $this->invokePrivate($this->encryptAll, 'generateOneTimePassword', ['user1']);
+ $this->assertTrue(is_string($password));
+ $this->assertSame(8, strlen($password));
+
+ $userPasswords = $this->invokePrivate($this->encryptAll, 'userPasswords');
+ $this->assertSame(1, count($userPasswords));
+ $this->assertSame($password, $userPasswords['user1']);
+ }
+
+ /**
+ * @param $isEncrypted
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataTestEncryptFile')]
+ public function testEncryptFile($isEncrypted): void {
+ $fileInfo = $this->createMock(FileInfo::class);
+ $fileInfo->expects($this->any())->method('isEncrypted')
+ ->willReturn($isEncrypted);
+ $this->view->expects($this->never())->method('getFileInfo');
+
+
+ if ($isEncrypted) {
+ $this->view->expects($this->never())->method('copy');
+ $this->view->expects($this->never())->method('rename');
+ } else {
+ $this->view->expects($this->once())->method('copy');
+ $this->view->expects($this->once())->method('rename');
+ }
+
+ $this->assertTrue(
+ $this->invokePrivate($this->encryptAll, 'encryptFile', [$fileInfo, 'foo.txt'])
+ );
+ }
+
+ public static function dataTestEncryptFile(): array {
+ return [
+ [true],
+ [false],
+ ];
+ }
+}