You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DecryptAllTest.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <?php
  2. /**
  3. * @author Björn Schießle <schiessle@owncloud.com>
  4. *
  5. * @copyright Copyright (c) 2015, ownCloud, Inc.
  6. * @license AGPL-3.0
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. namespace Test\Encryption;
  22. use OC\Encryption\DecryptAll;
  23. use OC\Encryption\Exceptions\DecryptionFailedException;
  24. use OC\Encryption\Manager;
  25. use OC\Files\FileInfo;
  26. use OC\Files\View;
  27. use OCP\Files\Storage;
  28. use OCP\IUserManager;
  29. use OCP\UserInterface;
  30. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  31. use Symfony\Component\Console\Helper\ProgressBar;
  32. use Symfony\Component\Console\Input\InputInterface;
  33. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  34. use Symfony\Component\Console\Output\OutputInterface;
  35. use Test\TestCase;
  36. /**
  37. * Class DecryptAllTest
  38. *
  39. * @group DB
  40. *
  41. * @package Test\Encryption
  42. */
  43. class DecryptAllTest extends TestCase {
  44. /** @var \PHPUnit_Framework_MockObject_MockObject | IUserManager */
  45. protected $userManager;
  46. /** @var \PHPUnit_Framework_MockObject_MockObject | Manager */
  47. protected $encryptionManager;
  48. /** @var \PHPUnit_Framework_MockObject_MockObject | View */
  49. protected $view;
  50. /** @var \PHPUnit_Framework_MockObject_MockObject | \Symfony\Component\Console\Input\InputInterface */
  51. protected $inputInterface;
  52. /** @var \PHPUnit_Framework_MockObject_MockObject | \Symfony\Component\Console\Output\OutputInterface */
  53. protected $outputInterface;
  54. /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\UserInterface */
  55. protected $userInterface;
  56. /** @var DecryptAll */
  57. protected $instance;
  58. public function setUp() {
  59. parent::setUp();
  60. $this->userManager = $this->getMockBuilder(IUserManager::class)
  61. ->disableOriginalConstructor()->getMock();
  62. $this->encryptionManager = $this->getMockBuilder('OC\Encryption\Manager')
  63. ->disableOriginalConstructor()->getMock();
  64. $this->view = $this->getMockBuilder(View::class)
  65. ->disableOriginalConstructor()->getMock();
  66. $this->inputInterface = $this->getMockBuilder(InputInterface::class)
  67. ->disableOriginalConstructor()->getMock();
  68. $this->outputInterface = $this->getMockBuilder(OutputInterface::class)
  69. ->disableOriginalConstructor()->getMock();
  70. $this->userInterface = $this->getMockBuilder(UserInterface::class)
  71. ->disableOriginalConstructor()->getMock();
  72. $this->outputInterface->expects($this->any())->method('getFormatter')
  73. ->willReturn($this->createMock(OutputFormatterInterface::class));
  74. $this->instance = new DecryptAll($this->encryptionManager, $this->userManager, $this->view);
  75. $this->invokePrivate($this->instance, 'input', [$this->inputInterface]);
  76. $this->invokePrivate($this->instance, 'output', [$this->outputInterface]);
  77. }
  78. public function dataDecryptAll() {
  79. return [
  80. [true, 'user1', true],
  81. [false, 'user1', true],
  82. [true, '0', true],
  83. [false, '0', true],
  84. [true, '', false],
  85. ];
  86. }
  87. /**
  88. * @dataProvider dataDecryptAll
  89. * @param bool $prepareResult
  90. * @param string $user
  91. * @param bool $userExistsChecked
  92. */
  93. public function testDecryptAll($prepareResult, $user, $userExistsChecked) {
  94. if ($userExistsChecked) {
  95. $this->userManager->expects($this->once())->method('userExists')->willReturn(true);
  96. } else {
  97. $this->userManager->expects($this->never())->method('userExists');
  98. }
  99. /** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject | $instance */
  100. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  101. ->setConstructorArgs(
  102. [
  103. $this->encryptionManager,
  104. $this->userManager,
  105. $this->view
  106. ]
  107. )
  108. ->setMethods(['prepareEncryptionModules', 'decryptAllUsersFiles'])
  109. ->getMock();
  110. $instance->expects($this->once())
  111. ->method('prepareEncryptionModules')
  112. ->with($user)
  113. ->willReturn($prepareResult);
  114. if ($prepareResult) {
  115. $instance->expects($this->once())
  116. ->method('decryptAllUsersFiles')
  117. ->with($user);
  118. } else {
  119. $instance->expects($this->never())->method('decryptAllUsersFiles');
  120. }
  121. $instance->decryptAll($this->inputInterface, $this->outputInterface, $user);
  122. }
  123. /**
  124. * test decrypt all call with a user who doesn't exists
  125. */
  126. public function testDecryptAllWrongUser() {
  127. $this->userManager->expects($this->once())->method('userExists')->willReturn(false);
  128. $this->outputInterface->expects($this->once())->method('writeln')
  129. ->with('User "user1" does not exist. Please check the username and try again');
  130. $this->assertFalse(
  131. $this->instance->decryptAll($this->inputInterface, $this->outputInterface, 'user1')
  132. );
  133. }
  134. public function dataTrueFalse() {
  135. return [
  136. [true],
  137. [false],
  138. ];
  139. }
  140. /**
  141. * @dataProvider dataTrueFalse
  142. * @param bool $success
  143. */
  144. public function testPrepareEncryptionModules($success) {
  145. $user = 'user1';
  146. $dummyEncryptionModule = $this->getMockBuilder('OCP\Encryption\IEncryptionModule')
  147. ->disableOriginalConstructor()->getMock();
  148. $dummyEncryptionModule->expects($this->once())
  149. ->method('prepareDecryptAll')
  150. ->with($this->inputInterface, $this->outputInterface, $user)
  151. ->willReturn($success);
  152. $callback = function() use ($dummyEncryptionModule) {return $dummyEncryptionModule;};
  153. $moduleDescription = [
  154. 'id' => 'id',
  155. 'displayName' => 'displayName',
  156. 'callback' => $callback
  157. ];
  158. $this->encryptionManager->expects($this->once())
  159. ->method('getEncryptionModules')
  160. ->willReturn([$moduleDescription]);
  161. $this->assertSame($success,
  162. $this->invokePrivate($this->instance, 'prepareEncryptionModules', [$user])
  163. );
  164. }
  165. /**
  166. * @dataProvider dataTestDecryptAllUsersFiles
  167. */
  168. public function testDecryptAllUsersFiles($user) {
  169. /** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject | $instance */
  170. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  171. ->setConstructorArgs(
  172. [
  173. $this->encryptionManager,
  174. $this->userManager,
  175. $this->view
  176. ]
  177. )
  178. ->setMethods(['decryptUsersFiles'])
  179. ->getMock();
  180. $this->invokePrivate($instance, 'input', [$this->inputInterface]);
  181. $this->invokePrivate($instance, 'output', [$this->outputInterface]);
  182. if (empty($user)) {
  183. $this->userManager->expects($this->once())
  184. ->method('getBackends')
  185. ->willReturn([$this->userInterface]);
  186. $this->userInterface->expects($this->any())
  187. ->method('getUsers')
  188. ->willReturn(['user1', 'user2']);
  189. $instance->expects($this->at(0))
  190. ->method('decryptUsersFiles')
  191. ->with('user1');
  192. $instance->expects($this->at(1))
  193. ->method('decryptUsersFiles')
  194. ->with('user2');
  195. } else {
  196. $instance->expects($this->once())
  197. ->method('decryptUsersFiles')
  198. ->with($user);
  199. }
  200. $this->invokePrivate($instance, 'decryptAllUsersFiles', [$user]);
  201. }
  202. public function dataTestDecryptAllUsersFiles() {
  203. return [
  204. ['user1'],
  205. ['']
  206. ];
  207. }
  208. public function testDecryptUsersFiles() {
  209. /** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
  210. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  211. ->setConstructorArgs(
  212. [
  213. $this->encryptionManager,
  214. $this->userManager,
  215. $this->view
  216. ]
  217. )
  218. ->setMethods(['decryptFile'])
  219. ->getMock();
  220. $storage = $this->getMockBuilder(Storage::class)
  221. ->disableOriginalConstructor()->getMock();
  222. $sharedStorage = $this->getMockBuilder(Storage::class)
  223. ->disableOriginalConstructor()->getMock();
  224. $sharedStorage->expects($this->once())->method('instanceOfStorage')
  225. ->with('OCA\Files_Sharing\SharedStorage')->willReturn(true);
  226. $this->view->expects($this->at(0))->method('getDirectoryContent')
  227. ->with('/user1/files')->willReturn(
  228. [
  229. new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type'=>'dir'], null),
  230. new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type'=>'file', 'encrypted'=>true], null),
  231. new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type'=>'file', 'encrypted'=>true], null),
  232. ]
  233. );
  234. $this->view->expects($this->at(3))->method('getDirectoryContent')
  235. ->with('/user1/files/foo')->willReturn(
  236. [
  237. new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type'=>'file', 'encrypted'=>true], null)
  238. ]
  239. );
  240. $this->view->expects($this->any())->method('is_dir')
  241. ->willReturnCallback(
  242. function($path) {
  243. if ($path === '/user1/files/foo') {
  244. return true;
  245. }
  246. return false;
  247. }
  248. );
  249. $instance->expects($this->at(0))
  250. ->method('decryptFile')
  251. ->with('/user1/files/bar');
  252. $instance->expects($this->at(1))
  253. ->method('decryptFile')
  254. ->with('/user1/files/foo/subfile');
  255. $output = $this->createMock(OutputInterface::class);
  256. $output->expects($this->any())
  257. ->method('getFormatter')
  258. ->willReturn($this->createMock(OutputFormatterInterface::class));
  259. $progressBar = new ProgressBar($output);
  260. $this->invokePrivate($instance, 'decryptUsersFiles', ['user1', $progressBar, '']);
  261. }
  262. /**
  263. * @dataProvider dataTrueFalse
  264. */
  265. public function testDecryptFile($isEncrypted) {
  266. $path = 'test.txt';
  267. /** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
  268. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  269. ->setConstructorArgs(
  270. [
  271. $this->encryptionManager,
  272. $this->userManager,
  273. $this->view
  274. ]
  275. )
  276. ->setMethods(['getTimestamp'])
  277. ->getMock();
  278. $fileInfo = $this->createMock(FileInfo::class);
  279. $fileInfo->expects($this->any())->method('isEncrypted')
  280. ->willReturn($isEncrypted);
  281. $this->view->expects($this->any())->method('getFileInfo')
  282. ->willReturn($fileInfo);
  283. if ($isEncrypted) {
  284. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  285. $this->view->expects($this->once())
  286. ->method('copy')
  287. ->with($path, $path . '.decrypted.42');
  288. $this->view->expects($this->once())
  289. ->method('rename')
  290. ->with($path . '.decrypted.42', $path);
  291. } else {
  292. $instance->expects($this->never())->method('getTimestamp');
  293. $this->view->expects($this->never())->method('copy');
  294. $this->view->expects($this->never())->method('rename');
  295. }
  296. $this->assertTrue(
  297. $this->invokePrivate($instance, 'decryptFile', [$path])
  298. );
  299. }
  300. public function testDecryptFileFailure() {
  301. $path = 'test.txt';
  302. /** @var DecryptAll | \PHPUnit_Framework_MockObject_MockObject $instance */
  303. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  304. ->setConstructorArgs(
  305. [
  306. $this->encryptionManager,
  307. $this->userManager,
  308. $this->view
  309. ]
  310. )
  311. ->setMethods(['getTimestamp'])
  312. ->getMock();
  313. $fileInfo = $this->createMock(FileInfo::class);
  314. $fileInfo->expects($this->any())->method('isEncrypted')
  315. ->willReturn(true);
  316. $this->view->expects($this->any())->method('getFileInfo')
  317. ->willReturn($fileInfo);
  318. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  319. $this->view->expects($this->once())
  320. ->method('copy')
  321. ->with($path, $path . '.decrypted.42')
  322. ->willReturnCallback(function() { throw new DecryptionFailedException();});
  323. $this->view->expects($this->never())->method('rename');
  324. $this->view->expects($this->once())
  325. ->method('file_exists')
  326. ->with($path . '.decrypted.42')
  327. ->willReturn(true);
  328. $this->view->expects($this->once())
  329. ->method('unlink')
  330. ->with($path . '.decrypted.42');
  331. $this->assertFalse(
  332. $this->invokePrivate($instance, 'decryptFile', [$path])
  333. );
  334. }
  335. }