Passed
Pull Request — master (#182)
by Arman
06:43 queued 02:40
created

WebAdapter::verifyOtp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
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.9.5
13
 */
14
15
namespace Quantum\Libraries\Auth\Adapters;
16
17
use Quantum\Libraries\Database\Exceptions\DatabaseException;
18
use Quantum\Libraries\Auth\AuthenticatableInterface;
19
use Quantum\Libraries\Encryption\CryptorException;
20
use Quantum\Libraries\Auth\AuthServiceInterface;
21
use Quantum\Libraries\Session\SessionException;
22
use Quantum\Libraries\Mailer\MailerInterface;
23
use Quantum\Libraries\Config\ConfigException;
24
use Quantum\Libraries\Auth\AuthException;
25
use Quantum\Libraries\Lang\LangException;
26
use Quantum\Libraries\Auth\BaseAuth;
27
use Quantum\Libraries\Hasher\Hasher;
28
use Quantum\Exceptions\DiException;
29
use Quantum\Libraries\Auth\User;
30
use ReflectionException;
31
use Exception;
32
33
/**
34
 * Class WebAuth
35
 * @package Quantum\Libraries\Auth
36
 */
37
class WebAdapter extends BaseAuth implements AuthenticatableInterface
38
{
39
40
    /**
41
     * @var WebAdapter
42
     */
43
    private static $instance;
44
45
    /**
46
     * @param AuthServiceInterface $authService
47
     * @param MailerInterface $mailer
48
     * @param Hasher $hasher
49
     * @throws AuthException
50
     */
51
    private function __construct(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher)
52
    {
53
        $this->authService = $authService;
54
        $this->mailer = $mailer;
55
        $this->hasher = $hasher;
56
57
        $userSchema = $this->authService->userSchema();
58
59
        $this->verifySchema($userSchema);
60
    }
61
62
    /**
63
     * @param AuthServiceInterface $authService
64
     * @param MailerInterface $mailer
65
     * @param Hasher $hasher
66
     * @return self
67
     * @throws AuthException
68
     */
69
    public static function getInstance(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher): self
70
    {
71
        if (self::$instance === null) {
72
            self::$instance = new self($authService, $mailer, $hasher);
73
        }
74
75
        return self::$instance;
76
    }
77
78
    /**
79
     * Sign In
80
     * @param string $username
81
     * @param string $password
82
     * @param bool $remember
83
     * @return string|true
84
     * @throws AuthException
85
     * @throws ConfigException
86
     * @throws CryptorException
87
     * @throws DatabaseException
88
     * @throws DiException
89
     * @throws ReflectionException
90
     * @throws SessionException
91
     * @throws Exception
92
     */
93
    public function signin(string $username, string $password, bool $remember = false)
94
    {
95
        $user = $this->getUser($username, $password);
96
97
        if ($remember) {
98
            $this->setRememberToken($user);
99
        }
100
101
        if (filter_var(config()->get('2FA'), FILTER_VALIDATE_BOOLEAN)) {
102
            return $this->twoStepVerification($user);
103
        } else {
104
            session()->regenerateId();
105
            session()->set($this->authUserKey, $this->getVisibleFields($user));
106
            return true;
107
        }
108
    }
109
110
    /**
111
     * Sign Out
112
     * @return bool
113
     * @throws ConfigException
114
     * @throws CryptorException
115
     * @throws DatabaseException
116
     * @throws DiException
117
     * @throws ReflectionException
118
     * @throws SessionException
119
     */
120
    public function signout(): bool
121
    {
122
        if (session()->has($this->authUserKey)) {
123
            session()->delete($this->authUserKey);
124
            session()->regenerateId();
125
            $this->removeRememberToken();
126
127
            return true;
128
        }
129
130
        return false;
131
    }
132
133
    /**
134
     * Gets the user object
135
     * @return User|null
136
     * @throws ConfigException
137
     * @throws CryptorException
138
     * @throws DatabaseException
139
     * @throws DiException
140
     * @throws LangException
141
     * @throws ReflectionException
142
     * @throws SessionException
143
     */
144
    public function user(): ?User
145
    {
146
        if (session()->has($this->authUserKey) && is_array(session()->get($this->authUserKey))) {
147
            return (new User())->setData(session()->get($this->authUserKey));
0 ignored issues
show
Bug introduced by
It seems like session()->get($this->authUserKey) can also be of type null; however, parameter $data of Quantum\Libraries\Auth\User::setData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
            return (new User())->setData(/** @scrutinizer ignore-type */ session()->get($this->authUserKey));
Loading history...
148
        } else if (cookie()->has($this->keyFields[self::REMEMBER_TOKEN_KEY])) {
149
            $user = $this->checkRememberToken();
150
151
            if ($user) {
152
                session()->set($this->authUserKey, $this->getVisibleFields($user));
153
                return $this->user();
154
            }
155
        }
156
157
        return null;
158
    }
159
160
    /**
161
     * Verify OTP
162
     * @param int $otp
163
     * @param string $otpToken
164
     * @return bool
165
     * @throws AuthException
166
     * @throws ConfigException
167
     * @throws CryptorException
168
     * @throws DatabaseException
169
     * @throws DiException
170
     * @throws ReflectionException
171
     * @throws SessionException
172
     */
173
    public function verifyOtp(int $otp, string $otpToken): bool
174
    {
175
        $user = $this->verifyAndUpdateOtp($otp, $otpToken);
176
177
        session()->set($this->authUserKey, $this->getVisibleFields($user));
178
179
        return true;
180
    }
181
182
    /**
183
     * Check Remember Token
184
     * @return User|false
185
     * @throws CryptorException
186
     */
187
    private function checkRememberToken()
188
    {
189
        $user = $this->authService->get(
190
            $this->keyFields[self::REMEMBER_TOKEN_KEY],
191
            cookie()->get($this->keyFields[self::REMEMBER_TOKEN_KEY])
192
        );
193
194
        if (!$user) {
195
            return false;
196
        }
197
198
        if (filter_var(config()->get('2FA'), FILTER_VALIDATE_BOOLEAN) && !empty($user->getFieldValue($this->keyFields[self::OTP_TOKEN_KEY]))) {
199
            return false;
200
        }
201
202
        return $user;
203
    }
204
205
    /**
206
     * Set Remember Token
207
     * @param User $user
208
     * @throws CryptorException
209
     */
210
    private function setRememberToken(User $user)
211
    {
212
        $rememberToken = $this->generateToken();
213
214
        $this->authService->update(
215
            $this->keyFields[self::USERNAME_KEY],
216
            $user->getFieldValue($this->keyFields[self::USERNAME_KEY]),
217
            [$this->keyFields[self::REMEMBER_TOKEN_KEY] => $rememberToken]
218
        );
219
220
        cookie()->set($this->keyFields[self::REMEMBER_TOKEN_KEY], $rememberToken);
221
    }
222
223
    /**
224
     * Remove Remember token
225
     * @throws CryptorException
226
     */
227
    private function removeRememberToken()
228
    {
229
        if (cookie()->has($this->keyFields[self::REMEMBER_TOKEN_KEY])) {
230
            $user = $this->authService->get(
231
                $this->keyFields[self::REMEMBER_TOKEN_KEY],
232
                cookie()->get($this->keyFields[self::REMEMBER_TOKEN_KEY])
233
            );
234
235
            if ($user) {
236
                $this->authService->update(
237
                    $this->keyFields[self::REMEMBER_TOKEN_KEY],
238
                    $user->getFieldValue($this->keyFields[self::REMEMBER_TOKEN_KEY]),
239
                    [$this->keyFields[self::REMEMBER_TOKEN_KEY] => '']
240
                );
241
            }
242
243
            cookie()->delete($this->keyFields[self::REMEMBER_TOKEN_KEY]);
244
        }
245
    }
246
}
247