Completed
Pull Request — master (#18)
by
unknown
11:55
created

Authenticator::checkOTP()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 6
nc 3
nop 0
1
<?php
2
3
namespace PragmaRX\Google2FALaravel\Support;
4
5
use Carbon\Carbon;
6
use Google2FA;
7
use Illuminate\Http\Request as IlluminateRequest;
8
use PragmaRX\Google2FA\Support\Constants as Google2FAConstants;
9
use PragmaRX\Google2FALaravel\Exceptions\InvalidOneTimePassword;
10
use PragmaRX\Google2FALaravel\Exceptions\InvalidSecretKey;
11
12
class Authenticator
13
{
14
    use Auth, Config, Request, Session;
15
16
    /**
17
     * Authenticator constructor.
18
     *
19
     * @param IlluminateRequest $request
20
     */
21
    public function __construct(IlluminateRequest $request)
22
    {
23
        $this->boot($request);
24
    }
25
26
    /**
27
     * Authenticator boot.
28
     *
29
     * @param $request
30
     *
31
     * @return Authenticator
32
     */
33
    public function boot($request)
34
    {
35
        $this->setRequest($request);
36
        return $this;
37
    }
38
39
    /**
40
     * Check if it is already logged in or passable without checking for an OTP.
41
     *
42
     * @return bool
43
     */
44
    protected function canPassWithoutCheckingOTP()
45
    {
46
        return
47
            !$this->isEnabled() ||
48
            $this->noUserIsAuthenticated() ||
49
            !$this->isActivated() ||
50
            $this->twoFactorAuthStillValid();
51
    }
52
53
    /**
54
     * Get the user Google2FA secret.
55
     *
56
     * @throws InvalidSecretKey
57
     *
58
     * @return mixed
59
     */
60
    protected function getGoogle2FASecretKey()
61
    {
62
        return $this->getUser()->{$this->config('otp_secret_column')};
63
    }
64
65
    /**
66
     * Check if the 2FA is activated for the user
67
     * 
68
     * @return bool
69
     */
70
    public function isActivated()
71
    {
72
        $secret = $this->getGoogle2FASecretKey();
73
        return !is_null($secret) && !empty($secret);
74
    }
75
76
    /**
77
     * Store the old OTP timestamp.
78
     *
79
     * @param $key
80
     *
81
     * @return mixed
82
     */
83
    protected function storeOldTimestamp($key)
84
    {
85
        return $this->config('forbid_old_passwords') === true
86
            ? $this->sessionPut(Constants::SESSION_OTP_TIMESTAMP, $key)
87
            : $key;
88
    }
89
90
    /**
91
     * Get the previous OTP timestamp.
92
     *
93
     * @return null|void
94
     */
95
    protected function getOldTimestamp()
96
    {
97
        return $this->config('forbid_old_passwords') === true
98
            ? $this->sessionGet(Constants::SESSION_OTP_TIMESTAMP)
99
            : null;
100
    }
101
102
    /**
103
     * Keep this OTP session alive.
104
     */
105
    protected function keepAlive()
106
    {
107
        if ($this->config('keep_alive')) {
108
            $this->updateCurrentAuthTime();
109
        }
110
    }
111
112
    /**
113
     * Get minutes since last activity.
114
     *
115
     * @return int
116
     */
117
    protected function minutesSinceLastActivity()
118
    {
119
        return Carbon::now()->diffInMinutes(
120
            $this->sessionGet(Constants::SESSION_AUTH_TIME)
121
        );
122
    }
123
124
    /**
125
     * Check if no user is authenticated using OTP.
126
     *
127
     * @return bool
128
     */
129
    protected function noUserIsAuthenticated()
130
    {
131
        return is_null($this->getUser());
132
    }
133
134
    /**
135
     * Check if OTP has expired.
136
     *
137
     * @return bool
138
     */
139
    protected function passwordExpired()
140
    {
141
        if (($minutes = $this->config('lifetime')) !== 0 && $this->minutesSinceLastActivity() > $minutes) {
142
            $this->logout();
143
144
            return true;
145
        }
146
147
        $this->keepAlive();
148
149
        return false;
150
    }
151
152
    /**
153
     * Verifies, in the current session, if a 2fa check has already passed.
154
     *
155
     * @return bool
156
     */
157
    protected function twoFactorAuthStillValid()
158
    {
159
        return
160
            (bool) $this->sessionGet(Constants::SESSION_AUTH_PASSED, false) &&
161
            !$this->passwordExpired();
162
    }
163
164
    /**
165
     * Check if the module is enabled.
166
     *
167
     * @return mixed
168
     */
169
    protected function isEnabled()
170
    {
171
        return $this->config('enabled');
172
    }
173
174
    /**
175
     * Set current auth as valid.
176
     */
177
    public function login()
178
    {
179
        $this->sessionPut(Constants::SESSION_AUTH_PASSED, true);
180
181
        $this->updateCurrentAuthTime();
182
    }
183
184
    /**
185
     * OTP logout.
186
     */
187
    public function logout()
188
    {
189
        $this->sessionForget();
190
    }
191
192
    /**
193
     * Update the current auth time.
194
     */
195
    protected function updateCurrentAuthTime()
196
    {
197
        $this->sessionPut(Constants::SESSION_AUTH_TIME, Carbon::now());
198
    }
199
200
    /**
201
     * Verify the OTP.
202
     *
203
     * @return mixed
204
     */
205
    public function verifyGoogle2FA($secret, $one_time_password)
206
    {
207
        return Google2Fa::verifyKey(
208
                $secret,
209
                $one_time_password,
210
                $this->config('window'),
211
                null, // $timestamp
212
                $this->getOldTimestamp() ?: Google2FAConstants::ARGUMENT_NOT_SET
213
        );
214
    }
215
216
    /**
217
     * Verify the OTP and store the timestamp
218
     *
219
     * @return mixed
220
     */
221
    protected function verifyAndStoreOneTimePassord($one_time_password)
222
    {
223
        return $this->storeOldTimeStamp(
224
            $this->verifyGoogle2FA(
225
                $this->getGoogle2FASecretKey(),
226
                $one_time_password
227
            )
228
        );
229
    }
230
    
231
}
232