GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( c0d893...b5b87f )
by James
05:14
created

Google2FA   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 308
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 73.79%

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 13
dl 0
loc 308
ccs 76
cts 103
cp 0.7379
rs 9.36
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A boot() 0 6 1
A getQRCodeBackend() 0 5 2
A getGoogle2FASecretKey() 0 4 1
A isActivated() 0 6 2
A storeOldTimestamp() 0 6 2
A getOldTimestamp() 0 6 2
A keepAlive() 0 6 2
A minutesSinceLastActivity() 0 6 1
A noUserIsAuthenticated() 0 4 1
A passwordExpired() 0 14 3
A twoFactorAuthStillValid() 0 6 2
A isEnabled() 0 4 1
A login() 0 7 1
A logout() 0 8 1
A updateCurrentAuthTime() 0 4 1
A verifyGoogle2FA() 0 10 2
A verifyAndStoreOneTimePassword() 0 9 1
B generateCookieToken() 0 35 6
A setQrCodeBackend() 0 6 1
A constructBackend() 0 17 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PragmaRX\Google2FALaravel;
6
7
use Carbon\Carbon;
8
use Illuminate\Database\QueryException;
9
use Illuminate\Http\Request as IlluminateRequest;
10
use Illuminate\Support\Facades\DB;
11
use Illuminate\Support\Str;
12
use PragmaRX\Google2FALaravel\Events\LoggedOut;
13
use PragmaRX\Google2FALaravel\Events\OneTimePasswordExpired;
14
use PragmaRX\Google2FALaravel\Exceptions\InvalidSecretKey;
15
use PragmaRX\Google2FALaravel\Support\Auth;
16
use PragmaRX\Google2FALaravel\Support\Config;
17
use PragmaRX\Google2FALaravel\Support\Constants;
18
use PragmaRX\Google2FALaravel\Support\Request;
19
use PragmaRX\Google2FALaravel\Support\Session;
20
use PragmaRX\Google2FAQRCode\Google2FA as Google2FAService;
21
22
/**
23
 * Class Google2FA
24
 */
25
class Google2FA extends Google2FAService
26
{
27
    use Auth, Config, Request, Session;
28
29
    protected $qrCodeBackend;
30
31
    /**
32
     * Construct the correct backend.
33
     */
34 12
    protected function constructBackend(): void
35
    {
36 12
        switch ($this->getQRCodeBackend()) {
37 12
            case Constants::QRCODE_IMAGE_BACKEND_SVG:
38 12
                parent::__construct(new \BaconQrCode\Renderer\Image\SvgImageBackEnd());
39 12
                break;
40
41
            case Constants::QRCODE_IMAGE_BACKEND_EPS:
42
                parent::__construct(new \BaconQrCode\Renderer\Image\EpsImageBackEnd());
43
                break;
44
45
            case Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK:
46
            default:
47
                parent::__construct();
48
                break;
49
        }
50 12
    }
51
52
    /**
53
     * Set the QRCode Backend.
54
     *
55
     * @param string $qrCodeBackend
56
     *
57
     * @return self
58
     */
59
    public function setQrCodeBackend(string $qrCodeBackend)
60
    {
61
        $this->qrCodeBackend = $qrCodeBackend;
62
63
        return $this;
64
    }
65
66
    /**
67
     * Authenticator constructor.
68
     *
69
     * @param IlluminateRequest $request
70
     */
71 12
    public function __construct(IlluminateRequest $request)
72
    {
73 12
        $this->boot($request);
74
75 12
        $this->constructBackend();
76 12
    }
77
78
    /**
79
     * Authenticator boot.
80
     *
81
     * @param $request
82
     *
83
     * @return Google2FA
84
     */
85 12
    public function boot($request)
86
    {
87 12
        $this->setRequest($request);
88
89 12
        return $this;
90
    }
91
92
    /**
93
     * The QRCode Backend.
94
     *
95
     * @return mixed
96
     */
97 12
    public function getQRCodeBackend()
98
    {
99 12
        return $this->qrCodeBackend
100 12
            ?: $this->config('qrcode_image_backend', Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK);
101
    }
102
103
    /**
104
     * Get the user Google2FA secret.
105
     *
106
     * @throws InvalidSecretKey
107
     *
108
     * @return mixed
109
     */
110 8
    protected function getGoogle2FASecretKey()
111
    {
112 8
        return $this->getUser()->{$this->config('otp_secret_column')};
113
    }
114
115
    /**
116
     * Check if the 2FA is activated for the user.
117
     *
118
     * @return bool
119
     */
120 8
    public function isActivated()
121
    {
122 8
        $secret = $this->getGoogle2FASecretKey();
123
124 8
        return !is_null($secret) && !empty($secret);
125
    }
126
127
    /**
128
     * Store the old OTP timestamp.
129
     *
130
     * @param $key
131
     *
132
     * @return mixed
133
     */
134 5
    protected function storeOldTimestamp($key)
135
    {
136 5
        return $this->config('forbid_old_passwords') === true
137 1
            ? $this->sessionPut(Constants::SESSION_OTP_TIMESTAMP, $key)
138 5
            : $key;
139
    }
140
141
    /**
142
     * Get the previous OTP timestamp.
143
     *
144
     * @return null|mixed
145
     */
146 6
    protected function getOldTimestamp()
147
    {
148 6
        return $this->config('forbid_old_passwords') === true
149 1
            ? $this->sessionGet(Constants::SESSION_OTP_TIMESTAMP)
150 6
            : null;
151
    }
152
153
    /**
154
     * Keep this OTP session alive.
155
     */
156 4
    protected function keepAlive()
157
    {
158 4
        if ($this->config('keep_alive')) {
159 4
            $this->updateCurrentAuthTime();
160
        }
161 4
    }
162
163
    /**
164
     * Get minutes since last activity.
165
     *
166
     * @return int
167
     */
168 1
    protected function minutesSinceLastActivity()
169
    {
170 1
        return Carbon::now()->diffInMinutes(
171 1
            $this->sessionGet(Constants::SESSION_AUTH_TIME)
172
        );
173
    }
174
175
    /**
176
     * Check if no user is authenticated using OTP.
177
     *
178
     * @return bool
179
     */
180 7
    protected function noUserIsAuthenticated()
181
    {
182 7
        return is_null($this->getUser());
183
    }
184
185
    /**
186
     * Check if OTP has expired.
187
     *
188
     * @return bool
189
     */
190 4
    protected function passwordExpired()
191
    {
192 4
        if (($minutes = $this->config('lifetime')) !== 0 && $this->minutesSinceLastActivity() > $minutes) {
193 1
            event(new OneTimePasswordExpired($this->getUser()));
194
195 1
            $this->logout();
196
197 1
            return true;
198
        }
199
200 4
        $this->keepAlive();
201
202 4
        return false;
203
    }
204
205
    /**
206
     * Verifies, in the current session, if a 2fa check has already passed.
207
     *
208
     * @return bool
209
     */
210 7
    protected function twoFactorAuthStillValid()
211
    {
212
        return
213 7
            (bool) $this->sessionGet(Constants::SESSION_AUTH_PASSED, false) &&
214 7
            !$this->passwordExpired();
215
    }
216
217
    /**
218
     * Check if the module is enabled.
219
     *
220
     * @return mixed
221
     */
222 7
    protected function isEnabled()
223
    {
224 7
        return $this->config('enabled');
225
    }
226
227
    /**
228
     * Set current auth as valid.
229
     */
230 5
    public function login()
231
    {
232 5
        $this->sessionPut(Constants::SESSION_AUTH_PASSED, true);
233 5
        $this->updateCurrentAuthTime();
234 5
        $this->generateCookieToken();
235
236 5
    }
237
238
    /**
239
     * OTP logout.
240
     */
241 3
    public function logout()
242
    {
243 3
        $user = $this->getUser();
244
245 3
        $this->sessionForget();
246
247 3
        event(new LoggedOut($user));
248 3
    }
249
250
    /**
251
     * Update the current auth time.
252
     */
253 5
    protected function updateCurrentAuthTime()
254
    {
255 5
        $this->sessionPut(Constants::SESSION_AUTH_TIME, Carbon::now()->toIso8601String());
256 5
    }
257
258
    /**
259
     * Verify the OTP.
260
     *
261
     * @param $secret
262
     * @param $one_time_password
263
     *
264
     * @return mixed
265
     */
266 6
    public function verifyGoogle2FA($secret, $one_time_password)
267
    {
268 6
        return $this->verifyKey(
269 6
                $secret,
270
                $one_time_password,
271 6
                $this->config('window'),
272 6
                null, // $timestamp
273 6
                $this->getOldTimestamp() ?: null
274
        );
275
    }
276
277
    /**
278
     * Verify the OTP and store the timestamp.
279
     *
280
     * @param $one_time_password
281
     *
282
     * @return mixed
283
     */
284 5
    protected function verifyAndStoreOneTimePassword($one_time_password)
285
    {
286 5
        return $this->storeOldTimeStamp(
287 5
            $this->verifyGoogle2FA(
288 5
                $this->getGoogle2FASecretKey(),
289
                $one_time_password
290
            )
291
        );
292
    }
293
294
    /**
295
     * Generate token, store in session.
296
     */
297 5
    private function generateCookieToken(): void
298
    {
299 5
        if (true === $this->config('store_in_cookie')) {
300
            // generate token and store in DB.
301
            // loop to prevent duplicates (you never know)
302
            $loops  = 0;
303
            $token  = null;
304
            $unique = false;
305
            $user   = $this->getUser();
306
            $expire = time() + (int)$this->config('cookie_lifetime');
307
            while ($loops < 10 && false === $unique) {
308
                $token = Str::random(64);
309
                try {
310
                    // store token in DB
311
                    DB::table('2fa_tokens')->insert(
312
                        [
313
                            'user_id'    => $user->id,
314
                            'expires_at' => date('Y-m-d H:i:s', $expire),
315
                            'token'      => $token,
316
                        ]
317
                    );
318
                } catch (QueryException $e) {
319
                    // token exists or DB error. Try again.
320
                    $loops++;
321
                    continue;
322
                }
323
                // break loop.
324
                $loops  = 20;
325
                $unique = true;
326
            }
327
            if (null !== $token) {
328
                $this->sessionPut(Constants::SESSION_TOKEN, $token);
329
            }
330
        }
331 5
    }
332
}
333