This commit is contained in:
WJQSERVER 2024-11-01 03:58:47 +08:00
parent 2a5570a447
commit 6f67f6f5b4
9 changed files with 72 additions and 5 deletions

View file

@ -1,5 +1,11 @@
# 更新日志
24w21a
---
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
- ADD: 尝试加入程序内置速率限制
- CHANGE: 更新相关依赖库
v1.6.2
---
- CHANGE: 优化前端界面,优化部分样式

View file

@ -1 +1 @@
24w20b
24w21a

View file

@ -12,6 +12,7 @@ type Config struct {
Auth AuthConfig
Blacklist BlacklistConfig
Whitelist WhitelistConfig
RateLimit RateLimitConfig
}
type ServerConfig struct {
@ -49,6 +50,12 @@ type WhitelistConfig struct {
WhitelistFile string `toml:"whitelistFile"`
}
type RateLimitConfig struct {
Enabled bool `toml:"enabled"`
RatePerMinute int `toml:"ratePerMinute"`
Burst int `toml:"burst"`
}
// LoadConfig 从 TOML 配置文件加载配置
func LoadConfig(filePath string) (*Config, error) {
var config Config

View file

@ -25,3 +25,8 @@ enabled = false
[whitelist]
enabled = false
whitelistFile = "/data/ghproxy/config/whitelist.json"
[rateLimit]
enabled = false
ratePerMinute = 100
burst = 10

5
go.mod
View file

@ -22,7 +22,7 @@ require (
github.com/go-playground/validator/v10 v10.22.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@ -32,7 +32,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/onsi/ginkgo/v2 v2.21.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.48.1 // indirect
@ -48,6 +48,7 @@ require (
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

7
go.sum
View file

@ -50,6 +50,8 @@ github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jn
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@ -76,8 +78,11 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -132,6 +137,8 @@ golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=

12
main.go
View file

@ -5,12 +5,14 @@ import (
"fmt"
"log"
"net/http"
"time"
"ghproxy/api"
"ghproxy/auth"
"ghproxy/config"
"ghproxy/logger"
"ghproxy/proxy"
"ghproxy/rate"
"github.com/gin-gonic/gin"
)
@ -20,6 +22,7 @@ var (
router *gin.Engine
configfile = "/data/ghproxy/config/config.toml"
cfgfile string
limiter *rate.RateLimiter
)
var (
@ -62,6 +65,13 @@ func setupApi(cfg *config.Config, router *gin.Engine) {
api.InitHandleRouter(cfg, router)
}
func setupRateLimit(cfg *config.Config) {
if cfg.RateLimit.Enabled {
limiter = rate.New(cfg.RateLimit.RatePerMinute, cfg.RateLimit.Burst, 1*time.Minute)
logInfo("Rate Limit Loaded")
}
}
func init() {
readFlag()
flag.Parse()
@ -92,7 +102,7 @@ func init() {
}
router.NoRoute(func(c *gin.Context) {
proxy.NoRouteHandler(cfg)(c)
proxy.NoRouteHandler(cfg, limiter)(c)
})
}

View file

@ -11,6 +11,7 @@ import (
"ghproxy/auth"
"ghproxy/config"
"ghproxy/logger"
"ghproxy/rate"
"github.com/gin-gonic/gin"
"github.com/imroc/req/v3"
@ -32,8 +33,17 @@ var exps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?://)?gist\.github(?:usercontent|)\.com/([^/]+)/.+?/.+`),
}
func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFunc {
return func(c *gin.Context) {
// 限制访问频率
if cfg.RateLimit.Enabled {
if !limiter.Allow() {
c.JSON(http.StatusTooManyRequests, gin.H{"error": "Too Many Requests"})
logWarning("%s %s %s %s %s 429-TooManyRequests", c.ClientIP(), c.Request.Method, c.Request.URL.RequestURI(), c.Request.Header.Get("User-Agent"), c.Request.Proto)
return
}
}
rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/")
re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`)
matches := re.FindStringSubmatch(rawPath)

21
rate/rate.go Normal file
View file

@ -0,0 +1,21 @@
package rate
import (
"time"
"golang.org/x/time/rate"
)
type RateLimiter struct {
limiter *rate.Limiter
}
func New(limit int, burst int, duration time.Duration) *RateLimiter {
return &RateLimiter{
limiter: rate.NewLimiter(rate.Limit(float64(limit)/duration.Seconds()), burst),
}
}
func (rl *RateLimiter) Allow() bool {
return rl.limiter.Allow()
}