strtotime('+1 year'), 'path' => '/', 'domain' => '.xxx.org.za', 'secure' => TRUE, 'httponly' => TRUE, 'samesite' => 'Lax')); session_start(); if (isset($_SESSION['editor'])) { $is_admin = TRUE; $username = $_SESSION['editor']; } elseif (check_persistent_login()) { // Note that check_persistent_login() sets $_SESSION['editor'] $is_admin = TRUE; $username = $_SESSION['editor']; } else { $is_admin = FALSE; } // Don't cache if $is_admin is set header( 'Cache-Control: no-store, no-cache, must-revalidate' ); header( 'Cache-Control: post-check=0, pre-check=0', false ); header( 'Pragma: no-cache' ); } function check_persistent_login() { if (!array_key_exists('PersistentAuth', $_COOKIE)) { return false; } global $db, $is_admin; $table = "persistent_sessions"; open_db('open'); $cookie_data = (string)$_COOKIE['PersistentAuth']; list($username, $key) = explode("|", $cookie_data, 2) + array('', ''); $query = "SELECT * FROM $table WHERE username LIKE ? LIMIT 1"; $getid = $db->execute_query($query, array($username)) or die("Query failed: ".$db->error); $row = $getid->fetch_assoc(); open_db('close'); if (isset($row)) { // Set up session, and delete old cookie, and create new persistent cookie $stored_session = $row['session']; if ($stored_session == $key) { // login login_editor($username); // delete cookie delete_persistent_login(); // create new cookie create_persistent_login($username); return true; } return false; } return false; } function create_persistent_login($username) { $validity = strtotime('+1 year'); // Time to keep the session valid global $db, $is_admin; $table = "persistent_sessions"; open_db('open'); $key = bin2hex(random_bytes(100)); // Add session key to database $query = "INSERT INTO $table (username, session) VALUES (?, ?)"; $db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error); open_db('close'); // Create cookie with key setcookie('PersistentAuth', "$username|$key", array('expires' => $validity, 'path' => '/', 'domain' => '.xxx.org.za', 'secure' => TRUE, 'httponly' => TRUE, 'samesite' => 'Lax')); return true; } function delete_persistent_login() { global $db, $is_admin; $table = "persistent_sessions"; open_db('open'); $cookie_data = (string)($_COOKIE['PersistentAuth'] ?? ''); list($username, $key) = explode("|", $cookie_data, 2) + array('', ''); // Remove this session key from the database $query = "DELETE FROM $table WHERE username LIKE ? AND session LIKE ?"; $db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error); // Reap old sessions $query = "DELETE FROM $table " . " WHERE created < DATE_SUB(now(), INTERVAL 1 YEAR);"; $db->query($query) or die("Query failed: ".$db->error); open_db('close'); // Delete cookie setcookie("PersistentAuth", '', array('expires' => strtotime('-1 year'), 'path' => '/', 'domain' => '.xxx.org.za', 'secure' => TRUE, 'httponly' => TRUE, 'samesite' => 'Lax')); return true; } /* * CSRF protection: every form that changes something carries a random * token from the session, and the handler checks it before acting. */ function csrf_token() { if (empty($_SESSION['csrf_token']) || !is_string($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); return $_SESSION['csrf_token']; } function csrf_field() { return ''; } function csrf_valid($token = NULL) { if ($token === NULL) $token = $_POST['csrf_token'] ?? ''; return is_string($token) && isset($_SESSION['csrf_token']) && hash_equals((string)$_SESSION['csrf_token'], $token); } /* * Log an editor in under a new session id, so that a session id that * someone planted or saw before the login is of no use afterwards. */ function login_editor($username) { session_regenerate_id(TRUE); unset($_SESSION['csrf_token']); $_SESSION['editor'] = $username; }