feat(subscribe): implement user agent limit feature with configurable list

This commit is contained in:
Chang lue Tsen 2025-08-16 13:37:09 -04:00
parent 4f2aafd8b2
commit 6580cc9d44
4 changed files with 35 additions and 23 deletions

View File

@ -55,6 +55,8 @@ type SubscribeConfig struct {
SubscribePath string `yaml:"SubscribePath" default:"/api/subscribe"` SubscribePath string `yaml:"SubscribePath" default:"/api/subscribe"`
SubscribeDomain string `yaml:"SubscribeDomain" default:""` SubscribeDomain string `yaml:"SubscribeDomain" default:""`
PanDomain bool `yaml:"PanDomain" default:"false"` PanDomain bool `yaml:"PanDomain" default:"false"`
UserAgentLimit bool `yaml:"UserAgentLimit" default:"false"`
UserAgentList string `yaml:"UserAgentList" default:""`
} }
type RegisterConfig struct { type RegisterConfig struct {

View File

@ -10,7 +10,7 @@ import (
"github.com/perfect-panel/server/internal/types" "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) { return func(c *gin.Context) {
var req types.SubscribeRequest var req types.SubscribeRequest
if c.Request.Header.Get("token") != "" { if c.Request.Header.Get("token") != "" {
@ -18,20 +18,26 @@ func V2SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
} else { } else {
req.Token = c.Query("token") req.Token = c.Query("token")
} }
ua := c.GetHeader("User-Agent")
req.UA = c.Request.Header.Get("User-Agent") req.UA = c.Request.Header.Get("User-Agent")
req.Flag = c.Query("flag") req.Flag = c.Query("flag")
// intercept browser if svcCtx.Config.Subscribe.UserAgentLimit {
ua := c.GetHeader("User-Agent") if ua == "" {
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) {
c.String(http.StatusForbidden, "Access denied") 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 return
} }
} }
@ -51,7 +57,5 @@ func RegisterSubscribeHandlers(router *gin.Engine, serverCtx *svc.ServiceContext
if path == "" { if path == "" {
path = "/api/subscribe" path = "/api/subscribe"
} }
router.GET(path, V2SubscribeHandler(serverCtx)) router.GET(path, SubscribeHandler(serverCtx))
router.GET(path+"/v2", V2SubscribeHandler(serverCtx))
} }

View File

@ -17,15 +17,21 @@ func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) {
// intercept browser // intercept browser
ua := c.GetHeader("User-Agent") ua := c.GetHeader("User-Agent")
if ua == "" {
c.String(http.StatusForbidden, "Access denied") if svc.Config.Subscribe.UserAgentLimit {
c.Abort() if ua == "" {
return c.String(http.StatusForbidden, "Access denied")
} c.Abort()
browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} return
for _, keyword := range browserKeywords { }
lcUA := strings.ToLower(ua) browserKeywords := strings.Split(svc.Config.Subscribe.UserAgentList, "\n")
if strings.Contains(lcUA, keyword) { 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.String(http.StatusForbidden, "Access denied")
c.Abort() c.Abort()
return return