adjustViewParams()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
/**
3
 * Two factor authentication provider for Threema Gateway which sends a 6-digit secret/code.
4
 * to the user.
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 gets a login secret. Similar to SMS/email 2FA.
14
 */
15
class ThreemaGateway_Tfa_Conventional extends ThreemaGateway_Tfa_AbstractProvider
16
{
17
    /**
18
     * Return a description of the 2FA methode.
19
     */
20
    public function getDescription()
21
    {
22
        /** @var array $params */
23
        $params = [];
24
        if ($this->gatewaySettings->isEndToEnd()) {
25
            $params['e2e'] = new XenForo_Phrase('threemagw_message_is_sent_e2e');
26
        } else {
27
            $params['e2e'] = '';
28
        }
29
30
        return new XenForo_Phrase('tfa_' . $this->_providerId . '_desc', $params);
31
    }
32
33
    /**
34
     * Called when verifying displaying the choose 2FA mode.
35
     *
36
     * @return bool
37
     */
38
    public function canEnable()
39
    {
40
        if (!parent::canEnable()) {
41
            return false;
42
        }
43
44
        // check whether it is activated in the settings
45
        /** @var XenForo_Options $options */
46
        $options = XenForo_Application::getOptions();
47
        if (!$options->threema_gateway_tfa_conventional) {
48
            return false;
49
        }
50
51
        // check specific permissions
52
        if (!$this->gatewayPermissions->hasPermission('send') ||
53
            !$this->gatewayPermissions->hasPermission('fetch')
54
        ) {
55
            return false;
56
        }
57
58
        return true;
59
    }
60
61
    /**
62
     * Called when trying to verify user. Sends Threema message.
63
     *
64
     * @param  string $context
65
     * @param  array  $user
66
     * @param  string $userIp
67
     * @param  array  $providerData
68
     * @return array
69
     */
70
    public function triggerVerification($context, array $user, $userIp, array &$providerData)
71
    {
72
        parent::triggerVerification($context, $user, $userIp, $providerData);
73
74
        if (!$providerData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $providerData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
75
            return [];
76
        }
77
78
        /** @var XenForo_Options $options */
79
        $options = XenForo_Application::getOptions();
80
81
        /** @var string $secret random 6 digit string */
82
        $secret = $this->generateRandomSecret();
83
84
        $providerData['secret']          = $secret;
85
        $providerData['secretGenerated'] = XenForo_Application::$time;
86
87
        //secret is only valid for some time
88 View Code Duplication
        if ($context == 'setup') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
89
            $providerData['validationTime'] = $options->threema_gateway_tfa_conventional_validation_setup * 60; //default: 10 minutes
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
90
        } else {
91
            $providerData['validationTime'] = $options->threema_gateway_tfa_conventional_validation * 60; //default: 3 minutes
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
92
        }
93
94
        // add options
95
        if ($providerData['useNumberSmilies']) {
96
            $secret = ThreemaGateway_Helper_Emoji::replaceDigits($secret);
97
        } else {
98
            // make secret a bold text
99
            $secret = '*' . $secret . '*';
100
        }
101
102
        /** @var string $phrase name of XenForo phrase to use */
103
        $phrase = 'tfa_threemagw_conventional_message';
104
        if ($providerData['useShortMessage']) {
105
            $phrase = 'tfa_threemagw_conventional_message_short';
106
        }
107
108
        $message = new XenForo_Phrase($phrase, [
109
            'secret' => $secret,
110
            'user' => $user['username'],
111
            'ip' => $userIp,
112
            'validationTime' => $this->parseTime($providerData['validationTime']),
113
            'board' => $options->boardTitle,
114
            'board_url' => $options->boardUrl
115
        ]);
116
117
        $this->sendMessage($providerData['threemaid'], $message);
118
119
        return [];
120
    }
121
122
    /**
123
     * Called when trying to verify user. Shows input for the secret and such things.
124
     *
125
     * @param  XenForo_View $view
126
     * @param  string       $context
127
     * @param  array        $user
128
     * @param  array        $providerData
129
     * @param  array        $triggerData
130
     * @return string       HTML code
131
     */
132
    public function renderVerification(XenForo_View $view, $context, array $user,
133
                                        array $providerData, array $triggerData)
134
    {
135
        parent::renderVerification($view, $context, $user, $providerData, $triggerData);
136
137
        $params = [
138
            'data' => $providerData,
139
            'context' => $context,
140
        ];
141
142
        return $view->createTemplateObject('two_step_threemagw_conventional', $params)->render();
143
    }
144
145
    /**
146
     * Called when trying to verify user. Checks whether a given secret is valid.
147
     *
148
     * @param string $context
149
     * @param array  $input
150
     * @param array  $user
151
     * @param array  $providerData
152
     *
153
     * @return bool
154
     */
155
    public function verifyFromInput($context, XenForo_Input $input, array $user, array &$providerData)
156
    {
157
        /** @var bool $result from parent, for error checking */
158
        $result = parent::verifyFromInput($context, $input, $user, $providerData);
159
160
        // let errors pass through
161
        if (!$result) {
162
            return $result;
163
        }
164
165
        // verify that secret has not expired yet
166
        if (!$this->verifySecretIsInTime($providerData)) {
167
            return false;
168
        }
169
170
        /** @var string $secret 6 digit string given as parameter */
171
        $secret = $input->filterSingle('code', XenForo_Input::STRING);
172
        $secret = preg_replace('/[^0-9]/', '', $secret); //remove all non-numeric characters
173
        if (!$secret) {
174
            return false;
175
        }
176
177
        // prevent replay attacks
178
        if (!$this->verifyNoReplayAttack($providerData, $secret)) {
179
            return false;
180
        }
181
182
        // compare required and given secret
183
        if (!$this->stringCompare($providerData['secret'], $secret)) {
184
            return false;
185
        }
186
187
        $this->updateReplayCheckData($providerData, $secret);
188
189
        $this->resetProviderOptionsForTrigger($context, $providerData);
190
191
        return true;
192
    }
193
194
    /**
195
     * Verifies the Treema ID formally after it was entered/changed.
196
     *
197
     * @param XenForo_Input $input
198
     * @param array         $user
199
     * @param array         $error
200
     *
201
     * @return array
202
     */
203
    public function verifySetupFromInput(XenForo_Input $input, array $user, &$error)
204
    {
205
        /** @var array $providerData */
206
        $providerData = parent::verifySetupFromInput($input, $user, $error);
207
208
        // let errors pass through
209
        if (!$providerData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $providerData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
210
            return $providerData;
211
        }
212
213
        //add other options to provider data
214
        $providerData['useNumberSmilies'] = $input->filterSingle('useNumberSmilies', XenForo_Input::BOOLEAN);
215
        $providerData['useShortMessage']  = $input->filterSingle('useShortMessage', XenForo_Input::BOOLEAN);
216
217
        return $providerData;
218
    }
219
220
    /**
221
     * Called before the setup verification is shown.
222
     *
223
     * @param array $providerData
224
     * @param array $triggerData
225
     *
226
     * @return bool
227
     */
228
    protected function initiateSetupData(array &$providerData, array &$triggerData)
229
    {
230
        return true;
231
    }
232
233
    /**
234
     * Generates the default provider options at setup time before it is
235
     * displayed to the user.
236
     *
237
     * @return array
238
     */
239
    protected function generateDefaultData()
240
    {
241
        return [
242
            'useNumberSmilies' => true,
243
            'useShortMessage' => false,
244
        ];
245
    }
246
247
    /**
248
     * Adjust the view aparams, e.g. add special params needed by your
249
     * template.
250
     *
251
     * @param array  $viewParams
252
     * @param string $context
253
     * @param array  $user
254
     *
255
     * @return array
256
     */
257
    protected function adjustViewParams(array $viewParams, $context, array $user)
258
    {
259
        return $viewParams;
260
    }
261
}
262