/** * encrypt files from the given user * * @param string $uid * @param ProgressBar $progress * @param string $userCount */ protected function decryptUsersFiles($uid, ProgressBar $progress, $userCount) { $this->setupUserFS($uid); $directories = array(); $directories[] = '/' . $uid . '/files'; while ($root = array_pop($directories)) { $content = $this->rootView->getDirectoryContent($root); foreach ($content as $file) { $path = $root . '/' . $file['name']; if ($this->rootView->is_dir($path)) { $directories[] = $path; continue; } else { try { $progress->setMessage("decrypt files for user {$userCount}: {$path}"); $progress->advance(); if ($this->decryptFile($path) === false) { $progress->setMessage("decrypt files for user {$userCount}: {$path} (already decrypted)"); $progress->advance(); } } catch (\Exception $e) { if (isset($this->failed[$uid])) { $this->failed[$uid][] = $path; } else { $this->failed[$uid] = [$path]; } } } } } }
/** * @medium * test restore file */ function testRestoreFile() { // generate filename $filename = 'tmp-' . $this->getUniqueID() . '.txt'; $filename2 = $filename . '.backup'; // a second file with similar name // save file with content $cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename2, $this->dataShort); // delete both files \OC\Files\Filesystem::unlink($filename); \OC\Files\Filesystem::unlink($filename2); $trashFiles = $this->view->getDirectoryContent('/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/'); $trashFileSuffix = null; $trashFileSuffix2 = null; // find created file with timestamp foreach ($trashFiles as $file) { if (strpos($file['path'], $filename . '.d') !== false) { $path_parts = pathinfo($file['name']); $trashFileSuffix = $path_parts['extension']; } } // prepare file information $timestamp = str_replace('d', '', $trashFileSuffix); // restore first file $this->assertTrue(\OCA\Files_Trashbin\Trashbin::restore($filename . '.' . $trashFileSuffix, $filename, $timestamp)); // check if file exists $this->assertTrue($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename)); // check if key for admin exists $this->assertTrue($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename . '.key')); // check if share key for admin exists $this->assertTrue($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/' . $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey')); // check that second file was NOT restored $this->assertFalse($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename2)); // check if key for admin exists $this->assertFalse($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename2 . '.key')); // check if share key for admin exists $this->assertFalse($this->view->file_exists( '/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/' . $filename2 . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey')); }
public function run() { $view = new View('/'); $children = $view->getDirectoryContent('/'); foreach ($children as $child) { if ($view->is_dir($child->getPath())) { $thumbnailsFolder = $child->getPath() . '/thumbnails'; if ($view->is_dir($thumbnailsFolder)) { $view->rmdir($thumbnailsFolder); } } } }
/** * recover users files * * @param string $path * @param string $privateKey * @param string $uid */ private function recoverAllFiles($path, $privateKey, $uid) { $dirContent = $this->view->getDirectoryContent($path); foreach ($dirContent as $item) { // Get relative path from encryption/keyfiles $filePath = $item->getPath(); if ($this->view->is_dir($filePath)) { $this->recoverAllFiles($filePath . '/', $privateKey, $uid); } else { $this->recoverFile($filePath, $privateKey, $uid); } } }
/** * collect all files and recover them one by one * @param string $path to look for files keys * @param string $privateKey private recovery key which is used to decrypt the files */ private function recoverAllFiles($path, $privateKey) { $dirContent = $this->view->getDirectoryContent($this->keysPath . '/' . $path); foreach ($dirContent as $item) { // get relative path from files_encryption/keyfiles $filePath = substr($item['path'], strlen('files_encryption/keys')); if ($this->view->is_dir($this->userFilesDir . '/' . $filePath)) { $this->recoverAllFiles($filePath . '/', $privateKey); } else { $this->recoverFile($filePath, $privateKey); } } }
function getBackupPath($extension) { $encPath = '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '/files_encryption'; $encFolderContent = $this->view->getDirectoryContent($encPath); $backupPath = ''; foreach ($encFolderContent as $c) { $name = $c['name']; if (substr($name, 0, strlen('backup.' . $extension)) === 'backup.' . $extension) { $backupPath = $encPath . '/' . $c['name']; break; } } return $backupPath; }
/** * @param \OCP\Files\FileInfo $dir * @param \OC\Files\View $view * @return array */ function getChildInfo($dir, $view) { $children = $view->getDirectoryContent($dir->getPath()); $result = array(); foreach ($children as $child) { $formated = \OCA\Files\Helper::formatFileInfo($child); if ($child->getType() === 'dir') { $formated['children'] = getChildInfo($child, $view); } $formated['mtime'] = $formated['mtime'] / 1000; $result[] = $formated; } return $result; }
/** * Test that the permissions of shared directory are returned correctly */ function testGetDirectoryPermissions() { $contents = $this->secondView->getDirectoryContent('files/shareddir'); $this->assertEquals('subdir', $contents[0]['name']); $this->assertEquals(31, $contents[0]['permissions']); $this->assertEquals('textfile.txt', $contents[1]['name']); // 27 is correct because create is reserved to folders only - requires more unit tests overall to ensure this $this->assertEquals(27, $contents[1]['permissions']); $contents = $this->secondView->getDirectoryContent('files/shareddirrestricted'); $this->assertEquals('subdir', $contents[0]['name']); $this->assertEquals(7, $contents[0]['permissions']); $this->assertEquals('textfile1.txt', $contents[1]['name']); // 3 is correct because create is reserved to folders only $this->assertEquals(3, $contents[1]['permissions']); }
/** * go recursively through a dir and collect all files and sub files. * * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ public function getAllFiles($dir) { $result = array(); $dirList = array($dir); while ($dirList) { $dir = array_pop($dirList); $content = $this->rootView->getDirectoryContent($dir); foreach ($content as $c) { if ($c->getType() === 'dir') { $dirList[] = $c->getPath(); } else { $result[] = $c->getPath(); } } } return $result; }
/** * Delete should fail is the source file cant be deleted */ public function testSingleStorageDeleteFail() { /** * @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage */ $storage = $this->getMockBuilder('\\OC\\Files\\Storage\\Temporary')->setConstructorArgs([[]])->setMethods(['rename', 'unlink'])->getMock(); $storage->expects($this->any())->method('rename')->will($this->returnValue(false)); $storage->expects($this->any())->method('unlink')->will($this->returnValue(false)); $cache = $storage->getCache(); Filesystem::mount($storage, [], '/' . $this->user . '/files'); $this->userView->file_put_contents('test.txt', 'foo'); $this->assertTrue($storage->file_exists('test.txt')); $this->assertFalse($this->userView->unlink('test.txt')); $this->assertTrue($storage->file_exists('test.txt')); $this->assertTrue($cache->inCache('test.txt')); // file should not be in the trashbin $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/'); $this->assertEquals(0, count($results)); }
/** * go recursively through a dir and collect all files and sub files. * * @param string $dir relative to the users files folder * @param string $mountPoint * @return array with list of files relative to the users files folder */ public function getAllFiles($dir, $mountPoint = '') { $result = array(); $dirList = array($dir); while ($dirList) { $dir = array_pop($dirList); $content = $this->view->getDirectoryContent($dir); foreach ($content as $c) { // getDirectoryContent() returns the paths relative to the mount points, so we need // to re-construct the complete path $path = $mountPoint !== '' ? $mountPoint . '/' . $c->getPath() : $c->getPath(); if ($c['type'] === 'dir') { $dirList[] = \OC\Files\Filesystem::normalizePath($path); } else { $result[] = \OC\Files\Filesystem::normalizePath($path); } } } return $result; }
/** * @medium * test delete file */ function testDeleteFile() { // generate filename $filename = 'tmp-' . uniqid() . '.txt'; // save file with content $cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile)); // check if key for admin exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename . '.key')); // check if share key for admin exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/' . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey')); // delete file \OC\FIles\Filesystem::unlink($filename); // check if file not exists $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename)); // check if key for admin not exists $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename . '.key')); // check if share key for admin not exists $this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/' . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey')); // get files $trashFiles = $this->view->getDirectoryContent('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/'); $trashFileSuffix = null; // find created file with timestamp foreach ($trashFiles as $file) { if (strncmp($file['path'], $filename, strlen($filename))) { $path_parts = pathinfo($file['name']); $trashFileSuffix = $path_parts['extension']; } } // check if we found the file we created $this->assertNotNull($trashFileSuffix); // check if key for admin not exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename . '.key.' . $trashFileSuffix)); // check if share key for admin not exists $this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix)); // return filename for next test return $filename . '.' . $trashFileSuffix; }
/** {@inheritDoc} */ public function run(IOutput $out) { $rootView = new View(); $dataDirectory = $this->config->getSystemValue('datadirectory', null); if (is_null($dataDirectory)) { throw new \Exception('No data directory specified'); } $pathToRootCerts = '/files_external/rootcerts.crt'; foreach ($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) { $uid = trim($fileInfo->getPath(), '/'); if ($rootView->file_exists($uid . $pathToRootCerts)) { // Delete the existing root certificate $rootView->unlink($uid . $pathToRootCerts); /** * FIXME: The certificate manager does only allow specifying the user * within the constructor. This makes DI impossible. */ // Regenerate the certificates $certificateManager = $this->server->getCertificateManager($uid); $certificateManager->createCertificateBundle(); } } }
/** * get the content of a directory * * @param string $directory path under datadirectory * @return array */ public static function getDirectoryContent($directory) { return self::$defaultInstance->getDirectoryContent($directory); }
/** * @param \OC\Files\View $view * @param string $path * * @return array */ private static function getAllChildren($view, $path) { $children = $view->getDirectoryContent($path); $childrensFiles = array(); $fakeRootLength = strlen($view->getRoot()); for ($i = 0; $i < count($children); $i++) { $child = $children[$i]; $childsPath = substr($child->getPath(), $fakeRootLength); if ($view->is_dir($childsPath)) { $children = array_merge($children, $view->getDirectoryContent($childsPath)); } else { $childrensFiles[] = $child; } } return $childrensFiles; }
function testGetFolderContentsInSubdir() { $results = $this->user2View->getDirectoryContent('/shareddir'); $this->verifyFiles(array(array('name' => 'bar.txt', 'path' => 'bar.txt', 'mimetype' => 'text/plain', 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, 'displayname_owner' => 'User One'), array('name' => 'emptydir', 'path' => 'emptydir', 'mimetype' => 'httpd/unix-directory', 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, 'displayname_owner' => 'User One'), array('name' => 'subdir', 'path' => 'subdir', 'mimetype' => 'httpd/unix-directory', 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, 'displayname_owner' => 'User One')), $results); }
/** * @param View $view * @param string $dir * @param string[]|string $files */ public static function lockFiles($view, $dir, $files) { if (!is_array($files)) { $file = $dir . '/' . $files; $files = [$file]; } foreach ($files as $file) { $file = $dir . '/' . $file; $view->lockFile($file, ILockingProvider::LOCK_SHARED); if ($view->is_dir($file)) { $contents = $view->getDirectoryContent($file); $contents = array_map(function ($fileInfo) use($file) { /** @var \OCP\Files\FileInfo $fileInfo */ return $file . '/' . $fileInfo->getName(); }, $contents); self::lockFiles($view, $dir, $contents); } } }
/** * recursive copy to copy a whole directory * * @param string $source source path, relative to the users files directory * @param string $destination destination path relative to the users root directoy * @param \OC\Files\View $view file view for the users root directory */ private static function copy_recursive($source, $destination, $view) { $size = 0; if ($view->is_dir($source)) { $view->mkdir($destination); $view->touch($destination, $view->filemtime($source)); foreach ($view->getDirectoryContent($source) as $i) { $pathDir = $source . '/' . $i['name']; if ($view->is_dir($pathDir)) { $size += self::copy_recursive($pathDir, $destination . '/' . $i['name'], $view); } else { $size += $view->filesize($pathDir); $result = $view->copy($pathDir, $destination . '/' . $i['name']); if (!$result) { throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); } $view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir)); } } } else { $size += $view->filesize($source); $result = $view->copy($source, $destination); if (!$result) { throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); } $view->touch($destination, $view->filemtime($source)); } return $size; }
/** * delete all share keys of a given file * @param \OC\Files\View $view * @param string $userId owner of the file * @param string $filePath path to the file, relative to the owners file dir */ public static function delAllShareKeys($view, $userId, $filePath) { $filePath = ltrim($filePath, '/'); if ($view->file_exists('/' . $userId . '/files/' . $filePath)) { \OCP\Util::writeLog('Encryption library', 'File still exists, stop deleting share keys!', \OCP\Util::ERROR); return false; } if ($filePath === '') { \OCP\Util::writeLog('Encryption library', 'Can\'t delete share-keys empty path given!', \OCP\Util::ERROR); return false; } $util = new util($view, $userId); if ($util->isSystemWideMountPoint($filePath)) { $baseDir = '/files_encryption/share-keys/'; } else { $baseDir = $userId . '/files_encryption/share-keys/'; } $result = true; if ($view->is_dir($baseDir . $filePath)) { \OCP\Util::writeLog('files_encryption', 'delAllShareKeys: delete share keys: ' . $baseDir . $filePath, \OCP\Util::DEBUG); $result = $view->unlink($baseDir . $filePath); } else { $parentDir = dirname($baseDir . $filePath); $filename = pathinfo($filePath, PATHINFO_BASENAME); foreach ($view->getDirectoryContent($parentDir) as $content) { $path = $content['path']; if (self::getFilenameFromShareKey($content['name']) === $filename) { \OCP\Util::writeLog('files_encryption', 'dellAllShareKeys: delete share keys: ' . '/' . $userId . '/' . $path, \OCP\Util::DEBUG); $result &= $view->unlink('/' . $userId . '/' . $path); } } } return (bool) $result; }
/** * returns all stored file versions from a given user * @param string $uid id of the user * @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename */ private static function getAllVersions($uid) { $view = new View('/' . $uid . '/'); $dirs = array(self::VERSIONS_ROOT); $versions = array(); while (!empty($dirs)) { $dir = array_pop($dirs); $files = $view->getDirectoryContent($dir); foreach ($files as $file) { if ($file['type'] === 'dir') { array_push($dirs, $file['path']); } else { $versionsBegin = strrpos($file['path'], '.v'); $relPathStart = strlen(self::VERSIONS_ROOT); $version = substr($file['path'], $versionsBegin + 2); $relpath = substr($file['path'], $relPathStart, $versionsBegin - $relPathStart); $key = $version . '#' . $relpath; $versions[$key] = array('path' => $relpath, 'timestamp' => $version); } } } // newest version first krsort($versions); $result = array(); foreach ($versions as $key => $value) { $size = $view->filesize(self::VERSIONS_ROOT . '/' . $value['path'] . '.v' . $value['timestamp']); $filename = $value['path']; $result['all'][$key]['version'] = $value['timestamp']; $result['all'][$key]['path'] = $filename; $result['all'][$key]['size'] = $size; $result['by_file'][$filename][$key]['version'] = $value['timestamp']; $result['by_file'][$filename][$key]['path'] = $filename; $result['by_file'][$filename][$key]['size'] = $size; } return $result; }
/** * get the content of a directory * * @param string $directory path under datadirectory * @param string $mimetype_filter limit returned content to this mimetype or mimepart * @return \OC\Files\FileInfo[] */ public static function getDirectoryContent($directory, $mimetype_filter = '') { return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); }
private function walkFiles(View $view, $path, \Closure $callBack) { foreach ($view->getDirectoryContent($path) as $fileInfo) { if (!$callBack($fileInfo)) { return; } if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { $this->walkFiles($view, $fileInfo->getPath(), $callBack); } } }