Completed
Push — master ( 23d816...b58616 )
by Paul
02:25
created

otp::getRegistrations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 9
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 9
loc 9
rs 9.6666
cc 1
eloc 6
nc 1
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\modules;
12
13
use OTPAuthenticate\OTPAuthenticate;
14
use OTPAuthenticate\OTPHelper;
15
use phpbb\db\driver\driver_interface;
16
use phpbb\request\request_interface;
17
use phpbb\template\template;
18
use phpbb\user;
19
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
20
21
class otp extends abstract_module
22
{
23
	/**
24
	 * @var \OTPAuthenticate\OTPHelper
25
	 */
26
	private $otp_helper;
27
28
	/**
29
	 * @var \OTPAuthenticate\OTPAuthenticate
30
	 */
31
	private $otp;
32
33
	/**
34
	 * @var \phpbb\request\request_interface
35
	 */
36
	private $request;
37
38
	/**
39
	 * @var string
40
	 */
41
	private $otp_registration_table;
42
43
	/**
44
	 * OTP constructor.
45
	 *
46
	 * @param \phpbb\db\driver\driver_interface $db
47
	 * @param \phpbb\user                       $user
48
	 * @param \phpbb\request\request_interface  $request
49
	 * @param \phpbb\template\template          $template
50
	 * @param string                            $otp_registration_table
51
	 */
52
	public function __construct(driver_interface $db, user $user, request_interface $request, template $template, $otp_registration_table)
53
	{
54
		$this->otp_helper = new OTPHelper();
55
		$this->otp = new OTPAuthenticate();
56
		$this->db = $db;
57
		$this->user = $user;
58
		$this->request = $request;
59
		$this->template = $template;
60
		$this->otp_registration_table = $otp_registration_table;
61
	}
62
63
	/**
64
	 * Get a language key for this specific module.
65
	 * @return string
66
	 */
67
	public function get_translatable_name()
68
	{
69
		return 'OTP';
70
	}
71
72
	/**
73
	 * Return the name of the current module
74
	 * This is for internal use only
75
	 * @return string
76
	 */
77
	public function get_name()
78
	{
79
		return 'otp';
80
	}
81
82
	/**
83
	 * Return if this module is enabled by the admin
84
	 * (And all server requirements are met).
85
	 *
86
	 * Do not return false in case a specific user disabled this module,
87
	 * OR if the user is unable to use this specific module,
88
	 * OR if a browser specific item is missing/incorrect.
89
	 * @return boolean
90
	 */
91
	public function is_enabled()
92
	{
93
		return true;
94
	}
95
96
	/**
97
	 * Check if the current user is able to use this module.
98
	 *
99
	 * This means that the user enabled it in the UCP,
100
	 * And has it setup up correctly.
101
	 * This method will be called during login, not during registration/
102
	 *
103
	 * @param int $user_id
104
	 *
105
	 * @return bool
106
	 */
107 View Code Duplication
	public function is_usable($user_id)
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...
108
	{
109
		$sql = 'SELECT COUNT(registration_id) as reg_id 
110
					FROM ' . $this->otp_registration_table . ' 
111
					WHERE 
112
						user_id = ' . (int) $user_id;
113
		$result = $this->db->sql_query($sql);
114
		$row = $this->db->sql_fetchrow($result);
115
		$this->db->sql_freeresult($result);
116
117
		return $row && $row['reg_id'] > 0;
118
	}
119
120
	/**
121
	 * Check if the user can potentially use this.
122
	 * This method is called at registration page.
123
	 *
124
	 * You can, for example, check if the current browser is suitable.
125
	 *
126
	 * @param int|boolean $user_id Use false to ignore user
127
	 *
128
	 * @return bool
129
	 */
130
	public function is_potentially_usable($user_id = false)
131
	{
132
		return true;
133
	}
134
135
	/**
136
	 * Get the priority for this module.
137
	 * A lower priority means more chance it gets selected as default option
138
	 *
139
	 * There can be only one module with a specific priority!
140
	 * If there is already a module registered with this priority,
141
	 * a Exception might be thrown
142
	 *
143
	 * @return int
144
	 */
145
	public function get_priority()
146
	{
147
		return 15;
148
	}
149
150
	/**
151
	 * Start of the login procedure.
152
	 *
153
	 * @param int $user_id
154
	 *
155
	 * @return int
156
	 */
157
	public function login_start($user_id)
158
	{
159
		$this->template->assign_vars(array(
160
			'S_TFA_INCLUDE_HTML'	=> 'tfa_otp_authenticate.html',
161
		));
162
	}
163
164
	/**
165
	 * Actual login procedure
166
	 *
167
	 * @param int $user_id
168
	 *
169
	 * @return bool
170
	 */
171
	public function login($user_id)
172
	{
173
		$key = $this->request->variable('authenticate', '');
174
175
		foreach ($this->getRegistrations($user_id) as $registration)
176
		{
177
			if ($this->otp->checkTOTP($registration['secret'], $key, 'sha1'))
178
			{
179
				// We found a valid key.
180
				$sql_ary = array(
181
					'last_used' => time(),
182
				);
183
				$sql = 'UPDATE ' . $this->otp_registration_table . ' 
184
							SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' 
185
							WHERE 
186
								registration_id = ' . (int) $registration['registration_id'];
187
				$this->db->sql_query($sql);
188
			}
189
		}
190
		return false;
191
	}
192
193
	/**
194
	 * If this module can add new keys (Or other things)
195
	 *
196
	 * @return boolean
197
	 */
198
	public function can_register()
199
	{
200
		return true;
201
	}
202
203
	/**
204
	 * Start with the registration of a new security key.
205
	 * This page should return a name of a template, and
206
	 * it should assign the required variables for this template.
207
	 *
208
	 * @return string
209
	 */
210
	public function register_start()
211
	{
212
		$secret = $this->otp->generateSecret();
213
		$QR = $this->otp_helper->generateKeyURI('totp', $secret, generate_board_url(), '',0, 'sha1');
214
		$this->template->assign_vars(array(
215
			'TFA_QR_CODE'				=> 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=' . $QR,
216
			'TFA_SECRET'				=> $secret,
217
			'L_TFA_ADD_OTP_KEY_EXPLAIN'	=> $this->user->lang('TFA_ADD_OTP_KEY_EXPLAIN', $secret),
218
			'S_HIDDEN_FIELDS_MODULE'	=> build_hidden_fields(array(
219
				'secret'	=> $secret,
220
			)),
221
		));
222
223
		return 'tfa_otp_ucp_new';
224
	}
225
226
	/**
227
	 * Do the actual registration of a new security key.
228
	 *
229
	 * @return boolean Result of the registration.
230
	 * @throws BadRequestHttpException
231
	 */
232
	public function register()
233
	{
234
		$secret = $this->request->variable('secret', '');
235
		$otp	= $this->request->variable('register', '');
236
237
		if (!$this->otp->checkTOTP($secret, $otp, 'sha1'))
238
		{
239
			throw new BadRequestHttpException($this->user->lang('TFA_OTP_INVALID_KEY'));
240
		}
241
242
		$sql_ary = array(
243
			'user_id' 		=> $this->user->data['user_id'],
244
			'secret'		=> $secret,
245
			'registered' 	=> time(),
246
			'last_used' 	=> time(),
247
		);
248
249
		$sql = 'INSERT INTO ' . $this->otp_registration_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
250
		$this->db->sql_query($sql);
251
	}
252
253
	/**
254
	 * This method is called to show the UCP page.
255
	 * You can assign template variables to the template, or do anything else here.
256
	 */
257
	public function show_ucp()
258
	{
259
		$this->show_ucp_complete($this->otp_registration_table);
260
	}
261
262
	/**
263
	 * Delete a specific row from the UCP.
264
	 * The data is based on the data provided in show_ucp.
265
	 *
266
	 * @param int $key
267
	 *
268
	 * @return void
269
	 */
270 View Code Duplication
	public function delete($key)
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...
271
	{
272
		$sql = 'DELETE FROM ' . $this->otp_registration_table . '
273
					WHERE user_id = ' . (int) $this->user->data['user_id'] . '
274
					AND registration_id =' . (int) $key;
275
276
		$this->db->sql_query($sql);
277
	}
278
279
	/**
280
	 * Select all registration objects from the database
281
	 * @param integer $user_id
282
	 * @return array
283
	 */
284 View Code Duplication
	private function getRegistrations($user_id)
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...
285
	{
286
		$sql = 'SELECT * FROM ' . $this->otp_registration_table . ' WHERE user_id = ' . (int) $user_id;
287
		$result = $this->db->sql_query($sql);
288
		$rows = $this->db->sql_fetchrowset($result);
289
290
		$this->db->sql_freeresult($result);
291
		return $rows;
292
	}
293
}
294