| 
									
										
										
										
											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/ratelimiter.php'; | 
					
						
							|  |  |  | require_once dirname(__DIR__, 3) . '/app/classes/log.php'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | use PHPUnit\Framework\TestCase; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RateLimiterTest extends TestCase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     private $db; | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     private $rateLimiter; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 : ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Set up test database
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  |         // The RateLimiter constructor will create all necessary tables
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |         $this->rateLimiter = new RateLimiter($this->db); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     protected function tearDown(): void | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // 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(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     public function testGetRecentAttempts() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $ip = '8.8.8.8'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Record some login attempts
 | 
					
						
							|  |  |  |         $stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->authRatelimitTable} 
 | 
					
						
							|  |  |  |             (ip_address, username, attempted_at) VALUES (?, ?, NOW())");
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Add 3 attempts
 | 
					
						
							|  |  |  |         for ($i = 0; $i < 3; $i++) { | 
					
						
							|  |  |  |             $stmt->execute([$ip, 'testuser']); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $attempts = $this->rateLimiter->getRecentAttempts($ip); | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $this->assertEquals(3, $attempts); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     public function testIsIpBlacklisted() | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $ip = '8.8.8.8'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Add IP to blacklist
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $stmt = $this->db->getConnection()->prepare("INSERT INTO {$this->rateLimiter->blacklistTable} 
 | 
					
						
							|  |  |  |             (ip_address, is_network, reason) VALUES (?, ?, ?)");
 | 
					
						
							|  |  |  |         $stmt->execute([$ip, 0, 'Test blacklist']); // Explicitly set is_network to 0 (false)
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $this->assertTrue($this->rateLimiter->isIpBlacklisted($ip)); | 
					
						
							|  |  |  |         $this->assertFalse($this->rateLimiter->isIpBlacklisted('8.8.4.4')); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     public function testIsIpWhitelisted() | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // 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
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // 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)
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $this->assertTrue($this->rateLimiter->isIpWhitelisted($ip)); | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $this->assertFalse($this->rateLimiter->isIpWhitelisted('8.8.4.4')); // Another IP not in private ranges
 | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |     public function testRateLimitCheck() | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         $ip = '8.8.8.8'; // Use non-whitelisted IP
 | 
					
						
							|  |  |  |         $endpoint = '/test'; | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // First request should be allowed
 | 
					
						
							|  |  |  |         $this->assertTrue($this->rateLimiter->isPageRequestAllowed($ip, $endpoint)); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // Add requests up to the limit
 | 
					
						
							|  |  |  |         for ($i = 0; $i < 60; $i++) { // Default limit is 60 per minute
 | 
					
						
							|  |  |  |             $this->rateLimiter->recordPageRequest($ip, $endpoint); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 14:15:56 +00:00
										 |  |  |         // The next request should be rate limited
 | 
					
						
							|  |  |  |         $this->assertFalse($this->rateLimiter->isPageRequestAllowed($ip, $endpoint)); | 
					
						
							| 
									
										
										
										
											2025-02-18 14:36:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } |