Compare commits
3 Commits
630f71ce4d
...
4a43d8cfc7
Author | SHA1 | Date |
---|---|---|
|
4a43d8cfc7 | |
|
adb8e42d61 | |
|
880c45025c |
|
@ -43,11 +43,11 @@ class Agent {
|
||||||
jat.endpoint AS agent_endpoint,
|
jat.endpoint AS agent_endpoint,
|
||||||
h.platform_id
|
h.platform_id
|
||||||
FROM
|
FROM
|
||||||
jilo_agents ja
|
jilo_agent ja
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agent_types jat ON ja.agent_type_id = jat.id
|
jilo_agent_type jat ON ja.agent_type_id = jat.id
|
||||||
JOIN
|
JOIN
|
||||||
hosts h ON ja.host_id = h.id
|
host h ON ja.host_id = h.id
|
||||||
WHERE
|
WHERE
|
||||||
ja.host_id = :host_id';
|
ja.host_id = :host_id';
|
||||||
|
|
||||||
|
@ -87,11 +87,11 @@ class Agent {
|
||||||
jat.endpoint AS agent_endpoint,
|
jat.endpoint AS agent_endpoint,
|
||||||
h.platform_id
|
h.platform_id
|
||||||
FROM
|
FROM
|
||||||
jilo_agents ja
|
jilo_agent ja
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agent_types jat ON ja.agent_type_id = jat.id
|
jilo_agent_type jat ON ja.agent_type_id = jat.id
|
||||||
JOIN
|
JOIN
|
||||||
hosts h ON ja.host_id = h.id
|
host h ON ja.host_id = h.id
|
||||||
WHERE
|
WHERE
|
||||||
ja.id = :agent_id';
|
ja.id = :agent_id';
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class Agent {
|
||||||
*/
|
*/
|
||||||
public function getAgentTypes() {
|
public function getAgentTypes() {
|
||||||
$sql = 'SELECT *
|
$sql = 'SELECT *
|
||||||
FROM jilo_agent_types
|
FROM jilo_agent_type
|
||||||
ORDER BY id';
|
ORDER BY id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
@ -131,7 +131,7 @@ class Agent {
|
||||||
id,
|
id,
|
||||||
agent_type_id
|
agent_type_id
|
||||||
FROM
|
FROM
|
||||||
jilo_agents
|
jilo_agent
|
||||||
WHERE
|
WHERE
|
||||||
host_id = :host_id';
|
host_id = :host_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
|
@ -152,7 +152,7 @@ class Agent {
|
||||||
*/
|
*/
|
||||||
public function addAgent($host_id, $newAgent) {
|
public function addAgent($host_id, $newAgent) {
|
||||||
try {
|
try {
|
||||||
$sql = 'INSERT INTO jilo_agents
|
$sql = 'INSERT INTO jilo_agent
|
||||||
(host_id, agent_type_id, url, secret_key, check_period)
|
(host_id, agent_type_id, url, secret_key, check_period)
|
||||||
VALUES
|
VALUES
|
||||||
(:host_id, :agent_type_id, :url, :secret_key, :check_period)';
|
(:host_id, :agent_type_id, :url, :secret_key, :check_period)';
|
||||||
|
@ -184,7 +184,7 @@ class Agent {
|
||||||
*/
|
*/
|
||||||
public function editAgent($agent_id, $updatedAgent) {
|
public function editAgent($agent_id, $updatedAgent) {
|
||||||
try {
|
try {
|
||||||
$sql = 'UPDATE jilo_agents
|
$sql = 'UPDATE jilo_agent
|
||||||
SET
|
SET
|
||||||
agent_type_id = :agent_type_id,
|
agent_type_id = :agent_type_id,
|
||||||
url = :url,
|
url = :url,
|
||||||
|
@ -222,7 +222,7 @@ class Agent {
|
||||||
*/
|
*/
|
||||||
public function deleteAgent($agent_id) {
|
public function deleteAgent($agent_id) {
|
||||||
try {
|
try {
|
||||||
$sql = 'DELETE FROM jilo_agents
|
$sql = 'DELETE FROM jilo_agent
|
||||||
WHERE
|
WHERE
|
||||||
id = :agent_id';
|
id = :agent_id';
|
||||||
|
|
||||||
|
@ -420,13 +420,13 @@ class Agent {
|
||||||
jac.agent_id,
|
jac.agent_id,
|
||||||
jat.description
|
jat.description
|
||||||
FROM
|
FROM
|
||||||
jilo_agent_checks jac
|
jilo_agent_check jac
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agents ja ON jac.agent_id = ja.id
|
jilo_agent ja ON jac.agent_id = ja.id
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agent_types jat ON ja.agent_type_id = jat.id
|
jilo_agent_type jat ON ja.agent_type_id = jat.id
|
||||||
JOIN
|
JOIN
|
||||||
hosts h ON ja.host_id = h.id
|
host h ON ja.host_id = h.id
|
||||||
WHERE
|
WHERE
|
||||||
h.id = :host_id
|
h.id = :host_id
|
||||||
AND jat.description = :agent_type
|
AND jat.description = :agent_type
|
||||||
|
@ -520,13 +520,13 @@ class Agent {
|
||||||
jac.response_content,
|
jac.response_content,
|
||||||
COUNT(*) as checks_count
|
COUNT(*) as checks_count
|
||||||
FROM
|
FROM
|
||||||
jilo_agent_checks jac
|
jilo_agent_check jac
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agents ja ON jac.agent_id = ja.id
|
jilo_agent ja ON jac.agent_id = ja.id
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agent_types jat ON ja.agent_type_id = jat.id
|
jilo_agent_type jat ON ja.agent_type_id = jat.id
|
||||||
JOIN
|
JOIN
|
||||||
hosts h ON ja.host_id = h.id
|
host h ON ja.host_id = h.id
|
||||||
WHERE
|
WHERE
|
||||||
h.id = :host_id
|
h.id = :host_id
|
||||||
AND jat.description = :agent_type
|
AND jat.description = :agent_type
|
||||||
|
@ -591,13 +591,13 @@ class Agent {
|
||||||
jac.timestamp,
|
jac.timestamp,
|
||||||
jac.response_content
|
jac.response_content
|
||||||
FROM
|
FROM
|
||||||
jilo_agent_checks jac
|
jilo_agent_check jac
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agents ja ON jac.agent_id = ja.id
|
jilo_agent ja ON jac.agent_id = ja.id
|
||||||
JOIN
|
JOIN
|
||||||
jilo_agent_types jat ON ja.agent_type_id = jat.id
|
jilo_agent_type jat ON ja.agent_type_id = jat.id
|
||||||
JOIN
|
JOIN
|
||||||
hosts h ON ja.host_id = h.id
|
host h ON ja.host_id = h.id
|
||||||
WHERE
|
WHERE
|
||||||
h.id = :host_id
|
h.id = :host_id
|
||||||
AND jat.description = :agent_type
|
AND jat.description = :agent_type
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Host {
|
||||||
platform_id,
|
platform_id,
|
||||||
name
|
name
|
||||||
FROM
|
FROM
|
||||||
hosts';
|
host';
|
||||||
|
|
||||||
if ($platform_id !== '' && $host_id !== '') {
|
if ($platform_id !== '' && $host_id !== '') {
|
||||||
$sql .= ' WHERE platform_id = :platform_id AND id = :host_id';
|
$sql .= ' WHERE platform_id = :platform_id AND id = :host_id';
|
||||||
|
@ -71,7 +71,7 @@ class Host {
|
||||||
*/
|
*/
|
||||||
public function addHost($newHost) {
|
public function addHost($newHost) {
|
||||||
try {
|
try {
|
||||||
$sql = 'INSERT INTO hosts
|
$sql = 'INSERT INTO host
|
||||||
(address, platform_id, name)
|
(address, platform_id, name)
|
||||||
VALUES
|
VALUES
|
||||||
(:address, :platform_id, :name)';
|
(:address, :platform_id, :name)';
|
||||||
|
@ -101,7 +101,7 @@ class Host {
|
||||||
*/
|
*/
|
||||||
public function editHost($platform_id, $updatedHost) {
|
public function editHost($platform_id, $updatedHost) {
|
||||||
try {
|
try {
|
||||||
$sql = 'UPDATE hosts SET
|
$sql = 'UPDATE host SET
|
||||||
address = :address,
|
address = :address,
|
||||||
name = :name
|
name = :name
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -140,13 +140,13 @@ class Host {
|
||||||
$this->db->beginTransaction();
|
$this->db->beginTransaction();
|
||||||
|
|
||||||
// First delete all agents associated with this host
|
// First delete all agents associated with this host
|
||||||
$sql = 'DELETE FROM jilo_agents WHERE host_id = :host_id';
|
$sql = 'DELETE FROM jilo_agent WHERE host_id = :host_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':host_id', $host_id);
|
$query->bindParam(':host_id', $host_id);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
|
||||||
// Then delete the host
|
// Then delete the host
|
||||||
$sql = 'DELETE FROM hosts WHERE id = :host_id';
|
$sql = 'DELETE FROM host WHERE id = :host_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':host_id', $host_id);
|
$query->bindParam(':host_id', $host_id);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
|
|
@ -26,8 +26,8 @@ class PasswordReset {
|
||||||
// Check if email exists
|
// Check if email exists
|
||||||
$query = $this->db->prepare("
|
$query = $this->db->prepare("
|
||||||
SELECT u.id, um.email
|
SELECT u.id, um.email
|
||||||
FROM users u
|
FROM user u
|
||||||
JOIN users_meta um ON u.id = um.user_id
|
JOIN user_meta um ON u.id = um.user_id
|
||||||
WHERE um.email = :email"
|
WHERE um.email = :email"
|
||||||
);
|
);
|
||||||
$query->bindParam(':email', $email);
|
$query->bindParam(':email', $email);
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Platform {
|
||||||
* @return array An associative array containing platform details.
|
* @return array An associative array containing platform details.
|
||||||
*/
|
*/
|
||||||
public function getPlatformDetails($platform_id = '') {
|
public function getPlatformDetails($platform_id = '') {
|
||||||
$sql = 'SELECT * FROM platforms';
|
$sql = 'SELECT * FROM platform';
|
||||||
if ($platform_id !== '') {
|
if ($platform_id !== '') {
|
||||||
$sql .= ' WHERE id = :platform_id';
|
$sql .= ' WHERE id = :platform_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
|
@ -57,7 +57,7 @@ class Platform {
|
||||||
*/
|
*/
|
||||||
public function addPlatform($newPlatform) {
|
public function addPlatform($newPlatform) {
|
||||||
try {
|
try {
|
||||||
$sql = 'INSERT INTO platforms
|
$sql = 'INSERT INTO platform
|
||||||
(name, jitsi_url, jilo_database)
|
(name, jitsi_url, jilo_database)
|
||||||
VALUES
|
VALUES
|
||||||
(:name, :jitsi_url, :jilo_database)';
|
(:name, :jitsi_url, :jilo_database)';
|
||||||
|
@ -90,7 +90,7 @@ class Platform {
|
||||||
*/
|
*/
|
||||||
public function editPlatform($platform_id, $updatedPlatform) {
|
public function editPlatform($platform_id, $updatedPlatform) {
|
||||||
try {
|
try {
|
||||||
$sql = 'UPDATE platforms SET
|
$sql = 'UPDATE platform SET
|
||||||
name = :name,
|
name = :name,
|
||||||
jitsi_url = :jitsi_url,
|
jitsi_url = :jitsi_url,
|
||||||
jilo_database = :jilo_database
|
jilo_database = :jilo_database
|
||||||
|
@ -125,7 +125,7 @@ class Platform {
|
||||||
$this->db->beginTransaction();
|
$this->db->beginTransaction();
|
||||||
|
|
||||||
// First, get all hosts in this platform
|
// First, get all hosts in this platform
|
||||||
$sql = 'SELECT id FROM hosts WHERE platform_id = :platform_id';
|
$sql = 'SELECT id FROM host WHERE platform_id = :platform_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':platform_id', $platform_id);
|
$query->bindParam(':platform_id', $platform_id);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
@ -133,20 +133,20 @@ class Platform {
|
||||||
|
|
||||||
// Delete all agents for each host
|
// Delete all agents for each host
|
||||||
foreach ($hosts as $host) {
|
foreach ($hosts as $host) {
|
||||||
$sql = 'DELETE FROM jilo_agents WHERE host_id = :host_id';
|
$sql = 'DELETE FROM jilo_agent WHERE host_id = :host_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':host_id', $host['id']);
|
$query->bindParam(':host_id', $host['id']);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all hosts in this platform
|
// Delete all hosts in this platform
|
||||||
$sql = 'DELETE FROM hosts WHERE platform_id = :platform_id';
|
$sql = 'DELETE FROM host WHERE platform_id = :platform_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':platform_id', $platform_id);
|
$query->bindParam(':platform_id', $platform_id);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
|
||||||
// Finally, delete the platform
|
// Finally, delete the platform
|
||||||
$sql = 'DELETE FROM platforms WHERE id = :platform_id';
|
$sql = 'DELETE FROM platform WHERE id = :platform_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':platform_id', $platform_id);
|
$query->bindParam(':platform_id', $platform_id);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
|
|
@ -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([
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* class User
|
* class User
|
||||||
*
|
*
|
||||||
* Handles user-related functionalities such as registration, login, rights management, and profile updates.
|
* Handles user-related functionalities such as login, rights management, and profile updates.
|
||||||
*/
|
*/
|
||||||
class User {
|
class User {
|
||||||
/**
|
/**
|
||||||
|
@ -36,9 +36,9 @@ class User {
|
||||||
/**
|
/**
|
||||||
* Logs in a user by verifying credentials.
|
* Logs in a user by verifying credentials.
|
||||||
*
|
*
|
||||||
* @param string $username The username of the user.
|
* @param string $username The username of the user.
|
||||||
* @param string $password The password of the user.
|
* @param string $password The password of the user.
|
||||||
* @param string $twoFactorCode Optional. The 2FA code if 2FA is enabled.
|
* @param string $twoFactorCode Optional. The 2FA code if 2FA is enabled.
|
||||||
*
|
*
|
||||||
* @return array Login result with status and any necessary data
|
* @return array Login result with status and any necessary data
|
||||||
*/
|
*/
|
||||||
|
@ -53,7 +53,7 @@ class User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then check credentials
|
// Then check credentials
|
||||||
$query = $this->db->prepare("SELECT * FROM users WHERE username = :username");
|
$query = $this->db->prepare("SELECT * FROM user WHERE username = :username");
|
||||||
$query->bindParam(':username', $username);
|
$query->bindParam(':username', $username);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
|
||||||
|
@ -92,7 +92,10 @@ class User {
|
||||||
|
|
||||||
// Get remaining attempts AFTER this failed attempt
|
// Get remaining attempts AFTER this failed attempt
|
||||||
$remainingAttempts = $this->rateLimiter->getRemainingAttempts($username, $ipAddress);
|
$remainingAttempts = $this->rateLimiter->getRemainingAttempts($username, $ipAddress);
|
||||||
throw new Exception("Invalid credentials. {$remainingAttempts} attempts remaining.");
|
return [
|
||||||
|
'status' => 'failed',
|
||||||
|
'message' => "Invalid credentials. {$remainingAttempts} attempts remaining."
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +108,7 @@ class User {
|
||||||
*/
|
*/
|
||||||
// FIXME not used now?
|
// FIXME not used now?
|
||||||
public function getUserId($username) {
|
public function getUserId($username) {
|
||||||
$sql = 'SELECT id FROM users WHERE username = :username';
|
$sql = 'SELECT id FROM user WHERE username = :username';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindParam(':username', $username);
|
$query->bindParam(':username', $username);
|
||||||
|
|
||||||
|
@ -128,8 +131,8 @@ class User {
|
||||||
um.*,
|
um.*,
|
||||||
u.username
|
u.username
|
||||||
FROM
|
FROM
|
||||||
users_meta um
|
user_meta um
|
||||||
LEFT JOIN users u
|
LEFT JOIN user u
|
||||||
ON um.user_id = u.id
|
ON um.user_id = u.id
|
||||||
WHERE
|
WHERE
|
||||||
u.id = :user_id';
|
u.id = :user_id';
|
||||||
|
@ -153,7 +156,7 @@ class User {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function addUserRight($userId, $right_id) {
|
public function addUserRight($userId, $right_id) {
|
||||||
$sql = 'INSERT INTO users_rights
|
$sql = 'INSERT INTO user_right
|
||||||
(user_id, right_id)
|
(user_id, right_id)
|
||||||
VALUES
|
VALUES
|
||||||
(:user_id, :right_id)';
|
(:user_id, :right_id)';
|
||||||
|
@ -174,7 +177,7 @@ class User {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function removeUserRight($userId, $right_id) {
|
public function removeUserRight($userId, $right_id) {
|
||||||
$sql = 'DELETE FROM users_rights
|
$sql = 'DELETE FROM user_right
|
||||||
WHERE
|
WHERE
|
||||||
user_id = :user_id
|
user_id = :user_id
|
||||||
AND
|
AND
|
||||||
|
@ -196,7 +199,7 @@ class User {
|
||||||
$sql = 'SELECT
|
$sql = 'SELECT
|
||||||
id AS right_id,
|
id AS right_id,
|
||||||
name AS right_name
|
name AS right_name
|
||||||
FROM rights
|
FROM `right`
|
||||||
ORDER BY id ASC';
|
ORDER BY id ASC';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
@ -219,10 +222,10 @@ class User {
|
||||||
r.id AS right_id,
|
r.id AS right_id,
|
||||||
r.name AS right_name
|
r.name AS right_name
|
||||||
FROM
|
FROM
|
||||||
users u
|
`user` u
|
||||||
LEFT JOIN users_rights ur
|
LEFT JOIN `user_right` ur
|
||||||
ON u.id = ur.user_id
|
ON u.id = ur.user_id
|
||||||
LEFT JOIN rights r
|
LEFT JOIN `right` r
|
||||||
ON ur.right_id = r.id
|
ON ur.right_id = r.id
|
||||||
WHERE
|
WHERE
|
||||||
u.id = :user_id';
|
u.id = :user_id';
|
||||||
|
@ -312,7 +315,7 @@ class User {
|
||||||
*/
|
*/
|
||||||
public function editUser($userId, $updatedUser) {
|
public function editUser($userId, $updatedUser) {
|
||||||
try {
|
try {
|
||||||
$sql = 'UPDATE users_meta SET
|
$sql = 'UPDATE user_meta SET
|
||||||
name = :name,
|
name = :name,
|
||||||
email = :email,
|
email = :email,
|
||||||
timezone = :timezone,
|
timezone = :timezone,
|
||||||
|
@ -347,7 +350,7 @@ class User {
|
||||||
public function removeAvatar($userId, $old_avatar = '') {
|
public function removeAvatar($userId, $old_avatar = '') {
|
||||||
try {
|
try {
|
||||||
// remove from database
|
// remove from database
|
||||||
$sql = 'UPDATE users_meta SET
|
$sql = 'UPDATE user_meta SET
|
||||||
avatar = NULL
|
avatar = NULL
|
||||||
WHERE user_id = :user_id';
|
WHERE user_id = :user_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
|
@ -396,7 +399,7 @@ class User {
|
||||||
if (move_uploaded_file($fileTmpPath, $dest_path)) {
|
if (move_uploaded_file($fileTmpPath, $dest_path)) {
|
||||||
try {
|
try {
|
||||||
// update user's avatar path in DB
|
// update user's avatar path in DB
|
||||||
$sql = 'UPDATE users_meta SET
|
$sql = 'UPDATE user_meta SET
|
||||||
avatar = :avatar
|
avatar = :avatar
|
||||||
WHERE user_id = :user_id';
|
WHERE user_id = :user_id';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
|
@ -432,7 +435,7 @@ class User {
|
||||||
*/
|
*/
|
||||||
public function getUsers() {
|
public function getUsers() {
|
||||||
$sql = "SELECT id, username
|
$sql = "SELECT id, username
|
||||||
FROM users
|
FROM `user`
|
||||||
ORDER BY username ASC";
|
ORDER BY username ASC";
|
||||||
|
|
||||||
$stmt = $this->db->prepare($sql);
|
$stmt = $this->db->prepare($sql);
|
||||||
|
@ -495,7 +498,7 @@ class User {
|
||||||
public function changePassword($userId, $currentPassword, $newPassword) {
|
public function changePassword($userId, $currentPassword, $newPassword) {
|
||||||
try {
|
try {
|
||||||
// First verify the current password
|
// First verify the current password
|
||||||
$sql = "SELECT password FROM users WHERE id = :user_id";
|
$sql = "SELECT password FROM user WHERE id = :user_id";
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->execute([':user_id' => $userId]);
|
$query->execute([':user_id' => $userId]);
|
||||||
$user = $query->fetch(PDO::FETCH_ASSOC);
|
$user = $query->fetch(PDO::FETCH_ASSOC);
|
||||||
|
@ -508,7 +511,7 @@ class User {
|
||||||
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
|
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
// Update the password
|
// Update the password
|
||||||
$sql = "UPDATE users SET password = :password WHERE id = :user_id";
|
$sql = "UPDATE user SET password = :password WHERE id = :user_id";
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
return $query->execute([
|
return $query->execute([
|
||||||
':password' => $hashedPassword,
|
':password' => $hashedPassword,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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())];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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') {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) ?? '';
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -11,7 +11,7 @@ SET NAMES utf8mb4;
|
||||||
--
|
--
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `users` (
|
CREATE TABLE `user` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`username` varchar(50) NOT NULL,
|
`username` varchar(50) NOT NULL,
|
||||||
`password` varchar(100) NOT NULL,
|
`password` varchar(100) NOT NULL,
|
||||||
|
@ -19,12 +19,12 @@ CREATE TABLE `users` (
|
||||||
UNIQUE KEY `username` (`username`)
|
UNIQUE KEY `username` (`username`)
|
||||||
) 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 `user` (`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 `user_meta` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`user_id` int(11) NOT NULL,
|
`user_id` int(11) NOT NULL,
|
||||||
`name` varchar(255) DEFAULT NULL,
|
`name` varchar(255) DEFAULT NULL,
|
||||||
|
@ -34,22 +34,22 @@ CREATE TABLE `users_meta` (
|
||||||
`bio` text DEFAULT NULL,
|
`bio` text DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`,`user_id`) USING BTREE,
|
PRIMARY KEY (`id`,`user_id`) USING BTREE,
|
||||||
KEY `user_id` (`user_id`),
|
KEY `user_id` (`user_id`),
|
||||||
CONSTRAINT `user_meta_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `user_meta_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
INSERT INTO `users_meta` (`id`, `user_id`, `name`, `email`, `timezone`, `avatar`, `bio`) VALUES
|
INSERT INTO `user_meta` (`id`, `user_id`, `name`, `email`, `timezone`, `avatar`, `bio`) VALUES
|
||||||
(1,1,'demo admin user','admin@example.com',NULL,NULL,'This is a demo user of the demo install of Jilo Web'),
|
(1,1,'demo admin user','admin@example.com',NULL,NULL,'This is a demo user of the demo install of Jilo Web'),
|
||||||
(2,2,'demo user','demo@example.com',NULL,NULL,'This is a demo user of the demo install of Jilo Web');
|
(2,2,'demo user','demo@example.com',NULL,NULL,'This is a demo user of the demo install of Jilo Web');
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `rights` (
|
CREATE TABLE `right` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `name` (`name`)
|
UNIQUE KEY `name` (`name`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
INSERT INTO `rights` (`id`, `name`) VALUES
|
INSERT INTO `right` (`id`, `name`) VALUES
|
||||||
(1, 'superuser'),
|
(1, 'superuser'),
|
||||||
(2, 'edit users'),
|
(2, 'edit users'),
|
||||||
(3, 'view config file'),
|
(3, 'view config file'),
|
||||||
|
@ -67,13 +67,13 @@ INSERT INTO `rights` (`id`, `name`) VALUES
|
||||||
(15,'view jilo config');
|
(15,'view jilo config');
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `users_right` (
|
CREATE TABLE `user_right` (
|
||||||
`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`),
|
||||||
KEY `fk_right_id` (`right_id`),
|
KEY `fk_right_id` (`right_id`),
|
||||||
CONSTRAINT `fk_right_id` FOREIGN KEY (`right_id`) REFERENCES `rights` (`id`),
|
CONSTRAINT `fk_right_id` FOREIGN KEY (`right_id`) REFERENCES `right` (`id`),
|
||||||
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
@ -85,7 +85,7 @@ CREATE TABLE `user_2fa` (
|
||||||
`created_at` datetime NOT NULL,
|
`created_at` datetime NOT NULL,
|
||||||
`last_used` datetime DEFAULT NULL,
|
`last_used` datetime DEFAULT NULL,
|
||||||
PRIMARY KEY (`user_id`),
|
PRIMARY KEY (`user_id`),
|
||||||
CONSTRAINT `fk_user_2fa_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `fk_user_2fa_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
@ -95,7 +95,7 @@ CREATE TABLE `user_2fa_temp` (
|
||||||
`created_at` datetime NOT NULL,
|
`created_at` datetime NOT NULL,
|
||||||
`expires_at` datetime NOT NULL,
|
`expires_at` datetime NOT NULL,
|
||||||
PRIMARY KEY (`user_id`, `code`),
|
PRIMARY KEY (`user_id`, `code`),
|
||||||
CONSTRAINT `fk_user_2fa_temp_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `fk_user_2fa_temp_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
@ -106,7 +106,7 @@ CREATE TABLE `user_password_reset` (
|
||||||
`expires` int(11) NOT NULL,
|
`expires` int(11) NOT NULL,
|
||||||
`used` TINYINT(1) NOT NULL DEFAULT 0,
|
`used` TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
CONSTRAINT `fk_user_password_reset` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
|
CONSTRAINT `fk_user_password_reset` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),
|
||||||
UNIQUE KEY `token_idx` (`token`)
|
UNIQUE KEY `token_idx` (`token`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ CREATE TABLE `user_password_reset` (
|
||||||
--
|
--
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `login_attempts` (
|
CREATE TABLE `security_rate_auth` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip_address` varchar(45) NOT NULL,
|
`ip_address` varchar(45) NOT NULL,
|
||||||
`username` varchar(255) NOT NULL,
|
`username` varchar(255) NOT NULL,
|
||||||
|
@ -125,7 +125,7 @@ CREATE TABLE `login_attempts` (
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `pages_rate_limits` (
|
CREATE TABLE `security_rate_page` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip_address` varchar(45) NOT NULL,
|
`ip_address` varchar(45) NOT NULL,
|
||||||
`endpoint` varchar(255) NOT NULL,
|
`endpoint` varchar(255) NOT NULL,
|
||||||
|
@ -136,7 +136,7 @@ CREATE TABLE `pages_rate_limits` (
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `ip_blacklist` (
|
CREATE TABLE `security_ip_blacklist` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip_address` varchar(45) NOT NULL,
|
`ip_address` varchar(45) NOT NULL,
|
||||||
`is_network` tinyint(1) DEFAULT 0,
|
`is_network` tinyint(1) DEFAULT 0,
|
||||||
|
@ -148,7 +148,7 @@ CREATE TABLE `ip_blacklist` (
|
||||||
UNIQUE KEY `unique_ip` (`ip_address`)
|
UNIQUE KEY `unique_ip` (`ip_address`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
INSERT INTO `ip_blacklist` (`id`, `ip_address`, `is_network`, `reason`, `expiry_time`, `created_at`, `created_by`) VALUES
|
INSERT INTO `security_ip_blacklist` (`id`, `ip_address`, `is_network`, `reason`, `expiry_time`, `created_at`, `created_by`) VALUES
|
||||||
(1, '0.0.0.0/8', 1, 'Reserved address space - RFC 1122', NULL, '2025-01-03 16:40:15', 'system'),
|
(1, '0.0.0.0/8', 1, 'Reserved address space - RFC 1122', NULL, '2025-01-03 16:40:15', 'system'),
|
||||||
(2, '100.64.0.0/10', 1, 'Carrier-grade NAT space - RFC 6598', NULL, '2025-01-03 16:40:15', 'system'),
|
(2, '100.64.0.0/10', 1, 'Carrier-grade NAT space - RFC 6598', NULL, '2025-01-03 16:40:15', 'system'),
|
||||||
(3, '192.0.2.0/24', 1, 'TEST-NET-1 Documentation space - RFC 5737', NULL, '2025-01-03 16:40:15', 'system'),
|
(3, '192.0.2.0/24', 1, 'TEST-NET-1 Documentation space - RFC 5737', NULL, '2025-01-03 16:40:15', 'system'),
|
||||||
|
@ -156,7 +156,7 @@ INSERT INTO `ip_blacklist` (`id`, `ip_address`, `is_network`, `reason`, `expiry_
|
||||||
(5, '203.0.113.0/24', 1, 'TEST-NET-3 Documentation space - RFC 5737', NULL, '2025-01-03 16:40:15', 'system');
|
(5, '203.0.113.0/24', 1, 'TEST-NET-3 Documentation space - RFC 5737', NULL, '2025-01-03 16:40:15', 'system');
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `ip_whitelist` (
|
CREATE TABLE `security_ip_whitelist` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip_address` varchar(45) NOT NULL,
|
`ip_address` varchar(45) NOT NULL,
|
||||||
`is_network` tinyint(1) DEFAULT 0,
|
`is_network` tinyint(1) DEFAULT 0,
|
||||||
|
@ -167,7 +167,7 @@ CREATE TABLE `ip_whitelist` (
|
||||||
UNIQUE KEY `unique_ip` (`ip_address`)
|
UNIQUE KEY `unique_ip` (`ip_address`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
INSERT INTO `ip_whitelist` (`id`, `ip_address`, `is_network`, `description`, `created_at`, `created_by`) VALUES
|
INSERT INTO `security_ip_whitelist` (`id`, `ip_address`, `is_network`, `description`, `created_at`, `created_by`) VALUES
|
||||||
(1, '127.0.0.1', 0, 'localhost IPv4', '2025-01-03 16:40:15', 'system'),
|
(1, '127.0.0.1', 0, 'localhost IPv4', '2025-01-03 16:40:15', 'system'),
|
||||||
(2, '::1', 0, 'localhost IPv6', '2025-01-03 16:40:15', 'system'),
|
(2, '::1', 0, 'localhost IPv6', '2025-01-03 16:40:15', 'system'),
|
||||||
(3, '10.0.0.0/8', 1, 'Private network (Class A)', '2025-01-03 16:40:15', 'system'),
|
(3, '10.0.0.0/8', 1, 'Private network (Class A)', '2025-01-03 16:40:15', 'system'),
|
||||||
|
@ -179,7 +179,7 @@ INSERT INTO `ip_whitelist` (`id`, `ip_address`, `is_network`, `description`, `cr
|
||||||
--
|
--
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `logs` (
|
CREATE TABLE `log` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`user_id` int(11) NOT NULL,
|
`user_id` int(11) NOT NULL,
|
||||||
`time` datetime NOT NULL DEFAULT current_timestamp(),
|
`time` datetime NOT NULL DEFAULT current_timestamp(),
|
||||||
|
@ -187,7 +187,7 @@ CREATE TABLE `logs` (
|
||||||
`message` varchar(255) NOT NULL,
|
`message` varchar(255) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `user_id` (`user_id`),
|
KEY `user_id` (`user_id`),
|
||||||
CONSTRAINT `log_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `log_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
--
|
--
|
||||||
|
@ -195,13 +195,13 @@ CREATE TABLE `logs` (
|
||||||
--
|
--
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `jilo_agent_types` (
|
CREATE TABLE `jilo_agent_type` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`description` varchar(255),
|
`description` varchar(255),
|
||||||
`endpoint` varchar(255),
|
`endpoint` varchar(255),
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
INSERT INTO `jilo_agent_types` (`id`, `description`, `endpoint`) VALUES
|
INSERT INTO `jilo_agent_type` (`id`, `description`, `endpoint`) VALUES
|
||||||
(1,'jvb','/jvb'),
|
(1,'jvb','/jvb'),
|
||||||
(2,'jicofo','/jicofo'),
|
(2,'jicofo','/jicofo'),
|
||||||
(3,'prosody','/prosody'),
|
(3,'prosody','/prosody'),
|
||||||
|
@ -209,7 +209,7 @@ INSERT INTO `jilo_agent_types` (`id`, `description`, `endpoint`) VALUES
|
||||||
(5,'jibri','/jibri');
|
(5,'jibri','/jibri');
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `platforms` (
|
CREATE TABLE `platform` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`jitsi_url` varchar(255) NOT NULL,
|
`jitsi_url` varchar(255) NOT NULL,
|
||||||
|
@ -221,17 +221,17 @@ INSERT INTO `platforms` (`id`, `name`, `jitsi_url`, `jilo_database`) VALUES
|
||||||
(1,'example.com','https://meet.example.com','../../jilo/jilo.db');
|
(1,'example.com','https://meet.example.com','../../jilo/jilo.db');
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `hosts` (
|
CREATE TABLE `host` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`address` varchar(255) NOT NULL,
|
`address` varchar(255) NOT NULL,
|
||||||
`platform_id` int(11) NOT NULL,
|
`platform_id` int(11) NOT NULL,
|
||||||
`name` varchar(255),
|
`name` varchar(255),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `hosts_ibfk_1` FOREIGN KEY (`platform_id`) REFERENCES `platforms` (`id`)
|
CONSTRAINT `host_ibfk_1` FOREIGN KEY (`platform_id`) REFERENCES `platform` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE `jilo_agents` (
|
CREATE TABLE `jilo_agent` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`host_id` int(11) NOT NULL,
|
`host_id` int(11) NOT NULL,
|
||||||
`agent_type_id` int(11) NOT NULL,
|
`agent_type_id` int(11) NOT NULL,
|
||||||
|
@ -239,12 +239,12 @@ CREATE TABLE `jilo_agents` (
|
||||||
`secret_key` varchar(255),
|
`secret_key` varchar(255),
|
||||||
`check_period` int(11) DEFAULT 0,
|
`check_period` int(11) DEFAULT 0,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `jilo_agents_ibfk_1` FOREIGN KEY (`agent_type_id`) REFERENCES `jilo_agent_types` (`id`),
|
CONSTRAINT `jilo_agent_ibfk_1` FOREIGN KEY (`agent_type_id`) REFERENCES `jilo_agent_type` (`id`),
|
||||||
CONSTRAINT `jilo_agents_ibfk_2` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`)
|
CONSTRAINT `jilo_agent_ibfk_2` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
CREATE TABLE jilo_agent_checks (
|
CREATE TABLE `jilo_agent_check` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`agent_id` int(11),
|
`agent_id` int(11),
|
||||||
`timestamp` datetime DEFAULT current_timestamp(),
|
`timestamp` datetime DEFAULT current_timestamp(),
|
||||||
|
@ -252,9 +252,8 @@ CREATE TABLE jilo_agent_checks (
|
||||||
`response_time_ms` int(11),
|
`response_time_ms` int(11),
|
||||||
`response_content` varchar(255),
|
`response_content` varchar(255),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `jilo_agent_checks_ibfk_1` FOREIGN KEY (`agent_id`) REFERENCES `jilo_agents` (`id`)
|
CONSTRAINT `jilo_agent_check_ibfk_1` FOREIGN KEY (`agent_id`) REFERENCES `jilo_agent` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Log {
|
||||||
*/
|
*/
|
||||||
public function insertLog($userId, $message, $scope = 'user') {
|
public function insertLog($userId, $message, $scope = 'user') {
|
||||||
try {
|
try {
|
||||||
$sql = 'INSERT INTO logs
|
$sql = 'INSERT INTO log
|
||||||
(user_id, scope, message)
|
(user_id, scope, message)
|
||||||
VALUES
|
VALUES
|
||||||
(:user_id, :scope, :message)';
|
(:user_id, :scope, :message)';
|
||||||
|
@ -68,8 +68,8 @@ class Log {
|
||||||
|
|
||||||
// Base query with user join
|
// Base query with user join
|
||||||
$base_sql = 'SELECT l.*, u.username
|
$base_sql = 'SELECT l.*, u.username
|
||||||
FROM logs l
|
FROM log l
|
||||||
LEFT JOIN users u ON l.user_id = u.id';
|
LEFT JOIN user u ON l.user_id = u.id';
|
||||||
|
|
||||||
// Add scope condition
|
// Add scope condition
|
||||||
if ($scope === 'user') {
|
if ($scope === 'user') {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -49,9 +49,9 @@ class Register {
|
||||||
// hash the password, don't store it plain
|
// hash the password, don't store it plain
|
||||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
// insert into users table
|
// insert into user table
|
||||||
$sql = 'INSERT
|
$sql = 'INSERT
|
||||||
INTO users (username, password)
|
INTO user (username, password)
|
||||||
VALUES (:username, :password)';
|
VALUES (:username, :password)';
|
||||||
$query = $this->db->prepare($sql);
|
$query = $this->db->prepare($sql);
|
||||||
$query->bindValue(':username', $username);
|
$query->bindValue(':username', $username);
|
||||||
|
@ -64,9 +64,9 @@ class Register {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert the last user id into users_meta table
|
// insert the last user id into user_meta table
|
||||||
$sql2 = 'INSERT
|
$sql2 = 'INSERT
|
||||||
INTO users_meta (user_id)
|
INTO user_meta (user_id)
|
||||||
VALUES (:user_id)';
|
VALUES (:user_id)';
|
||||||
$query2 = $this->db->prepare($sql2);
|
$query2 = $this->db->prepare($sql2);
|
||||||
$query2->bindValue(':user_id', $this->db->lastInsertId());
|
$query2->bindValue(':user_id', $this->db->lastInsertId());
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -16,137 +16,235 @@ class RateLimitMiddlewareTest extends TestCase
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
// Set global IP for rate limiting
|
||||||
|
global $user_IP;
|
||||||
|
$user_IP = '8.8.8.8';
|
||||||
|
|
||||||
|
// Prepare DB for Github CI
|
||||||
|
$host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
|
||||||
|
$password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
|
||||||
|
|
||||||
// Set up test database
|
// Set up test database
|
||||||
$this->db = new Database([
|
$this->db = new Database([
|
||||||
'type' => 'sqlite',
|
'type' => 'mariadb',
|
||||||
'dbFile' => ':memory:'
|
'host' => $host,
|
||||||
|
'port' => '3306',
|
||||||
|
'dbname' => 'totalmeet_test',
|
||||||
|
'user' => 'test_totalmeet',
|
||||||
|
'password' => $password
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create rate limiter table
|
// Create rate limiter instance
|
||||||
$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);
|
$this->rateLimiter = new RateLimiter($this->db);
|
||||||
|
|
||||||
// Mock $_SERVER variables
|
// Drop tables if they exist
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
|
||||||
$_SERVER['REQUEST_URI'] = '/login';
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_page");
|
||||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_ip_blacklist");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_ip_whitelist");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS log");
|
||||||
|
|
||||||
// Define testing constant
|
// Create required tables with correct names from RateLimiter class
|
||||||
if (!defined('TESTING')) {
|
$this->db->getConnection()->exec("
|
||||||
define('TESTING', true);
|
CREATE TABLE IF NOT EXISTS security_rate_auth (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
username VARCHAR(255) NOT NULL,
|
||||||
|
attempted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_ip_username (ip_address, username)
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS security_rate_page (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
endpoint VARCHAR(255) NOT NULL,
|
||||||
|
request_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_ip_endpoint (ip_address, endpoint),
|
||||||
|
INDEX idx_request_time (request_time)
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS security_ip_blacklist (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
is_network BOOLEAN DEFAULT FALSE,
|
||||||
|
reason VARCHAR(255),
|
||||||
|
expiry_time TIMESTAMP NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_by VARCHAR(255),
|
||||||
|
UNIQUE KEY unique_ip (ip_address)
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS security_ip_whitelist (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
is_network BOOLEAN DEFAULT FALSE,
|
||||||
|
description VARCHAR(255),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_by VARCHAR(255),
|
||||||
|
UNIQUE KEY unique_ip (ip_address)
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Create log table
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS log (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
user_id INT,
|
||||||
|
scope VARCHAR(50) NOT NULL,
|
||||||
|
message TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Mock $_SERVER['REMOTE_ADDR'] with a non-whitelisted IP
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '8.8.8.8';
|
||||||
|
|
||||||
|
// Define PHPUNIT_RUNNING constant
|
||||||
|
if (!defined('PHPUNIT_RUNNING')) {
|
||||||
|
define('PHPUNIT_RUNNING', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
{
|
{
|
||||||
// Clean up rate limit records
|
// Clean up all rate limit records
|
||||||
$this->db->getConnection()->exec('DELETE FROM pages_rate_limits');
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_ip_blacklist");
|
||||||
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_ip_whitelist");
|
||||||
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_auth");
|
||||||
|
$this->db->getConnection()->exec("TRUNCATE TABLE log");
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRateLimitMiddleware()
|
public function testRateLimitMiddleware()
|
||||||
{
|
{
|
||||||
// Test multiple requests
|
// Clean any existing rate limit records
|
||||||
for ($i = 1; $i <= 5; $i++) {
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
$result = checkRateLimit($this->db, '/login');
|
|
||||||
|
|
||||||
if ($i <= 5) {
|
// Make 60 requests to reach the limit
|
||||||
// First 5 requests should pass
|
for ($i = 0; $i < 60; $i++) {
|
||||||
$this->assertTrue($result);
|
$result = checkRateLimit($this->db, '/login');
|
||||||
} else {
|
$this->assertTrue($result, "Request $i should be allowed");
|
||||||
// 6th and subsequent requests should be blocked
|
|
||||||
$this->assertFalse($result);
|
// Verify request was recorded
|
||||||
}
|
$stmt = $this->db->getConnection()->prepare("
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM security_rate_page
|
||||||
|
WHERE ip_address = ?
|
||||||
|
AND endpoint = ?
|
||||||
|
AND request_time >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)
|
||||||
|
");
|
||||||
|
$stmt->execute(['8.8.8.8', '/login']);
|
||||||
|
$count = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
|
||||||
|
$this->assertEquals($i + 1, $count, "Expected " . ($i + 1) . " requests to be recorded, got {$count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The 61st request should be blocked
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
|
$this->assertFalse($result, "Request should be blocked after 60 requests");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRateLimitBypass()
|
public function testRateLimitBypass()
|
||||||
{
|
{
|
||||||
// Test AJAX request bypass
|
// Clean any existing rate limit records and lists
|
||||||
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
$result = checkRateLimit($this->db, '/login');
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_ip_whitelist");
|
||||||
$this->assertTrue($result);
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_ip_blacklist");
|
||||||
|
|
||||||
|
// Add IP to whitelist and verify it was added
|
||||||
|
$stmt = $this->db->getConnection()->prepare("INSERT INTO security_ip_whitelist (ip_address, is_network, description, created_by) VALUES (?, 0, ?, 'PHPUnit')");
|
||||||
|
$stmt->execute(['8.8.8.8', 'Test whitelist']);
|
||||||
|
|
||||||
|
// Verify IP is in whitelist
|
||||||
|
$stmt = $this->db->getConnection()->prepare("SELECT COUNT(*) as count FROM security_ip_whitelist WHERE ip_address = ?");
|
||||||
|
$stmt->execute(['8.8.8.8']);
|
||||||
|
$count = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
|
||||||
|
$this->assertEquals(1, $count, "IP should be in whitelist");
|
||||||
|
|
||||||
|
// Should be able to make more requests than limit
|
||||||
|
for ($i = 0; $i < 100; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
|
$this->assertTrue($result, "Request $i should be allowed for whitelisted IP");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRateLimitReset()
|
public function testRateLimitReset()
|
||||||
{
|
{
|
||||||
// Use up the rate limit
|
// Clean any existing rate limit records
|
||||||
for ($i = 0; $i < 5; $i++) {
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
checkRateLimit($this->db, '/login');
|
|
||||||
|
// Make some requests
|
||||||
|
for ($i = 0; $i < 15; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for rate limit to reset (use a short window for testing)
|
// Manually expire old requests
|
||||||
sleep(2);
|
$this->db->getConnection()->exec("
|
||||||
|
DELETE FROM security_rate_page
|
||||||
|
WHERE request_time < DATE_SUB(NOW(), INTERVAL 1 MINUTE)
|
||||||
|
");
|
||||||
|
|
||||||
// Should be able to make request again
|
// Should be able to make requests again
|
||||||
$result = checkRateLimit($this->db, '/login');
|
$result = checkRateLimit($this->db, '/login');
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDifferentEndpoints()
|
public function testDifferentEndpoints()
|
||||||
{
|
{
|
||||||
// Use up rate limit for login
|
// Clean any existing rate limit records
|
||||||
for ($i = 0; $i < 5; $i++) {
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
checkRateLimit($this->db, '/login');
|
|
||||||
|
// Make requests to login endpoint (default limit: 60)
|
||||||
|
for ($i = 0; $i < 30; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
|
$this->assertTrue($result, "Request $i to /login should be allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should still be able to access different endpoint
|
// Clean up between endpoint tests
|
||||||
$result = checkRateLimit($this->db, '/dashboard');
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
$this->assertTrue($result);
|
|
||||||
|
// Make requests to register endpoint (limit: 5)
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/register');
|
||||||
|
$this->assertTrue($result, "Request $i to /register should be allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 6th request to register should be blocked
|
||||||
|
$result = checkRateLimit($this->db, '/register');
|
||||||
|
$this->assertFalse($result, "Request should be blocked after 5 requests to /register");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDifferentIpAddresses()
|
public function testDifferentIpAddresses()
|
||||||
{
|
{
|
||||||
// Use up rate limit for first IP
|
// Make requests from first IP
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
for ($i = 0; $i < 30; $i++) {
|
||||||
for ($i = 0; $i < 5; $i++) {
|
$result = checkRateLimit($this->db, '/login');
|
||||||
checkRateLimit($this->db, '/login');
|
$this->assertTrue($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Different IP should not be affected
|
// Change IP
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.2';
|
$_SERVER['REMOTE_ADDR'] = '8.8.4.4';
|
||||||
$result = checkRateLimit($this->db, '/login');
|
|
||||||
$this->assertTrue($result);
|
// Should be able to make requests from different IP
|
||||||
|
for ($i = 0; $i < 30; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWhitelistedIp()
|
public function testWhitelistedIp()
|
||||||
{
|
{
|
||||||
// Add IP to whitelist
|
// Add IP to whitelist
|
||||||
$this->db->execute(
|
$this->rateLimiter->addToWhitelist('8.8.8.8', false, 'Test whitelist', 'PHPUnit');
|
||||||
'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
|
// Should be able to make more requests than limit
|
||||||
for ($i = 0; $i < 10; $i++) {
|
for ($i = 0; $i < 50; $i++) {
|
||||||
$result = checkRateLimit($this->db, '/login');
|
$result = checkRateLimit($this->db, '/login');
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
}
|
}
|
||||||
|
@ -154,30 +252,39 @@ class RateLimitMiddlewareTest extends TestCase
|
||||||
|
|
||||||
public function testBlacklistedIp()
|
public function testBlacklistedIp()
|
||||||
{
|
{
|
||||||
// Add IP to blacklist
|
// Add IP to blacklist and verify it was added
|
||||||
$this->db->execute(
|
$this->db->getConnection()->exec("INSERT INTO security_ip_blacklist (ip_address, is_network, reason, created_by) VALUES ('8.8.8.8', 0, 'Test blacklist', 'system')");
|
||||||
'INSERT INTO ip_blacklist (ip_address, reason, created_by) VALUES (?, ?, ?)',
|
|
||||||
['127.0.0.1', 'Test blacklist', 'PHPUnit']
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should be blocked immediately
|
// Request should be blocked
|
||||||
$result = checkRateLimit($this->db, '/login');
|
$result = checkRateLimit($this->db, '/login');
|
||||||
$this->assertFalse($result);
|
$this->assertFalse($result, "Blacklisted IP should be blocked");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRateLimitPersistence()
|
public function testRateLimitPersistence()
|
||||||
{
|
{
|
||||||
// Use up some of the rate limit
|
// Clean any existing rate limit records
|
||||||
for ($i = 0; $i < 2; $i++) {
|
$this->db->getConnection()->exec("TRUNCATE TABLE security_rate_page");
|
||||||
checkRateLimit($this->db, '/login');
|
|
||||||
|
// Make 60 requests to reach the limit
|
||||||
|
for ($i = 0; $i < 60; $i++) {
|
||||||
|
$result = checkRateLimit($this->db, '/login');
|
||||||
|
$this->assertTrue($result, "Request $i should be allowed");
|
||||||
|
|
||||||
|
// Verify request was recorded
|
||||||
|
$stmt = $this->db->getConnection()->prepare("
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM security_rate_page
|
||||||
|
WHERE ip_address = ?
|
||||||
|
AND endpoint = ?
|
||||||
|
AND request_time >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)
|
||||||
|
");
|
||||||
|
$stmt->execute(['8.8.8.8', '/login']);
|
||||||
|
$count = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
|
||||||
|
$this->assertEquals($i + 1, $count, "Expected " . ($i + 1) . " requests to be recorded, got {$count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy and restart session
|
// The 61st request should be blocked
|
||||||
//session_destroy();
|
|
||||||
//session_start();
|
|
||||||
|
|
||||||
// Should still count previous requests
|
|
||||||
$result = checkRateLimit($this->db, '/login');
|
$result = checkRateLimit($this->db, '/login');
|
||||||
$this->assertTrue($result);
|
$this->assertFalse($result, "Request should be blocked after 60 requests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,9 @@ class AgentTest extends TestCase
|
||||||
'dbFile' => ':memory:'
|
'dbFile' => ':memory:'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create jilo_agents table
|
// Create jilo_agent table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE jilo_agents (
|
CREATE TABLE jilo_agent (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
host_id INTEGER NOT NULL,
|
host_id INTEGER NOT NULL,
|
||||||
agent_type_id INTEGER NOT NULL,
|
agent_type_id INTEGER NOT NULL,
|
||||||
|
@ -38,18 +38,18 @@ class AgentTest extends TestCase
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create jilo_agent_types table
|
// Create jilo_agent_type table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE jilo_agent_types (
|
CREATE TABLE jilo_agent_type (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
description TEXT NOT NULL,
|
description TEXT NOT NULL,
|
||||||
endpoint TEXT NOT NULL
|
endpoint TEXT NOT NULL
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create hosts table
|
// Create host table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE hosts (
|
CREATE TABLE host (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
platform_id INTEGER NOT NULL,
|
platform_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL
|
name TEXT NOT NULL
|
||||||
|
@ -58,12 +58,12 @@ class AgentTest extends TestCase
|
||||||
|
|
||||||
// Insert test host
|
// Insert test host
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
INSERT INTO hosts (id, platform_id, name) VALUES (1, 1, 'Test Host')
|
INSERT INTO host (id, platform_id, name) VALUES (1, 1, 'Test Host')
|
||||||
");
|
");
|
||||||
|
|
||||||
// Insert test agent type
|
// Insert test agent type
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
INSERT INTO jilo_agent_types (id, description, endpoint)
|
INSERT INTO jilo_agent_type (id, description, endpoint)
|
||||||
VALUES (1, 'Test Agent Type', '/api/test')
|
VALUES (1, 'Test Agent Type', '/api/test')
|
||||||
");
|
");
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class AgentTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify agent was created
|
// Verify agent was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM jilo_agents WHERE host_id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM jilo_agent WHERE host_id = ?');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$agent = $stmt->fetch(PDO::FETCH_ASSOC);
|
$agent = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ class AgentTest extends TestCase
|
||||||
$this->agent->addAgent($hostId, $data);
|
$this->agent->addAgent($hostId, $data);
|
||||||
|
|
||||||
// Get agent ID
|
// Get agent ID
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agents WHERE host_id = ? LIMIT 1');
|
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agent WHERE host_id = ? LIMIT 1');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ class AgentTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM jilo_agents WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM jilo_agent WHERE id = ?');
|
||||||
$stmt->execute([$agentId]);
|
$stmt->execute([$agentId]);
|
||||||
$agent = $stmt->fetch(PDO::FETCH_ASSOC);
|
$agent = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ class AgentTest extends TestCase
|
||||||
$this->agent->addAgent($hostId, $data);
|
$this->agent->addAgent($hostId, $data);
|
||||||
|
|
||||||
// Get agent ID
|
// Get agent ID
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agents WHERE host_id = ? LIMIT 1');
|
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agent WHERE host_id = ? LIMIT 1');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ class AgentTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify deletion
|
// Verify deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM jilo_agents WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM jilo_agent WHERE id = ?');
|
||||||
$stmt->execute([$agentId]);
|
$stmt->execute([$agentId]);
|
||||||
$count = $stmt->fetch(PDO::FETCH_COLUMN);
|
$count = $stmt->fetch(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ class AgentTest extends TestCase
|
||||||
$this->agent->addAgent($hostId, $data);
|
$this->agent->addAgent($hostId, $data);
|
||||||
|
|
||||||
// Get agent ID
|
// Get agent ID
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agents WHERE host_id = ? LIMIT 1');
|
$stmt = $this->db->getConnection()->prepare('SELECT id FROM jilo_agent WHERE host_id = ? LIMIT 1');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
$agentId = $stmt->fetch(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ class HostTest extends TestCase
|
||||||
'dbFile' => ':memory:'
|
'dbFile' => ':memory:'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create hosts table
|
// Create host table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE hosts (
|
CREATE TABLE host (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
platform_id INTEGER NOT NULL,
|
platform_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
@ -33,9 +33,9 @@ class HostTest extends TestCase
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create jilo_agents table for relationship testing
|
// Create jilo_agent table for relationship testing
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE jilo_agents (
|
CREATE TABLE jilo_agent (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
host_id INTEGER NOT NULL,
|
host_id INTEGER NOT NULL,
|
||||||
agent_type_id INTEGER NOT NULL,
|
agent_type_id INTEGER NOT NULL,
|
||||||
|
@ -60,7 +60,7 @@ class HostTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify host was created
|
// Verify host was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM hosts WHERE platform_id = ? AND name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM host WHERE platform_id = ? AND name = ?');
|
||||||
$stmt->execute([$data['platform_id'], $data['name']]);
|
$stmt->execute([$data['platform_id'], $data['name']]);
|
||||||
$host = $stmt->fetch(\PDO::FETCH_ASSOC);
|
$host = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ class HostTest extends TestCase
|
||||||
$this->host->addHost($data);
|
$this->host->addHost($data);
|
||||||
|
|
||||||
// Get host ID
|
// Get host ID
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT id FROM hosts WHERE platform_id = ? AND name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT id FROM host WHERE platform_id = ? AND name = ?');
|
||||||
$stmt->execute([$data['platform_id'], $data['name']]);
|
$stmt->execute([$data['platform_id'], $data['name']]);
|
||||||
$hostId = $stmt->fetch(\PDO::FETCH_COLUMN);
|
$hostId = $stmt->fetch(\PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ class HostTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM hosts WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM host WHERE id = ?');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$host = $stmt->fetch(\PDO::FETCH_ASSOC);
|
$host = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -141,13 +141,13 @@ class HostTest extends TestCase
|
||||||
$this->host->addHost($data);
|
$this->host->addHost($data);
|
||||||
|
|
||||||
// Get host ID
|
// Get host ID
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT id FROM hosts WHERE platform_id = ? AND name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT id FROM host WHERE platform_id = ? AND name = ?');
|
||||||
$stmt->execute([$data['platform_id'], $data['name']]);
|
$stmt->execute([$data['platform_id'], $data['name']]);
|
||||||
$hostId = $stmt->fetch(\PDO::FETCH_COLUMN);
|
$hostId = $stmt->fetch(\PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
// Add test agent to the host
|
// Add test agent to the host
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
INSERT INTO jilo_agents (host_id, agent_type_id, url, secret_key)
|
INSERT INTO jilo_agent (host_id, agent_type_id, url, secret_key)
|
||||||
VALUES ($hostId, 1, 'http://test:8080', 'secret')
|
VALUES ($hostId, 1, 'http://test:8080', 'secret')
|
||||||
");
|
");
|
||||||
|
|
||||||
|
@ -156,13 +156,13 @@ class HostTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify host deletion
|
// Verify host deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM hosts WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM host WHERE id = ?');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$hostCount = $stmt->fetch(\PDO::FETCH_COLUMN);
|
$hostCount = $stmt->fetch(\PDO::FETCH_COLUMN);
|
||||||
$this->assertEquals(0, $hostCount);
|
$this->assertEquals(0, $hostCount);
|
||||||
|
|
||||||
// Verify agent deletion
|
// Verify agent deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM jilo_agents WHERE host_id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) FROM jilo_agent WHERE host_id = ?');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$agentCount = $stmt->fetch(\PDO::FETCH_COLUMN);
|
$agentCount = $stmt->fetch(\PDO::FETCH_COLUMN);
|
||||||
$this->assertEquals(0, $agentCount);
|
$this->assertEquals(0, $agentCount);
|
||||||
|
|
|
@ -1,138 +1,261 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once dirname(__DIR__, 3) . '/app/classes/database.php';
|
require_once dirname(__DIR__, 3) . '/app/classes/database.php';
|
||||||
require_once dirname(__DIR__, 3) . '/app/classes/log.php';
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestLogger class for testing log functionality
|
||||||
|
* This is a simplified implementation that mimics the plugin's Log class
|
||||||
|
* but with a different name to avoid conflicts
|
||||||
|
*/
|
||||||
|
class TestLogger {
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
public function __construct($database) {
|
||||||
|
$this->db = $database->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertLog($userId, $message, $scope = 'user') {
|
||||||
|
try {
|
||||||
|
$sql = 'INSERT INTO log
|
||||||
|
(user_id, scope, message)
|
||||||
|
VALUES
|
||||||
|
(:user_id, :scope, :message)';
|
||||||
|
|
||||||
|
$query = $this->db->prepare($sql);
|
||||||
|
$query->execute([
|
||||||
|
':user_id' => $userId,
|
||||||
|
':scope' => $scope,
|
||||||
|
':message' => $message,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readLog($userId, $scope, $offset = 0, $items_per_page = '', $filters = []) {
|
||||||
|
$params = [];
|
||||||
|
$where_clauses = [];
|
||||||
|
|
||||||
|
// Base query with user join
|
||||||
|
$base_sql = 'SELECT l.*, u.username
|
||||||
|
FROM log l
|
||||||
|
LEFT JOIN user u ON l.user_id = u.id';
|
||||||
|
|
||||||
|
// Add scope condition
|
||||||
|
if ($scope === 'user') {
|
||||||
|
$where_clauses[] = 'l.user_id = :user_id';
|
||||||
|
$params[':user_id'] = $userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add time range filters if specified
|
||||||
|
if (!empty($filters['from_time'])) {
|
||||||
|
$where_clauses[] = 'l.time >= :from_time';
|
||||||
|
$params[':from_time'] = $filters['from_time'] . ' 00:00:00';
|
||||||
|
}
|
||||||
|
if (!empty($filters['until_time'])) {
|
||||||
|
$where_clauses[] = 'l.time <= :until_time';
|
||||||
|
$params[':until_time'] = $filters['until_time'] . ' 23:59:59';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add message search if specified
|
||||||
|
if (!empty($filters['message'])) {
|
||||||
|
$where_clauses[] = 'l.message LIKE :message';
|
||||||
|
$params[':message'] = '%' . $filters['message'] . '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add user ID search if specified
|
||||||
|
if (!empty($filters['id'])) {
|
||||||
|
$where_clauses[] = 'l.user_id = :search_user_id';
|
||||||
|
$params[':search_user_id'] = $filters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine WHERE clauses
|
||||||
|
$sql = $base_sql;
|
||||||
|
if (!empty($where_clauses)) {
|
||||||
|
$sql .= ' WHERE ' . implode(' AND ', $where_clauses);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ordering
|
||||||
|
$sql .= ' ORDER BY l.time DESC';
|
||||||
|
|
||||||
|
// Add pagination
|
||||||
|
if ($items_per_page) {
|
||||||
|
$items_per_page = (int)$items_per_page;
|
||||||
|
$sql .= ' LIMIT ' . $offset . ',' . $items_per_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->prepare($sql);
|
||||||
|
$query->execute($params);
|
||||||
|
|
||||||
|
return $query->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LogTest extends TestCase
|
class LogTest extends TestCase
|
||||||
{
|
{
|
||||||
private $db;
|
private $db;
|
||||||
private $log;
|
private $log;
|
||||||
|
private $testUserId;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
// Prepare DB for Github CI
|
||||||
|
$host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
|
||||||
|
$password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
|
||||||
|
|
||||||
// Set up test database
|
// Set up test database
|
||||||
$this->db = new Database([
|
$this->db = new Database([
|
||||||
'type' => 'sqlite',
|
'type' => 'mariadb',
|
||||||
'dbFile' => ':memory:'
|
'host' => $host,
|
||||||
|
'port' => '3306',
|
||||||
|
'dbname' => 'totalmeet_test',
|
||||||
|
'user' => 'test_totalmeet',
|
||||||
|
'password' => $password
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create users table
|
// Create user table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE users (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
username TEXT NOT NULL
|
username VARCHAR(255) NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create test user
|
// Create log table with the expected schema from Log class
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
INSERT INTO users (id, username) VALUES (1, 'testuser'), (2, 'testuser2')
|
CREATE TABLE IF NOT EXISTS log (
|
||||||
");
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
user_id INT,
|
||||||
// Create logs table
|
scope VARCHAR(50) NOT NULL DEFAULT 'user',
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE logs (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
user_id INTEGER,
|
|
||||||
scope TEXT NOT NULL,
|
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
FOREIGN KEY (user_id) REFERENCES user(id)
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
$this->log = new Log($this->db);
|
// Create test users with all required fields
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
INSERT INTO user (username, password, email)
|
||||||
|
VALUES
|
||||||
|
('testuser', 'password123', 'testuser@example.com'),
|
||||||
|
('testuser2', 'password123', 'testuser2@example.com')
|
||||||
|
");
|
||||||
|
|
||||||
|
// Store test user ID for later use
|
||||||
|
$stmt = $this->db->getConnection()->query("SELECT id FROM user WHERE username = 'testuser' LIMIT 1");
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$this->testUserId = $user['id'];
|
||||||
|
|
||||||
|
// Create a TestLogger instance that will be used by the app's Log wrapper
|
||||||
|
$this->log = new TestLogger($this->db);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
// Drop tables in correct order (respect foreign key constraints)
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS log");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
||||||
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInsertLog()
|
public function testInsertLog()
|
||||||
{
|
{
|
||||||
$result = $this->log->insertLog(1, 'Test message', 'test');
|
$result = $this->log->insertLog($this->testUserId, 'Test message', 'test');
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
$stmt = $this->db->getConnection()->prepare("SELECT * FROM logs WHERE scope = ?");
|
// Verify the log was inserted
|
||||||
$stmt->execute(['test']);
|
$stmt = $this->db->getConnection()->query("SELECT * FROM log WHERE user_id = {$this->testUserId} LIMIT 1");
|
||||||
$log = $stmt->fetch(PDO::FETCH_ASSOC);
|
$log = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$this->assertEquals(1, $log['user_id']);
|
|
||||||
$this->assertEquals('Test message', $log['message']);
|
$this->assertEquals('Test message', $log['message']);
|
||||||
$this->assertEquals('test', $log['scope']);
|
$this->assertEquals('test', $log['scope']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadLog()
|
public function testReadLog()
|
||||||
{
|
{
|
||||||
// Insert test logs
|
// Insert some test logs with a delay to ensure order
|
||||||
$this->log->insertLog(1, 'Test message 1', 'user');
|
$this->log->insertLog($this->testUserId, 'Test message 1', 'user');
|
||||||
$this->log->insertLog(1, 'Test message 2', 'user');
|
sleep(1); // Ensure different timestamps
|
||||||
|
$this->log->insertLog($this->testUserId, 'Test message 2', 'user');
|
||||||
|
|
||||||
$logs = $this->log->readLog(1, 'user');
|
$logs = $this->log->readLog($this->testUserId, 'user');
|
||||||
$this->assertCount(2, $logs);
|
$this->assertCount(2, $logs);
|
||||||
$this->assertEquals('Test message 1', $logs[0]['message']);
|
$this->assertEquals('Test message 2', $logs[0]['message']); // Most recent first (by time)
|
||||||
$this->assertEquals('Test message 2', $logs[1]['message']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadLogWithTimeFilter()
|
public function testReadLogWithTimeFilter()
|
||||||
{
|
{
|
||||||
// Insert test logs with different times
|
// First message from yesterday
|
||||||
$this->log->insertLog(1, 'Old message', 'user');
|
$yesterday = date('Y-m-d', strtotime('-1 day'));
|
||||||
sleep(1); // Ensure different timestamps
|
$stmt = $this->db->getConnection()->prepare("
|
||||||
$this->log->insertLog(1, 'New message', 'user');
|
INSERT INTO log (user_id, scope, message, time)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
");
|
||||||
|
$stmt->execute([$this->testUserId, 'user', 'Test message 1', $yesterday . ' 12:00:00']);
|
||||||
|
|
||||||
$now = date('Y-m-d H:i:s');
|
// Second message from today
|
||||||
$oneHourAgo = date('Y-m-d H:i:s', strtotime('-1 hour'));
|
$today = date('Y-m-d');
|
||||||
|
$stmt->execute([$this->testUserId, 'user', 'Test message 2', $today . ' 12:00:00']);
|
||||||
|
|
||||||
$logs = $this->log->readLog(1, 'user', 0, '', [
|
// Should get only today's messages
|
||||||
'from_time' => $oneHourAgo,
|
$logs = $this->log->readLog($this->testUserId, 'user', 0, '', [
|
||||||
'until_time' => $now
|
'from_time' => $today
|
||||||
]);
|
]);
|
||||||
|
$this->assertCount(1, $logs);
|
||||||
$this->assertCount(2, $logs);
|
$this->assertEquals('Test message 2', $logs[0]['message']); // Most recent first
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadLogWithPagination()
|
public function testReadLogWithPagination()
|
||||||
{
|
{
|
||||||
// Insert test logs
|
// Insert multiple test logs with delays to ensure order
|
||||||
$this->log->insertLog(1, 'Message 1', 'user');
|
for ($i = 1; $i <= 5; $i++) {
|
||||||
$this->log->insertLog(1, 'Message 2', 'user');
|
$this->log->insertLog($this->testUserId, "Test message $i", 'user');
|
||||||
$this->log->insertLog(1, 'Message 3', 'user');
|
sleep(1); // Ensure different timestamps
|
||||||
|
}
|
||||||
|
|
||||||
// Test with limit
|
// Get all logs to verify total
|
||||||
$logs = $this->log->readLog(1, 'user', 0, 2);
|
$allLogs = $this->log->readLog($this->testUserId, 'user');
|
||||||
|
$this->assertCount(5, $allLogs);
|
||||||
|
|
||||||
|
// Get first page (offset 0, limit 2)
|
||||||
|
$logs = $this->log->readLog($this->testUserId, 'user', 0, 2);
|
||||||
$this->assertCount(2, $logs);
|
$this->assertCount(2, $logs);
|
||||||
|
$this->assertEquals('Test message 5', $logs[0]['message']); // Most recent first
|
||||||
|
$this->assertEquals('Test message 4', $logs[1]['message']);
|
||||||
|
|
||||||
// Test with offset
|
// Get second page (offset 2, limit 2)
|
||||||
$logs = $this->log->readLog(1, 'user', 2, 2);
|
$logs = $this->log->readLog($this->testUserId, 'user', 2, 2);
|
||||||
$this->assertCount(1, $logs);
|
$this->assertCount(2, $logs);
|
||||||
|
$this->assertEquals('Test message 3', $logs[0]['message']);
|
||||||
|
$this->assertEquals('Test message 2', $logs[1]['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadLogWithMessageFilter()
|
public function testReadLogWithMessageFilter()
|
||||||
{
|
{
|
||||||
// Insert test logs
|
// Insert test logs with different messages and delays
|
||||||
$this->log->insertLog(1, 'Test message', 'user');
|
$this->log->insertLog($this->testUserId, 'Test message ABC', 'user');
|
||||||
$this->log->insertLog(1, 'Another message', 'user');
|
sleep(1); // Ensure different timestamps
|
||||||
|
$this->log->insertLog($this->testUserId, 'Test message XYZ', 'user');
|
||||||
|
sleep(1); // Ensure different timestamps
|
||||||
|
$this->log->insertLog($this->testUserId, 'Different message', 'user');
|
||||||
|
|
||||||
$logs = $this->log->readLog(1, 'user', 0, '', [
|
// Filter by message content
|
||||||
'message' => 'Test'
|
$logs = $this->log->readLog($this->testUserId, 'user', 0, '', ['message' => 'Test message']);
|
||||||
]);
|
$this->assertCount(2, $logs);
|
||||||
|
|
||||||
$this->assertCount(1, $logs);
|
// Verify filtered results
|
||||||
$this->assertEquals('Test message', $logs[0]['message']);
|
foreach ($logs as $log) {
|
||||||
}
|
$this->assertStringContainsString('Test message', $log['message']);
|
||||||
|
}
|
||||||
public function testReadLogWithUserFilter()
|
|
||||||
{
|
|
||||||
// Insert test logs for different users
|
|
||||||
$this->log->insertLog(1, 'User 1 message', 'user');
|
|
||||||
$this->log->insertLog(2, 'User 2 message', 'user');
|
|
||||||
|
|
||||||
$logs = $this->log->readLog(1, 'user', 0, '', [
|
|
||||||
'id' => 1
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertCount(1, $logs);
|
|
||||||
$this->assertEquals('User 1 message', $logs[0]['message']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,26 +20,26 @@ class PlatformTest extends TestCase
|
||||||
'dbFile' => ':memory:'
|
'dbFile' => ':memory:'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create hosts table
|
// Create host table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE hosts (
|
CREATE TABLE host (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
platform_id INTEGER NOT NULL,
|
platform_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL
|
name TEXT NOT NULL
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create jilo_agents table
|
// Create jilo_agent table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE jilo_agents (
|
CREATE TABLE jilo_agent (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
host_id INTEGER NOT NULL
|
host_id INTEGER NOT NULL
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create platforms table
|
// Create platform table
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE platforms (
|
CREATE TABLE platform (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
jitsi_url TEXT NOT NULL,
|
jitsi_url TEXT NOT NULL,
|
||||||
|
@ -64,7 +64,7 @@ class PlatformTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify platform was created
|
// Verify platform was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM platforms WHERE name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM platform WHERE name = ?');
|
||||||
$stmt->execute([$data['name']]);
|
$stmt->execute([$data['name']]);
|
||||||
$platform = $stmt->fetch(PDO::FETCH_ASSOC);
|
$platform = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class PlatformTest extends TestCase
|
||||||
public function testGetPlatformDetails()
|
public function testGetPlatformDetails()
|
||||||
{
|
{
|
||||||
// Create test platform
|
// Create test platform
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO platforms (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
$stmt = $this->db->getConnection()->prepare('INSERT INTO platform (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
||||||
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
||||||
$platformId = $this->db->getConnection()->lastInsertId();
|
$platformId = $this->db->getConnection()->lastInsertId();
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ class PlatformTest extends TestCase
|
||||||
public function testEditPlatform()
|
public function testEditPlatform()
|
||||||
{
|
{
|
||||||
// Create test platform
|
// Create test platform
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO platforms (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
$stmt = $this->db->getConnection()->prepare('INSERT INTO platform (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
||||||
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
||||||
$platformId = $this->db->getConnection()->lastInsertId();
|
$platformId = $this->db->getConnection()->lastInsertId();
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class PlatformTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM platforms WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT * FROM platform WHERE id = ?');
|
||||||
$stmt->execute([$platformId]);
|
$stmt->execute([$platformId]);
|
||||||
$platform = $stmt->fetch(PDO::FETCH_ASSOC);
|
$platform = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -120,36 +120,36 @@ class PlatformTest extends TestCase
|
||||||
public function testDeletePlatform()
|
public function testDeletePlatform()
|
||||||
{
|
{
|
||||||
// Create test platform
|
// Create test platform
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO platforms (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
$stmt = $this->db->getConnection()->prepare('INSERT INTO platform (name, jitsi_url, jilo_database) VALUES (?, ?, ?)');
|
||||||
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
$stmt->execute(['Test platform', 'https://jitsi.example.com', '/path/to/jilo.db']);
|
||||||
$platformId = $this->db->getConnection()->lastInsertId();
|
$platformId = $this->db->getConnection()->lastInsertId();
|
||||||
|
|
||||||
// Create test host
|
// Create test host
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO hosts (platform_id, name) VALUES (?, ?)');
|
$stmt = $this->db->getConnection()->prepare('INSERT INTO host (platform_id, name) VALUES (?, ?)');
|
||||||
$stmt->execute([$platformId, 'Test host']);
|
$stmt->execute([$platformId, 'Test host']);
|
||||||
$hostId = $this->db->getConnection()->lastInsertId();
|
$hostId = $this->db->getConnection()->lastInsertId();
|
||||||
|
|
||||||
// Create test agent
|
// Create test agent
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO jilo_agents (host_id) VALUES (?)');
|
$stmt = $this->db->getConnection()->prepare('INSERT INTO jilo_agent (host_id) VALUES (?)');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
|
|
||||||
$result = $this->platform->deletePlatform($platformId);
|
$result = $this->platform->deletePlatform($platformId);
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify platform deletion
|
// Verify platform deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platforms WHERE id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platform WHERE id = ?');
|
||||||
$stmt->execute([$platformId]);
|
$stmt->execute([$platformId]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(0, $result['count']);
|
$this->assertEquals(0, $result['count']);
|
||||||
|
|
||||||
// Verify host deletion
|
// Verify host deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM hosts WHERE platform_id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM host WHERE platform_id = ?');
|
||||||
$stmt->execute([$platformId]);
|
$stmt->execute([$platformId]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(0, $result['count']);
|
$this->assertEquals(0, $result['count']);
|
||||||
|
|
||||||
// Verify agent deletion
|
// Verify agent deletion
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM jilo_agents WHERE host_id = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM jilo_agent WHERE host_id = ?');
|
||||||
$stmt->execute([$hostId]);
|
$stmt->execute([$hostId]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(0, $result['count']);
|
$this->assertEquals(0, $result['count']);
|
||||||
|
@ -167,7 +167,7 @@ class PlatformTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify platform was created
|
// Verify platform was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platforms WHERE name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platform WHERE name = ?');
|
||||||
$stmt->execute([$validData['name']]);
|
$stmt->execute([$validData['name']]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(1, $result['count']);
|
$this->assertEquals(1, $result['count']);
|
||||||
|
@ -182,7 +182,7 @@ class PlatformTest extends TestCase
|
||||||
$this->assertIsString($result); // Should return error message
|
$this->assertIsString($result); // Should return error message
|
||||||
|
|
||||||
// Verify platform was not created
|
// Verify platform was not created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platforms WHERE name = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platform WHERE name = ?');
|
||||||
$stmt->execute([$invalidData['name']]);
|
$stmt->execute([$invalidData['name']]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(0, $result['count']);
|
$this->assertEquals(0, $result['count']);
|
||||||
|
@ -205,7 +205,7 @@ class PlatformTest extends TestCase
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify platform was created
|
// Verify platform was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platforms WHERE jilo_database = ?');
|
$stmt = $this->db->getConnection()->prepare('SELECT COUNT(*) as count FROM platform WHERE jilo_database = ?');
|
||||||
$stmt->execute([$tempDb]);
|
$stmt->execute([$tempDb]);
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$this->assertEquals(1, $result['count']);
|
$this->assertEquals(1, $result['count']);
|
||||||
|
|
|
@ -8,103 +8,99 @@ use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class RateLimiterTest extends TestCase
|
class RateLimiterTest extends TestCase
|
||||||
{
|
{
|
||||||
private $rateLimiter;
|
|
||||||
private $db;
|
private $db;
|
||||||
|
private $rateLimiter;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
// Set up in-memory SQLite database
|
// Prepare DB for Github CI
|
||||||
|
$host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
|
||||||
|
$password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
|
||||||
|
|
||||||
|
// Set up test database
|
||||||
$this->db = new Database([
|
$this->db = new Database([
|
||||||
'type' => 'sqlite',
|
'type' => 'mariadb',
|
||||||
'dbFile' => ':memory:'
|
'host' => $host,
|
||||||
|
'port' => '3306',
|
||||||
|
'dbname' => 'totalmeet_test',
|
||||||
|
'user' => 'test_totalmeet',
|
||||||
|
'password' => $password
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// The RateLimiter constructor will create all necessary tables
|
||||||
$this->rateLimiter = new RateLimiter($this->db);
|
$this->rateLimiter = new RateLimiter($this->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
// Drop tables in correct order
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS {$this->rateLimiter->authRatelimitTable}");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS {$this->rateLimiter->pagesRatelimitTable}");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS {$this->rateLimiter->blacklistTable}");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS {$this->rateLimiter->whitelistTable}");
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetRecentAttempts()
|
public function testGetRecentAttempts()
|
||||||
{
|
{
|
||||||
$ip = '127.0.0.1';
|
$ip = '8.8.8.8';
|
||||||
$username = 'testuser';
|
|
||||||
|
|
||||||
// Clean up any existing attempts first
|
// Record some login attempts
|
||||||
$stmt = $this->db->getConnection()->prepare("DELETE FROM {$this->rateLimiter->authRatelimitTable} WHERE ip_address = ?");
|
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->authRatelimitTable}
|
||||||
$stmt->execute([$ip]);
|
(ip_address, username, attempted_at) VALUES (?, ?, NOW())");
|
||||||
|
|
||||||
|
// Add 3 attempts
|
||||||
|
for ($i = 0; $i < 3; $i++) {
|
||||||
|
$stmt->execute([$ip, 'testuser']);
|
||||||
|
}
|
||||||
|
|
||||||
// Initially should have no attempts
|
|
||||||
$attempts = $this->rateLimiter->getRecentAttempts($ip);
|
$attempts = $this->rateLimiter->getRecentAttempts($ip);
|
||||||
$this->assertEquals(0, $attempts);
|
$this->assertEquals(3, $attempts);
|
||||||
|
|
||||||
// Add a login attempt
|
|
||||||
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->authRatelimitTable} (ip_address, username) VALUES (?, ?)");
|
|
||||||
$stmt->execute([$ip, $username]);
|
|
||||||
|
|
||||||
// Should now have 1 attempt
|
|
||||||
$attempts = $this->rateLimiter->getRecentAttempts($ip);
|
|
||||||
$this->assertEquals(1, $attempts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIpBlacklisting()
|
public function testIsIpBlacklisted()
|
||||||
{
|
{
|
||||||
$ip = '192.0.2.1'; // Using TEST-NET-1 range
|
$ip = '8.8.8.8';
|
||||||
|
|
||||||
// Should be blacklisted by default (TEST-NET-1 range)
|
|
||||||
$this->assertTrue($this->rateLimiter->isIpBlacklisted($ip));
|
|
||||||
|
|
||||||
// Test with non-blacklisted IP
|
|
||||||
$nonBlacklistedIp = '8.8.8.8'; // Google DNS
|
|
||||||
$this->assertFalse($this->rateLimiter->isIpBlacklisted($nonBlacklistedIp));
|
|
||||||
|
|
||||||
// Add IP to blacklist
|
// Add IP to blacklist
|
||||||
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->blacklistTable} (ip_address, reason) VALUES (?, ?)");
|
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->blacklistTable}
|
||||||
$stmt->execute([$nonBlacklistedIp, 'Test blacklist']);
|
(ip_address, is_network, reason) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$ip, 0, 'Test blacklist']); // Explicitly set is_network to 0 (false)
|
||||||
|
|
||||||
// IP should now be blacklisted
|
|
||||||
$this->assertTrue($this->rateLimiter->isIpBlacklisted($nonBlacklistedIp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testIpWhitelisting()
|
|
||||||
{
|
|
||||||
$ip = '127.0.0.1'; // Localhost
|
|
||||||
|
|
||||||
// Clean up any existing whitelist entries
|
|
||||||
$stmt = $this->db->getConnection()->prepare("DELETE FROM {$this->rateLimiter->whitelistTable} WHERE ip_address = ?");
|
|
||||||
$stmt->execute([$ip]);
|
|
||||||
|
|
||||||
// Add to whitelist
|
|
||||||
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->whitelistTable} (ip_address, description) VALUES (?, ?)");
|
|
||||||
$stmt->execute([$ip, 'Test whitelist']);
|
|
||||||
|
|
||||||
// Should be whitelisted
|
|
||||||
$this->assertTrue($this->rateLimiter->isIpWhitelisted($ip));
|
|
||||||
|
|
||||||
// Test with non-whitelisted IP
|
|
||||||
$nonWhitelistedIp = '8.8.8.8'; // Google DNS
|
|
||||||
$this->assertFalse($this->rateLimiter->isIpWhitelisted($nonWhitelistedIp));
|
|
||||||
|
|
||||||
// Add to whitelist
|
|
||||||
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->whitelistTable} (ip_address, description) VALUES (?, ?)");
|
|
||||||
$stmt->execute([$nonWhitelistedIp, 'Test whitelist']);
|
|
||||||
|
|
||||||
// Should now be whitelisted
|
|
||||||
$this->assertTrue($this->rateLimiter->isIpWhitelisted($nonWhitelistedIp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testIpRangeBlacklisting()
|
|
||||||
{
|
|
||||||
$ip = '8.8.8.8'; // Google DNS
|
|
||||||
$networkIp = '8.8.8.0/24'; // Network containing Google DNS
|
|
||||||
|
|
||||||
// Initially IP should not be blacklisted
|
|
||||||
$this->assertFalse($this->rateLimiter->isIpBlacklisted($ip));
|
|
||||||
|
|
||||||
// Add network to blacklist
|
|
||||||
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->blacklistTable} (ip_address, is_network, reason) VALUES (?, 1, ?)");
|
|
||||||
$stmt->execute([$networkIp, 'Test network blacklist']);
|
|
||||||
|
|
||||||
// IP in range should now be blacklisted
|
|
||||||
$this->assertTrue($this->rateLimiter->isIpBlacklisted($ip));
|
$this->assertTrue($this->rateLimiter->isIpBlacklisted($ip));
|
||||||
|
$this->assertFalse($this->rateLimiter->isIpBlacklisted('8.8.4.4'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsIpWhitelisted()
|
||||||
|
{
|
||||||
|
// Test with an IP that's not in the default whitelisted ranges
|
||||||
|
$ip = '8.8.8.8'; // Google's DNS, definitely not in private ranges
|
||||||
|
|
||||||
|
// Add IP to whitelist
|
||||||
|
$stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->whitelistTable}
|
||||||
|
(ip_address, is_network, description) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$ip, 0, 'Test whitelist']); // Explicitly set is_network to 0 (false)
|
||||||
|
|
||||||
|
$this->assertTrue($this->rateLimiter->isIpWhitelisted($ip));
|
||||||
|
$this->assertFalse($this->rateLimiter->isIpWhitelisted('8.8.4.4')); // Another IP not in private ranges
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRateLimitCheck()
|
||||||
|
{
|
||||||
|
$ip = '8.8.8.8'; // Use non-whitelisted IP
|
||||||
|
$endpoint = '/test';
|
||||||
|
|
||||||
|
// First request should be allowed
|
||||||
|
$this->assertTrue($this->rateLimiter->isPageRequestAllowed($ip, $endpoint));
|
||||||
|
|
||||||
|
// Add requests up to the limit
|
||||||
|
for ($i = 0; $i < 60; $i++) { // Default limit is 60 per minute
|
||||||
|
$this->rateLimiter->recordPageRequest($ip, $endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next request should be rate limited
|
||||||
|
$this->assertFalse($this->rateLimiter->isPageRequestAllowed($ip, $endpoint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,78 +17,64 @@ class UserRegisterTest extends TestCase
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
// Set up test database
|
// Prepare DB for Github CI
|
||||||
|
$host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
|
||||||
|
$password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
|
||||||
|
|
||||||
$this->db = new Database([
|
$this->db = new Database([
|
||||||
'type' => 'sqlite',
|
'type' => 'mariadb',
|
||||||
'dbFile' => ':memory:'
|
'host' => $host,
|
||||||
|
'port' => '3306',
|
||||||
|
'dbname' => 'totalmeet_test',
|
||||||
|
'user' => 'test_totalmeet',
|
||||||
|
'password' => $password
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create users table
|
// Create user table with MariaDB syntax
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE users (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username VARCHAR(255) NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL
|
password VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create users_meta table
|
// Create user_meta table with MariaDB syntax
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE users_meta (
|
CREATE TABLE IF NOT EXISTS user_meta (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INT NOT NULL,
|
||||||
name TEXT,
|
name VARCHAR(255),
|
||||||
email TEXT,
|
email VARCHAR(255),
|
||||||
timezone TEXT,
|
timezone VARCHAR(100),
|
||||||
bio TEXT,
|
bio TEXT,
|
||||||
avatar TEXT,
|
avatar VARCHAR(255),
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Create security_rate_auth table for rate limiting
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS security_rate_auth (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
username VARCHAR(255) NOT NULL,
|
||||||
|
attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_ip_username (ip_address, username)
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create user_2fa table for two-factor authentication
|
// Create user_2fa table for two-factor authentication
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE user_2fa (
|
CREATE TABLE IF NOT EXISTS user_2fa (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INT NOT NULL,
|
||||||
secret_key TEXT NOT NULL,
|
secret_key VARCHAR(255) NOT NULL,
|
||||||
backup_codes TEXT,
|
backup_codes TEXT,
|
||||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create tables for rate limiter
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE login_attempts (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ip_address TEXT NOT NULL,
|
|
||||||
username TEXT NOT NULL,
|
|
||||||
attempted_at TEXT DEFAULT (DATETIME('now'))
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$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
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$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
|
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
|
@ -96,91 +82,116 @@ class UserRegisterTest extends TestCase
|
||||||
$this->user = new User($this->db);
|
$this->user = new User($this->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
// Drop tables in correct order
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_2fa");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_meta");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
public function testRegister()
|
public function testRegister()
|
||||||
{
|
{
|
||||||
$result = $this->register->register('testuser', 'password123');
|
// Register a new user
|
||||||
|
$username = 'testuser';
|
||||||
|
$password = 'password123';
|
||||||
|
|
||||||
|
$result = $this->register->register($username, $password);
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify user was created
|
// Verify user was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM users WHERE username = ?');
|
$stmt = $this->db->getConnection()->prepare("SELECT * FROM user WHERE username = ?");
|
||||||
$stmt->execute(['testuser']);
|
$stmt->execute([$username]);
|
||||||
$user = $stmt->fetch(\PDO::FETCH_ASSOC);
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$this->assertEquals('testuser', $user['username']);
|
$this->assertNotNull($user);
|
||||||
$this->assertTrue(password_verify('password123', $user['password']));
|
$this->assertEquals($username, $user['username']);
|
||||||
|
$this->assertTrue(password_verify($password, $user['password']));
|
||||||
|
|
||||||
// Verify user_meta was created
|
// Verify metadata was created
|
||||||
$stmt = $this->db->getConnection()->prepare('SELECT * FROM users_meta WHERE user_id = ?');
|
$stmt = $this->db->getConnection()->prepare("SELECT * FROM user_meta WHERE user_id = ?");
|
||||||
$stmt->execute([$user['id']]);
|
$stmt->execute([$user['id']]);
|
||||||
$meta = $stmt->fetch(\PDO::FETCH_ASSOC);
|
$meta = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$this->assertNotNull($meta);
|
$this->assertNotNull($meta);
|
||||||
|
$this->assertEquals($user['id'], $meta['user_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLogin()
|
public function testLogin()
|
||||||
{
|
{
|
||||||
// Create a test user
|
// First register a user
|
||||||
|
$username = 'testuser';
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
|
||||||
|
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
|
$this->register->register($username, $password);
|
||||||
$stmt->execute(['testuser', $hashedPassword]);
|
|
||||||
|
|
||||||
// Mock $_SERVER['REMOTE_ADDR'] for rate limiter
|
// Mock $_SERVER['REMOTE_ADDR'] for rate limiter
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
|
||||||
// Test successful login
|
// Test successful login
|
||||||
try {
|
try {
|
||||||
$result = $this->user->login('testuser', $password);
|
$result = $this->user->login($username, $password);
|
||||||
$this->assertIsArray($result);
|
$this->assertIsArray($result);
|
||||||
$this->assertEquals('success', $result['status']);
|
$this->assertEquals('success', $result['status']);
|
||||||
$this->assertArrayHasKey('user_id', $result);
|
$this->assertArrayHasKey('user_id', $result);
|
||||||
$this->assertArrayHasKey('username', $result);
|
$this->assertArrayHasKey('username', $result);
|
||||||
$this->assertArrayHasKey('user_id', $_SESSION);
|
$this->assertArrayHasKey('user_id', $_SESSION);
|
||||||
|
$this->assertArrayHasKey('username', $_SESSION);
|
||||||
$this->assertArrayHasKey('CREATED', $_SESSION);
|
$this->assertArrayHasKey('CREATED', $_SESSION);
|
||||||
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->fail('Login should not throw an exception for valid credentials: ' . $e->getMessage());
|
$this->fail('Login should not throw for valid credentials: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test failed login
|
// Test failed login
|
||||||
try {
|
$result = $this->user->login($username, 'wrongpassword');
|
||||||
$this->user->login('testuser', 'wrongpassword');
|
$this->assertIsArray($result);
|
||||||
$this->fail('Login should throw an exception for invalid credentials');
|
$this->assertEquals('failed', $result['status']);
|
||||||
} catch (Exception $e) {
|
$this->assertArrayHasKey('message', $result);
|
||||||
$this->assertStringContainsString('Invalid credentials', $e->getMessage());
|
$this->assertStringContainsString('Invalid credentials', $result['message']);
|
||||||
}
|
|
||||||
|
|
||||||
// Test nonexistent user
|
|
||||||
try {
|
|
||||||
$this->user->login('nonexistent', $password);
|
|
||||||
$this->fail('Login should throw an exception for nonexistent user');
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->assertStringContainsString('Invalid credentials', $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetUserDetails()
|
public function testGetUserDetails()
|
||||||
{
|
{
|
||||||
// Create a test user
|
// Register a test user first
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
|
$username = 'testuser';
|
||||||
$stmt->execute(['testuser', 'hashedpassword']);
|
$password = 'password123';
|
||||||
$userId = $this->db->getConnection()->lastInsertId();
|
$result = $this->register->register($username, $password);
|
||||||
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Create user meta with some data
|
// Get user ID from database
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users_meta (user_id, name, email) VALUES (?, ?, ?)');
|
$stmt = $this->db->getConnection()->prepare("SELECT id FROM user WHERE username = ?");
|
||||||
$stmt->execute([$userId, 'Test User', 'test@example.com']);
|
$stmt->execute([$username]);
|
||||||
|
$userId = $stmt->fetchColumn();
|
||||||
|
$this->assertNotFalse($userId);
|
||||||
|
|
||||||
|
// Insert user metadata
|
||||||
|
$stmt = $this->db->getConnection()->prepare("
|
||||||
|
UPDATE user_meta
|
||||||
|
SET name = ?, email = ?
|
||||||
|
WHERE user_id = ?
|
||||||
|
");
|
||||||
|
$stmt->execute(['Test User', 'test@example.com', $userId]);
|
||||||
|
|
||||||
|
// Get user details
|
||||||
$userDetails = $this->user->getUserDetails($userId);
|
$userDetails = $this->user->getUserDetails($userId);
|
||||||
$this->assertIsArray($userDetails);
|
|
||||||
$this->assertCount(1, $userDetails); // Should return one row
|
|
||||||
$user = $userDetails[0]; // Get the first row
|
|
||||||
$this->assertEquals('testuser', $user['username']);
|
|
||||||
$this->assertEquals('Test User', $user['name']);
|
|
||||||
$this->assertEquals('test@example.com', $user['email']);
|
|
||||||
|
|
||||||
// Test nonexistent user
|
$this->assertIsArray($userDetails);
|
||||||
$userDetails = $this->user->getUserDetails(999);
|
$this->assertNotEmpty($userDetails);
|
||||||
$this->assertEmpty($userDetails);
|
$this->assertArrayHasKey(0, $userDetails, 'User details should be returned as an array');
|
||||||
|
|
||||||
|
// Get first row since we're querying by primary key
|
||||||
|
$userDetails = $userDetails[0];
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('username', $userDetails, 'User details should include username');
|
||||||
|
$this->assertArrayHasKey('name', $userDetails, 'User details should include name');
|
||||||
|
$this->assertArrayHasKey('email', $userDetails, 'User details should include email');
|
||||||
|
|
||||||
|
// Verify values
|
||||||
|
$this->assertEquals($username, $userDetails['username'], 'Username should match');
|
||||||
|
$this->assertEquals('Test User', $userDetails['name'], 'Name should match');
|
||||||
|
$this->assertEquals('test@example.com', $userDetails['email'], 'Email should match');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
require_once dirname(__DIR__, 3) . '/app/classes/database.php';
|
require_once dirname(__DIR__, 3) . '/app/classes/database.php';
|
||||||
require_once dirname(__DIR__, 3) . '/app/classes/user.php';
|
require_once dirname(__DIR__, 3) . '/app/classes/user.php';
|
||||||
|
require_once dirname(__DIR__, 3) . '/plugins/register/models/register.php';
|
||||||
require_once dirname(__DIR__, 3) . '/app/classes/ratelimiter.php';
|
require_once dirname(__DIR__, 3) . '/app/classes/ratelimiter.php';
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
@ -9,154 +10,161 @@ use PHPUnit\Framework\TestCase;
|
||||||
class UserTest extends TestCase
|
class UserTest extends TestCase
|
||||||
{
|
{
|
||||||
private $db;
|
private $db;
|
||||||
|
private $register;
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
// Set up test database
|
// Prepare DB for Github CI
|
||||||
|
$host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
|
||||||
|
$password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
|
||||||
|
|
||||||
$this->db = new Database([
|
$this->db = new Database([
|
||||||
'type' => 'sqlite',
|
'type' => 'mariadb',
|
||||||
'dbFile' => ':memory:'
|
'host' => $host,
|
||||||
|
'port' => '3306',
|
||||||
|
'dbname' => 'totalmeet_test',
|
||||||
|
'user' => 'test_totalmeet',
|
||||||
|
'password' => $password
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create users table
|
// Create user table with MariaDB syntax
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE users (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username VARCHAR(255) NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL
|
password VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create users_meta table
|
// Create user_meta table with MariaDB syntax
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE users_meta (
|
CREATE TABLE IF NOT EXISTS user_meta (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INT NOT NULL,
|
||||||
name TEXT,
|
name VARCHAR(255),
|
||||||
email TEXT,
|
email VARCHAR(255),
|
||||||
timezone TEXT,
|
timezone VARCHAR(100),
|
||||||
bio TEXT,
|
bio TEXT,
|
||||||
avatar TEXT,
|
avatar VARCHAR(255),
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Create security_rate_auth table for rate limiting
|
||||||
|
$this->db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS security_rate_auth (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
username VARCHAR(255) NOT NULL,
|
||||||
|
attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_ip_username (ip_address, username)
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
// Create user_2fa table for two-factor authentication
|
// Create user_2fa table for two-factor authentication
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("
|
||||||
CREATE TABLE user_2fa (
|
CREATE TABLE IF NOT EXISTS user_2fa (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INT NOT NULL,
|
||||||
secret_key TEXT NOT NULL,
|
secret_key VARCHAR(255) NOT NULL,
|
||||||
backup_codes TEXT,
|
backup_codes TEXT,
|
||||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create tables for rate limiter
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE login_attempts (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ip_address TEXT NOT NULL,
|
|
||||||
username TEXT NOT NULL,
|
|
||||||
attempted_at TEXT DEFAULT (DATETIME('now'))
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$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
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$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->user = new User($this->db);
|
$this->user = new User($this->db);
|
||||||
|
$this->register = new Register($this->db);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
// Drop tables in correct order
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_2fa");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_meta");
|
||||||
|
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
||||||
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLogin()
|
public function testLogin()
|
||||||
{
|
{
|
||||||
// Create a test user
|
// First register a user
|
||||||
|
$username = 'testuser';
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
|
||||||
|
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
|
$this->register->register($username, $password);
|
||||||
$stmt->execute(['testuser', $hashedPassword]);
|
|
||||||
|
|
||||||
// Mock $_SERVER['REMOTE_ADDR'] for rate limiter
|
// Mock $_SERVER['REMOTE_ADDR'] for rate limiter
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
|
||||||
// Test successful login
|
// Test successful login
|
||||||
try {
|
try {
|
||||||
$result = $this->user->login('testuser', $password);
|
$result = $this->user->login($username, $password);
|
||||||
$this->assertIsArray($result);
|
$this->assertIsArray($result);
|
||||||
$this->assertEquals('success', $result['status']);
|
$this->assertEquals('success', $result['status']);
|
||||||
$this->assertArrayHasKey('user_id', $result);
|
$this->assertArrayHasKey('user_id', $result);
|
||||||
$this->assertArrayHasKey('username', $result);
|
$this->assertArrayHasKey('username', $result);
|
||||||
$this->assertArrayHasKey('user_id', $_SESSION);
|
$this->assertArrayHasKey('user_id', $_SESSION);
|
||||||
|
$this->assertArrayHasKey('username', $_SESSION);
|
||||||
$this->assertArrayHasKey('CREATED', $_SESSION);
|
$this->assertArrayHasKey('CREATED', $_SESSION);
|
||||||
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->fail('Login should not throw an exception for valid credentials: ' . $e->getMessage());
|
$this->fail('Login should not throw for valid credentials: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test failed login
|
// Test failed login
|
||||||
try {
|
$result = $this->user->login($username, 'wrongpassword');
|
||||||
$this->user->login('testuser', 'wrongpassword');
|
$this->assertIsArray($result);
|
||||||
$this->fail('Login should throw an exception for invalid credentials');
|
$this->assertEquals('failed', $result['status']);
|
||||||
} catch (Exception $e) {
|
$this->assertArrayHasKey('message', $result);
|
||||||
$this->assertStringContainsString('Invalid credentials', $e->getMessage());
|
$this->assertStringContainsString('Invalid credentials', $result['message']);
|
||||||
}
|
|
||||||
|
|
||||||
// Test nonexistent user
|
|
||||||
try {
|
|
||||||
$this->user->login('nonexistent', $password);
|
|
||||||
$this->fail('Login should throw an exception for nonexistent user');
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->assertStringContainsString('Invalid credentials', $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetUserDetails()
|
public function testGetUserDetails()
|
||||||
{
|
{
|
||||||
// Create a test user
|
// Register a test user first
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
|
$username = 'testuser';
|
||||||
$stmt->execute(['testuser', 'hashedpassword']);
|
$password = 'password123';
|
||||||
$userId = $this->db->getConnection()->lastInsertId();
|
$result = $this->register->register($username, $password);
|
||||||
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Create user meta with some data
|
// Get user ID from database
|
||||||
$stmt = $this->db->getConnection()->prepare('INSERT INTO users_meta (user_id, name, email) VALUES (?, ?, ?)');
|
$stmt = $this->db->getConnection()->prepare("SELECT id FROM user WHERE username = ?");
|
||||||
$stmt->execute([$userId, 'Test User', 'test@example.com']);
|
$stmt->execute([$username]);
|
||||||
|
$userId = $stmt->fetchColumn();
|
||||||
|
$this->assertNotFalse($userId);
|
||||||
|
|
||||||
|
// Insert user metadata
|
||||||
|
$stmt = $this->db->getConnection()->prepare("
|
||||||
|
UPDATE user_meta
|
||||||
|
SET name = ?, email = ?
|
||||||
|
WHERE user_id = ?
|
||||||
|
");
|
||||||
|
$stmt->execute(['Test User', 'test@example.com', $userId]);
|
||||||
|
|
||||||
|
// Get user details
|
||||||
$userDetails = $this->user->getUserDetails($userId);
|
$userDetails = $this->user->getUserDetails($userId);
|
||||||
$this->assertIsArray($userDetails);
|
|
||||||
$this->assertCount(1, $userDetails); // Should return one row
|
|
||||||
$user = $userDetails[0]; // Get the first row
|
|
||||||
$this->assertEquals('testuser', $user['username']);
|
|
||||||
$this->assertEquals('Test User', $user['name']);
|
|
||||||
$this->assertEquals('test@example.com', $user['email']);
|
|
||||||
|
|
||||||
// Test nonexistent user
|
$this->assertIsArray($userDetails);
|
||||||
$userDetails = $this->user->getUserDetails(999);
|
$this->assertNotEmpty($userDetails);
|
||||||
$this->assertEmpty($userDetails);
|
$this->assertArrayHasKey(0, $userDetails, 'User details should be returned as an array');
|
||||||
|
|
||||||
|
// Get first row since we're querying by primary key
|
||||||
|
$userDetails = $userDetails[0];
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('username', $userDetails, 'User details should include username');
|
||||||
|
$this->assertArrayHasKey('name', $userDetails, 'User details should include name');
|
||||||
|
$this->assertArrayHasKey('email', $userDetails, 'User details should include email');
|
||||||
|
|
||||||
|
// Verify values
|
||||||
|
$this->assertEquals($username, $userDetails['username'], 'Username should match');
|
||||||
|
$this->assertEquals('Test User', $userDetails['name'], 'Name should match');
|
||||||
|
$this->assertEquals('test@example.com', $userDetails['email'], 'Email should match');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,19 @@ 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__ . '/../app/helpers/ip_helper.php';
|
||||||
|
|
||||||
|
// Initialize global user_IP for tests
|
||||||
|
global $user_IP;
|
||||||
|
$user_IP = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
|
||||||
|
|
||||||
// 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 +36,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
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue