Files
rpi-tor-relay-panel/web/lib/app.php
2025-11-07 09:47:03 +01:00

109 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => $secure,
'httponly' => true,
'samesite' => 'Strict',
]);
ini_set('session.use_strict_mode', '1');
ini_set('session.cookie_httponly', '1');
session_name('torpanel');
session_start();
const APP_CONF_DIR = '/etc/torpanel';
const APP_CONF_FILE = APP_CONF_DIR . '/app.json';
const STATE_DIR = '/var/lib/torpanel';
const LOGIN_THROTTLE_FILE = STATE_DIR . '/login_throttle.json';
const SESSION_IDLE_TTL = 60 * 60 * 12;
if (!empty($_SESSION['last']) && (time() - (int)$_SESSION['last']) > SESSION_IDLE_TTL) {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$p = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'] ?? false, $p['httponly'] ?? true);
}
session_destroy();
session_start();
}
$_SESSION['last'] = time();
function app_is_installed(): bool {
return is_file(APP_CONF_FILE);
}
function app_config(): array {
if (!app_is_installed()) return [];
$raw = @file_get_contents(APP_CONF_FILE);
return $raw ? (json_decode($raw, true) ?: []) : [];
}
function app_save_config(array $cfg): void {
if (!is_dir(APP_CONF_DIR)) mkdir(APP_CONF_DIR, 0770, true);
$tmp = APP_CONF_FILE . '.tmp';
file_put_contents($tmp, json_encode($cfg, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
rename($tmp, APP_CONF_FILE);
@chmod(APP_CONF_FILE, 0640);
}
function auth_login(string $u, string $p): bool {
$cfg = app_config();
if (!isset($cfg['admin_user'], $cfg['admin_pass'])) return false;
if (!hash_equals($cfg['admin_user'], $u)) return false;
if (!password_verify($p, $cfg['admin_pass'])) return false;
session_regenerate_id(true);
$_SESSION['uid'] = $u;
$_SESSION['ua'] = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 160);
$_SESSION['last'] = time();
return true;
}
function auth_logout(): void {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$p = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'] ?? false, $p['httponly'] ?? true);
}
session_destroy();
}
function auth_require(): void {
if (!app_is_installed()) { header('Location: /setup.php'); exit; }
if (empty($_SESSION['uid'])) { header('Location: /login.php'); exit; }
}
function throttle_state(): array {
if (!is_dir(STATE_DIR)) @mkdir(STATE_DIR, 0775, true);
$raw = @file_get_contents(LOGIN_THROTTLE_FILE);
return $raw ? (json_decode($raw, true) ?: []) : [];
}
function throttle_save(array $st): void {
$tmp = LOGIN_THROTTLE_FILE . '.tmp';
file_put_contents($tmp, json_encode($st));
@chmod($tmp, 0660);
rename($tmp, LOGIN_THROTTLE_FILE);
}
function throttle_check(string $ip): int {
$st = throttle_state();
$now = time();
$key = $ip ?: 'unknown';
$rec = $st[$key] ?? ['fails'=>0, 'until'=>0];
if ($rec['until'] > $now) return $rec['until'] - $now;
return 0;
}
function throttle_record(string $ip, bool $ok): void {
$st = throttle_state();
$now = time();
$key = $ip ?: 'unknown';
$rec = $st[$key] ?? ['fails'=>0, 'until'=>0];
if ($ok) {
$rec = ['fails'=>0, 'until'=>0];
} else {
$rec['fails'] = min(10, ($rec['fails'] ?? 0) + 1);
$wait = min(300, 2 ** $rec['fails']);
$rec['until'] = $now + $wait;
}
$st[$key] = $rec;
throttle_save($st);
}