Adds tests for middleware
parent
c2f63f6121
commit
5327bde032
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require_once __DIR__ . '/../helpers/security.php';
|
require_once __DIR__ . '/../helpers/security.php';
|
||||||
|
|
||||||
function verifyCsrfToken() {
|
function applyCsrfMiddleware() {
|
||||||
$security = SecurityHelper::getInstance();
|
$security = SecurityHelper::getInstance();
|
||||||
|
|
||||||
// Skip CSRF check for GET requests
|
// Skip CSRF check for GET requests
|
||||||
|
|
|
@ -11,6 +11,7 @@ require_once __DIR__ . '/../classes/ratelimiter.php';
|
||||||
* @return bool True if request is allowed, false if rate limited
|
* @return bool True if request is allowed, false if rate limited
|
||||||
*/
|
*/
|
||||||
function checkRateLimit($database, $endpoint, $userId = null) {
|
function checkRateLimit($database, $endpoint, $userId = null) {
|
||||||
|
$isTest = defined('PHPUNIT_RUNNING');
|
||||||
$rateLimiter = new RateLimiter($database['db']);
|
$rateLimiter = new RateLimiter($database['db']);
|
||||||
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||||
|
|
||||||
|
@ -19,28 +20,34 @@ function checkRateLimit($database, $endpoint, $userId = null) {
|
||||||
// Get remaining requests for error message
|
// Get remaining requests for error message
|
||||||
$remaining = $rateLimiter->getRemainingPageRequests($ipAddress, $endpoint, $userId);
|
$remaining = $rateLimiter->getRemainingPageRequests($ipAddress, $endpoint, $userId);
|
||||||
|
|
||||||
// Set rate limit headers
|
if (!$isTest) {
|
||||||
header('X-RateLimit-Remaining: ' . $remaining);
|
// Set rate limit headers
|
||||||
header('X-RateLimit-Reset: ' . (time() + 60)); // Reset in 1 minute
|
header('X-RateLimit-Remaining: ' . $remaining);
|
||||||
|
header('X-RateLimit-Reset: ' . (time() + 60)); // Reset in 1 minute
|
||||||
|
|
||||||
// Return 429 Too Many Requests
|
// Return 429 Too Many Requests
|
||||||
http_response_code(429);
|
http_response_code(429);
|
||||||
|
|
||||||
// If AJAX request, return JSON
|
// If AJAX request, return JSON
|
||||||
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
||||||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
|
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => 'Too many requests. Please try again in a minute.',
|
'message' => 'Too many requests. Please try again in a minute.',
|
||||||
'messageData' => Feedback::getMessageData('ERROR', 'DEFAULT', 'Too many requests. Please try again in a minute.', true)
|
'messageData' => Feedback::getMessageData('ERROR', 'DEFAULT', 'Too many requests. Please try again in a minute.', true)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// For regular requests, set flash message and redirect
|
// For regular requests, set flash message and redirect
|
||||||
Feedback::flash('ERROR', 'DEFAULT', 'Too many requests. Please try again in a minute.', true);
|
Feedback::flash('ERROR', 'DEFAULT', 'Too many requests. Please try again in a minute.', true);
|
||||||
header('Location: ' . htmlspecialchars($app_root));
|
header('Location: ' . htmlspecialchars($app_root));
|
||||||
|
}
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
exit;
|
|
||||||
|
// In test mode, just set the flash message
|
||||||
|
Feedback::flash('ERROR', 'DEFAULT', 'Too many requests. Please try again in a minute.', true);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record this request
|
// Record this request
|
||||||
|
|
|
@ -7,43 +7,86 @@
|
||||||
* This middleware should be included in all protected pages.
|
* This middleware should be included in all protected pages.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Start session if not already started
|
function applySessionMiddleware($config, $app_root) {
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
$isTest = defined('PHPUNIT_RUNNING');
|
||||||
session_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user is logged in
|
// Access $_SESSION directly in test mode
|
||||||
if (!isset($_SESSION['USER_ID'])) {
|
if (!$isTest) {
|
||||||
header('Location: ' . $app_root . '?page=login');
|
// Start session if not already started
|
||||||
exit();
|
if (session_status() !== PHP_SESSION_ACTIVE && !headers_sent()) {
|
||||||
}
|
session_start([
|
||||||
|
'cookie_httponly' => 1,
|
||||||
|
'cookie_secure' => 1,
|
||||||
|
'cookie_samesite' => 'Strict',
|
||||||
|
'gc_maxlifetime' => 1440 // 24 minutes
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check session timeout
|
// Check if user is logged in
|
||||||
$session_timeout = isset($_SESSION['REMEMBER_ME']) ? (30 * 24 * 60 * 60) : 1440; // 30 days or 24 minutes
|
if (!isset($_SESSION['USER_ID'])) {
|
||||||
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $session_timeout)) {
|
if (!$isTest) {
|
||||||
// Session has expired
|
header('Location: ' . $app_root . '?page=login');
|
||||||
session_unset();
|
exit();
|
||||||
session_destroy();
|
}
|
||||||
setcookie('username', '', [
|
return false;
|
||||||
'expires' => time() - 3600,
|
}
|
||||||
'path' => $config['folder'],
|
|
||||||
'domain' => $config['domain'],
|
|
||||||
'secure' => isset($_SERVER['HTTPS']),
|
|
||||||
'httponly' => true,
|
|
||||||
'samesite' => 'Strict'
|
|
||||||
]);
|
|
||||||
header('Location: ' . $app_root . '?page=login&timeout=1');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update last activity time
|
// Check session timeout
|
||||||
$_SESSION['LAST_ACTIVITY'] = time();
|
$session_timeout = isset($_SESSION['REMEMBER_ME']) ? (30 * 24 * 60 * 60) : 1440; // 30 days or 24 minutes
|
||||||
|
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $session_timeout)) {
|
||||||
|
// Session has expired
|
||||||
|
$oldSessionData = $_SESSION;
|
||||||
|
$_SESSION = array();
|
||||||
|
|
||||||
// Regenerate session ID periodically (every 30 minutes)
|
if (!$isTest && session_status() === PHP_SESSION_ACTIVE) {
|
||||||
if (!isset($_SESSION['CREATED'])) {
|
session_unset();
|
||||||
$_SESSION['CREATED'] = time();
|
session_destroy();
|
||||||
} else if (time() - $_SESSION['CREATED'] > 1800) {
|
|
||||||
// Regenerate session ID and update creation time
|
// Start a new session to prevent errors
|
||||||
session_regenerate_id(true);
|
if (!headers_sent()) {
|
||||||
$_SESSION['CREATED'] = time();
|
session_start([
|
||||||
|
'cookie_httponly' => 1,
|
||||||
|
'cookie_secure' => 1,
|
||||||
|
'cookie_samesite' => 'Strict',
|
||||||
|
'gc_maxlifetime' => 1440
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isTest && !headers_sent()) {
|
||||||
|
setcookie('username', '', [
|
||||||
|
'expires' => time() - 3600,
|
||||||
|
'path' => $config['folder'],
|
||||||
|
'domain' => $config['domain'],
|
||||||
|
'secure' => isset($_SERVER['HTTPS']),
|
||||||
|
'httponly' => true,
|
||||||
|
'samesite' => 'Strict'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isTest) {
|
||||||
|
header('Location: ' . $app_root . '?page=login&timeout=1');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update last activity time
|
||||||
|
$_SESSION['LAST_ACTIVITY'] = time();
|
||||||
|
|
||||||
|
// Regenerate session ID periodically (every 30 minutes)
|
||||||
|
if (!isset($_SESSION['CREATED'])) {
|
||||||
|
$_SESSION['CREATED'] = time();
|
||||||
|
} else if (time() - $_SESSION['CREATED'] > 1800) {
|
||||||
|
// Regenerate session ID and update creation time
|
||||||
|
if (!$isTest && !headers_sent() && session_status() === PHP_SESSION_ACTIVE) {
|
||||||
|
$oldData = $_SESSION;
|
||||||
|
session_regenerate_id(true);
|
||||||
|
$_SESSION = $oldData;
|
||||||
|
$_SESSION['CREATED'] = time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once dirname(__DIR__, 4) . '/app/classes/database.php';
|
||||||
|
require_once dirname(__DIR__, 4) . '/app/classes/ratelimiter.php';
|
||||||
|
require_once dirname(__DIR__, 4) . '/app/includes/rate_limit_middleware.php';
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class RateLimitMiddlewareTest extends TestCase
|
||||||
|
{
|
||||||
|
private $db;
|
||||||
|
private $rateLimiter;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Set up test database
|
||||||
|
$this->db = new Database([
|
||||||
|
'type' => 'sqlite',
|
||||||
|
'dbFile' => ':memory:'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create rate limiter table
|
||||||
|
$this->db->getConnection()->exec("CREATE TABLE pages_rate_limits (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip_address TEXT NOT NULL,
|
||||||
|
endpoint TEXT NOT NULL,
|
||||||
|
request_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)");
|
||||||
|
|
||||||
|
// Create ip_whitelist table
|
||||||
|
$this->db->getConnection()->exec("CREATE TABLE ip_whitelist (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip_address TEXT NOT NULL UNIQUE,
|
||||||
|
is_network BOOLEAN DEFAULT 0 CHECK(is_network IN (0,1)),
|
||||||
|
description TEXT,
|
||||||
|
created_at TEXT DEFAULT (DATETIME('now')),
|
||||||
|
created_by TEXT
|
||||||
|
)");
|
||||||
|
|
||||||
|
// Create ip_blacklist table
|
||||||
|
$this->db->getConnection()->exec("CREATE TABLE ip_blacklist (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip_address TEXT NOT NULL UNIQUE,
|
||||||
|
is_network BOOLEAN DEFAULT 0 CHECK(is_network IN (0,1)),
|
||||||
|
reason TEXT,
|
||||||
|
expiry_time TEXT NULL,
|
||||||
|
created_at TEXT DEFAULT (DATETIME('now')),
|
||||||
|
created_by TEXT
|
||||||
|
)");
|
||||||
|
|
||||||
|
$this->rateLimiter = new RateLimiter($this->db);
|
||||||
|
|
||||||
|
// Mock $_SERVER variables
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
$_SERVER['REQUEST_URI'] = '/login';
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||||
|
|
||||||
|
// Define testing constant
|
||||||
|
if (!defined('TESTING')) {
|
||||||
|
define('TESTING', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
// Clean up rate limit records
|
||||||
|
$this->db->getConnection()->exec('DELETE FROM pages_rate_limits');
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRateLimitMiddleware()
|
||||||
|
{
|
||||||
|
// Test multiple requests
|
||||||
|
for ($i = 1; $i <= 5; $i++) {
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
|
||||||
|
if ($i <= 5) {
|
||||||
|
// First 5 requests should pass
|
||||||
|
$this->assertTrue($result);
|
||||||
|
} else {
|
||||||
|
// 6th and subsequent requests should be blocked
|
||||||
|
$this->assertFalse($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRateLimitBypass()
|
||||||
|
{
|
||||||
|
// Test AJAX request bypass
|
||||||
|
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRateLimitReset()
|
||||||
|
{
|
||||||
|
// Use up the rate limit
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for rate limit to reset (use a short window for testing)
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
// Should be able to make request again
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDifferentEndpoints()
|
||||||
|
{
|
||||||
|
// Use up rate limit for login
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should still be able to access different endpoint
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/dashboard');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDifferentIpAddresses()
|
||||||
|
{
|
||||||
|
// Use up rate limit for first IP
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Different IP should not be affected
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.2';
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhitelistedIp()
|
||||||
|
{
|
||||||
|
// Add IP to whitelist
|
||||||
|
$this->db->execute(
|
||||||
|
'INSERT INTO ip_whitelist (ip_address, description, created_by) VALUES (?, ?, ?)',
|
||||||
|
['127.0.0.1', 'Test whitelist', 'PHPUnit']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should be able to make more requests than limit
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBlacklistedIp()
|
||||||
|
{
|
||||||
|
// Add IP to blacklist
|
||||||
|
$this->db->execute(
|
||||||
|
'INSERT INTO ip_blacklist (ip_address, reason, created_by) VALUES (?, ?, ?)',
|
||||||
|
['127.0.0.1', 'Test blacklist', 'PHPUnit']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should be blocked immediately
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertFalse($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRateLimitPersistence()
|
||||||
|
{
|
||||||
|
// Use up some of the rate limit
|
||||||
|
for ($i = 0; $i < 2; $i++) {
|
||||||
|
checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy and restart session
|
||||||
|
//session_destroy();
|
||||||
|
//session_start();
|
||||||
|
|
||||||
|
// Should still count previous requests
|
||||||
|
$result = checkRateLimit(['db' => $this->db], '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once dirname(__DIR__, 4) . '/app/includes/session_middleware.php';
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class SessionMiddlewareTest extends TestCase
|
||||||
|
{
|
||||||
|
protected $config;
|
||||||
|
protected $app_root;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Mock server variables
|
||||||
|
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit Test Browser';
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
||||||
|
// Set up test config
|
||||||
|
$this->config = [
|
||||||
|
'folder' => '/app',
|
||||||
|
'domain' => 'localhost'
|
||||||
|
];
|
||||||
|
$this->app_root = 'https://localhost/app';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSessionStart()
|
||||||
|
{
|
||||||
|
$_SESSION = ['USER_ID' => 1];
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertTrue($result);
|
||||||
|
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
||||||
|
$this->assertArrayHasKey('CREATED', $_SESSION);
|
||||||
|
$this->assertArrayHasKey('USER_ID', $_SESSION);
|
||||||
|
$this->assertEquals(1, $_SESSION['USER_ID']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSessionTimeout()
|
||||||
|
{
|
||||||
|
$_SESSION = [
|
||||||
|
'USER_ID' => 1,
|
||||||
|
'LAST_ACTIVITY' => time() - 1500 // 25 minutes ago
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertFalse($result);
|
||||||
|
$this->assertArrayNotHasKey('USER_ID', $_SESSION, 'Session should be cleared after timeout');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSessionRegeneration()
|
||||||
|
{
|
||||||
|
$now = time();
|
||||||
|
$_SESSION = [
|
||||||
|
'USER_ID' => 1,
|
||||||
|
'CREATED' => $now - 1900 // 31+ minutes ago
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertTrue($result);
|
||||||
|
$this->assertEquals(1, $_SESSION['USER_ID']);
|
||||||
|
$this->assertGreaterThanOrEqual($now - 1900, $_SESSION['CREATED']);
|
||||||
|
$this->assertLessThanOrEqual($now + 10, $_SESSION['CREATED']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRememberMe()
|
||||||
|
{
|
||||||
|
$_SESSION = [
|
||||||
|
'USER_ID' => 1,
|
||||||
|
'REMEMBER_ME' => true,
|
||||||
|
'LAST_ACTIVITY' => time() - 86500 // More than 24 hours ago
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertTrue($result);
|
||||||
|
$this->assertArrayHasKey('USER_ID', $_SESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoUserSession()
|
||||||
|
{
|
||||||
|
$_SESSION = [];
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertFalse($result);
|
||||||
|
$this->assertArrayNotHasKey('USER_ID', $_SESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSessionHeaders()
|
||||||
|
{
|
||||||
|
$_SESSION = [
|
||||||
|
'USER_ID' => 1,
|
||||||
|
'LAST_ACTIVITY' => time() - 1500 // 25 minutes ago
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = applySessionMiddleware($this->config, $this->app_root);
|
||||||
|
|
||||||
|
$this->assertFalse($result);
|
||||||
|
$this->assertArrayNotHasKey('USER_ID', $_SESSION, 'Session should be cleared after timeout');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Session Handler
|
||||||
|
*
|
||||||
|
* Provides session handling functionality for PHPUnit tests.
|
||||||
|
* This class ensures proper session management during testing.
|
||||||
|
*/
|
||||||
|
class TestSessionHandler implements SessionHandlerInterface
|
||||||
|
{
|
||||||
|
private static $initialized = false;
|
||||||
|
private $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize session settings
|
||||||
|
*/
|
||||||
|
public static function init()
|
||||||
|
{
|
||||||
|
if (!self::$initialized && !headers_sent()) {
|
||||||
|
// Clean up any existing session
|
||||||
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||||
|
session_write_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_COOKIE[session_name()])) {
|
||||||
|
setcookie(session_name(), '', time()-3600, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION = array();
|
||||||
|
|
||||||
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||||
|
session_destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set session configuration
|
||||||
|
session_name('jilo');
|
||||||
|
|
||||||
|
// Start a new session
|
||||||
|
if (session_status() !== PHP_SESSION_ACTIVE) {
|
||||||
|
session_start([
|
||||||
|
'cookie_httponly' => 1,
|
||||||
|
'cookie_secure' => 1,
|
||||||
|
'cookie_samesite' => 'Strict',
|
||||||
|
'gc_maxlifetime' => 1440 // 24 minutes
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a fresh session
|
||||||
|
*/
|
||||||
|
public static function startSession()
|
||||||
|
{
|
||||||
|
// Clean up any existing session first
|
||||||
|
self::cleanupSession();
|
||||||
|
|
||||||
|
// Initialize new session
|
||||||
|
if (session_status() !== PHP_SESSION_ACTIVE && !headers_sent()) {
|
||||||
|
session_name('jilo');
|
||||||
|
session_start([
|
||||||
|
'cookie_httponly' => 1,
|
||||||
|
'cookie_secure' => 1,
|
||||||
|
'cookie_samesite' => 'Strict',
|
||||||
|
'gc_maxlifetime' => 1440
|
||||||
|
]);
|
||||||
|
self::$initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up the current session
|
||||||
|
*/
|
||||||
|
public static function cleanupSession()
|
||||||
|
{
|
||||||
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||||
|
session_write_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_COOKIE[session_name()])) {
|
||||||
|
setcookie(session_name(), '', time()-3600, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION = array();
|
||||||
|
|
||||||
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||||
|
session_destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function open($path, $name): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($id): string|false
|
||||||
|
{
|
||||||
|
return $this->data[$id] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($id, $data): bool
|
||||||
|
{
|
||||||
|
$this->data[$id] = $data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id): bool
|
||||||
|
{
|
||||||
|
unset($this->data[$id]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gc($max_lifetime): int|false
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,18 +3,14 @@
|
||||||
// Set test environment
|
// Set test environment
|
||||||
define('PHPUNIT_RUNNING', true);
|
define('PHPUNIT_RUNNING', true);
|
||||||
|
|
||||||
// Configure session before starting it
|
// Configure session before any output
|
||||||
ini_set('session.use_strict_mode', '1');
|
if (!headers_sent()) {
|
||||||
ini_set('session.use_only_cookies', '1');
|
// Configure session settings
|
||||||
ini_set('session.cookie_httponly', '1');
|
ini_set('session.cookie_httponly', 1);
|
||||||
ini_set('session.cookie_secure', '1');
|
ini_set('session.cookie_secure', 1);
|
||||||
ini_set('session.cookie_samesite', 'Lax');
|
ini_set('session.cookie_samesite', 'Strict');
|
||||||
ini_set('session.gc_maxlifetime', 1440);
|
ini_set('session.gc_maxlifetime', 1440); // 24 minutes
|
||||||
|
}
|
||||||
// Start session if not already started
|
|
||||||
//if (session_status() === PHP_SESSION_NONE) {
|
|
||||||
// session_start();
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Load Composer's autoloader
|
// Load Composer's autoloader
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
@ -33,26 +29,9 @@ $GLOBALS['config'] = [
|
||||||
'db' => [
|
'db' => [
|
||||||
'type' => 'sqlite',
|
'type' => 'sqlite',
|
||||||
'dbFile' => ':memory:'
|
'dbFile' => ':memory:'
|
||||||
],
|
|
||||||
'folder' => '/',
|
|
||||||
'domain' => 'localhost',
|
|
||||||
'login' => [
|
|
||||||
'max_attempts' => 5,
|
|
||||||
'lockout_time' => 900
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Initialize system_messages array
|
|
||||||
$GLOBALS['system_messages'] = [];
|
|
||||||
|
|
||||||
// Set up server variables
|
|
||||||
$_SERVER['PHP_SELF'] = '/index.php';
|
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
|
||||||
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit Test Browser';
|
|
||||||
$_SERVER['HTTP_HOST'] = 'localhost';
|
|
||||||
$_SERVER['REQUEST_URI'] = '/?page=login';
|
|
||||||
$_SERVER['HTTPS'] = 'on';
|
|
||||||
|
|
||||||
// Define global connectDB function
|
// Define global connectDB function
|
||||||
if (!function_exists('connectDB')) {
|
if (!function_exists('connectDB')) {
|
||||||
function connectDB($config) {
|
function connectDB($config) {
|
||||||
|
@ -62,3 +41,9 @@ if (!function_exists('connectDB')) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up server variables
|
||||||
|
$_SERVER['PHP_SELF'] = '/index.php';
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit Test Browser';
|
||||||
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[Session]
|
||||||
|
session.cookie_httponly = 1
|
||||||
|
session.use_only_cookies = 1
|
||||||
|
session.cookie_secure = 1
|
||||||
|
session.cookie_samesite = "Strict"
|
||||||
|
session.gc_maxlifetime = 1440
|
||||||
|
session.use_strict_mode = 1
|
Loading…
Reference in New Issue