@@ -4,12 +4,17 @@ import (
44 "github.com/0xJacky/Nginx-UI/api"
55 "github.com/0xJacky/Nginx-UI/internal/logger"
66 "github.com/0xJacky/Nginx-UI/internal/user"
7+ "github.com/0xJacky/Nginx-UI/query"
8+ "github.com/0xJacky/Nginx-UI/settings"
79 "github.com/gin-gonic/gin"
810 "github.com/pkg/errors"
911 "net/http"
12+ "sync"
1013 "time"
1114)
1215
16+ var mutex = & sync.Mutex {}
17+
1318type LoginUser struct {
1419 Name string `json:"name" binding:"required,max=255"`
1520 Password string `json:"password" binding:"required,max=255"`
@@ -29,6 +34,25 @@ type LoginResponse struct {
2934}
3035
3136func Login (c * gin.Context ) {
37+ // make sure that only one request is processed at a time
38+ mutex .Lock ()
39+ defer mutex .Unlock ()
40+ // check if the ip is banned
41+ clientIP := c .ClientIP ()
42+ b := query .BanIP
43+ banIP , _ := b .Where (b .IP .Eq (clientIP ),
44+ b .ExpiredAt .Gte (time .Now ().Unix ()),
45+ b .Attempts .Gte (settings .AuthSettings .MaxAttempts ),
46+ ).Count ()
47+
48+ if banIP > 0 {
49+ c .JSON (http .StatusTooManyRequests , LoginResponse {
50+ Message : "Max attempts" ,
51+ Code : ErrMaxAttempts ,
52+ })
53+ return
54+ }
55+
3256 var json LoginUser
3357 ok := api .BindAndValid (c , & json )
3458 if ! ok {
@@ -37,7 +61,7 @@ func Login(c *gin.Context) {
3761
3862 u , err := user .Login (json .Name , json .Password )
3963 if err != nil {
40- time .Sleep (5 * time .Second )
64+ // time.Sleep(5 * time.Second)
4165 switch {
4266 case errors .Is (err , user .ErrPasswordIncorrect ):
4367 c .JSON (http .StatusForbidden , LoginResponse {
@@ -52,9 +76,13 @@ func Login(c *gin.Context) {
5276 default :
5377 api .ErrHandler (c , err )
5478 }
79+ user .BanIP (clientIP )
5580 return
5681 }
5782
83+ // login success, clear banned record
84+ _ , _ = b .Where (b .IP .Eq (clientIP )).Delete ()
85+
5886 logger .Info ("[User Login]" , u .Name )
5987 token , err := user .GenerateJWT (u .Name )
6088 if err != nil {
0 commit comments