Test Failed
Push — 2.x ( 25acc4...469edd )
by Terry
20:00
created

User   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Test Coverage

Coverage 99.05%

Importance

Changes 9
Bugs 0 Features 0
Metric Value
wmc 26
eloc 98
c 9
b 0
f 0
dl 0
loc 243
ccs 104
cts 105
cp 0.9905
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A applyCaptchaForms() 0 18 4
B login() 0 67 6
A userLoginAsAdmin() 0 34 5
A logout() 0 23 4
A userLoginAsDemo() 0 16 3
A checkCaptchaValidation() 0 12 3
1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 * 
10
 * php version 7.1.0
11
 * 
12
 * @category  Web-security
13
 * @package   Shieldon
14
 * @author    Terry Lin <[email protected]>
15
 * @copyright 2019 terrylinooo
16
 * @license   https://github.com/terrylinooo/shieldon/blob/2.x/LICENSE MIT
17
 * @link      https://github.com/terrylinooo/shieldon
18
 * @see       https://shieldon.io
19
 */
20
21
declare(strict_types=1);
22
23
namespace Shieldon\Firewall\Panel;
24
25
use Psr\Http\Message\ResponseInterface;
26
use Shieldon\Firewall\Panel\BaseController;
27
use Shieldon\Firewall\Firewall\Captcha\CaptchaFactory;
28
use Shieldon\Firewall\Captcha\Foundation;
29
use Shieldon\Event\Event;
30
use function Shieldon\Firewall\__;
31
use function Shieldon\Firewall\get_request;
32
use function Shieldon\Firewall\get_response;
33
use function Shieldon\Firewall\get_session_instance;
34
use function Shieldon\Firewall\unset_superglobal;
35
use function password_verify;
36
37
/**
38
 * User
39
 */
40
class User extends BaseController
41
{
42
    /**
43
     *   Public methods       | Desctiotion
44
     *  ----------------------|---------------------------------------------
45
     *   login                | Display the login form.
46
     *   logout               | Remove the login status.
47
     *  ----------------------|---------------------------------------------
48
     */
49
50
    /**
51
     * Constructor.
52
     */
53 10
    public function __construct() 
54
    {
55 10
        parent::__construct();
56
    }
57
58
    /**
59
     * Login
60
     * 
61
     * @param string $mode login mode.
62
     *
63
     * @return ResponseInterface
64
     */
65 9
    public function login(): ResponseInterface
66
    {
67 9
        $this->applyCaptchaForms();
68
69 9
        $postParams = get_request()->getParsedBody();
70 9
        $login = false;
71 9
        $data = [];
72
73 9
        $data['error'] = '';
74 9
        $addonTitle = $this->markAsDemo;
75
76
        if (
77 9
            isset($postParams['s_user']) &&
78 9
            isset($postParams['s_pass'])
79
        ) {
80 5
            if ($this->mode === 'demo') {
81 2
                $loginResult = $this->userLoginAsDemo(
82 2
                    $postParams['s_user'],
83 2
                    $postParams['s_pass']
84 2
                );
85
            } else {
86 3
                $loginResult = $this->userLoginAsAdmin(
87 3
                    $postParams['s_user'],
88 3
                    $postParams['s_pass']
89 3
                );
90
            }
91
92 5
            $login = $loginResult['result'];
93 5
            $data['error'] = $loginResult['message'];
94
        }
95
96 9
        if ($login) {
97
            // This session variable is to mark current session as a logged user.
98 2
            get_session_instance()->set('shieldon_user_login', true);
99
100 2
            Event::doDispatch('user_login');
101
102
            // Redirect to overview page if logged in successfully.
103 2
            return get_response()->withHeader('Location', $this->url('home/overview'));
104
        }
105
106
        // Start to prompt a login form is not logged.
107 8
        if (!defined('SHIELDON_VIEW')) {
108 8
            define('SHIELDON_VIEW', true);
109
        }
110
111
        // `$ui` will be used in `css-default.php`. Do not remove it.
112 8
        $ui = [
113 8
            'background_image' => '',
114 8
            'bg_color'         => '#ffffff',
115 8
            'header_bg_color'  => '#212531',
116 8
            'header_color'     => '#ffffff',
117 8
            'shadow_opacity'   => '0.2',
118 8
        ];
119
120 8
        $data['csrf'] = $this->fieldCsrf();
121 8
        $data['form'] = get_request()->getUri()->getPath();
122 8
        $data['captchas'] = $this->captcha;
123
124 8
        $data['css'] = include $this->kernel::KERNEL_DIR . '/../../templates/frontend/css/default.php';
125
126 8
        unset($ui);
127
128 8
        $data['title'] = __('panel', 'title_login', 'Login') . $addonTitle;
129
130 8
        return $this->respond(
131 8
            $this->loadView('frontend/login', $data)
132 8
        );
133
    }
134
135
    /**
136
     * Logout
137
     *
138
     * @return ResponseInterface
139
     */
140 1
    public function logout(): ResponseInterface
141
    {
142 1
        $sessionLoginStatus = get_session_instance()->get('shieldon_user_login');
143 1
        $sessionPanelLang = get_session_instance()->get('shieldon_panel_lang');
144 1
        $response = get_response();
145
146 1
        if (isset($sessionLoginStatus)) {
147 1
            unset_superglobal('shieldon_user_login', 'session');
148
        }
149
150 1
        if (isset($sessionPanelLang)) {
151 1
            unset_superglobal('shieldon_panel_lang', 'session');
152
        }
153
154
        // @codeCoverageIgnoreStart
155 1
        if ($this->kernel->psr7) {
156
            unset_superglobal('_shieldon', 'cookie');
157
        } else {
158 1
            setcookie('_shieldon', '', time() - 3600, '/');
159
        }
160
        // // @codeCoverageIgnoreEnd
161
162 1
        return $response->withHeader('Location', $this->url('user/login'));
163
    }
164
165
    /**
166
     * Set the Captcha modules.
167
     *
168
     * @return void
169
     */
170 9
    protected function applyCaptchaForms(): void
171
    {
172 9
        $this->captcha[] = new Foundation();
173
174 9
        $captchaList = [
175 9
            'recaptcha',
176 9
            'image',
177 9
        ];
178
179 9
        foreach ($captchaList as $captcha) {
180 9
            $setting = $this->getConfig('captcha_modules.' . $captcha);
181
182 9
            if (is_array($setting)) {
183 9
                if (CaptchaFactory::check($setting)) {
184 1
                    $this->captcha[] = CaptchaFactory::getInstance($captcha, $setting);
185
                }
186
            }
187 9
            unset($setting);
188
        }
189
    }
190
191
    /**
192
     * Login as demonstration.
193
     *
194
     * @param string $username The username.
195
     * @param string $password The password.
196
     *
197
     * @return array
198
     */
199 2
    private function userLoginAsDemo($username, $password): array
200
    {
201 2
        $login = false;
202 2
        $errorMsg = '';
203
204 2
        if ($username === 'demo' && $password === 'demo') {
205 2
            $login = true;
206
        }
207
208 2
        $captcha = $this->checkCaptchaValidation($login, $errorMsg);
209 2
        $login = $captcha['result'];
210 2
        $errorMsg = $captcha['message'];
211
212 2
        return [
213 2
            'result' => $login,
214 2
            'message' => $errorMsg,
215 2
        ];
216
    }
217
218
    /**
219
     * Login as administration.
220
     *
221
     * @param string $username The username.
222
     * @param string $password The password.
223
     *
224
     * @return array
225
     */
226 3
    private function userLoginAsAdmin($username, $password): array
227
    {
228 3
        $admin = $this->getConfig('admin');
229
230 3
        $login = false;
231 3
        $errorMsg = '';
232
233
        if (
234
            // Default password, unencrypted.
235 3
            $admin['user'] === $username && 
236 3
            $admin['pass'] === $password
237
        ) {
238
            // @codeCoverageIgnoreStart
239
            $login = true;
240
            // @codeCoverageIgnoreEnd
241
242
        } elseif (
243
            // User has already changed password, encrypted.
244 3
            $admin['user'] === $username && 
245 3
            password_verify($password, $admin['pass'])
246
        ) {
247 2
            $login = true;
248
249
        } else {
250 1
            $errorMsg = __('panel', 'login_message_invalid_user_or_pass', 'Invalid username or password.');
251
        }
252
253 3
        $captcha = $this->checkCaptchaValidation($login, $errorMsg);
254 3
        $login = $captcha['result'];
255 3
        $errorMsg = $captcha['message'];
256
257 3
        return [
258 3
            'result' => $login,
259 3
            'message' => $errorMsg,
260 3
        ];
261
    }
262
263
    /**
264
     * Check Captcha.
265
     * 
266
     * @param bool   $login    The login status that will be overwritten.
267
     * @param string $errorMsg The error message.
268
     *
269
     * @return array
270
     */
271 5
    private function checkCaptchaValidation(bool $login, string $errorMsg): array
272
    {
273 5
        foreach ($this->captcha as $captcha) {
274 5
            if (!$captcha->response()) {
275 2
                $login = false;
276 5
                $errorMsg = __('panel', 'login_message_invalid_captcha', 'Invalid Captcha code.');
277
            }
278
        }
279
280 5
        return [
281 5
            'result' => $login,
282 5
            'message' => $errorMsg,
283 5
        ];
284
    }
285
}
286