First git commit
This commit is contained in:
117
public_html/lib/auth.php
Normal file
117
public_html/lib/auth.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
// Sessions, auth, CSRF. Included by every page via bootstrap.php.
|
||||
|
||||
function session_boot(): void {
|
||||
if (session_status() === PHP_SESSION_ACTIVE) return;
|
||||
// WAP gateways often strip cookies -> accept the sid from the query string.
|
||||
ini_set('session.use_only_cookies', '0');
|
||||
ini_set('session.use_trans_sid', '0');
|
||||
session_name('WAPSID');
|
||||
if (!empty($_REQUEST['WAPSID']) && preg_match('/^[A-Za-z0-9,\-]{8,64}$/', $_REQUEST['WAPSID'])) {
|
||||
session_id($_REQUEST['WAPSID']);
|
||||
}
|
||||
session_start();
|
||||
}
|
||||
|
||||
function csrf_token(): string {
|
||||
if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(16));
|
||||
return $_SESSION['csrf'];
|
||||
}
|
||||
|
||||
function csrf_ok(): bool {
|
||||
$t = $_POST['csrf'] ?? $_GET['csrf'] ?? '';
|
||||
return $t !== '' && !empty($_SESSION['csrf']) && hash_equals($_SESSION['csrf'], $t);
|
||||
}
|
||||
|
||||
function require_csrf(): void {
|
||||
if (!csrf_ok()) bail('Error', 'Session expired or bad token. Please try again.');
|
||||
}
|
||||
|
||||
function current_user(): ?array {
|
||||
static $cache = null;
|
||||
static $done = false;
|
||||
if ($done) return $cache;
|
||||
$done = true;
|
||||
if (empty($_SESSION['uid'])) return $cache = null;
|
||||
$s = db()->prepare("SELECT * FROM users WHERE id=?");
|
||||
$s->execute([$_SESSION['uid']]);
|
||||
$u = $s->fetch();
|
||||
if (!$u || $u['is_banned']) { $_SESSION['uid'] = null; return $cache = null; }
|
||||
// throttle last_seen writes to once a minute
|
||||
if (time() - (int)$u['last_seen'] > 60) {
|
||||
db()->prepare("UPDATE users SET last_seen=? WHERE id=?")->execute([time(), $u['id']]);
|
||||
}
|
||||
return $cache = $u;
|
||||
}
|
||||
|
||||
function require_login(): array {
|
||||
$u = current_user();
|
||||
if (!$u) {
|
||||
page_start('Login needed', ['back' => '/index.php']);
|
||||
p_para('You must log in to use this feature.');
|
||||
p_links([['/login.php', 'Login'], ['/signup.php', 'Sign up'], ['/index.php', 'Home']]);
|
||||
page_end();
|
||||
exit;
|
||||
}
|
||||
return $u;
|
||||
}
|
||||
|
||||
function require_admin(): array {
|
||||
$u = require_login();
|
||||
if (!$u['is_admin']) bail('Denied', 'Admin only.');
|
||||
return $u;
|
||||
}
|
||||
|
||||
function user_login(string $name, string $pass): ?array {
|
||||
$s = db()->prepare("SELECT * FROM users WHERE username=?");
|
||||
$s->execute([$name]);
|
||||
$u = $s->fetch();
|
||||
if (!$u || !password_verify($pass, $u['pass_hash'])) return null;
|
||||
if ($u['is_banned']) return null;
|
||||
$_SESSION['uid'] = (int)$u['id'];
|
||||
return $u;
|
||||
}
|
||||
|
||||
function user_create(string $name, string $pass, int $admin = 0): int {
|
||||
$s = db()->prepare("INSERT INTO users (username,pass_hash,is_admin,created_at)
|
||||
VALUES (?,?,?,?)");
|
||||
$s->execute([$name, password_hash($pass, PASSWORD_DEFAULT), $admin, time()]);
|
||||
return (int)db()->lastInsertId();
|
||||
}
|
||||
|
||||
function username_taken(string $n): bool {
|
||||
$s = db()->prepare("SELECT 1 FROM users WHERE username=?");
|
||||
$s->execute([$n]);
|
||||
return (bool)$s->fetchColumn();
|
||||
}
|
||||
|
||||
function valid_username(string $n): bool {
|
||||
return (bool)preg_match('/^[A-Za-z0-9_]{3,16}$/', $n);
|
||||
}
|
||||
|
||||
function user_by_id(int $id): ?array {
|
||||
$s = db()->prepare("SELECT * FROM users WHERE id=?");
|
||||
$s->execute([$id]);
|
||||
return $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
function user_by_name(string $n): ?array {
|
||||
$s = db()->prepare("SELECT * FROM users WHERE username=?");
|
||||
$s->execute([$n]);
|
||||
return $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
function unread_count(int $uid): int {
|
||||
$s = db()->prepare("SELECT COUNT(*) FROM messages WHERE to_id=? AND is_read=0");
|
||||
$s->execute([$uid]);
|
||||
return (int)$s->fetchColumn();
|
||||
}
|
||||
|
||||
function ago(int $ts): string {
|
||||
$d = max(0, time() - $ts);
|
||||
if ($d < 60) return $d . 's';
|
||||
if ($d < 3600) return floor($d / 60) . 'm';
|
||||
if ($d < 86400) return floor($d / 3600) . 'h';
|
||||
if ($d < 2592000) return floor($d / 86400) . 'd';
|
||||
return date('d/m/y', $ts);
|
||||
}
|
||||
Reference in New Issue
Block a user