Passed
Push — develop ( 169afe...f2bd80 )
by Jens
02:39
created

CmsComponent::searchRouting()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace library\components {
3
4
	use library\components\cms\ConfigurationRouting;
5
	use library\components\cms\DocumentRouting;
6
	use library\components\cms\FilesRouting;
7
	use library\components\cms\ImagesRouting;
8
	use library\components\cms\SearchRouting;
9
	use library\components\cms\SitemapRouting;
10
	use library\crypt\Crypt;
11
	use library\storage\JsonStorage;
12
13
	class CmsComponent extends BaseComponent
14
	{
15
		/**
16
		 * @var \library\storage\JsonStorage
17
		 */
18
		public $storage;
19
20
		const INVALID_CREDENTIALS_MESSAGE = 'Invalid username / password combination';
21
22
		const MAIN_NAV_CLASS = 'default';
23
24
		const PARAMETER_APPLICATION_COMPONENT = 'applicationComponent';
25
		const PARAMETER_APPLICATION_COMPONENTS = 'applicationComponents';
26
		const PARAMETER_BLACKLIST_IPS = 'blacklistIps';
27
		const PARAMETER_BODY = 'body';
28
		const PARAMETER_BRICK = 'brick';
29
		const PARAMETER_BRICKS = 'bricks';
30
		const PARAMETER_CMS_PREFIX = 'cmsPrefix';
31
		const PARAMETER_CONFIGURATION = 'configuration';
32
		const PARAMETER_DOCUMENT = 'document';
33
		const PARAMETER_DOCUMENTS = 'documents';
34
		const PARAMETER_DOCUMENT_TYPE = 'documentType';
35
		const PARAMETER_DOCUMENT_TYPES = 'documentTypes';
36
		const PARAMETER_ERROR_MESSAGE = 'errorMsg';
37
		const PARAMETER_FILES = 'files';
38
		const PARAMETER_FOLDER = 'folder';
39
		const PARAMETER_IMAGE = 'image';
40
		const PARAMETER_IMAGES = 'images';
41
		const PARAMETER_IMAGE_SET = 'imageSet';
42
		const PARAMETER_MAIN_NAV_CLASS = 'mainNavClass';
43
		const PARAMETER_MY_BRICK_SLUG = 'myBrickSlug';
44
		const PARAMETER_SEARCH = 'search';
45
		const PARAMETER_SEARCH_LOG = "searchLog";
46
		const PARAMETER_SEARCH_NEEDS_UPDATE = "searchNeedsUpdate";
47
		const PARAMETER_SITEMAP = 'sitemap';
48
		const PARAMETER_SITEMAP_ITEM = 'sitemapItem';
49
		const PARAMETER_SMALLEST_IMAGE = 'smallestImage';
50
		const PARAMETER_STATIC = 'static';
51
		const PARAMETER_USER = 'user';
52
		const PARAMETER_USERS = 'users';
53
		const PARAMETER_USER_RIGHTS = 'userRights';
54
		const PARAMETER_WHITELIST_IPS = 'whitelistIps';
55
56
		const POST_PARAMETER_COMPONENT = 'component';
57
		const POST_PARAMETER_PASSWORD = 'password';
58
		const POST_PARAMETER_SAVE = 'save';
59
		const POST_PARAMETER_TEMPLATE = 'template';
60
		const POST_PARAMETER_TITLE = 'title';
61
		const POST_PARAMETER_USERNAME = 'username';
62
63
		const GET_PARAMETER_PATH = 'path';
64
		const GET_PARAMETER_SLUG = 'slug';
65
66
		const FILES_PARAMETER_FILE = 'file';
67
68
		const SESSION_PARAMETER_CLOUD_CONTROL = 'cloudcontrol';
69
70
		const LOGIN_TEMPLATE_PATH = 'cms/login';
71
72
		const CONTENT_TYPE_APPLICATION_JSON = 'Content-type:application/json';
73
74
		public $subTemplate = null;
75
76
77
		/**
78
		 * @param JsonStorage $storage
79
		 *
80
		 * @return void
81
		 */
82
		public function run(JsonStorage $storage)
83
		{
84
			$this->parameters[self::PARAMETER_MAIN_NAV_CLASS] = self::MAIN_NAV_CLASS;
85
			$this->storage = $storage;
86
87
			$remoteAddress = $_SERVER['REMOTE_ADDR'];
88
			$this->checkWhiteList($remoteAddress);
89
			$this->checkBlackList($remoteAddress);
90
91
			$this->checkLogin();
92
93
			$this->parameters[self::PARAMETER_USER_RIGHTS] = $_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL]->rights;
94
95
			$this->routing();
96
		}
97
98
		/**
99
		 * See if a user is logged or wants to log in and
100
		 * takes appropriate actions.
101
		 *
102
		 * @throws \Exception
103
		 */
104
		protected function checkLogin()
105
		{
106
			$request = $this->request;
107
108
			if (!isset($_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL])) {
109
				if (isset($request::$post[self::POST_PARAMETER_USERNAME], $request::$post[self::POST_PARAMETER_PASSWORD])) {
110
					$this->checkLoginAttempt($request);
111
				} else {
112
					$this->showLogin();
113
				}
114
			}
115
		}
116
117
		/**
118
		 * Overrides normal behaviour and only renders the
119
		 * login screen
120
		 *
121
		 * @throws \Exception
122
		 */
123
		protected function showLogin()
124
		{
125
			$loginTemplatePath = self::LOGIN_TEMPLATE_PATH;
126
			$this->renderTemplate($loginTemplatePath);
127
			ob_end_flush();
128
			exit;
129
		}
130
131
		/**
132
		 * As an exception, to keep the initial file structure simple
133
		 * the cms implements it's own routing, apart from the regular sitemap functionality
134
		 *
135
		 * @throws \Exception
136
		 */
137
		protected function routing()
138
		{
139
			$relativeCmsUri = $this->getRelativeCmsUri($this->request);
140
141
			$userRights = $_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL]->rights;
142
143
			$this->dashboardRouting($relativeCmsUri);
144
			$this->logOffRouting($this->request, $relativeCmsUri);
145
			$this->apiRouting($relativeCmsUri);
146
			$this->documentRouting($userRights, $relativeCmsUri);
147
			$this->sitemapRouting($userRights, $relativeCmsUri);
148
			$this->imageRouting($userRights, $relativeCmsUri);
149
			$this->filesRouting($userRights, $relativeCmsUri);
150
			$this->configurationRouting($userRights, $relativeCmsUri);
151
			$this->searchRouting($userRights, $relativeCmsUri);
152
153
			$this->renderBody();
154
		}
155
156
		/**
157
		 * @param $remoteAddress
158
		 *
159
		 * @throws \Exception
160
		 */
161 View Code Duplication
		private function checkWhiteList($remoteAddress)
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...
162
		{
163
			if (isset($this->parameters[self::PARAMETER_WHITELIST_IPS])) {
164
				$whitelistIps = explode(',', $this->parameters[self::PARAMETER_WHITELIST_IPS]);
165
				$whitelistIps = array_map("trim", $whitelistIps);
166
				if (!in_array($remoteAddress, $whitelistIps)) {
167
					throw new \Exception('Ip address ' . $remoteAddress . ' is not on whitelist');
168
				}
169
			}
170
		}
171
172
		/**
173
		 * @param $remoteAddress
174
		 *
175
		 * @throws \Exception
176
		 */
177 View Code Duplication
		private function checkBlackList($remoteAddress)
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...
178
		{
179
			if (isset($this->parameters[self::PARAMETER_BLACKLIST_IPS])) {
180
				$blacklistIps = explode(',', $this->parameters[self::PARAMETER_BLACKLIST_IPS]);
181
				$blacklistIps = array_map("trim", $blacklistIps);
182
				if (in_array($remoteAddress, $blacklistIps)) {
183
					throw new \Exception('Ip address ' . $remoteAddress . ' is on blacklist');
184
				}
185
			}
186
		}
187
188
		/**
189
		 * @param $request
190
		 *
191
		 * @return mixed|string
192
		 */
193
		private function getRelativeCmsUri($request)
194
		{
195
			// TODO Use regex match parameter instead of calculating relative uri
196
			$pos = strpos($request::$relativeUri, $this->parameters[self::PARAMETER_CMS_PREFIX]);
197
			$relativeCmsUri = '/';
198
			if ($pos !== false) {
199
				$relativeCmsUri = substr_replace($request::$relativeUri, '', $pos, strlen($this->parameters[self::PARAMETER_CMS_PREFIX]));
200
			}
201
202
			return $relativeCmsUri;
203
		}
204
205
		/**
206
		 * @param $relativeCmsUri
207
		 */
208
		private function apiRouting($relativeCmsUri)
209
		{
210
			if ($relativeCmsUri == '/images.json') {
211
				header(self::CONTENT_TYPE_APPLICATION_JSON);
212
				die(json_encode($this->storage->getImages()));
213
			} elseif ($relativeCmsUri == '/files.json') {
214
				header(self::CONTENT_TYPE_APPLICATION_JSON);
215
				die(json_encode($this->storage->getFiles()));
216
			} elseif ($relativeCmsUri == '/documents.json') {
217
				header(self::CONTENT_TYPE_APPLICATION_JSON);
218
				die(json_encode($this->storage->getDocuments()));
219
			}
220
		}
221
222
		private function logOffRouting($request, $relativeCmsUri)
223
		{
224
			if ($relativeCmsUri == '/log-off') {
225
				$_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL] = null;
226
				unset($_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL]);
227
				header('Location: ' . $request::$subfolders . $this->parameters[self::PARAMETER_CMS_PREFIX]);
228
				exit;
229
			}
230
		}
231
232
		public function setParameter($parameterName, $parameterValue)
233
		{
234
			$this->parameters[$parameterName] = $parameterValue;
235
		}
236
237
		public function getParameter($parameterName)
238
		{
239
			return $this->parameters[$parameterName];
240
		}
241
242
		/**
243
		 * @param $relativeCmsUri
244
		 */
245
		protected function dashboardRouting($relativeCmsUri)
246
		{
247
			if ($relativeCmsUri == '' || $relativeCmsUri == '/') {
248
				$this->subTemplate = 'cms/dashboard';
249
			}
250
		}
251
252
		/**
253
		 * @param $userRights
254
		 * @param $relativeCmsUri
255
		 */
256
		protected function documentRouting($userRights, $relativeCmsUri)
257
		{
258
			if (in_array(self::PARAMETER_DOCUMENTS, $userRights)) {
259
				new DocumentRouting($this->request, $relativeCmsUri, $this);
260
			}
261
		}
262
263
		/**
264
		 * @param $userRights
265
		 * @param $relativeCmsUri
266
		 */
267
		protected function sitemapRouting($userRights, $relativeCmsUri)
268
		{
269
			if (in_array(self::PARAMETER_SITEMAP, $userRights)) {
270
				new SitemapRouting($this->request, $relativeCmsUri, $this);
271
			}
272
		}
273
274
		/**
275
		 * @param $userRights
276
		 * @param $relativeCmsUri
277
		 */
278
		protected function imageRouting($userRights, $relativeCmsUri)
279
		{
280
			if (in_array(self::PARAMETER_IMAGES, $userRights)) {
281
				new ImagesRouting($this->request, $relativeCmsUri, $this);
282
			}
283
		}
284
285
		/**
286
		 * @param $userRights
287
		 * @param $relativeCmsUri
288
		 */
289
		protected function filesRouting($userRights, $relativeCmsUri)
290
		{
291
			if (in_array(self::PARAMETER_FILES, $userRights)) {
292
				new FilesRouting($this->request, $relativeCmsUri, $this);
293
			}
294
		}
295
296
		/**
297
		 * @param $userRights
298
		 * @param $relativeCmsUri
299
		 */
300
		protected function configurationRouting($userRights, $relativeCmsUri)
301
		{
302
			if (in_array('configuration', $userRights)) {
303
				new ConfigurationRouting($this->request, $relativeCmsUri, $this);
304
			}
305
		}
306
307
		protected function renderBody()
308
		{
309
			if ($this->subTemplate !== null) {
310
				$this->parameters[self::PARAMETER_BODY] = $this->renderTemplate($this->subTemplate);
311
			}
312
		}
313
314
		/**
315
		 * @param $crypt
316
		 * @param $request
317
		 */
318
		protected function invalidCredentials($crypt, $request)
319
		{
320
			$crypt->encrypt($request::$post[self::POST_PARAMETER_PASSWORD], 16); // Buy time, to avoid brute forcing
321
			$this->parameters[self::PARAMETER_ERROR_MESSAGE] = self::INVALID_CREDENTIALS_MESSAGE;
322
			$this->showLogin();
323
		}
324
325
		/**
326
		 * @param $user
327
		 * @param $crypt
328
		 * @param $request
329
		 */
330
		protected function checkPassword($user, $crypt, $request)
331
		{
332
			$salt = $user->salt;
333
			$password = $user->password;
334
335
			$passwordCorrect = $crypt->compare($request::$post[self::POST_PARAMETER_PASSWORD], $password, $salt);
336
337
			if ($passwordCorrect) {
338
				$_SESSION[self::SESSION_PARAMETER_CLOUD_CONTROL] = $user;
339
			} else {
340
				$this->parameters[self::PARAMETER_ERROR_MESSAGE] = self::INVALID_CREDENTIALS_MESSAGE;
341
				$this->showLogin();
342
			}
343
		}
344
345
		/**
346
		 * @param $request
347
		 */
348
		protected function checkLoginAttempt($request)
349
		{
350
			$user = $this->storage->getUserByUsername($request::$post[self::POST_PARAMETER_USERNAME]);
351
			$crypt = new Crypt();
352
			if (empty($user)) {
353
				$this->invalidCredentials($crypt, $request);
354
			} else {
355
				$this->checkPassword($user, $crypt, $request);
356
			}
357
		}
358
359
		private function searchRouting($userRights, $relativeCmsUri)
360
		{
361
			if (in_array(self::PARAMETER_SEARCH, $userRights)) {
362
				new SearchRouting($this->request, $relativeCmsUri, $this);
363
			}
364
		}
365
	}
366
}