184 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
			
		
		
	
	
			184 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
<?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/ratelimiter.php';
 | 
						|
 | 
						|
use PHPUnit\Framework\TestCase;
 | 
						|
 | 
						|
class UserTest extends TestCase
 | 
						|
{
 | 
						|
    private $db;
 | 
						|
    private $user;
 | 
						|
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        parent::setUp();
 | 
						|
 | 
						|
        // Set up test database
 | 
						|
        $this->db = new Database([
 | 
						|
            'type' => 'sqlite',
 | 
						|
            'dbFile' => ':memory:'
 | 
						|
        ]);
 | 
						|
 | 
						|
        // Create users table
 | 
						|
        $this->db->getConnection()->exec("
 | 
						|
            CREATE TABLE users (
 | 
						|
                id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
						|
                username TEXT NOT NULL UNIQUE,
 | 
						|
                password TEXT NOT NULL
 | 
						|
            )
 | 
						|
        ");
 | 
						|
 | 
						|
        // Create users_meta table
 | 
						|
        $this->db->getConnection()->exec("
 | 
						|
            CREATE TABLE users_meta (
 | 
						|
                id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
						|
                user_id INTEGER NOT NULL,
 | 
						|
                name TEXT,
 | 
						|
                email TEXT,
 | 
						|
                timezone TEXT,
 | 
						|
                bio TEXT,
 | 
						|
                avatar TEXT,
 | 
						|
                FOREIGN KEY (user_id) REFERENCES users(id)
 | 
						|
            )
 | 
						|
        ");
 | 
						|
 | 
						|
        // Create user_2fa table for two-factor authentication
 | 
						|
        $this->db->getConnection()->exec("
 | 
						|
            CREATE TABLE user_2fa (
 | 
						|
                id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
						|
                user_id INTEGER NOT NULL,
 | 
						|
                secret_key TEXT NOT NULL,
 | 
						|
                backup_codes TEXT,
 | 
						|
                enabled TINYINT(1) NOT NULL DEFAULT 0,
 | 
						|
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 | 
						|
                FOREIGN KEY (user_id) REFERENCES users(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);
 | 
						|
    }
 | 
						|
 | 
						|
    public function testRegister()
 | 
						|
    {
 | 
						|
        $result = $this->user->register('testuser', 'password123');
 | 
						|
        $this->assertTrue($result);
 | 
						|
 | 
						|
        // Verify user was created
 | 
						|
        $stmt = $this->db->getConnection()->prepare('SELECT * FROM users WHERE username = ?');
 | 
						|
        $stmt->execute(['testuser']);
 | 
						|
        $user = $stmt->fetch(\PDO::FETCH_ASSOC);
 | 
						|
 | 
						|
        $this->assertEquals('testuser', $user['username']);
 | 
						|
        $this->assertTrue(password_verify('password123', $user['password']));
 | 
						|
 | 
						|
        // Verify user_meta was created
 | 
						|
        $stmt = $this->db->getConnection()->prepare('SELECT * FROM users_meta WHERE user_id = ?');
 | 
						|
        $stmt->execute([$user['id']]);
 | 
						|
        $meta = $stmt->fetch(\PDO::FETCH_ASSOC);
 | 
						|
 | 
						|
        $this->assertNotNull($meta);
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLogin()
 | 
						|
    {
 | 
						|
        // Create a test user
 | 
						|
        $password = 'password123';
 | 
						|
        $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
 | 
						|
 | 
						|
        $stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
 | 
						|
        $stmt->execute(['testuser', $hashedPassword]);
 | 
						|
 | 
						|
        // Mock $_SERVER['REMOTE_ADDR'] for rate limiter
 | 
						|
        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
 | 
						|
 | 
						|
        // Test successful login
 | 
						|
        try {
 | 
						|
            $result = $this->user->login('testuser', $password);
 | 
						|
            $this->assertIsArray($result);
 | 
						|
            $this->assertEquals('success', $result['status']);
 | 
						|
            $this->assertArrayHasKey('user_id', $result);
 | 
						|
            $this->assertArrayHasKey('username', $result);
 | 
						|
            $this->assertArrayHasKey('user_id', $_SESSION);
 | 
						|
            $this->assertArrayHasKey('CREATED', $_SESSION);
 | 
						|
            $this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
 | 
						|
        } catch (Exception $e) {
 | 
						|
            $this->fail('Login should not throw an exception for valid credentials: ' . $e->getMessage());
 | 
						|
        }
 | 
						|
 | 
						|
        // Test failed login
 | 
						|
        try {
 | 
						|
            $this->user->login('testuser', 'wrongpassword');
 | 
						|
            $this->fail('Login should throw an exception for invalid credentials');
 | 
						|
        } catch (Exception $e) {
 | 
						|
            $this->assertStringContainsString('Invalid credentials', $e->getMessage());
 | 
						|
        }
 | 
						|
 | 
						|
        // 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()
 | 
						|
    {
 | 
						|
        // Create a test user
 | 
						|
        $stmt = $this->db->getConnection()->prepare('INSERT INTO users (username, password) VALUES (?, ?)');
 | 
						|
        $stmt->execute(['testuser', 'hashedpassword']);
 | 
						|
        $userId = $this->db->getConnection()->lastInsertId();
 | 
						|
 | 
						|
        // Create user meta with some data
 | 
						|
        $stmt = $this->db->getConnection()->prepare('INSERT INTO users_meta (user_id, name, email) VALUES (?, ?, ?)');
 | 
						|
        $stmt->execute([$userId, 'Test User', 'test@example.com']);
 | 
						|
 | 
						|
        $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
 | 
						|
        $userDetails = $this->user->getUserDetails(999);
 | 
						|
        $this->assertEmpty($userDetails);
 | 
						|
    }
 | 
						|
}
 |