diff --git a/internal/client/client.go b/internal/client/client.go index ebfe203..77108c3 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -7,7 +7,6 @@ import ( "io" "mime/multipart" "net/http" - "net/url" "reflect" "strconv" "strings" @@ -430,7 +429,7 @@ func (c *DouyuClient) Exchange(cookie, commodityID string, csrf *string) (string } `json:"data"` } if c.Activity.UseCTN { - // 电竞手册:用 ctn(acf_ccn) 鉴权,urlencoded 表单 + // 电竞手册:用 ctn(acf_ccn) 鉴权,multipart 表单(与浏览器抓包一致) ctn := "" if csrf != nil { parts := strings.SplitN(*csrf, "\x00", 2) @@ -446,7 +445,7 @@ func (c *DouyuClient) Exchange(cookie, commodityID string, csrf *string) (string } ctn = ctnVal } - if err := c.postForm(c.Activity.ExchangeURL, cookie, csrf, "正式兑换", map[string]string{ + if err := c.postMultipart(c.Activity.ExchangeURL, cookie, csrf, "正式兑换", map[string]string{ "manualID": c.Activity.ManualID, "commodityID": commodityID, "num": "1", @@ -558,11 +557,22 @@ func (c *DouyuClient) postMultipart(url, cookie string, csrf *string, label stri if err != nil { return err } + // 处理组合 token:csrf\x00ctn(电竞手册用 ctn 鉴权时) + // 拆分后 cvl_csrf_token 和 acf_ccn 都合并到 Cookie 头 currentCSRF := "" + ctnVal := "" if csrf != nil { - currentCSRF = *csrf + parts := strings.SplitN(*csrf, "\x00", 2) + currentCSRF = parts[0] + if len(parts) > 1 { + ctnVal = parts[1] + } } - c.setBrowserHeaders(req, utils.MergeCookie(cookie, "cvl_csrf_token", currentCSRF)) + mergedCookie := utils.MergeCookie(cookie, "cvl_csrf_token", currentCSRF) + if ctnVal != "" { + mergedCookie = utils.MergeCookie(mergedCookie, "acf_ccn", ctnVal) + } + c.setBrowserHeaders(req, mergedCookie) req.Header.Set("Content-Type", writer.FormDataContentType()) resp, err := c.doJSON(req, out, label) if resp != nil { @@ -570,43 +580,6 @@ func (c *DouyuClient) postMultipart(url, cookie string, csrf *string, label stri if nextCSRF != *csrf { logger.LogEvent("网络", "info", "响应刷新CSRF已同步: %s %s %s", label, req.Method, requestPath(req)) } - *csrf = nextCSRF - } - } - return err -} - -// postForm 发送 application/x-www-form-urlencoded POST 请求。 -// 用于电竞手册等使用 ctn 鉴权的活动。 -// csrf 参数为组合值 "cvl_csrf_token\x00acf_ccn",两者都会合并到 Cookie 头。 -func (c *DouyuClient) postForm(targetURL, cookie string, csrf *string, label string, fields map[string]string, out any) error { - vals := url.Values{} - for k, v := range fields { - vals.Set(k, v) - } - req, err := http.NewRequest("POST", targetURL, strings.NewReader(vals.Encode())) - if err != nil { - return err - } - // 拆分组合 token,合并到 Cookie - csrfVal := "" - ctnVal := "" - if csrf != nil { - parts := strings.SplitN(*csrf, "\x00", 2) - csrfVal = parts[0] - if len(parts) > 1 { - ctnVal = parts[1] - } - } - mergedCookie := utils.MergeCookie(cookie, "cvl_csrf_token", csrfVal) - if ctnVal != "" { - mergedCookie = utils.MergeCookie(mergedCookie, "acf_ccn", ctnVal) - } - c.setBrowserHeaders(req, mergedCookie) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") - resp, err := c.doJSON(req, out, label) - if resp != nil && csrf != nil { - if nextCSRF := csrfFromResponse(resp); nextCSRF != "" { if ctnVal != "" { *csrf = nextCSRF + "\x00" + ctnVal } else {