Completed
Push — master ( 03b333...573f2e )
by Abdelrahman
02:45
created

processTwoFactorTotpBackup()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 14
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 24
rs 8.9713
1
<?php
2
3
/*
4
 * NOTICE OF LICENSE
5
 *
6
 * Part of the Rinvex Fort Package.
7
 *
8
 * This source file is subject to The MIT License (MIT)
9
 * that is bundled with this package in the LICENSE file.
10
 *
11
 * Package: Rinvex Fort Package
12
 * License: The MIT License (MIT)
13
 * Link:    https://rinvex.com
14
 */
15
16
namespace Rinvex\Fort\Http\Controllers\Frontend;
17
18
use Carbon\Carbon;
19
use Illuminate\Support\MessageBag;
20
use Illuminate\Support\Facades\Auth;
21
use Illuminate\Support\ViewErrorBag;
22
use Illuminate\Support\Facades\Lang;
23
use Rinvex\Fort\Http\Requests\TwoFactorTotp;
24
use Rinvex\Fort\Http\Requests\TwoFactorPhone;
25
use Rinvex\Fort\Services\TwoFactorTotpProvider;
26
use Rinvex\Fort\Contracts\UserRepositoryContract;
27
use Rinvex\Fort\Http\Controllers\AbstractController;
28
29
class TwoFactorUpdateController extends AbstractController
30
{
31
    /**
32
     * The users repository instance.
33
     *
34
     * @var \Rinvex\Fort\Contracts\UserRepositoryContract
35
     */
36
    protected $users;
37
38
    /**
39
     * Create a new account controller instance.
40
     *
41
     * @param \Rinvex\Fort\Contracts\UserRepositoryContract $users
42
     *
43
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
44
     */
45
    public function __construct(UserRepositoryContract $users)
46
    {
47
        $this->users = $users;
48
49
        $this->middleware($this->getAuthMiddleware(), ['except' => $this->middlewareWhitelist]);
50
    }
51
52
    /**
53
     * Show the Two-Factor TOTP enable form.
54
     *
55
     * @param \Rinvex\Fort\Http\Requests\TwoFactorTotp    $request
56
     * @param \Rinvex\Fort\Services\TwoFactorTotpProvider $totpProvider
57
     *
58
     * @return \Illuminate\Http\Response
0 ignored issues
show
Documentation introduced by
Should the return type not be \Illuminate\View\View|\I...\Contracts\View\Factory?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
59
     */
60
    public function showTwoFactorTotpEnable(TwoFactorTotp $request, TwoFactorTotpProvider $totpProvider)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
61
    {
62
        $currentUser = $this->currentUser();
63
        $settings    = $currentUser->getTwoFactor();
64
65
        if (array_get($settings, 'totp.enabled') && ! session()->get('rinvex.fort.alert.success') && ! session()->get('errors')) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
66
            $messageBag = new MessageBag([Lang::get('rinvex.fort::message.verification.twofactor.totp.already')]);
67
            $errors     = (new ViewErrorBag())->put('default', $messageBag);
68
        }
69
70
        if (! $secret = array_get($settings, 'totp.secret')) {
71
            array_set($settings, 'totp.enabled', false);
72
            array_set($settings, 'totp.secret', $secret = $totpProvider->generateSecretKey());
73
74
            $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
75
                'two_factor' => $settings,
76
            ]);
77
        }
78
79
        $qrCode = $totpProvider->getQRCodeInline(config('rinvex.fort.twofactor.issuer'), $currentUser->email, $secret);
0 ignored issues
show
Bug introduced by
Accessing email on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
80
81
        return view('rinvex.fort::profile.twofactor', compact('secret', 'qrCode', 'settings', 'errors'));
82
    }
83
84
    /**
85
     * Process the Two-Factor TOTP enable form.
86
     *
87
     * @param \Rinvex\Fort\Http\Requests\TwoFactorTotp    $request
88
     * @param \Rinvex\Fort\Services\TwoFactorTotpProvider $totpProvider
89
     *
90
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
91
     */
92
    public function processTwoFactorTotpEnable(TwoFactorTotp $request, TwoFactorTotpProvider $totpProvider)
93
    {
94
        $currentUser = $this->currentUser();
95
        $settings    = $currentUser->getTwoFactor();
96
        $secret      = array_get($settings, 'totp.secret');
97
        $backup      = array_get($settings, 'totp.backup');
98
        $backupAt    = array_get($settings, 'totp.backup_at');
99
100
        if ($totpProvider->verifyKey($secret, $request->get('token'))) {
101
            array_set($settings, 'totp.enabled', true);
102
            array_set($settings, 'totp.secret', $secret);
103
            array_set($settings, 'totp.backup', $backup ?: $this->generateTwoFactorTotpBackups());
104
            array_set($settings, 'totp.backup_at', $backupAt ?: (new Carbon())->toDateTimeString());
105
106
            // Update Two-Factor settings
107
            $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
108
                'two_factor' => $settings,
109
            ]);
110
111
            return intend([
112
                'back' => true,
113
                'with' => ['rinvex.fort.alert.success' => Lang::get('rinvex.fort::message.verification.twofactor.totp.enabled')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 129 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
114
            ]);
115
        }
116
117
        return intend([
118
            'back'       => true,
119
            'withErrors' => ['token' => Lang::get('rinvex.fort::message.verification.twofactor.totp.invalid_token')],
120
        ]);
121
    }
122
123
    /**
124
     * Process the Two-Factor TOTP disable.
125
     *
126
     * @param \Rinvex\Fort\Http\Requests\TwoFactorTotp $request
127
     *
128
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
129
     */
130
    public function processTwoFactorTotpDisable(TwoFactorTotp $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
131
    {
132
        $currentUser = $this->currentUser();
133
        $settings    = $currentUser->getTwoFactor();
134
135
        array_set($settings, 'totp', []);
136
137
        $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
138
            'two_factor' => $settings,
139
        ]);
140
141
        return intend([
142
            'intended' => route('rinvex.fort.account.page'),
143
            'with'     => ['rinvex.fort.alert.success' => Lang::get('rinvex.fort::message.verification.twofactor.totp.disabled')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
144
        ]);
145
    }
146
147
    /**
148
     * Process the Two-Factor Phone enable.
149
     *
150
     * @param \Rinvex\Fort\Http\Requests\TwoFactorPhone $request
151
     *
152
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
153
     */
154
    public function processTwoFactorPhoneEnable(TwoFactorPhone $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
155
    {
156
        $currentUser = $this->currentUser();
157
158
        if (! $currentUser->phone || ! $currentUser->phone_verified) {
0 ignored issues
show
Bug introduced by
Accessing phone on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing phone_verified on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
159
            return intend([
160
                'intended'   => route('rinvex.fort.account.page'),
161
                'withErrors' => ['phone' => Lang::get('rinvex.fort::message.account.phone_required')],
162
            ]);
163
        }
164
165
        $settings = $currentUser->getTwoFactor();
166
167
        array_set($settings, 'phone.enabled', true);
168
169
        $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
170
            'two_factor' => $settings,
171
        ]);
172
173
        return intend([
174
            'intended' => route('rinvex.fort.account.page'),
175
            'with'     => ['rinvex.fort.alert.success' => Lang::get('rinvex.fort::message.verification.twofactor.phone.enabled')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
176
        ]);
177
    }
178
179
    /**
180
     * Process the Two-Factor Phone disable.
181
     *
182
     * @param \Rinvex\Fort\Http\Requests\TwoFactorPhone $request
183
     *
184
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
185
     */
186
    public function processTwoFactorPhoneDisable(TwoFactorPhone $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
187
    {
188
        $currentUser = $this->currentUser();
189
        $settings    = $currentUser->getTwoFactor();
190
191
        array_set($settings, 'phone.enabled', false);
192
193
        $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
194
            'two_factor' => $settings,
195
        ]);
196
197
        return intend([
198
            'intended' => route('rinvex.fort.account.page'),
199
            'with'     => ['rinvex.fort.alert.success' => Lang::get('rinvex.fort::message.verification.twofactor.phone.disabled')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 131 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
200
        ]);
201
    }
202
203
    /**
204
     * Process the Two-Factor OTP backup.
205
     *
206
     * @param \Rinvex\Fort\Http\Requests\TwoFactorTotp $request
207
     *
208
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
209
     */
210
    public function processTwoFactorTotpBackup(TwoFactorTotp $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
211
    {
212
        $currentUser = $this->currentUser();
213
        $settings    = $currentUser->getTwoFactor();
214
215
        if (! array_get($settings, 'totp.enabled')) {
216
            return intend([
217
                'intended'   => route('rinvex.fort.account.page'),
218
                'withErrors' => ['rinvex.fort.verification.twofactor.totp.cant_backup' => Lang::get('rinvex.fort::message.verification.twofactor.totp.cant_backup')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 165 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
219
            ]);
220
        }
221
222
        array_set($settings, 'totp.backup', $this->generateTwoFactorTotpBackups());
223
        array_set($settings, 'totp.backup_at', (new Carbon())->toDateTimeString());
224
225
        $this->users->update($currentUser->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
226
            'two_factor' => $settings,
227
        ]);
228
229
        return intend([
230
            'back' => true,
231
            'with' => ['rinvex.fort.alert.success' => Lang::get('rinvex.fort::message.verification.twofactor.totp.rebackup')],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
232
        ]);
233
    }
234
235
    /**
236
     * Generate Two-Factor OTP backup codes.
237
     *
238
     * @return array
239
     */
240
    protected function generateTwoFactorTotpBackups()
241
    {
242
        $backup = [];
243
244
        for ($x = 0; $x <= 9; $x++) {
245
            $backup[] = str_pad(random_int(0, 9999999999), 10, 0, STR_PAD_BOTH);
246
        }
247
248
        return $backup;
249
    }
250
251
    /**
252
     * Get current user.
253
     *
254
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract
255
     */
256
    protected function currentUser()
257
    {
258
        return Auth::guard($this->getGuard())->user();
259
    }
260
}
261