mirror of
https://github.com/hyzendust/freedoms4-backend-public.git
synced 2026-09-19 02:33:04 +02:00
Fix: auto-logout sessions + another minor hardening
This commit is contained in:
@@ -218,6 +218,7 @@ function xmpp_delete_backup(string $username): void {
|
|||||||
|
|
||||||
// ── Session + admin check ──
|
// ── Session + admin check ──
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
ini_set('session.gc_maxlifetime', (string) SESSION_TTL);
|
||||||
session_name(SESSION_NAME);
|
session_name(SESSION_NAME);
|
||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => 0,
|
'lifetime' => 0,
|
||||||
|
|||||||
15
auth.php
15
auth.php
@@ -37,7 +37,6 @@ define('PROSODY_HOST', $env['PROSODY_HOST'] ?? 'freedoms4.org');
|
|||||||
define('SESSION_NAME', 'f4_session');
|
define('SESSION_NAME', 'f4_session');
|
||||||
define('SESSION_SECURE', true);
|
define('SESSION_SECURE', true);
|
||||||
define('SESSION_SAMESITE', 'None');
|
define('SESSION_SAMESITE', 'None');
|
||||||
define('SESSION_TTL', 86400); // 24 hours
|
|
||||||
|
|
||||||
define('OTP_FROM', 'no-reply@freedoms4.org');
|
define('OTP_FROM', 'no-reply@freedoms4.org');
|
||||||
define('OTP_TTL', 600); // 10 minutes
|
define('OTP_TTL', 600); // 10 minutes
|
||||||
@@ -79,6 +78,7 @@ function json_out(array $data, int $status = 200): never {
|
|||||||
|
|
||||||
function start_session(): void {
|
function start_session(): void {
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
ini_set('session.gc_maxlifetime', (string) SESSION_TTL);
|
||||||
session_name(SESSION_NAME);
|
session_name(SESSION_NAME);
|
||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => 0,
|
'lifetime' => 0,
|
||||||
@@ -600,17 +600,24 @@ if ($action === 'check_session') {
|
|||||||
json_out(['valid' => false]);
|
json_out(['valid' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify user still exists in DB
|
// Verify user still exists in DB and isn't blocked
|
||||||
try {
|
try {
|
||||||
$pdo = db_connect();
|
$pdo = db_connect();
|
||||||
$stmt = $pdo->prepare('SELECT 1 FROM users WHERE id = :id LIMIT 1');
|
$stmt = $pdo->prepare('SELECT blocked FROM users WHERE id = :id LIMIT 1');
|
||||||
$stmt->execute([':id' => $_SESSION['user_id']]);
|
$stmt->execute([':id' => $_SESSION['user_id']]);
|
||||||
if (!$stmt->fetch()) {
|
$row = $stmt->fetch();
|
||||||
|
if (!$row) {
|
||||||
// User deleted — destroy session
|
// User deleted — destroy session
|
||||||
$_SESSION = [];
|
$_SESSION = [];
|
||||||
session_destroy();
|
session_destroy();
|
||||||
json_out(['valid' => false]);
|
json_out(['valid' => false]);
|
||||||
}
|
}
|
||||||
|
if ($row['blocked'] === true || $row['blocked'] === 't') {
|
||||||
|
// User blocked — destroy session
|
||||||
|
$_SESSION = [];
|
||||||
|
session_destroy();
|
||||||
|
json_out(['valid' => false]);
|
||||||
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// DB unavailable — don't force logout, just report invalid so frontend can retry
|
// DB unavailable — don't force logout, just report invalid so frontend can retry
|
||||||
json_out(['valid' => false, 'db_error' => true]);
|
json_out(['valid' => false, 'db_error' => true]);
|
||||||
|
|||||||
10
comments.php
10
comments.php
@@ -84,6 +84,7 @@ function db_connect(): PDO {
|
|||||||
|
|
||||||
function start_session(): void {
|
function start_session(): void {
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
ini_set('session.gc_maxlifetime', (string) SESSION_TTL);
|
||||||
session_name(SESSION_NAME);
|
session_name(SESSION_NAME);
|
||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => 0,
|
'lifetime' => 0,
|
||||||
@@ -171,6 +172,15 @@ function send_notification(string $type, string $actor, string $body, string $po
|
|||||||
|
|
||||||
function logged_in_user(): ?array {
|
function logged_in_user(): ?array {
|
||||||
if (empty($_SESSION['user_id']) || empty($_SESSION['username'])) return null;
|
if (empty($_SESSION['user_id']) || empty($_SESSION['username'])) return null;
|
||||||
|
|
||||||
|
// Enforce same TTL as auth.php
|
||||||
|
$last_seen = $_SESSION['last_seen'] ?? 0;
|
||||||
|
if (time() - $last_seen > SESSION_TTL) {
|
||||||
|
$_SESSION = [];
|
||||||
|
session_destroy();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify the user still exists in the DB (handles deleted accounts / wiped DB)
|
// Verify the user still exists in the DB (handles deleted accounts / wiped DB)
|
||||||
try {
|
try {
|
||||||
$pdo = db_connect();
|
$pdo = db_connect();
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ DB_USER=""
|
|||||||
DB_PASS=""
|
DB_PASS=""
|
||||||
PROSODY_DB_USER=""
|
PROSODY_DB_USER=""
|
||||||
PROSODY_DB_PASS="" # must match /etc/prosody/prosody.cfg.lua
|
PROSODY_DB_PASS="" # must match /etc/prosody/prosody.cfg.lua
|
||||||
DOMAIN=""
|
DOMAIN="backend.freedoms4.org"
|
||||||
CERTBOT_EMAIL=""
|
CERTBOT_EMAIL=""
|
||||||
API_DIR=""
|
API_DIR=""
|
||||||
ENV_FILE=""
|
ENV_FILE=""
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
OTP_FROM="" # for example: no-reply@freedoms4.org
|
OTP_FROM="" # for example: no-reply@freedoms4.org
|
||||||
|
SESSION_GC_MAXLIFETIME=86400 # time to auto-logout a session in seconds
|
||||||
|
|
||||||
|
|
||||||
# Must run as root
|
# Must run as root
|
||||||
if [[ $EUID -ne 0 ]]; then
|
if [[ $EUID -ne 0 ]]; then
|
||||||
@@ -365,6 +367,7 @@ fi
|
|||||||
|
|
||||||
mkdir -p "${API_DIR}"
|
mkdir -p "${API_DIR}"
|
||||||
cp "${SCRIPT_DIR}/auth.php" "${API_DIR}/auth.php"
|
cp "${SCRIPT_DIR}/auth.php" "${API_DIR}/auth.php"
|
||||||
|
sed -i "/define('SESSION_SAMESITE',/a define('SESSION_TTL', ${SESSION_GC_MAXLIFETIME});" "${API_DIR}/auth.php"
|
||||||
chown -R www-data:www-data "${API_DIR}"
|
chown -R www-data:www-data "${API_DIR}"
|
||||||
chmod 640 "${API_DIR}/auth.php"
|
chmod 640 "${API_DIR}/auth.php"
|
||||||
success "auth.php deployed."
|
success "auth.php deployed."
|
||||||
@@ -373,6 +376,7 @@ if [[ ! -f "${SCRIPT_DIR}/comments.php" ]]; then
|
|||||||
error "comments.php not found in ${SCRIPT_DIR}."
|
error "comments.php not found in ${SCRIPT_DIR}."
|
||||||
fi
|
fi
|
||||||
cp "${SCRIPT_DIR}/comments.php" "${API_DIR}/comments.php"
|
cp "${SCRIPT_DIR}/comments.php" "${API_DIR}/comments.php"
|
||||||
|
sed -i "/define('SESSION_SAMESITE',/a define('SESSION_TTL', ${SESSION_GC_MAXLIFETIME});" "${API_DIR}/comments.php"
|
||||||
chown www-data:www-data "${API_DIR}/comments.php"
|
chown www-data:www-data "${API_DIR}/comments.php"
|
||||||
chmod 640 "${API_DIR}/comments.php"
|
chmod 640 "${API_DIR}/comments.php"
|
||||||
success "comments.php deployed."
|
success "comments.php deployed."
|
||||||
@@ -381,6 +385,7 @@ if [[ ! -f "${SCRIPT_DIR}/admin.php" ]]; then
|
|||||||
error "admin.php not found in ${SCRIPT_DIR}."
|
error "admin.php not found in ${SCRIPT_DIR}."
|
||||||
fi
|
fi
|
||||||
cp "${SCRIPT_DIR}/admin.php" "${API_DIR}/admin.php"
|
cp "${SCRIPT_DIR}/admin.php" "${API_DIR}/admin.php"
|
||||||
|
sed -i "/define('SESSION_SAMESITE',/a define('SESSION_TTL', ${SESSION_GC_MAXLIFETIME});" "${API_DIR}/admin.php"
|
||||||
chown www-data:www-data "${API_DIR}/admin.php"
|
chown www-data:www-data "${API_DIR}/admin.php"
|
||||||
chmod 640 "${API_DIR}/admin.php"
|
chmod 640 "${API_DIR}/admin.php"
|
||||||
success "admin.php deployed."
|
success "admin.php deployed."
|
||||||
|
|||||||
Reference in New Issue
Block a user