Passed
Push — master ( 9fb1d9...8460a0 )
by Maxence
02:20
created

Website::getRelativePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
1
<?php
2
/**
3
 * CMS Pico - Integration of Pico within your files to create websites.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\CMSPico\Model;
28
29
use OC\Files\View;
30
use OCA\CMSPico\AppInfo\Application;
31
use OCA\CMSPico\Exceptions\CheckCharsException;
32
use OCA\CMSPico\Exceptions\ContentDirIsNotLocalException;
33
use OCA\CMSPico\Exceptions\MinCharsException;
34
use OCA\CMSPico\Exceptions\PathContainSpecificFoldersException;
35
use OCA\CMSPico\Exceptions\UserIsNotOwnerException;
36
use OCA\CMSPico\Exceptions\WebpageDoesNotExistException;
37
use OCA\CMSPico\Exceptions\WebsiteIsPrivateException;
38
use OCA\CMSPico\Service\MiscService;
39
use OCP\Files\IRootFolder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\IRootFolder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
use OCP\Files\NotFoundException;
0 ignored issues
show
Bug introduced by
The type OCP\Files\NotFoundException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
use OCP\IL10N;
42
43
class Website extends WebsiteCore {
44
45
46
	const TYPE_PUBLIC = 1;
47
	const TYPE_PRIVATE = 2;
48
49
	const SITE_LENGTH_MIN = 3;
50
	const NAME_LENGTH_MIN = 5;
51
52
	/** @var IL10N */
53
	private $l10n;
54
55
	/** @var IRootFolder */
56
	private $rootFolder;
57
58
	/** @var string */
59
	private $viewer;
60
61
	/** @var string */
62
	private $templateSource;
63
64
	/** @var View */
65
	private $ownerView;
66
67
68
	public function __construct() {
69
		$this->l10n = \OC::$server->getL10N(Application::APP_NAME);
70
		$this->rootFolder = \OC::$server->getRootFolder();
71
72
		parent::__construct();
73
	}
74
75
76
	private function initSiteOwnerView() {
77
78
		if ($this->ownerView !== null) {
79
			return;
80
		}
81
82
		$this->ownerView = new View($this->getUserId() . '/files/');
83
	}
84
85
86
	/**
87
	 * @return string
88
	 */
89
	public function getAbsolutePath() {
90
91
		$this->initSiteOwnerView();
92
93
		$path = $this->ownerView->getLocalFile($this->getPath());
94
		MiscService::endSlash($path);
95
96
		return $path;
97
	}
98
99
100
	/**
101
	 * @param string $local
102
	 *
103
	 * @return false|\OC\Files\FileInfo
104
	 */
105
	public function isReadableByViewer($local = '') {
106
107
		$fileId = $this->getPageFileId($local);
108
		$viewerFiles = $this->rootFolder->getUserFolder($this->getViewer())
109
										->getById($fileId);
110
111
		foreach ($viewerFiles as $file) {
112
			if ($file->isReadable()) {
113
				return true;
114
			}
115
		}
116
117
		return false;
118
	}
119
120
121
	/**
122
	 * @param string $local
123
	 *
124
	 * @return int
125
	 * @throws WebpageDoesNotExistException
126
	 */
127
	public function getPageFileId($local = '') {
128
129
		try {
130
			$ownerFile = $this->rootFolder->getUserFolder($this->getUserId())
131
										  ->get($this->getPath() . $local);
132
133
			return $ownerFile->getId();
134
		} catch (NotFoundException $e) {
135
			throw new WebpageDoesNotExistException($this->l10n->t('Webpage does not exist'));
136
		}
137
	}
138
139
140
	/**
141
	 * @param string $viewer
142
	 */
143
	public function setViewer($viewer) {
144
		$this->viewer = $viewer;
145
	}
146
147
	/**
148
	 * @return string
149
	 */
150
	public function getViewer() {
151
		return $this->viewer;
152
	}
153
154
155
	/**
156
	 * @param string $source
157
	 */
158
	public function setTemplateSource($source) {
159
		$this->templateSource = $source;
160
	}
161
162
	/**
163
	 * @return string
164
	 */
165
	public function getTemplateSource() {
166
		return $this->templateSource;
167
	}
168
169
170
	/**
171
	 * @param $userId
172
	 *
173
	 * @throws UserIsNotOwnerException
174
	 */
175
	public function hasToBeOwnedBy($userId) {
176
		if ($this->getUserId() !== $userId) {
177
			throw new UserIsNotOwnerException($this->l10n->t('You are not the owner of this website'));
178
		}
179
	}
180
181
182
	public function contentMustBeLocal($path) {
183
184
		if (strpos($path, $this->getAbsolutePath()) !== 0 || strpos($path, '..') !== false) {
185
			throw new ContentDirIsNotLocalException($this->l10n->t('Content Directory is not valid.'));
186
		}
187
188
	}
189
190
191
	public function getRelativePath($path) {
192
		if (substr($path, 0, 1) !== '/') {
193
			return $path;
194
		}
195
196
		return substr($path, strlen($this->getAbsolutePath()));
197
	}
198
199
	/**
200
	 * @param string $local
201
	 * @param array $meta
202
	 *
203
	 * @throws WebsiteIsPrivateException
204
	 */
205
	public function viewerMustHaveAccess($local, $meta) {
206
207
		$relativePath = $this->getRelativePath($local);
208
		if ($this->pageIsPublic($meta)) {
209
			return;
210
		}
211
212
		if ($this->getViewer() === $this->getUserId()
213
			|| $this->isReadableByViewer($relativePath)) {
214
			return;
215
		}
216
217
		throw new WebsiteIsPrivateException(
218
			$this->l10n->t('Website is private. You do not have access to this website')
219
		);
220
	}
221
222
223
	/**
224
	 * @param array $meta
225
	 *
226
	 * @return bool
227
	 */
228
	private function pageIsPublic($meta) {
229
230
		if (key_exists('access', $meta) && strtolower($meta['access']) === 'private') {
231
			return false;
232
		}
233
234
		if ($this->getOption('private') === '1') {
235
			return false;
236
		}
237
238
		return true;
239
	}
240
241
242
	/**
243
	 * @throws CheckCharsException
244
	 * @throws MinCharsException
245
	 * @throws PathContainSpecificFoldersException
246
	 */
247
	public function hasToBeFilledWithValidEntries() {
248
249
		$this->hasToBeFilledWithNonEmptyValues();
250
		$this->pathCantContainSpecificFolders();
251
252
		if (MiscService::checkChars($this->getSite(), MiscService::ALPHA_NUMERIC_SCORES) === false) {
253
			throw new CheckCharsException(
254
				$this->l10n->t('The address of the website can only contains alpha numeric chars')
255
			);
256
		}
257
	}
258
259
260
	/**
261
	 * @throws MinCharsException
262
	 */
263
	private function hasToBeFilledWithNonEmptyValues() {
264
		if (strlen($this->getSite()) < self::SITE_LENGTH_MIN) {
265
			throw new MinCharsException($this->l10n->t('The address of the website must be longer'));
266
		}
267
268
		if (strlen($this->getName()) < self::NAME_LENGTH_MIN) {
269
			throw new MinCharsException($this->l10n->t('The name of the website must be longer'));
270
		}
271
	}
272
273
274
	/**
275
	 * this is overkill - NC does not allow to create directory outside of the users' filesystem
276
	 * Not sure that there is a single use for this security check
277
	 *
278
	 * @throws PathContainSpecificFoldersException
279
	 */
280
	private function pathCantContainSpecificFolders() {
281
		$limit = ['.', '..'];
282
283
		$folders = explode('/', $this->getPath());
284
		foreach ($folders as $folder) {
285
			if (in_array($folder, $limit)) {
286
				throw new PathContainSpecificFoldersException(
287
					$this->l10n->t('Path is malformed, please check.')
288
				);
289
			}
290
		}
291
	}
292
}