Completed
Push — master ( 008470...1b1851 )
by Antonio Carlos
02:02
created

Google2FA::verifyAndStoreOneTimePassword()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 4
cp 1
rs 9.9666
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
    /**
23
     * Authenticator constructor.
24
     *
25
     * @param IlluminateRequest $request
26
     */
27 14
    public function __construct(IlluminateRequest $request)
28
    {
29 14
        $this->boot($request);
30
31 14
        switch ($this->config('qr_image_backend')) {
32 14
            case 'svg':
33
                parent::__construct(new \BaconQrCode\Renderer\Image\SvgImageBackEnd());
34
                break;
35
36 14
            case 'eps':
37
                parent::__construct(new \BaconQrCode\Renderer\Image\EpsImageBackEnd());
38
                break;
39
40
            default:
41 14
                parent::__construct();
42 14
                break;
43
44
        }
45 14
    }
46
47
    /**
48
     * Authenticator boot.
49
     *
50
     * @param $request
51
     *
52
     * @return Google2FA
53
     */
54 14
    public function boot($request)
55
    {
56 14
        $this->setRequest($request);
57
58 14
        return $this;
59
    }
60
61
    /**
62
     * Get the user Google2FA secret.
63
     *
64
     * @throws InvalidSecretKey
65
     *
66
     * @return mixed
67
     */
68 10
    protected function getGoogle2FASecretKey()
69
    {
70 10
        return $this->getUser()->{$this->config('otp_secret_column')};
71
    }
72
73
    /**
74
     * Check if the 2FA is activated for the user.
75
     *
76
     * @return bool
77
     */
78 10
    public function isActivated()
79
    {
80 10
        $secret = $this->getGoogle2FASecretKey();
81
82 10
        return !is_null($secret) && !empty($secret);
83
    }
84
85
    /**
86
     * Store the old OTP timestamp.
87
     *
88
     * @param $key
89
     *
90
     * @return mixed
91
     */
92 5
    protected function storeOldTimestamp($key)
93
    {
94 5
        return $this->config('forbid_old_passwords') === true
95 1
            ? $this->sessionPut(Constants::SESSION_OTP_TIMESTAMP, $key)
96 5
            : $key;
97
    }
98
99
    /**
100
     * Get the previous OTP timestamp.
101
     *
102
     * @return null|mixed
103
     */
104 6
    protected function getOldTimestamp()
105
    {
106 6
        return $this->config('forbid_old_passwords') === true
107 1
            ? $this->sessionGet(Constants::SESSION_OTP_TIMESTAMP)
108 6
            : null;
109
    }
110
111
    /**
112
     * Keep this OTP session alive.
113
     */
114 4
    protected function keepAlive()
115
    {
116 4
        if ($this->config('keep_alive')) {
117 4
            $this->updateCurrentAuthTime();
118
        }
119 4
    }
120
121
    /**
122
     * Get minutes since last activity.
123
     *
124
     * @return int
125
     */
126 1
    protected function minutesSinceLastActivity()
127
    {
128 1
        return Carbon::now()->diffInMinutes(
129 1
            $this->sessionGet(Constants::SESSION_AUTH_TIME)
130
        );
131
    }
132
133
    /**
134
     * Check if no user is authenticated using OTP.
135
     *
136
     * @return bool
137
     */
138 9
    protected function noUserIsAuthenticated()
139
    {
140 9
        return is_null($this->getUser());
141
    }
142
143
    /**
144
     * Check if OTP has expired.
145
     *
146
     * @return bool
147
     */
148 4
    protected function passwordExpired()
149
    {
150 4
        if (($minutes = $this->config('lifetime')) !== 0 && $this->minutesSinceLastActivity() > $minutes) {
151 1
            event(new OneTimePasswordExpired($this->getUser()));
152
153 1
            $this->logout();
154
155 1
            return true;
156
        }
157
158 4
        $this->keepAlive();
159
160 4
        return false;
161
    }
162
163
    /**
164
     * Verifies, in the current session, if a 2fa check has already passed.
165
     *
166
     * @return bool
167
     */
168 9
    protected function twoFactorAuthStillValid()
169
    {
170
        return
171 9
            (bool) $this->sessionGet(Constants::SESSION_AUTH_PASSED, false) &&
172 9
            !$this->passwordExpired();
173
    }
174
175
    /**
176
     * Check if the module is enabled.
177
     *
178
     * @return mixed
179
     */
180 9
    protected function isEnabled()
181
    {
182 9
        return $this->config('enabled');
183
    }
184
185
    /**
186
     * Set current auth as valid.
187
     */
188 5
    public function login()
189
    {
190 5
        $this->sessionPut(Constants::SESSION_AUTH_PASSED, true);
191
192 5
        $this->updateCurrentAuthTime();
193 5
    }
194
195
    /**
196
     * OTP logout.
197
     */
198 3
    public function logout()
199
    {
200 3
        $user = $this->getUser();
201
202 3
        $this->sessionForget();
203
204 3
        event(new LoggedOut($user));
205 3
    }
206
207
    /**
208
     * Update the current auth time.
209
     */
210 5
    protected function updateCurrentAuthTime()
211
    {
212 5
        $this->sessionPut(Constants::SESSION_AUTH_TIME, Carbon::now());
213 5
    }
214
215
    /**
216
     * Verify the OTP.
217
     *
218
     * @param $secret
219
     * @param $one_time_password
220
     *
221
     * @return mixed
222
     */
223 6
    public function verifyGoogle2FA($secret, $one_time_password)
224
    {
225 6
        return $this->verifyKey(
226 6
                $secret,
227
                $one_time_password,
228 6
                $this->config('window'),
229 6
                null, // $timestamp
230 6
                $this->getOldTimestamp() ?: Google2FAConstants::ARGUMENT_NOT_SET
231
        );
232
    }
233
234
    /**
235
     * Verify the OTP and store the timestamp.
236
     *
237
     * @param $one_time_password
238
     *
239
     * @return mixed
240
     */
241 5
    protected function verifyAndStoreOneTimePassword($one_time_password)
242
    {
243 5
        return $this->storeOldTimeStamp(
244 5
            $this->verifyGoogle2FA(
245 5
                $this->getGoogle2FASecretKey(),
246
                $one_time_password
247
            )
248
        );
249
    }
250
}
251