Completed
Push — master ( f2b8d7...c7becd )
by Roeland
11:44 queued 10:17
created

DocumentController::template()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 0
cts 33
cp 0
rs 9.296
c 0
b 0
f 0
cc 4
nc 4
nop 3
crap 20
1
<?php
2
/**
3
 * ownCloud - Richdocuments App
4
 *
5
 * @author Victor Dubiniuk
6
 * @copyright 2014 Victor Dubiniuk [email protected]
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later.
10
 */
11
12
namespace OCA\Richdocuments\Controller;
13
14
use OCA\Richdocuments\TokenManager;
15
use OCA\Richdocuments\WOPI\Parser;
16
use \OCP\AppFramework\Controller;
17
use OCP\AppFramework\Http;
18
use OCP\AppFramework\Http\JSONResponse;
19
use OCP\Files\Folder;
20
use OCP\Files\IRootFolder;
21
use OCP\Files\Node;
22
use OCP\Files\NotFoundException;
23
use OCP\Files\NotPermittedException;
24
use \OCP\IRequest;
25
use \OCP\IConfig;
26
use \OCP\IL10N;
27
use \OCP\ILogger;
28
use \OCP\AppFramework\Http\ContentSecurityPolicy;
29
use \OCP\AppFramework\Http\TemplateResponse;
30
use \OCA\Richdocuments\AppConfig;
31
use \OCA\Richdocuments\Helper;
32
use OCP\ISession;
33
use OCP\Share\IManager;
34
use OC\Files\Type\TemplateManager;
35
36
class DocumentController extends Controller {
37
	/** @var string */
38
	private $uid;
39
	/** @var IL10N */
40
	private $l10n;
41
	/** @var IConfig */
42
	private $settings;
43
	/** @var AppConfig */
44
	private $appConfig;
45
	/** @var ILogger */
46
	private $logger;
47
	/** @var IManager */
48
	private $shareManager;
49
	/** @var TokenManager */
50
	private $tokenManager;
51
	/** @var ISession */
52
	private $session;
53
	/** @var IRootFolder */
54
	private $rootFolder;
55
	/** @var \OCA\Richdocuments\TemplateManager */
56
	private $templateManager;
57
58
	const ODT_TEMPLATE_PATH = '/assets/odttemplate.odt';
59
60
61
	/**
62
	 * @param string $appName
63
	 * @param IRequest $request
64
	 * @param IConfig $settings
65
	 * @param AppConfig $appConfig
66
	 * @param IL10N $l10n
67
	 * @param IManager $shareManager
68
	 * @param TokenManager $tokenManager
69
	 * @param IRootFolder $rootFolder
70
	 * @param ISession $session
71
	 * @param string $UserId
72
	 * @param ILogger $logger
73
	 */
74 View Code Duplication
	public function __construct($appName,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
75
								IRequest $request,
76
								IConfig $settings,
77
								AppConfig $appConfig,
78
								IL10N $l10n,
79
								IManager $shareManager,
80
								TokenManager $tokenManager,
81
								IRootFolder $rootFolder,
82
								ISession $session,
83
								$UserId,
84
								ILogger $logger,
85
								\OCA\Richdocuments\TemplateManager $templateManager) {
86
		parent::__construct($appName, $request);
87
		$this->uid = $UserId;
88
		$this->l10n = $l10n;
89
		$this->settings = $settings;
90
		$this->appConfig = $appConfig;
91
		$this->shareManager = $shareManager;
92
		$this->tokenManager = $tokenManager;
93
		$this->rootFolder = $rootFolder;
94
		$this->session = $session;
95
		$this->logger = $logger;
96
		$this->templateManager = $templateManager;
97
	}
98
99
	/**
100
	 * @PublicPage
101
	 * @NoCSRFRequired
102
	 *
103
	 * Returns the access_token and urlsrc for WOPI access for given $fileId
104
	 * Requests is accepted only when a secret_token is provided set by admin in
105
	 * settings page
106
	 *
107
	 * @param string $fileId
108
	 * @return access_token, urlsrc
0 ignored issues
show
Documentation introduced by
The doc-type access_token, could not be parsed: Expected "|" or "end of type", but got "," at position 12. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
109
	 */
110
	public function extAppGetData($fileId) {
111
		$secretToken = $this->request->getParam('secret_token');
112
		$apps = array_filter(explode(',', $this->appConfig->getAppValue('external_apps')));
113
		foreach($apps as $app) {
114
			if ($app !== '' && $secretToken === $app) {
115
				$appName = explode(':', $app);
116
				$this->logger->debug('External app "{extApp}" authenticated; issuing access token for fileId {fileId}', [
117
					'app' => $this->appName,
118
					'extApp' => $appName[0],
119
					'fileId' => $fileId
120
				]);
121
				try {
122
					$folder = $this->rootFolder->getUserFolder($this->uid);
123
					$item = $folder->getById($fileId)[0];
124
					if(!($item instanceof Node)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Node does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
125
						throw new \Exception();
126
					}
127
					list($urlSrc, $token) = $this->tokenManager->getToken($item->getId());
128
					return [
129
						'status' => 'success',
130
						'urlsrc' => $urlSrc,
131
						'token' => $token
132
					];
133
				} catch (\Exception $e) {
134
					$this->logger->logException($e, ['app'=>'richdocuments']);
135
					$params = [
136
						'remoteAddr' => $this->request->getRemoteAddress(),
137
						'requestID' => $this->request->getId(),
138
						'debugMode' => $this->settings->getSystemValue('debug'),
139
						'errorClass' => get_class($e),
140
						'errorCode' => $e->getCode(),
141
						'errorMsg' => $e->getMessage(),
142
						'file' => $e->getFile(),
143
						'line' => $e->getLine(),
144
						'trace' => $e->getTraceAsString()
145
					];
146
					return new TemplateResponse('core', 'exception', $params, 'guest');
147
				}
148
			}
149
150
			return [
151
				'status' => 'error',
152
				'message' => 'Permission denied'
153
			];
154
		}
155
	}
156
157
	/**
158
	 * Strips the path and query parameters from the URL.
159
	 *
160
	 * @param string $url
161
	 * @return string
162
	 */
163
	private function domainOnly($url) {
164
		$parsed_url = parse_url($url);
165
		$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
166
		$host   = isset($parsed_url['host']) ? $parsed_url['host'] : '';
167
		$port   = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
168
		return "$scheme$host$port";
169
	}
170
171
	/**
172
	 * @NoAdminRequired
173
	 *
174
	 * @param string $fileId
175
	 * @return TemplateResponse
176
	 */
177
	public function index($fileId) {
178
		try {
179
			$folder = $this->rootFolder->getUserFolder($this->uid);
180
			$item = $folder->getById($fileId)[0];
181
			if(!($item instanceof Node)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Node does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
182
				throw new \Exception();
183
			}
184
			list($urlSrc, $token) = $this->tokenManager->getToken($item->getId());
185
			$params = [
186
				'permissions' => $item->getPermissions(),
187
				'title' => $item->getName(),
188
				'fileId' => $item->getId() . '_' . $this->settings->getSystemValue('instanceid'),
189
				'token' => $token,
190
				'urlsrc' => $urlSrc,
191
				'path' => $folder->getRelativePath($item->getPath()),
192
				'instanceId' => $this->settings->getSystemValue('instanceid'),
193
				'canonical_webroot' => $this->appConfig->getAppValue('canonical_webroot'),
194
			];
195
196
			$encryptionManager = \OC::$server->getEncryptionManager();
197
			if ($encryptionManager->isEnabled())
198
			{
199
				// Update the current file to be accessible with system public shared key
200
				$owner = $item->getOwner()->getUID();
201
				$absPath = '/' . $owner . '/' .  $item->getInternalPath();
202
				$accessList = \OC::$server->getEncryptionFilesHelper()->getAccessList($absPath);
203
				$accessList['public'] = true;
204
				$encryptionManager->getEncryptionModule()->update($absPath, $owner, $accessList);
205
			}
206
207
			$response = new TemplateResponse('richdocuments', 'documents', $params, 'empty');
208
			$policy = new ContentSecurityPolicy();
209
			$policy->addAllowedFrameDomain($this->domainOnly($this->appConfig->getAppValue('wopi_url')));
210
			$policy->allowInlineScript(true);
211
			$response->setContentSecurityPolicy($policy);
212
			return $response;
213
		} catch (\Exception $e) {
214
			$this->logger->logException($e, ['app'=>'richdocuments']);
215
			$params = [
216
				'remoteAddr' => $this->request->getRemoteAddress(),
217
				'requestID' => $this->request->getId(),
218
				'debugMode' => $this->settings->getSystemValue('debug'),
219
				'errorClass' => get_class($e),
220
				'errorCode' => $e->getCode(),
221
				'errorMsg' => $e->getMessage(),
222
				'file' => $e->getFile(),
223
				'line' => $e->getLine(),
224
				'trace' => $e->getTraceAsString()
225
			];
226
			return new TemplateResponse('core', 'exception', $params, 'guest');
227
		}
228
229
		return new TemplateResponse('core', '403', [], 'guest');
0 ignored issues
show
Unused Code introduced by
return new \OCP\AppFrame...03', array(), 'guest'); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
230
	}
231
232
	/**
233
	 * @NoAdminRequired
234
	 *
235
	 * @param int $templateId
236
	 * @param string $fileName
237
	 * @param string $dir
238
	 * @return TemplateResponse
239
	 */
240
	public function template($templateId, $fileName, $dir) {
241
		if (!$this->templateManager->isTemplate($templateId)) {
242
			return new TemplateResponse('core', '403', [], 'guest');
243
		}
244
245
		$userFolder = $this->rootFolder->getUserFolder($this->uid);
246
		try {
247
			$folder = $userFolder->get($dir);
248
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
249
			return new TemplateResponse('core', '403', [], 'guest');
250
		}
251
252
		if ((!$folder instanceof Folder)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
253
			return new TemplateResponse('core', '403', [], 'guest');
254
		}
255
256
		$file = $folder->newFile($fileName);
257
258
		$template = $this->templateManager->get($templateId);
259
		list($urlSrc, $token) = $this->tokenManager->getTokenForTemplate($template, $this->uid, $file->getId());
260
261
		$params = [
262
			'permissions' => $template->getPermissions(),
263
			'title' => $template->getName(),
264
			'fileId' => $template->getId() . '_' . $this->settings->getSystemValue('instanceid'),
265
			'token' => $token,
266
			'urlsrc' => $urlSrc,
267
			'path' => $userFolder->getRelativePath($file->getPath()),
268
			'instanceId' => $this->settings->getSystemValue('instanceid'),
269
			'canonical_webroot' => $this->appConfig->getAppValue('canonical_webroot'),
270
		];
271
272
		$response = new TemplateResponse('richdocuments', 'documents', $params, 'empty');
273
		$policy = new ContentSecurityPolicy();
274
		$policy->addAllowedFrameDomain($this->domainOnly($this->appConfig->getAppValue('wopi_url')));
275
		$policy->allowInlineScript(true);
276
		$response->setContentSecurityPolicy($policy);
277
		return $response;
278
	}
279
280
	/**
281
	 * @PublicPage
282
	 *
283
	 * @param string $shareToken
284
	 * @param string $fileName
285
	 * @return TemplateResponse
286
	 * @throws \Exception
287
	 */
288
	public function publicPage($shareToken, $fileName, $fileId) {
289
		try {
290
			$share = $this->shareManager->getShareByToken($shareToken);
291
			// not authenticated ?
292
			if($share->getPassword()){
293
				if (!$this->session->exists('public_link_authenticated')
294
					|| $this->session->get('public_link_authenticated') !== (string)$share->getId()
295
				) {
296
					throw new \Exception('Invalid password');
297
				}
298
			}
299
300
			$node = $share->getNode();
301
			if($node instanceof Folder) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
302
				$item = $node->getById($fileId)[0];
303
			} else {
304
				$item = $node;
305
			}
306
			if ($item instanceof Node) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Node does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
307
				list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), $shareToken);
308
				$params = [
309
					'permissions' => $share->getPermissions(),
310
					'title' => $item->getName(),
311
					'fileId' => $item->getId() . '_' . $this->settings->getSystemValue('instanceid'),
312
					'token' => $token,
313
					'urlsrc' => $urlSrc,
314
					'path' => '/',
315
					'instanceId' => $this->settings->getSystemValue('instanceid'),
316
					'canonical_webroot' => $this->appConfig->getAppValue('canonical_webroot'),
317
				];
318
319
				$response = new TemplateResponse('richdocuments', 'documents', $params, 'empty');
320
				$policy = new ContentSecurityPolicy();
321
				$policy->addAllowedFrameDomain($this->domainOnly($this->appConfig->getAppValue('wopi_url')));
322
				$policy->allowInlineScript(true);
323
				$response->setContentSecurityPolicy($policy);
324
				return $response;
325
			}
326
		} catch (\Exception $e) {
327
			$this->logger->logException($e, ['app'=>'richdocuments']);
328
			$params = [
329
				'remoteAddr' => $this->request->getRemoteAddress(),
330
				'requestID' => $this->request->getId(),
331
				'debugMode' => $this->settings->getSystemValue('debug'),
332
				'errorClass' => get_class($e),
333
				'errorCode' => $e->getCode(),
334
				'errorMsg' => $e->getMessage(),
335
				'file' => $e->getFile(),
336
				'line' => $e->getLine(),
337
				'trace' => $e->getTraceAsString()
338
			];
339
			return new TemplateResponse('core', 'exception', $params, 'guest');
340
		}
341
342
		return new TemplateResponse('core', '403', [], 'guest');
343
	}
344
345
	/**
346
	 * @NoAdminRequired
347
	 *
348
	 * @param string $mimetype
349
	 * @param string $filename
350
	 * @param string $dir
351
	 * @return JSONResponse
352
	 */
353
	public function create($mimetype,
354
						   $filename,
355
						   $dir = '/'){
356
357
		$root = $this->rootFolder->getUserFolder($this->uid);
358
		try {
359
			/** @var Folder $folder */
360
			$folder = $root->get($dir);
361
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
362
			return new JSONResponse([
363
					'status' => 'error',
364
					'message' => $this->l10n->t('Can\'t create document')
365
			], Http::STATUS_BAD_REQUEST);
366
		}
367
368 View Code Duplication
		if (!($folder instanceof Folder)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
369
			return new JSONResponse([
370
				'status' => 'error',
371
				'message' => $this->l10n->t('Can\'t create document')
372
			], Http::STATUS_BAD_REQUEST);
373
		}
374
375
		$basename = $this->l10n->t('New Document.odt');
376
		switch ($mimetype) {
377
			case 'application/vnd.oasis.opendocument.spreadsheet':
378
				$basename = $this->l10n->t('New Spreadsheet.ods');
379
				break;
380
			case 'application/vnd.oasis.opendocument.presentation':
381
				$basename = $this->l10n->t('New Presentation.odp');
382
				break;
383
			case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
384
				$basename = $this->l10n->t('New Document.docx');
385
				break;
386
			case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
387
				$basename = $this->l10n->t('New Spreadsheet.xlsx');
388
				break;
389
			case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
390
				$basename = $this->l10n->t('New Presentation.pptx');
391
				break;
392
			default:
393
				// to be safe
394
				$mimetype = 'application/vnd.oasis.opendocument.text';
395
				break;
396
		}
397
398
		if (!$filename){
399
			$filename = Helper::getNewFileName($folder, $basename);
400
		}
401
402 View Code Duplication
		if ($folder->nodeExists($filename)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
403
			return new JSONResponse([
404
				'status' => 'error',
405
				'message' => $this->l10n->t('Document already exists')
406
			], Http::STATUS_BAD_REQUEST);
407
		}
408
409
		try {
410
			$file = $folder->newFile($filename);
411
		} catch (NotPermittedException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotPermittedException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
412
			return new JSONResponse([
413
				'status' => 'error',
414
				'message' => $this->l10n->t('Not allowed to create document')
415
			], Http::STATUS_BAD_REQUEST);
416
		}
417
418
		$content = '';
419
		if (class_exists(TemplateManager::class)){
420
			$manager = \OC_Helper::getFileTemplateManager();
421
			$content = $manager->getTemplate($mimetype);
422
		}
423
424
		if (!$content){
425
			$content = file_get_contents(dirname(dirname(__DIR__)) . self::ODT_TEMPLATE_PATH);
426
		}
427
428
		if ($content) {
429
			$file->putContent($content);
430
431
			return new JSONResponse([
432
				'status' => 'success',
433
				'data' => \OCA\Files\Helper::formatFileInfo($file->getFileInfo())
434
			]);
435
		}
436
437
438
		return new JSONResponse([
439
			'status' => 'error',
440
			'message' => $this->l10n->t('Can\'t create document')
441
		]);
442
	}
443
}
444