| 
					
				 | 
			
			
				@@ -3,13 +3,46 @@ package servauth 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"log" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"net/http" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"github.com/vladimirok5959/golang-utils/utils/http/helpers" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// TODO: protect from bruteforce 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var mRequests = &Requests{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	counter:   map[string]int{}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	lastTime:  map[string]int64{}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cleanTime: time.Now().UTC().Unix(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func BasicAuth(handler http.Handler, username, password, realm string) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if username != "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Cleanup every hour 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (time.Now().UTC().Unix() - mRequests.cleanTime) > 3600 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.Cleanup() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ip := helpers.ClientIP(r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			reqs := mRequests.Count(ip) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ltime := mRequests.Time(ip) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Reset counter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (time.Now().UTC().Unix() - ltime) >= 30 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				reqs = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetCount(ip, reqs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetTime(ip, time.Now().UTC().Unix()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Restrict access 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if reqs >= 5 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				w.Header().Set("Retry-After", "30") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				w.WriteHeader(429) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if _, err := w.Write([]byte("Too Many Requests\n")); err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					log.Printf("%s\n", err.Error()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if realm == "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				realm = "Please enter username and password" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -25,6 +58,11 @@ func BasicAuth(handler http.Handler, username, password, realm string) http.Hand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if u != username { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				// Inc counter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				reqs = reqs + 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetCount(ip, reqs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetTime(ip, time.Now().UTC().Unix()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				w.WriteHeader(401) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if _, err := w.Write([]byte("Unauthorised\n")); err != nil { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -34,6 +72,11 @@ func BasicAuth(handler http.Handler, username, password, realm string) http.Hand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if p != password { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				// Inc counter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				reqs = reqs + 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetCount(ip, reqs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mRequests.SetTime(ip, time.Now().UTC().Unix()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				w.WriteHeader(401) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if _, err := w.Write([]byte("Unauthorised\n")); err != nil { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -41,6 +84,11 @@ func BasicAuth(handler http.Handler, username, password, realm string) http.Hand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Reset counter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			reqs = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			mRequests.SetCount(ip, reqs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			mRequests.SetTime(ip, time.Now().UTC().Unix()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		handler.ServeHTTP(w, r) 
			 |