Completed
Push — master ( ca855b...6e4305 )
by Antonio Carlos
02:11
created

Google2FA::setQrCodeBackend()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace PragmaRX\Google2FALaravel;
4
5
use Carbon\Carbon;
6
use Illuminate\Http\Request as IlluminateRequest;
7
use PragmaRX\Google2FA\Support\Constants as Google2FAConstants;
8
use PragmaRX\Google2FALaravel\Events\LoggedOut;
9
use PragmaRX\Google2FALaravel\Events\OneTimePasswordExpired;
10
use PragmaRX\Google2FALaravel\Exceptions\InvalidSecretKey;
11
use PragmaRX\Google2FALaravel\Support\Auth;
12
use PragmaRX\Google2FALaravel\Support\Config;
13
use PragmaRX\Google2FALaravel\Support\Constants;
14
use PragmaRX\Google2FALaravel\Support\Request;
15
use PragmaRX\Google2FALaravel\Support\Session;
16
use PragmaRX\Google2FAQRCode\Google2FA as Google2FAService;
17
18
class Google2FA extends Google2FAService
19
{
20
    use Auth, Config, Request, Session;
21
22
    protected $qrCodeBackend;
23
24
    /**
25
     * Construct the correct backend.
26
     */
27 15
    protected function constructBackend(): void
28
    {
29 15
        switch ($this->getQRCodeBackend()) {
30 15
            case Constants::QRCODE_IMAGE_BACKEND_SVG:
31
                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...
32
                break;
33
34 15
            case Constants::QRCODE_IMAGE_BACKEND_EPS:
35
                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...
36
                break;
37
38 15
            case Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK:
39
            default:
40 15
                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...
41 15
                break;
42
        }
43 15
    }
44
45
    /**
46
     * Set the QRCode Backend.
47
     *
48
     * @param string $qrCodeBackend
49
     * @return self
50
     */
51 1
    public function setQrCodeBackend(string $qrCodeBackend)
52
    {
53 1
        $this->qrCodeBackend = $qrCodeBackend;
54
55 1
        return $this;
56
    }
57
58
    /**
59
     * Authenticator constructor.
60
     *
61
     * @param IlluminateRequest $request
62
     */
63 15
    public function __construct(IlluminateRequest $request)
64
    {
65 15
        $this->boot($request);
66
67 15
        $this->constructBackend();
68 15
    }
69
70
    /**
71
     * Authenticator boot.
72
     *
73
     * @param $request
74
     *
75
     * @return Google2FA
76
     */
77 15
    public function boot($request)
78
    {
79 15
        $this->setRequest($request);
80
81 15
        return $this;
82
    }
83
84
    /**
85
     * The QRCode Backend.
86
     *
87
     * @return mixed
88
     */
89 15
    public function getQRCodeBackend()
90
    {
91 15
        return $this->qrCodeBackend
92 15
            ?: $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 10
    protected function getGoogle2FASecretKey()
103
    {
104 10
        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 10
    public function isActivated()
113
    {
114 10
        $secret = $this->getGoogle2FASecretKey();
115
116 10
        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 5
    protected function storeOldTimestamp($key)
127
    {
128 5
        return $this->config('forbid_old_passwords') === true
129 1
            ? $this->sessionPut(Constants::SESSION_OTP_TIMESTAMP, $key)
130 5
            : $key;
131
    }
132
133
    /**
134
     * Get the previous OTP timestamp.
135
     *
136
     * @return null|mixed
137
     */
138 6
    protected function getOldTimestamp()
139
    {
140 6
        return $this->config('forbid_old_passwords') === true
141 1
            ? $this->sessionGet(Constants::SESSION_OTP_TIMESTAMP)
142 6
            : null;
143
    }
144
145
    /**
146
     * Keep this OTP session alive.
147
     */
148 4
    protected function keepAlive()
149
    {
150 4
        if ($this->config('keep_alive')) {
151 4
            $this->updateCurrentAuthTime();
152
        }
153 4
    }
154
155
    /**
156
     * Get minutes since last activity.
157
     *
158
     * @return int
159
     */
160 1
    protected function minutesSinceLastActivity()
161
    {
162 1
        return Carbon::now()->diffInMinutes(
163 1
            $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 9
    protected function noUserIsAuthenticated()
173
    {
174 9
        return is_null($this->getUser());
175
    }
176
177
    /**
178
     * Check if OTP has expired.
179
     *
180
     * @return bool
181
     */
182 4
    protected function passwordExpired()
183
    {
184 4
        if (($minutes = $this->config('lifetime')) !== 0 && $this->minutesSinceLastActivity() > $minutes) {
185 1
            event(new OneTimePasswordExpired($this->getUser()));
186
187 1
            $this->logout();
188
189 1
            return true;
190
        }
191
192 4
        $this->keepAlive();
193
194 4
        return false;
195
    }
196
197
    /**
198
     * Verifies, in the current session, if a 2fa check has already passed.
199
     *
200
     * @return bool
201
     */
202 9
    protected function twoFactorAuthStillValid()
203
    {
204
        return
205 9
            (bool) $this->sessionGet(Constants::SESSION_AUTH_PASSED, false) &&
206 9
            !$this->passwordExpired();
207
    }
208
209
    /**
210
     * Check if the module is enabled.
211
     *
212
     * @return mixed
213
     */
214 9
    protected function isEnabled()
215
    {
216 9
        return $this->config('enabled');
217
    }
218
219
    /**
220
     * Set current auth as valid.
221
     */
222 5
    public function login()
223
    {
224 5
        $this->sessionPut(Constants::SESSION_AUTH_PASSED, true);
225
226 5
        $this->updateCurrentAuthTime();
227 5
    }
228
229
    /**
230
     * OTP logout.
231
     */
232 3
    public function logout()
233
    {
234 3
        $user = $this->getUser();
235
236 3
        $this->sessionForget();
237
238 3
        event(new LoggedOut($user));
239 3
    }
240
241
    /**
242
     * Update the current auth time.
243
     */
244 5
    protected function updateCurrentAuthTime()
245
    {
246 5
        $this->sessionPut(Constants::SESSION_AUTH_TIME, Carbon::now());
247 5
    }
248
249
    /**
250
     * Verify the OTP.
251
     *
252
     * @param $secret
253
     * @param $one_time_password
254
     *
255
     * @return mixed
256
     */
257 6
    public function verifyGoogle2FA($secret, $one_time_password)
258
    {
259 6
        return $this->verifyKey(
260 6
                $secret,
261
                $one_time_password,
262 6
                $this->config('window'),
263 6
                null, // $timestamp
264 6
                $this->getOldTimestamp() ?: Google2FAConstants::ARGUMENT_NOT_SET
265
        );
266
    }
267
268
    /**
269
     * Verify the OTP and store the timestamp.
270
     *
271
     * @param $one_time_password
272
     *
273
     * @return mixed
274
     */
275 5
    protected function verifyAndStoreOneTimePassword($one_time_password)
276
    {
277 5
        return $this->storeOldTimeStamp(
278 5
            $this->verifyGoogle2FA(
279 5
                $this->getGoogle2FASecretKey(),
280
                $one_time_password
281
            )
282
        );
283
    }
284
}
285