Completed
Push — master ( 31df20...de57e8 )
by Nazar
09:01
created

profile::profile_sign_in()   C

Complexity

Conditions 12
Paths 9

Size

Total Lines 45
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 21.6512

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 34
c 1
b 0
f 0
nc 9
nop 1
dl 0
loc 45
rs 5.1612
ccs 19
cts 32
cp 0.5938
crap 21.6512

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage System module
5
 * @category   modules
6
 * @author     Nazar Mokrynskyi <[email protected]>
7
 * @copyright  Copyright (c) 2015-2016, Nazar Mokrynskyi
8
 * @license    MIT License, see license.txt
9
 */
10
namespace cs\modules\System\api\Controller;
11
use
12
	cs\Config,
13
	cs\Core,
14
	cs\ExitException,
15
	cs\Language,
16
	cs\Mail,
17
	cs\Session,
18
	cs\User;
19
20
trait profile {
21
	public static function profile_get () {
22
		$User         = User::instance();
23
		$fields       = [
24
			'id',
25
			'login',
26
			'username',
27
			'language',
28
			'timezone',
29
			'avatar'
30
		];
31
		$result       = $User->get($fields, $User->id);
32
		$result['id'] = (int)$result['id'];
33
		if ($User->guest()) {
34
			$result['username'] = Language::instance()->system_profile_guest;
35
			$result['avatar']   = $User->avatar();
36
		}
37
		return $result;
38
	}
39
	/**
40
	 * @param \cs\Request $Request
41
	 *
42
	 * @throws ExitException
43
	 */
44
	public static function profile_patch ($Request) {
45
		$user_data = $Request->data('login', 'username', 'language', 'timezone', 'avatar');
46
		if (
47
			!$user_data ||
48
			!$user_data['login']
49
		) {
50
			throw new ExitException(400);
51
		}
52
		$Config = Config::instance();
53
		$User   = User::instance();
54
		if ($User->guest()) {
55
			throw new ExitException(403);
56
		}
57
		$user_data = xap($user_data, false);
58
		if (
59
			(
60
				$user_data['language'] &&
61
				!in_array($user_data['language'], $Config->core['active_languages'])
62
			) ||
63
			(
64
				$user_data['timezone'] &&
65
				!in_array($user_data['timezone'], get_timezones_list())
66
			)
67
		) {
68
			throw new ExitException(400);
69
		}
70
		$user_data['login'] = mb_strtolower($user_data['login']);
71
		/**
72
		 * Check for changing login to new one and whether it is available
73
		 */
74
		if (
75
			$user_data['login'] != $User->login &&
76
			$user_data['login'] != $User->email &&
77
			(
78
				filter_var($user_data['login'], FILTER_VALIDATE_EMAIL) ||
79
				$User->get_id(hash('sha224', $user_data['login'])) !== false
80
			)
81
		) {
82
			throw new ExitException(Language::instance()->system_admin_users_login_occupied, 400);
83
		}
84
		if (!$User->set($user_data)) {
85
			throw new ExitException(500);
86
		}
87
	}
88
	/**
89
	 * @param \cs\Request $Request
90
	 *
91
	 * @throws ExitException
92
	 */
93
	public static function profile_change_password ($Request) {
94
		$L    = Language::prefix('system_profile_');
95
		$User = User::instance();
96
		$data = $Request->data('current_password', 'new_password');
97
		if (!$data) {
98
			throw new ExitException(400);
99
		}
100
		if (!$User->user()) {
101
			throw new ExitException(403);
102
		}
103
		if (!$data['new_password']) {
104
			throw new ExitException($L->please_type_new_password, 400);
105
		}
106
		if (!$User->validate_password($data['current_password'], $User->id, true)) {
107
			throw new ExitException($L->wrong_current_password, 400);
108
		}
109
		$id = $User->id;
110
		if ($User->set_password($data['new_password'], $id, true)) {
111
			Session::instance()->add($id);
112
		} else {
113
			throw new ExitException($L->change_password_server_error, 400);
114
		}
115
	}
116
	/**
117
	 * @param \cs\Request  $Request
118
	 * @param \cs\Response $Response
119
	 *
120
	 * @throws ExitException
121
	 */
122
	public static function profile_registration ($Request, $Response) {
123
		$Config = Config::instance();
124
		$L      = Language::prefix('system_profile_registration_');
125
		$User   = User::instance();
126
		if (!$User->guest()) {
127
			throw new ExitException(403);
128
		}
129
		if (!$Config->core['allow_user_registration']) {
130
			throw new ExitException($L->prohibited, 403);
131
		}
132
		$email   = $Request->data('email');
133
		$email   = mb_strtolower($email);
134
		$result  = static::try_to_register($User, $L, $email);
135
		$confirm = $result['reg_key'] !== true;
136
		static::fill_optional_profile_data($Request, $User, $result['id']);
137
		$title = $L->success_mail(get_core_ml_text('name'));
138
		$body  = $L->success_mail(
139
			$User->username($result['id']),
140
			get_core_ml_text('name'),
141
			$Config->core_url().'/profile/settings',
142
			$User->get('login', $result['id'])
143
		);
144
		if ($confirm) {
145
			$title = $L->need_confirmation_mail(get_core_ml_text('name'));
146
			$body  = $L->need_confirmation_mail_body(
147
				$User->username($result['id']),
148
				get_core_ml_text('name'),
149
				$Config->core_url()."/profile/registration_confirmation/$result[reg_key]",
150
				$L->time($Config->core['registration_confirmation_time'], 'd')
151
			);
152
		} elseif (!$Request->data('password') && $result['password']) {
153
			$body = $L->success_mail_with_password_body(
154
				$User->username($result['id']),
155
				get_core_ml_text('name'),
156
				$Config->core_url().'/profile/settings',
157
				$User->get('login', $result['id']),
158
				$result['password']
159
			);
160
		}
161
		if (!Mail::instance()->send_to($email, $title, $body)) {
162
			$User->registration_cancel();
163
			throw new ExitException($L->mail_sending_error, 500);
164
		}
165
		$Response->code = $confirm ? 202 : 201;
166
	}
167
	/**
168
	 * @param User            $User
169
	 * @param Language\Prefix $L
170
	 * @param string          $email
171
	 *
172
	 * @return array
173
	 *
174
	 * @throws ExitException
175
	 */
176
	protected static function try_to_register ($User, $L, $email) {
177
		$result = $User->registration($email);
178
		if ($result === false) {
179
			throw new ExitException($L->please_type_correct_email, 400);
180
		}
181
		if ($result == 'error') {
182
			throw new ExitException($L->server_error, 500);
183
		}
184
		if ($result == 'exists') {
185
			throw new ExitException($L->error_exists, 400);
186
		}
187
		return $result;
188
	}
189
	/**
190
	 * @param \cs\Request $Request
191
	 * @param User        $User
192
	 * @param int         $user_id
193
	 */
194
	protected static function fill_optional_profile_data ($Request, $User, $user_id) {
195
		if ($Request->data('username')) {
196
			$User->set('username', $Request->data['username'], $user_id);
197
		}
198
		// Actually `sha512(sha512(password) + public_key)` instead of plain password
199
		if ($Request->data('password')) {
200
			$User->set_password($Request->data['password'], $user_id, true);
201
		}
202
		if ($Request->data('language')) {
203
			$User->set('language', $Request->data['language'], $user_id);
204
		}
205
		if ($Request->data('timezone')) {
206
			$User->set('timezone', $Request->data['timezone'], $user_id);
207
		}
208
		if ($Request->data('avatar')) {
209
			$User->set('avatar', $Request->data['avatar'], $user_id);
210
		}
211
	}
212
	/**
213
	 * @param \cs\Request $Request
214
	 *
215
	 * @throws ExitException
216
	 */
217
	public static function profile_restore_password ($Request) {
218
		$Config = Config::instance();
219
		$L      = Language::prefix('system_profile_restore_password_');
220
		$User   = User::instance();
221
		$email  = $Request->data('email');
222
		if (!$User->guest()) {
223
			throw new ExitException(403);
224
		}
225
		if (!$email) {
226
			throw new ExitException($L->please_type_your_email, 400);
227
		}
228
		$id = $User->get_id(mb_strtolower($email));
229
		if (!$id) {
230
			throw new ExitException($L->user_with_such_login_email_not_found, 400);
231
		}
232
		$key = $User->restore_password($id);
233
		if (
234
			!$key ||
235
			!Mail::instance()->send_to(
236
				$User->get('email', $id),
1 ignored issue
show
Security Bug introduced by
It seems like $User->get('email', $id) targeting cs\User\Management::get() can also be of type false; however, cs\Mail::send_to() does only seem to accept array|string, did you maybe forget to handle an error condition?
Loading history...
237
				$L->confirmation_mail(get_core_ml_text('name')),
238
				$L->confirmation_mail_body(
239
					$User->username($id),
240
					get_core_ml_text('name'),
241
					$Config->core_url()."/profile/restore_password_confirmation/$key",
242
					$L->time($Config->core['registration_confirmation_time'], 'd')
243
				)
244
			)
245
		) {
246
			throw new ExitException($L->server_error, 500);
247
		}
248
	}
249
	/**
250
	 * @param \cs\Request $Request
251
	 *
252
	 * @throws ExitException
253
	 */
254 4
	public static function profile_sign_in ($Request) {
255 4
		$Config = Config::instance();
256 4
		$L      = Language::prefix('system_profile_sign_in_');
257 4
		$User   = User::instance();
258 4
		$data   = $Request->data('login', 'password');
259 4
		if (!$data) {
260
			throw new ExitException(400);
261
		}
262 4
		if (!$User->guest()) {
263
			return;
264
		}
265
		if (
266 4
			$Config->core['sign_in_attempts_block_count'] &&
267 4
			$User->get_sign_in_attempts_count($data['login']) >= $Config->core['sign_in_attempts_block_count']
268
		) {
269
			$User->sign_in_result(false, $data['login']);
270
			throw new ExitException($L->attempts_are_over_try_again_in(format_time($Config->core['sign_in_attempts_block_time'])), 403);
271
		}
272 4
		$id = $User->get_id($data['login']);
273 4
		if ($id && $User->validate_password($data['password'], $id, true)) {
274 4
			$status      = $User->get('status', $id);
275 4
			$block_until = $User->get('block_until', $id);
276 4
			if ($status == User::STATUS_NOT_ACTIVATED) {
277
				throw new ExitException($L->your_account_is_not_active, 403);
278
			}
279 4
			if ($status == User::STATUS_INACTIVE) {
280
				throw new ExitException($L->your_account_disabled, 403);
281
			}
282 4
			if ($block_until > time()) {
283
				throw new ExitException($L->your_account_blocked_until(date($L->_datetime, $block_until)), 403);
284
			}
285 4
			Session::instance()->add($id);
286 4
			$User->sign_in_result(true, $data['login']);
287
		} else {
288
			$User->sign_in_result(false, $data['login']);
289
			$content = $L->authentication_error;
290
			if (
291
				$Config->core['sign_in_attempts_block_count'] &&
292
				$User->get_sign_in_attempts_count($data['login']) >= $Config->core['sign_in_attempts_block_count'] * 2 / 3
293
			) {
294
				$content .= ' '.$L->attempts_left($Config->core['sign_in_attempts_block_count'] - $User->get_sign_in_attempts_count($data['login']));
295
			}
296
			throw new ExitException($content, 400);
297
		}
298 4
	}
299
	/**
300
	 * @param \cs\Request  $Request
301
	 * @param \cs\Response $Response
302
	 *
303
	 * @throws ExitException
304
	 */
305
	public static function profile_sign_out (
306
		/** @noinspection PhpUnusedParameterInspection */
307
		$Request,
308
		$Response
309
	) {
310
		if (User::instance()->guest()) {
311
			return;
312
		}
313
		if (!Session::instance()->del()) {
314
			throw new ExitException(500);
315
		}
316
		/**
317
		 * Hack for 403 after sign out in administration
318
		 */
319
		$Response->cookie('sign_out', 1, TIME + 5, true);
320
	}
321
	public static function profile_configuration () {
322
		$Config = Config::instance();
323
		return [
324
			'public_key'            => Core::instance()->public_key,
325
			'password_min_length'   => (int)$Config->core['password_min_length'],
326
			'password_min_strength' => (int)$Config->core['password_min_strength']
327
		];
328
	}
329
}
330