nextcloud/tests/lib/Encryption/DecryptAllTest.php

401 lines
12 KiB
PHP

<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace Test\Encryption;
use OC\Encryption\DecryptAll;
use OC\Encryption\Exceptions\DecryptionFailedException;
use OC\Encryption\Manager;
use OC\Files\FileInfo;
use OC\Files\View;
use OCP\Files\Storage;
use OCP\IUserManager;
use OCP\UserInterface;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Test\TestCase;
/**
* Class DecryptAllTest
*
* @group DB
*
* @package Test\Encryption
*/
class DecryptAllTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject | IUserManager */
protected $userManager;
/** @var \PHPUnit_Framework_MockObject_MockObject | Manager */
protected $encryptionManager;
/** @var \PHPUnit_Framework_MockObject_MockObject | View */
protected $view;
/** @var \PHPUnit_Framework_MockObject_MockObject | \Symfony\Component\Console\Input\InputInterface */
protected $inputInterface;
/** @var \PHPUnit_Framework_MockObject_MockObject | \Symfony\Component\Console\Output\OutputInterface */
protected $outputInterface;
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\UserInterface */
protected $userInterface;
/** @var DecryptAll */
protected $instance;
protected function setUp(): void {
parent::setUp();
$this->userManager = $this->getMockBuilder(IUserManager::class)
->disableOriginalConstructor()->getMock();
$this->encryptionManager = $this->getMockBuilder('OC\Encryption\Manager')
->disableOriginalConstructor()->getMock();
$this->view = $this->getMockBuilder(View::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->outputInterface->expects($this->any())->method('getFormatter')
->willReturn($this->createMock(OutputFormatterInterface::class));
$this->instance = new DecryptAll($this->encryptionManager, $this->userManager, $this->view);
$this->invokePrivate($this->instance, 'input', [$this->inputInterface]);
$this->invokePrivate($this->instance, 'output', [$this->outputInterface]);
}
public function dataDecryptAll() {
return [
[true, 'user1', true],
[false, 'user1', true],
[true, '0', true],
[false, '0', true],
[true, '', false],
];
}
/**
* @dataProvider dataDecryptAll
* @param bool $prepareResult
* @param string $user
* @param bool $userExistsChecked
*/
public function testDecryptAll($prepareResult, $user, $userExistsChecked) {
if ($userExistsChecked) {
$this->userManager->expects($this->once())->method('userExists')->willReturn(true);
} else {
$this->userManager->expects($this->never())->method('userExists');
}
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject | $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
[
$this->encryptionManager,
$this->userManager,
$this->view
]
)
->setMethods(['prepareEncryptionModules', 'decryptAllUsersFiles'])
->getMock();
$instance->expects($this->once())
->method('prepareEncryptionModules')
->with($user)
->willReturn($prepareResult);
if ($prepareResult) {
$instance->expects($this->once())
->method('decryptAllUsersFiles')
->with($user);
} else {
$instance->expects($this->never())->method('decryptAllUsersFiles');
}
$instance->decryptAll($this->inputInterface, $this->outputInterface, $user);
}
/**
* test decrypt all call with a user who doesn't exists
*/
public function testDecryptAllWrongUser() {
$this->userManager->expects($this->once())->method('userExists')->willReturn(false);
$this->outputInterface->expects($this->once())->method('writeln')
->with('User "user1" does not exist. Please check the username and try again');
$this->assertFalse(
$this->instance->decryptAll($this->inputInterface, $this->outputInterface, 'user1')
);
}
public function dataTrueFalse() {
return [
[true],
[false],
];
}
/**
* @dataProvider dataTrueFalse
* @param bool $success
*/
public function testPrepareEncryptionModules($success) {
$user = 'user1';
$dummyEncryptionModule = $this->getMockBuilder('OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()->getMock();
$dummyEncryptionModule->expects($this->once())
->method('prepareDecryptAll')
->with($this->inputInterface, $this->outputInterface, $user)
->willReturn($success);
$callback = function() use ($dummyEncryptionModule) {return $dummyEncryptionModule;};
$moduleDescription = [
'id' => 'id',
'displayName' => 'displayName',
'callback' => $callback
];
$this->encryptionManager->expects($this->once())
->method('getEncryptionModules')
->willReturn([$moduleDescription]);
$this->assertSame($success,
$this->invokePrivate($this->instance, 'prepareEncryptionModules', [$user])
);
}
/**
* @dataProvider dataTestDecryptAllUsersFiles
*/
public function testDecryptAllUsersFiles($user) {
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject | $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
[
$this->encryptionManager,
$this->userManager,
$this->view
]
)
->setMethods(['decryptUsersFiles'])
->getMock();
$this->invokePrivate($instance, 'input', [$this->inputInterface]);
$this->invokePrivate($instance, 'output', [$this->outputInterface]);
if (empty($user)) {
$this->userManager->expects($this->once())
->method('getBackends')
->willReturn([$this->userInterface]);
$this->userInterface->expects($this->any())
->method('getUsers')
->willReturn(['user1', 'user2']);
$instance->expects($this->at(0))
->method('decryptUsersFiles')
->with('user1');
$instance->expects($this->at(1))
->method('decryptUsersFiles')
->with('user2');
} else {
$instance->expects($this->once())
->method('decryptUsersFiles')
->with($user);
}
$this->invokePrivate($instance, 'decryptAllUsersFiles', [$user]);
}
public function dataTestDecryptAllUsersFiles() {
return [
['user1'],
['']
];
}
public function testDecryptUsersFiles() {
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
[
$this->encryptionManager,
$this->userManager,
$this->view
]
)
->setMethods(['decryptFile'])
->getMock();
$storage = $this->getMockBuilder(Storage::class)
->disableOriginalConstructor()->getMock();
$sharedStorage = $this->getMockBuilder(Storage::class)
->disableOriginalConstructor()->getMock();
$sharedStorage->expects($this->once())->method('instanceOfStorage')
->with('OCA\Files_Sharing\SharedStorage')->willReturn(true);
$this->view->expects($this->at(0))->method('getDirectoryContent')
->with('/user1/files')->willReturn(
[
new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type'=>'dir'], null),
new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type'=>'file', 'encrypted'=>true], null),
new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type'=>'file', 'encrypted'=>true], null),
]
);
$this->view->expects($this->at(3))->method('getDirectoryContent')
->with('/user1/files/foo')->willReturn(
[
new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type'=>'file', 'encrypted'=>true], null)
]
);
$this->view->expects($this->any())->method('is_dir')
->willReturnCallback(
function($path) {
if ($path === '/user1/files/foo') {
return true;
}
return false;
}
);
$instance->expects($this->at(0))
->method('decryptFile')
->with('/user1/files/bar');
$instance->expects($this->at(1))
->method('decryptFile')
->with('/user1/files/foo/subfile');
$output = $this->createMock(OutputInterface::class);
$output->expects($this->any())
->method('getFormatter')
->willReturn($this->createMock(OutputFormatterInterface::class));
$progressBar = new ProgressBar($output);
$this->invokePrivate($instance, 'decryptUsersFiles', ['user1', $progressBar, '']);
}
/**
* @dataProvider dataTrueFalse
*/
public function testDecryptFile($isEncrypted) {
$path = 'test.txt';
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
[
$this->encryptionManager,
$this->userManager,
$this->view
]
)
->setMethods(['getTimestamp'])
->getMock();
$fileInfo = $this->createMock(FileInfo::class);
$fileInfo->expects($this->any())->method('isEncrypted')
->willReturn($isEncrypted);
$this->view->expects($this->any())->method('getFileInfo')
->willReturn($fileInfo);
if ($isEncrypted) {
$instance->expects($this->any())->method('getTimestamp')->willReturn(42);
$this->view->expects($this->once())
->method('copy')
->with($path, $path . '.decrypted.42');
$this->view->expects($this->once())
->method('rename')
->with($path . '.decrypted.42', $path);
} else {
$instance->expects($this->never())->method('getTimestamp');
$this->view->expects($this->never())->method('copy');
$this->view->expects($this->never())->method('rename');
}
$this->assertTrue(
$this->invokePrivate($instance, 'decryptFile', [$path])
);
}
public function testDecryptFileFailure() {
$path = 'test.txt';
/** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
$instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
->setConstructorArgs(
[
$this->encryptionManager,
$this->userManager,
$this->view
]
)
->setMethods(['getTimestamp'])
->getMock();
$fileInfo = $this->createMock(FileInfo::class);
$fileInfo->expects($this->any())->method('isEncrypted')
->willReturn(true);
$this->view->expects($this->any())->method('getFileInfo')
->willReturn($fileInfo);
$instance->expects($this->any())->method('getTimestamp')->willReturn(42);
$this->view->expects($this->once())
->method('copy')
->with($path, $path . '.decrypted.42')
->willReturnCallback(function() { throw new DecryptionFailedException();});
$this->view->expects($this->never())->method('rename');
$this->view->expects($this->once())
->method('file_exists')
->with($path . '.decrypted.42')
->willReturn(true);
$this->view->expects($this->once())
->method('unlink')
->with($path . '.decrypted.42');
$this->assertFalse(
$this->invokePrivate($instance, 'decryptFile', [$path])
);
}
}