/** * @medium */ function testRecursiveDelShareKeys() { // generate filename $filename = '/tmp-' . time() . '.txt'; // create folder structure $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1/subfolder'); $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1/subfolder/subsubfolder'); // enable encryption proxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = true; // save file with content $cryptedFile = file_put_contents('crypt:///' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1/subfolder/subsubfolder' . $filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile)); // change encryption proxy to previous state \OC_FileProxy::$enabled = $proxyStatus; // recursive delete keys Encryption\Keymanager::delShareKey($this->view, array('admin'), '/folder1/'); // check if share key not exists $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/folder1/subfolder/subsubfolder/' . $filename . '.admin.shareKey')); // enable encryption proxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = true; // cleanup $this->view->unlink('/admin/files/folder1'); // change encryption proxy to previous state \OC_FileProxy::$enabled = $proxyStatus; }
public function setUp() { //set testing key $_SESSION['enckey'] = md5(time()); //clear all proxies and hooks so we can do clean testing OC_FileProxy::clearProxies(); OC_Hook::clear('OC_Filesystem'); //enable only the encryption hook OC_FileProxy::register(new OC_FileProxy_Encryption()); //set up temporary storage OC_Filesystem::clearMounts(); OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); //set up the users home folder in the temp storage $rootView = new OC_FilesystemView(''); $rootView->mkdir('/' . OC_User::getUser()); $rootView->mkdir('/' . OC_User::getUser() . '/files'); }
public function setUp() { $this->oldConfig = OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true'); OCP\Config::setAppValue('files_encryption', 'enable_encryption', 'true'); $this->oldKey = isset($_SESSION['enckey']) ? $_SESSION['enckey'] : null; //set testing key $_SESSION['enckey'] = md5(time()); //clear all proxies and hooks so we can do clean testing OC_FileProxy::clearProxies(); OC_Hook::clear('OC_Filesystem'); //enable only the encryption hook OC_FileProxy::register(new OC_FileProxy_Encryption()); //set up temporary storage OC_Filesystem::clearMounts(); OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); //set up the users home folder in the temp storage $rootView = new OC_FilesystemView(''); $rootView->mkdir('/' . OC_User::getUser()); $rootView->mkdir('/' . OC_User::getUser() . '/files'); }
/** * @large */ function testRecoveryForUser() { $this->markTestIncomplete('This test drives Jenkins crazy - "Cannot modify header information - headers already sent" - line 811'); // login as admin \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1); \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123'); $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); // login as user2 \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2); $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(1)); // create folder structure $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1); $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder); $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); // save file with content $cryptedFile1 = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); $this->assertTrue(is_int($cryptedFile2)); // check if share key for user and recovery exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // login as admin \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1); // change password \OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123'); // login as user2 \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test'); // get file contents $retrievedCryptedFile1 = file_get_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename); $retrievedCryptedFile2 = file_get_contents('crypt:///' . \Test_Encryption_Share::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->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1); $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->filename); // check if share key for user and recovery exists $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); \OCA\Encryption\Helper::adminDisableRecovery('test123'); $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled')); }
public static function init($login, $password) { $view = new OC_FilesystemView('/'); if (!$view->file_exists('/' . $login)) { $view->mkdir('/' . $login); } OC_FileProxy::$enabled = false; if (!$view->file_exists('/' . $login . '/encryption.key')) { // does key exist? OC_Crypt::createkey($login, $password); } $key = $view->file_get_contents('/' . $login . '/encryption.key'); OC_FileProxy::$enabled = true; $_SESSION['enckey'] = OC_Crypt::decrypt($key, $password); }
protected function getStorage() { if (isset($this->storage)) { return $this->storage; } if (OC_User::isLoggedIn()) { $subdir = 'cache'; $view = new OC_FilesystemView('/' . OC_User::getUser()); if (!$view->file_exists($subdir)) { $view->mkdir($subdir); } $this->storage = new OC_FilesystemView('/' . OC_User::getUser() . '/' . $subdir); return $this->storage; } else { OC_Log::write('core', 'Can\'t get cache storage, user not logged in', OC_Log::ERROR); return false; } }
public function setUp() { //clear all proxies and hooks so we can do clean testing OC_FileProxy::clearProxies(); OC_Hook::clear('OC_Filesystem'); //enable only the encryption hook if needed if (OC_App::isEnabled('files_encryption')) { OC_FileProxy::register(new OC_FileProxy_Encryption()); } //set up temporary storage OC_Filesystem::clearMounts(); OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); OC_User::clearBackends(); OC_User::useBackend(new OC_User_Dummy()); //login OC_User::createUser('test', 'test'); $this->user = OC_User::getUser(); OC_User::setUserId('test'); //set up the users dir $rootView = new OC_FilesystemView(''); $rootView->mkdir('/test'); $this->instance = new OC_Cache_File(); }
/** * @brief if session is started, check if ownCloud key pair is set up, if not create it * @param \OC_FilesystemView $view * * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ public function __construct($view) { $this->view = $view; if (!$this->view->is_dir('owncloud_private_key')) { $this->view->mkdir('owncloud_private_key'); } $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); if ($publicShareKeyId === null) { $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); } if (!$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key") || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key")) { $keypair = Crypt::createKeypair(); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Save public key if (!$view->is_dir('/public-keys')) { $view->mkdir('/public-keys'); } $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); // Encrypt private key empty passphrase $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); // Save private key $this->view->file_put_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); \OC_FileProxy::$enabled = $proxyStatus; } if (\OCA\Encryption\Helper::isPublicAccess()) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key'); $privateKey = Crypt::decryptPrivateKey($encryptedKey, ''); $this->setPublicSharePrivateKey($privateKey); \OC_FileProxy::$enabled = $proxyStatus; } }
function testDelAllShareKeysFile() { $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1/existingFile.txt', 'data'); // create folder structure for some dummy share key files $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1'); // create some dummy share keys for the existing file $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user1.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user2.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user3.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey', 'data'); // create some dummy share keys for a non-existing file $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user1.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user2.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user3.shareKey', 'data'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey', 'data'); // try to del all share keys from a existing file, should fail because the file still exists $result = Encryption\Keymanager::delAllShareKeys($this->view, Test_Encryption_Keymanager::TEST_USER, 'folder1/existingFile.txt'); $this->assertFalse($result); // check if share keys still exists $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user1.shareKey')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user2.shareKey')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/existingFile.txt.user3.shareKey')); // try to del all share keys from file, should succeed because the does not exist any more $result2 = Encryption\Keymanager::delAllShareKeys($this->view, Test_Encryption_Keymanager::TEST_USER, 'folder1/nonexistingFile.txt'); $this->assertTrue($result2); // check if share keys are really gone $this->assertFalse($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey')); // check that it only deleted keys or users who had access, others remain $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user1.shareKey')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user2.shareKey')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/share-keys/folder1/nonexistingFile.txt.user3.shareKey')); // cleanup $this->view->deleteAll('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); }
/** * @large */ function testEncryptLegacyFiles() { \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER); $userView = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER); $view = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files'); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey); $userView->file_put_contents('/encryption.key', $encryptionKeyContent); $legacyEncryptedData = file_get_contents($this->legacyEncryptedData); $view->mkdir('/test/'); $view->mkdir('/test/subtest/'); $view->file_put_contents('/test/subtest/legacy-encrypted-text.txt', $legacyEncryptedData); $fileInfo = $view->getFileInfo('/test/subtest/legacy-encrypted-text.txt'); $fileInfo['encrypted'] = true; $view->putFileInfo('/test/subtest/legacy-encrypted-text.txt', $fileInfo); \OC_FileProxy::$enabled = $proxyStatus; $params['uid'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER; $params['password'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER; $util = new Encryption\Util($this->view, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER); $this->setMigrationStatus(0, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER); $this->assertTrue(OCA\Encryption\Hooks::login($params)); $this->assertEquals($this->legacyKey, \OC::$session->get('legacyKey')); $files = $util->findEncFiles('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files/'); $this->assertTrue(is_array($files)); $found = false; foreach ($files['encrypted'] as $encryptedFile) { if ($encryptedFile['name'] === 'legacy-encrypted-text.txt') { $found = true; break; } } $this->assertTrue($found); }
/** * @param string $appid * @return OC_FilesystemView */ public static function getStorage($appid) { if (OC_App::isEnabled($appid)) { //sanity check if (OC_User::isLoggedIn()) { $view = new OC_FilesystemView('/' . OC_User::getUser()); if (!$view->file_exists($appid)) { $view->mkdir($appid); } return new OC_FilesystemView('/' . OC_User::getUser() . '/' . $appid); } else { OC_Log::write('core', 'Can\'t get app storage, app, user not logged in', OC_Log::ERROR); return false; } } else { OC_Log::write('core', 'Can\'t get app storage, app ' . $appid . ' not enabled', OC_Log::ERROR); return false; } }
/** * @brief Make preparations to vars and filesystem for saving a keyfile */ public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) { $targetPath = ltrim($path, '/'); $path_parts = pathinfo($targetPath); // If the file resides within a subdirectory, create it if (isset($path_parts['dirname']) && !$view->file_exists($basePath . '/' . $path_parts['dirname'])) { $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); $dir = ''; foreach ($sub_dirs as $sub_dir) { $dir .= '/' . $sub_dir; if (!$view->is_dir($dir)) { $view->mkdir($dir); } } } return $targetPath; }
<?php OCP\JSON::checkAppEnabled('files_external'); if (!($filename = $_FILES['rootcert_import']['name'])) { header("Location: settings/personal.php"); exit; } $fh = fopen($_FILES['rootcert_import']['tmp_name'], 'r'); $data = fread($fh, filesize($_FILES['rootcert_import']['tmp_name'])); fclose($fh); $filename = $_FILES['rootcert_import']['name']; $view = new \OC_FilesystemView('/' . \OCP\User::getUser() . '/files_external/uploads'); if (!$view->file_exists('')) { $view->mkdir(''); } $isValid = openssl_pkey_get_public($data); //maybe it was just the wrong file format, try to convert it... if ($isValid == false) { $data = chunk_split(base64_encode($data), 64, "\n"); $data = "-----BEGIN CERTIFICATE-----\n" . $data . "-----END CERTIFICATE-----\n"; $isValid = openssl_pkey_get_public($data); } // add the certificate if it could be verified if ($isValid) { $view->file_put_contents($filename, $data); OC_Mount_Config::createCertificateBundle(); } else { OCP\Util::writeLog("files_external", "Couldn't import SSL root certificate ({$filename}), allowed formats: PEM and DER", OCP\Util::WARN); } header("Location: settings/personal.php"); exit;
public function testHooks() { if (OC_Filesystem::getView()) { $user = OC_User::getUser(); } else { $user = uniqid(); OC_Filesystem::init('/' . $user . '/files'); } OC_Hook::clear('OC_Filesystem'); OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); $rootView = new OC_FilesystemView(''); $rootView->mkdir('/' . $user); $rootView->mkdir('/' . $user . '/files'); OC_Filesystem::file_put_contents('/foo', 'foo'); OC_Filesystem::mkdir('/bar'); OC_Filesystem::file_put_contents('/bar//foo', 'foo'); $tmpFile = OC_Helper::tmpFile(); file_put_contents($tmpFile, 'foo'); $fh = fopen($tmpFile, 'r'); OC_Filesystem::file_put_contents('/bar//foo', $fh); }
/** * store a new version of a file. */ public function store($filename) { if (\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED) == 'true') { list($uid, $filename) = self::getUidAndFilename($filename); $files_view = new \OC_FilesystemView('/' . $uid . '/files'); $users_view = new \OC_FilesystemView('/' . $uid); //check if source file already exist as version to avoid recursions. // todo does this check work? if ($users_view->file_exists($filename)) { return false; } // check if filename is a directory if ($files_view->is_dir($filename)) { return false; } // check filetype blacklist $blacklist = explode(' ', \OCP\Config::getSystemValue('files_versionsblacklist', Storage::DEFAULTBLACKLIST)); foreach ($blacklist as $bl) { $parts = explode('.', $filename); $ext = end($parts); if (strtolower($ext) == $bl) { return false; } } // we should have a source file to work with if (!$files_view->file_exists($filename)) { return false; } // check filesize if ($files_view->filesize($filename) > \OCP\Config::getSystemValue('files_versionsmaxfilesize', Storage::DEFAULTMAXFILESIZE)) { return false; } // check mininterval if the file is being modified by the owner (all shared files should be versioned despite mininterval) if ($uid == \OCP\User::getUser()) { $versions_fileview = new \OC_FilesystemView('/' . $uid . '/files_versions'); $versionsFolderName = \OCP\Config::getSystemValue('datadirectory') . $versions_fileview->getAbsolutePath(''); $matches = glob($versionsFolderName . '/' . $filename . '.v*'); sort($matches); $parts = explode('.v', end($matches)); if (end($parts) + Storage::DEFAULTMININTERVAL > time()) { return false; } } // create all parent folders $dirname = dirname($filename); if (!$users_view->file_exists('/files_versions/' . $dirname)) { $users_view->mkdir('/files_versions/' . $dirname, 0700, true); } // store a new version of a file $users_view->copy('files' . $filename, 'files_versions' . $filename . '.v' . time()); // expire old revisions if necessary Storage::expire($filename); } }
/** * Share an item, adds an entry into the database * @param $source The source location of the item * @param $uid_shared_with The user or group to share the item with * @param $permissions The permissions, use the constants WRITE and DELETE */ public function __construct($source, $uid_shared_with, $permissions) { $uid_owner = OCP\USER::getUser(); $query = OCP\DB::prepare("INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)"); // Check if this is a reshare and use the original source if ($result = OC_Share::getSource($source)) { $source = $result; } if ($uid_shared_with == self::PUBLICLINK) { $token = sha1("{$uid_shared_with}-{$source}"); $query->execute(array($uid_owner, self::PUBLICLINK, $source, $token, $permissions)); $this->token = $token; } else { if (OC_Group::groupExists($uid_shared_with)) { $gid = $uid_shared_with; $uid_shared_with = OC_Group::usersInGroup($gid); // Remove the owner from the list of users in the group $uid_shared_with = array_diff($uid_shared_with, array($uid_owner)); } else { if (OCP\User::userExists($uid_shared_with)) { $userGroups = OC_Group::getUserGroups($uid_owner); // Check if the user is in one of the owner's groups foreach ($userGroups as $group) { if ($inGroup = OC_Group::inGroup($uid_shared_with, $group)) { $gid = null; $uid_shared_with = array($uid_shared_with); break; } } if (!$inGroup) { throw new Exception("You can't share with " . $uid_shared_with); } } else { throw new Exception($uid_shared_with . " is not a user"); } } foreach ($uid_shared_with as $uid) { // Check if this item is already shared with the user $checkSource = OCP\DB::prepare("SELECT source FROM *PREFIX*sharing WHERE source = ? AND uid_shared_with " . self::getUsersAndGroups($uid, false)); $resultCheckSource = $checkSource->execute(array($source))->fetchAll(); // TODO Check if the source is inside a folder if (count($resultCheckSource) > 0) { if (!isset($gid)) { throw new Exception("This item is already shared with " . $uid); } else { // Skip this user if sharing with a group continue; } } // Check if the target already exists for the user, if it does append a number to the name $sharedFolder = '/' . $uid . '/files/Shared'; $target = $sharedFolder . "/" . basename($source); $checkTarget = OCP\DB::prepare("SELECT source FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with " . self::getUsersAndGroups($uid, false) . " LIMIT 1"); $result = $checkTarget->execute(array($target))->fetchAll(); if (count($result) > 0) { if ($pos = strrpos($target, ".")) { $name = substr($target, 0, $pos); $ext = substr($target, $pos); } else { $name = $target; $ext = ""; } $counter = 1; while (count($result) > 0) { $target = $name . "_" . $counter . $ext; $result = $checkTarget->execute(array($target))->fetchAll(); $counter++; } } if (isset($gid)) { $uid = $uid . "@" . $gid; } $query->execute(array($uid_owner, $uid, $source, $target, $permissions)); // Update mtime of shared folder to invoke a file cache rescan $rootView = new OC_FilesystemView('/'); if (!$rootView->is_dir($sharedFolder)) { if (!$rootView->is_dir('/' . $uid . '/files')) { OC_Util::tearDownFS(); OC_Util::setupFS($uid); OC_Util::tearDownFS(); } $rootView->mkdir($sharedFolder); } $rootView->touch($sharedFolder); } } }
/** * @large */ function testRecoveryForUser() { // login as admin \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1); $result = \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123'); $this->assertTrue($result); $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); // login as user2 \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2); $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \Test_Encryption_Share::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('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1); $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder); $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); // save file with content $cryptedFile1 = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); $this->assertTrue(is_int($cryptedFile2)); // check if share key for user and recovery exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // login as admin \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1); // change password \OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123'); $params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'password' => 'test', 'recoveryPassword' => 'test123'); \OCA\Encryption\Hooks::setPassphrase($params); // login as user2 \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test'); // get file contents $retrievedCryptedFile1 = file_get_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename); $retrievedCryptedFile2 = file_get_contents('crypt:///' . \Test_Encryption_Share::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('/' . \Test_Encryption_Share::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('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // disable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); \OCA\Encryption\Helper::adminDisableRecovery('test123'); $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled')); //clean up, reset passwords \OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test123'); $params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'password' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'recoveryPassword' => 'test123'); \OCA\Encryption\Hooks::setPassphrase($params); }
/** * @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing * @param array with oldpath and newpath * * This function is connected to the rename signal of OC_Filesystem and adjust the name and location * of the stored versions along the actual file */ public static function postRename($params) { if (\OCP\App::isEnabled('files_encryption') === false) { return true; } // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView('/'); $session = new \OCA\Encryption\Session($view); $userId = \OCP\User::getUser(); $util = new Util($view, $userId); // Format paths to be relative to user files dir if ($util->isSystemWideMountPoint($params['oldpath'])) { $baseDir = 'files_encryption/'; $oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath']; } else { $baseDir = $userId . '/' . 'files_encryption/'; $oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath']; } if ($util->isSystemWideMountPoint($params['newpath'])) { $newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath']; } else { $newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath']; } // add key ext if this is not an folder if (!$view->is_dir($oldKeyfilePath)) { $oldKeyfilePath .= '.key'; $newKeyfilePath .= '.key'; // handle share-keys $localKeyPath = $view->getLocalFile($baseDir . 'share-keys/' . $params['oldpath']); $escapedPath = Helper::escapeGlobPattern($localKeyPath); $matches = glob($escapedPath . '*.shareKey'); foreach ($matches as $src) { $dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src)); // create destination folder if not exists if (!file_exists(dirname($dst))) { mkdir(dirname($dst), 0750, true); } rename($src, $dst); } } else { // handle share-keys folders $oldShareKeyfilePath = $baseDir . 'share-keys/' . $params['oldpath']; $newShareKeyfilePath = $baseDir . 'share-keys/' . $params['newpath']; // create destination folder if not exists if (!$view->file_exists(dirname($newShareKeyfilePath))) { $view->mkdir(dirname($newShareKeyfilePath), 0750, true); } $view->rename($oldShareKeyfilePath, $newShareKeyfilePath); } // Rename keyfile so it isn't orphaned if ($view->file_exists($oldKeyfilePath)) { // create destination folder if not exists if (!$view->file_exists(dirname($newKeyfilePath))) { $view->mkdir(dirname($newKeyfilePath), 0750, true); } $view->rename($oldKeyfilePath, $newKeyfilePath); } // build the path to the file $newPath = '/' . $userId . '/files' . $params['newpath']; $newPathRelative = $params['newpath']; if ($util->fixFileSize($newPath)) { // get sharing app state $sharingEnabled = \OCP\Share::isEnabled(); // get users $usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative); // update sharing-keys $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative); } \OC_FileProxy::$enabled = $proxyStatus; }