public function setUp() { $this->loginHelper(self::TEST_ENCRYPTION_MIGRATION_USER1); $this->view = new \OC\Files\View(); $this->public_share_key_id = \OCA\Files_Encryption\Helper::getPublicShareKeyId(); $this->recovery_key_id = \OCA\Files_Encryption\Helper::getRecoveryKeyId(); if (\OC_DB::tableExists('encryption_test')) { \OC_DB::dropTable('encryption_test'); } $this->assertTableNotExist('encryption_test'); }
public static function setUpBeforeClass() { parent::setUpBeforeClass(); // reset backend \OC_User::clearBackends(); \OC_User::useBackend('database'); \OCA\Files_Encryption\Helper::registerFilesystemHooks(); \OCA\Files_Encryption\Helper::registerUserHooks(); \OCA\Files_Encryption\Helper::registerShareHooks(); \OC::registerShareHooks(); \OCP\Util::connectHook('OC_Filesystem', 'setup', '\\OC\\Files\\Storage\\Shared', 'setup'); // clear and register hooks \OC_FileProxy::clearProxies(); \OC_FileProxy::register(new \OCA\Files_Encryption\Proxy()); }
/** * Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle * @param boolean $sharingEnabled * @param string $filePath path relativ to current users files folder */ public function getSharingUsersArray($sharingEnabled, $filePath) { $appConfig = \OC::$server->getAppConfig(); // Check if key recovery is enabled if ($appConfig->getValue('files_encryption', 'recoveryAdminEnabled') && $this->recoveryEnabledForUser()) { $recoveryEnabled = true; } else { $recoveryEnabled = false; } // Make sure that a share key is generated for the owner too list($owner, $ownerPath) = $this->getUidAndFilename($filePath); $ownerPath = Helper::stripPartialFileExtension($ownerPath); // always add owner to the list of users with access to the file $userIds = array($owner); if ($sharingEnabled) { // Find out who, if anyone, is sharing the file $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); $userIds = \array_merge($userIds, $result['users']); if ($result['public'] || $result['remote']) { $userIds[] = $this->publicShareKeyId; } } // If recovery is enabled, add the // Admin UID to list of users to share to if ($recoveryEnabled) { // Find recoveryAdmin user ID $recoveryKeyId = $appConfig->getValue('files_encryption', 'recoveryKeyId'); // Add recoveryAdmin to list of users sharing $userIds[] = $recoveryKeyId; } // check if it is a group mount if (\OCP\App::isEnabled("files_external")) { $mounts = \OC_Mount_Config::getSystemMountPoints(); foreach ($mounts as $mount) { if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { $userIds = array_merge($userIds, $this->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups'])); } } } // Remove duplicate UIDs $uniqueUserIds = array_unique($userIds); return $uniqueUserIds; }
$errorMessage = $l->t('Please repeat the new recovery password'); \OCP\JSON::error(array('data' => array('message' => $errorMessage))); exit; } if ($_POST['newPassword'] !== $_POST['confirmPassword']) { $errorMessage = $l->t('Repeated recovery key password does not match the provided recovery key password'); \OCP\JSON::error(array('data' => array('message' => $errorMessage))); exit; } $view = new \OC\Files\View('/'); $util = new \OCA\Files_Encryption\Util(new \OC\Files\View('/'), \OCP\User::getUser()); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $keyId = $util->getRecoveryKeyId(); $encryptedRecoveryKey = \OCA\Files_Encryption\Keymanager::getPrivateSystemKey($keyId); $decryptedRecoveryKey = $encryptedRecoveryKey ? \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedRecoveryKey, $oldPassword) : false; if ($decryptedRecoveryKey) { $cipher = \OCA\Files_Encryption\Helper::getCipher(); $encryptedKey = \OCA\Files_Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword, $cipher); if ($encryptedKey) { \OCA\Files_Encryption\Keymanager::setPrivateSystemKey($encryptedKey, $keyId); $return = true; } } \OC_FileProxy::$enabled = $proxyStatus; // success or failure if ($return) { \OCP\JSON::success(array('data' => array('message' => $l->t('Password successfully changed.')))); } else { \OCP\JSON::error(array('data' => array('message' => $l->t('Could not change the password. Maybe the old password was not correct.')))); }
/** * @dataProvider dataPaths */ function testSplitPath($path, $expected) { $result = Helper::splitPath($path); $this->compareArray($result, $expected); }
/** * @medium * test if stream wrapper can read files outside from the data folder */ function testStreamFromLocalFile() { $filename = '/' . $this->userId . '/files/' . 'tmp-' . $this->getUniqueID() . '.txt'; $tmpFilename = "/tmp/" . $this->getUniqueID() . ".txt"; // write an encrypted file $cryptedFile = $this->view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); // create a copy outside of the data folder in /tmp $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $encryptedContent = $this->view->file_get_contents($filename); \OC_FileProxy::$enabled = $proxyStatus; file_put_contents($tmpFilename, $encryptedContent); \OCA\Files_Encryption\Helper::addTmpFileToMapper($tmpFilename, $filename); // try to read the file from /tmp $handle = fopen("crypt://" . $tmpFilename, "r"); $contentFromTmpFile = stream_get_contents($handle); // check if it was successful $this->assertEquals($this->dataShort, $contentFromTmpFile); fclose($handle); // clean up unlink($tmpFilename); $this->view->unlink($filename); }
function testGetUser() { self::setUpUsers(); $path1 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/files/foo/bar.txt"; $path2 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/cache/foo/bar.txt"; $path3 = "/" . self::TEST_ENCRYPTION_HELPER_USER2 . "/thumbnails/foo"; $path4 = "/" . "/" . self::TEST_ENCRYPTION_HELPER_USER1; self::loginHelper(self::TEST_ENCRYPTION_HELPER_USER1); // if we are logged-in every path should return the currently logged-in user $this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, \OCA\Files_Encryption\Helper::getUser($path3)); // now log out self::logoutHelper(); // now we should only get the user from /user/files and user/cache paths $this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, \OCA\Files_Encryption\Helper::getUser($path1)); $this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, \OCA\Files_Encryption\Helper::getUser($path2)); $this->assertFalse(\OCA\Files_Encryption\Helper::getUser($path3)); $this->assertFalse(\OCA\Files_Encryption\Helper::getUser($path4)); // Log-in again self::loginHelper(self::TEST_ENCRYPTION_HELPER_USER1); self::cleanUpUsers(); }
/** * @large */ function testRecoveryForUser() { // login as admin self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1); $result = \OCA\Files_Encryption\Helper::adminEnableRecovery(null, 'test123'); $this->assertTrue($result); $recoveryKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryKeyId'); // login as user2 self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER2); $util = new \OCA\Files_Encryption\Util(new \OC\Files\View('/'), self::TEST_ENCRYPTION_SHARE_USER2); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(1)); // add recovery keys for existing files (e.g. the auto-generated welcome.txt) $util->addRecoveryKeys(); // create folder structure $this->view->mkdir('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1); $this->view->mkdir('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder); $this->view->mkdir('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); // save file with content $cryptedFile1 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertInternalType('int', $cryptedFile1); $this->assertInternalType('int', $cryptedFile2); // check if share key for user and recovery exists $this->assertTrue($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->filename . '/' . $recoveryKeyId . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '/' . $recoveryKeyId . '.shareKey')); // login as admin self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1); // change password \OC_User::setPassword(self::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123'); $params = array('uid' => self::TEST_ENCRYPTION_SHARE_USER2, 'password' => 'test', 'recoveryPassword' => 'test123'); \OCA\Files_Encryption\Hooks::setPassphrase($params); // login as user2 self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER2, false, 'test'); // get file contents $retrievedCryptedFile1 = file_get_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename); $retrievedCryptedFile2 = file_get_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if data is the same as we previously written $this->assertEquals($this->dataShort, $retrievedCryptedFile1); $this->assertEquals($this->dataShort, $retrievedCryptedFile2); // cleanup $this->view->chroot('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/'); $this->view->unlink($this->folder1); $this->view->unlink($this->filename); $this->view->chroot('/'); // check if share key for user and recovery exists $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->filename . '/' . $recoveryKeyId . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '/' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); \OCA\Files_Encryption\Helper::adminDisableRecovery('test123'); $this->assertEquals(0, \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled')); //clean up, reset passwords \OC_User::setPassword(self::TEST_ENCRYPTION_SHARE_USER2, self::TEST_ENCRYPTION_SHARE_USER2, 'test123'); $params = array('uid' => self::TEST_ENCRYPTION_SHARE_USER2, 'password' => self::TEST_ENCRYPTION_SHARE_USER2, 'recoveryPassword' => 'test123'); \OCA\Files_Encryption\Hooks::setPassphrase($params); }
/** * @return bool */ public function stream_close() { $this->flush(); // if there is no valid private key return false if ($this->privateKey === false) { // cleanup if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && !$this->isLocalTmpFile) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ($this->rootView->file_exists($this->rawPath) && $this->size === 0) { fclose($this->handle); $this->rootView->unlink($this->rawPath); } // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } // if private key is not valid redirect user to a error page Helper::redirectToErrorPage($this->session); } if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && $this->isLocalTmpFile === false && $this->size > 0 && $this->unencryptedSize > 0) { // only write keyfiles if it was a new file if ($this->newFile === true) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Fetch user's public key $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->keyId); // Check if OC sharing api is enabled $sharingEnabled = \OCP\Share::isEnabled(); // Get all users sharing the file includes current user $uniqueUserIds = $this->util->getSharingUsersArray($sharingEnabled, $this->relPath); $checkedUserIds = $this->util->filterShareReadyUsers($uniqueUserIds); // Fetch public keys for all sharing users $publicKeys = Keymanager::getPublicKeys($this->rootView, $checkedUserIds['ready']); // Encrypt enc key for all sharing users $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); // Save the new encrypted file key Keymanager::setFileKey($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['data']); // Save the sharekeys Keymanager::setShareKeys($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['keys']); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } // we need to update the file info for the real file, not for the // part file. $path = Helper::stripPartialFileExtension($this->rawPath); $fileInfo = array('mimetype' => $this->rootView->getMimeType($this->rawPath), 'encrypted' => true, 'unencrypted_size' => $this->unencryptedSize); // if we write a part file we also store the unencrypted size for // the part file so that it can be re-used later $this->rootView->putFileInfo($this->rawPath, $fileInfo); if ($path !== $this->rawPath) { $this->rootView->putFileInfo($path, $fileInfo); } } $result = fclose($this->handle); if ($result === false) { \OCP\Util::writeLog('Encryption library', 'Could not close stream, file could be corrupted', \OCP\Util::FATAL); } return $result; }
} if ($_POST['recoveryPassword'] !== $_POST['confirmPassword']) { $errorMessage = $l->t('Repeated recovery key password does not match the provided recovery key password'); \OCP\JSON::error(array('data' => array('message' => $errorMessage))); exit; } // Enable recoveryAdmin $recoveryKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryKeyId'); if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1') { $return = Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']); // Return success or failure if ($return) { $successMessage = $l->t('Recovery key successfully enabled'); } else { $errorMessage = $l->t('Could not disable recovery key. Please check your recovery key password!'); } // Disable recoveryAdmin } elseif (isset($_POST['adminEnableRecovery']) && '0' === $_POST['adminEnableRecovery']) { $return = Helper::adminDisableRecovery($_POST['recoveryPassword']); if ($return) { $successMessage = $l->t('Recovery key successfully disabled'); } else { $errorMessage = $l->t('Could not disable recovery key. Please check your recovery key password!'); } } // Return success or failure if ($return) { \OCP\JSON::success(array('data' => array('message' => $successMessage))); } else { \OCP\JSON::error(array('data' => array('message' => $errorMessage))); }