Completed
Pull Request — master (#13)
by
unknown
15:09
created

TotpController   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 182
Duplicated Lines 5.49 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 2
dl 10
loc 182
rs 10
c 0
b 0
f 0
ccs 0
cts 90
cp 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A behaviors() 0 26 1
A denyCallback() 0 4 1
C actionEnable() 10 60 11
B actionDisable() 0 29 6
A deferredRedirect() 0 4 1
A actionToggle() 0 7 2
A actionCheck() 0 30 4
A goBack() 0 9 2

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
 * Multi-factor authentication for Yii2 projects
4
 *
5
 * @link      https://github.com/hiqdev/yii2-mfa
6
 * @package   yii2-mfa
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2016-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\yii2\mfa\controllers;
12
13
use hiqdev\yii2\mfa\base\MfaIdentityInterface;
14
use hiqdev\yii2\mfa\base\RecoveryCodeCollection;
15
use hiqdev\yii2\mfa\forms\InputForm;
16
use Yii;
17
use yii\filters\AccessControl;
18
19
/**
20
 * TOTP controller.
21
 * Time-based One Time Password.
22
 */
23
class TotpController extends \yii\web\Controller
24
{
25
    public function behaviors()
26
    {
27
        return array_merge(
28
            parent::behaviors(),
29
            [
30
                'access' => [
31
                    'class' => AccessControl::class,
32
                    'denyCallback' => [$this, 'denyCallback'],
33
                    'rules' => [
34
                        // ? - guest
35
                        [
36
                            'actions' => ['check'],
37
                            'roles' => ['?'],
38
                            'allow' => true,
39
                        ],
40
                        // @ - authenticated
41
                        [
42
                            'actions' => ['enable', 'disable', 'toggle'],
43
                            'roles' => ['@'],
44
                            'allow' => true,
45
                        ],
46
                    ],
47
                ],
48
            ]
49
        );
50
    }
51
52
    public function denyCallback()
53
    {
54
        return $this->goHome();
55
    }
56
57
    public function actionEnable($back = null)
58
    {
59
        /** @var MfaIdentityInterface $user */
60
        $user = Yii::$app->user->identity;
61 View Code Duplication
        if ($user->getTotpSecret()) {
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...
62
            Yii::$app->session->setFlash(
63
                'error',
64
                Yii::t('mfa', 'Two-factor authentication is already enabled. Disable first.')
65
            );
66
67
            return empty($back) ? $this->goHome() : $this->deferredRedirect($back);
68
        }
69
70
        $model = new InputForm();
71
        $secret = $this->module->getTotp()->getSecret();
72
73
        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
74
            if ($this->module->getTotp()->verifyCode($secret, $model->code)) {
75
                $user->setTotpSecret($secret);
76
                $this->module->getTotp()->setIsVerified(true);
77
                if ($user->save() && Yii::$app->user->login($user)) {
78
                    $recovery = new RecoveryCodeCollection();
79
                    if (!$recovery->generate()->save()) {
80
                        Yii::$app->session->setFlash(
81
                            'error',
82
                            Yii::t(
83
                                'mfa',
84
                                'Sorry, we have failed to generate your recovery codes. Please try again later.'
85
                            )
86
                        );
87
                    }
88
                    Yii::$app->session->setFlash(
89
                        'success',
90
                        Yii::t('mfa', 'Two-factor authentication successfully enabled.')
91
                    );
92
93
                    return empty($back) ? $this->goBack() : $this->deferredRedirect($back);
94 View Code Duplication
                } else {
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...
95
                    Yii::$app->session->setFlash(
96
                        'error',
97
                        Yii::t(
98
                            'mfa',
99
                            'Sorry, we have failed to enable two-factor authentication.'
100
                        )
101
                    );
102
103
                    return empty($back) ? $this->goHome() : $this->deferredRedirect($back);
104
                }
105
            } else {
106
                $model->addError(
107
                    'code',
108
                    Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')
109
                );
110
            }
111
        }
112
113
        $qrcode = $this->module->getTotp()->getQRCodeImageAsDataUri($user->getUsername(), $secret);
114
115
        return $this->render('enable', compact('model', 'secret', 'qrcode'));
116
    }
117
118
    public function actionDisable($back = null)
119
    {
120
        /** @var MfaIdentityInterface $user */
121
        $user = Yii::$app->user->identity;
122
        $model = new InputForm();
123
        $secret = $user->getTotpSecret();
124
125
        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
126
            if ($this->module->getTotp()->verifyCode($secret, $model->code)) {
127
                $this->module->getTotp()->removeSecret();
128
                $user->setTotpSecret('');
129
                if ($user->save()) {
130
                    Yii::$app->session->setFlash(
131
                        'success',
132
                        Yii::t('mfa', 'Two-factor authentication successfully disabled.')
133
                    );
134
                }
135
136
                return empty($back) ? $this->goBack() : $this->deferredRedirect($back);
137
            } else {
138
                $model->addError(
139
                    'code',
140
                    Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')
141
                );
142
            }
143
        }
144
145
        return $this->render('disable', compact('model'));
146
    }
147
148
    public function deferredRedirect($url = null)
149
    {
150
        return $this->render('redirect', compact('url'));
151
    }
152
153
    public function actionToggle($back = null)
154
    {
155
        /** @var MfaIdentityInterface $user */
156
        $user = Yii::$app->user->identity;
157
158
        return empty($user->getTotpSecret()) ? $this->actionEnable($back) : $this->actionDisable($back);
159
    }
160
161
    public function actionCheck()
162
    {
163
        /** @var MfaIdentityInterface $user */
164
        $user = $this->module->getHalfUser();
165
        $model = new InputForm();
166
        $secret = $user->getTotpSecret();
167
168
        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
169
            if ($this->module->getTotp()->verifyCode($secret, $model->code)) {
170
                $this->module->getTotp()->setIsVerified(true);
171
                Yii::$app->user->login($user);
172
173
                return $this->goBack();
174
            } else {
175
                $model->addError(
176
                    'code',
177
                    Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')
178
                );
179
            }
180
        }
181
182
        return $this->render(
183
            'check',
184
            [
185
                'model' => $model,
186
                'issuer' => $this->module->getTotp()->issuer,
187
                'username' => $user->getUsername(),
188
            ]
189
        );
190
    }
191
192
    /**
193
     * @inheritDoc
194
     */
195
    public function goBack($defaultUrl = null)
196
    {
197
        $redirectUrl = Yii::$app->params['totpRedirectBackAction.url'];
198
        if (!empty($redirectUrl)) {
199
            return $this->redirect($redirectUrl);
200
        }
201
202
        return parent::goBack($defaultUrl);
203
    }
204
}
205