Completed
Push — master ( 6cfe9f...d6cbe8 )
by Paul
13s queued 10s
created

session_helper::isTfaKeyRegistred()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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