|
@@ -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)
|