Migrates app database from SQLite to MariaDB

main
Yasen Pramatarov 2025-04-25 12:10:29 +03:00
parent 630f71ce4d
commit 880c45025c
22 changed files with 191 additions and 172 deletions

View File

@ -2,15 +2,16 @@
class RateLimiter { class RateLimiter {
public $db; public $db;
private $database;
private $log; private $log;
public $maxAttempts = 5; // Maximum login attempts public $maxAttempts = 5; // Maximum login attempts
public $decayMinutes = 15; // Time window in minutes public $decayMinutes = 15; // Time window in minutes
public $autoBlacklistThreshold = 10; // Attempts before auto-blacklist public $autoBlacklistThreshold = 10; // Attempts before auto-blacklist
public $autoBlacklistDuration = 24; // Hours to blacklist for public $autoBlacklistDuration = 24; // Hours to blacklist for
public $authRatelimitTable = 'login_attempts'; // For username/password attempts public $authRatelimitTable = 'security_rate_auth'; // For rate limiting username/password attempts
public $pagesRatelimitTable = 'pages_rate_limits'; // For page requests public $pagesRatelimitTable = 'security_rate_page'; // For rate limiting page requests
public $whitelistTable = 'ip_whitelist'; public $whitelistTable = 'security_ip_whitelist'; // For whitelisting IPs and network ranges
public $blacklistTable = 'ip_blacklist'; public $blacklistTable = 'security_ip_blacklist'; // For blacklisting IPs and network ranges
private $pageLimits = [ private $pageLimits = [
// Default rate limits per minute // Default rate limits per minute
'default' => 60, 'default' => 60,
@ -23,11 +24,8 @@ class RateLimiter {
]; ];
public function __construct($database) { public function __construct($database) {
if ($database instanceof PDO) { $this->database = $database; // Store the Database object
$this->db = $database; $this->db = $database->getConnection();
} else {
$this->db = $database->getConnection();
}
// Initialize logger via Log wrapper // Initialize logger via Log wrapper
require_once __DIR__ . '/log.php'; require_once __DIR__ . '/log.php';
$this->log = new Log($database); $this->log = new Log($database);
@ -39,42 +37,47 @@ class RateLimiter {
private function createTablesIfNotExist() { private function createTablesIfNotExist() {
// Authentication attempts table // Authentication attempts table
$sql = "CREATE TABLE IF NOT EXISTS {$this->authRatelimitTable} ( $sql = "CREATE TABLE IF NOT EXISTS {$this->authRatelimitTable} (
id INTEGER PRIMARY KEY AUTOINCREMENT, id int(11) PRIMARY KEY AUTO_INCREMENT,
ip_address TEXT NOT NULL, ip_address VARCHAR(45) NOT NULL,
username TEXT NOT NULL, username VARCHAR(255) NOT NULL,
attempted_at TEXT DEFAULT (DATETIME('now')) attempted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_ip_username (ip_address, username)
)"; )";
$this->db->exec($sql); $this->db->exec($sql);
// Pages rate limits table // Pages rate limits table
$sql = "CREATE TABLE IF NOT EXISTS {$this->pagesRatelimitTable} ( $sql = "CREATE TABLE IF NOT EXISTS {$this->pagesRatelimitTable} (
id INTEGER PRIMARY KEY AUTOINCREMENT, id int(11) PRIMARY KEY AUTO_INCREMENT,
ip_address TEXT NOT NULL, ip_address VARCHAR(45) NOT NULL,
endpoint TEXT NOT NULL, endpoint VARCHAR(255) NOT NULL,
request_time DATETIME DEFAULT CURRENT_TIMESTAMP request_time DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_ip_endpoint (ip_address, endpoint),
INDEX idx_request_time (request_time)
)"; )";
$this->db->exec($sql); $this->db->exec($sql);
// IP whitelist table // IP whitelist table
$sql = "CREATE TABLE IF NOT EXISTS {$this->whitelistTable} ( $sql = "CREATE TABLE IF NOT EXISTS {$this->whitelistTable} (
id INTEGER PRIMARY KEY AUTOINCREMENT, id int(11) PRIMARY KEY AUTO_INCREMENT,
ip_address TEXT NOT NULL UNIQUE, ip_address VARCHAR(45) NOT NULL,
is_network BOOLEAN DEFAULT 0 CHECK(is_network IN (0,1)), is_network BOOLEAN DEFAULT FALSE,
description TEXT, description VARCHAR(255),
created_at TEXT DEFAULT (DATETIME('now')), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by TEXT created_by VARCHAR(255),
UNIQUE KEY unique_ip (ip_address)
)"; )";
$this->db->exec($sql); $this->db->exec($sql);
// IP blacklist table // IP blacklist table
$sql = "CREATE TABLE IF NOT EXISTS {$this->blacklistTable} ( $sql = "CREATE TABLE IF NOT EXISTS {$this->blacklistTable} (
id INTEGER PRIMARY KEY AUTOINCREMENT, id int(11) PRIMARY KEY AUTO_INCREMENT,
ip_address TEXT NOT NULL UNIQUE, ip_address VARCHAR(45) NOT NULL,
is_network BOOLEAN DEFAULT 0 CHECK(is_network IN (0,1)), is_network BOOLEAN DEFAULT FALSE,
reason TEXT, reason VARCHAR(255),
expiry_time TEXT NULL, expiry_time TIMESTAMP NULL,
created_at TEXT DEFAULT (DATETIME('now')), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by TEXT created_by VARCHAR(255),
UNIQUE KEY unique_ip (ip_address)
)"; )";
$this->db->exec($sql); $this->db->exec($sql);
@ -88,7 +91,7 @@ class RateLimiter {
]; ];
// Insert default whitelisted IPs if they don't exist // Insert default whitelisted IPs if they don't exist
$stmt = $this->db->prepare("INSERT OR IGNORE INTO {$this->whitelistTable} $stmt = $this->db->prepare("INSERT IGNORE INTO {$this->whitelistTable}
(ip_address, is_network, description, created_by) (ip_address, is_network, description, created_by)
VALUES (?, ?, ?, 'system')"); VALUES (?, ?, ?, 'system')");
foreach ($defaultIps as $ip) { foreach ($defaultIps as $ip) {
@ -104,7 +107,7 @@ class RateLimiter {
['203.0.113.0/24', true, 'TEST-NET-3 Documentation space - RFC 5737'] ['203.0.113.0/24', true, 'TEST-NET-3 Documentation space - RFC 5737']
]; ];
$stmt = $this->db->prepare("INSERT OR IGNORE INTO {$this->blacklistTable} $stmt = $this->db->prepare("INSERT IGNORE INTO {$this->blacklistTable}
(ip_address, is_network, reason, created_by) (ip_address, is_network, reason, created_by)
VALUES (?, ?, ?, 'system')"); VALUES (?, ?, ?, 'system')");
@ -119,7 +122,7 @@ class RateLimiter {
*/ */
public function getRecentAttempts($ip) { public function getRecentAttempts($ip) {
$stmt = $this->db->prepare("SELECT COUNT(*) as attempts FROM {$this->authRatelimitTable} $stmt = $this->db->prepare("SELECT COUNT(*) as attempts FROM {$this->authRatelimitTable}
WHERE ip_address = ? AND attempted_at > datetime('now', '-' || :minutes || ' minutes')"); WHERE ip_address = ? AND attempted_at > DATE_SUB(NOW(), INTERVAL ? MINUTE)");
$stmt->execute([$ip, $this->decayMinutes]); $stmt->execute([$ip, $this->decayMinutes]);
$result = $stmt->fetch(PDO::FETCH_ASSOC); $result = $stmt->fetch(PDO::FETCH_ASSOC);
return intval($result['attempts']); return intval($result['attempts']);
@ -222,9 +225,13 @@ class RateLimiter {
return false; return false;
} }
$stmt = $this->db->prepare("INSERT OR REPLACE INTO {$this->whitelistTable} $stmt = $this->db->prepare("INSERT INTO {$this->whitelistTable}
(ip_address, is_network, description, created_by) (ip_address, is_network, description, created_by)
VALUES (?, ?, ?, ?)"); VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
is_network = VALUES(is_network),
description = VALUES(description),
created_by = VALUES(created_by)");
$result = $stmt->execute([$ip, $isNetwork, $description, $createdBy]); $result = $stmt->execute([$ip, $isNetwork, $description, $createdBy]);
@ -236,7 +243,7 @@ class RateLimiter {
$createdBy, $createdBy,
$description $description
); );
$this->log->insertLog($userId ?? 0, $logMessage, 'system'); $this->log->insertLog($userId ?? null, $logMessage, 'system');
} }
return $result; return $result;
@ -271,7 +278,7 @@ class RateLimiter {
$removedBy, $removedBy,
$ipDetails['created_by'] $ipDetails['created_by']
); );
$this->log->insertLog($userId ?? 0, $logMessage, 'system'); $this->log->insertLog($userId ?? null, $logMessage, 'system');
} }
return $result; return $result;
@ -299,9 +306,14 @@ class RateLimiter {
$expiryTime = $expiryHours ? date('Y-m-d H:i:s', strtotime("+{$expiryHours} hours")) : null; $expiryTime = $expiryHours ? date('Y-m-d H:i:s', strtotime("+{$expiryHours} hours")) : null;
$stmt = $this->db->prepare("INSERT OR REPLACE INTO {$this->blacklistTable} $stmt = $this->db->prepare("INSERT INTO {$this->blacklistTable}
(ip_address, is_network, reason, expiry_time, created_by) (ip_address, is_network, reason, expiry_time, created_by)
VALUES (?, ?, ?, ?, ?)"); VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
is_network = VALUES(is_network),
reason = VALUES(reason),
expiry_time = VALUES(expiry_time),
created_by = VALUES(created_by)");
$result = $stmt->execute([$ip, $isNetwork, $reason, $expiryTime, $createdBy]); $result = $stmt->execute([$ip, $isNetwork, $reason, $expiryTime, $createdBy]);
@ -314,7 +326,7 @@ class RateLimiter {
$reason, $reason,
$expiryTime ?? 'never' $expiryTime ?? 'never'
); );
$this->log->insertLog($userId ?? 0, $logMessage, 'system'); $this->log->insertLog($userId ?? null, $logMessage, 'system');
} }
return $result; return $result;
@ -348,7 +360,7 @@ class RateLimiter {
$ipDetails['created_by'], $ipDetails['created_by'],
$ipDetails['reason'] $ipDetails['reason']
); );
$this->log->insertLog($userId ?? 0, $logMessage, 'system'); $this->log->insertLog($userId ?? null, $logMessage, 'system');
} }
return $result; return $result;
@ -379,17 +391,17 @@ class RateLimiter {
try { try {
// Remove expired blacklist entries // Remove expired blacklist entries
$stmt = $this->db->prepare("DELETE FROM {$this->blacklistTable} $stmt = $this->db->prepare("DELETE FROM {$this->blacklistTable}
WHERE expiry_time IS NOT NULL AND expiry_time < datetime('now')"); WHERE expiry_time IS NOT NULL AND expiry_time < NOW()");
$stmt->execute(); $stmt->execute();
// Clean old login attempts // Clean old login attempts
$stmt = $this->db->prepare("DELETE FROM {$this->authRatelimitTable} $stmt = $this->db->prepare("DELETE FROM {$this->authRatelimitTable}
WHERE attempted_at < datetime('now', '-' || :minutes || ' minutes')"); WHERE attempted_at < DATE_SUB(NOW(), INTERVAL :minutes MINUTE)");
$stmt->execute([':minutes' => $this->decayMinutes]); $stmt->execute([':minutes' => $this->decayMinutes]);
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
$this->log->insertLog(0, "Failed to cleanup expired entries: " . $e->getMessage(), 'system'); $this->log->insertLog(null, "Failed to cleanup expired entries: " . $e->getMessage(), 'system');
Feedback::flash('ERROR', 'DEFAULT', "Failed to cleanup expired entries: " . $e->getMessage()); Feedback::flash('ERROR', 'DEFAULT', "Failed to cleanup expired entries: " . $e->getMessage());
return false; return false;
} }
@ -418,7 +430,7 @@ class RateLimiter {
$sql = "SELECT COUNT(*) as total_attempts $sql = "SELECT COUNT(*) as total_attempts
FROM {$this->authRatelimitTable} FROM {$this->authRatelimitTable}
WHERE ip_address = :ip WHERE ip_address = :ip
AND attempted_at > datetime('now', '-' || :minutes || ' minutes')"; AND attempted_at > DATE_SUB(NOW(), INTERVAL :minutes MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([
':ip' => $ipAddress, ':ip' => $ipAddress,
@ -456,7 +468,7 @@ class RateLimiter {
FROM {$this->authRatelimitTable} FROM {$this->authRatelimitTable}
WHERE ip_address = :ip WHERE ip_address = :ip
AND username = :username AND username = :username
AND attempted_at > datetime('now', '-' || :minutes || ' minutes')"; AND attempted_at > DATE_SUB(NOW(), INTERVAL :minutes MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([
@ -492,7 +504,7 @@ class RateLimiter {
public function clearOldAttempts() { public function clearOldAttempts() {
$sql = "DELETE FROM {$this->authRatelimitTable} $sql = "DELETE FROM {$this->authRatelimitTable}
WHERE attempted_at < datetime('now', '-' || :minutes || ' minutes')"; WHERE attempted_at < DATE_SUB(NOW(), INTERVAL :minutes MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([
@ -505,7 +517,7 @@ class RateLimiter {
FROM {$this->authRatelimitTable} FROM {$this->authRatelimitTable}
WHERE ip_address = :ip WHERE ip_address = :ip
AND username = :username AND username = :username
AND attempted_at > datetime('now', '-' || :minutes || ' minutes')"; AND attempted_at > DATE_SUB(NOW(), INTERVAL :minutes MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([
@ -547,7 +559,7 @@ class RateLimiter {
FROM {$this->pagesRatelimitTable} FROM {$this->pagesRatelimitTable}
WHERE ip_address = :ip WHERE ip_address = :ip
AND endpoint = :endpoint AND endpoint = :endpoint
AND request_time >= DATETIME('now', '-1 minute')"; AND request_time >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([
@ -578,7 +590,7 @@ class RateLimiter {
*/ */
private function cleanOldPageRequests() { private function cleanOldPageRequests() {
$sql = "DELETE FROM {$this->pagesRatelimitTable} $sql = "DELETE FROM {$this->pagesRatelimitTable}
WHERE request_time < DATETIME('now', '-1 minute')"; WHERE request_time < DATE_SUB(NOW(), INTERVAL 1 MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute(); $stmt->execute();
@ -590,8 +602,10 @@ class RateLimiter {
private function getPageLimitForEndpoint($endpoint, $userId = null) { private function getPageLimitForEndpoint($endpoint, $userId = null) {
// Admin users get higher limits // Admin users get higher limits
if ($userId) { if ($userId) {
$userObj = new User($this->db); // Check admin rights directly from database
if ($userObj->hasRight($userId, 'admin')) { $stmt = $this->db->prepare('SELECT COUNT(*) FROM `user_right` ur JOIN `right` r ON ur.right_id = r.id WHERE ur.user_id = ? AND r.name = ?');
$stmt->execute([$userId, 'superuser']);
if ($stmt->fetchColumn() > 0) {
return $this->pageLimits['admin']; return $this->pageLimits['admin'];
} }
} }
@ -627,7 +641,7 @@ class RateLimiter {
FROM {$this->pagesRatelimitTable} FROM {$this->pagesRatelimitTable}
WHERE ip_address = :ip WHERE ip_address = :ip
AND endpoint = :endpoint AND endpoint = :endpoint
AND request_time > DATETIME('now', '-1 minute')"; AND request_time > DATE_SUB(NOW(), INTERVAL 1 MINUTE)";
$stmt = $this->db->prepare($sql); $stmt = $this->db->prepare($sql);
$stmt->execute([ $stmt->execute([

View File

@ -22,12 +22,20 @@ return [
//******************************************* //*******************************************
// database // database
'db' => [ 'db_type' => 'mariadb',
// DB type for the web app, currently only "sqlite" is used
'db_type' => 'sqlite', 'sqlite' => [
// default is ../app/jilo-web.db
'sqlite_file' => '../app/jilo-web.db', 'sqlite_file' => '../app/jilo-web.db',
], ],
'sql' => [
'sql_host' => 'localhost',
'sql_port' => '3306',
'sql_database' => 'jilo',
'sql_username' => 'jilouser',
'sql_password' => 'jilopass',
],
// avatars path // avatars path
'avatars_path' => 'uploads/avatars/', 'avatars_path' => 'uploads/avatars/',
// default avatar // default avatar

View File

@ -21,10 +21,10 @@ class DatabaseConnector
try { try {
$db = connectDB($config); $db = connectDB($config);
if (!$db['db']) { if (!$db) {
throw new Exception('Could not connect to database'); throw new Exception('Could not connect to database');
} }
return $db['db']; return $db;
} catch (Exception $e) { } catch (Exception $e) {
// Show error and exit // Show error and exit
Feedback::flash('ERROR', 'DEFAULT', getError('Error connecting to the database.', $e->getMessage())); Feedback::flash('ERROR', 'DEFAULT', getError('Error connecting to the database.', $e->getMessage()));

View File

@ -1,61 +1,63 @@
<?php <?php
// connect to database // connect to database
function connectDB($config, $database = '', $dbFile = '', $platformId = '') { function connectDB($config) {
// sqlite database file
// connecting ti a jilo sqlite database if ($config['db_type'] === 'sqlite') {
if ($database === 'jilo') {
try { try {
$dbFile = $config['sqlite']['sqlite_file'] ?? null;
if (!$dbFile || !file_exists($dbFile)) { if (!$dbFile || !file_exists($dbFile)) {
throw new Exception(getError("Invalid platform ID \"{$platformId}\", database file \"{$dbFile}\" not found.")); throw new Exception(getError("Database file \"{$dbFile}\"not found."));
} }
$db = new Database([ $db = new Database([
'type' => 'sqlite', 'type' => $config['db_type'],
'dbFile' => $dbFile, 'dbFile' => $dbFile,
]); ]);
return ['db' => $db, 'error' => null]; $pdo = $db->getConnection();
} catch (Exception $e) { } catch (Exception $e) {
return ['db' => null, 'error' => getError('Error connecting to DB.', $e->getMessage())]; Feedback::flash('ERROR', 'DEFAULT', getError('Error connecting to DB.', $e->getMessage()));
return false;
} }
return $db;
// connecting to a jilo-web database of the web app // mysql/mariadb database
} elseif ($config['db_type'] === 'mysql' || $config['db_type'] === 'mariadb') {
$db = new Database([
'type' => $config['db_type'],
'host' => $config['sql']['sql_host'] ?? 'localhost',
'port' => $config['sql']['sql_port'] ?? '3306',
'dbname' => $config['sql']['sql_database'],
'user' => $config['sql']['sql_username'],
'password' => $config['sql']['sql_password'],
]);
try {
$pdo = $db->getConnection();
} catch (Exception $e) {
Feedback::flash('ERROR', 'DEFAULT', getError('Error connecting to DB.', $e->getMessage()));
return false;
}
return $db;
// unknown database
} else { } else {
Feedback::flash('ERROR', 'DEFAULT', getError("Error: unknown database type \"{$config['db_type']}\""));
// sqlite database file return false;
if ($config['db']['db_type'] === 'sqlite') {
try {
$db = new Database([
'type' => $config['db']['db_type'],
'dbFile' => $config['db']['sqlite_file'],
]);
$pdo = $db->getConnection();
return ['db' => $db, 'error' => null];
} catch (Exception $e) {
return ['db' => null, 'error' => getError('Error connecting to DB.', $e->getMessage())];
}
// mysql/mariadb database
} elseif ($config['db']['db_type'] === 'mysql' || $config['db']['db_type'] === 'mariadb') {
try {
$db = new Database([
'type' => $config['db']['db_type'],
'host' => $config['db']['sql_host'] ?? 'localhost',
'port' => $config['db']['sql_port'] ?? '3306',
'dbname' => $config['db']['sql_database'],
'user' => $config['db']['sql_username'],
'password' => $config['db']['sql_password'],
]);
$pdo = $db->getConnection();
return ['db' => $db, 'error' => null];
} catch (Exception $e) {
return ['db' => null, 'error' => getError('Error connecting to DB.', $e->getMessage())];
}
// unknown database
} else {
$error = "Error: unknow database type \"{$config['db']['db_type']}\"";
Feedback::flash('ERROR', 'DEFAULT', $error);
exit();
}
} }
} }
// connect to Jilo database
function connectJiloDB($config, $dbFile = '', $platformId = '') {
try {
if (!$dbFile || !file_exists($dbFile)) {
throw new Exception(getError("Invalid platform ID \"{$platformId}\", database file \"{$dbFile}\" not found."));
}
$db = new Database([
'type' => 'sqlite',
'dbFile' => $dbFile,
]);
return ['db' => $db, 'error' => null];
} catch (Exception $e) {
return ['db' => null, 'error' => getError('Error connecting to DB.', $e->getMessage())];
}
}

View File

@ -19,8 +19,8 @@ $agentId = filter_input(INPUT_GET, 'agent', FILTER_VALIDATE_INT);
require '../app/classes/agent.php'; require '../app/classes/agent.php';
require '../app/classes/host.php'; require '../app/classes/host.php';
$agentObject = new Agent($dbWeb); $agentObject = new Agent($db);
$hostObject = new Host($dbWeb); $hostObject = new Host($db);
/** /**
* Get the cache key for an agent * Get the cache key for an agent
@ -50,7 +50,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Apply rate limiting for adding new contacts // Apply rate limiting for adding new contacts
require '../app/includes/rate_limit_middleware.php'; require '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'contact', $userId); checkRateLimit($db, 'contact', $userId);
// Validate agent ID for POST operations // Validate agent ID for POST operations
if ($agentId === false || $agentId === null) { if ($agentId === false || $agentId === null) {

View File

@ -9,7 +9,7 @@
*/ */
// connect to database // connect to database
$response = connectDB($config, 'jilo', $platformDetails[0]['jilo_database'], $platform_id); $response = connectJiloDB($config, $platformDetails[0]['jilo_database'], $platform_id);
// if DB connection has error, display it and stop here // if DB connection has error, display it and stop here
if ($response['db'] === null) { if ($response['db'] === null) {

View File

@ -9,7 +9,7 @@
*/ */
// connect to database // connect to database
$response = connectDB($config, 'jilo', $platformDetails[0]['jilo_database'], $platform_id); $response = connectJiloDB($config, $platformDetails[0]['jilo_database'], $platform_id);
// if DB connection has error, display it and stop here // if DB connection has error, display it and stop here
if ($response['db'] === null) { if ($response['db'] === null) {

View File

@ -13,7 +13,7 @@ require '../app/classes/config.php';
require '../app/classes/api_response.php'; require '../app/classes/api_response.php';
// Initialize required objects // Initialize required objects
$userObject = new User($dbWeb); $userObject = new User($db);
$configObject = new Config(); $configObject = new Config();
// For AJAX requests // For AJAX requests
@ -63,7 +63,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Apply rate limiting // Apply rate limiting
require '../app/includes/rate_limit_middleware.php'; require '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'config', $userId); checkRateLimit($db, 'config', $userId);
// Ensure no output before this point // Ensure no output before this point
ob_clean(); ob_clean();

View File

@ -15,7 +15,7 @@
*/ */
// Initialize user object // Initialize user object
$userObject = new User($dbWeb); $userObject = new User($db);
// Get action and item from request // Get action and item from request
$action = $_REQUEST['action'] ?? ''; $action = $_REQUEST['action'] ?? '';
@ -33,7 +33,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Apply rate limiting // Apply rate limiting
require_once '../app/includes/rate_limit_middleware.php'; require_once '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'credentials', $userId); checkRateLimit($db, 'credentials', $userId);
switch ($item) { switch ($item) {
case '2fa': case '2fa':

View File

@ -16,7 +16,7 @@ require '../app/classes/conference.php';
require '../app/classes/participant.php'; require '../app/classes/participant.php';
// connect to database // connect to database
$response = connectDB($config, 'jilo', $platformDetails[0]['jilo_database'], $platform_id); $response = connectJiloDB($config, $platformDetails[0]['jilo_database'], $platform_id);
// if DB connection has error, display it and stop here // if DB connection has error, display it and stop here
if ($response['db'] === null) { if ($response['db'] === null) {

View File

@ -7,11 +7,11 @@ require '../app/classes/agent.php';
require '../app/classes/conference.php'; require '../app/classes/conference.php';
require '../app/classes/host.php'; require '../app/classes/host.php';
$agentObject = new Agent($dbWeb); $agentObject = new Agent($db);
$hostObject = new Host($dbWeb); $hostObject = new Host($db);
// Connect to Jilo database for log data // Connect to Jilo database for log data
$response = connectDB($config, 'jilo', $platformDetails[0]['jilo_database'], $platform_id); $response = connectJiloDB($config, $platformDetails[0]['jilo_database'], $platform_id);
if ($response['db'] === null) { if ($response['db'] === null) {
Feedback::flash('ERROR', 'DEFAULT', $response['error']); Feedback::flash('ERROR', 'DEFAULT', $response['error']);
} else { } else {

View File

@ -3,8 +3,8 @@
require '../app/classes/agent.php'; require '../app/classes/agent.php';
require '../app/classes/host.php'; require '../app/classes/host.php';
$agentObject = new Agent($dbWeb); $agentObject = new Agent($db);
$hostObject = new Host($dbWeb); $hostObject = new Host($db);
// Define metrics to display // Define metrics to display
$metrics = [ $metrics = [

View File

@ -19,7 +19,7 @@ unset($error);
try { try {
// connect to database // connect to database
$db = connectDB($config)['db']; $db = connectDB($config);
// Initialize RateLimiter // Initialize RateLimiter
require_once '../app/classes/ratelimiter.php'; require_once '../app/classes/ratelimiter.php';

View File

@ -9,7 +9,7 @@
*/ */
// connect to database // connect to database
$response = connectDB($config, 'jilo', $platformDetails[0]['jilo_database'], $platform_id); $response = connectJiloDB($config, $platformDetails[0]['jilo_database'], $platform_id);
// if DB connection has error, display it and stop here // if DB connection has error, display it and stop here
if ($response['db'] === null) { if ($response['db'] === null) {

View File

@ -30,7 +30,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Apply rate limiting for profile operations // Apply rate limiting for profile operations
require_once '../app/includes/rate_limit_middleware.php'; require_once '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'profile', $userId); checkRateLimit($db, 'profile', $userId);
// avatar removal // avatar removal
if ($item === 'avatar' && $action === 'remove') { if ($item === 'avatar' && $action === 'remove') {

View File

@ -14,7 +14,7 @@ $section = isset($_POST['section']) ? $_POST['section'] : (isset($_GET['section'
// Initialize RateLimiter // Initialize RateLimiter
require_once '../app/classes/ratelimiter.php'; require_once '../app/classes/ratelimiter.php';
$rateLimiter = new RateLimiter($dbWeb); $rateLimiter = new RateLimiter($db);
// Handle form submissions // Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
@ -22,7 +22,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
// Apply rate limiting for security operations // Apply rate limiting for security operations
require_once '../app/includes/rate_limit_middleware.php'; require_once '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'security', $userId); checkRateLimit($db, 'security', $userId);
$action = $_POST['action']; $action = $_POST['action'];
$validator = new Validator($_POST); $validator = new Validator($_POST);

View File

@ -21,8 +21,8 @@ $host = $_REQUEST['host'] ?? '';
require '../app/classes/host.php'; require '../app/classes/host.php';
require '../app/classes/agent.php'; require '../app/classes/agent.php';
$hostObject = new Host($dbWeb); $hostObject = new Host($db);
$agentObject = new Agent($dbWeb); $agentObject = new Agent($db);
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
/** /**
@ -31,7 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Apply rate limiting for profile operations // Apply rate limiting for profile operations
require_once '../app/includes/rate_limit_middleware.php'; require_once '../app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'profile', $userId); checkRateLimit($db, 'profile', $userId);
// Get hash from URL if present // Get hash from URL if present
$hash = parse_url($_SERVER['REQUEST_URI'], PHP_URL_FRAGMENT) ?? ''; $hash = parse_url($_SERVER['REQUEST_URI'], PHP_URL_FRAGMENT) ?? '';

View File

@ -13,8 +13,8 @@ include '../app/helpers/feedback.php';
require '../app/classes/agent.php'; require '../app/classes/agent.php';
require '../app/classes/host.php'; require '../app/classes/host.php';
$agentObject = new Agent($dbWeb); $agentObject = new Agent($db);
$hostObject = new Host($dbWeb); $hostObject = new Host($db);
include '../app/templates/status-server.php'; include '../app/templates/status-server.php';
@ -22,7 +22,7 @@ include '../app/templates/status-server.php';
foreach ($platformsAll as $platform) { foreach ($platformsAll as $platform) {
// check if we can connect to the jilo database // check if we can connect to the jilo database
$response = connectDB($config, 'jilo', $platform['jilo_database'], $platform['id']); $response = connectJiloDB($config, $platform['jilo_database'], $platform['id']);
if ($response['error'] !== null) { if ($response['error'] !== null) {
$jilo_database_status = $response['error']; $jilo_database_status = $response['error'];
} else { } else {

View File

@ -20,8 +20,8 @@ CREATE TABLE `users` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
INSERT INTO `users` (`id`, `username`, `password`) VALUES INSERT INTO `users` (`id`, `username`, `password`) VALUES
(1,'demo','$2y$10$tLCLvgYu91gf/zBoc58Am.iVls/SOMcIXO3ykGfgFFei9yneZTrb2'), (1,'demo','$2y$12$AtIKs3eVxD4wTT1IWwJujuuHyGhhmfBJYqSfIrPFFPMDfKu3Rcsx6'),
(2,'demo1','$2y$10$LtV9m.rMCJ.K/g45e6tzDexZ8C/9xxu3qFCkvz92pUYa7Jg06np0i'); (2,'demo1','$2y$12$ELwYyhQ8XDkVvX9Xsb0mlORqeQHNFaBOvaBuPQym4n4IomA/DgvLC');
-- -------------------------------------------------------- -- --------------------------------------------------------
CREATE TABLE `users_meta` ( CREATE TABLE `users_meta` (
@ -67,7 +67,7 @@ INSERT INTO `rights` (`id`, `name`) VALUES
(15,'view jilo config'); (15,'view jilo config');
-- -------------------------------------------------------- -- --------------------------------------------------------
CREATE TABLE `users_right` ( CREATE TABLE `users_rights` (
`user_id` int(11) NOT NULL, `user_id` int(11) NOT NULL,
`right_id` int(11) NOT NULL, `right_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`right_id`), PRIMARY KEY (`user_id`,`right_id`),

View File

@ -21,13 +21,13 @@ require_once dirname(__FILE__, 4) . '/app/helpers/security.php';
if ($config['registration_enabled'] == true) { if ($config['registration_enabled'] == true) {
try { try {
global $dbWeb, $logObject, $userObject; global $db, $logObject, $userObject;
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) { if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
// Apply rate limiting // Apply rate limiting
require_once dirname(__FILE__, 4) . '/app/includes/rate_limit_middleware.php'; require_once dirname(__FILE__, 4) . '/app/includes/rate_limit_middleware.php';
checkRateLimit($dbWeb, 'register'); checkRateLimit($db, 'register');
$security = SecurityHelper::getInstance(); $security = SecurityHelper::getInstance();
@ -67,7 +67,7 @@ if ($config['registration_enabled'] == true) {
$password = $formData['password']; $password = $formData['password'];
// registering // registering
$register = new Register($dbWeb); $register = new Register($db);
$result = $register->register($username, $password); $result = $register->register($username, $password);
// redirect to login // redirect to login

View File

@ -80,30 +80,13 @@ error_reporting(E_ALL);
// edit accordingly, add 'pages/PAGE.php' // edit accordingly, add 'pages/PAGE.php'
$allowed_urls = [ $allowed_urls = [
'dashboard', 'dashboard',
'conferences','participants','components',
'conferences', 'graphs','latest','livejs','agents',
'participants', 'profile','credentials','config','security',
'components',
'graphs',
'latest',
'livejs',
'agents',
'config',
'profile',
'credentials',
'settings', 'settings',
'security',
'status', 'status',
'help', 'help',
'login','logout',
'login',
'logout',
'about', 'about',
]; ];
@ -137,10 +120,10 @@ require_once __DIR__ . '/../app/core/Router.php';
use App\Core\Router; use App\Core\Router;
$currentUser = Router::checkAuth($config, $app_root, $public_pages, $page); $currentUser = Router::checkAuth($config, $app_root, $public_pages, $page);
// connect to DB via DatabaseConnector // Connect to DB via DatabaseConnector
require_once __DIR__ . '/../app/core/DatabaseConnector.php'; require_once __DIR__ . '/../app/core/DatabaseConnector.php';
use App\Core\DatabaseConnector; use App\Core\DatabaseConnector;
$dbWeb = DatabaseConnector::connect($config); $db = DatabaseConnector::connect($config);
// Logging: default to NullLogger, plugin can override // Logging: default to NullLogger, plugin can override
require_once __DIR__ . '/../app/core/NullLogger.php'; require_once __DIR__ . '/../app/core/NullLogger.php';
@ -151,7 +134,7 @@ require_once __DIR__ . '/../app/helpers/ip_helper.php';
$user_IP = ''; $user_IP = '';
// Plugin: initialize logging system plugin if available // Plugin: initialize logging system plugin if available
do_hook('logger.system_init', ['db' => $dbWeb]); do_hook('logger.system_init', ['db' => $db]);
// Override defaults if plugin provided real logger // Override defaults if plugin provided real logger
if (isset($GLOBALS['logObject'])) { if (isset($GLOBALS['logObject'])) {
@ -174,7 +157,7 @@ require '../app/classes/ratelimiter.php';
// get platforms details // get platforms details
require '../app/classes/platform.php'; require '../app/classes/platform.php';
$platformObject = new Platform($dbWeb); $platformObject = new Platform($db);
$platformsAll = $platformObject->getPlatformDetails(); $platformsAll = $platformObject->getPlatformDetails();
// by default we connect ot the first configured platform // by default we connect ot the first configured platform
@ -187,7 +170,7 @@ $platformDetails = $platformObject->getPlatformDetails($platform_id);
// init user functions // init user functions
require '../app/classes/user.php'; require '../app/classes/user.php';
include '../app/helpers/profile.php'; include '../app/helpers/profile.php';
$userObject = new User($dbWeb); $userObject = new User($db);
// logout is a special case, as we can't use session vars for notices // logout is a special case, as we can't use session vars for notices
if ($page == 'logout') { if ($page == 'logout') {
@ -225,7 +208,7 @@ if ($page == 'logout') {
// check if the Jilo Server is running // check if the Jilo Server is running
require '../app/classes/server.php'; require '../app/classes/server.php';
$serverObject = new Server($dbWeb); $serverObject = new Server($db);
$server_host = '127.0.0.1'; $server_host = '127.0.0.1';
$server_port = '8080'; $server_port = '8080';
@ -255,9 +238,9 @@ if ($page == 'logout') {
// all normal pages // all normal pages
if (isset($plugin_controllers[$page])) { if (isset($plugin_controllers[$page])) {
include $plugin_controllers[$page]; include $plugin_controllers[$page];
} else { } else {
include "../app/pages/{$page}.php"; include "../app/pages/{$page}.php";
} }
} else { } else {
// the page is not in allowed urls, loading "not found" page // the page is not in allowed urls, loading "not found" page
include '../app/templates/error-notfound.php'; include '../app/templates/error-notfound.php';

View File

@ -12,9 +12,16 @@ if (!headers_sent()) {
ini_set('session.gc_maxlifetime', 1440); // 24 minutes ini_set('session.gc_maxlifetime', 1440); // 24 minutes
} }
// Load plugin Log model and IP helper early so fallback wrapper is bypassed
require_once __DIR__ . '/../plugins/logs/models/Log.php';
require_once __DIR__ . '/../app/helpers/ip_helper.php';
// Load Composer's autoloader // Load Composer's autoloader
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
// Ensure core NullLogger is available during tests
require_once __DIR__ . '/../app/core/NullLogger.php';
// Set error reporting // Set error reporting
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set('display_errors', 1); ini_set('display_errors', 1);
@ -26,18 +33,23 @@ date_default_timezone_set('UTC');
// Define global variables needed by the application // Define global variables needed by the application
$GLOBALS['app_root'] = '/'; $GLOBALS['app_root'] = '/';
$GLOBALS['config'] = [ $GLOBALS['config'] = [
'db' => [ 'db_type' => 'mariadb',
'type' => 'sqlite', 'sql' => [
'dbFile' => ':memory:' 'sql_host' => 'localhost',
] 'sql_port' => '3306',
'sql_database' => 'jilo_test',
'sql_username' => 'test_jilo',
'sql_password' => '',
],
'environment' => 'testing'
]; ];
// Define global connectDB function // Define global connectDB function
if (!function_exists('connectDB')) { if (!function_exists('connectDB')) {
function connectDB($config) { function connectDB($config) {
global $dbWeb; global $db;
return [ return [
'db' => $dbWeb 'db' => $db
]; ];
} }
} }