📄 Source: auth.php
<?php
/**
* Authentication gate. Include this at the top of every page and API entry.
*
* Behaviour:
* - If AUTH_ENABLED is false, everything is allowed.
* - If the client IP is in LAN_SUBNETS, no login required.
* - Otherwise, a session must exist and be valid.
* - If a user has device_binding on, the session must carry a matching
* device token (set in a separate long-lived cookie).
*/
$CFG = require __DIR__ . '/config.php';
session_name($CFG['session_name']);
session_set_cookie_params([
'lifetime' => $CFG['session_lifetime'],
'path' => '/',
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
require_once __DIR__ . '/lib/net.php';
require_once __DIR__ . '/lib/users.php';
users_ensure_owner($CFG['owner_username'], $CFG['owner_password']);
$GLOBALS['__CFG'] = $CFG;
$GLOBALS['__LAN'] = is_lan($CFG['lan_subnets']);
$GLOBALS['__AUTHED'] = false;
$GLOBALS['__USER'] = null;
if (!$CFG['auth_enabled'] || $GLOBALS['__LAN']) {
$GLOBALS['__AUTHED'] = true;
$GLOBALS['__USER'] = $GLOBALS['__LAN'] ? ['username' => '(LAN)', 'is_owner' => true] : ['username' => '(auth off)', 'is_owner' => true];
} elseif (!empty($_SESSION['username'])) {
$u = users_find($_SESSION['username']);
if ($u !== null) {
// Device binding check
if (!empty($u['device_bound'])) {
$cookieName = $CFG['session_name'] . '_dev';
$token = $_COOKIE[$cookieName] ?? '';
if (!$token || !hash_equals((string)$u['device_token'], (string)$token)) {
// Bound but cookie missing/mismatched → refuse.
session_destroy();
$u = null;
}
}
if ($u !== null) {
$GLOBALS['__AUTHED'] = true;
$GLOBALS['__USER'] = $u;
}
}
}
function require_auth_json(): void {
if (!$GLOBALS['__AUTHED']) {
http_response_code(401);
header('Content-Type: application/json');
echo json_encode(['ok' => false, 'error' => 'Not authenticated']);
exit;
}
}
function require_owner_json(): void {
require_auth_json();
if (empty($GLOBALS['__USER']['is_owner'])) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode(['ok' => false, 'error' => 'Owner only']);
exit;
}
}
← Back