diff --git a/internal/handler/subscribe.go b/internal/handler/subscribe.go index bf4cad8..1ec76da 100644 --- a/internal/handler/subscribe.go +++ b/internal/handler/subscribe.go @@ -10,41 +10,41 @@ import ( "github.com/perfect-panel/server/internal/types" ) -func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.SubscribeRequest - if c.Request.Header.Get("token") != "" { - req.Token = c.Request.Header.Get("token") - } else { - req.Token = c.Query("token") - } - 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) { - c.String(http.StatusForbidden, "Access denied") - return - } - } - - l := subscribe.NewSubscribeLogic(c, svcCtx) - resp, err := l.Generate(&req) - if err != nil { - return - } - c.Header("subscription-userinfo", resp.Header) - c.String(200, "%s", string(resp.Config)) - } -} +//func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// return func(c *gin.Context) { +// var req types.SubscribeRequest +// if c.Request.Header.Get("token") != "" { +// req.Token = c.Request.Header.Get("token") +// } else { +// req.Token = c.Query("token") +// } +// 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) { +// c.String(http.StatusForbidden, "Access denied") +// return +// } +// } +// +// l := subscribe.NewSubscribeLogic(c, svcCtx) +// resp, err := l.V2(&req) +// if err != nil { +// return +// } +// c.Header("subscription-userinfo", resp.Header) +// c.String(200, "%s", string(resp.Config)) +// } +//} func V2SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { diff --git a/internal/logic/subscribe/subscribeLogic.go b/internal/logic/subscribe/subscribeLogic.go index 063e13e..fd4a0a3 100644 --- a/internal/logic/subscribe/subscribeLogic.go +++ b/internal/logic/subscribe/subscribeLogic.go @@ -1,16 +1,9 @@ package subscribe import ( - "fmt" - "net/url" "strings" "time" - "github.com/perfect-panel/server/pkg/adapter" - "github.com/perfect-panel/server/pkg/adapter/shadowrocket" - "github.com/perfect-panel/server/pkg/adapter/surfboard" - "github.com/perfect-panel/server/pkg/adapter/surge" - "github.com/perfect-panel/server/internal/model/server" "github.com/perfect-panel/server/internal/model/user" @@ -39,38 +32,38 @@ func NewSubscribeLogic(ctx *gin.Context, svc *svc.ServiceContext) *SubscribeLogi } } -func (l *SubscribeLogic) Generate(req *types.SubscribeRequest) (*types.SubscribeResponse, error) { - userSub, err := l.getUserSubscribe(req.Token) - if err != nil { - return nil, err - } - - var subscribeStatus = false - defer func() { - l.logSubscribeActivity(subscribeStatus, userSub, req) - }() - - servers, err := l.getServers(userSub) - if err != nil { - return nil, err - } - - rules, err := l.getRules() - if err != nil { - return nil, err - } - - resp, headerInfo, err := l.buildClientConfig(req, userSub, servers, rules) - if err != nil { - return nil, err - } - - subscribeStatus = true - return &types.SubscribeResponse{ - Config: resp, - Header: headerInfo, - }, nil -} +//func (l *SubscribeLogic) GenerateBak(req *types.SubscribeRequest) (*types.SubscribeResponse, error) { +// userSub, err := l.getUserSubscribe(req.Token) +// if err != nil { +// return nil, err +// } +// +// var subscribeStatus = false +// defer func() { +// l.logSubscribeActivity(subscribeStatus, userSub, req) +// }() +// +// servers, err := l.getServers(userSub) +// if err != nil { +// return nil, err +// } +// +// rules, err := l.getRules() +// if err != nil { +// return nil, err +// } +// +// resp, headerInfo, err := l.buildClientConfig(req, userSub, servers, rules) +// if err != nil { +// return nil, err +// } +// +// subscribeStatus = true +// return &types.SubscribeResponse{ +// Config: resp, +// Header: headerInfo, +// }, nil +//} func (l *SubscribeLogic) getUserSubscribe(token string) (*user.Subscribe, error) { userSub, err := l.svc.UserModel.FindOneSubscribeByToken(l.ctx.Request.Context(), token) @@ -171,174 +164,174 @@ func (l *SubscribeLogic) getFirstHostLine() string { return host } -func (l *SubscribeLogic) getRules() ([]*server.RuleGroup, error) { - rules, err := l.svc.ServerModel.QueryAllRuleGroup(l.ctx) - if err != nil { - l.Errorw("[Generate Subscribe]find rule group error: %v", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find rule group error: %v", err.Error()) - } - return rules, nil -} +//func (l *SubscribeLogic) getRules() ([]*server.RuleGroup, error) { +// rules, err := l.svc.ServerModel.QueryAllRuleGroup(l.ctx) +// if err != nil { +// l.Errorw("[Generate Subscribe]find rule group error: %v", logger.Field("error", err.Error())) +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find rule group error: %v", err.Error()) +// } +// return rules, nil +//} +// +//func (l *SubscribeLogic) buildClientConfig(req *types.SubscribeRequest, userSub *user.Subscribe, servers []*server.Server, rules []*server.RuleGroup) ([]byte, string, error) { +// tags := make(map[string][]*server.Server) +// +// serverTags, err := l.svc.ServerModel.FindServerTags(l.ctx) +// if err != nil { +// l.Errorw("[Generate Subscribe]find server tags error: %v", logger.Field("error", err.Error())) +// return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server tags error: %v", err.Error()) +// } +// // Deduplicate tags +// serverTags = tool.RemoveDuplicateElements(serverTags...) +// for _, tag := range serverTags { +// s, err := l.svc.ServerModel.FindServersByTag(l.ctx.Request.Context(), tag) +// if err != nil { +// l.Errorw("[Generate Subscribe]find servers by tag error: %v", logger.Field("error", err.Error())) +// continue +// } +// if len(s) > 0 { +// tags[tag] = s +// } +// } +// +// proxyManager := adapter.NewAdapter(&adapter.Config{ +// Nodes: servers, +// Rules: rules, +// Tags: tags, +// }) +// clientType := l.getClientType(req) +// var resp []byte +// +// l.Logger.Info(fmt.Sprintf("[Generate Subscribe] %s", clientType), logger.Field("ua", req.UA), logger.Field("flag", req.Flag)) +// +// switch clientType { +// case "clash": +// resp, err = proxyManager.BuildClash(userSub.UUID) +// if err != nil { +// l.Errorw("[Generate Subscribe] build clash error", logger.Field("error", err.Error())) +// return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build clash error: %v", err.Error()) +// } +// l.setClashHeaders() +// case "sing-box": +// resp, err = proxyManager.BuildSingbox(userSub.UUID) +// if err != nil { +// l.Errorw("[Generate Subscribe] build sing-box error", logger.Field("error", err.Error())) +// return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build sing-box error: %v", err.Error()) +// } +// case "quantumult": +// resp = []byte(proxyManager.BuildQuantumultX(userSub.UUID)) +// case "shadowrocket": +// resp = proxyManager.BuildShadowrocket(userSub.UUID, shadowrocket.UserInfo{ +// Upload: userSub.Upload, +// Download: userSub.Download, +// TotalTraffic: userSub.Traffic, +// ExpiredDate: userSub.ExpireTime, +// }) +// case "loon": +// resp = proxyManager.BuildLoon(userSub.UUID) +// l.setLoonHeaders() +// case "surfboard": +// subsURL := l.getSubscribeURL(userSub.Token, "surfboard") +// resp = proxyManager.BuildSurfboard(l.svc.Config.Site.SiteName, surfboard.UserInfo{ +// Upload: userSub.Upload, +// Download: userSub.Download, +// TotalTraffic: userSub.Traffic, +// ExpiredDate: userSub.ExpireTime, +// UUID: userSub.UUID, +// SubscribeURL: subsURL, +// }) +// l.setSurfboardHeaders() +// case "v2rayn": +// resp = proxyManager.BuildV2rayN(userSub.UUID) +// case "surge": +// subsURL := l.getSubscribeURL(userSub.Token, "surge") +// resp = proxyManager.BuildSurge(l.svc.Config.Site.SiteName, surge.UserInfo{ +// UUID: userSub.UUID, +// Upload: userSub.Upload, +// Download: userSub.Download, +// TotalTraffic: userSub.Traffic, +// ExpiredDate: userSub.ExpireTime, +// SubscribeURL: subsURL, +// }) +// l.setSurgeHeaders() +// default: +// resp = proxyManager.BuildGeneral(userSub.UUID) +// } +// +// headerInfo := fmt.Sprintf("upload=%d;download=%d;total=%d;expire=%d", +// userSub.Upload, userSub.Download, userSub.Traffic, userSub.ExpireTime.Unix()) +// +// return resp, headerInfo, nil +//} +// +//func (l *SubscribeLogic) setClashHeaders() { +// l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s", url.QueryEscape(l.svc.Config.Site.SiteName))) +// l.ctx.Header("Profile-Update-Interval", "24") +// l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") +//} +// +//func (l *SubscribeLogic) setSurfboardHeaders() { +// l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) +// l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") +//} +// +//func (l *SubscribeLogic) setSurgeHeaders() { +// l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) +// l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") +//} +// +//func (l *SubscribeLogic) setLoonHeaders() { +// l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) +// l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") +//} -func (l *SubscribeLogic) buildClientConfig(req *types.SubscribeRequest, userSub *user.Subscribe, servers []*server.Server, rules []*server.RuleGroup) ([]byte, string, error) { - tags := make(map[string][]*server.Server) +//func (l *SubscribeLogic) getSubscribeURL(token, flag string) string { +// if l.svc.Config.Subscribe.PanDomain { +// return fmt.Sprintf("https://%s", l.ctx.Request.Host) +// } +// +// if l.svc.Config.Subscribe.SubscribeDomain != "" { +// domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n") +// return fmt.Sprintf("https://%s%s?token=%s&flag=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token, flag) +// } +// +// return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token) +//} - serverTags, err := l.svc.ServerModel.FindServerTags(l.ctx) - if err != nil { - l.Errorw("[Generate Subscribe]find server tags error: %v", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server tags error: %v", err.Error()) - } - // Deduplicate tags - serverTags = tool.RemoveDuplicateElements(serverTags...) - for _, tag := range serverTags { - s, err := l.svc.ServerModel.FindServersByTag(l.ctx.Request.Context(), tag) - if err != nil { - l.Errorw("[Generate Subscribe]find servers by tag error: %v", logger.Field("error", err.Error())) - continue - } - if len(s) > 0 { - tags[tag] = s - } - } - - proxyManager := adapter.NewAdapter(&adapter.Config{ - Nodes: servers, - Rules: rules, - Tags: tags, - }) - clientType := l.getClientType(req) - var resp []byte - - l.Logger.Info(fmt.Sprintf("[Generate Subscribe] %s", clientType), logger.Field("ua", req.UA), logger.Field("flag", req.Flag)) - - switch clientType { - case "clash": - resp, err = proxyManager.BuildClash(userSub.UUID) - if err != nil { - l.Errorw("[Generate Subscribe] build clash error", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build clash error: %v", err.Error()) - } - l.setClashHeaders() - case "sing-box": - resp, err = proxyManager.BuildSingbox(userSub.UUID) - if err != nil { - l.Errorw("[Generate Subscribe] build sing-box error", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build sing-box error: %v", err.Error()) - } - case "quantumult": - resp = []byte(proxyManager.BuildQuantumultX(userSub.UUID)) - case "shadowrocket": - resp = proxyManager.BuildShadowrocket(userSub.UUID, shadowrocket.UserInfo{ - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - }) - case "loon": - resp = proxyManager.BuildLoon(userSub.UUID) - l.setLoonHeaders() - case "surfboard": - subsURL := l.getSubscribeURL(userSub.Token, "surfboard") - resp = proxyManager.BuildSurfboard(l.svc.Config.Site.SiteName, surfboard.UserInfo{ - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - UUID: userSub.UUID, - SubscribeURL: subsURL, - }) - l.setSurfboardHeaders() - case "v2rayn": - resp = proxyManager.BuildV2rayN(userSub.UUID) - case "surge": - subsURL := l.getSubscribeURL(userSub.Token, "surge") - resp = proxyManager.BuildSurge(l.svc.Config.Site.SiteName, surge.UserInfo{ - UUID: userSub.UUID, - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - SubscribeURL: subsURL, - }) - l.setSurgeHeaders() - default: - resp = proxyManager.BuildGeneral(userSub.UUID) - } - - headerInfo := fmt.Sprintf("upload=%d;download=%d;total=%d;expire=%d", - userSub.Upload, userSub.Download, userSub.Traffic, userSub.ExpireTime.Unix()) - - return resp, headerInfo, nil -} - -func (l *SubscribeLogic) setClashHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Profile-Update-Interval", "24") - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setSurfboardHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setSurgeHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setLoonHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) getSubscribeURL(token, flag string) string { - if l.svc.Config.Subscribe.PanDomain { - return fmt.Sprintf("https://%s", l.ctx.Request.Host) - } - - if l.svc.Config.Subscribe.SubscribeDomain != "" { - domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n") - return fmt.Sprintf("https://%s%s?token=%s&flag=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token, flag) - } - - return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token) -} - -func (l *SubscribeLogic) getClientType(req *types.SubscribeRequest) string { - clientTypeMap := map[string]string{ - "clash": "clash", - "meta": "clash", - "sing-box": "sing-box", - "hiddify": "sing-box", - "surge": "surge", - "quantumult": "quantumult", - "shadowrocket": "shadowrocket", - "loon": "loon", - "surfboard": "surfboard", - "v2rayn": "v2rayn", - } - - findClient := func(s string) string { - s = strings.ToLower(strings.TrimSpace(s)) - if s == "" { - return "" - } - - for key, clientType := range clientTypeMap { - if strings.Contains(s, key) { - return clientType - } - } - - return "" - } - - // 优先检查Flag参数 - if typ := findClient(req.Flag); typ != "" { - return typ - } - - // 其次检查UA参数 - return findClient(req.UA) -} +//func (l *SubscribeLogic) getClientType(req *types.SubscribeRequest) string { +// clientTypeMap := map[string]string{ +// "clash": "clash", +// "meta": "clash", +// "sing-box": "sing-box", +// "hiddify": "sing-box", +// "surge": "surge", +// "quantumult": "quantumult", +// "shadowrocket": "shadowrocket", +// "loon": "loon", +// "surfboard": "surfboard", +// "v2rayn": "v2rayn", +// } +// +// findClient := func(s string) string { +// s = strings.ToLower(strings.TrimSpace(s)) +// if s == "" { +// return "" +// } +// +// for key, clientType := range clientTypeMap { +// if strings.Contains(s, key) { +// return clientType +// } +// } +// +// return "" +// } +// +// // 优先检查Flag参数 +// if typ := findClient(req.Flag); typ != "" { +// return typ +// } +// +// // 其次检查UA参数 +// return findClient(req.UA) +//} diff --git a/internal/logic/subscribe/v2Logic.go b/internal/logic/subscribe/v2Logic.go index c4ed247..ebc4fdc 100644 --- a/internal/logic/subscribe/v2Logic.go +++ b/internal/logic/subscribe/v2Logic.go @@ -110,6 +110,7 @@ func (l *SubscribeLogic) V2(req *types.SubscribeRequest) (resp *types.SubscribeR userSubscribe.Upload, userSubscribe.Download, userSubscribe.Traffic, userSubscribe.ExpireTime.Unix(), ), } + subscribeStatus = true return } diff --git a/internal/middleware/panDomainMiddleware.go b/internal/middleware/panDomainMiddleware.go index b5ce8eb..68977af 100644 --- a/internal/middleware/panDomainMiddleware.go +++ b/internal/middleware/panDomainMiddleware.go @@ -41,7 +41,7 @@ func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { UA: c.Request.Header.Get("User-Agent"), } l := subscribe.NewSubscribeLogic(c, svc) - resp, err := l.Generate(&request) + resp, err := l.V2(&request) if err != nil { return }