Files
Critters/session.php
T
pauljd 9805d5056d
pauljd/davidson-ci: Davidson CI / quality (push) Successful in 14s
pauljd/davidson-ci: Davidson CI / ai-review (push) Successful in 1m5s
issues identified by Davidson CI
2026-09-09 22:49:46 +01:00

59 lines
1.7 KiB
PHP

<?php
function send_app_csp_header(): void
{
if (headers_sent()) {
return;
}
header('Content-Security-Policy: ' . implode(' ', [
"script-src 'self' 'unsafe-inline' https://unpkg.com https://cdn.paddle.com;",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;",
"font-src https://fonts.gstatic.com;",
"img-src 'self' data:;",
"connect-src 'self' https://cdn.paddle.com https://api.paddle.com https://sandbox-api.paddle.com;",
"frame-src https://buy.paddle.com https://sandbox-buy.paddle.com;",
"object-src 'none';",
"base-uri 'self';",
"frame-ancestors 'none';",
]), true, 0);
}
function start_app_session(): void
{
send_app_csp_header();
if (session_status() === PHP_SESSION_ACTIVE) {
return;
}
$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https')
|| (($_SERVER['SERVER_PORT'] ?? '') === '443');
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => $isHttps,
'httponly' => true,
'samesite' => 'Strict',
]);
session_start();
}
function csrf_token(): string
{
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function csrf_field(): string
{
return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars(csrf_token(), ENT_QUOTES, 'UTF-8') . '">';
}
function csrf_verify(?string $token): bool
{
return is_string($token) && $token !== '' && isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}