1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Two factor authentication provider for Threema Gateway which sends a |
4
|
|
|
* confirmation message. |
5
|
|
|
* |
6
|
|
|
* @package ThreemaGateway |
7
|
|
|
* @author rugk |
8
|
|
|
* @copyright Copyright (c) 2015-2016 rugk |
9
|
|
|
* @license MIT |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* TFA where the user acknowledges a message sent my the server. |
14
|
|
|
*/ |
15
|
|
|
class ThreemaGateway_Tfa_Fast extends ThreemaGateway_Tfa_AbstractProvider |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* Called when verifying displaying the choose 2FA mode. |
19
|
|
|
* |
20
|
|
|
* @return bool |
21
|
|
|
*/ |
22
|
|
View Code Duplication |
public function canEnable() |
|
|
|
|
23
|
|
|
{ |
24
|
|
|
if (!parent::canEnable()) { |
25
|
|
|
return false; |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
// check whether it is activated in the settings |
29
|
|
|
/** @var XenForo_Options $options */ |
30
|
|
|
$options = XenForo_Application::getOptions(); |
31
|
|
|
if (!$options->threema_gateway_tfa_fast) { |
32
|
|
|
return false; |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
// this 2FA mode requires end-to-end encryption |
36
|
|
|
if (!$this->gatewaySettings->isEndToEnd()) { |
37
|
|
|
return false; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
// check specific permissions |
41
|
|
|
if (!$this->gatewayPermissions->hasPermission('send') || |
42
|
|
|
!$this->gatewayPermissions->hasPermission('receive') || |
43
|
|
|
!$this->gatewayPermissions->hasPermission('fetch') |
44
|
|
|
) { |
45
|
|
|
return false; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
return true; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Called when trying to verify user. Creates secret and registers callback |
53
|
|
|
* request. |
54
|
|
|
* |
55
|
|
|
* @param string $context |
56
|
|
|
* @param array $user |
57
|
|
|
* @param string $ip |
58
|
|
|
* @param array $providerData |
59
|
|
|
* @return array |
60
|
|
|
*/ |
61
|
|
|
public function triggerVerification($context, array $user, $ip, array &$providerData) |
62
|
|
|
{ |
63
|
|
|
parent::triggerVerification($context, $user, $ip, $providerData); |
64
|
|
|
|
65
|
|
|
// this 2FA mode requires end-to-end encryption |
66
|
|
|
if (!$this->gatewaySettings->isEndToEnd()) { |
67
|
|
|
throw new XenForo_Exception(new XenForo_Phrase('threema_this_action_required_e2e')); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** @var XenForo_Options $options */ |
71
|
|
|
$options = XenForo_Application::getOptions(); |
72
|
|
|
|
73
|
|
|
//message is only valid for some time |
74
|
|
View Code Duplication |
if ($context == 'setup') { |
|
|
|
|
75
|
|
|
$providerData['validationTime'] = $options->threema_gateway_tfa_fast_validation_setup * 60; //default: 10 minutes |
|
|
|
|
76
|
|
|
} else { |
77
|
|
|
$providerData['validationTime'] = $options->threema_gateway_tfa_fast_validation * 60; //default: 3 minutes |
|
|
|
|
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
// temporarily save IP, which triggered this |
81
|
|
|
$providerData['triggerIp'] = $ip; |
82
|
|
|
|
83
|
|
|
// send message |
84
|
|
|
/** @var string $phrase name of XenForo phrase to use */ |
85
|
|
|
$phrase = 'tfa_threemagw_fast_message'; |
86
|
|
|
if ($context == 'setup') { |
87
|
|
|
$phrase = 'tfa_threemagw_fast_setup_message'; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** @var bool $isBlocked true when the user is blocked */ |
91
|
|
|
$isBlocked = false; |
92
|
|
|
// whether the login is still blocked right now |
93
|
|
|
if ($this->userIsBlocked($providerData, true)) { |
94
|
|
|
$isBlocked = true; |
95
|
|
|
if ( |
96
|
|
|
$this->gatewayPermissions->hasPermission('blockedNotification') && |
97
|
|
|
!$providerData['blockedNotification'] |
98
|
|
|
) { |
99
|
|
|
// skip message sending |
100
|
|
|
// This is not recommend as it makes the whole request faster, |
101
|
|
|
// which means timing attacks can be used to detect that the |
102
|
|
|
// user is blocked |
103
|
|
|
return []; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
// silently send a block message noticing the user of the |
107
|
|
|
// blocking |
108
|
|
|
$phrase .= '_blocked'; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
if (!$isBlocked && $providerData['useShortMessage']) { |
112
|
|
|
$phrase .= '_short'; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** @var XenForo_Phrase $message */ |
116
|
|
|
$message = new XenForo_Phrase($phrase, [ |
117
|
|
|
'user' => $user['username'], |
118
|
|
|
'ip' => $ip, |
119
|
|
|
'validationTime' => $this->parseTime($providerData['validationTime']), |
120
|
|
|
'board' => $options->boardTitle, |
121
|
|
|
'board_url' => $options->boardUrl |
122
|
|
|
]); |
123
|
|
|
|
124
|
|
|
/** @var int $messageId */ |
125
|
|
|
$messageId = $this->sendMessage($providerData['threemaid'], $message); |
126
|
|
|
|
127
|
|
|
// save message ID as secret here |
128
|
|
|
$providerData['secret'] = $messageId; |
129
|
|
|
$providerData['secretGenerated'] = XenForo_Application::$time; |
130
|
|
|
|
131
|
|
|
// register message request for Threema callback |
132
|
|
|
$this->registerPendingConfirmationMessage( |
133
|
|
|
$providerData, |
134
|
|
|
ThreemaGateway_Model_TfaPendingMessagesConfirmation::PENDING_REQUEST_DELIVERY_RECEIPT, |
135
|
|
|
$user, |
136
|
|
|
$messageId |
137
|
|
|
); |
138
|
|
|
|
139
|
|
|
return []; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Called when trying to verify user. Shows only the request to confirm |
144
|
|
|
* the message. |
145
|
|
|
* |
146
|
|
|
* @param XenForo_View $view |
147
|
|
|
* @param string $context |
148
|
|
|
* @param array $user |
149
|
|
|
* @param array $providerData |
150
|
|
|
* @param array $triggerData |
151
|
|
|
* @return string HTML code |
152
|
|
|
*/ |
153
|
|
|
public function renderVerification(XenForo_View $view, $context, array $user, |
154
|
|
|
array $providerData, array $triggerData) |
155
|
|
|
{ |
156
|
|
|
parent::renderVerification($view, $context, $user, $providerData, $triggerData); |
157
|
|
|
|
158
|
|
|
/** @var XenForo_Options $xenOptions */ |
159
|
|
|
$xenOptions = XenForo_Application::getOptions(); |
160
|
|
|
|
161
|
|
|
$params = [ |
162
|
|
|
'data' => $providerData, |
163
|
|
|
'trigger' => $triggerData, |
164
|
|
|
'context' => $context, |
165
|
|
|
'validationTime' => $this->parseTime($providerData['validationTime']), |
166
|
|
|
'gatewayid' => $this->gatewaySettings->getId(), |
167
|
|
|
'autoTrigger' => $xenOptions->threema_gateway_tfa_fast_auto_trigger |
168
|
|
|
]; |
169
|
|
|
return $view->createTemplateObject('two_step_threemagw_fast', $params)->render(); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Called when trying to verify user. Checks whether the delivery receipt was received |
174
|
|
|
* from the Threema Gateway callback and acknowledges the message. |
175
|
|
|
* |
176
|
|
|
* @param string $context |
177
|
|
|
* @param array $input |
178
|
|
|
* @param array $user |
179
|
|
|
* @param array $providerData |
180
|
|
|
* |
181
|
|
|
* @return bool |
182
|
|
|
*/ |
183
|
|
|
public function verifyFromInput($context, XenForo_Input $input, array $user, array &$providerData) |
184
|
|
|
{ |
185
|
|
|
$result = parent::verifyFromInput($context, $input, $user, $providerData); |
186
|
|
|
|
187
|
|
|
// let errors pass through |
188
|
|
|
if (!$result) { |
189
|
|
|
return $result; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
|
193
|
|
|
// assure that secret has not expired yet |
194
|
|
|
if (!$this->verifySecretIsInTime($providerData)) { |
195
|
|
|
return false; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
// assure that secret has been received at all |
199
|
|
|
if (!isset($providerData['receivedSecret'])) { |
200
|
|
|
return false; |
201
|
|
|
} |
202
|
|
|
if (!isset($providerData['receivedDeliveryReceipt'])) { |
203
|
|
|
return false; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
// prevent replay attacks |
207
|
|
|
if (!$this->verifyNoReplayAttack($providerData, $providerData['receivedSecret'])) { |
208
|
|
|
return false; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
// assure that the secret is the same as required |
212
|
|
|
if (!$this->stringCompare($providerData['secret'], $providerData['receivedSecret'])) { |
213
|
|
|
return false; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
// verify block state |
217
|
|
|
// we do this right now to prevent timing attacks to detect whether the |
218
|
|
|
// user is blocked |
219
|
|
|
if ($this->userIsBlocked($providerData)) { |
220
|
|
|
return false; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
// assure that the current delivery receipt is *not* a decline message |
224
|
|
|
if ($providerData['receivedDeliveryReceipt'] === 4) { |
225
|
|
|
// take more drastic steps if it the user explicitly disallowed access |
226
|
|
|
$this->handleMessageDecline($providerData, $user); |
227
|
|
|
if ($context == 'login') { |
228
|
|
|
// manually need to save provider data as when verification fails this is not done by default |
229
|
|
|
$tfaModel = XenForo_Model::create('XenForo_Model_Tfa'); |
230
|
|
|
$tfaModel->updateUserProvider($user['user_id'], $this->_providerId, $providerData, true); |
231
|
|
|
// usually this part of the code should never be reached as the callback/receiver |
232
|
|
|
// triggers this check and saves the resulting provider data in any case |
233
|
|
|
} |
234
|
|
|
return false; // and fail silently |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
// assure that the receipt message is a confirmation/acknowledge receipt |
238
|
|
|
// or has at least been a confirmation receipe before |
239
|
|
|
if ($providerData['receivedDeliveryReceipt'] !== 3 && |
240
|
|
|
$providerData['receivedDeliveryReceiptLargest'] !== 3 |
241
|
|
|
) { |
242
|
|
|
return false; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
$this->updateReplayCheckData($providerData, $providerData['receivedSecret']); |
246
|
|
|
|
247
|
|
|
// unregister confirmation |
248
|
|
|
$this->unregisterPendingConfirmationMessage( |
249
|
|
|
$providerData, |
250
|
|
|
ThreemaGateway_Model_TfaPendingMessagesConfirmation::PENDING_REQUEST_DELIVERY_RECEIPT |
251
|
|
|
); |
252
|
|
|
|
253
|
|
|
// unset data |
254
|
|
|
// |
255
|
|
|
// IMPORTANT: This is very important here as some data cannot be replay- |
256
|
|
|
// checked and would therefore result in a vulnerability. |
257
|
|
|
// Especially 'receivedDeliveryReceiptLargest' would lead to problems |
258
|
|
|
// this case when it is not reset! |
259
|
|
|
$this->resetProviderOptionsForTrigger($context, $providerData); |
260
|
|
|
|
261
|
|
|
return true; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Verifies the Treema ID formally after it was entered/changed. |
266
|
|
|
* |
267
|
|
|
* @param XenForo_Input $input |
268
|
|
|
* @param array $user |
269
|
|
|
* @param array $error |
270
|
|
|
* |
271
|
|
|
* @return array |
272
|
|
|
*/ |
273
|
|
|
public function verifySetupFromInput(XenForo_Input $input, array $user, &$error) |
274
|
|
|
{ |
275
|
|
|
/** @var array $providerData */ |
276
|
|
|
$providerData = parent::verifySetupFromInput($input, $user, $error); |
277
|
|
|
|
278
|
|
|
// let errors pass through |
279
|
|
|
if (!$providerData) { |
|
|
|
|
280
|
|
|
return $providerData; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
//add other options to provider data |
284
|
|
|
$providerData['useShortMessage'] = $input->filterSingle('useShortMessage', XenForo_Input::BOOLEAN); |
285
|
|
|
|
286
|
|
|
// default to false (if not passed/set/allowed as permissions) |
287
|
|
|
$providerData['blockedNotification'] = false; |
288
|
|
|
$providerData['blockTfaMode'] = false; |
289
|
|
|
$providerData['blockUser'] = false; |
290
|
|
|
$providerData['blockIp'] = false; |
291
|
|
|
|
292
|
|
|
// decline options |
293
|
|
|
if ($this->gatewayPermissions->hasPermission('blockedNotification')) { |
294
|
|
|
$providerData['blockedNotification'] = $input->filterSingle('blockedNotification', XenForo_Input::BOOLEAN); |
295
|
|
|
} |
296
|
|
|
if ($this->gatewayPermissions->hasPermission('blockTfaMode')) { |
297
|
|
|
$providerData['blockTfaMode'] = $input->filterSingle('blockTfaMode', XenForo_Input::BOOLEAN); |
298
|
|
|
} |
299
|
|
|
if ($this->gatewayPermissions->hasPermission('blockUser')) { |
300
|
|
|
$providerData['blockUser'] = $input->filterSingle('blockUser', XenForo_Input::BOOLEAN); |
301
|
|
|
} |
302
|
|
|
if ($this->gatewayPermissions->hasPermission('blockIp')) { |
303
|
|
|
$providerData['blockIp'] = $input->filterSingle('blockIp', XenForo_Input::BOOLEAN); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
return $providerData; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Called before the setup verification is shown. |
311
|
|
|
* |
312
|
|
|
* @param array $providerData |
313
|
|
|
* @param array $triggerData |
314
|
|
|
* |
315
|
|
|
* @return bool |
316
|
|
|
*/ |
317
|
|
|
protected function initiateSetupData(array &$providerData, array &$triggerData) |
318
|
|
|
{ |
319
|
|
|
return true; |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Generates the default provider options at setup time before it is |
324
|
|
|
* displayed to the user. |
325
|
|
|
* |
326
|
|
|
* @return array |
327
|
|
|
*/ |
328
|
|
|
protected function generateDefaultData() |
329
|
|
|
{ |
330
|
|
|
return [ |
331
|
|
|
'useShortMessage' => false, |
332
|
|
|
'blockedNotification' => true, |
333
|
|
|
'blockTfaMode' => true, |
334
|
|
|
'blockUser' => false, |
335
|
|
|
'blockIp' => false |
336
|
|
|
]; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Adjust the view params for managing the 2FA mode, e.g. add special |
341
|
|
|
* params needed by your template. |
342
|
|
|
* |
343
|
|
|
* @param array $viewParams |
344
|
|
|
* @param string $context |
345
|
|
|
* @param array $user |
346
|
|
|
* |
347
|
|
|
* @return array |
348
|
|
|
*/ |
349
|
|
|
protected function adjustViewParams(array $viewParams, $context, array $user) |
350
|
|
|
{ |
351
|
|
|
/** @var XenForo_Options $xenOptions */ |
352
|
|
|
$xenOptions = XenForo_Application::getOptions(); |
353
|
|
|
|
354
|
|
|
/** @var array $declinePermissions all permissions when declining a message */ |
355
|
|
|
$declinePermissions = [ |
356
|
|
|
'blockedNotification' => $this->gatewayPermissions->hasPermission('blockedNotification'), |
357
|
|
|
'blockTfaMode' => $this->gatewayPermissions->hasPermission('blockTfaMode'), |
358
|
|
|
'blockUser' => $this->gatewayPermissions->hasPermission('blockUser'), |
359
|
|
|
'blockIp' => $this->gatewayPermissions->hasPermission('blockIp'), |
360
|
|
|
]; |
361
|
|
|
|
362
|
|
|
// if user is admin/mod we unfortunately cannot ban them as it is not supported by XenForo |
363
|
|
|
if ($user['is_moderator'] || $user['is_admin']) { |
364
|
|
|
$declinePermissions['blockUser'] = false; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
$viewParams += [ |
368
|
|
|
'https' => XenForo_Application::$secure, |
369
|
|
|
'showqrcode' => $xenOptions->threema_gateway_tfa_fast_show_qr_code, |
370
|
|
|
'gatewayid' => $this->gatewaySettings->getId(), |
371
|
|
|
'blockTime' => $this->parseTime($xenOptions->threema_gateway_tfa_blocking_time * 60), |
372
|
|
|
'blockTimeDayRounded' => $this->parseTime(ThreemaGateway_Helper_General::roundToDayRelative($xenOptions->threema_gateway_tfa_blocking_time * 60, true)), |
373
|
|
|
// permissions for decline options |
374
|
|
|
'declinePermissionsSet' => in_array(true, $declinePermissions, true), |
375
|
|
|
'declinePermissions' => $declinePermissions, |
376
|
|
|
]; |
377
|
|
|
|
378
|
|
|
return $viewParams; |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Resets the provider options to make sure the current 2FA verification |
383
|
|
|
* does not affect the next one. |
384
|
|
|
* |
385
|
|
|
* @param string $context |
386
|
|
|
* @param array $providerData |
387
|
|
|
*/ |
388
|
|
|
protected function resetProviderOptionsForTrigger($context, array &$providerData) |
389
|
|
|
{ |
390
|
|
|
parent::resetProviderOptionsForTrigger($context, $providerData); |
391
|
|
|
|
392
|
|
|
unset($providerData['receivedSecret']); |
393
|
|
|
unset($providerData['receivedDeliveryReceipt']); |
394
|
|
|
unset($providerData['receivedDeliveryReceiptLargest']); |
395
|
|
|
unset($providerData['triggerIp']); |
396
|
|
|
unset($providerData['blocked']); |
397
|
|
|
unset($providerData['blockedUntil']); |
398
|
|
|
unset($providerData['blockedBy']); |
399
|
|
|
unset($providerData['messageDeclineHandeled']); |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
/** |
403
|
|
|
* Checks whether a user is blocked. |
404
|
|
|
* |
405
|
|
|
* @param array $providerData |
406
|
|
|
* @param bool $messageYetToSent Set to true to specify that the message |
407
|
|
|
* still needs to be sent |
408
|
|
|
* |
409
|
|
|
* @return bool |
410
|
|
|
*/ |
411
|
|
|
private function userIsBlocked(array $providerData, $messageYetToSent = false) |
412
|
|
|
{ |
413
|
|
|
// not blocked when not marked as beeing blocked |
414
|
|
|
if (empty($providerData['blocked'])) { |
415
|
|
|
return false; |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
// assure that block is not expired yet |
419
|
|
|
if (XenForo_Application::$time > $providerData['blockedUntil']) { |
420
|
|
|
return false; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
// as message ID is evaluated below, we need to assure that it is |
424
|
|
|
// correct/already set |
425
|
|
|
if ($messageYetToSent) { |
426
|
|
|
// if the message ID has not been sent yet, we know the user is blocked |
427
|
|
|
return true; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
// exception: ignore blocking if the message ID is the same and the |
431
|
|
|
// delivery receipt is an accept message (which overwrites decline |
432
|
|
|
// messages in this case) |
433
|
|
|
if ($this->stringCompare($providerData['blockedBy'], $providerData['secret']) && |
434
|
|
|
$providerData['receivedDeliveryReceipt'] == 3 |
435
|
|
|
) { |
436
|
|
|
// this makes it possible to 'correct' a possible wrong tap on 'decline' |
437
|
|
|
return false; |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
return true; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* Handles the actions when a user declines a received message. |
445
|
|
|
* |
446
|
|
|
* It can block the login for some time, ban the user temporarily or even |
447
|
|
|
* ban the IP permanently. |
448
|
|
|
* |
449
|
|
|
* @param array $providerData |
450
|
|
|
* @param array $user aray of user data |
451
|
|
|
* @param string|null $ip the current IP address |
452
|
|
|
*/ |
453
|
|
|
private function handleMessageDecline(array &$providerData, array $user, $ip = null) |
454
|
|
|
{ |
455
|
|
|
/** @var XenForo_Options $xenOptions */ |
456
|
|
|
$xenOptions = XenForo_Application::getOptions(); |
457
|
|
|
/** @var int $blockingTime seconds how long users should be blocked */ |
458
|
|
|
$blockingTime = $xenOptions->threema_gateway_tfa_blocking_time * 60; |
459
|
|
|
|
460
|
|
|
if (!$ip) { |
|
|
|
|
461
|
|
|
$ip = $providerData['triggerIp']; |
462
|
|
|
} |
463
|
|
|
// cancel, if already handeled |
464
|
|
|
if (!empty($providerData['messageDeclineHandeled'])) { |
465
|
|
|
return; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
/** @var string $blockActions description of actions taken */ |
469
|
|
|
$blockActions = ''; |
470
|
|
|
|
471
|
|
|
// silently ban 2FA login |
472
|
|
|
if ($this->gatewayPermissions->hasPermission('blockTfaMode') && |
473
|
|
|
$providerData['blockTfaMode'] |
474
|
|
|
) { |
475
|
|
|
// ban this 2FA method |
476
|
|
|
$providerData['blocked'] = true; |
477
|
|
|
$providerData['blockedBy'] = $providerData['secret']; |
478
|
|
|
$providerData['blockedUntil'] = XenForo_Application::$time + $blockingTime; |
479
|
|
|
|
480
|
|
|
// append to action list |
481
|
|
|
$blockActions .= ' ' . (new XenForo_Phrase('tfa_threemagw_message_blocked_login', [ |
482
|
|
|
'blockTime' => $this->parseTime($blockingTime), |
483
|
|
|
]))->render(); |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
// ban user |
487
|
|
|
// Note that the user is not blocked from logging in, in this case; |
488
|
|
|
// they are just shown a blocking message after logging in. |
489
|
|
|
if ($this->gatewayPermissions->hasPermission('blockUser') && |
490
|
|
|
$providerData['blockUser'] |
491
|
|
|
) { |
492
|
|
|
/** @var XenForo_DataWriter_UserBan $userBanDw */ |
493
|
|
|
$userBanDw = XenForo_DataWriter::create('XenForo_DataWriter_UserBan', XenForo_DataWriter::ERROR_SILENT); |
494
|
|
|
$userBanDw->set('user_id', $user['user_id']); |
495
|
|
|
$userBanDw->set('ban_user_id', $user['user_id']); |
496
|
|
|
$userBanDw->set('user_reason', new XenForo_Phrase('threemagw_tfa_user_banned')); |
497
|
|
|
// as the ban is only lifted daily we need to set a useful day time |
498
|
|
|
$userBanDw->set('end_date', |
499
|
|
|
// round unix time to day (00:00) |
500
|
|
|
ThreemaGateway_Helper_General::roundToDay( |
501
|
|
|
XenForo_Application::$time + $blockingTime, |
502
|
|
|
true // round up to next full day |
503
|
|
|
) |
504
|
|
|
); |
505
|
|
|
$userBanDw->set('triggered', 1); |
506
|
|
|
$userBanDw->save(); |
507
|
|
|
|
508
|
|
|
// append to action list |
509
|
|
|
$blockActions .= ' ' . (new XenForo_Phrase('tfa_threemagw_message_blocked_user', [ |
510
|
|
|
'blockTime' => $this->parseTime(ThreemaGateway_Helper_General::roundToDayRelative($blockingTime, true)), |
511
|
|
|
]))->render(); |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
// ban ip |
515
|
|
|
if ($this->gatewayPermissions->hasPermission('blockIp') && |
516
|
|
|
$providerData['blockIp'] |
517
|
|
|
) { |
518
|
|
|
/** @var XenForo_Model_Banning $ipBanModel */ |
519
|
|
|
$ipBanModel = XenForo_Model::create('XenForo_Model_Banning'); |
520
|
|
|
$ipBanModel->banIp($ip); |
521
|
|
|
|
522
|
|
|
// append to action list |
523
|
|
|
$blockActions .= ' ' . (new XenForo_Phrase('tfa_threemagw_message_blocked_ip'))->render(); |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
// send notification message |
527
|
|
|
if ($this->gatewayPermissions->hasPermission('blockedNotification') && |
528
|
|
|
$providerData['blockedNotification'] |
529
|
|
|
) { |
530
|
|
|
// remove unneccessary whitespace |
531
|
|
|
$blockActions = trim($blockActions); |
532
|
|
|
|
533
|
|
|
// add line breaks if actions were executed |
534
|
|
|
if ($blockActions) { |
535
|
|
|
$blockActions = PHP_EOL . $blockActions; |
536
|
|
|
} else { |
|
|
|
|
537
|
|
|
// theoretically we could explicitly state that nothing has |
538
|
|
|
// been done, but this is not particularly useful: |
539
|
|
|
// $blockActions = (new XenForo_Phrase('tfa_threemagw_message_blocked_nothing'))->render(); |
|
|
|
|
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
// add information that this is reversible if no permanent block actions |
543
|
|
|
// have been executed |
544
|
|
|
if (!$providerData['blockIp'] && |
545
|
|
|
!$providerData['blockUser'] |
546
|
|
|
) { |
547
|
|
|
$blockActions = PHP_EOL . PHP_EOL . (new XenForo_Phrase('tfa_threemagw_message_blocked_canreverse'))->render(); |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** @var XenForo_Options $options */ |
551
|
|
|
$options = XenForo_Application::getOptions(); |
552
|
|
|
|
553
|
|
|
/** @var XenForo_Phrase $message */ |
554
|
|
|
$message = new XenForo_Phrase('tfa_threemagw_message_blocked_general', [ |
555
|
|
|
'user' => $user['username'], |
556
|
|
|
'ip' => $ip, |
557
|
|
|
'blockActions' => $blockActions, |
558
|
|
|
'board' => $options->boardTitle, |
559
|
|
|
'board_url' => $options->boardUrl |
560
|
|
|
]); |
561
|
|
|
|
562
|
|
|
$this->sendMessage($providerData['threemaid'], $message); |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
// set value to prevent duplicate handling by this method |
566
|
|
|
// This is needed as otherwise this method is executed again and again |
567
|
|
|
// if the user has not activated blockTfaMode. |
568
|
|
|
$providerData['messageDeclineHandeled'] = true; |
569
|
|
|
} |
570
|
|
|
} |
571
|
|
|
|
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.