From 5bb95737d5b40c5c074470966def8a5d589670fa Mon Sep 17 00:00:00 2001
From: Nathanael Jourdane <nathanael.jourdane@irap.omp.eu>
Date: Mon, 13 Nov 2017 19:53:21 +0100
Subject: [PATCH] Add a query limit for getParameters webservice

---
 php/classes/WebServer.php | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/php/classes/WebServer.php b/php/classes/WebServer.php
index f20ea07..c1e0ab8 100644
--- a/php/classes/WebServer.php
+++ b/php/classes/WebServer.php
@@ -83,6 +83,9 @@ class WebServer
   private $wsUserMgr;
   private $resultMgr, $myParamsInfoMgr;
   private $dataFileName;
+	private $QUERY_TIME_INTERVAL;
+	private $MAX_QUERIES;
+	private $CLIENTS_ACCESS_PATH;
 
   function __construct() {
     $this->userID  = 'impex';
@@ -90,6 +93,9 @@ class WebServer
     $this->sessionID = $this->userID;
     $this->myParamsInfoMgr =  new ParamsInfoMgr();
     $this->resultMgr = new WebResultMgr();
+	  $this->QUERY_TIME_INTERVAL = 30; // Time interval to limit access, in seconds.
+	  $this->MAX_QUERIES = 3;  // Number of queries allowed in one time interval, per IP.
+	  $this->CLIENTS_ACCESS_PATH = './clients'; // Path of the file containing clients access counters.
   }
  
   protected function init($data) {
@@ -117,6 +123,44 @@ class WebServer
     return array('success' => true, 'vars' => $vars);
   }
 
+  	// Returns true if the user reached its query limit.
+	private function isRateLimitReached() {
+		$currentTime = (int)(((new DateTime())->getTimestamp())/$this->QUERY_TIME_INTERVAL);
+		$ip = $_SERVER['REMOTE_ADDR'];
+		error_log("Client IP: $ip ; Current time: $currentTime\n");
+
+		if(file_exists($this->CLIENTS_ACCESS_PATH)) {
+			$clients = file_get_contents($this->CLIENTS_ACCESS_PATH);
+			$matches = array();
+			if(preg_match("/($ip) (\d*) (\d*)/", $clients, $matches, PREG_OFFSET_CAPTURE)) {
+				error_log("Found an entry for this IP (". $matches[0][0] . ")\n");
+				$lastTime = (int)($matches[2][0]);
+				if($currentTime == $lastTime) {
+					$count = (int)($matches[3][0]);
+					if($count >= $this->MAX_QUERIES) {
+						error_log("Same time range and max count value reached: please wait a moment and try again.\n");
+						return true;
+					} else {
+						$count++;
+						error_log("Same time range, but max count value not reached yet: incrementing counter (" . ($this->MAX_QUERIES-$count) . "/$this->MAX_QUERIES).\n");
+						$clients = substr_replace($clients, $count, $matches[3][1], strlen($matches[3][0]));
+					}
+				} else {
+					error_log("New time range: resetting time entry.");
+					$clients = substr_replace($clients, "$ip $currentTime 1", $matches[0][1], strlen($matches[0][0]));
+				}
+			} else {
+				error_log("IP $ip not found: creating new time entry\n");
+				$clients = "$clients$ip $currentTime 1\n";
+			}
+		} else {
+			error_log("File not created yet: creating file and new time entry\n");
+			$clients = "$ip $currentTime 1\n";
+		}
+		file_put_contents($this->CLIENTS_ACCESS_PATH, $clients);
+		return false;
+	}
+
   private function setID(){
 
                    $nb_min = 10000;
@@ -549,7 +593,11 @@ class WebServer
 ///////////////////////////////////////START GET DATASET   ///////////////////////////////
   public function getParameter($data) {
 
-    $multiParam = false;
+	  if($this->isRateLimitReached()) {
+		  return array('success' => false, 'message' => 'Rate limit reached. Please try again later.');
+	  }
+
+	  $multiParam = false;
 
     $res = $this->init($data);
     
--
libgit2 0.21.2