DecryptAllTest.php 12 KB

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