1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace CloudControl\Cms\components { |
4
|
|
|
|
5
|
|
|
use CloudControl\Cms\components\cms\BaseRouting; |
6
|
|
|
use CloudControl\Cms\components\cms\CmsConstants; |
7
|
|
|
use CloudControl\Cms\crypt\Crypt; |
8
|
|
|
use CloudControl\Cms\storage\Storage; |
9
|
|
|
|
10
|
|
|
class CmsComponent extends BaseComponent |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* @var \CloudControl\Cms\storage\Storage |
14
|
|
|
*/ |
15
|
|
|
public $storage; |
16
|
|
|
|
17
|
|
|
public $subTemplate; |
18
|
|
|
|
19
|
|
|
public $autoUpdateSearchIndex = true; |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @param Storage $storage |
24
|
|
|
* |
25
|
|
|
* @return void |
26
|
|
|
* @throws \Exception |
27
|
|
|
*/ |
28
|
|
|
public function run(Storage $storage) |
29
|
|
|
{ |
30
|
|
|
$this->setParameter(CmsConstants::PARAMETER_MAIN_NAV_CLASS, CmsConstants::MAIN_NAV_CLASS); |
31
|
|
|
$this->storage = $storage; |
32
|
|
|
|
33
|
|
|
$remoteAddress = $_SERVER['REMOTE_ADDR']; |
34
|
|
|
$this->checkWhiteList($remoteAddress); |
35
|
|
|
$this->checkBlackList($remoteAddress); |
36
|
|
|
|
37
|
|
|
$this->checkAutoUpdateSearchIndex(); |
38
|
|
|
|
39
|
|
|
$this->checkLogin(); |
40
|
|
|
|
41
|
|
|
$this->setParameter(CmsConstants::PARAMETER_USER_RIGHTS, $_SESSION[CmsConstants::SESSION_PARAMETER_CLOUD_CONTROL]->rights); |
42
|
|
|
|
43
|
|
|
$this->routing(); |
44
|
|
|
|
45
|
|
|
$this->renderBody(); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* See if a user is logged or wants to log in and |
50
|
|
|
* takes appropriate actions. |
51
|
|
|
* |
52
|
|
|
* @throws \Exception |
53
|
|
|
*/ |
54
|
|
|
protected function checkLogin() |
55
|
|
|
{ |
56
|
|
|
$request = $this->request; |
57
|
|
|
|
58
|
|
|
if (!isset($_SESSION[CmsConstants::SESSION_PARAMETER_CLOUD_CONTROL])) { |
59
|
|
|
if (isset($request::$post[CmsConstants::POST_PARAMETER_USERNAME], $request::$post[CmsConstants::POST_PARAMETER_PASSWORD])) { |
60
|
|
|
$this->checkLoginAttempt($request); |
61
|
|
|
} else { |
62
|
|
|
$this->showLogin(); |
63
|
|
|
} |
64
|
|
|
} |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Overrides normal behaviour and only renders the |
69
|
|
|
* login screen |
70
|
|
|
* |
71
|
|
|
* @throws \Exception |
72
|
|
|
*/ |
73
|
|
|
protected function showLogin() |
74
|
|
|
{ |
75
|
|
|
$loginTemplatePath = CmsConstants::LOGIN_TEMPLATE_PATH; |
76
|
|
|
$this->renderTemplate($loginTemplatePath); |
77
|
|
|
ob_end_flush(); |
78
|
|
|
exit; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* As an exception, to keep the initial file structure simple |
83
|
|
|
* the cms implements it's own routing, apart from the regular sitemap functionality |
84
|
|
|
* |
85
|
|
|
* @throws \Exception |
86
|
|
|
*/ |
87
|
|
|
protected function routing() |
88
|
|
|
{ |
89
|
|
|
$relativeCmsUri = $this->getRelativeCmsUri($this->request); |
90
|
|
|
$userRights = $_SESSION[CmsConstants::SESSION_PARAMETER_CLOUD_CONTROL]->rights; |
91
|
|
|
|
92
|
|
|
$baseRouting = new BaseRouting($this->request, $relativeCmsUri, $this); |
93
|
|
|
$baseRouting->setUserRights($userRights); |
94
|
|
|
$baseRouting->route(); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @param $remoteAddress |
99
|
|
|
* |
100
|
|
|
* @throws \Exception |
101
|
|
|
*/ |
102
|
|
View Code Duplication |
protected function checkWhiteList($remoteAddress) |
|
|
|
|
103
|
|
|
{ |
104
|
|
|
if (isset($this->parameters[CmsConstants::PARAMETER_WHITELIST_IPS])) { |
105
|
|
|
$whitelistIps = explode(',', $this->parameters[CmsConstants::PARAMETER_WHITELIST_IPS]); |
106
|
|
|
$whitelistIps = array_map("trim", $whitelistIps); |
107
|
|
|
if (!in_array($remoteAddress, $whitelistIps)) { |
108
|
|
|
throw new \Exception('Ip address ' . $remoteAddress . ' is not on whitelist'); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @param $remoteAddress |
115
|
|
|
* |
116
|
|
|
* @throws \Exception |
117
|
|
|
*/ |
118
|
|
View Code Duplication |
protected function checkBlackList($remoteAddress) |
|
|
|
|
119
|
|
|
{ |
120
|
|
|
if (isset($this->parameters[CmsConstants::PARAMETER_BLACKLIST_IPS])) { |
121
|
|
|
$blacklistIps = explode(',', $this->parameters[CmsConstants::PARAMETER_BLACKLIST_IPS]); |
122
|
|
|
$blacklistIps = array_map("trim", $blacklistIps); |
123
|
|
|
if (in_array($remoteAddress, $blacklistIps)) { |
124
|
|
|
throw new \Exception('Ip address ' . $remoteAddress . ' is on blacklist'); |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @param $request |
131
|
|
|
* |
132
|
|
|
* @return mixed|string |
133
|
|
|
*/ |
134
|
|
|
protected function getRelativeCmsUri($request) |
135
|
|
|
{ |
136
|
|
|
// TODO Use regex match parameter instead of calculating relative uri |
137
|
|
|
$pos = strpos($request::$relativeUri, $this->parameters[CmsConstants::PARAMETER_CMS_PREFIX]); |
138
|
|
|
$relativeCmsUri = '/'; |
139
|
|
|
if ($pos !== false) { |
140
|
|
|
$relativeCmsUri = substr_replace($request::$relativeUri, '', $pos, strlen($this->parameters[CmsConstants::PARAMETER_CMS_PREFIX])); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
return $relativeCmsUri; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* @param $parameterName |
148
|
|
|
* @param $parameterValue |
149
|
|
|
*/ |
150
|
|
|
public function setParameter($parameterName, $parameterValue) |
151
|
|
|
{ |
152
|
|
|
$this->parameters[$parameterName] = $parameterValue; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @param $parameterName |
157
|
|
|
* @return mixed |
158
|
|
|
*/ |
159
|
|
|
public function getParameter($parameterName) |
160
|
|
|
{ |
161
|
|
|
return $this->parameters[$parameterName]; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @throws \Exception |
166
|
|
|
*/ |
167
|
|
|
protected function renderBody() |
168
|
|
|
{ |
169
|
|
|
if ($this->subTemplate !== null) { |
170
|
|
|
$this->parameters[CmsConstants::PARAMETER_BODY] = $this->renderTemplate($this->subTemplate); |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @param Crypt $crypt |
176
|
|
|
* @param Request $request |
177
|
|
|
* @throws \Exception |
178
|
|
|
*/ |
179
|
|
|
protected function invalidCredentials($crypt, $request) |
180
|
|
|
{ |
181
|
|
|
$crypt->encrypt($request::$post[CmsConstants::POST_PARAMETER_PASSWORD], 16); // Buy time, to avoid brute forcing |
182
|
|
|
$this->parameters[CmsConstants::PARAMETER_ERROR_MESSAGE] = CmsConstants::INVALID_CREDENTIALS_MESSAGE; |
183
|
|
|
$this->showLogin(); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @param $user |
188
|
|
|
* @param Crypt $crypt |
189
|
|
|
* @param Request $request |
190
|
|
|
* @throws \Exception |
191
|
|
|
*/ |
192
|
|
|
protected function checkPassword($user, $crypt, $request) |
193
|
|
|
{ |
194
|
|
|
$salt = $user->salt; |
195
|
|
|
$password = $user->password; |
196
|
|
|
|
197
|
|
|
$passwordCorrect = $crypt->compare($request::$post[CmsConstants::POST_PARAMETER_PASSWORD], $password, $salt); |
198
|
|
|
|
199
|
|
|
if ($passwordCorrect) { |
200
|
|
|
$_SESSION[CmsConstants::SESSION_PARAMETER_CLOUD_CONTROL] = $user; |
201
|
|
|
$this->storage->getActivityLog()->add('logged in', 'user'); |
202
|
|
|
} else { |
203
|
|
|
$this->parameters[CmsConstants::PARAMETER_ERROR_MESSAGE] = CmsConstants::INVALID_CREDENTIALS_MESSAGE; |
204
|
|
|
$this->showLogin(); |
205
|
|
|
} |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @param $request |
210
|
|
|
* @throws \Exception |
211
|
|
|
*/ |
212
|
|
|
protected function checkLoginAttempt($request) |
213
|
|
|
{ |
214
|
|
|
$user = $this->storage->getUsers()->getUserByUsername($request::$post[CmsConstants::POST_PARAMETER_USERNAME]); |
215
|
|
|
$crypt = new Crypt(); |
216
|
|
|
if (empty($user)) { |
217
|
|
|
$this->invalidCredentials($crypt, $request); |
218
|
|
|
} else { |
219
|
|
|
$this->checkPassword($user, $crypt, $request); |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* @param $template |
225
|
|
|
* @param null $application |
226
|
|
|
* @return string |
227
|
|
|
*/ |
228
|
|
|
protected function getTemplateDir($template, $application = null) |
229
|
|
|
{ |
230
|
|
|
return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . $template . '.php'; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
private function checkAutoUpdateSearchIndex() |
234
|
|
|
{ |
235
|
|
|
if (isset($this->parameters[CmsConstants::PARAMETER_AUTO_UPDATE_SEARCH_INDEX])) { |
236
|
|
|
$param = $this->parameters[CmsConstants::PARAMETER_AUTO_UPDATE_SEARCH_INDEX]; |
237
|
|
|
if ($param === 'false') { |
238
|
|
|
$this->autoUpdateSearchIndex = false; |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
public static function isCmsLoggedIn() |
244
|
|
|
{ |
245
|
|
|
return isset($_SESSION[CmsConstants::SESSION_PARAMETER_CLOUD_CONTROL]); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
} |
249
|
|
|
} |
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.