Auth::logout()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 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\Controller\ConfigController;
23
use CoreModules\Admin\Model\User;
24
use DebugBar\DebugBarException;
25
use Random\RandomException;
0 ignored issues
show
Bug introduced by
The type Random\RandomException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
abstract class Auth
28
{
29
    private const COOKIE_NAME = 'alxarafe_login';
30
    private const COOKIE_USER = self::COOKIE_NAME . '_user';
31
    private const COOKIE_EXPIRE_TIME = 30 * 24 * 60 * 60; // 30 days
32
    private const COOKIE_SAMESITE = 'Strict';
33
34
    public static ?User $user = null;
35
    /**
36
     * Contains the JWT security key
37
     *
38
     * @var string|null
39
     */
40
    private static ?string $security_key = null;
41
42
    public static function isLogged(): bool
43
    {
44
        $userId = FILTER_INPUT(INPUT_COOKIE, self::COOKIE_USER);
45
        $token = FILTER_INPUT(INPUT_COOKIE, self::COOKIE_NAME);
46
47
        if (empty($token)) {
48
            return false;
49
        }
50
51
        try {
52
            self::$user = User::find($userId);
53
        } catch (\Exception $e) {
54
            Messages::addError(Trans::_('error_message', ['message' => $e->getMessage()]));
55
            Functions::httpRedirect(ConfigController::url());
56
        }
57
58
        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...
59
    }
60
61
    /**
62
     * Return true if login is correct with user/mail and password.
63
     * TODO: This is a test. It will be checked against a user database.
64
     *
65
     * @param string $username
66
     * @param string $password
67
     *
68
     * @return bool
69
     */
70
    public static function login(string $username, string $password): bool
71
    {
72
        $user = User::where('name', $username)->first();
73
74
        if (!isset($user)) {
75
            return false;
76
        }
77
78
        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...
79
            return false;
80
        }
81
82
        self::setLoginCookie($user->id);
0 ignored issues
show
Bug introduced by
The property id does not seem to exist on Illuminate\Database\Eloq...elations\HasManyThrough.
Loading history...
Bug introduced by
The property id does not seem to exist on Illuminate\Database\Eloq...Relations\HasOneThrough.
Loading history...
83
84
        return true;
85
    }
86
87
    public static function setLoginCookie($userId): void
88
    {
89
        $user = User::find($userId);
0 ignored issues
show
Unused Code introduced by
The assignment to $user is dead and can be removed.
Loading history...
90
        self::$user = User::find($userId);
91
92
        $token = self::generateToken();
93
94
        if (!isset(self::$user)) {
95
            self::$user = User::find($userId);
96
        }
97
98
        if (isset(self::$user)) {
99
            self::$user->saveToken($token);
100
        }
101
102
        /**
103
         * Ideally, "secure" is set to true, but this does not work with self-signed certificates.
104
         * With "secure" set to false, it is important that samesite is set to Strict.
105
         */
106
        $cookie_options = [
107
            'expires' => time() + self::COOKIE_EXPIRE_TIME,
108
            'path' => '/',
109
            'domain' => $_SERVER['HTTP_HOST'],
110
            'secure' => false,
111
            'httponly' => true,
112
            'samesite' => self::COOKIE_SAMESITE,
113
        ];
114
115
        setcookie(self::COOKIE_USER, $userId);
116
        setcookie(self::COOKIE_NAME, $token, $cookie_options);
117
    }
118
119
    private static function generateToken(): string
120
    {
121
        return bin2hex(random_bytes(32));
122
    }
123
124
    public static function logout(): void
125
    {
126
        // Erase old cookies.
127
        setcookie(self::COOKIE_USER, '', time() - 60);
128
        setcookie(self::COOKIE_NAME, '', time() - 60);
129
    }
130
131
    /**
132
     * Return the JWT security Key
133
     *
134
     * @return string|null
135
     * @throws DebugBarException
136
     * @throws RandomException
137
     */
138
    public static function getSecurityKey()
139
    {
140
        if (self::$security_key !== null) {
141
            return self::$security_key;
142
        }
143
144
        $config = Config::getConfig();
145
        if (!isset($config->security->jwt_secret_key)) {
146
            $config->security->jwt_secret_key = bin2hex(random_bytes(20));
147
            if (!Config::setConfig($config)) {
148
                return null;
149
            }
150
        }
151
152
        self::$security_key = $config->security->jwt_secret_key;
153
        return self::$security_key;
154
    }
155
}
156