2025-04-17 07:59:40 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
require_once dirname(__DIR__, 3) . '/app/classes/database.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';
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
|
|
|
|
class UserRegisterTest extends TestCase
|
|
|
|
{
|
|
|
|
private $db;
|
|
|
|
private $register;
|
|
|
|
private $user;
|
|
|
|
|
|
|
|
protected function setUp(): void
|
|
|
|
{
|
|
|
|
parent::setUp();
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// 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 : '';
|
|
|
|
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->db = new Database([
|
2025-04-25 14:15:56 +00:00
|
|
|
'type' => 'mariadb',
|
|
|
|
'host' => $host,
|
|
|
|
'port' => '3306',
|
|
|
|
'dbname' => 'totalmeet_test',
|
|
|
|
'user' => 'test_totalmeet',
|
|
|
|
'password' => $password
|
2025-04-17 07:59:40 +00:00
|
|
|
]);
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Create user table with MariaDB syntax
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->db->getConnection()->exec("
|
2025-04-25 14:15:56 +00:00
|
|
|
CREATE TABLE IF NOT EXISTS user (
|
|
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
|
|
username VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
password VARCHAR(255) NOT NULL,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
2025-04-17 07:59:40 +00:00
|
|
|
)
|
|
|
|
");
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Create user_meta table with MariaDB syntax
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->db->getConnection()->exec("
|
2025-04-25 14:15:56 +00:00
|
|
|
CREATE TABLE IF NOT EXISTS user_meta (
|
|
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
|
|
user_id INT NOT NULL,
|
|
|
|
name VARCHAR(255),
|
|
|
|
email VARCHAR(255),
|
|
|
|
timezone VARCHAR(100),
|
2025-04-17 07:59:40 +00:00
|
|
|
bio TEXT,
|
2025-04-25 14:15:56 +00:00
|
|
|
avatar VARCHAR(255),
|
2025-04-25 13:16:38 +00:00
|
|
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
2025-04-17 07:59:40 +00:00
|
|
|
)
|
|
|
|
");
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Create security_rate_auth table for rate limiting
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->db->getConnection()->exec("
|
2025-04-25 14:15:56 +00:00
|
|
|
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)
|
2025-04-17 07:59:40 +00:00
|
|
|
)
|
|
|
|
");
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Create user_2fa table for two-factor authentication
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->db->getConnection()->exec("
|
2025-04-25 14:15:56 +00:00
|
|
|
CREATE TABLE IF NOT EXISTS user_2fa (
|
|
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
|
|
user_id INT NOT NULL,
|
|
|
|
secret_key VARCHAR(255) NOT NULL,
|
|
|
|
backup_codes TEXT,
|
|
|
|
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
2025-04-17 07:59:40 +00:00
|
|
|
)
|
|
|
|
");
|
|
|
|
|
|
|
|
$this->register = new Register($this->db);
|
|
|
|
$this->user = new User($this->db);
|
|
|
|
}
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2025-04-17 07:59:40 +00:00
|
|
|
public function testRegister()
|
|
|
|
{
|
2025-04-25 14:15:56 +00:00
|
|
|
// Register a new user
|
|
|
|
$username = 'testuser';
|
|
|
|
$password = 'password123';
|
|
|
|
|
|
|
|
$result = $this->register->register($username, $password);
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
|
|
// Verify user was created
|
2025-04-25 14:15:56 +00:00
|
|
|
$stmt = $this->db->getConnection()->prepare("SELECT * FROM user WHERE username = ?");
|
|
|
|
$stmt->execute([$username]);
|
|
|
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
2025-04-17 07:59:40 +00:00
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->assertNotNull($user);
|
|
|
|
$this->assertEquals($username, $user['username']);
|
|
|
|
$this->assertTrue(password_verify($password, $user['password']));
|
2025-04-17 07:59:40 +00:00
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Verify metadata was created
|
|
|
|
$stmt = $this->db->getConnection()->prepare("SELECT * FROM user_meta WHERE user_id = ?");
|
2025-04-17 07:59:40 +00:00
|
|
|
$stmt->execute([$user['id']]);
|
2025-04-25 14:15:56 +00:00
|
|
|
$meta = $stmt->fetch(PDO::FETCH_ASSOC);
|
2025-04-17 07:59:40 +00:00
|
|
|
|
|
|
|
$this->assertNotNull($meta);
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->assertEquals($user['id'], $meta['user_id']);
|
2025-04-17 07:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testLogin()
|
|
|
|
{
|
2025-04-25 14:15:56 +00:00
|
|
|
// First register a user
|
|
|
|
$username = 'testuser';
|
2025-04-17 07:59:40 +00:00
|
|
|
$password = 'password123';
|
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->register->register($username, $password);
|
2025-04-17 07:59:40 +00:00
|
|
|
|
|
|
|
// Mock $_SERVER['REMOTE_ADDR'] for rate limiter
|
|
|
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
|
|
|
|
|
|
|
// Test successful login
|
|
|
|
try {
|
2025-04-25 14:15:56 +00:00
|
|
|
$result = $this->user->login($username, $password);
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->assertIsArray($result);
|
|
|
|
$this->assertEquals('success', $result['status']);
|
|
|
|
$this->assertArrayHasKey('user_id', $result);
|
|
|
|
$this->assertArrayHasKey('username', $result);
|
|
|
|
$this->assertArrayHasKey('user_id', $_SESSION);
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->assertArrayHasKey('username', $_SESSION);
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->assertArrayHasKey('CREATED', $_SESSION);
|
|
|
|
$this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
|
|
|
|
} catch (Exception $e) {
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->fail('Login should not throw for valid credentials: ' . $e->getMessage());
|
2025-04-17 07:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test failed login
|
2025-04-25 14:15:56 +00:00
|
|
|
$result = $this->user->login($username, 'wrongpassword');
|
|
|
|
$this->assertIsArray($result);
|
|
|
|
$this->assertEquals('failed', $result['status']);
|
|
|
|
$this->assertArrayHasKey('message', $result);
|
|
|
|
$this->assertStringContainsString('Invalid credentials', $result['message']);
|
2025-04-17 07:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testGetUserDetails()
|
|
|
|
{
|
2025-04-25 14:15:56 +00:00
|
|
|
// Register a test user first
|
|
|
|
$username = 'testuser';
|
|
|
|
$password = 'password123';
|
|
|
|
$result = $this->register->register($username, $password);
|
|
|
|
$this->assertTrue($result);
|
2025-04-17 07:59:40 +00:00
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Get user ID from database
|
|
|
|
$stmt = $this->db->getConnection()->prepare("SELECT id FROM user WHERE username = ?");
|
|
|
|
$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]);
|
2025-04-17 07:59:40 +00:00
|
|
|
|
2025-04-25 14:15:56 +00:00
|
|
|
// Get user details
|
2025-04-17 07:59:40 +00:00
|
|
|
$userDetails = $this->user->getUserDetails($userId);
|
2025-04-25 14:15:56 +00:00
|
|
|
|
2025-04-17 07:59:40 +00:00
|
|
|
$this->assertIsArray($userDetails);
|
2025-04-25 14:15:56 +00:00
|
|
|
$this->assertNotEmpty($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');
|
2025-04-17 07:59:40 +00:00
|
|
|
}
|
|
|
|
}
|