- Update passkey data mapping to use associative arrays and handle JSON decoding for `transports`. - Refactor token caching logic to validate database existence and clear stale entries. - Improve 2FA handling by centralizing `token->type` and `user_id` processing for reuse.
106 lines
3.3 KiB
PHP
106 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace objects;
|
|
|
|
use classes\db;
|
|
use classes\object_property;
|
|
use Exception;
|
|
use traits\db_object_t;
|
|
|
|
class tokens_o extends db
|
|
{
|
|
use db_object_t;
|
|
|
|
public object_property $user_id;
|
|
public object_property $type; // AUTH_TOKEN, RESET_PASSWORD, AUTH_TOKEN_SUBUSER
|
|
public object_property $token;
|
|
|
|
public function structure(): void
|
|
{
|
|
$this->setTable('tokens');
|
|
}
|
|
|
|
public function objectChanged(): void
|
|
{
|
|
// Invalidate the cache
|
|
if ($this->id > 0) {
|
|
try {
|
|
$token = $this->token->value();
|
|
redis->clear_token($token);
|
|
} catch (\Exception $e) {
|
|
// If the record is already gone or token cannot be retrieved, we can't clear by token string.
|
|
// This can happen during a hard delete where objectChanged is called after the record is deleted.
|
|
}
|
|
}
|
|
}
|
|
|
|
public function create(int $user_id, string $token, string $type = 'AUTH_TOKEN'): void
|
|
{
|
|
global $db;
|
|
// Avoid SQL injection
|
|
$token = $db->escape_string($token);
|
|
// Create a new record in the database
|
|
$sql = "INSERT INTO $this->table (user_id, token, type) VALUES ($user_id, '$token', '$type')";
|
|
$db->query($sql);
|
|
|
|
// Get the id of the new record
|
|
$this->id = $db->insert_id();
|
|
|
|
// Set the values of the object properties
|
|
$this->getObjectProperties();
|
|
}
|
|
|
|
public function getObjectProperties(): void
|
|
{
|
|
$this->user_id = new object_property($this->table, $this->id, 'user_id', 'int', true);
|
|
$this->type = new object_property($this->table, $this->id, 'type', 'string', true);
|
|
$this->token = new object_property($this->table, $this->id, 'token', 'string', true);
|
|
}
|
|
|
|
/**
|
|
* @throws Exception
|
|
*/
|
|
public function getToken(string $token): tokens_o
|
|
{
|
|
global $db;
|
|
// Check if the token is cached
|
|
$cached = redis->get_token($token);
|
|
if ($cached) {
|
|
$this->id = (int)$cached['id'];
|
|
// Verify that the token still exists in the database to avoid stale cache issues.
|
|
if ($this->exists()) {
|
|
$this->getObjectProperties();
|
|
return $this;
|
|
}
|
|
// If it doesn't exist, clear the stale cache entry and proceed to check the database.
|
|
redis->clear_token($token);
|
|
}
|
|
// Avoid SQL injection
|
|
$token = $db->escape_string($token);
|
|
// Prepare the SQL statement
|
|
$sql = "SELECT id FROM $this->table WHERE token = '$token'";
|
|
$result = $db->query($sql);
|
|
$row = $db->fetch_assoc($result);
|
|
if (!$row) {
|
|
throw new Exception("Token not found " . $token);
|
|
}
|
|
// Cache the token
|
|
redis->cache_token($token, $row);
|
|
$this->id = $row['id'];
|
|
$this->getObjectProperties();
|
|
return $this;
|
|
}
|
|
|
|
public function delete(string $token): void
|
|
{
|
|
global $db;
|
|
// Avoid SQL injection
|
|
$token = $db->escape_string($token);
|
|
// Prepare the SQL statement
|
|
$sql = "DELETE FROM $this->table WHERE token = '$token'";
|
|
$db->query($sql);
|
|
|
|
// Clear the token from the cache
|
|
redis->clear_token($token);
|
|
}
|
|
} |