Completed
Pull Request — master (#86)
by
unknown
03:08
created

Google2FA::setQrCodeBackend()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace PragmaRX\Google2FALaravel;
4
5
use Carbon\Carbon;
6
use Illuminate\Http\Request as IlluminateRequest;
7
use PragmaRX\Google2FALaravel\Events\LoggedOut;
8
use PragmaRX\Google2FALaravel\Events\OneTimePasswordExpired;
9
use PragmaRX\Google2FALaravel\Exceptions\InvalidSecretKey;
10
use PragmaRX\Google2FALaravel\Support\Auth;
11
use PragmaRX\Google2FALaravel\Support\Config;
12
use PragmaRX\Google2FALaravel\Support\Constants;
13
use PragmaRX\Google2FALaravel\Support\Request;
14
use PragmaRX\Google2FALaravel\Support\Session;
15
use PragmaRX\Google2FAQRCode\Google2FA as Google2FAService;
16
17
class Google2FA extends Google2FAService
18
{
19
    use Auth, Config, Request, Session;
20
21
    protected $qrCodeBackend;
22
23
    /**
24
     * Construct the correct backend.
25
     */
26 7
    protected function constructBackend(): void
27
    {
28 7
        switch ($this->getQRCodeBackend()) {
29 7
            case Constants::QRCODE_IMAGE_BACKEND_SVG:
30
                parent::__construct(new \BaconQrCode\Renderer\Image\SvgImageBackEnd());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (__construct() instead of constructBackend()). Are you sure this is correct? If so, you might want to change this to $this->__construct().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
31
                break;
32
33 7
            case Constants::QRCODE_IMAGE_BACKEND_EPS:
34
                parent::__construct(new \BaconQrCode\Renderer\Image\EpsImageBackEnd());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (__construct() instead of constructBackend()). Are you sure this is correct? If so, you might want to change this to $this->__construct().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
35
                break;
36
37 7
            case Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK:
38
            default:
39 7
                parent::__construct();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (__construct() instead of constructBackend()). Are you sure this is correct? If so, you might want to change this to $this->__construct().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
40 7
                break;
41
        }
42 7
    }
43
44
    /**
45
     * Set the QRCode Backend.
46
     *
47
     * @param string $qrCodeBackend
48
     *
49
     * @return self
50
     */
51
    public function setQrCodeBackend(string $qrCodeBackend)
52
    {
53
        $this->qrCodeBackend = $qrCodeBackend;
54
55
        return $this;
56
    }
57
58
    /**
59
     * Authenticator constructor.
60
     *
61
     * @param IlluminateRequest $request
62
     */
63 7
    public function __construct(IlluminateRequest $request)
64
    {
65 7
        $this->boot($request);
66
67 7
        $this->constructBackend();
68 7
    }
69
70
    /**
71
     * Authenticator boot.
72
     *
73
     * @param $request
74
     *
75
     * @return Google2FA
76
     */
77 7
    public function boot($request)
78
    {
79 7
        $this->setRequest($request);
80
81 7
        return $this;
82
    }
83
84
    /**
85
     * The QRCode Backend.
86
     *
87
     * @return mixed
88
     */
89 7
    public function getQRCodeBackend()
90
    {
91 7
        return $this->qrCodeBackend
92 7
            ?: $this->config('qrcode_image_backend', Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK);
93
    }
94
95
    /**
96
     * Get the user Google2FA secret.
97
     *
98
     * @throws InvalidSecretKey
99
     *
100
     * @return mixed
101
     */
102 5
    protected function getGoogle2FASecretKey()
103
    {
104 5
        return $this->getUser()->{$this->config('otp_secret_column')};
105
    }
106
107
    /**
108
     * Check if the 2FA is activated for the user.
109
     *
110
     * @return bool
111
     */
112 5
    public function isActivated()
113
    {
114 5
        $secret = $this->getGoogle2FASecretKey();
115
116 5
        return !is_null($secret) && !empty($secret);
117
    }
118
119
    /**
120
     * Store the old OTP timestamp.
121
     *
122
     * @param $key
123
     *
124
     * @return mixed
125
     */
126 3
    protected function storeOldTimestamp($key)
127
    {
128 3
        return $this->config('forbid_old_passwords') === true
129
            ? $this->sessionPut(Constants::SESSION_OTP_TIMESTAMP, $key)
130 3
            : $key;
131
    }
132
133
    /**
134
     * Get the previous OTP timestamp.
135
     *
136
     * @return null|mixed
137
     */
138 4
    protected function getOldTimestamp()
139
    {
140 4
        return $this->config('forbid_old_passwords') === true
141
            ? $this->sessionGet(Constants::SESSION_OTP_TIMESTAMP)
142 4
            : null;
143
    }
144
145
    /**
146
     * Keep this OTP session alive.
147
     */
148 2
    protected function keepAlive()
149
    {
150 2
        if ($this->config('keep_alive')) {
151 2
            $this->updateCurrentAuthTime();
152
        }
153 2
    }
154
155
    /**
156
     * Get minutes since last activity.
157
     *
158
     * @return int
159
     */
160
    protected function minutesSinceLastActivity()
161
    {
162
        return Carbon::now()->diffInMinutes(
163
            $this->sessionGet(Constants::SESSION_AUTH_TIME)
164
        );
165
    }
166
167
    /**
168
     * Check if no user is authenticated using OTP.
169
     *
170
     * @return bool
171
     */
172 4
    protected function noUserIsAuthenticated()
173
    {
174 4
        return is_null($this->getUser());
175
    }
176
177
    /**
178
     * Check if OTP has expired.
179
     *
180
     * @return bool
181
     */
182 2
    protected function passwordExpired()
183
    {
184 2
        if (($minutes = $this->config('lifetime')) !== 0 && $this->minutesSinceLastActivity() > $minutes) {
185
            event(new OneTimePasswordExpired($this->getUser()));
186
187
            $this->logout();
188
189
            return true;
190
        }
191
192 2
        $this->keepAlive();
193
194 2
        return false;
195
    }
196
197
    /**
198
     * Verifies, in the current session, if a 2fa check has already passed.
199
     *
200
     * @return bool
201
     */
202 4
    protected function twoFactorAuthStillValid()
203
    {
204
        return
205
            (
206 4
                (bool) $this->sessionGet(Constants::SESSION_AUTH_PASSED, false) ||
207 4
                ( $this->config('remember') && $this->getUser()->{$this->config('remember_column')} && ( Carbon::now() <= (new Carbon($this->getUser()->{$this->config('remember_column')}))->addMinutes($this->config('lifetime')) ) )
208
            ) &&
209 4
            !$this->passwordExpired();
210
    }
211
212
    /**
213
     * Check if the module is enabled.
214
     *
215
     * @return mixed
216
     */
217 4
    protected function isEnabled()
218
    {
219 4
        return $this->config('enabled');
220
    }
221
222
    /**
223
     * Set current auth as valid.
224
     */
225 2
    public function login()
226
    {
227 2
        $this->sessionPut(Constants::SESSION_AUTH_PASSED, true);
228
229 2
        if (isset(\Cookie::get()[\Auth::getRecallerName()])) {
230
            $user = $this->getUser();
231
            $user->{$this->config('remember_column')} = Carbon::now();
232
            $user->save();
233
        }
234
235 2
        $this->updateCurrentAuthTime();
236 2
    }
237
238
    /**
239
     * OTP logout.
240
     */
241 1
    public function logout()
242
    {
243 1
        $user = $this->getUser();
244 1
        $user->{$this->config('remember_column')} = null;
245 1
        $user->save();
246
247
        $this->sessionForget();
248
249
        event(new LoggedOut($user));
250
    }
251
252
    /**
253
     * Update the current auth time.
254
     */
255 2
    protected function updateCurrentAuthTime()
256
    {
257 2
        $this->sessionPut(Constants::SESSION_AUTH_TIME, Carbon::now());
258 2
    }
259
260
    /**
261
     * Verify the OTP.
262
     *
263
     * @param $secret
264
     * @param $one_time_password
265
     *
266
     * @return mixed
267
     */
268 4
    public function verifyGoogle2FA($secret, $one_time_password)
269
    {
270 4
        return $this->verifyKey(
271 4
                $secret,
272
                $one_time_password,
273 4
                $this->config('window'),
274 4
                null, // $timestamp
275 4
                $this->getOldTimestamp() ?: null
276
        );
277
    }
278
279
    /**
280
     * Verify the OTP and store the timestamp.
281
     *
282
     * @param $one_time_password
283
     *
284
     * @return mixed
285
     */
286 3
    protected function verifyAndStoreOneTimePassword($one_time_password)
287
    {
288 3
        return $this->storeOldTimeStamp(
289 3
            $this->verifyGoogle2FA(
290 3
                $this->getGoogle2FASecretKey(),
291
                $one_time_password
292
            )
293
        );
294
    }
295
}
296