util.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. require_once realpath(dirname(__FILE__) . '/../../../lib/base.php');
  9. require_once realpath(dirname(__FILE__) . '/../lib/crypt.php');
  10. require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php');
  11. require_once realpath(dirname(__FILE__) . '/../lib/proxy.php');
  12. require_once realpath(dirname(__FILE__) . '/../lib/stream.php');
  13. require_once realpath(dirname(__FILE__) . '/../lib/util.php');
  14. require_once realpath(dirname(__FILE__) . '/../appinfo/app.php');
  15. use OCA\Encryption;
  16. /**
  17. * Class Test_Encryption_Util
  18. */
  19. class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
  20. const TEST_ENCRYPTION_UTIL_USER1 = "test-util-user1";
  21. const TEST_ENCRYPTION_UTIL_LEGACY_USER = "test-legacy-user";
  22. public $userId;
  23. public $encryptionDir;
  24. public $publicKeyDir;
  25. public $pass;
  26. /**
  27. * @var OC_FilesystemView
  28. */
  29. public $view;
  30. public $keyfilesPath;
  31. public $publicKeyPath;
  32. public $privateKeyPath;
  33. /**
  34. * @var \OCA\Encryption\Util
  35. */
  36. public $util;
  37. public $dataShort;
  38. public $legacyEncryptedData;
  39. public $legacyEncryptedDataKey;
  40. public $legacyKey;
  41. public $stateFilesTrashbin;
  42. public static function setUpBeforeClass() {
  43. // reset backend
  44. \OC_User::clearBackends();
  45. \OC_User::useBackend('database');
  46. // Filesystem related hooks
  47. \OCA\Encryption\Helper::registerFilesystemHooks();
  48. // clear and register hooks
  49. \OC_FileProxy::clearProxies();
  50. \OC_FileProxy::register(new OCA\Encryption\Proxy());
  51. // create test user
  52. \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, true);
  53. \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER, true);
  54. }
  55. function setUp() {
  56. \OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
  57. $this->userId = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
  58. $this->pass = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
  59. // set content for encrypting / decrypting in tests
  60. $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php');
  61. $this->dataShort = 'hats';
  62. $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php'));
  63. $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt');
  64. $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt');
  65. $this->legacyEncryptedDataKey = realpath(dirname(__FILE__) . '/encryption.key');
  66. $this->legacyKey = "30943623843030686906\0\0\0\0";
  67. $keypair = Encryption\Crypt::createKeypair();
  68. $this->genPublicKey = $keypair['publicKey'];
  69. $this->genPrivateKey = $keypair['privateKey'];
  70. $this->publicKeyDir = '/' . 'public-keys';
  71. $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
  72. $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
  73. $this->publicKeyPath =
  74. $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
  75. $this->privateKeyPath =
  76. $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
  77. $this->view = new \OC_FilesystemView('/');
  78. $this->util = new Encryption\Util($this->view, $this->userId);
  79. // remember files_trashbin state
  80. $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
  81. // we don't want to tests with app files_trashbin enabled
  82. \OC_App::disable('files_trashbin');
  83. }
  84. function tearDown() {
  85. // reset app files_trashbin
  86. if ($this->stateFilesTrashbin) {
  87. OC_App::enable('files_trashbin');
  88. }
  89. else {
  90. OC_App::disable('files_trashbin');
  91. }
  92. }
  93. public static function tearDownAfterClass() {
  94. // cleanup test user
  95. \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
  96. \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  97. }
  98. /**
  99. * @medium
  100. * @brief test that paths set during User construction are correct
  101. */
  102. function testKeyPaths() {
  103. $util = new Encryption\Util($this->view, $this->userId);
  104. $this->assertEquals($this->publicKeyDir, $util->getPath('publicKeyDir'));
  105. $this->assertEquals($this->encryptionDir, $util->getPath('encryptionDir'));
  106. $this->assertEquals($this->keyfilesPath, $util->getPath('keyfilesPath'));
  107. $this->assertEquals($this->publicKeyPath, $util->getPath('publicKeyPath'));
  108. $this->assertEquals($this->privateKeyPath, $util->getPath('privateKeyPath'));
  109. }
  110. /**
  111. * @medium
  112. * @brief test setup of encryption directories
  113. */
  114. function testSetupServerSide() {
  115. $this->assertEquals(true, $this->util->setupServerSide($this->pass));
  116. }
  117. /**
  118. * @medium
  119. * @brief test checking whether account is ready for encryption,
  120. */
  121. function testUserIsReady() {
  122. $this->assertEquals(true, $this->util->ready());
  123. }
  124. /**
  125. * @brief test checking whether account is not ready for encryption,
  126. */
  127. // function testUserIsNotReady() {
  128. // $this->view->unlink($this->publicKeyDir);
  129. //
  130. // $params['uid'] = $this->userId;
  131. // $params['password'] = $this->pass;
  132. // $this->assertFalse(OCA\Encryption\Hooks::login($params));
  133. //
  134. // $this->view->unlink($this->privateKeyPath);
  135. // }
  136. /**
  137. * @medium
  138. * @brief test checking whether account is not ready for encryption,
  139. */
  140. function testIsLegacyUser() {
  141. \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  142. $userView = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  143. // Disable encryption proxy to prevent recursive calls
  144. $proxyStatus = \OC_FileProxy::$enabled;
  145. \OC_FileProxy::$enabled = false;
  146. $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey);
  147. $userView->file_put_contents('/encryption.key', $encryptionKeyContent);
  148. \OC_FileProxy::$enabled = $proxyStatus;
  149. $params['uid'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
  150. $params['password'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
  151. $this->setMigrationStatus(0, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  152. $this->assertTrue(OCA\Encryption\Hooks::login($params));
  153. $this->assertEquals($this->legacyKey, \OC::$session->get('legacyKey'));
  154. }
  155. /**
  156. * @medium
  157. */
  158. function testRecoveryEnabledForUser() {
  159. $util = new Encryption\Util($this->view, $this->userId);
  160. // Record the value so we can return it to it's original state later
  161. $enabled = $util->recoveryEnabledForUser();
  162. $this->assertTrue($util->setRecoveryForUser(1));
  163. $this->assertEquals(1, $util->recoveryEnabledForUser());
  164. $this->assertTrue($util->setRecoveryForUser(0));
  165. $this->assertEquals(0, $util->recoveryEnabledForUser());
  166. // Return the setting to it's previous state
  167. $this->assertTrue($util->setRecoveryForUser($enabled));
  168. }
  169. /**
  170. * @medium
  171. */
  172. function testGetUidAndFilename() {
  173. \OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
  174. $filename = '/tmp-' . time() . '.test';
  175. // Disable encryption proxy to prevent recursive calls
  176. $proxyStatus = \OC_FileProxy::$enabled;
  177. \OC_FileProxy::$enabled = false;
  178. $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
  179. // Re-enable proxy - our work is done
  180. \OC_FileProxy::$enabled = $proxyStatus;
  181. $util = new Encryption\Util($this->view, $this->userId);
  182. list($fileOwnerUid, $file) = $util->getUidAndFilename($filename);
  183. $this->assertEquals(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, $fileOwnerUid);
  184. $this->assertEquals($file, $filename);
  185. $this->view->unlink($this->userId . '/files/' . $filename);
  186. }
  187. /**
  188. * @medium
  189. */
  190. function testIsSharedPath() {
  191. $sharedPath = '/user1/files/Shared/test';
  192. $path = '/user1/files/test';
  193. $this->assertTrue($this->util->isSharedPath($sharedPath));
  194. $this->assertFalse($this->util->isSharedPath($path));
  195. }
  196. /**
  197. * @large
  198. */
  199. function testEncryptLegacyFiles() {
  200. \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  201. $userView = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  202. $view = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files');
  203. // Disable encryption proxy to prevent recursive calls
  204. $proxyStatus = \OC_FileProxy::$enabled;
  205. \OC_FileProxy::$enabled = false;
  206. $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey);
  207. $userView->file_put_contents('/encryption.key', $encryptionKeyContent);
  208. $legacyEncryptedData = file_get_contents($this->legacyEncryptedData);
  209. $view->mkdir('/test/');
  210. $view->mkdir('/test/subtest/');
  211. $view->file_put_contents('/test/subtest/legacy-encrypted-text.txt', $legacyEncryptedData);
  212. $fileInfo = $view->getFileInfo('/test/subtest/legacy-encrypted-text.txt');
  213. $fileInfo['encrypted'] = true;
  214. $view->putFileInfo('/test/subtest/legacy-encrypted-text.txt', $fileInfo);
  215. \OC_FileProxy::$enabled = $proxyStatus;
  216. $params['uid'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
  217. $params['password'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
  218. $util = new Encryption\Util($this->view, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  219. $this->setMigrationStatus(0, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
  220. $this->assertTrue(OCA\Encryption\Hooks::login($params));
  221. $this->assertEquals($this->legacyKey, \OC::$session->get('legacyKey'));
  222. $files = $util->findEncFiles('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files/');
  223. $this->assertTrue(is_array($files));
  224. $found = false;
  225. foreach ($files['encrypted'] as $encryptedFile) {
  226. if ($encryptedFile['name'] === 'legacy-encrypted-text.txt') {
  227. $found = true;
  228. break;
  229. }
  230. }
  231. $this->assertTrue($found);
  232. }
  233. /**
  234. * @param $user
  235. * @param bool $create
  236. * @param bool $password
  237. */
  238. public static function loginHelper($user, $create = false, $password = false) {
  239. if ($create) {
  240. \OC_User::createUser($user, $user);
  241. }
  242. if ($password === false) {
  243. $password = $user;
  244. }
  245. \OC_Util::tearDownFS();
  246. \OC_User::setUserId('');
  247. \OC\Files\Filesystem::tearDown();
  248. \OC_Util::setupFS($user);
  249. \OC_User::setUserId($user);
  250. $params['uid'] = $user;
  251. $params['password'] = $password;
  252. OCA\Encryption\Hooks::login($params);
  253. }
  254. /**
  255. * helper function to set migration status to the right value
  256. * to be able to test the migration path
  257. *
  258. * @param $status needed migration status for test
  259. * @param $user for which user the status should be set
  260. * @return boolean
  261. */
  262. private function setMigrationStatus($status, $user) {
  263. $sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ?';
  264. $args = array(
  265. $status,
  266. $user
  267. );
  268. $query = \OCP\DB::prepare($sql);
  269. if ($query->execute($args)) {
  270. return true;
  271. } else {
  272. return false;
  273. }
  274. }
  275. }