Completed
Push — master ( abbd86...80619a )
by Arman
16s queued 11s
created

ApiAuth::resendOtp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 20
rs 9.9666
cc 2
nc 2
nop 2
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.0.0
13
 */
14
15
namespace Quantum\Libraries\Auth;
16
17
use Quantum\Exceptions\ExceptionMessages;
18
use Quantum\Exceptions\AuthException;
19
use Quantum\Libraries\JWToken\JWToken;
20
use Quantum\Libraries\Hasher\Hasher;
21
use Quantum\Http\Response;
22
use Quantum\Http\Request;
23
use Quantum\Libraries\Mailer\Mailer;
24
25
/**
26
 * Class ApiAuth
27
 * @package Quantum\Libraries\Auth
28
 */
29
class ApiAuth extends BaseAuth implements AuthenticableInterface
30
{
31
32
    /**
33
     * @var JWToken
34
     */
35
    protected $jwt;
36
37
    /**
38
     * @var Hasher
39
     */
40
    protected $hasher;
41
42
    /**
43
     * @var AuthServiceInterface
44
     */
45
    protected $authService;
46
47
    /**
48
     * @var array
49
     */
50
    protected $keys = [];
51
52
    /**
53
     * @var string
54
     */
55
    protected $authUserKey = 'auth_user';
56
57
    /**
58
     * ApiAuth constructor.
59
     * @param AuthServiceInterface $authService
60
     * @param Hasher $hasher
61
     * @param JWToken|null $jwt
62
     */
63
    public function __construct(AuthServiceInterface $authService, Hasher $hasher, JWToken $jwt = null)
64
    {
65
        $this->jwt = $jwt;
66
        $this->hasher = $hasher;
67
        $this->authService = $authService;
68
        $this->keys = $this->authService->getDefinedKeys();
69
    }
70
71
    /**
72
     * Sign In
73
     * @param string $username
74
     * @param string $password
75
     * @return mixed|array
76
     * @throws AuthException
77
     */
78
    public function signin($mailer, $username, $password)
79
    {
80
        $user = $this->authService->get($this->keys['usernameKey'], $username);
81
82
        if (empty($user)) {
83
            throw new AuthException(ExceptionMessages::INCORRECT_AUTH_CREDENTIALS);
84
        }
85
86
        if (!$this->hasher->check($password, $user[$this->keys['passwordKey']])) {
87
            throw new AuthException(ExceptionMessages::INCORRECT_AUTH_CREDENTIALS);
88
        }
89
        if (!$this->isActivated($user)) {
90
            throw new AuthException(ExceptionMessages::INACTIVE_ACCOUNT);
91
        }
92
93
        if (filter_var(config()->get('2SV'), FILTER_VALIDATE_BOOLEAN)) {
94
95
            $otp_token = $this->generateOtpToken($user[$this->keys['usernameKey']]);
96
97
            $time = new \DateTime();
98
99
            $time->add(new \DateInterval('PT' . config()->get('otp_expiry_time') . 'M'));
100
101
            $otp_expiry_time = $time->format('Y-m-d H:i');
102
103
            $this->towStepVerification($mailer, $user, $otp_expiry_time, $otp_token);
104
105
            return $otp_token;
106
107
        } else {
108
109
            $tokens = $this->setUpdatedTokens($user);
110
111
            return $tokens;
112
        }
113
    }
114
115
    /**
116
     * Sign Out
117
     * @return bool|mixed
118
     */
119
    public function signout()
120
    {
121
        $refreshToken = Request::getHeader($this->keys['refreshTokenKey']);
122
123
        $user = $this->authService->get($this->keys['refreshTokenKey'], $refreshToken);
124
125
        if (!empty($user)) {
126
            $this->authService->update(
127
                    $this->keys['refreshTokenKey'],
128
                    $refreshToken,
129
                    [
130
                        $this->authUserKey => $user,
131
                        $this->keys['refreshTokenKey'] => ''
132
                    ]
133
            );
134
135
            Request::deleteHeader($this->keys['refreshTokenKey']);
136
            Request::deleteHeader('Authorization');
137
            Response::delete('tokens');
138
139
            return true;
140
        }
141
142
        return false;
143
    }
144
145
    /**
146
     * User
147
     * @return mixed|null
148
     */
149
    public function user()
150
    {
151
        try {
152
            $accessToken = base64_decode(Request::getAuthorizationBearer());
153
            return (object) $this->jwt->retrieve($accessToken)->fetchData();
154
        } catch (\Exception $e) {
155
            if (Request::hasHeader($this->keys['refreshTokenKey'])) {
156
                $user = $this->checkRefreshToken();
157
                if ($user) {
158
                    return $this->user();
159
                }
160
            }
161
            return null;
162
        }
163
    }
164
165
    /**
166
     * Get Updated Tokens
167
     * @param object $user
168
     * @return array
169
     */
170
    public function getUpdatedTokens(array $user)
171
    {
172
        return [
173
            $this->keys['refreshTokenKey'] => $this->generateToken(),
174
            $this->keys['accessTokenKey'] => base64_encode($this->jwt->setData($this->filterFields($user))->compose())
175
        ];
176
    }
177
178
    /**
179
     * Verify
180
     * @param int $otp
181
     * @param string $otp_token
182
     * @return array
183
     * @throws \Exception
184
     */
185
    public function verify($otp, $otp_token)
186
    {
187
        $user = $this->authService->get($this->keys['otpToken'], $otp_token);
188
189
        if (new \DateTime() >= new \DateTime($user[$this->keys['otpExpiryIn']])){
190
            throw new AuthException(ExceptionMessages::VERIFICATION_CODE_EXPIRY_IN);
191
        }
192
193
        if ($otp != $user[$this->keys['otpKey']]) {
194
            throw new AuthException(ExceptionMessages::INCORRECT_VERIFICATION_CODE);
195
        }
196
197
        $this->authService->update($this->keys['usernameKey'], $user[$this->keys['usernameKey']], [
198
            $this->keys['otpKey'] => null,
199
            $this->keys['otpExpiryIn'] => null,
200
            $this->keys['otpToken'] => null,
201
        ]);
202
203
        $tokens = $this->setUpdatedTokens($this->filterFields($user));
204
205
        return $tokens;
206
    }
207
208
    /**
209
     * Resend Otp
210
     * @param Mailer $mailer
211
     * @param string $otp_token
212
     * @return bool|mixed
213
     * @throws AuthException
214
     */
215
216
    public function resendOtp($mailer, $otp_token)
217
    {
218
        $user = $this->authService->get($this->keys['otpToken'], $otp_token);
219
220
        if (empty($user)) {
221
222
            throw new AuthException(ExceptionMessages::INCORRECT_AUTH_CREDENTIALS);
223
        }
224
225
        $otp_token = $this->generateOtpToken($user[$this->keys['usernameKey']]);
226
227
        $time = new \DateTime();
228
229
        $time->add(new \DateInterval('PT' . config()->get('otp_expiry_time') . 'M'));
230
231
        $stamp = $time->format('Y-m-d H:i');
232
233
        $this->towStepVerification($mailer, $user, $stamp, $otp_token);
234
235
        return $otp_token;
236
    }
237
238
    /**
239
     * Check Refresh Token
240
     * @return bool|mixed
241
     */
242
    protected function checkRefreshToken()
243
    {
244
        $user = $this->authService->get($this->keys['refreshTokenKey'], Request::getHeader($this->keys['refreshTokenKey']));
245
246
        if (!empty($user)) {
247
            $this->setUpdatedTokens($user);
248
            return $user;
249
        }
250
251
        return false;
252
    }
253
254
    /**
255
     * Set Updated Tokens
256
     * @param array $user
257
     * @return array
258
     */
259
    protected function setUpdatedTokens(array $user)
260
    {
261
        $tokens = $this->getUpdatedTokens($user);
262
263
        $this->authService->update(
264
                $this->keys['usernameKey'],
265
                $user[$this->keys['usernameKey']],
266
                [
267
                    $this->authUserKey => $user,
268
                    $this->keys['refreshTokenKey'] => $tokens[$this->keys['refreshTokenKey']]
269
                ]
270
        );
271
272
        Request::setHeader($this->keys['refreshTokenKey'], $tokens[$this->keys['refreshTokenKey']]);
273
        Request::setHeader('Authorization', 'Bearer ' . $tokens[$this->keys['accessTokenKey']]);
274
        Response::set('tokens', $tokens);
275
276
        return $tokens;
277
    }
278
279
}
280