improve: 优化 detector 请求数量

This commit is contained in:
Mmx233
2024-01-01 18:22:38 +08:00
parent 4080ef291b
commit ca2215b44e
2 changed files with 145 additions and 149 deletions

View File

@@ -25,11 +25,13 @@ func Login(eth *tools.Eth, debugOutput bool) error {
CustomHeader: config.Settings.CustomHeader, CustomHeader: config.Settings.CustomHeader,
}) })
srunDetector := srunClient.Api.NewDetector()
// Reality 与 Acid // Reality 与 Acid
var acidOnReality bool var acidOnReality bool
if config.Settings.Reality.Enable { if config.Settings.Reality.Enable {
log.Debugln("开始 Reality 流程") 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 { if err != nil {
log.Errorln("Reality 请求异常:", err) log.Errorln("Reality 请求异常:", err)
return err return err
@@ -46,7 +48,7 @@ func Login(eth *tools.Eth, debugOutput bool) error {
} }
if !acidOnReality && flags.AutoAcid { if !acidOnReality && flags.AutoAcid {
log.Debugln("开始嗅探 acid") log.Debugln("开始嗅探 acid")
acid, err := srunClient.Api.DetectAcid() acid, err := srunDetector.DetectAcid()
if err != nil { if err != nil {
if errors.Is(err, srun.ErrAcidCannotFound) { if errors.Is(err, srun.ErrAcidCannotFound) {
log.Warnln("找不到 acid使用配置 acid") log.Warnln("找不到 acid使用配置 acid")
@@ -61,7 +63,7 @@ func Login(eth *tools.Eth, debugOutput bool) error {
if flags.AutoEnc { if flags.AutoEnc {
log.Debugln("开始嗅探 enc") log.Debugln("开始嗅探 enc")
enc, err := srunClient.Api.DetectEnc() enc, err := srunDetector.DetectEnc()
if err != nil { if err != nil {
if errors.Is(err, srun.ErrEnvCannotFound) { if errors.Is(err, srun.ErrEnvCannotFound) {
log.Warnln("找不到 enc使用配置 enc") log.Warnln("找不到 enc使用配置 enc")

View File

@@ -13,14 +13,25 @@ import (
) )
func (a *Api) NewDetector() Detector { func (a *Api) NewDetector() Detector {
redirectReg, err := regexp.Compile(
`<script>top\.self\.location\.href='(.*)'</script>|<meta http-equiv="refresh" content=".*url=(.*?)">`,
)
if err != nil {
panic(err)
}
return Detector{ return Detector{
api: a, api: a,
redirectReg: redirectReg,
} }
} }
type Detector struct { type Detector struct {
api *Api api *Api
redirectReg *regexp.Regexp
// 登录页 html data
page []byte page []byte
} }
@@ -37,58 +48,67 @@ func (a *Detector) _JoinRedirectLocation(addr *url.URL, loc string) (*url.URL, e
} }
type _FollowRedirectConfig struct { type _FollowRedirectConfig struct {
// 覆盖响应处理逻辑,设置后 onNextAddr 无效
onResponse func(res *http.Response) (next *url.URL, err error)
// 获取到下一个请求地址时触发 // 获取到下一个请求地址时触发
onNextAddr func(addr *url.URL) 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 addrCopy := *addr
addr = &addrCopy addr = &addrCopy
var body []byte
var res *http.Response
for { for {
log.Debugln("HTTP GET", addr) log.Debugln("HTTP GET", addr)
req, err := http.NewRequest("GET", addr.String(), nil) req, err := http.NewRequest("GET", addr.String(), nil)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
for k, v := range a.api.CustomHeader { for k, v := range a.api.CustomHeader {
req.Header.Set(k, fmt.Sprint(v)) req.Header.Set(k, fmt.Sprint(v))
} }
res, err := a.api.NoDirect.Do(req) res, err = a.api.NoDirect.Do(req)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if conf.onResponse != nil {
var nextAddr *url.URL if res.StatusCode < 300 {
nextAddr, err = conf.onResponse(res) body, err = io.ReadAll(res.Body)
_ = res.Body.Close()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} else if nextAddr == nil { }
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 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 { } 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) { 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) { func (a *Detector) DetectEnc() (string, error) {
log.Debugln("HTTP GET", a.api.BaseUrl) if a.page == nil {
res, err := a.api.Client.Get(a.api.BaseUrl) 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)<script src="\.?(.+[./]portal[0-9]*\.js)(\?.*)?">`)
if err != nil { if err != nil {
return "", err return "", err
} }
defer res.Body.Close() jsPathMatch := jsReg.FindSubmatch(a.page)
if res.StatusCode == 200 { if len(jsPathMatch) == 3 {
indexHtml, err := io.ReadAll(res.Body) jsPathBytes := jsPathMatch[1]
jsPath := unsafe.String(unsafe.SliceData(jsPathBytes), len(jsPathBytes))
jsUrl, err := url.Parse(a.api.BaseUrl)
if err != nil { if err != nil {
return "", err return "", err
} }
jsReg, err := regexp.Compile(`(?i)<script src="\.?(.+[./]portal[0-9]*\.js)(\?.*)?">`) jsUrl.Path = jsPath
jsAddr := jsUrl.String()
log.Debugln("HTTP GET", jsAddr)
jsRes, err := a.api.Client.Get(jsAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
jsPathMatch := jsReg.FindSubmatch(indexHtml) defer jsRes.Body.Close()
if len(jsPathMatch) == 3 { if jsRes.StatusCode == 200 {
jsPathBytes := jsPathMatch[1] jsContent, err := io.ReadAll(jsRes.Body)
jsPath := unsafe.String(unsafe.SliceData(jsPathBytes), len(jsPathBytes)) if err == nil {
jsUrl, err := url.Parse(a.api.BaseUrl) reg, err := regexp.Compile(`var enc = (.*?)[,;]`)
if err != nil { if err != nil {
return "", err return "", err
} }
jsUrl.Path = jsPath encMatch := reg.FindSubmatch(jsContent)
jsAddr := jsUrl.String() if len(encMatch) == 2 {
log.Debugln("HTTP GET", jsAddr) encBytes := encMatch[1]
jsRes, err := a.api.Client.Get(jsAddr) encStr := unsafe.String(unsafe.SliceData(encBytes), len(encBytes))
if err != nil { encSplit := strings.Split(encStr, "+")
return "", err for i, v := range encSplit {
} encSplit[i] = strings.Trim(strings.TrimSpace(v), "'\"")
defer jsRes.Body.Close() }
if jsRes.StatusCode == 200 { enc := strings.Join(encSplit, "")
jsContent, err := io.ReadAll(jsRes.Body) return enc, nil
if err == nil {
reg, err := regexp.Compile(`var enc = (.*?)[,;]`)
if err != nil {
return "", err
}
encMatch := reg.FindSubmatch(jsContent)
if len(encMatch) == 2 {
encBytes := encMatch[1]
encStr := unsafe.String(unsafe.SliceData(encBytes), len(encBytes))
encSplit := strings.Split(encStr, "+")
for i, v := range encSplit {
encSplit[i] = strings.Trim(strings.TrimSpace(v), "'\"")
}
enc := strings.Join(encSplit, "")
return enc, nil
}
} }
} else {
_, _ = io.Copy(io.Discard, jsRes.Body)
} }
} else {
_, _ = io.Copy(io.Discard, jsRes.Body)
} }
} else {
_, _ = io.Copy(io.Discard, res.Body)
} }
return "", ErrEnvCannotFound return "", ErrEnvCannotFound
} }
// DetectAcid err 为 nil 时 acid 一定存在 // DetectAcid err 为 nil 时 acid 一定存在
func (a *Detector) DetectAcid() (string, error) { func (a *Detector) DetectAcid() (string, error) {
// 从入口地址 url query 寻找 acid if a.page == nil {
baseUrl, err := url.Parse(a.api.BaseUrl) // page 有值时说明 reality 已进行过 query match此部分可跳过
if err != nil { // 从入口地址 url query 寻找 acid
return "", err baseUrl, err := url.Parse(a.api.BaseUrl)
} if err != nil {
return "", err
var AcidFound = errors.New("acid found") }
var acid string
finalAddr, err := a._FollowRedirect(baseUrl, _FollowRedirectConfig{ var AcidFound = errors.New("acid found")
onNextAddr: func(addr *url.URL) error { var acid string
var ok bool _, a.page, err = a._FollowRedirect(baseUrl, _FollowRedirectConfig{
acid, ok = a._SearchAcid(addr.Query()) onNextAddr: func(addr *url.URL) error {
if ok { var ok bool
return AcidFound acid, ok = a._SearchAcid(addr.Query())
} if ok {
return nil return AcidFound
}, }
}) return nil
if err != nil { },
if errors.Is(err, AcidFound) { })
return acid, nil if err != nil {
if errors.Is(err, AcidFound) {
return acid, nil
}
return "", err
} }
return "", err
} }
// 从 html 寻找 acid // 从 html 寻找 acid
log.Debugln("HTTP GET", finalAddr.String()) var reg *regexp.Regexp
res, err := a.api.Client.Get(a.api.BaseUrl) reg, err := regexp.Compile(`"ac_id".*?value="(.+)"`)
if err != nil { if err != nil {
return "", err return "", err
} }
defer res.Body.Close() result := reg.FindSubmatch(a.page)
if res.StatusCode == 200 { if len(result) == 2 {
var indexHtml []byte return string(result[1]), nil
indexHtml, err = io.ReadAll(res.Body)
if err == nil {
var reg *regexp.Regexp
reg, err = regexp.Compile(`"ac_id".*?value="(.+)"`)
if err != nil {
return "", err
}
result := reg.FindSubmatch(indexHtml)
if len(result) == 2 {
return string(result[1]), nil
}
}
} else {
_, _ = io.Copy(io.Discard, res.Body)
} }
return "", ErrAcidCannotFound return "", ErrAcidCannotFound
@@ -219,36 +232,12 @@ func (a *Detector) Reality(addr string, getAcid bool) (acid string, online bool,
return "", false, err return "", false, err
} }
var AlreadyOnline = errors.New("already online") var AlreadyOnline = errors.New("already online")
var finalUrl *url.URL finalRes, pageBytes, err := a._FollowRedirect(startUrl, _FollowRedirectConfig{
finalUrl, err = a._FollowRedirect(startUrl, _FollowRedirectConfig{ onNextAddr: func(addr *url.URL) error {
onResponse: func(res *http.Response) (next *url.URL, err error) { if getAcid {
defer res.Body.Close() acid, _ = a._SearchAcid(addr.Query())
if res.StatusCode < 300 {
var body []byte
body, err = io.ReadAll(res.Body)
if err != nil {
return
}
var reg *regexp.Regexp
reg, err = regexp.Compile(`<script>top\.self\.location\.href='(.*)'</script>`)
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"))
} }
if getAcid && next != nil { return nil
acid, _ = a._SearchAcid(next.Query())
}
return
}, },
}) })
if err != nil { if err != nil {
@@ -259,6 +248,11 @@ func (a *Detector) Reality(addr string, getAcid bool) (acid string, online bool,
} }
return return
} }
online = finalUrl.Host == startUrl.Host online = finalRes.Request.URL.Host == startUrl.Host
a.page = pageBytes
return return
} }
func (a *Detector) Reset() {
a.page = nil
}