Issues (169)

src/Libraries/Auth/WebAuth.php (1 issue)

Labels
Severity
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.0
13
 */
14
15
namespace Quantum\Libraries\Auth;
16
17
use Quantum\Libraries\Mailer\MailerInterface;
18
use Quantum\Exceptions\DatabaseException;
19
use Quantum\Exceptions\CryptorException;
20
use Quantum\Exceptions\SessionException;
21
use Quantum\Exceptions\ConfigException;
22
use Quantum\Exceptions\AuthException;
23
use Quantum\Libraries\Hasher\Hasher;
24
use Quantum\Exceptions\DiException;
25
use PHPMailer\PHPMailer\Exception;
26
use ReflectionException;
27
28
/**
29
 * Class WebAuth
30
 * @package Quantum\Libraries\Auth
31
 */
32
class WebAuth extends BaseAuth implements AuthenticableInterface
33
{
34
35
    /**
36
     * Instance of WebAuth
37
     * @var WebAuth
38
     */
39
    private static $instance;
40
41
    /**
42
     * WebAuth constructor.
43
     * @param AuthServiceInterface $authService
44
     * @param MailerInterface $mailer
45
     * @param Hasher $hasher
46
     * @throws AuthException
47
     */
48
    private function __construct(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher)
49
    {
50
        $this->mailer = $mailer;
51
        $this->hasher = $hasher;
52
        $this->authService = $authService;
53
54
        $userSchema = $this->authService->userSchema();
55
56
        $this->verifySchema($userSchema);
57
    }
58
59
    /**
60
     * Get Instance
61
     * @param AuthServiceInterface $authService
62
     * @param MailerInterface $mailer
63
     * @param Hasher $hasher
64
     * @return WebAuth
65
     * @throws AuthException
66
     */
67
    public static function getInstance(AuthServiceInterface $authService, MailerInterface $mailer, Hasher $hasher): WebAuth
68
    {
69
        if (self::$instance === null) {
70
            self::$instance = new self($authService, $mailer, $hasher);
71
        }
72
73
        return self::$instance;
74
    }
75
76
    /**
77
     * Sign In
78
     * @param string $username
79
     * @param string $password
80
     * @param bool $remember
81
     * @return bool|string
82
     * @throws AuthException
83
     * @throws ReflectionException
84
     * @throws Exception
85
     * @throws ConfigException
86
     * @throws CryptorException
87
     * @throws DatabaseException
88
     * @throws DiException
89
     * @throws SessionException
90
     */
91
    public function signin(string $username, string $password, bool $remember = false)
92
    {
93
        $user = $this->getUser($username, $password);
94
95
        if ($remember) {
96
            $this->setRememberToken($user);
97
        }
98
99
        if (filter_var(config()->get('2FA'), FILTER_VALIDATE_BOOLEAN)) {
100
            return $this->twoStepVerification($user);
101
        } else {
102
            session()->set($this->authUserKey, $this->getVisibleFields($user));
103
            return true;
104
        }
105
    }
106
107
    /**
108
     * Sign Out
109
     * @return bool
110
     * @throws ReflectionException
111
     * @throws ConfigException
112
     * @throws DatabaseException
113
     * @throws DiException
114
     * @throws SessionException
115
     * @throws CryptorException
116
     */
117
    public function signout(): bool
118
    {
119
        if (session()->has($this->authUserKey)) {
120
            session()->delete($this->authUserKey);
121
            $this->removeRememberToken();
122
123
            return true;
124
        }
125
126
        return false;
127
    }
128
129
    /**
130
     * Gets the user object
131
     * @return User|null
132
     * @throws ReflectionException
133
     * @throws ConfigException
134
     * @throws CryptorException
135
     * @throws DatabaseException
136
     * @throws DiException
137
     * @throws SessionException
138
     */
139
    public function user(): ?User
140
    {
141
        if (session()->has($this->authUserKey) && is_array(session()->get($this->authUserKey))) {
142
            return (new User())->setData(session()->get($this->authUserKey));
0 ignored issues
show
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

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