4in1_ws_web/lib/admin.php

181 lines
5.6 KiB
PHP

<?php
class admin {
const int ADMIN_SESSION_TIMEOUT = 86400 * 14;
const string ADMIN_COOKIE_NAME = 'admin_key';
const int ADMIN_LOGIN_MAX_LENGTH = 32;
// session data
protected static ?int $id = null;
protected static ?int $authId = null;
protected static ?string $csrfSalt = null;
protected static ?string $login = null;
public static function exists(string $login): bool {
$db = DB();
return (int)$db->result($db->query("SELECT COUNT(*) FROM admins WHERE login=? LIMIT 1", $login)) > 0;
}
public static function add(string $login, string $password): int {
$db = DB();
$db->insert('admins', [
'login' => $login,
'password' => saltPassword($password),
'activity_ts' => 0
]);
return $db->insertId();
}
public static function delete(string $login): bool {
$db = DB();
$id = self::getIdByLogin($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[]
*/
public static function getLoginsById(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;
}
protected static function getIdByLogin(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;
}
public static function setPassword(string $login, string $password): bool {
$db = DB();
$db->query("UPDATE admins SET password=? WHERE login=?", saltPassword($password), $login);
return $db->affectedRows() > 0;
}
public static function auth(string $login, string $password): bool {
$db = DB();
$salted_password = saltPassword($password);
$q = $db->query("SELECT id, active FROM admins WHERE login=? AND password=?", $login, $salted_password);
if (!$db->numRows($q)) {
logDebug(__METHOD__.': login or password is invalid');
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);
self::setSessionData($id, $login, $auth_id, $salted_password);
self::setCookie($token);
return true;
}
public static function logout() {
if (!isAdmin())
return;
$db = DB();
$db->query("DELETE FROM admin_auth WHERE id=?", self::$authId);
self::unsetSessionData();
self::unsetCookie();
}
public static function log(\AdminActions\BaseAction $action) {
\AdminActions\Util\Logger::record($action);
}
public static function check(): void {
if (!isset($_COOKIE[self::ADMIN_COOKIE_NAME]))
return;
$cookie = (string)$_COOKIE[self::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)) {
unset($_COOKIE[self::ADMIN_COOKIE_NAME]);
return;
}
$info = $db->fetch($q);
self::setSessionData((int)$info['id'], $info['login'], (int)$info['auth_id'], $info['salted_password']);
if ($time - $info['activity_ts'] > 15)
$db->query("UPDATE admins SET activity_ts=? WHERE id=?", $time, self::$id);
}
protected static function setCookie(string $token): void {
global $config;
setcookie(self::ADMIN_COOKIE_NAME, $token, time() + self::ADMIN_SESSION_TIMEOUT, '/', $config['cookie_host']);
}
protected static function unsetCookie(): void {
global $config;
setcookie(self::ADMIN_COOKIE_NAME, '', 1, '/', $config['cookie_host']);
}
protected static function setSessionData(int $id, string $login, int $authId, string $saltedPassword) {
self::$id = $id;
self::$login = $login;
self::$authId = $authId;
self::$csrfSalt = saltPassword(strrev($saltedPassword));
}
protected static function unsetSessionData(): void {
self::$id = null;
self::$authId = null;
self::$csrfSalt = null;
self::$login = null;
}
public static function getId(): ?int { return self::$id; }
public static function getCSRFSalt(): ?string { return self::$csrfSalt; }
public static function getLogin(): ?string { return self::$login; }
}