server/apps/files_sharing/lib/controllers/sharecontroller.php
Lukas Reschke 48243a2949 Allow iframes from same domain in share view
This is required because the PDF Viewer itself is embedded using an iframe from the same domain. The default policy is blocking this.

Going on further, we have to come up with a solution in the future how to handle previews by applications, one example might be that they call their own endpoint and not the generic share page to allow applications to have full control over how to display previews.

Anyways, to test this behaviour use a decent newer browser (such as Chrome 41) and share a PDF file, obviously the PDF viewer needs to be enabled as well. Without this patch publicly shared PDF files should not get previewed and an error is thrown. (if it isn't then your browser is probably not obeying our Content-Security-Policy and you might consider switching to another one ;))
2015-03-10 10:06:15 +01:00

309 lines
10 KiB
PHP

<?php
/**
* @author Clark Tomlinson <clark@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @copyright 2014 Clark Tomlinson & Lukas Reschke
*
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\Controllers;
use OC;
use OC\Files\Filesystem;
use OC_Files;
use OC_Util;
use OCP;
use OCP\Template;
use OCP\JSON;
use OCP\Share;
use OCP\AppFramework\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OC\URLGenerator;
use OC\AppConfig;
use OCP\ILogger;
use OCA\Files_Sharing\Helper;
use OCP\User;
use OCP\Util;
use OCA\Files_Sharing\Activity;
/**
* Class ShareController
*
* @package OCA\Files_Sharing\Controllers
*/
class ShareController extends Controller {
/** @var \OC\User\Session */
protected $userSession;
/** @var \OC\AppConfig */
protected $appConfig;
/** @var \OCP\IConfig */
protected $config;
/** @var \OC\URLGenerator */
protected $urlGenerator;
/** @var \OC\User\Manager */
protected $userManager;
/** @var \OCP\ILogger */
protected $logger;
/** @var OCP\Activity\IManager */
protected $activityManager;
/**
* @param string $appName
* @param IRequest $request
* @param OC\User\Session $userSession
* @param AppConfig $appConfig
* @param OCP\IConfig $config
* @param URLGenerator $urlGenerator
* @param OC\User\Manager $userManager
* @param ILogger $logger
* @param OCP\Activity\IManager $activityManager
*/
public function __construct($appName,
IRequest $request,
OC\User\Session $userSession,
AppConfig $appConfig,
OCP\IConfig $config,
URLGenerator $urlGenerator,
OC\User\Manager $userManager,
ILogger $logger,
OCP\Activity\IManager $activityManager) {
parent::__construct($appName, $request);
$this->userSession = $userSession;
$this->appConfig = $appConfig;
$this->config = $config;
$this->urlGenerator = $urlGenerator;
$this->userManager = $userManager;
$this->logger = $logger;
$this->activityManager = $activityManager;
}
/**
* @PublicPage
* @NoCSRFRequired
*
* @param string $token
* @return TemplateResponse|RedirectResponse
*/
public function showAuthenticate($token) {
$linkItem = Share::getShareByToken($token, false);
if(Helper::authenticate($linkItem)) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
}
return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
}
/**
* @PublicPage
* @UseSession
*
* Authenticates against password-protected shares
* @param $token
* @param string $password
* @return RedirectResponse|TemplateResponse
*/
public function authenticate($token, $password = '') {
$linkItem = Share::getShareByToken($token, false);
if($linkItem === false) {
return new TemplateResponse('core', '404', array(), 'guest');
}
$authenticate = Helper::authenticate($linkItem, $password);
if($authenticate === true) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
}
return new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
}
/**
* @PublicPage
* @NoCSRFRequired
*
* @param string $token
* @param string $path
* @return TemplateResponse|RedirectResponse
*/
public function showShare($token, $path = '') {
\OC_User::setIncognitoMode(true);
// Check whether share exists
$linkItem = Share::getShareByToken($token, false);
if($linkItem === false) {
return new TemplateResponse('core', '404', array(), 'guest');
}
$shareOwner = $linkItem['uid_owner'];
$originalSharePath = null;
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
if (isset($rootLinkItem['uid_owner'])) {
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
OC_Util::tearDownFS();
OC_Util::setupFS($rootLinkItem['uid_owner']);
$originalSharePath = Filesystem::getPath($linkItem['file_source']);
}
// Share is password protected - check whether the user is permitted to access the share
if (isset($linkItem['share_with']) && !Helper::authenticate($linkItem)) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
array('token' => $token)));
}
if (Filesystem::isReadable($originalSharePath . $path)) {
$getPath = Filesystem::normalizePath($path);
$originalSharePath .= $path;
}
$file = basename($originalSharePath);
$shareTmpl = array();
$shareTmpl['displayName'] = User::getDisplayName($shareOwner);
$shareTmpl['filename'] = $file;
$shareTmpl['directory_path'] = $linkItem['file_target'];
$shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath);
$shareTmpl['dirToken'] = $linkItem['token'];
$shareTmpl['sharingToken'] = $token;
$shareTmpl['server2serversharing'] = Helper::isOutgoingServer2serverShareEnabled();
$shareTmpl['protected'] = isset($linkItem['share_with']) ? 'true' : 'false';
$shareTmpl['dir'] = '';
$nonHumanFileSize = \OC\Files\Filesystem::filesize($originalSharePath);
$shareTmpl['nonHumanFileSize'] = $nonHumanFileSize;
$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($nonHumanFileSize);
// Show file list
if (Filesystem::is_dir($originalSharePath)) {
$shareTmpl['dir'] = $getPath;
$maxUploadFilesize = Util::maxUploadFilesize($originalSharePath);
$freeSpace = Util::freeSpace($originalSharePath);
$uploadLimit = Util::uploadLimit();
$folder = new Template('files', 'list', '');
$folder->assign('dir', $getPath);
$folder->assign('dirToken', $linkItem['token']);
$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
$folder->assign('isPublic', true);
$folder->assign('publicUploadEnabled', 'no');
$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
$folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
$folder->assign('freeSpace', $freeSpace);
$folder->assign('uploadLimit', $uploadLimit); // PHP upload limit
$folder->assign('usedSpacePercent', 0);
$folder->assign('trash', false);
$shareTmpl['folder'] = $folder->fetchPage();
}
$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', array('token' => $token));
$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
$csp = new OCP\AppFramework\Http\ContentSecurityPolicy();
$csp->addAllowedFrameDomain('\'self\'');
$response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
$response->setContentSecurityPolicy($csp);
return $response;
}
/**
* @PublicPage
* @NoCSRFRequired
*
* @param string $token
* @param string $files
* @param string $path
* @return void|RedirectResponse
*/
public function downloadShare($token, $files = null, $path = '') {
\OC_User::setIncognitoMode(true);
$linkItem = OCP\Share::getShareByToken($token, false);
// Share is password protected - check whether the user is permitted to access the share
if (isset($linkItem['share_with'])) {
if(!Helper::authenticate($linkItem)) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
array('token' => $token)));
}
}
$files_list = null;
if (!is_null($files)) { // download selected files
$files_list = json_decode($files);
// in case we get only a single file
if ($files_list === null) {
$files_list = array($files);
}
}
$originalSharePath = self::getPath($token);
// Create the activities
if (isset($originalSharePath) && Filesystem::isReadable($originalSharePath . $path)) {
$originalSharePath = Filesystem::normalizePath($originalSharePath . $path);
$isDir = \OC\Files\Filesystem::is_dir($originalSharePath);
$activities = [];
if (!$isDir) {
// Single file public share
$activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
} else if (!empty($files_list)) {
// Only some files are downloaded
foreach ($files_list as $file) {
$filePath = Filesystem::normalizePath($originalSharePath . '/' . $file);
$isDir = \OC\Files\Filesystem::is_dir($filePath);
$activities[$filePath] = ($isDir) ? Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED : Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
}
} else {
// The folder is downloaded
$activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
}
foreach ($activities as $filePath => $subject) {
$this->activityManager->publishActivity(
'files_sharing', $subject, array($filePath), '', array(),
$filePath, '', $linkItem['uid_owner'], Activity::TYPE_PUBLIC_LINKS, Activity::PRIORITY_MEDIUM
);
}
}
// download selected files
if (!is_null($files)) {
// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
// after dispatching the request which results in a "Cannot modify header information" notice.
OC_Files::get($originalSharePath, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD');
exit();
} else {
// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
// after dispatching the request which results in a "Cannot modify header information" notice.
OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $_SERVER['REQUEST_METHOD'] == 'HEAD');
exit();
}
}
/**
* @param $token
* @return null|string
*/
private function getPath($token) {
$linkItem = Share::getShareByToken($token, false);
$path = null;
if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
// seems to be a valid share
$rootLinkItem = Share::resolveReShare($linkItem);
if (isset($rootLinkItem['uid_owner'])) {
JSON::checkUserExists($rootLinkItem['uid_owner']);
OC_Util::tearDownFS();
OC_Util::setupFS($rootLinkItem['uid_owner']);
$path = Filesystem::getPath($linkItem['file_source']);
}
}
return $path;
}
}