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 +}