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

TotpController::actionEnable()   C

Complexity

Conditions 11
Paths 10

Size

Total Lines 60

Duplication

Lines 10
Ratio 16.67 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
dl 10
loc 60
rs 6.726
c 0
b 0
f 0
ccs 0
cts 46
cp 0
cc 11
nc 10
nop 1
crap 132

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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