session_helper   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 329
Duplicated Lines 3.95 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 1
dl 13
loc 329
rs 9.52
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 11 11 1
A validate_modules() 0 22 5
A find_module() 0 14 3
A get_modules() 0 8 2
B is_tfa_required() 0 28 8
A is_tfa_registered() 0 19 4
A is_tfa_key_registred() 0 15 3
A generate_page() 0 54 3
A user_data() 0 11 2
A do_permission_check() 0 23 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
*
4
* 2FA extension for the phpBB Forum Software package.
5
*
6
* @copyright (c) 2015 Paul Sohier
7
* @license GNU General Public License, version 2 (GPL-2.0)
8
*
9
*/
10
11
namespace paul999\tfa\helper;
12
13
use paul999\tfa\exceptions\module_exception;
14
use paul999\tfa\modules\module_interface;
15
use phpbb\auth\auth;
16
use phpbb\config\config;
17
use phpbb\controller\helper;
18
use phpbb\db\driver\driver_interface;
19
use phpbb\di\service_collection;
20
use phpbb\template\template;
21
use phpbb\user;
22
23
/**
24
 * helper method which is used to detect if a user needs to use 2FA
25
 */
26
class session_helper implements session_helper_interface
27
{
28
	/**
29
	 * @var driver_interface
30
	 */
31
	private $db;
32
33
	/**
34
	 * @var config
35
	 */
36
	private $config;
37
38
	/**
39
	 * @var user
40
	 */
41
	private $user;
42
43
	/**
44
	 * @var array
45
	 */
46
	private $modules;
47
48
	private $module_data = [];
49
50
	/**
51
	 * @var string
52
	 */
53
	private $registration_table;
54
55
	/**
56
	 * @var string
57
	 */
58
	private $user_table;
59
60
	/**
61
	 * @var array
62
	 */
63
	private $user_array = [];
64
65
	/**
66
	 * @var \phpbb\template\template
67
	 */
68
	private $template;
69
70
	/**
71
	 * @var \phpbb\controller\helper
72
	 */
73
	private $controller_helper;
74
75
	/**
76
	 * Constructor
77
	 *
78
	 * @access public
79
	 *
80
	 * @param driver_interface         $db
81
	 * @param config                   $config
82
	 * @param user                     $user
83
	 * @param service_collection       $modules
84
	 * @param \phpbb\template\template $template
85
	 * @param \phpbb\controller\helper $controller_helper
86
	 * @param string                   $registration_table
87
	 * @param string                   $user_table
88
	 */
89 View Code Duplication
	public function __construct(driver_interface $db, config $config, user $user, service_collection $modules, template $template, helper $controller_helper, $registration_table, $user_table)
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...
90
	{
91
		$this->db					= $db;
92
		$this->user					= $user;
93
		$this->config				= $config;
94
		$this->template 			= $template;
95
		$this->controller_helper 	= $controller_helper;
96
		$this->registration_table	= $registration_table;
97
		$this->user_table			= $user_table;
98
		$this->module_data			= $modules;
0 ignored issues
show
Documentation Bug introduced by
It seems like $modules of type object<phpbb\di\service_collection> is incompatible with the declared type array of property $module_data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
99
	}
100
101
	/**
102
	 * Register the tagged modules if they are enabled.
103
	 */
104
	private function validate_modules()
105
	{
106
		/**
107
		 * @var module_interface $module
108
		 */
109
		foreach ($this->module_data as $module)
110
		{
111
			if ($module instanceof module_interface)
112
			{
113
				// Only add them if they are actually a module_interface.
114
				$priority = $module->get_priority();
115
				if (isset($this->modules[$module->get_priority()]))
116
				{
117
					throw new module_exception(400, 'TFA_DOUBLE_PRIORITY', array($priority, get_class($module), get_class($this->modules[$priority])));
118
				}
119
				if ($module->is_enabled())
120
				{
121
					$this->modules[$priority] = $module;
122
				}
123
			}
124
		}
125
	}
126
127
	/**
128
	 * @param $requested_module
129
	 * @return null|module_interface
130
	 */
131
	public function find_module($requested_module)
132
	{
133
		/**
134
		 * @var module_interface $module
135
		 */
136
		foreach ($this->get_modules() as $module)
137
		{
138
			if ($module->get_name() == $requested_module)
139
			{
140
				return $module;
141
			}
142
		}
143
		return null;
144
	}
145
146
	/**
147
	 * @return array
148
	 */
149
	public function get_modules()
150
	{
151
		if (empty($this->modules))
152
		{
153
			$this->validate_modules();
154
		}
155
		return $this->modules;
156
	}
157
158
	/**
159
	 * @param int $user_id
160
	 * @param bool $admin
161
	 * @param array $userdata
162
	 * @return bool
163
	 */
164
	public function is_tfa_required($user_id, $admin = false, $userdata = array())
165
	{
166
		if (sizeof($this->get_modules()) == 0)
167
		{
168
			return false;
169
		}
170
		switch ($this->config['tfa_mode'])
171
		{
172
			case session_helper_interface::MODE_DISABLED:
173
				return false;
174
175
			case session_helper_interface::MODE_NOT_REQUIRED:
176
				return $this->is_tfa_registered($user_id);
177
178
			case session_helper_interface::MODE_REQUIRED_FOR_ACP_LOGIN:
179
			case session_helper_interface::MODE_REQUIRED_FOR_ADMIN:
180
				return $this->do_permission_check($user_id, $userdata, 'a_');
181
182
			case session_helper_interface::MODE_REQUIRED_FOR_MODERATOR:
183
				return $this->do_permission_check($user_id, $userdata, array('m_', 'a_'));
184
185
			case session_helper_interface::MODE_REQUIRED:
186
				return true;
187
188
			default:
189
				return false;
190
		}
191
	}
192
193
	/**
194
	 * Check if the user has two factor authentication added to his account.
195
	 *
196
	 * @param int $user_id
197
	 * @return bool
198
	 */
199
	public function is_tfa_registered($user_id)
200
	{
201
		if (isset($this->user_array[$user_id]))
202
		{
203
			return $this->user_array[$user_id];
204
		}
205
206
		$this->user_array[$user_id] = false; // Preset to false.
207
208
		/**
209
		 * @var int $priority
210
		 * @var module_interface $module
211
		 */
212
		foreach ($this->get_modules() as $priority => $module)
213
		{
214
			$this->user_array[$user_id] = $this->user_array[$user_id] || $module->is_usable($user_id);
215
		}
216
		return $this->user_array[$user_id];
217
	}
218
219
	/**
220
	 * Check if the user has any key registred, even if the module is not available.
221
	 *
222
	 * @param int $user_id
223
	 * @return bool
224
	 */
225
	public function is_tfa_key_registred($user_id)
226
	{
227
		/**
228
		 * @var int $priority
229
		 * @var module_interface $module
230
		 */
231
		foreach ($this->get_modules() as $priority => $module)
232
		{
233
			if ($module->key_registered($user_id))
234
			{
235
				return true;
236
			}
237
		}
238
		return false;
239
	}
240
241
242
	/**
243
	 * @param int $user_id
244
	 * @param bool $admin
245
	 * @param bool $auto_login
246
	 * @param bool $viewonline
247
	 * @param string $redirect
248
	 * @param bool $secure
249
	 * @throws \Exception
250
	 */
251
	public function generate_page($user_id, $admin, $auto_login, $viewonline, $redirect, $secure = false)
252
	{
253
		$this->user->add_lang_ext('paul999/tfa', 'common');
254
		$modules = $this->get_modules();
255
256
		/**
257
		 * @var module_interface $row
258
		 */
259
		foreach ($modules as $row)
260
		{
261
			if ($row->is_usable($user_id))
262
			{
263
				$this->template->assign_block_vars('tfa_options', array_merge(array(
264
					'ID'	=> $row->get_name(),
265
					'NAME'	=> $this->user->lang($row->get_translatable_name()),
266
					'U_SUBMIT_AUTH'	=> $this->controller_helper->route('paul999_tfa_read_controller_submit', array(
267
						'user_id'		=> (int) $user_id,
268
						'admin'			=> (int) $admin,
269
						'auto_login'	=> (int) $auto_login,
270
						'viewonline'	=> (int) $viewonline,
271
						'class'			=> $row->get_name(),
272
					)),
273
					'S_HIDDEN_FIELDS' => build_hidden_fields(['sid' => $this->user->session_id]),
274
				), $row->login_start($user_id)));
275
			}
276
		}
277
278
		add_form_key('tfa_login_page');
279
280
		$random = sha1(random_bytes(32));
281
282
		$sql_ary = array(
283
			'tfa_random' 	=> $random,
284
			'tfa_uid'		=> $user_id,
285
		);
286
		$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . "
287
			WHERE
288
				session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "' AND
289
				session_user_id = " . (int) $this->user->data['user_id'];
290
		$this->db->sql_query($sql);
291
292
		$this->template->assign_vars(array(
293
			'REDIRECT'		=> $redirect,
294
			'RANDOM'		=> $random,
295
			'RELOGIN_NOTE'	=> $secure,
296
		));
297
298
		page_header('TFA_KEY_REQUIRED');
299
300
		$this->template->set_filenames(array(
301
			'body' => '@paul999_tfa/authenticate_main.html'
302
		));
303
		page_footer(false); // Do not include cron on this page!
304
	}
305
306
	/**
307
	 * Return the userdata for a specific user.
308
	 *
309
	 * @param int $user_id
310
	 * @param array $userdata
311
	 * @return array
312
	 */
313
	private function user_data($user_id, $userdata = array())
314
	{
315
		if (empty($userdata))
316
		{
317
			$sql = 'SELECT * FROM ' . $this->user_table . ' WHERE user_id = ' . (int) $user_id;
318
			$result = $this->db->sql_query($sql);
319
			$userdata = $this->db->sql_fetchrow($result);
320
			$this->db->sql_freeresult($result);
321
		}
322
		return $userdata;
323
	}
324
325
	/**
326
	 * @param int $user_id
327
	 * @param array $userdata
328
	 * @param string|array $permission
329
	 * @return bool
330
	 */
331
	private function do_permission_check($user_id, $userdata, $permission)
332
	{
333
		if ($this->is_tfa_registered($user_id))
334
		{
335
			return true;
336
		}
337
		$userdata = $this->user_data($user_id, $userdata);
338
		$auth = new auth();
339
		$auth->acl($userdata);
340
341
		if (!is_array($permission))
342
		{
343
			$permission = array($permission);
344
		}
345
		foreach ($permission as $perm)
346
		{
347
			if ($auth->acl_get($perm))
348
			{
349
				return true;
350
			}
351
		}
352
		return false;
353
	}
354
}
355