mirror of
				https://github.com/pierre42100/ComunicAPI
				synced 2025-11-03 19:54:14 +00:00 
			
		
		
		
	Setup API requests limit system.
This commit is contained in:
		@@ -17,31 +17,38 @@ class accountController {
 | 
				
			|||||||
	 * @url POST /account/login
 | 
						 * @url POST /account/login
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public function connectUSER(){
 | 
						public function connectUSER(){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Check variables sent in request
 | 
							//Check variables sent in request
 | 
				
			||||||
		if(!isset($_POST['userMail']) OR !isset($_POST['userPassword']))
 | 
							if(!isset($_POST['userMail']) OR !isset($_POST['userPassword']))
 | 
				
			||||||
		   throw new RestException(400, "Missing data !");
 | 
							   throw new RestException(400, "Missing data !");
 | 
				
			||||||
	   
 | 
						   
 | 
				
			||||||
	   //Retrieve database connection
 | 
							//API limit
 | 
				
			||||||
	   $db = CS::get()->db;;
 | 
							api_limit_query(APILimits::ACTION_LOGIN_FAILED, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	   //Extract data
 | 
							//Retrieve database connection
 | 
				
			||||||
	   $userMail = $_POST["userMail"];
 | 
							$db = CS::get()->db;;
 | 
				
			||||||
	   $userPassword = $_POST['userPassword'];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	   //Try to perform login
 | 
							//Extract data
 | 
				
			||||||
	   $loginTokens = CS::get()->components->account->generateUserLoginTokens($userMail, $userPassword, APIServiceID, $db);
 | 
							$userMail = $_POST["userMail"];
 | 
				
			||||||
 | 
							$userPassword = $_POST['userPassword'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	   if(count($loginTokens) == 0)
 | 
							//Try to perform login
 | 
				
			||||||
		   throw new RestException(401, "Invalid e-mail address / password !");
 | 
							$loginTokens = CS::get()->components->account->generateUserLoginTokens($userMail, $userPassword, APIServiceID, $db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	   //Return result with tokens
 | 
							if(count($loginTokens) == 0){
 | 
				
			||||||
	   return array(
 | 
								api_limit_query(APILimits::ACTION_LOGIN_FAILED, true);
 | 
				
			||||||
		   "success" => "User logged in !",
 | 
								throw new RestException(401, "Invalid e-mail address / password !");
 | 
				
			||||||
		   "tokens" => array(
 | 
							}
 | 
				
			||||||
			   "token1" => $loginTokens[0],
 | 
							   
 | 
				
			||||||
			   "token2" => $loginTokens[1],
 | 
					
 | 
				
			||||||
		   ),
 | 
							//Return result with tokens
 | 
				
			||||||
	   );
 | 
							return array(
 | 
				
			||||||
 | 
								"success" => "User logged in !",
 | 
				
			||||||
 | 
								"tokens" => array(
 | 
				
			||||||
 | 
									"token1" => $loginTokens[0],
 | 
				
			||||||
 | 
									"token2" => $loginTokens[1],
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										135
									
								
								classes/APILimits.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								classes/APILimits.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * API Actions limits count
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @author Pierre HUBERT
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class APILimits {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Table name
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const TABLE_NAME = DBprefix."api_limit_count";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Entries live time
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const KEEP_DATA_FOR = 3600; // 1 hour
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Actions list
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const ACTION_LOGIN_FAILED = "failed_login";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Actions configruation
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const ACTIONS = array(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//Login failed
 | 
				
			||||||
 | 
							self::ACTION_LOGIN_FAILED => array(
 | 
				
			||||||
 | 
								"limit" => 10
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Limit the number of time a client can perform a query over the API
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param string $action The name of the action to limit
 | 
				
			||||||
 | 
						 * @param bool $trigger Specify whether this call of the method must be
 | 
				
			||||||
 | 
						 * considered as a call of the client or not
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function limit_query(string $action, bool $trigger){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//First, clean old entries
 | 
				
			||||||
 | 
							$this->clean();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$ip = $_SERVER["REMOTE_ADDR"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//If required, increase action by one
 | 
				
			||||||
 | 
							if($trigger)
 | 
				
			||||||
 | 
								$this->trigger($action, $ip);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//Count the number of time the action occurred
 | 
				
			||||||
 | 
							if($this->count($action, $ip) > self::ACTIONS[$action]["limit"])
 | 
				
			||||||
 | 
								Rest_fatal_error(429, "Too many request. Please try again later.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Clean old entries
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function clean(){
 | 
				
			||||||
 | 
							db()->deleteEntry(
 | 
				
			||||||
 | 
								self::TABLE_NAME,
 | 
				
			||||||
 | 
								"time_start < ?",
 | 
				
			||||||
 | 
								array(time() - self::KEEP_DATA_FOR)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Increase by one the number of the time a client performed
 | 
				
			||||||
 | 
						 * an action
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param string $action The action to trigger
 | 
				
			||||||
 | 
						 * @param string $ip The target IP address
 | 
				
			||||||
 | 
						 * @return bool TRUE for a success else FALSE
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private function trigger(string $action, string $ip) : bool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(!$this->exists($action, $ip)){
 | 
				
			||||||
 | 
								return db()->addLine(self::TABLE_NAME, array(
 | 
				
			||||||
 | 
									"ip" => $ip,
 | 
				
			||||||
 | 
									"time_start" => time(),
 | 
				
			||||||
 | 
									"action" => $action,
 | 
				
			||||||
 | 
									"count" => 1
 | 
				
			||||||
 | 
								));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								$number = $this->count($action, $ip);
 | 
				
			||||||
 | 
								$number++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return db()->updateDB(self::TABLE_NAME,
 | 
				
			||||||
 | 
									"ip = ? AND action = ?",
 | 
				
			||||||
 | 
									array("count" => $number),
 | 
				
			||||||
 | 
									array($ip, $action));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Check wether an action has been referenced at least once in
 | 
				
			||||||
 | 
						 * the database
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param string $action The action to check
 | 
				
			||||||
 | 
						 * @param string $ip The target IP address
 | 
				
			||||||
 | 
						 * @return bool TRUE if the entry has been found at least once / FALSE else
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private function exists(string $action, string $ip) : bool {
 | 
				
			||||||
 | 
							return db()->count(self::TABLE_NAME, 
 | 
				
			||||||
 | 
								"WHERE ip = ? AND action = ?",
 | 
				
			||||||
 | 
								array($ip, $action)) > 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Count the number of time an IP address has performed an action
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param string $action The target action
 | 
				
			||||||
 | 
						 * @param string $ip Target IP address
 | 
				
			||||||
 | 
						 * @return int The number of time the action has been done
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private function count(string $action, string $ip) : int {
 | 
				
			||||||
 | 
							$data = db()->select(self::TABLE_NAME, 
 | 
				
			||||||
 | 
								"WHERE ip = ? AND action = ?",
 | 
				
			||||||
 | 
								array($ip, $action),
 | 
				
			||||||
 | 
								array("count"));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(count($data) < 1)
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								return $data[0]["count"];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -72,6 +72,14 @@ CREATE TABLE `commentaires` (
 | 
				
			|||||||
  PRIMARY KEY (`ID`)
 | 
					  PRIMARY KEY (`ID`)
 | 
				
			||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DROP TABLE IF EXISTS `comunic_api_limit_count`;
 | 
				
			||||||
 | 
					CREATE TABLE `comunic_api_limit_count` (
 | 
				
			||||||
 | 
					  `ip` varchar(15) NOT NULL,
 | 
				
			||||||
 | 
					  `time_start` int(11) DEFAULT NULL,
 | 
				
			||||||
 | 
					  `action` varchar(45) DEFAULT NULL,
 | 
				
			||||||
 | 
					  `count` int(11) DEFAULT NULL
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DROP TABLE IF EXISTS `comunic_API_ServicesToken`;
 | 
					DROP TABLE IF EXISTS `comunic_API_ServicesToken`;
 | 
				
			||||||
CREATE TABLE `comunic_API_ServicesToken` (
 | 
					CREATE TABLE `comunic_API_ServicesToken` (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								helpers/APILimits.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								helpers/APILimits.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * API Limits helper
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @author Pierre HUBERT
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Limit the number of time a query can be performed by a client
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param string $name The name of the action to limit
 | 
				
			||||||
 | 
					 * @param bool $trigger Count this as an action of the user or not
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function api_limit_query(string $name, bool $trigger){
 | 
				
			||||||
 | 
						cs()->limit->limit_query($name, $trigger);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user