188 lines
5.0 KiB
PHP
188 lines
5.0 KiB
PHP
<?php
|
|
|
|
const ADMIN_SESSION_TIMEOUT = 86400 * 14;
|
|
const ADMIN_COOKIE_NAME = 'admin_key';
|
|
const ADMIN_LOGIN_MAX_LENGTH = 32;
|
|
|
|
$AdminSession = new class {
|
|
public function __construct(
|
|
public ?int $id = null,
|
|
public ?int $authId = null,
|
|
public ?string $csrfSalt = null,
|
|
public ?string $login = null,
|
|
) {}
|
|
|
|
public function mrProper(): void {
|
|
$this->id = null;
|
|
$this->authId = null;
|
|
$this->csrfSalt = null;
|
|
$this->login = null;
|
|
}
|
|
|
|
public function makeCSRFSalt(string $salted_password): void {
|
|
$this->csrfSalt = salt_password(strrev($salted_password));
|
|
}
|
|
};
|
|
|
|
function is_admin(): bool {
|
|
global $AdminSession;
|
|
if ($AdminSession->id === null)
|
|
_admin_check();
|
|
return $AdminSession->id != 0;
|
|
}
|
|
|
|
function admin_exists(string $login): bool {
|
|
$db = DB();
|
|
return (int)$db->result($db->query("SELECT COUNT(*) FROM admins WHERE login=? LIMIT 1", $login)) > 0;
|
|
}
|
|
|
|
function admin_add(string $login, string $password): int {
|
|
$db = DB();
|
|
$db->insert('admins', [
|
|
'login' => $login,
|
|
'password' => salt_password($password),
|
|
'activity_ts' => 0
|
|
]);
|
|
return $db->insertId();
|
|
}
|
|
|
|
function admin_delete(string $login): bool {
|
|
$db = DB();
|
|
$id = admin_get_id_by_login($login);
|
|
if (!$db->query("DELETE FROM admins WHERE login=?", $login)) return false;
|
|
if (!$db->query("DELETE FROM admin_auth WHERE admin_id=?", $id)) return false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param int[] $ids
|
|
* @return string[]
|
|
*/
|
|
function admin_get_logins_by_id(array $ids): array {
|
|
$db = DB();
|
|
$logins = [];
|
|
$q = $db->query("SELECT id, login FROM admins WHERE id IN (".implode(',', $ids).")");
|
|
while ($row = $db->fetch($q)) {
|
|
$logins[(int)$row['id']] = $row['login'];
|
|
}
|
|
return $logins;
|
|
}
|
|
|
|
function admin_get_id_by_login(string $login): ?int {
|
|
$db = DB();
|
|
$q = $db->query("SELECT id FROM admins WHERE login=?", $login);
|
|
return $db->numRows($q) > 0 ? (int)$db->result($q) : null;
|
|
}
|
|
|
|
function admin_set_password(string $login, string $password): bool {
|
|
$db = DB();
|
|
$db->query("UPDATE admins SET password=? WHERE login=?", salt_password($password), $login);
|
|
return $db->affectedRows() > 0;
|
|
}
|
|
|
|
function admin_auth(string $login, string $password): bool {
|
|
global $AdminSession;
|
|
|
|
$db = DB();
|
|
$salted_password = salt_password($password);
|
|
$q = $db->query("SELECT id, active FROM admins WHERE login=? AND password=?", $login, $salted_password);
|
|
if (!$db->numRows($q))
|
|
return false;
|
|
|
|
$row = $db->fetch($q);
|
|
$id = (int)$row['id'];
|
|
$active = (bool)$row['active'];
|
|
if (!$active)
|
|
return false;
|
|
|
|
$time = time();
|
|
|
|
do {
|
|
$token = strgen(32);
|
|
} while ($db->numRows($db->query("SELECT id FROM admin_auth WHERE token=? LIMIT 1", $token)) > 0);
|
|
|
|
$db->insert('admin_auth', [
|
|
'admin_id' => $id,
|
|
'token' => $token,
|
|
'ts' => $time
|
|
]);
|
|
$auth_id = $db->insertId();
|
|
|
|
$db->insert('admin_log', [
|
|
'admin_id' => $id,
|
|
'ts' => $time,
|
|
'ip' => ip2ulong($_SERVER['REMOTE_ADDR']),
|
|
'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
|
]);
|
|
|
|
$db->query("UPDATE admins SET activity_ts=? WHERE id=?", $time, $id);
|
|
|
|
$AdminSession->id = $id;
|
|
$AdminSession->login = $login;
|
|
$AdminSession->makeCSRFSalt($salted_password);
|
|
$AdminSession->authId = $auth_id;
|
|
|
|
_admin_set_cookie($token);
|
|
return true;
|
|
}
|
|
|
|
function admin_logout() {
|
|
if (!is_admin())
|
|
return;
|
|
|
|
global $AdminSession;
|
|
|
|
$db = DB();
|
|
$db->query("DELETE FROM admin_auth WHERE id=?", $AdminSession->authId);
|
|
|
|
$AdminSession->mrProper();
|
|
_admin_unset_cookie();
|
|
}
|
|
|
|
function admin_log(\AdminActions\BaseAction $action) {
|
|
\AdminActions\Util\Logger::record($action);
|
|
}
|
|
|
|
function _admin_check(): void {
|
|
if (!isset($_COOKIE[ADMIN_COOKIE_NAME]))
|
|
return;
|
|
|
|
$cookie = (string)$_COOKIE[ADMIN_COOKIE_NAME];
|
|
$db = DB();
|
|
$time = time();
|
|
$q = $db->query("SELECT
|
|
admin_auth.id AS auth_id,
|
|
admin_auth.admin_id AS id,
|
|
admins.activity_ts AS activity_ts,
|
|
admins.password AS salted_password,
|
|
admins.login AS login
|
|
FROM admin_auth
|
|
LEFT JOIN admins ON admin_auth.admin_id=admins.id
|
|
WHERE admin_auth.token=?
|
|
LIMIT 1", $cookie);
|
|
|
|
if (!$db->numRows($q))
|
|
return;
|
|
|
|
$info = $db->fetch($q);
|
|
|
|
global $AdminSession;
|
|
$AdminSession->id = (int)$info['id'];
|
|
$AdminSession->login = $info['login'];
|
|
$AdminSession->authId = (int)$info['auth_id'];
|
|
$AdminSession->makeCSRFSalt($info['salted_password']);
|
|
|
|
if ($time - $info['activity_ts'] > 15)
|
|
$db->query("UPDATE admins SET activity_ts=? WHERE id=?", $time, $AdminSession->id);
|
|
}
|
|
|
|
function _admin_set_cookie(string $token): void {
|
|
global $config;
|
|
setcookie(ADMIN_COOKIE_NAME, $token, time() + ADMIN_SESSION_TIMEOUT, '/', $config['cookie_host']);
|
|
}
|
|
|
|
function _admin_unset_cookie(): void {
|
|
global $config;
|
|
setcookie(ADMIN_COOKIE_NAME, '', 1, '/', $config['cookie_host']);
|
|
}
|