Passed
Push — develop ( de6037...adf684 )
by Jens
05:36
created

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

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
391
        {
392
            new SearchRouting($this->request, $relativeCmsUri, $this);
393
        }
394
395
        protected function getTemplateDir($template, $application = null)
396
        {
397
            return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . $template . '.php';
398
        }
399
400
        private function redirectRouting($userRights, $relativeCmsUri)
401
        {
402
            if (in_array(self::PARAMETER_SITEMAP, $userRights)) {
403
                new RedirectRouting($this->request, $relativeCmsUri, $this);
404
            }
405
        }
406
    }
407
}