Passed
Push — master ( 4393f1...8816bb )
by Ashish
02:47
created

setupTwoFactorAuthentication()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 21
rs 9.3142
cc 2
eloc 13
nc 2
nop 1
1
<?php
2
3
namespace Thecodework\TwoFactorAuthentication\Http\Controllers;
4
5
use App\Http\Controllers\Controller;
6
use Base32\Base32;
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Facades\Schema;
9
use OTPHP\TOTP;
10
use Thecodework\TwoFactorAuthentication\AuthenticatesUsersWith2FA;
11
use Thecodework\TwoFactorAuthentication\Contracts\TwoFactorAuthenticationInterface;
12
use Thecodework\TwoFactorAuthentication\Exceptions\TwoFactorAuthenticationExceptions;
13
use Thecodework\TwoFactorAuthentication\TwoFactorAuthenticationServiceProvider;
14
15
class TwoFactorAuthenticationController extends Controller implements TwoFactorAuthenticationInterface
16
{
17
    use AuthenticatesUsersWith2FA;
18
19
    /**
20
     * User Model.
21
     */
22
    protected $TwoFAModel;
23
24
    /**
25
     * Assigns $usersModel Property a Model instance.
26
     */
27
    public function __construct()
28
    {
29
        $this->TwoFAModel = TwoFactorAuthenticationServiceProvider::getTwoFAModelInstance();
30
31
        $this->middleware(function ($request, $next) {
32
            $this->setUser(auth()->user());
0 ignored issues
show
Bug introduced by
The method user does only exist in Illuminate\Contracts\Auth\Guard, but not in Illuminate\Contracts\Auth\Factory.

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...
33
            return $next($request);
34
        });
35
    }
36
37
    /**
38
     * Setup two factor authentication.
39
     *
40
     * @param \Illuminate\Http\Request
41
     * @param \Illuminate\Http\Response
42
     *
43
     * @throws \Thecodework\TwoFactorAuthentications\Exceptions\TwoFactorAuthenticationExceptions
44
     */
45
    public function setupTwoFactorAuthentication(Request $request)
46
    {
47
        $this->updateUserWith2FAGeneratedKey();
48
        $user = $this->getUser();
49
        $totp = new TOTP(
50
            config('2fa-config.account_name'),
51
            $user->two_factor_secret_key,
52
            config('2fa-config.period'),
53
            config('2fa-config.digest_algorithm'),
54
            config('2fa-config.number_of_digits')
55
        );
56
57
        $barcode = $totp->getQrCodeUri();
58
59
        // Return Barcode image if ajax Request
60
        if ($request->ajax()) {
61
            return $barcode;
62
        }
63
64
        return view('2fa::setup', compact('barcode', 'user'));
65
    }
66
67
    /**
68
     * Disable 2FA.
69
     *
70
     * @param \Illuminate\Http\Request
71
     *
72
     * @return mixed
73
     */
74 View Code Duplication
    public function enableTwoFactorAuthentication(Request $request)
75
    {
76
        $user = $this->TwoFAModel->find($request->user()->id);
77
        $user->is_two_factor_enabled = 1;
78
        $user->update();
79
80
        if ($request->ajax()) {
81
            return [
82
                'data' => [
83
                    'message'     => 'success',
84
                    'description' => '2FA Enabled',
85
                ],
86
            ];
87
        }
88
89
        return redirect('home');
90
    }
91
92
    /**
93
     * Enable 2FA.
94
     *
95
     * @param \Illuminate\Http\Request
96
     *
97
     * @return mixed
98
     */
99 View Code Duplication
    public function disableTwoFactorAuthentication(Request $request)
100
    {
101
        $user = $this->TwoFAModel->find($request->user()->id);
102
        $user->is_two_factor_enabled = 0;
103
        $user->two_factor_secret_key = null;
104
        $user->update();
105
106
        if ($request->ajax()) {
107
            return [
108
                'data' => [
109
                    'message'     => 'success',
110
                    'description' => '2FA Disabled',
111
                ],
112
            ];
113
        }
114
115
        return redirect('home');
116
    }
117
118
    /**
119
     * Verify Two Factor Authentication.
120
     *
121
     * @param \Illuminate\Http\Request $request
122
     */
123
    public function verifyTwoFactorAuthentication(Request $request)
124
    {
125
        if ($request->session()->has('2fa:user:id')) {
126
            $secret = getenv('HMAC_SECRET');
127
            $signature = hash_hmac('sha256', decrypt($request->session()->get('2fa:user:id')), $secret);
128
129
            if (md5($signature) !== md5($request->signature)) {
130
                return redirect()->intended('login');
131
            }
132
133
            return view('2fa::verify');
134
        }
135
136
        return redirect()->back(); //shoud be configurable
137
    }
138
139
    /**
140
     * Encode Random String to 32 Base Transfer Encoding.
141
     *
142
     * @param int $length Length of the encoded string.
143
     *
144
     * @return string
145
     */
146
    private function base32EncodedString($length = 30):
147
    string
148
    {
149
        return Base32::encode($this->strRandom($length));
150
    }
151
152
    /**
153
     * Generate a more truly "random" alpha-numeric string.
154
     *
155
     * @param int $length
156
     *
157
     * @return string
158
     */
159
    private function strRandom($length = 30):
160
    string
161
    {
162
        $string = '';
163
164
        while (($len = strlen($string)) < $length) {
165
            $size = $length - $len;
166
167
            $bytes = random_bytes($size);
168
169
            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
170
        }
171
172
        return $string;
173
    }
174
175
    private function updateUserWith2FAGeneratedKey()
176
    {
177
        $user = $this->TwoFAModel->find($this->getUser()->id);
178
        if (!Schema::hasColumn(config('2fa-config.table'), 'two_factor_secret_key') ||
179
            !Schema::hasColumn(config('2fa-config.table'), 'is_two_factor_enabled')) {
180
            throw TwoFactorAuthenticationExceptions::columnNotFound();
181
        }
182
        $user->two_factor_secret_key = $user->two_factor_secret_key ?? $this->base32EncodedString(config('2fa-config.number_of_digits'));
183
        $user->update();
184
    }
185
}
186