Completed
Push — master ( 5ee4c9...308b6a )
by Antonio
05:05
created

SettingsController::actionTwoFactorEnable()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 0
cts 14
cp 0
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 17
nc 5
nop 1
crap 20
1
<?php
2
3
/*
4
 * This file is part of the 2amigos/yii2-usuario project.
5
 *
6
 * (c) 2amigOS! <http://2amigos.us/>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace Da\User\Controller;
13
14
use Da\User\Contracts\MailChangeStrategyInterface;
15
use Da\User\Event\ProfileEvent;
16
use Da\User\Event\SocialNetworkConnectEvent;
17
use Da\User\Event\UserEvent;
18
use Da\User\Form\SettingsForm;
19
use Da\User\Model\Profile;
20
use Da\User\Model\SocialNetworkAccount;
21
use Da\User\Model\User;
22
use Da\User\Module;
23
use Da\User\Query\ProfileQuery;
24
use Da\User\Query\SocialNetworkAccountQuery;
25
use Da\User\Query\UserQuery;
26
use Da\User\Service\EmailChangeService;
27
use Da\User\Service\TwoFactorQrCodeUriGeneratorService;
28
use Da\User\Traits\ContainerAwareTrait;
29
use Da\User\Validator\AjaxRequestModelValidator;
30
use Da\User\Validator\TwoFactorCodeValidator;
31
use Yii;
32
use yii\filters\AccessControl;
33
use yii\filters\VerbFilter;
34
use yii\web\Controller;
35
use yii\web\ForbiddenHttpException;
36
use yii\web\NotFoundHttpException;
37
use yii\web\Response;
38
39
class SettingsController extends Controller
40
{
41
    use ContainerAwareTrait;
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public $defaultAction = 'profile';
47
48
    protected $profileQuery;
49
    protected $userQuery;
50
    protected $socialNetworkAccountQuery;
51
52
    /**
53
     * SettingsController constructor.
54
     *
55
     * @param string $id
56
     * @param Module $module
57
     * @param ProfileQuery $profileQuery
58
     * @param UserQuery $userQuery
59
     * @param SocialNetworkAccountQuery $socialNetworkAccountQuery
60
     * @param array $config
61
     */
62 1
    public function __construct(
63
        $id,
64
        Module $module,
65
        ProfileQuery $profileQuery,
66
        UserQuery $userQuery,
67
        SocialNetworkAccountQuery $socialNetworkAccountQuery,
68
        array $config = []
69
    ) {
70 1
        $this->profileQuery = $profileQuery;
71 1
        $this->userQuery = $userQuery;
72 1
        $this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
73 1
        parent::__construct($id, $module, $config);
74 1
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 1
    public function behaviors()
80
    {
81
        return [
82 1
            'verbs' => [
83 1
                'class' => VerbFilter::className(),
84
                'actions' => [
85
                    'disconnect' => ['post'],
86
                    'delete' => ['post'],
87
                    'two-factor-disable' => ['post']
88
                ],
89
            ],
90
            'access' => [
91 1
                'class' => AccessControl::className(),
92
                'rules' => [
93
                    [
94
                        'allow' => true,
95
                        'actions' => [
96
                            'profile',
97
                            'account',
98
                            'networks',
99
                            'disconnect',
100
                            'delete',
101
                            'two-factor',
102
                            'two-factor-enable',
103
                            'two-factor-disable'
104
                        ],
105
                        'roles' => ['@'],
106
                    ],
107
                    [
108
                        'allow' => true,
109
                        'actions' => ['confirm'],
110
                        'roles' => ['?', '@'],
111
                    ],
112
                ],
113
            ],
114
        ];
115
    }
116
117
    public function actionProfile()
118
    {
119
        $profile = $this->profileQuery->whereUserId(Yii::$app->user->identity->getId())->one();
120
121
        if ($profile === null) {
122
            $profile = $this->make(Profile::class);
123
            $profile->link('user', Yii::$app->user->identity);
124
        }
125
126
        $event = $this->make(ProfileEvent::class, [$profile]);
127
128
        $this->make(AjaxRequestModelValidator::class, [$profile])->validate();
129
130
        if ($profile->load(Yii::$app->request->post())) {
131
            $this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event);
132
            if ($profile->save()) {
133
                Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Your profile has been updated'));
0 ignored issues
show
Bug introduced by
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
134
                $this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event);
135
136
                return $this->refresh();
137
            }
138
        }
139
140
        return $this->render(
141
            'profile',
142
            [
143
                'model' => $profile,
144
            ]
145
        );
146
    }
147
148 1
    public function actionAccount()
149
    {
150
        /** @var SettingsForm $form */
151 1
        $form = $this->make(SettingsForm::class);
152 1
        $event = $this->make(UserEvent::class, [$form->getUser()]);
153
154 1
        $this->make(AjaxRequestModelValidator::class, [$form])->validate();
155
156 1
        if ($form->load(Yii::$app->request->post())) {
157
            $this->trigger(UserEvent::EVENT_BEFORE_ACCOUNT_UPDATE, $event);
158
159
            if ($form->save()) {
160
                Yii::$app->getSession()->setFlash(
0 ignored issues
show
Bug introduced by
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
161
                    'success',
162
                    Yii::t('usuario', 'Your account details have been updated')
163
                );
164
                $this->trigger(UserEvent::EVENT_AFTER_ACCOUNT_UPDATE, $event);
165
166
                return $this->refresh();
167
            }
168
        }
169
170 1
        return $this->render(
171 1
            'account',
172
            [
173 1
                'model' => $form,
174
            ]
175
        );
176
    }
177
178
    public function actionConfirm($id, $code)
179
    {
180
        $user = $this->userQuery->whereId($id)->one();
181
182
        if ($user === null || $this->module->emailChangeStrategy == MailChangeStrategyInterface::TYPE_INSECURE) {
183
            throw new NotFoundHttpException();
184
        }
185
        $event = $this->make(UserEvent::class, [$user]);
186
187
        $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
188
        if ($this->make(EmailChangeService::class, [$code, $user])->run()) {
189
            $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event);
190
        }
191
192
        return $this->redirect(['account']);
193
    }
194
195
    public function actionNetworks()
196
    {
197
        return $this->render(
198
            'networks',
199
            [
200
                'user' => Yii::$app->user->identity,
201
            ]
202
        );
203
    }
204
205
    public function actionDisconnect($id)
206
    {
207
        /** @var SocialNetworkAccount $account */
208
        $account = $this->socialNetworkAccountQuery->whereId($id)->one();
209
210
        if ($account === null) {
211
            throw new NotFoundHttpException();
212
        }
213
        if ($account->user_id != Yii::$app->user->id) {
214
            throw new ForbiddenHttpException();
215
        }
216
        $event = $this->make(SocialNetworkConnectEvent::class, [Yii::$app->user->identity, $account]);
217
218
        $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_DISCONNECT, $event);
219
        $account->delete();
220
        $this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_DISCONNECT, $event);
221
222
        return $this->redirect(['networks']);
223
    }
224
225
    public function actionDelete()
226
    {
227
        if (!$this->module->allowAccountDelete) {
228
            throw new NotFoundHttpException(Yii::t('usuario', 'Not found'));
229
        }
230
231
        /** @var User $user */
232
        $user = Yii::$app->user->identity;
233
        $event = $this->make(UserEvent::class, [$user]);
234
        Yii::$app->user->logout();
235
236
        $this->trigger(UserEvent::EVENT_BEFORE_DELETE, $event);
237
        $user->delete();
238
        $this->trigger(UserEvent::EVENT_AFTER_DELETE, $event);
239
240
        Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your account has been completely deleted'));
241
242
        return $this->goHome();
243
    }
244
245
    public function actionTwoFactor($id)
246
    {
247
        /** @var User $user */
248
        $user = $this->userQuery->whereId($id)->one();
249
250
        if (null === $user) {
251
            throw new NotFoundHttpException();
252
        }
253
254
        $uri = $this->make(TwoFactorQrCodeUriGeneratorService::class, [$user])->run();
255
256
        return $this->renderAjax('two-factor', ['id' => $id, 'uri' => $uri]);
257
    }
258
259
    public function actionTwoFactorEnable($id)
260
    {
261
        Yii::$app->response->format = Response::FORMAT_JSON;
262
263
        /** @var User $user */
264
        $user = $this->userQuery->whereId($id)->one();
265
266
        if (null === $user) {
267
            return [
268
                'success' => false,
269
                'message' => Yii::t('usuario', 'User not found.')
270
            ];
271
        }
272
        $code = Yii::$app->request->get('code');
273
274
        $success = $this
275
            ->make(TwoFactorCodeValidator::class, [$user, $code, $this->module->twoFactorAuthenticationCycles])
276
            ->validate();
277
278
        $success = $success && $user->updateAttributes(['auth_tf_enabled' => '1']);
279
280
        return [
281
            'success' => $success,
282
            'message' => $success
283
                ? Yii::t('usuario', 'Two factor successfully enabled.')
284
                : Yii::t('usuario', 'Verification failed. Please, enter new code.')
285
        ];
286
    }
287
288
    public function actionTwoFactorDisable($id)
289
    {
290
        /** @var User $user */
291
        $user = $this->userQuery->whereId($id)->one();
292
293
        if (null === $user) {
294
            throw new NotFoundHttpException();
295
        }
296
297
        if($user->updateAttributes(['auth_tf_enabled' => '0']))
298
        {
299
            Yii::$app
0 ignored issues
show
Bug introduced by
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
300
                ->getSession()
301
                ->setFlash('success', Yii::t('usuario', 'Two-factor authorization has been disabled.'));
302
        } else {
303
            Yii::$app
304
                ->getSession()
305
                ->setFlash('danger', Yii::t('usuario', 'Unable to disable two-factor authorization.'));
306
        }
307
308
        $this->redirect(['account']);
309
    }
310
}
311