Passed
Push — main ( 0f30b5...54eb22 )
by Rafael
05:37
created

Auth::getSecurityKey()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 16
rs 9.9666
cc 4
nc 4
nop 0
1
<?php
2
3
/* Copyright (C) 2024      Rafael San José      <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace Alxarafe\Lib;
20
21
use Alxarafe\Base\Config;
22
use CoreModules\Admin\Model\User;
23
24
abstract class Auth
25
{
26
    private const COOKIE_NAME = 'alxarafe_login';
27
    private const COOKIE_USER = self::COOKIE_NAME . '_user';
28
    private const COOKIE_EXPIRE_TIME = 30 * 86400; // 30 days
29
    private const COOKIE_SAMESITE = 'Strict';
30
31
    /**
32
     * Contains the JWT security key
33
     *
34
     * @var string|null
35
     */
36
    private static ?string $security_key = null;
37
38
    public static ?User $user = null;
39
40
    public static function isLogged(): bool
41
    {
42
        $userId = FILTER_INPUT(INPUT_COOKIE, self::COOKIE_USER);
43
        $token = FILTER_INPUT(INPUT_COOKIE, self::COOKIE_NAME);
44
        if (empty($token)) {
45
            return false;
46
        }
47
48
        if (!isset(self::$user)) {
49
            self::$user = User::find($userId);
50
        }
51
52
        if (!isset(self::$user)) {
53
            return false;
54
        }
55
56
        return self::$user->token === $token;
0 ignored issues
show
Bug introduced by
The property token does not seem to exist on CoreModules\Admin\Model\User. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
57
    }
58
59
    /**
60
     * Return true if login is correct with user/mail and password.
61
     * TODO: This is a test. It will be checked against a user database.
62
     *
63
     * @param string $username
64
     * @param string $password
65
     *
66
     * @return bool
67
     */
68
    public static function login(string $username, string $password): bool
69
    {
70
        $user = User::where('name', $username)->first();
71
72
        if (!isset($user)) {
73
            return false;
74
        }
75
76
        if (!password_verify($password, $user->password)) {
0 ignored issues
show
Bug introduced by
The property password does not seem to exist on Illuminate\Database\Eloq...Relations\HasOneThrough.
Loading history...
Bug introduced by
The property password does not seem to exist on Illuminate\Database\Eloq...elations\HasManyThrough.
Loading history...
Bug introduced by
The property password does not seem to exist on CoreModules\Admin\Model\User. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
77
            return false;
78
        }
79
80
        self::setLoginCookie($user->id);
0 ignored issues
show
Bug introduced by
The property id does not seem to exist on Illuminate\Database\Eloq...Relations\HasOneThrough.
Loading history...
Bug introduced by
The property id does not seem to exist on Illuminate\Database\Eloq...elations\HasManyThrough.
Loading history...
81
82
        return true;
83
    }
84
85
    public static function setLoginCookie($userId): void
86
    {
87
        $user = User::find($userId);
0 ignored issues
show
Unused Code introduced by
The assignment to $user is dead and can be removed.
Loading history...
88
        self::$user = User::find($userId);
89
90
        $token = self::generateToken();
91
92
        if (!isset(self::$user)) {
93
            self::$user = User::find($userId);
94
        }
95
96
        if (isset(self::$user)) {
97
            self::$user->saveToken($token);
98
        }
99
100
        $cookie_options = [
101
            'expires' => time() + self::COOKIE_EXPIRE_TIME,
102
            'path' => '/',
103
            'domain' => $_SERVER['HTTP_HOST'],
104
            'secure' => true,
105
            'httponly' => true,
106
            'samesite' => self::COOKIE_SAMESITE,
107
        ];
108
109
        setcookie(self::COOKIE_USER, $userId);
110
        setcookie(self::COOKIE_NAME, $token, $cookie_options);
111
    }
112
113
    private static function generateToken(): string
114
    {
115
        return bin2hex(random_bytes(32));
116
    }
117
118
    public static function logout(): void
119
    {
120
        // Erase old cookies.
121
        setcookie(self::COOKIE_USER, '', time() - 60);
122
        setcookie(self::COOKIE_NAME, '', time() - 60);
123
    }
124
125
    /**
126
     * Return the JWT security Key
127
     *
128
     * @return string|null
129
     * @throws \DebugBar\DebugBarException
130
     * @throws \Random\RandomException
131
     */
132
    public static function getSecurityKey()
133
    {
134
        if (self::$security_key !== null) {
135
            return self::$security_key;
136
        }
137
138
        $config = Config::getConfig();
139
        if (!isset($config->security->jwt_secret_key)) {
140
            $config->security->jwt_secret_key = bin2hex(random_bytes(20));
141
            if (!Config::setConfig($config)) {
142
                return null;
143
            }
144
        }
145
146
        self::$security_key = $config->security->jwt_secret_key;
147
        return self::$security_key;
148
    }
149
}
150