Completed
Push — master ( a1bada...5f4a81 )
by Julius
14s queued 10s
created

Application::addTrustedRemote()   A

Complexity

Conditions 2
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 8
cp 0
rs 9.8333
c 0
b 0
f 0
cc 2
nc 4
nop 2
crap 6
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Lukas Reschke <[email protected]>
4
 *
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\Richdocuments\AppInfo;
26
27
use OC\Files\Type\Detection;
28
use OC\Security\CSP\ContentSecurityPolicy;
29
use OCA\Federation\TrustedServers;
30
use OCA\Richdocuments\AppConfig;
31
use OCA\Richdocuments\Capabilities;
32
use OCA\Richdocuments\Preview\MSExcel;
33
use OCA\Richdocuments\Preview\MSWord;
34
use OCA\Richdocuments\Preview\OOXML;
35
use OCA\Richdocuments\Preview\OpenDocument;
36
use OCA\Richdocuments\Preview\Pdf;
37
use OCA\Richdocuments\Service\CapabilitiesService;
38
use OCA\Richdocuments\Service\FederationService;
39
use OCA\Richdocuments\WOPI\DiscoveryManager;
40
use OCA\Viewer\Event\LoadViewer;
41
use OCP\AppFramework\App;
42
use OCP\AppFramework\QueryException;
43
use OCP\EventDispatcher\IEventDispatcher;
44
use OCP\GlobalScale\IConfig;
45
use OCP\IPreview;
46
47
class Application extends App {
48
49
	const APPNAME = 'richdocuments';
50
51
	/**
52
	 * Strips the path and query parameters from the URL.
53
	 *
54
	 * @param string $url
55
	 * @return string
56
	 */
57
	private function domainOnly($url) {
58
		$parsed_url = parse_url($url);
59
		$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
60
		$host	= isset($parsed_url['host']) ? $parsed_url['host'] : '';
61
		$port	= isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
62
		return "$scheme$host$port";
63
	}
64
65
	public function __construct(array $urlParams = array()) {
66
		parent::__construct(self::APPNAME, $urlParams);
67
68
		try {
69
			/** @var IEventDispatcher $eventDispatcher */
70
			$eventDispatcher = $this->getContainer()->getServer()->query(IEventDispatcher::class);
71
			if (class_exists(LoadViewer::class)) {
72
				$eventDispatcher->addListener(LoadViewer::class, function () {
73
					\OCP\Util::addScript('richdocuments', 'viewer');
74
				});
75
			}
76
		} catch (QueryException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
77
		}
78
79
		$this->getContainer()->registerCapability(Capabilities::class);
80
	}
81
82
	public function registerProvider() {
83
		$container = $this->getContainer();
84
85
		// Register mimetypes
86
		/** @var Detection $detector */
87
		$detector = $container->query(\OCP\Files\IMimeTypeDetector::class);
88
		$detector->getAllMappings();
89
		$detector->registerType('ott','application/vnd.oasis.opendocument.text-template');
90
		$detector->registerType('ots', 'application/vnd.oasis.opendocument.spreadsheet-template');
91
		$detector->registerType('otp', 'application/vnd.oasis.opendocument.presentation-template');
92
93
		/** @var IPreview $previewManager */
94
		$previewManager = $container->query(IPreview::class);
95
96
		$previewManager->registerProvider('/application\/vnd.ms-excel/', function() use ($container) {
97
			return $container->query(MSExcel::class);
98
		});
99
100
		$previewManager->registerProvider('/application\/msword/', function() use ($container) {
101
			return $container->query(MSWord::class);
102
		});
103
104
		$previewManager->registerProvider('/application\/vnd.openxmlformats-officedocument.*/', function() use ($container) {
105
			return $container->query(OOXML::class);
106
		});
107
108
		// \OC::$server->getLogger()->debug('==== Richdocuments Application registerProvider: calling manager registerProvider:');
109
		$previewManager->registerProvider('/application\/vnd.oasis.opendocument.*/', function() use ($container) {
110
			// \OC::$server->getLogger()->debug('==== Richdocuments Application registerProvider lambda. OpenDocument::class=' . OpenDocument::class);
111
			return $container->query(OpenDocument::class);
112
		});
113
114
		$previewManager->registerProvider('/application\/pdf/', function() use ($container) {
115
			return $container->query(Pdf::class);
116
		});
117
118
	}
119
120
	public function updateCSP() {
121
		$container = $this->getContainer();
122
123
		$publicWopiUrl = $container->getServer()->getConfig()->getAppValue('richdocuments', 'public_wopi_url', '');
124
		$publicWopiUrl = $publicWopiUrl === '' ? \OC::$server->getConfig()->getAppValue('richdocuments', 'wopi_url') : $publicWopiUrl;
125
		$cspManager = $container->getServer()->getContentSecurityPolicyManager();
126
		$policy = new ContentSecurityPolicy();
127
		if ($publicWopiUrl !== '') {
128
			$policy->addAllowedFrameDomain('\'self\'');
129
			$policy->addAllowedFrameDomain($this->domainOnly($publicWopiUrl));
130
			if (method_exists($policy, 'addAllowedFormActionDomain')) {
131
				$policy->addAllowedFormActionDomain($this->domainOnly($publicWopiUrl));
132
			}
133
		}
134
135
		/**
136
		 * Dynamically add CSP for federated editing
137
		 */
138
		$path = '';
139
		try {
140
			$path = $container->getServer()->getRequest()->getPathInfo();
141
		} catch (\Exception $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
142
		if (strpos($path, '/apps/files') === 0 && $container->getServer()->getAppManager()->isEnabledForUser('federation')) {
143
			/** @var FederationService $federationService */
144
			$federationService = \OC::$server->query(FederationService::class);
145
146
			// Always add trusted servers on global scale
147
			/** @var IConfig $globalScale */
148
			$globalScale = $container->query(IConfig::class);
149
			if ($globalScale->isGlobalScaleEnabled()) {
150
				$trustedList = \OC::$server->getConfig()->getSystemValue('gs.trustedHosts', []);
151
				foreach ($trustedList as $server) {
152
					$this->addTrustedRemote($policy, $server);
153
				}
154
			}
155
			$remoteAccess = $container->getServer()->getRequest()->getParam('richdocuments_remote_access');
156
157
			if ($remoteAccess && $federationService->isTrustedRemote($remoteAccess)) {
158
				$this->addTrustedRemote($policy, $remoteAccess);
159
			}
160
		}
161
162
		$cspManager->addDefaultPolicy($policy);
163
	}
164
165
	private function addTrustedRemote($policy, $url) {
166
		/** @var FederationService $federationService */
167
		$federationService = \OC::$server->query(FederationService::class);
168
		try {
169
			$remoteCollabora = $federationService->getRemoteCollaboraURL($url);
170
			$policy->addAllowedFrameDomain($url);
171
			$policy->addAllowedFrameDomain($remoteCollabora);
172
		} catch (\Exception $e) {
173
			// We can ignore this exception for adding predefined domains to the CSP as it it would then just
174
			// reload the page to set a proper allowed frame domain if we don't have a fixed list of trusted
175
			// remotes in a global scale scenario
176
		}
177
	}
178
179
	public function checkAndEnableCODEServer() {
180
		// Supported only on Linux OS, and x86_64 & ARM64 platforms
181
		$supportedArchs = array('x86_64', 'aarch64');
182
		$osFamily = PHP_VERSION_ID >= 70200 ? PHP_OS_FAMILY : PHP_OS;
183
		if ($osFamily !== 'Linux' || !in_array(php_uname('m'), $supportedArchs))
184
			return;
185
186
		$CODEAppID = (php_uname('m') === 'x86_64') ? 'richdocumentscode' : 'richdocumentscode_arm64';
187
188
		if ($this->getContainer()->getServer()->getAppManager()->isEnabledForUser($CODEAppID)) {
189
			$appConfig = $this->getContainer()->query(AppConfig::class);
190
			$wopi_url = $appConfig->getAppValue('wopi_url');
191
192
			// Check if we have the wopi_url set currently
193
			if ($wopi_url !== null && $wopi_url !== '') {
194
				return;
195
			}
196
197
			$urlGenerator = \OC::$server->getURLGenerator();
198
			$relativeUrl = $urlGenerator->linkTo($CODEAppID, '') . 'proxy.php';
199
			$absoluteUrl = $urlGenerator->getAbsoluteURL($relativeUrl);
200
			$wopi_url = $absoluteUrl . '?req=';
201
202
			$appConfig->setAppValue('wopi_url', $wopi_url);
203
			$appConfig->setAppValue('disable_certificate_verification', 'yes');
204
205
			$discoveryManager = $this->getContainer()->query(DiscoveryManager::class);
206
			$capabilitiesService = $this->getContainer()->query(CapabilitiesService::class);
207
208
			$discoveryManager->refretch();
209
			$capabilitiesService->clear();
210
			$capabilitiesService->refetch();
211
		}
212
	}
213
}
214