Browse Source

Merge pull request #147 from Moroka8/fix/vk-captcha-checkbox

fix: handle checkbox captcha and improve manual proxy debug
main v1.8.3
cacggghp 2 months ago
committed by GitHub
parent
commit
e8a96967dc
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      client/main.go
  2. 20
      client/manual_captcha.go
  3. 18
      client/slider_captcha.go

2
client/main.go

@ -228,7 +228,7 @@ func applyBrowserProfileFhttp(req *fhttp.Request, profile Profile) {
}
func generateBrowserFp(profile Profile) string {
data := profile.UserAgent + profile.SecChUa + "1920x1080x24"
data := profile.UserAgent + profile.SecChUa + "1920x1080x24" + strconv.FormatInt(time.Now().UnixNano(), 10)
h := md5.Sum([]byte(data))
return hex.EncodeToString(h[:])
}

20
client/manual_captcha.go

@ -125,6 +125,7 @@ func rewriteProxyRequest(req *http.Request, targetURL *neturl.URL) {
req.Host = targetURL.Host
req.Header.Del("Accept-Encoding")
req.Header.Del("TE") // Disable transfer encoding compression
for _, headerName := range []string{"Origin", "Referer"} {
if rewritten := rewriteProxyHeaderURL(req.Header.Get(headerName), targetURL); rewritten != "" {
req.Header.Set(headerName, rewritten)
@ -341,7 +342,7 @@ func newCaptchaProxyTransport(dialer *dnsdialer.Dialer) *http.Transport {
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
ForceAttemptHTTP2: false,
}
if dialer != nil {
transport.DialContext = dialer.DialContext
@ -458,16 +459,17 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
rewriteProxyRequest(req.Out, targetURL)
},
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
log.Printf("captcha proxy error for %s: %v", r.URL.String(), err)
log.Printf("[Captcha Proxy] ERROR for %s %s: %v", r.Method, r.URL.String(), err)
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusBadGateway)
_, _ = fmt.Fprintf(w, `<!DOCTYPE html><html><body style="font-family:sans-serif;padding:20px"><h2>Captcha proxy error</h2><p>%v</p></body></html>`, err)
_, _ = fmt.Fprintf(w, `<!DOCTYPE html><html><body style="font-family:sans-serif;padding:20px"><h2>Captcha proxy error</h2><p>%s %s</p><p>%v</p></body></html>`, r.Method, r.URL.String(), err)
},
ModifyResponse: func(res *http.Response) error {
rewriteProxyCookies(res.Header)
if res.StatusCode >= 300 && res.StatusCode < 400 {
if loc := res.Header.Get("Location"); loc != "" {
log.Printf("[Captcha Proxy] Redirecting to: %s", loc)
if rewritten, ok := rewriteProxyRedirectLocation(loc, targetURL); ok {
res.Header.Set("Location", rewritten)
} else {
@ -477,7 +479,13 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
}
contentType := res.Header.Get("Content-Type")
shouldInspectBody := strings.Contains(contentType, "text/html") || strings.Contains(res.Request.URL.Path, "captchaNotRobot.check")
contentEncoding := res.Header.Get("Content-Encoding")
log.Printf("[Captcha Proxy] %s %d | Content-Type: %q, Encoding: %q", res.Request.Method, res.StatusCode, contentType, contentEncoding)
shouldInspectBody := strings.Contains(contentType, "text/html") ||
strings.Contains(contentType, "application/xhtml+xml") ||
strings.Contains(res.Request.URL.Path, "captchaNotRobot.check")
if !shouldInspectBody {
return nil
}
@ -517,6 +525,8 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
"Cross-Origin-Embedder-Policy",
"Cross-Origin-Resource-Policy",
"X-Frame-Options",
"Strict-Transport-Security",
"Alt-Svc",
} {
res.Header.Del(headerName)
}
@ -559,7 +569,9 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Printf("[Captcha Proxy] HTTP %s %s", r.Method, r.URL.String())
if r.URL.Path == "/" && targetURL.Path != "" && targetURL.Path != "/" && r.URL.RawQuery == "" {
log.Printf("[Captcha Proxy] Redirecting ROOT to: %s", localCaptchaURLForTarget(targetURL))
http.Redirect(w, r, localCaptchaURLForTarget(targetURL), http.StatusTemporaryRedirect)
return
}

18
client/slider_captcha.go

@ -153,7 +153,7 @@ func (s *captchaNotRobotSession) requestComponentDone() error {
}
func (s *captchaNotRobotSession) requestCheckboxCheck() (*captchaCheckResult, error) {
return s.requestCheck("[]", base64.StdEncoding.EncodeToString([]byte("{}")))
return s.requestCheck(generateSliderCursor(0, 1), base64.StdEncoding.EncodeToString([]byte("{}")))
}
func (s *captchaNotRobotSession) requestSliderContent(sliderSettings string) (*sliderCaptchaContent, error) {
@ -267,6 +267,22 @@ func callCaptchaNotRobotWithSliderPOC(
sliderContent, err := session.requestSliderContent(sliderSettings)
if err != nil {
log.Printf(
"[STREAM %d] [Captcha] Slider getContent failed (status: %v). Trying to solve as a checkbox instead...",
streamID,
err,
)
// Fallback: maybe it's just a checkbox that needs a human-like check
time.Sleep(300 * time.Millisecond)
finalCheck, err2 := session.requestCheckboxCheck()
if err2 == nil && finalCheck.Status == "OK" {
if finalCheck.SuccessToken == "" {
return "", fmt.Errorf("success_token not found in fallback check")
}
log.Printf("[STREAM %d] [Captcha] Fallback checkbox check succeeded!", streamID)
session.requestEndSession()
return finalCheck.SuccessToken, nil
}
return "", fmt.Errorf("check status: %s (slider getContent failed: %w)", initialCheck.Status, err)
}

Loading…
Cancel
Save