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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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->at(0))
  194. ->method('decryptUsersFiles')
  195. ->with('user1');
  196. $instance->expects($this->at(1))
  197. ->method('decryptUsersFiles')
  198. ->with('user2');
  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->at(0))->method('getDirectoryContent')
  231. ->with('/user1/files')->willReturn(
  232. [
  233. new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type' => 'dir'], null),
  234. new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type' => 'file', 'encrypted' => true], null),
  235. new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type' => 'file', 'encrypted' => true], null),
  236. ]
  237. );
  238. $this->view->expects($this->at(3))->method('getDirectoryContent')
  239. ->with('/user1/files/foo')->willReturn(
  240. [
  241. new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type' => 'file', 'encrypted' => true], null)
  242. ]
  243. );
  244. $this->view->expects($this->any())->method('is_dir')
  245. ->willReturnCallback(
  246. function ($path) {
  247. if ($path === '/user1/files/foo') {
  248. return true;
  249. }
  250. return false;
  251. }
  252. );
  253. $instance->expects($this->at(0))
  254. ->method('decryptFile')
  255. ->with('/user1/files/bar');
  256. $instance->expects($this->at(1))
  257. ->method('decryptFile')
  258. ->with('/user1/files/foo/subfile');
  259. /* We need format method to return a string */
  260. $outputFormatter = $this->createMock(OutputFormatterInterface::class);
  261. $outputFormatter->method('format')->willReturn('foo');
  262. $output = $this->createMock(OutputInterface::class);
  263. $output->expects($this->any())
  264. ->method('getFormatter')
  265. ->willReturn($outputFormatter);
  266. $progressBar = new ProgressBar($output);
  267. $this->invokePrivate($instance, 'decryptUsersFiles', ['user1', $progressBar, '']);
  268. }
  269. /**
  270. * @dataProvider dataTrueFalse
  271. */
  272. public function testDecryptFile($isEncrypted) {
  273. $path = 'test.txt';
  274. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */
  275. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  276. ->setConstructorArgs(
  277. [
  278. $this->encryptionManager,
  279. $this->userManager,
  280. $this->view
  281. ]
  282. )
  283. ->setMethods(['getTimestamp'])
  284. ->getMock();
  285. $fileInfo = $this->createMock(FileInfo::class);
  286. $fileInfo->expects($this->any())->method('isEncrypted')
  287. ->willReturn($isEncrypted);
  288. $this->view->expects($this->any())->method('getFileInfo')
  289. ->willReturn($fileInfo);
  290. if ($isEncrypted) {
  291. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  292. $this->view->expects($this->once())
  293. ->method('copy')
  294. ->with($path, $path . '.decrypted.42');
  295. $this->view->expects($this->once())
  296. ->method('rename')
  297. ->with($path . '.decrypted.42', $path);
  298. } else {
  299. $instance->expects($this->never())->method('getTimestamp');
  300. $this->view->expects($this->never())->method('copy');
  301. $this->view->expects($this->never())->method('rename');
  302. }
  303. $this->assertTrue(
  304. $this->invokePrivate($instance, 'decryptFile', [$path])
  305. );
  306. }
  307. public function testDecryptFileFailure() {
  308. $path = 'test.txt';
  309. /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */
  310. $instance = $this->getMockBuilder('OC\Encryption\DecryptAll')
  311. ->setConstructorArgs(
  312. [
  313. $this->encryptionManager,
  314. $this->userManager,
  315. $this->view
  316. ]
  317. )
  318. ->setMethods(['getTimestamp'])
  319. ->getMock();
  320. $fileInfo = $this->createMock(FileInfo::class);
  321. $fileInfo->expects($this->any())->method('isEncrypted')
  322. ->willReturn(true);
  323. $this->view->expects($this->any())->method('getFileInfo')
  324. ->willReturn($fileInfo);
  325. $instance->expects($this->any())->method('getTimestamp')->willReturn(42);
  326. $this->view->expects($this->once())
  327. ->method('copy')
  328. ->with($path, $path . '.decrypted.42')
  329. ->willReturnCallback(function () {
  330. throw new DecryptionFailedException();
  331. });
  332. $this->view->expects($this->never())->method('rename');
  333. $this->view->expects($this->once())
  334. ->method('file_exists')
  335. ->with($path . '.decrypted.42')
  336. ->willReturn(true);
  337. $this->view->expects($this->once())
  338. ->method('unlink')
  339. ->with($path . '.decrypted.42');
  340. $this->assertFalse(
  341. $this->invokePrivate($instance, 'decryptFile', [$path])
  342. );
  343. }
  344. }