diff --git a/internal/controllers/login.go b/internal/controllers/login.go
index 8063023..4b7ad8e 100644
--- a/internal/controllers/login.go
+++ b/internal/controllers/login.go
@@ -25,11 +25,13 @@ func Login(eth *tools.Eth, debugOutput bool) error {
CustomHeader: config.Settings.CustomHeader,
})
+ srunDetector := srunClient.Api.NewDetector()
+
// Reality 与 Acid
var acidOnReality bool
if config.Settings.Reality.Enable {
log.Debugln("开始 Reality 流程")
- acid, _, err := srunClient.Api.Reality(config.Settings.Reality.Addr, flags.AutoAcid)
+ acid, _, err := srunDetector.Reality(config.Settings.Reality.Addr, flags.AutoAcid)
if err != nil {
log.Errorln("Reality 请求异常:", err)
return err
@@ -46,7 +48,7 @@ func Login(eth *tools.Eth, debugOutput bool) error {
}
if !acidOnReality && flags.AutoAcid {
log.Debugln("开始嗅探 acid")
- acid, err := srunClient.Api.DetectAcid()
+ acid, err := srunDetector.DetectAcid()
if err != nil {
if errors.Is(err, srun.ErrAcidCannotFound) {
log.Warnln("找不到 acid,使用配置 acid")
@@ -61,7 +63,7 @@ func Login(eth *tools.Eth, debugOutput bool) error {
if flags.AutoEnc {
log.Debugln("开始嗅探 enc")
- enc, err := srunClient.Api.DetectEnc()
+ enc, err := srunDetector.DetectEnc()
if err != nil {
if errors.Is(err, srun.ErrEnvCannotFound) {
log.Warnln("找不到 enc,使用配置 enc")
diff --git a/pkg/srun/detect.go b/pkg/srun/detect.go
index 781e580..cef1a7f 100644
--- a/pkg/srun/detect.go
+++ b/pkg/srun/detect.go
@@ -13,14 +13,25 @@ import (
)
func (a *Api) NewDetector() Detector {
+ redirectReg, err := regexp.Compile(
+ `|`,
+ )
+ if err != nil {
+ panic(err)
+ }
+
return Detector{
- api: a,
+ api: a,
+ redirectReg: redirectReg,
}
}
type Detector struct {
api *Api
+ redirectReg *regexp.Regexp
+
+ // 登录页 html data
page []byte
}
@@ -37,58 +48,67 @@ func (a *Detector) _JoinRedirectLocation(addr *url.URL, loc string) (*url.URL, e
}
type _FollowRedirectConfig struct {
- // 覆盖响应处理逻辑,设置后 onNextAddr 无效
- onResponse func(res *http.Response) (next *url.URL, err error)
// 获取到下一个请求地址时触发
onNextAddr func(addr *url.URL) error
}
-func (a *Detector) _FollowRedirect(addr *url.URL, conf _FollowRedirectConfig) (*url.URL, error) {
+func (a *Detector) _FollowRedirect(addr *url.URL, conf _FollowRedirectConfig) (*http.Response, []byte, error) {
addrCopy := *addr
addr = &addrCopy
+
+ var body []byte
+ var res *http.Response
for {
log.Debugln("HTTP GET", addr)
req, err := http.NewRequest("GET", addr.String(), nil)
if err != nil {
- return nil, err
+ return nil, nil, err
}
for k, v := range a.api.CustomHeader {
req.Header.Set(k, fmt.Sprint(v))
}
- res, err := a.api.NoDirect.Do(req)
+ res, err = a.api.NoDirect.Do(req)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- if conf.onResponse != nil {
- var nextAddr *url.URL
- nextAddr, err = conf.onResponse(res)
+
+ if res.StatusCode < 300 {
+ body, err = io.ReadAll(res.Body)
+ _ = res.Body.Close()
if err != nil {
- return nil, err
- } else if nextAddr == nil {
+ return nil, nil, err
+ }
+ locMatch := a.redirectReg.FindSubmatch(body)
+ if len(locMatch) > 2 {
+ locBytes := locMatch[1]
+ addr, err = a._JoinRedirectLocation(addr, unsafe.String(unsafe.SliceData(locBytes), len(locBytes)))
+ if err != nil {
+ return nil, nil, err
+ }
+ } else {
break
}
- addr = nextAddr
- continue
- }
- _, _ = io.Copy(io.Discard, res.Body)
- _ = res.Body.Close()
- if res.StatusCode < 300 {
- break
- } else if res.StatusCode < 400 {
- addr, err = a._JoinRedirectLocation(addr, res.Header.Get("location"))
- if err != nil {
- return nil, err
- }
- if conf.onNextAddr != nil {
- if err = conf.onNextAddr(addr); err != nil {
- return nil, err
- }
- }
} else {
- return nil, fmt.Errorf("server return http status %d", res.StatusCode)
+ _, _ = io.Copy(io.Discard, res.Body)
+ _ = res.Body.Close()
+
+ if res.StatusCode < 400 {
+ addr, err = a._JoinRedirectLocation(addr, res.Header.Get("location"))
+ if err != nil {
+ return nil, nil, err
+ }
+ } else {
+ return nil, nil, fmt.Errorf("server return http status %d", res.StatusCode)
+ }
+ }
+
+ if conf.onNextAddr != nil {
+ if err = conf.onNextAddr(addr); err != nil {
+ return nil, nil, err
+ }
}
}
- return addr, nil
+ return res, body, nil
}
func (a *Detector) _SearchAcid(query url.Values) (string, bool) {
@@ -97,116 +117,109 @@ func (a *Detector) _SearchAcid(query url.Values) (string, bool) {
}
func (a *Detector) DetectEnc() (string, error) {
- log.Debugln("HTTP GET", a.api.BaseUrl)
- res, err := a.api.Client.Get(a.api.BaseUrl)
+ if a.page == nil {
+ log.Debugln("HTTP GET", a.api.BaseUrl)
+ res, err := a.api.Client.Get(a.api.BaseUrl)
+ if err != nil {
+ return "", err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ _, _ = io.Copy(io.Discard, res.Body)
+ return "", fmt.Errorf("server return http status: %d", res.StatusCode)
+ }
+ a.page, err = io.ReadAll(res.Body)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ jsReg, err := regexp.Compile(`(?i)`)
- if err != nil {
- return
- }
-
- result := reg.FindSubmatch(body)
- if len(result) == 2 {
- nextBytes := result[1]
- nextAddr := unsafe.String(unsafe.SliceData(nextBytes), len(nextBytes))
- next, err = url.Parse(nextAddr)
- }
- } else if res.StatusCode < 400 {
- next, err = a._JoinRedirectLocation(res.Request.URL, res.Header.Get("location"))
+ finalRes, pageBytes, err := a._FollowRedirect(startUrl, _FollowRedirectConfig{
+ onNextAddr: func(addr *url.URL) error {
+ if getAcid {
+ acid, _ = a._SearchAcid(addr.Query())
}
- if getAcid && next != nil {
- acid, _ = a._SearchAcid(next.Query())
- }
- return
+ return nil
},
})
if err != nil {
@@ -259,6 +248,11 @@ func (a *Detector) Reality(addr string, getAcid bool) (acid string, online bool,
}
return
}
- online = finalUrl.Host == startUrl.Host
+ online = finalRes.Request.URL.Host == startUrl.Host
+ a.page = pageBytes
return
}
+
+func (a *Detector) Reset() {
+ a.page = nil
+}