| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-20 08:41:14 +00:00
										 |  |  | require_once dirname(__DIR__, 3) . '/app/classes/database.php'; | 
					
						
							|  |  |  | require_once dirname(__DIR__, 3) . '/app/classes/user.php'; | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  | require_once dirname(__DIR__, 3) . '/plugins/register/models/register.php'; | 
					
						
							| 
									
										
										
										
											2025-02-20 08:41:14 +00:00
										 |  |  | require_once dirname(__DIR__, 3) . '/app/classes/ratelimiter.php'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | use PHPUnit\Framework\TestCase; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UserTest extends TestCase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     private $db; | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     private $register; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     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-02-18 14:36:31 +00:00
										 |  |  |         $this->db = new Database([ | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |             'type' => 'mariadb', | 
					
						
							|  |  |  |             'host' => $host, | 
					
						
							|  |  |  |             'port' => '3306', | 
					
						
							| 
									
										
										
										
											2025-04-25 15:30:24 +00:00
										 |  |  |             'dbname' => 'jilo_test', | 
					
						
							|  |  |  |             'user' => 'test_jilo', | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |             'password' => $password | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |         ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Create user table with MariaDB syntax
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Create user_meta table with MariaDB syntax
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +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-08 10:13:49 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Create security_rate_auth table for rate limiting
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Create user_2fa table for two-factor authentication
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ");
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->user = new User($this->db); | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $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(); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function testLogin() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // First register a user
 | 
					
						
							|  |  |  |         $username = 'testuser'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |         $password = 'password123'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $this->register->register($username, $password); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-08 10:13:49 +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-08 10:13:49 +00:00
										 |  |  |             $this->assertArrayHasKey('CREATED', $_SESSION); | 
					
						
							|  |  |  |             $this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |         } catch (Exception $e) { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |             $this->fail('Login should not throw for valid credentials: ' . $e->getMessage()); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // 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-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Get user details
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |         $userDetails = $this->user->getUserDetails($userId); | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +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-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } |