DecryptAllTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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\OutputInterface;
  34. use Test\TestCase;
  35. /**
  36. * Class DecryptAllTest
  37. *
  38. * @group DB
  39. *
  40. * @package Test\Encryption
  41. */
  42. class DecryptAllTest extends TestCase {
  43. /** @var \PHPUnit\Framework\MockObject\MockObject | IUserManager */
  44. protected $userManager;
  45. /** @var \PHPUnit\Framework\MockObject\MockObject | Manager */
  46. protected $encryptionManager;
  47. /** @var \PHPUnit\Framework\MockObject\MockObject | View */
  48. protected $view;
  49. /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Input\InputInterface */
  50. protected $inputInterface;
  51. /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Output\OutputInterface */
  52. protected $outputInterface;
  53. /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\UserInterface */
  54. protected $userInterface;
  55. /** @var DecryptAll */
  56. protected $instance;
  57. protected function setUp(): void {
  58. parent::setUp();
  59. $this->userManager = $this->getMockBuilder(IUserManager::class)
  60. ->disableOriginalConstructor()->getMock();
  61. $this->encryptionManager = $this->getMockBuilder('OC\Encryption\Manager')
  62. ->disableOriginalConstructor()->getMock();
  63. $this->view = $this->getMockBuilder(View::class)
  64. ->disableOriginalConstructor()->getMock();
  65. $this->inputInterface = $this->getMockBuilder(InputInterface::class)
  66. ->disableOriginalConstructor()->getMock();
  67. $this->outputInterface = $this->getMockBuilder(OutputInterface::class)
  68. ->disableOriginalConstructor()->getMock();
  69. $this->userInterface = $this->getMockBuilder(UserInterface::class)
  70. ->disableOriginalConstructor()->getMock();
  71. $this->outputInterface->expects($this->any())->method('getFormatter')
  72. ->willReturn($this->createMock(OutputFormatterInterface::class));
  73. $this->instance = new DecryptAll($this->encryptionManager, $this->userManager, $this->view);
  74. $this->invokePrivate($this->instance, 'input', [$this->inputInterface]);
  75. $this->invokePrivate($this->instance, 'output', [$this->outputInterface]);
  76. }
  77. public function dataDecryptAll() {
  78. return [
  79. [true, 'user1', true],
  80. [false, 'user1', true],
  81. [true, '0', true],
  82. [false, '0', true],
  83. [true, '', false],
  84. ];
  85. }
  86. /**
  87. * @dataProvider dataDecryptAll
  88. * @param bool $prepareResult
  89. * @param string $user
  90. * @param bool $userExistsChecked
  91. */
  92. public function testDecryptAll($prepareResult, $user, $userExistsChecked) {
  93. if ($userExistsChecked) {
  94. $this->userManager->expects($this->once())->method('userExists')->willReturn(true);
  95. } else {
  96. $this->userManager->expects($this->never())->method('userExists');
  97. }
  98. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject | $instance */
  99. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  100. ->setConstructorArgs(
  101. [
  102. $this->encryptionManager,
  103. $this->userManager,
  104. $this->view
  105. ]
  106. )
  107. ->setMethods(['prepareEncryptionModules', 'decryptAllUsersFiles'])
  108. ->getMock();
  109. $instance->expects($this->once())
  110. ->method('prepareEncryptionModules')
  111. ->with($user)
  112. ->willReturn($prepareResult);
  113. if ($prepareResult) {
  114. $instance->expects($this->once())
  115. ->method('decryptAllUsersFiles')
  116. ->with($user);
  117. } else {
  118. $instance->expects($this->never())->method('decryptAllUsersFiles');
  119. }
  120. $instance->decryptAll($this->inputInterface, $this->outputInterface, $user);
  121. }
  122. /**
  123. * test decrypt all call with a user who doesn't exists
  124. */
  125. public function testDecryptAllWrongUser() {
  126. $this->userManager->expects($this->once())->method('userExists')->willReturn(false);
  127. $this->outputInterface->expects($this->once())->method('writeln')
  128. ->with('User "user1" does not exist. Please check the username and try again');
  129. $this->assertFalse(
  130. $this->instance->decryptAll($this->inputInterface, $this->outputInterface, 'user1')
  131. );
  132. }
  133. public function dataTrueFalse() {
  134. return [
  135. [true],
  136. [false],
  137. ];
  138. }
  139. /**
  140. * @dataProvider dataTrueFalse
  141. * @param bool $success
  142. */
  143. public function testPrepareEncryptionModules($success) {
  144. $user = 'user1';
  145. $dummyEncryptionModule = $this->getMockBuilder('OCP\Encryption\IEncryptionModule')
  146. ->disableOriginalConstructor()->getMock();
  147. $dummyEncryptionModule->expects($this->once())
  148. ->method('prepareDecryptAll')
  149. ->with($this->inputInterface, $this->outputInterface, $user)
  150. ->willReturn($success);
  151. $callback = function () use ($dummyEncryptionModule) {
  152. return $dummyEncryptionModule;
  153. };
  154. $moduleDescription = [
  155. 'id' => 'id',
  156. 'displayName' => 'displayName',
  157. 'callback' => $callback
  158. ];
  159. $this->encryptionManager->expects($this->once())
  160. ->method('getEncryptionModules')
  161. ->willReturn([$moduleDescription]);
  162. $this->assertSame($success,
  163. $this->invokePrivate($this->instance, 'prepareEncryptionModules', [$user])
  164. );
  165. }
  166. /**
  167. * @dataProvider dataTestDecryptAllUsersFiles
  168. */
  169. public function testDecryptAllUsersFiles($user) {
  170. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject | $instance */
  171. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  172. ->setConstructorArgs(
  173. [
  174. $this->encryptionManager,
  175. $this->userManager,
  176. $this->view
  177. ]
  178. )
  179. ->setMethods(['decryptUsersFiles'])
  180. ->getMock();
  181. $this->invokePrivate($instance, 'input', [$this->inputInterface]);
  182. $this->invokePrivate($instance, 'output', [$this->outputInterface]);
  183. if (empty($user)) {
  184. $this->userManager->expects($this->once())
  185. ->method('getBackends')
  186. ->willReturn([$this->userInterface]);
  187. $this->userInterface->expects($this->any())
  188. ->method('getUsers')
  189. ->willReturn(['user1', 'user2']);
  190. $instance->expects($this->at(0))
  191. ->method('decryptUsersFiles')
  192. ->with('user1');
  193. $instance->expects($this->at(1))
  194. ->method('decryptUsersFiles')
  195. ->with('user2');
  196. } else {
  197. $instance->expects($this->once())
  198. ->method('decryptUsersFiles')
  199. ->with($user);
  200. }
  201. $this->invokePrivate($instance, 'decryptAllUsersFiles', [$user]);
  202. }
  203. public function dataTestDecryptAllUsersFiles() {
  204. return [
  205. ['user1'],
  206. ['']
  207. ];
  208. }
  209. public function testDecryptUsersFiles() {
  210. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */
  211. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  212. ->setConstructorArgs(
  213. [
  214. $this->encryptionManager,
  215. $this->userManager,
  216. $this->view
  217. ]
  218. )
  219. ->setMethods(['decryptFile'])
  220. ->getMock();
  221. $storage = $this->getMockBuilder(Storage::class)
  222. ->disableOriginalConstructor()->getMock();
  223. $sharedStorage = $this->getMockBuilder(Storage::class)
  224. ->disableOriginalConstructor()->getMock();
  225. $sharedStorage->expects($this->once())->method('instanceOfStorage')
  226. ->with('OCA\Files_Sharing\SharedStorage')->willReturn(true);
  227. $this->view->expects($this->at(0))->method('getDirectoryContent')
  228. ->with('/user1/files')->willReturn(
  229. [
  230. new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type' => 'dir'], null),
  231. new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type' => 'file', 'encrypted' => true], null),
  232. new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type' => 'file', 'encrypted' => true], null),
  233. ]
  234. );
  235. $this->view->expects($this->at(3))->method('getDirectoryContent')
  236. ->with('/user1/files/foo')->willReturn(
  237. [
  238. new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type' => 'file', 'encrypted' => true], null)
  239. ]
  240. );
  241. $this->view->expects($this->any())->method('is_dir')
  242. ->willReturnCallback(
  243. function ($path) {
  244. if ($path === '/user1/files/foo') {
  245. return true;
  246. }
  247. return false;
  248. }
  249. );
  250. $instance->expects($this->at(0))
  251. ->method('decryptFile')
  252. ->with('/user1/files/bar');
  253. $instance->expects($this->at(1))
  254. ->method('decryptFile')
  255. ->with('/user1/files/foo/subfile');
  256. $output = $this->createMock(OutputInterface::class);
  257. $output->expects($this->any())
  258. ->method('getFormatter')
  259. ->willReturn($this->createMock(OutputFormatterInterface::class));
  260. $progressBar = new ProgressBar($output);
  261. $this->invokePrivate($instance, 'decryptUsersFiles', ['user1', $progressBar, '']);
  262. }
  263. /**
  264. * @dataProvider dataTrueFalse
  265. */
  266. public function testDecryptFile($isEncrypted) {
  267. $path = 'test.txt';
  268. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */
  269. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  270. ->setConstructorArgs(
  271. [
  272. $this->encryptionManager,
  273. $this->userManager,
  274. $this->view
  275. ]
  276. )
  277. ->setMethods(['getTimestamp'])
  278. ->getMock();
  279. $fileInfo = $this->createMock(FileInfo::class);
  280. $fileInfo->expects($this->any())->method('isEncrypted')
  281. ->willReturn($isEncrypted);
  282. $this->view->expects($this->any())->method('getFileInfo')
  283. ->willReturn($fileInfo);
  284. if ($isEncrypted) {
  285. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  286. $this->view->expects($this->once())
  287. ->method('copy')
  288. ->with($path, $path . '.decrypted.42');
  289. $this->view->expects($this->once())
  290. ->method('rename')
  291. ->with($path . '.decrypted.42', $path);
  292. } else {
  293. $instance->expects($this->never())->method('getTimestamp');
  294. $this->view->expects($this->never())->method('copy');
  295. $this->view->expects($this->never())->method('rename');
  296. }
  297. $this->assertTrue(
  298. $this->invokePrivate($instance, 'decryptFile', [$path])
  299. );
  300. }
  301. public function testDecryptFileFailure() {
  302. $path = 'test.txt';
  303. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */
  304. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  305. ->setConstructorArgs(
  306. [
  307. $this->encryptionManager,
  308. $this->userManager,
  309. $this->view
  310. ]
  311. )
  312. ->setMethods(['getTimestamp'])
  313. ->getMock();
  314. $fileInfo = $this->createMock(FileInfo::class);
  315. $fileInfo->expects($this->any())->method('isEncrypted')
  316. ->willReturn(true);
  317. $this->view->expects($this->any())->method('getFileInfo')
  318. ->willReturn($fileInfo);
  319. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  320. $this->view->expects($this->once())
  321. ->method('copy')
  322. ->with($path, $path . '.decrypted.42')
  323. ->willReturnCallback(function () {
  324. throw new DecryptionFailedException();
  325. });
  326. $this->view->expects($this->never())->method('rename');
  327. $this->view->expects($this->once())
  328. ->method('file_exists')
  329. ->with($path . '.decrypted.42')
  330. ->willReturn(true);
  331. $this->view->expects($this->once())
  332. ->method('unlink')
  333. ->with($path . '.decrypted.42');
  334. $this->assertFalse(
  335. $this->invokePrivate($instance, 'decryptFile', [$path])
  336. );
  337. }
  338. }