174 lines
5.4 KiB
PHP
174 lines
5.4 KiB
PHP
<?php
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 0);
|
|
ini_set('log_errors', 1);
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
http_response_code(204);
|
|
exit;
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
|
http_response_code(405);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Method not allowed'
|
|
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
|
exit;
|
|
}
|
|
|
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/session_bootstrap.php';
|
|
|
|
function userRespond($payload, $status = 200)
|
|
{
|
|
http_response_code($status);
|
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
|
exit;
|
|
}
|
|
|
|
function getAuthorizationToken()
|
|
{
|
|
$header = '';
|
|
|
|
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
|
$header = trim((string)$_SERVER['HTTP_AUTHORIZATION']);
|
|
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
|
$header = trim((string)$_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
|
|
}
|
|
|
|
if ($header === '') {
|
|
return null;
|
|
}
|
|
|
|
if (preg_match('/^Bearer\s+(.+)$/i', $header, $matches)) {
|
|
return trim($matches[1]);
|
|
}
|
|
|
|
if (preg_match('/^Token\s+(.+)$/i', $header, $matches)) {
|
|
return trim($matches[1]);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function tableExists(PDO $pdo, $schema, $table)
|
|
{
|
|
$stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = :schema AND table_name = :table');
|
|
$stmt->execute([
|
|
':schema' => $schema,
|
|
':table' => $table
|
|
]);
|
|
return (int)$stmt->fetchColumn() > 0;
|
|
}
|
|
|
|
function getTableColumns(PDO $pdo, $schema, $table)
|
|
{
|
|
$stmt = $pdo->prepare('SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table');
|
|
$stmt->execute([
|
|
':schema' => $schema,
|
|
':table' => $table
|
|
]);
|
|
$columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
return is_array($columns) ? $columns : [];
|
|
}
|
|
|
|
function resolveUserIdFromBearer(PDO $pdo, $rawToken)
|
|
{
|
|
$token = trim((string)$rawToken);
|
|
if ($token === '') {
|
|
return null;
|
|
}
|
|
|
|
$schema = (string)$pdo->query('SELECT DATABASE()')->fetchColumn();
|
|
if ($schema === '') {
|
|
return null;
|
|
}
|
|
|
|
$candidates = [
|
|
['table' => 'remember_tokens', 'user' => 'user_id', 'token' => 'token', 'expires' => 'expires_at', 'revoked' => null],
|
|
['table' => 'user_tokens', 'user' => 'user_id', 'token' => 'token', 'expires' => 'expires_at', 'revoked' => 'revoked_at'],
|
|
['table' => 'api_tokens', 'user' => 'user_id', 'token' => 'token', 'expires' => 'expires_at', 'revoked' => 'revoked_at'],
|
|
['table' => 'access_tokens', 'user' => 'user_id', 'token' => 'token', 'expires' => 'expires_at', 'revoked' => 'revoked_at'],
|
|
['table' => 'auth_tokens', 'user' => 'user_id', 'token' => 'token', 'expires' => 'expires_at', 'revoked' => 'revoked_at']
|
|
];
|
|
|
|
$hashes = [
|
|
$token,
|
|
hash('sha256', $token)
|
|
];
|
|
|
|
foreach ($candidates as $candidate) {
|
|
if (!tableExists($pdo, $schema, $candidate['table'])) {
|
|
continue;
|
|
}
|
|
|
|
$columns = getTableColumns($pdo, $schema, $candidate['table']);
|
|
if (!in_array($candidate['user'], $columns, true) || !in_array($candidate['token'], $columns, true)) {
|
|
continue;
|
|
}
|
|
|
|
$select = 'SELECT `' . $candidate['user'] . '` AS user_id FROM `' . $candidate['table'] . '` WHERE `' . $candidate['token'] . '` IN (:token_raw, :token_sha)';
|
|
|
|
if ($candidate['expires'] !== null && in_array($candidate['expires'], $columns, true)) {
|
|
$select .= ' AND (`' . $candidate['expires'] . '` IS NULL OR `' . $candidate['expires'] . '` > NOW())';
|
|
}
|
|
|
|
if ($candidate['revoked'] !== null && in_array($candidate['revoked'], $columns, true)) {
|
|
$select .= ' AND `' . $candidate['revoked'] . '` IS NULL';
|
|
}
|
|
|
|
$select .= ' ORDER BY user_id DESC LIMIT 1';
|
|
|
|
$stmt = $pdo->prepare($select);
|
|
$stmt->execute([
|
|
':token_raw' => $hashes[0],
|
|
':token_sha' => $hashes[1]
|
|
]);
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if ($row && isset($row['user_id']) && (int)$row['user_id'] > 0) {
|
|
return (int)$row['user_id'];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function requireUserAuth()
|
|
{
|
|
if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true && !empty($_SESSION['user_id'])) {
|
|
return (int)$_SESSION['user_id'];
|
|
}
|
|
|
|
global $pdo;
|
|
|
|
$token = getAuthorizationToken();
|
|
if ($token !== null && isset($pdo) && ($pdo instanceof PDO)) {
|
|
$tokenUserId = resolveUserIdFromBearer($pdo, $token);
|
|
if ($tokenUserId !== null) {
|
|
$_SESSION['logged_in'] = true;
|
|
$_SESSION['user_id'] = $tokenUserId;
|
|
return $tokenUserId;
|
|
}
|
|
}
|
|
|
|
userRespond([
|
|
'success' => false,
|
|
'error' => 'Unauthorized'
|
|
], 401);
|
|
}
|
|
|
|
require_once __DIR__ . '/../administration/includes/config.php';
|
|
|
|
if (!isset($pdo) || !($pdo instanceof PDO)) {
|
|
userRespond([
|
|
'success' => false,
|
|
'error' => 'Database connection not initialized'
|
|
], 500);
|
|
}
|