Beispiel #1
0
 /**
  * @param $path
  */
 public function handleFile($path)
 {
     // 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 = Helper::getUser($path);
     $util = new Util($view, $userId);
     // split the path parts
     $pathParts = explode('/', $path);
     // get relative path
     $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
     // only if file is on 'files' folder fix file size and sharing
     if (isset($pathParts[2]) && $pathParts[2] === 'files' && $util->fixFileSize($path)) {
         // get sharing app state
         $sharingEnabled = \OCP\Share::isEnabled();
         // get users
         $usersSharing = $util->getSharingUsersArray($sharingEnabled, $relativePath);
         // update sharing-keys
         $util->setSharedFileKeyfiles($session, $usersSharing, $relativePath);
     }
     \OC_FileProxy::$enabled = $proxyStatus;
 }
Beispiel #2
0
 /**
  * @param string $path
  * @param int $size
  * @return int|bool
  */
 public function postFileSize($path, $size, $fileInfo = null)
 {
     $view = new \OC\Files\View('/');
     $userId = Helper::getUser($path);
     $util = new Util($view, $userId);
     // if encryption is no longer enabled or if the files aren't migrated yet
     // we return the default file size
     if (!\OCP\App::isEnabled('files_encryption') || $util->getMigrationStatus() !== Util::MIGRATION_COMPLETED) {
         return $size;
     }
     // if path is a folder do nothing
     if ($view->is_dir($path)) {
         $proxyState = \OC_FileProxy::$enabled;
         \OC_FileProxy::$enabled = false;
         $fileInfo = $view->getFileInfo($path);
         \OC_FileProxy::$enabled = $proxyState;
         if (isset($fileInfo['unencrypted_size']) && $fileInfo['unencrypted_size'] > 0) {
             return $fileInfo['unencrypted_size'];
         }
         return $size;
     }
     // get relative path
     $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
     // if path is empty we cannot resolve anything
     if (empty($relativePath)) {
         return $size;
     }
     // get file info from database/cache if not .part file
     if (empty($fileInfo) && !Helper::isPartialFilePath($path)) {
         $proxyState = \OC_FileProxy::$enabled;
         \OC_FileProxy::$enabled = false;
         $fileInfo = $view->getFileInfo($path);
         \OC_FileProxy::$enabled = $proxyState;
     }
     // if file is encrypted return real file size
     if (isset($fileInfo['encrypted']) && $fileInfo['encrypted'] === true) {
         // try to fix unencrypted file size if it doesn't look plausible
         if ((int) $fileInfo['size'] > 0 && (int) $fileInfo['unencrypted_size'] === 0) {
             $fixSize = $util->getFileSize($path);
             $fileInfo['unencrypted_size'] = $fixSize;
             // put file info if not .part file
             if (!Helper::isPartialFilePath($relativePath)) {
                 $view->putFileInfo($path, array('unencrypted_size' => $fixSize));
             }
         }
         $size = $fileInfo['unencrypted_size'];
     } else {
         $fileInfoUpdates = array();
         $fixSize = $util->getFileSize($path);
         if ($fixSize > 0) {
             $size = $fixSize;
             $fileInfoUpdates['encrypted'] = true;
             $fileInfoUpdates['unencrypted_size'] = $size;
             // put file info if not .part file
             if (!Helper::isPartialFilePath($relativePath)) {
                 $view->putFileInfo($path, $fileInfoUpdates);
             }
         }
     }
     return $size;
 }
Beispiel #3
0
 /**
  * Find all files and their encryption status within a directory
  * @param string $directory The path of the parent directory to search
  * @param bool $found the founded files if called again
  * @return array keys: plain, encrypted, broken
  * @note $directory needs to be a path relative to OC data dir. e.g.
  *       /admin/files NOT /backup OR /home/www/oc/data/admin/files
  */
 public function findEncFiles($directory, &$found = false)
 {
     // Disable proxy - we don't want files to be decrypted before
     // we handle them
     \OC_FileProxy::$enabled = false;
     if ($found === false) {
         $found = array('plain' => array(), 'encrypted' => array(), 'broken' => array());
     }
     if ($this->view->is_dir($directory) && ($handle = $this->view->opendir($directory))) {
         if (is_resource($handle)) {
             while (false !== ($file = readdir($handle))) {
                 if ($file !== "." && $file !== "..") {
                     $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
                     $relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
                     // If the path is a directory, search
                     // its contents
                     if ($this->view->is_dir($filePath)) {
                         $this->findEncFiles($filePath, $found);
                         // If the path is a file, determine
                         // its encryption status
                     } elseif ($this->view->is_file($filePath)) {
                         // Disable proxies again, some-
                         // where they got re-enabled :/
                         \OC_FileProxy::$enabled = false;
                         $isEncryptedPath = $this->isEncryptedPath($filePath);
                         // If the file is encrypted
                         // NOTE: If the userId is
                         // empty or not set, file will
                         // detected as plain
                         // NOTE: This is inefficient;
                         // scanning every file like this
                         // will eat server resources :(
                         if ($isEncryptedPath) {
                             $fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
                             $shareKey = Keymanager::getShareKey($this->view, $this->userId, $this, $relPath);
                             // if file is encrypted but now file key is available, throw exception
                             if ($fileKey === false || $shareKey === false) {
                                 \OCP\Util::writeLog('encryption library', 'No keys available to decrypt the file: ' . $filePath, \OCP\Util::ERROR);
                                 $found['broken'][] = array('name' => $file, 'path' => $filePath);
                             } else {
                                 $found['encrypted'][] = array('name' => $file, 'path' => $filePath);
                             }
                             // If the file is not encrypted
                         } else {
                             $found['plain'][] = array('name' => $file, 'path' => $relPath);
                         }
                     }
                 }
             }
         }
     }
     \OC_FileProxy::$enabled = true;
     return $found;
 }
Beispiel #4
0
 /**
  * get the file size of the unencrypted file
  * @param string $path absolute path
  * @return bool
  */
 public function getFileSize($path)
 {
     $result = 0;
     // Disable encryption proxy to prevent recursive calls
     $proxyStatus = \OC_FileProxy::$enabled;
     \OC_FileProxy::$enabled = false;
     // split the path parts
     $pathParts = explode('/', $path);
     if (isset($pathParts[2]) && $pathParts[2] === 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) {
         $cipher = 'AES-128-CFB';
         $realSize = 0;
         // get the size from filesystem
         $size = $this->view->filesize($path);
         // open stream
         $stream = $this->view->fopen($path, "r");
         if (is_resource($stream)) {
             // if the file contains a encryption header we
             // we set the cipher
             // and we update the size
             if ($this->containHeader($path)) {
                 $data = fread($stream, Crypt::BLOCKSIZE);
                 $header = Crypt::parseHeader($data);
                 $cipher = Crypt::getCipher($header);
                 $size -= Crypt::BLOCKSIZE;
             }
             // fast path, else the calculation for $lastChunkNr is bogus
             if ($size === 0) {
                 \OC_FileProxy::$enabled = $proxyStatus;
                 return 0;
             }
             // calculate last chunk nr
             // next highest is end of chunks, one subtracted is last one
             // we have to read the last chunk, we can't just calculate it (because of padding etc)
             $lastChunkNr = ceil($size / Crypt::BLOCKSIZE) - 1;
             // calculate last chunk position
             $lastChunkPos = $lastChunkNr * Crypt::BLOCKSIZE;
             // get the content of the last chunk
             if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) {
                 $realSize += $lastChunkNr * 6126;
             }
             $lastChunkContentEncrypted = '';
             $count = Crypt::BLOCKSIZE;
             while ($count > 0) {
                 $data = fread($stream, Crypt::BLOCKSIZE);
                 $count = strlen($data);
                 $lastChunkContentEncrypted .= $data;
                 if (strlen($lastChunkContentEncrypted) > Crypt::BLOCKSIZE) {
                     $realSize += 6126;
                     $lastChunkContentEncrypted = substr($lastChunkContentEncrypted, Crypt::BLOCKSIZE);
                 }
             }
             fclose($stream);
             $relPath = \OCA\Encryption\Helper::stripUserFilesPath($path);
             $shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $relPath);
             if ($shareKey === false) {
                 \OC_FileProxy::$enabled = $proxyStatus;
                 return $result;
             }
             $session = new \OCA\Encryption\Session($this->view);
             $privateKey = $session->getPrivateKey();
             $plainKeyfile = $this->decryptKeyfile($relPath, $privateKey);
             $plainKey = Crypt::multiKeyDecrypt($plainKeyfile, $shareKey, $privateKey);
             $lastChunkContent = Crypt::symmetricDecryptFileContent($lastChunkContentEncrypted, $plainKey, $cipher);
             // calc the real file size with the size of the last chunk
             $realSize += strlen($lastChunkContent);
             // store file size
             $result = $realSize;
         }
     }
     \OC_FileProxy::$enabled = $proxyStatus;
     return $result;
 }
Beispiel #5
0
 /**
  * Decrypt all files
  * @return bool
  */
 public function decryptAll()
 {
     $found = $this->findEncFiles($this->userId . '/files');
     $successful = true;
     if ($found) {
         $versionStatus = \OCP\App::isEnabled('files_versions');
         \OC_App::disable('files_versions');
         $decryptedFiles = array();
         // Encrypt unencrypted files
         foreach ($found['encrypted'] as $encryptedFile) {
             //relative to data/<user>/file
             $relPath = Helper::stripUserFilesPath($encryptedFile['path']);
             //get file info
             $fileInfo = \OC\Files\Filesystem::getFileInfo($relPath);
             //relative to /data
             $rawPath = $encryptedFile['path'];
             //get timestamp
             $timestamp = $fileInfo['mtime'];
             //enable proxy to use OC\Files\View to access the original file
             \OC_FileProxy::$enabled = true;
             // Open enc file handle for binary reading
             $encHandle = $this->view->fopen($rawPath, 'rb');
             // Disable proxy to prevent file being encrypted again
             \OC_FileProxy::$enabled = false;
             if ($encHandle === false) {
                 \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $rawPath . '", decryption failed!', \OCP\Util::FATAL);
                 $successful = false;
                 continue;
             }
             // Open plain file handle for binary writing, with same filename as original plain file
             $plainHandle = $this->view->fopen($rawPath . '.part', 'wb');
             if ($plainHandle === false) {
                 \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $rawPath . '.part", decryption failed!', \OCP\Util::FATAL);
                 $successful = false;
                 continue;
             }
             // Move plain file to a temporary location
             $size = stream_copy_to_stream($encHandle, $plainHandle);
             if ($size === 0) {
                 \OCP\Util::writeLog('Encryption library', 'Zero bytes copied of "' . $rawPath . '", decryption failed!', \OCP\Util::FATAL);
                 $successful = false;
                 continue;
             }
             fclose($encHandle);
             fclose($plainHandle);
             $fakeRoot = $this->view->getRoot();
             $this->view->chroot('/' . $this->userId . '/files');
             $this->view->rename($relPath . '.part', $relPath);
             //set timestamp
             $this->view->touch($relPath, $timestamp);
             $this->view->chroot($fakeRoot);
             // Add the file to the cache
             \OC\Files\Filesystem::putFileInfo($relPath, array('encrypted' => false, 'size' => $size, 'unencrypted_size' => 0, 'etag' => $fileInfo['etag']));
             $decryptedFiles[] = $relPath;
         }
         if ($versionStatus) {
             \OC_App::enable('files_versions');
         }
         if (!$this->decryptVersions($decryptedFiles)) {
             $successful = false;
         }
         // if there are broken encrypted files than the complete decryption
         // was not successful
         if (!empty($found['broken'])) {
             $successful = false;
         }
         if ($successful) {
             $this->view->rename($this->keyfilesPath, $this->keyfilesPath . '.backup');
             $this->view->rename($this->shareKeysPath, $this->shareKeysPath . '.backup');
         }
         \OC_FileProxy::$enabled = true;
     }
     return $successful;
 }
Beispiel #6
0
 /**
  * Get the path including the storage mount point
  * @param int $id
  * @return string the path including the mount point like AmazonS3/folder/file.txt
  */
 public function getPathWithMountPoint($id)
 {
     list($storage, $internalPath) = \OC\Files\Cache\Cache::getById($id);
     $mount = \OC\Files\Filesystem::getMountByStorageId($storage);
     $mountPoint = $mount[0]->getMountPoint();
     $path = \OC\Files\Filesystem::normalizePath($mountPoint . '/' . $internalPath);
     // reformat the path to be relative e.g. /user/files/folder becomes /folder/
     $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
     return $relativePath;
 }