From 6580cc9d44fb71dcbe9831a4e016f9d88f3afe81 Mon Sep 17 00:00:00 2001 From: Chang lue Tsen Date: Sat, 16 Aug 2025 13:37:09 -0400 Subject: [PATCH] feat(subscribe): implement user agent limit feature with configurable list --- .../database/02102_subscribe_config.down.sql | 0 internal/config/config.go | 2 ++ internal/handler/subscribe.go | 32 +++++++++++-------- internal/middleware/panDomainMiddleware.go | 24 ++++++++------ 4 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 initialize/migrate/database/02102_subscribe_config.down.sql diff --git a/initialize/migrate/database/02102_subscribe_config.down.sql b/initialize/migrate/database/02102_subscribe_config.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/config/config.go b/internal/config/config.go index 1d51df4..6758559 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -55,6 +55,8 @@ type SubscribeConfig struct { SubscribePath string `yaml:"SubscribePath" default:"/api/subscribe"` SubscribeDomain string `yaml:"SubscribeDomain" default:""` PanDomain bool `yaml:"PanDomain" default:"false"` + UserAgentLimit bool `yaml:"UserAgentLimit" default:"false"` + UserAgentList string `yaml:"UserAgentList" default:""` } type RegisterConfig struct { diff --git a/internal/handler/subscribe.go b/internal/handler/subscribe.go index baf64a4..4751be6 100644 --- a/internal/handler/subscribe.go +++ b/internal/handler/subscribe.go @@ -10,7 +10,7 @@ import ( "github.com/perfect-panel/server/internal/types" ) -func V2SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { var req types.SubscribeRequest if c.Request.Header.Get("token") != "" { @@ -18,20 +18,26 @@ func V2SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { } else { req.Token = c.Query("token") } + ua := c.GetHeader("User-Agent") req.UA = c.Request.Header.Get("User-Agent") req.Flag = c.Query("flag") - // intercept browser - ua := c.GetHeader("User-Agent") - if ua == "" { - c.String(http.StatusForbidden, "Access denied") - return - } - browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} - for _, keyword := range browserKeywords { - lcUA := strings.ToLower(ua) - if strings.Contains(lcUA, keyword) { + if svcCtx.Config.Subscribe.UserAgentLimit { + if ua == "" { c.String(http.StatusForbidden, "Access denied") + c.Abort() + return + } + browserKeywords := strings.Split(svcCtx.Config.Subscribe.UserAgentList, "\n") + var allow = false + for _, keyword := range browserKeywords { + if strings.Contains(strings.ToLower(ua), strings.ToLower(keyword)) { + allow = true + } + } + if !allow { + c.String(http.StatusForbidden, "Access denied") + c.Abort() return } } @@ -51,7 +57,5 @@ func RegisterSubscribeHandlers(router *gin.Engine, serverCtx *svc.ServiceContext if path == "" { path = "/api/subscribe" } - router.GET(path, V2SubscribeHandler(serverCtx)) - - router.GET(path+"/v2", V2SubscribeHandler(serverCtx)) + router.GET(path, SubscribeHandler(serverCtx)) } diff --git a/internal/middleware/panDomainMiddleware.go b/internal/middleware/panDomainMiddleware.go index 0b41376..576ff59 100644 --- a/internal/middleware/panDomainMiddleware.go +++ b/internal/middleware/panDomainMiddleware.go @@ -17,15 +17,21 @@ func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { // intercept browser ua := c.GetHeader("User-Agent") - if ua == "" { - c.String(http.StatusForbidden, "Access denied") - c.Abort() - return - } - browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} - for _, keyword := range browserKeywords { - lcUA := strings.ToLower(ua) - if strings.Contains(lcUA, keyword) { + + if svc.Config.Subscribe.UserAgentLimit { + if ua == "" { + c.String(http.StatusForbidden, "Access denied") + c.Abort() + return + } + browserKeywords := strings.Split(svc.Config.Subscribe.UserAgentList, "\n") + var allow = false + for _, keyword := range browserKeywords { + if strings.Contains(strings.ToLower(ua), keyword) { + allow = true + } + } + if !allow { c.String(http.StatusForbidden, "Access denied") c.Abort() return