RecoveryTest.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Encryption\Tests;
  8. use OC\Files\View;
  9. use OCA\Encryption\Crypto\Crypt;
  10. use OCA\Encryption\KeyManager;
  11. use OCA\Encryption\Recovery;
  12. use OCP\Encryption\IFile;
  13. use OCP\IConfig;
  14. use OCP\IUser;
  15. use OCP\IUserSession;
  16. use PHPUnit\Framework\MockObject\MockObject;
  17. use Test\TestCase;
  18. class RecoveryTest extends TestCase {
  19. private static $tempStorage = [];
  20. /**
  21. * @var IFile|\PHPUnit\Framework\MockObject\MockObject
  22. */
  23. private $fileMock;
  24. /**
  25. * @var View|\PHPUnit\Framework\MockObject\MockObject
  26. */
  27. private $viewMock;
  28. /**
  29. * @var IUserSession|\PHPUnit\Framework\MockObject\MockObject
  30. */
  31. private $userSessionMock;
  32. /**
  33. * @var MockObject|IUser
  34. */
  35. private $user;
  36. /**
  37. * @var KeyManager|\PHPUnit\Framework\MockObject\MockObject
  38. */
  39. private $keyManagerMock;
  40. /**
  41. * @var IConfig|\PHPUnit\Framework\MockObject\MockObject
  42. */
  43. private $configMock;
  44. /**
  45. * @var Crypt|\PHPUnit\Framework\MockObject\MockObject
  46. */
  47. private $cryptMock;
  48. /**
  49. * @var Recovery
  50. */
  51. private $instance;
  52. public function testEnableAdminRecoverySuccessful(): void {
  53. $this->keyManagerMock->expects($this->exactly(2))
  54. ->method('recoveryKeyExists')
  55. ->willReturnOnConsecutiveCalls(false, true);
  56. $this->cryptMock->expects($this->once())
  57. ->method('createKeyPair')
  58. ->willReturn([
  59. 'publicKey' => 'privateKey',
  60. 'privateKey' => 'publicKey',
  61. ]);
  62. $this->keyManagerMock->expects($this->once())
  63. ->method('setRecoveryKey')
  64. ->willReturn(false);
  65. $this->keyManagerMock->expects($this->exactly(2))
  66. ->method('checkRecoveryPassword')
  67. ->willReturnOnConsecutiveCalls(true, true);
  68. $this->assertTrue($this->instance->enableAdminRecovery('password'));
  69. $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
  70. $this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
  71. $this->assertTrue($this->instance->enableAdminRecovery('password'));
  72. }
  73. public function testEnableAdminRecoveryCouldNotCheckPassword(): void {
  74. $this->keyManagerMock->expects($this->exactly(2))
  75. ->method('recoveryKeyExists')
  76. ->willReturnOnConsecutiveCalls(false, true);
  77. $this->cryptMock->expects($this->once())
  78. ->method('createKeyPair')
  79. ->willReturn([
  80. 'publicKey' => 'privateKey',
  81. 'privateKey' => 'publicKey',
  82. ]);
  83. $this->keyManagerMock->expects($this->once())
  84. ->method('setRecoveryKey')
  85. ->willReturn(false);
  86. $this->keyManagerMock->expects($this->exactly(2))
  87. ->method('checkRecoveryPassword')
  88. ->willReturnOnConsecutiveCalls(true, false);
  89. $this->assertTrue($this->instance->enableAdminRecovery('password'));
  90. $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
  91. $this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
  92. $this->assertFalse($this->instance->enableAdminRecovery('password'));
  93. }
  94. public function testEnableAdminRecoveryCouldNotCreateKey(): void {
  95. $this->keyManagerMock->expects($this->once())
  96. ->method('recoveryKeyExists')
  97. ->willReturn(false);
  98. $this->cryptMock->expects($this->once())
  99. ->method('createKeyPair')
  100. ->willReturn(false);
  101. $this->assertFalse($this->instance->enableAdminRecovery('password'));
  102. }
  103. public function testChangeRecoveryKeyPasswordSuccessful(): void {
  104. $this->assertFalse($this->instance->changeRecoveryKeyPassword('password',
  105. 'passwordOld'));
  106. $this->keyManagerMock->expects($this->once())
  107. ->method('getSystemPrivateKey');
  108. $this->cryptMock->expects($this->once())
  109. ->method('decryptPrivateKey');
  110. $this->cryptMock->expects($this->once())
  111. ->method('encryptPrivateKey')
  112. ->willReturn(true);
  113. $this->assertTrue($this->instance->changeRecoveryKeyPassword('password',
  114. 'passwordOld'));
  115. }
  116. public function testChangeRecoveryKeyPasswordCouldNotDecryptPrivateRecoveryKey(): void {
  117. $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
  118. $this->keyManagerMock->expects($this->once())
  119. ->method('getSystemPrivateKey');
  120. $this->cryptMock->expects($this->once())
  121. ->method('decryptPrivateKey')
  122. ->willReturn(false);
  123. $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
  124. }
  125. public function testDisableAdminRecovery(): void {
  126. $this->keyManagerMock->expects($this->exactly(2))
  127. ->method('checkRecoveryPassword')
  128. ->willReturnOnConsecutiveCalls(true, false);
  129. $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
  130. $this->assertTrue($this->instance->disableAdminRecovery('password'));
  131. $this->assertEquals(0, self::$tempStorage['recoveryAdminEnabled']);
  132. $this->assertFalse($this->instance->disableAdminRecovery('password'));
  133. }
  134. public function testIsRecoveryEnabledForUser(): void {
  135. $this->configMock->expects($this->exactly(2))
  136. ->method('getUserValue')
  137. ->willReturnOnConsecutiveCalls('1', '0');
  138. $this->assertTrue($this->instance->isRecoveryEnabledForUser());
  139. $this->assertFalse($this->instance->isRecoveryEnabledForUser('admin'));
  140. }
  141. public function testIsRecoveryKeyEnabled(): void {
  142. $this->assertFalse($this->instance->isRecoveryKeyEnabled());
  143. self::$tempStorage['recoveryAdminEnabled'] = '1';
  144. $this->assertTrue($this->instance->isRecoveryKeyEnabled());
  145. }
  146. public function testSetRecoveryFolderForUser(): void {
  147. $this->viewMock->expects($this->exactly(2))
  148. ->method('getDirectoryContent')
  149. ->willReturn([]);
  150. $this->assertTrue($this->instance->setRecoveryForUser(0));
  151. $this->assertTrue($this->instance->setRecoveryForUser('1'));
  152. }
  153. public function testRecoverUserFiles(): void {
  154. $this->viewMock->expects($this->once())
  155. ->method('getDirectoryContent')
  156. ->willReturn([]);
  157. $this->cryptMock->expects($this->once())
  158. ->method('decryptPrivateKey')
  159. ->willReturn('privateKey');
  160. $this->instance->recoverUsersFiles('password', 'admin');
  161. $this->addToAssertionCount(1);
  162. }
  163. public function testRecoverFile(): void {
  164. $this->keyManagerMock->expects($this->once())
  165. ->method('getEncryptedFileKey')
  166. ->willReturn(true);
  167. $this->keyManagerMock->expects($this->once())
  168. ->method('getShareKey')
  169. ->willReturn(true);
  170. $this->cryptMock->expects($this->once())
  171. ->method('multiKeyDecryptLegacy')
  172. ->willReturn('multiKeyDecryptLegacyResult');
  173. $this->fileMock->expects($this->once())
  174. ->method('getAccessList')
  175. ->willReturn(['users' => ['admin']]);
  176. $this->keyManagerMock->expects($this->once())
  177. ->method('getPublicKey')
  178. ->willReturn('publicKey');
  179. $this->keyManagerMock->expects($this->once())
  180. ->method('addSystemKeys')
  181. ->with($this->anything(), $this->anything(), $this->equalTo('admin'))
  182. ->willReturn(['admin' => 'publicKey']);
  183. $this->cryptMock->expects($this->once())
  184. ->method('multiKeyEncrypt')
  185. ->willReturn(['admin' => 'shareKey']);
  186. $this->keyManagerMock->expects($this->once())
  187. ->method('deleteLegacyFileKey');
  188. $this->keyManagerMock->expects($this->once())
  189. ->method('setShareKey');
  190. $this->assertNull(self::invokePrivate($this->instance,
  191. 'recoverFile',
  192. ['/', 'testkey', 'admin']));
  193. }
  194. protected function setUp(): void {
  195. parent::setUp();
  196. $this->user = $this->createMock(IUser::class);
  197. $this->user->expects($this->any())
  198. ->method('getUID')
  199. ->willReturn('admin');
  200. $this->userSessionMock = $this->createMock(IUserSession::class);
  201. $this->userSessionMock->expects($this->any())
  202. ->method('getUser')
  203. ->willReturn($this->user);
  204. $this->userSessionMock->expects($this->any())
  205. ->method('isLoggedIn')
  206. ->willReturn(true);
  207. $this->cryptMock = $this->getMockBuilder(Crypt::class)->disableOriginalConstructor()->getMock();
  208. $this->keyManagerMock = $this->getMockBuilder(KeyManager::class)->disableOriginalConstructor()->getMock();
  209. $this->configMock = $this->createMock(IConfig::class);
  210. $this->fileMock = $this->createMock(IFile::class);
  211. $this->viewMock = $this->createMock(View::class);
  212. $this->configMock->expects($this->any())
  213. ->method('setAppValue')
  214. ->willReturnCallback([$this, 'setValueTester']);
  215. $this->configMock->expects($this->any())
  216. ->method('getAppValue')
  217. ->willReturnCallback([$this, 'getValueTester']);
  218. $this->instance = new Recovery($this->userSessionMock,
  219. $this->cryptMock,
  220. $this->keyManagerMock,
  221. $this->configMock,
  222. $this->fileMock,
  223. $this->viewMock);
  224. }
  225. /**
  226. * @param $app
  227. * @param $key
  228. * @param $value
  229. */
  230. public function setValueTester($app, $key, $value) {
  231. self::$tempStorage[$key] = $value;
  232. }
  233. /**
  234. * @param $key
  235. */
  236. public function removeValueTester($key) {
  237. unset(self::$tempStorage[$key]);
  238. }
  239. /**
  240. * @param $app
  241. * @param $key
  242. * @return mixed
  243. */
  244. public function getValueTester($app, $key) {
  245. if (!empty(self::$tempStorage[$key])) {
  246. return self::$tempStorage[$key];
  247. }
  248. return null;
  249. }
  250. }