Passed
Pull Request — master (#182)
by Arman
03:14
created

WebAdapter::getInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 3
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\Auth\AuthenticatableInterface;
18
use Quantum\Libraries\Auth\AuthServiceInterface;
19
use Quantum\Libraries\Mailer\MailerInterface;
20
use Quantum\Exceptions\DatabaseException;
21
use Quantum\Libraries\Auth\AuthException;
22
use Quantum\Exceptions\CryptorException;
23
use Quantum\Exceptions\SessionException;
24
use Quantum\Exceptions\ConfigException;
25
use Quantum\Exceptions\LangException;
26
use Quantum\Libraries\Hasher\Hasher;
27
use Quantum\Libraries\Auth\BaseAuth;
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
     * @throws LangException
51
     */
52
    private function __construct(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher)
53
    {
54
        $this->authService = $authService;
55
        $this->mailer = $mailer;
56
        $this->hasher = $hasher;
57
58
        $userSchema = $this->authService->userSchema();
59
60
        $this->verifySchema($userSchema);
61
    }
62
63
    /**
64
     * @param AuthServiceInterface $authService
65
     * @param MailerInterface $mailer
66
     * @param Hasher $hasher
67
     * @return self
68
     * @throws AuthException
69
     * @throws LangException
70
     */
71
    public static function getInstance(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher): self
72
    {
73
        if (self::$instance === null) {
74
            self::$instance = new self($authService, $mailer, $hasher);
75
        }
76
77
        return self::$instance;
78
    }
79
80
    /**
81
     * Sign In
82
     * @param string $username
83
     * @param string $password
84
     * @param bool $remember
85
     * @return string|true
86
     * @throws AuthException
87
     * @throws ConfigException
88
     * @throws CryptorException
89
     * @throws DatabaseException
90
     * @throws DiException
91
     * @throws ReflectionException
92
     * @throws SessionException
93
     * @throws LangException
94
     * @throws Exception
95
     */
96
    public function signin(string $username, string $password, bool $remember = false)
97
    {
98
        $user = $this->getUser($username, $password);
99
100
        if ($remember) {
101
            $this->setRememberToken($user);
102
        }
103
104
        if (filter_var(config()->get('2FA'), FILTER_VALIDATE_BOOLEAN)) {
105
            return $this->twoStepVerification($user);
106
        } else {
107
            session()->regenerateId();
108
            session()->set($this->authUserKey, $this->getVisibleFields($user));
109
            return true;
110
        }
111
    }
112
113
    /**
114
     * Sign Out
115
     * @return bool
116
     * @throws ConfigException
117
     * @throws CryptorException
118
     * @throws DatabaseException
119
     * @throws DiException
120
     * @throws LangException
121
     * @throws ReflectionException
122
     * @throws SessionException
123
     */
124
    public function signout(): bool
125
    {
126
        if (session()->has($this->authUserKey)) {
127
            session()->delete($this->authUserKey);
128
            session()->regenerateId();
129
            $this->removeRememberToken();
130
131
            return true;
132
        }
133
134
        return false;
135
    }
136
137
    /**
138
     * Gets the user object
139
     * @return User|null
140
     * @throws ConfigException
141
     * @throws CryptorException
142
     * @throws DatabaseException
143
     * @throws DiException
144
     * @throws LangException
145
     * @throws ReflectionException
146
     * @throws SessionException
147
     */
148
    public function user(): ?User
149
    {
150
        if (session()->has($this->authUserKey) && is_array(session()->get($this->authUserKey))) {
151
            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

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