diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AppInfo/Application.php | 37 | ||||
-rw-r--r-- | lib/Controller/WopiController.php | 16 | ||||
-rw-r--r-- | lib/Service/FederationService.php | 58 | ||||
-rw-r--r-- | lib/TemplateManager.php | 10 |
4 files changed, 100 insertions, 21 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 7b72e938..7e86f801 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -41,6 +41,7 @@ use OCA\Viewer\Event\LoadViewer; use OCP\AppFramework\App; use OCP\AppFramework\QueryException; use OCP\EventDispatcher\IEventDispatcher; +use OCP\GlobalScale\IConfig; use OCP\IPreview; class Application extends App { @@ -139,22 +140,42 @@ class Application extends App { $path = $container->getServer()->getRequest()->getPathInfo(); } catch (\Exception $e) {} if (strpos($path, '/apps/files') === 0 && $container->getServer()->getAppManager()->isEnabledForUser('federation')) { - /** @var TrustedServers $trustedServers */ - $trustedServers = $container->query(TrustedServers::class); /** @var FederationService $federationService */ - $federationService = $container->query(FederationService::class); + $federationService = \OC::$server->query(FederationService::class); + + // Always add trusted servers on global scale + /** @var IConfig $globalScale */ + $globalScale = $container->query(IConfig::class); + if ($globalScale->isGlobalScaleEnabled()) { + $trustedList = \OC::$server->getConfig()->getSystemValue('gs.trustedHosts', []); + foreach ($trustedList as $server) { + $this->addTrustedRemote($policy, $server); + } + } $remoteAccess = $container->getServer()->getRequest()->getParam('richdocuments_remote_access'); - if ($remoteAccess && $trustedServers->isTrustedServer($remoteAccess)) { - $remoteCollabora = $federationService->getRemoteCollaboraURL($remoteAccess); - $policy->addAllowedFrameDomain($remoteAccess); - $policy->addAllowedFrameDomain($remoteCollabora); + if ($remoteAccess && $federationService->isTrustedRemote($remoteAccess)) { + $this->addTrustedRemote($policy, $remoteAccess); } } $cspManager->addDefaultPolicy($policy); } + private function addTrustedRemote($policy, $url) { + /** @var FederationService $federationService */ + $federationService = \OC::$server->query(FederationService::class); + try { + $remoteCollabora = $federationService->getRemoteCollaboraURL($url); + $policy->addAllowedFrameDomain($url); + $policy->addAllowedFrameDomain($remoteCollabora); + } catch (\Exception $e) { + // We can ignore this exception for adding predefined domains to the CSP as it it would then just + // reload the page to set a proper allowed frame domain if we don't have a fixed list of trusted + // remotes in a global scale scenario + } + } + public function checkAndEnableCODEServer() { // Supported only on Linux OS, and x86_64 & ARM64 platforms $supportedArchs = array('x86_64', 'aarch64'); @@ -190,7 +211,7 @@ class Application extends App { $discoveryManager = $this->getContainer()->query(DiscoveryManager::class); $capabilitiesService = $this->getContainer()->query(CapabilitiesService::class); - $discoveryManager->refretch(); + $discoveryManager->refetch(); $capabilitiesService->clear(); $capabilitiesService->refetch(); } diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index a0a475bd..0fbc5ef3 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -353,15 +353,23 @@ class WopiController extends Controller { $versionPath = '/files_versions/' . $relPath . '.v' . $version; $view = new View('/' . $wopi->getOwnerUid()); if ($view->file_exists($versionPath)){ - $response = new StreamResponse($view->fopen($versionPath, 'rb')); + $info = $view->getFileInfo($versionPath); + if ($info->getSize() === 0) { + $response = new Http\Response(); + } else { + $response = new StreamResponse($view->fopen($versionPath, 'rb')); + } } else { return new JSONResponse([], Http::STATUS_NOT_FOUND); } } - else - { - $response = new StreamResponse($file->fopen('rb')); + else { + if ($file->getSize() === 0) { + $response = new Http\Response(); + } else { + $response = new StreamResponse($file->fopen('rb')); + } } $response->addHeader('Content-Disposition', 'attachment'); $response->addHeader('Content-Type', 'application/octet-stream'); diff --git a/lib/Service/FederationService.php b/lib/Service/FederationService.php index fce2ea74..1d18fdef 100644 --- a/lib/Service/FederationService.php +++ b/lib/Service/FederationService.php @@ -35,6 +35,7 @@ use OCP\Files\NotFoundException; use OCP\Http\Client\IClientService; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IConfig; use OCP\ILogger; class FederationService { @@ -47,14 +48,17 @@ class FederationService { private $logger; /** @var TrustedServers */ private $trustedServers; + /** @var IConfig */ + private $config; /** @var TokenManager */ private $tokenManager; - public function __construct(ICacheFactory $cacheFactory, IClientService $clientService, ILogger $logger, TokenManager $tokenManager) { + public function __construct(ICacheFactory $cacheFactory, IClientService $clientService, ILogger $logger, TokenManager $tokenManager, IConfig $config) { $this->cache = $cacheFactory->createLocal('richdocuments_remote/'); $this->clientService = $clientService; $this->logger = $logger; $this->tokenManager = $tokenManager; + $this->config = $config; try { $this->trustedServers = \OC::$server->query( \OCA\Federation\TrustedServers::class); } catch (QueryException $e) {} @@ -66,7 +70,7 @@ class FederationService { * @throws \Exception */ public function getRemoteCollaboraURL($remote) { - if ($this->trustedServers === null || !$this->trustedServers->isTrustedServer($remote)) { + if (!$this->isTrustedRemote($remote)) { throw new \Exception('Unable to determine collabora URL of remote server ' . $remote . ' - Remote is not a trusted server'); } if ($remoteCollabora = $this->cache->get('richdocuments_remote/' . $remote)) { @@ -86,6 +90,54 @@ class FederationService { return ''; } + public function isTrustedRemote($domainWithPort) { + if (strpos($domainWithPort, 'http://') === 0 || strpos($domainWithPort, 'https://') === 0) { + $port = parse_url($domainWithPort, PHP_URL_PORT); + $domainWithPort = parse_url($domainWithPort, PHP_URL_HOST) . ($port ? ':' . $port : ''); + } + + if ($this->trustedServers !== null && $this->trustedServers->isTrustedServer($domainWithPort)) { + return true; + } + + $domain = $this->getDomainWithoutPort($domainWithPort); + + $trustedList = $this->config->getSystemValue('gs.trustedHosts', []); + if (!is_array($trustedList)) { + return false; + } + + foreach ($trustedList as $trusted) { + if (!is_string($trusted)) { + break; + } + $regex = '/^' . implode('[-\.a-zA-Z0-9]*', array_map(function ($v) { + return preg_quote($v, '/'); + }, explode('*', $trusted))) . '$/i'; + if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) { + return true; + } + } + + return false; + } + + /** + * Strips a potential port from a domain (in format domain:port) + * @param string $host + * @return string $host without appended port + */ + private function getDomainWithoutPort($host) { + $pos = strrpos($host, ':'); + if ($pos !== false) { + $port = substr($host, $pos + 1); + if (is_numeric($port)) { + $host = substr($host, 0, $pos); + } + } + return $host; + } + public function getRemoteDirectUrl($remote, $shareToken, $filePath) { if ($this->getRemoteCollaboraURL() === '') { return ''; @@ -108,7 +160,7 @@ class FederationService { } public function getRemoteFileDetails($remote, $remoteToken) { - if ($this->trustedServers === null || !$this->trustedServers->isTrustedServer($remote)) { + if (!$this->isTrustedRemote($remote)) { $this->logger->info('Unable to determine collabora URL of remote server ' . $remote . ' - Remote is not a trusted server'); return null; } diff --git a/lib/TemplateManager.php b/lib/TemplateManager.php index 2c5e33bb..5edd0d16 100644 --- a/lib/TemplateManager.php +++ b/lib/TemplateManager.php @@ -424,18 +424,16 @@ class TemplateManager { * @return Folder */ private function getSystemTemplateDir() { - return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null)) - ->get('richdocuments') - ->get('templates'); + $path = 'appdata_' . $this->config->getSystemValue('instanceid', null) . '/richdocuments/templates'; + return $this->rootFolder->get($path); } /** * @return Folder */ private function getEmptyTemplateDir() { - return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null)) - ->get('richdocuments') - ->get('empty_templates'); + $path = 'appdata_' . $this->config->getSystemValue('instanceid', null) . '/richdocuments/empty_templates'; + return $this->rootFolder->get($path); } /** |