Completed
Push — master ( 4c378e...4e4c88 )
by Paul
02:27
created

session_helper   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 304
Duplicated Lines 4.28 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 6
Bugs 2 Features 0
Metric Value
wmc 35
c 6
b 2
f 0
lcom 1
cbo 8
dl 13
loc 304
rs 9

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 13 13 1
B validateModules() 0 22 5
A findModule() 0 14 3
A getModules() 0 4 1
C isTfaRequired() 0 24 8
A isTfaRegistered() 0 19 4
A generate_page() 0 57 4
A user_data() 0 11 2
C do_permission_check() 0 23 7

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
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
23
24
/**
25
 * helper method which is used to detect if a user needs to use 2FA
26
 */
27
class session_helper implements session_helper_interface
28
{
29
30
	/**
31
	 * @var driver_interface
32
	 */
33
	private $db;
34
35
	/**
36
	 * @var config
37
	 */
38
	private $config;
39
40
	/**
41
	 * @var user
42
	 */
43
	private $user;
44
45
	/**
46
	 * @var array
47
	 */
48
	private $modules = array();
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 = 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
99
		$this->validateModules($modules);
100
101
	}
102
103
	/**
104
	 * Register the tagged modules if they are enabled.
105
	 * @param service_collection $modules
106
	 */
107
	private function validateModules(service_collection $modules)
108
	{
109
		/**
110
		 * @var module_interface $module
111
		 */
112
		foreach ($modules as $module)
113
		{
114
			if ($module instanceof module_interface)
115
			{
116
				// Only add them if they are actually a module_interface.
117
				$priority = $module->get_priority();
118
				if (isset($this->modules[$module->get_priority()]))
119
				{
120
					throw new module_exception($this->user->lang('TFA_DOUBLE_PRIORITY', $priority, get_class($module), get_class($this->modules[$priority])));
121
				}
122
				if ($module->is_enabled())
123
				{
124
					$this->modules[$priority] = $module;
125
				}
126
			}
127
		}
128
	}
129
130
	/**
131
	 * @param $requested_module
132
	 * @return null|module_interface
133
	 */
134
	public function findModule($requested_module)
135
	{
136
		/**
137
		 * @var module_interface $module
138
		 */
139
		foreach ($this->getModules() as $module)
140
		{
141
			if ($module->get_name() == $requested_module)
142
			{
143
				return $module;
144
			}
145
		}
146
		return null;
147
	}
148
149
	/**
150
	 * @return array
151
	 */
152
	public function getModules()
153
	{
154
		return $this->modules;
155
	}
156
157
	/**
158
	 * @param int $user_id
159
	 * @param bool $admin
160
	 * @param array $userdata
161
	 * @param bool $try
162
	 * @return bool
163
	 */
164
	public function isTfaRequired($user_id, $admin = false, $userdata = array(), $try = false)
165
	{
166
		if (sizeof($this->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
			case session_helper_interface::MODE_NOT_REQUIRED:
175
				return $this->isTfaRegistered($user_id);
176
			case session_helper_interface::MODE_REQUIRED_FOR_ACP_LOGIN:
177
				return $this->do_permission_check($user_id, $userdata, 'a_', $admin, $try);
178
			case session_helper_interface::MODE_REQUIRED_FOR_ADMIN:
179
				return $this->do_permission_check($user_id, $userdata, 'a_', true, $try);
180
			case session_helper_interface::MODE_REQUIRED_FOR_MODERATOR:
181
				return $this->do_permission_check($user_id, $userdata, array('m_', 'a_'), $admin, true);
182
			case session_helper_interface::MODE_REQUIRED:
183
				return true;
184
			default:
185
				return false;
186
		}
187
	}
188
189
	/**
190
	 * Check if the user has two factor authentication added to his account.
191
	 *
192
	 * @param int $user_id
193
	 * @return bool
194
	 */
195
	public function isTfaRegistered($user_id)
196
	{
197
		if (isset($this->user_array[$user_id]))
198
		{
199
			return $this->user_array[$user_id];
200
		}
201
202
		$this->user_array[$user_id] = false; // Preset to false.
203
204
		/**
205
		 * @var int $priority
206
		 * @var module_interface $module
207
		 */
208
		foreach ($this->modules as $priority => $module)
209
		{
210
			$this->user_array[$user_id] = $this->user_array[$user_id] || $module->is_usable($user_id);
211
		}
212
		return $this->user_array[$user_id];
213
	}
214
215
	/**
216
	 * @param int  $user_id
217
	 * @param bool $admin
218
	 * @param bool $auto_login
219
	 * @param bool $viewonline
220
	 * @param string     $redirect
221
	 */
222
	public function generate_page($user_id, $admin, $auto_login, $viewonline, $redirect)
223
	{
224
225
		$this->user->add_lang_ext('paul999/tfa', 'common');
226
		$modules = $this->getModules();
227
228
		/**
229
		 * @var module_interface $row
230
		 */
231
		foreach ($modules as $row)
232
		{
233
			if ($row->is_usable($user_id))
234
			{
235
				$this->template->assign_block_vars('tfa_options', array_merge(array(
236
					'ID'	=> $row->get_name(),
237
					'U_SUBMIT_AUTH'	=> $this->controller_helper->route('paul999_tfa_read_controller_submit', array(
238
						'user_id'		=> (int) $user_id,
239
						'admin'			=> (int) $admin,
240
						'auto_login'	=> (int) $auto_login,
241
						'viewonline'	=> (int) $viewonline,
242
						'class'			=> $row->get_name(),
243
					)),
244
				), $row->login_start($user_id)));
245
			}
246
		}
247
248
		add_form_key('tfa_login_page');
249
250
		$random = sha1(random_bytes(32));
251
252
		if (!empty($this->user->data['tfa_random']))
253
		{
254
			throw new BadRequestHttpException($this->user->lang('TFA_SOMETHING_WENT_WRONG'));
255
		}
256
257
		$sql_ary = array(
258
			'tfa_random' 	=> $random,
259
			'tfa_uid'		=> $user_id,
260
		);
261
		$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
262
							WHERE
263
								session_id = \'' . $this->db->sql_escape($this->user->data['session_id']) . '\' AND
264
								session_user_id = ' . (int) $this->user->data['user_id'];
265
		$this->db->sql_query($sql);
266
267
		$this->template->assign_vars(array(
268
			'REDIRECT'		=> $redirect,
269
			'RANDOM'		=> $random,
270
		));
271
272
		page_header('TFA_KEY_REQUIRED');
273
274
		$this->template->set_filenames(array(
275
				'body' => '@paul999_tfa/authenticate_main.html')
276
		);
277
		page_footer(false); // Do not include cron on this page!
278
	}
279
280
	/**
281
	 * Return the userdata for a specific user.
282
	 *
283
	 * @param int $user_id
284
	 * @param array $userdata
285
	 * @return array
286
	 */
287
	private function user_data($user_id, $userdata = array())
288
	{
289
		if (empty($userdata))
290
		{
291
			$sql = 'SELECT * FROM ' . $this->user_table . ' WHERE user_id = ' . (int) $user_id;
292
			$result = $this->db->sql_query($sql);
293
			$userdata = $this->db->sql_fetchrow($result);
294
			$this->db->sql_freeresult($result);
295
		}
296
		return $userdata;
297
	}
298
299
	/**
300
	 * @param int $user_id
301
	 * @param array $userdata
302
	 * @param string|array $permission
303
	 * @param bool $admin
304
	 * @param bool $try
305
	 * @return bool
306
	 */
307
	private function do_permission_check($user_id, $userdata, $permission, $admin, $try)
308
	{
309
		if ($this->isTfaRegistered($user_id))
310
		{
311
			return true;
312
		}
313
		$userdata = $this->user_data($user_id, $userdata);
314
		$at = new auth();
315
		$at->acl($userdata);
316
317
		if (!is_array($permission))
318
		{
319
			$permission = array($permission);
320
		}
321
		foreach ($permission as $perm)
322
		{
323
			if ($at->acl_get($perm) && ($admin || $try))
324
			{
325
				return true;
326
			}
327
		}
328
		return false;
329
	}
330
}
331