diff --git a/conf/conf.go b/conf/conf.go index ffacc58..f8bf8c8 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -15,6 +15,12 @@ type ConnectionStats struct { TotalGigabyte uint64 } +type IpBan struct { + Id int `gorm:"primaryKey;autoIncrement"` + Ip string + TimeStamp int64 +} + // 全局转发协程等待组 var Wg sync.WaitGroup diff --git a/go.mod b/go.mod index d1e6fbb..791fa6d 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,9 @@ require ( github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/sessions v1.2.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect @@ -40,6 +43,7 @@ require ( ) require ( + github.com/gin-contrib/sessions v0.0.5 github.com/gin-gonic/gin v1.9.1 github.com/glebarez/sqlite v1.10.0 github.com/jinzhu/inflection v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1b752e3..0788e40 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= +github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= @@ -32,6 +34,12 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -93,6 +101,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sql/sql.go b/sql/sql.go index a3720e7..ea07bca 100644 --- a/sql/sql.go +++ b/sql/sql.go @@ -5,6 +5,7 @@ import ( "log" "os" "path/filepath" + "time" "csz.net/goForward/conf" "github.com/glebarez/sqlite" @@ -24,14 +25,15 @@ func init() { dbPath = "goForward.db" } else { dbPath = filepath.Join(filepath.Dir(executablePath), "goForward.db") - } + fmt.Println("Data:", dbPath) db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) if err != nil { log.Println("连接数据库失败") return } db.AutoMigrate(&conf.ConnectionStats{}) + db.AutoMigrate(&conf.IpBan{}) } // 获取转发列表 @@ -118,3 +120,37 @@ func DelForward(id int) bool { } return true } + +// 增加错误登录 +func AddBan(ip conf.IpBan) bool { + //开启事务 + tx := db.Begin() + if tx.Error != nil { + return false + } + // 在事务中执行插入操作 + if err := tx.Create(&ip).Error; err != nil { + log.Println(err) + tx.Rollback() // 回滚事务 + return false + } + // 提交事务 + tx.Commit() + return true +} + +// 检查过去一天内指定IP地址的记录条数是否超过三条 +func IpFree(ip string) bool { + // 获取过去一天的时间戳 + oneDayAgo := time.Now().Add(-24 * time.Hour).Unix() + + // 查询过去一天内指定IP地址的记录条数 + var count int64 + if err := db.Model(&conf.IpBan{}).Where("ip = ? AND time_stamp > ?", ip, oneDayAgo).Count(&count).Error; err != nil { + log.Println(err) + return false + } + + // 如果记录条数超过三条,则返回false;否则返回true + return count < 3 +} diff --git a/web/web.go b/web/web.go index 904b912..61c7f07 100644 --- a/web/web.go +++ b/web/web.go @@ -6,17 +6,22 @@ import ( "net/http" "strconv" "strings" + "time" "csz.net/goForward/assets" "csz.net/goForward/conf" "csz.net/goForward/sql" "csz.net/goForward/utils" + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" ) func Run() { gin.SetMode(gin.ReleaseMode) r := gin.Default() + store := cookie.NewStore([]byte("secret")) + r.Use(sessions.Sessions("goForward", store)) r.Use(checkCookieMiddleware) r.SetHTMLTemplate(template.Must(template.New("").Funcs(r.FuncMap).ParseFS(assets.Templates, "templates/*"))) r.GET("/", func(c *gin.Context) { @@ -84,7 +89,23 @@ func Run() { c.HTML(200, "pwd.tmpl", nil) }) r.POST("/pwd", func(c *gin.Context) { - c.SetCookie("p", c.PostForm("p"), 0, "/", c.Request.Host, false, true) + if !sql.IpFree(c.ClientIP()) { + c.HTML(200, "msg.tmpl", gin.H{ + "msg": "IP is Ban", + "suc": false, + }) + return + } + session := sessions.Default(c) + session.Set("p", c.PostForm("p")) + session.Save() + if c.PostForm("p") != conf.WebPass { + ban := conf.IpBan{ + Ip: c.ClientIP(), + TimeStamp: time.Now().Unix(), + } + sql.AddBan(ban) + } c.Redirect(302, "/") }) fmt.Println("Web管理面板端口:" + conf.WebPort) @@ -93,10 +114,11 @@ func Run() { // 密码验证中间件 func checkCookieMiddleware(c *gin.Context) { - cookie, err := c.Cookie("p") currenPath := c.Request.URL.Path if conf.WebPass != "" && currenPath != "/pwd" { - if err != nil || cookie != conf.WebPass { + session := sessions.Default(c) + pass := session.Get("p") + if pass != conf.WebPass { c.Redirect(http.StatusFound, "/pwd") c.Abort() return