/** * create a new share * * @param array $params * @return \OC_OCS_Result */ public function createShare($params) { if (!$this->isS2SEnabled(true)) { return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); } $remote = isset($_POST['remote']) ? $_POST['remote'] : null; $token = isset($_POST['token']) ? $_POST['token'] : null; $name = isset($_POST['name']) ? $_POST['name'] : null; $owner = isset($_POST['owner']) ? $_POST['owner'] : null; $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; $remoteId = isset($_POST['remoteId']) ? (int) $_POST['remoteId'] : null; if ($remote && $token && $name && $owner && $remoteId && $shareWith) { if (!\OCP\Util::isValidFileName($name)) { return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); } if (!\OCP\User::userExists($shareWith)) { return new \OC_OCS_Result(null, 400, 'User does not exists'); } \OC_Util::setupFS($shareWith); $externalManager = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPHelper(), $shareWith); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); $user = $owner . '@' . $this->cleanupRemote($remote); \OC::$server->getActivityManager()->publishActivity('files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user), '', array(), '', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); return new \OC_OCS_Result(); } catch (\Exception $e) { \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); } } return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); }
/** * create a new share * * @param array $params * @return \OC_OCS_Result */ public function createShare($params) { if (!$this->isS2SEnabled(true)) { return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); } $remote = isset($_POST['remote']) ? $_POST['remote'] : null; $token = isset($_POST['token']) ? $_POST['token'] : null; $name = isset($_POST['name']) ? $_POST['name'] : null; $owner = isset($_POST['owner']) ? $_POST['owner'] : null; $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; $remoteId = isset($_POST['remoteId']) ? (int) $_POST['remoteId'] : null; if ($remote && $token && $name && $owner && $remoteId && $shareWith) { if (!\OCP\Util::isValidFileName($name)) { return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); } // FIXME this should be a method in the user management instead \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG); \OCP\Util::emitHook('\\OCA\\Files_Sharing\\API\\Server2Server', 'preLoginNameUsedAsUserName', array('uid' => &$shareWith)); \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG); if (!\OCP\User::userExists($shareWith)) { return new \OC_OCS_Result(null, 400, 'User does not exists'); } \OC_Util::setupFS($shareWith); $externalManager = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPHelper(), \OC::$server->getNotificationManager(), $shareWith); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); $user = $owner . '@' . $this->cleanupRemote($remote); \OC::$server->getActivityManager()->publishActivity(Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user, trim($name, '/')), '', array(), '', '', $shareWith, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_LOW); /** * FIXME $urlGenerator = \OC::$server->getURLGenerator(); $notificationManager = \OC::$server->getNotificationManager(); $notification = $notificationManager->createNotification(); $notification->setApp('files_sharing') ->setUser($shareWith) ->setTimestamp(time()) ->setObject('remote_share', $remoteId) ->setSubject('remote_share', [$user, trim($name, '/')]); $declineAction = $notification->createAction(); $declineAction->setLabel('decline') ->setLink($urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/remote_shares/' . $remoteId), 'DELETE'); $notification->addAction($declineAction); $acceptAction = $notification->createAction(); $acceptAction->setLabel('accept') ->setLink($urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/remote_shares/' . $remoteId), 'POST'); $notification->addAction($acceptAction); $notificationManager->notify($notification); */ return new \OC_OCS_Result(); } catch (\Exception $e) { \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); } } return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); }
/** * Updates the data * * The data argument is a readable stream resource. * * After a successful put operation, you may choose to return an ETag. The * etag must always be surrounded by double-quotes. These quotes must * appear in the actual string you're returning. * * Clients may use the ETag from a PUT request to later on make sure that * when they update the file, the contents haven't changed in the mean * time. * * If you don't plan to store the file byte-by-byte, and you return a * different object on a subsequent GET you are strongly recommended to not * return an ETag, and just return null. * * @param resource $data * @throws \Sabre\DAV\Exception\Forbidden * @throws OC_Connector_Sabre_Exception_UnsupportedMediaType * @throws \Sabre\DAV\Exception\BadRequest * @throws \Sabre\DAV\Exception * @throws OC_Connector_Sabre_Exception_EntityTooLarge * @throws \Sabre\DAV\Exception\ServiceUnavailable * @return string|null */ public function put($data) { if ($this->info && $this->fileView->file_exists($this->path) && !$this->info->isUpdateable()) { throw new \Sabre\DAV\Exception\Forbidden(); } // throw an exception if encryption was disabled but the files are still encrypted if (\OC_Util::encryptedFiles()) { throw new \Sabre\DAV\Exception\ServiceUnavailable(); } $fileName = basename($this->path); if (!\OCP\Util::isValidFileName($fileName)) { throw new \Sabre\DAV\Exception\BadRequest(); } // chunked handling if (isset($_SERVER['HTTP_OC_CHUNKED'])) { return $this->createFileChunked($data); } // mark file as partial while uploading (ignored by the scanner) $partFilePath = $this->path . '.ocTransferId' . rand() . '.part'; try { $putOkay = $this->fileView->file_put_contents($partFilePath, $data); if ($putOkay === false) { \OC_Log::write('webdav', '\\OC\\Files\\Filesystem::file_put_contents() failed', \OC_Log::ERROR); $this->fileView->unlink($partFilePath); // because we have no clue about the cause we can only throw back a 500/Internal Server Error throw new \Sabre\DAV\Exception('Could not write file contents'); } } catch (\OCP\Files\NotPermittedException $e) { // a more general case - due to whatever reason the content could not be written throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); } catch (\OCP\Files\EntityTooLargeException $e) { // the file is too big to be stored throw new OC_Connector_Sabre_Exception_EntityTooLarge($e->getMessage()); } catch (\OCP\Files\InvalidContentException $e) { // the file content is not permitted throw new OC_Connector_Sabre_Exception_UnsupportedMediaType($e->getMessage()); } catch (\OCP\Files\InvalidPathException $e) { // the path for the file was not valid // TODO: find proper http status code for this case throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); } catch (\OCP\Files\LockNotAcquiredException $e) { // the file is currently being written to by another process throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } // double check if the file was fully received // compare expected and actual size $expected = $_SERVER['CONTENT_LENGTH']; $actual = $this->fileView->filesize($partFilePath); if ($actual != $expected) { $this->fileView->unlink($partFilePath); throw new \Sabre\DAV\Exception\BadRequest('expected filesize ' . $expected . ' got ' . $actual); } // rename to correct path try { $renameOkay = $this->fileView->rename($partFilePath, $this->path); $fileExists = $this->fileView->file_exists($this->path); if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\\OC\\Files\\Filesystem::rename() failed', \OC_Log::ERROR); $this->fileView->unlink($partFilePath); throw new \Sabre\DAV\Exception('Could not rename part file to final file'); } } catch (\OCP\Files\LockNotAcquiredException $e) { // the file is currently being written to by another process throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } // allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); if ($mtime !== false) { if ($this->fileView->touch($this->path, $mtime)) { header('X-OC-MTime: accepted'); } } $this->refreshInfo(); return '"' . $this->info->getEtag() . '"'; }
/** * @dataProvider filenameValidationProvider */ public function testFilenameValidation($file, $valid) { // private API $this->assertEquals($valid, \OC_Util::isValidFileName($file)); // public API $this->assertEquals($valid, \OCP\Util::isValidFileName($file)); }
OCP\JSON::callCheck(); OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('files_sharing'); $l = \OC::$server->getL10N('files_sharing'); // check if server admin allows to mount public links from other servers if (OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled() === false) { \OCP\JSON::error(array('data' => array('message' => $l->t('Server to server sharing is not enabled on this server')))); exit; } $token = $_POST['token']; $remote = $_POST['remote']; $owner = $_POST['owner']; $name = $_POST['name']; $password = $_POST['password']; // Check for invalid name if (!\OCP\Util::isValidFileName($name)) { \OCP\JSON::error(array('data' => array('message' => $l->t('The mountpoint name contains invalid characters.')))); exit; } $externalManager = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPHelper(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession()->getUser()->getUID()); // check for ssl cert if (substr($remote, 0, 5) === 'https') { try { \OC::$server->getHTTPClientService()->newClient()->get($remote)->getBody(); } catch (\Exception $e) { \OCP\JSON::error(array('data' => array('message' => $l->t('Invalid or untrusted SSL certificate')))); exit; } } $mount = $externalManager->addShare($remote, $token, $password, $name, $owner, true); /**
/** * Moves a file from one location to another * * @param string $sourcePath The path to the file which should be moved * @param string $destinationPath The full destination path, so not just the destination parent node * @throws \Sabre\DAV\Exception\BadRequest * @throws \Sabre\DAV\Exception\ServiceUnavailable * @throws \Sabre\DAV\Exception\Forbidden * @return int */ public function move($sourcePath, $destinationPath) { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } $sourceNode = $this->getNodeForPath($sourcePath); if ($sourceNode instanceof \Sabre\DAV\ICollection and $this->nodeExists($destinationPath)) { throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists'); } list($sourceDir, ) = \Sabre\DAV\URLUtil::splitPath($sourcePath); list($destinationDir, ) = \Sabre\DAV\URLUtil::splitPath($destinationPath); $isMovableMount = false; $sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath)); $internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath)); if ($sourceMount instanceof MoveableMount && $internalPath === '') { $isMovableMount = true; } try { // check update privileges if (!$this->fileView->isUpdatable($sourcePath) && !$isMovableMount) { throw new \Sabre\DAV\Exception\Forbidden(); } if ($sourceDir !== $destinationDir) { if (!$this->fileView->isCreatable($destinationDir)) { throw new \Sabre\DAV\Exception\Forbidden(); } if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) { throw new \Sabre\DAV\Exception\Forbidden(); } } $fileName = basename($destinationPath); if (!\OCP\Util::isValidFileName($fileName)) { throw new \Sabre\DAV\Exception\BadRequest(); } $renameOkay = $this->fileView->rename($sourcePath, $destinationPath); if (!$renameOkay) { throw new \Sabre\DAV\Exception\Forbidden(''); } } catch (\OCP\Files\StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); } // update properties $query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?' . ' WHERE `userid` = ? AND `propertypath` = ?'); $query->execute(array(\OC\Files\Filesystem::normalizePath($destinationPath), \OC_User::getUser(), \OC\Files\Filesystem::normalizePath($sourcePath))); $this->markDirty($sourceDir); $this->markDirty($destinationDir); }
/** * Renames the node * @param string $name The new name * @throws \Sabre\DAV\Exception\BadRequest * @throws \Sabre\DAV\Exception\Forbidden */ public function setName($name) { // rename is only allowed if the update privilege is granted if (!$this->info->isUpdateable()) { throw new \Sabre\DAV\Exception\Forbidden(); } list($parentPath, ) = URLUtil::splitPath($this->path); list(, $newName) = URLUtil::splitPath($name); if (!\OCP\Util::isValidFileName($newName)) { throw new \Sabre\DAV\Exception\BadRequest(); } $newPath = $parentPath . '/' . $newName; $oldPath = $this->path; $this->fileView->rename($this->path, $newPath); $this->path = $newPath; $query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?' . ' WHERE `userid` = ? AND `propertypath` = ?'); $query->execute(array($newPath, OC_User::getUser(), $oldPath)); $this->refreshInfo(); }
/** * @param string $tzId * @return bool */ private function isValidFileName($tzId) { $filename = str_replace('/', '-', $tzId); if (in_array($filename, $this->fileBlacklist) || !Util::isValidFileName($filename)) { return false; } return true; }
/** * Moves a file from one location to another * * @param string $sourcePath The path to the file which should be moved * @param string $destinationPath The full destination path, so not just the destination parent node * @throws \Sabre\DAV\Exception\BadRequest * @throws \Sabre\DAV\Exception\ServiceUnavailable * @throws \Sabre\DAV\Exception\Forbidden * @return int */ public function move($sourcePath, $destinationPath) { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } $targetNodeExists = $this->nodeExists($destinationPath); $sourceNode = $this->getNodeForPath($sourcePath); if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) { throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists'); } list($sourceDir, ) = \Sabre\DAV\URLUtil::splitPath($sourcePath); list($destinationDir, ) = \Sabre\DAV\URLUtil::splitPath($destinationPath); $isMovableMount = false; $sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath)); $internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath)); if ($sourceMount instanceof MoveableMount && $internalPath === '') { $isMovableMount = true; } try { $sameFolder = $sourceDir === $destinationDir; // if we're overwriting or same folder if ($targetNodeExists || $sameFolder) { // note that renaming a share mount point is always allowed if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) { throw new \Sabre\DAV\Exception\Forbidden(); } } else { if (!$this->fileView->isCreatable($destinationDir)) { throw new \Sabre\DAV\Exception\Forbidden(); } } if (!$sameFolder) { // moving to a different folder, source will be gone, like a deletion // note that moving a share mount point is always allowed if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) { throw new \Sabre\DAV\Exception\Forbidden(); } } $fileName = basename($destinationPath); if (!\OCP\Util::isValidFileName($fileName)) { throw new \Sabre\DAV\Exception\BadRequest(); } $renameOkay = $this->fileView->rename($sourcePath, $destinationPath); if (!$renameOkay) { throw new \Sabre\DAV\Exception\Forbidden(''); } } catch (\OCP\Files\StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); } // update properties $query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?' . ' WHERE `userid` = ? AND `propertypath` = ?'); $query->execute(array(\OC\Files\Filesystem::normalizePath($destinationPath), \OC_User::getUser(), \OC\Files\Filesystem::normalizePath($sourcePath))); $this->markDirty($sourceDir); $this->markDirty($destinationDir); }