Skip to content

Commit e8a9696

Browse files
authored
Merge pull request #147 from Moroka8/fix/vk-captcha-checkbox
fix: handle checkbox captcha and improve manual proxy debug
2 parents 597311f + ae15a40 commit e8a9696

File tree

3 files changed

+34
-6
lines changed

3 files changed

+34
-6
lines changed

client/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func applyBrowserProfileFhttp(req *fhttp.Request, profile Profile) {
228228
}
229229

230230
func generateBrowserFp(profile Profile) string {
231-
data := profile.UserAgent + profile.SecChUa + "1920x1080x24"
231+
data := profile.UserAgent + profile.SecChUa + "1920x1080x24" + strconv.FormatInt(time.Now().UnixNano(), 10)
232232
h := md5.Sum([]byte(data))
233233
return hex.EncodeToString(h[:])
234234
}

client/manual_captcha.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func rewriteProxyRequest(req *http.Request, targetURL *neturl.URL) {
125125
req.Host = targetURL.Host
126126

127127
req.Header.Del("Accept-Encoding")
128+
req.Header.Del("TE") // Disable transfer encoding compression
128129
for _, headerName := range []string{"Origin", "Referer"} {
129130
if rewritten := rewriteProxyHeaderURL(req.Header.Get(headerName), targetURL); rewritten != "" {
130131
req.Header.Set(headerName, rewritten)
@@ -341,7 +342,7 @@ func newCaptchaProxyTransport(dialer *dnsdialer.Dialer) *http.Transport {
341342
IdleConnTimeout: 90 * time.Second,
342343
TLSHandshakeTimeout: 10 * time.Second,
343344
ExpectContinueTimeout: 1 * time.Second,
344-
ForceAttemptHTTP2: true,
345+
ForceAttemptHTTP2: false,
345346
}
346347
if dialer != nil {
347348
transport.DialContext = dialer.DialContext
@@ -458,16 +459,17 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
458459
rewriteProxyRequest(req.Out, targetURL)
459460
},
460461
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
461-
log.Printf("captcha proxy error for %s: %v", r.URL.String(), err)
462+
log.Printf("[Captcha Proxy] ERROR for %s %s: %v", r.Method, r.URL.String(), err)
462463
w.Header().Set("Content-Type", "text/html; charset=utf-8")
463464
w.WriteHeader(http.StatusBadGateway)
464-
_, _ = 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)
465+
_, _ = 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)
465466
},
466467
ModifyResponse: func(res *http.Response) error {
467468
rewriteProxyCookies(res.Header)
468469

469470
if res.StatusCode >= 300 && res.StatusCode < 400 {
470471
if loc := res.Header.Get("Location"); loc != "" {
472+
log.Printf("[Captcha Proxy] Redirecting to: %s", loc)
471473
if rewritten, ok := rewriteProxyRedirectLocation(loc, targetURL); ok {
472474
res.Header.Set("Location", rewritten)
473475
} else {
@@ -477,7 +479,13 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
477479
}
478480

479481
contentType := res.Header.Get("Content-Type")
480-
shouldInspectBody := strings.Contains(contentType, "text/html") || strings.Contains(res.Request.URL.Path, "captchaNotRobot.check")
482+
contentEncoding := res.Header.Get("Content-Encoding")
483+
log.Printf("[Captcha Proxy] %s %d | Content-Type: %q, Encoding: %q", res.Request.Method, res.StatusCode, contentType, contentEncoding)
484+
485+
shouldInspectBody := strings.Contains(contentType, "text/html") ||
486+
strings.Contains(contentType, "application/xhtml+xml") ||
487+
strings.Contains(res.Request.URL.Path, "captchaNotRobot.check")
488+
481489
if !shouldInspectBody {
482490
return nil
483491
}
@@ -517,6 +525,8 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
517525
"Cross-Origin-Embedder-Policy",
518526
"Cross-Origin-Resource-Policy",
519527
"X-Frame-Options",
528+
"Strict-Transport-Security",
529+
"Alt-Svc",
520530
} {
521531
res.Header.Del(headerName)
522532
}
@@ -559,7 +569,9 @@ func solveCaptchaViaProxy(redirectURI string, dialer *dnsdialer.Dialer) (string,
559569
})
560570

561571
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
572+
log.Printf("[Captcha Proxy] HTTP %s %s", r.Method, r.URL.String())
562573
if r.URL.Path == "/" && targetURL.Path != "" && targetURL.Path != "/" && r.URL.RawQuery == "" {
574+
log.Printf("[Captcha Proxy] Redirecting ROOT to: %s", localCaptchaURLForTarget(targetURL))
563575
http.Redirect(w, r, localCaptchaURLForTarget(targetURL), http.StatusTemporaryRedirect)
564576
return
565577
}

client/slider_captcha.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (s *captchaNotRobotSession) requestComponentDone() error {
153153
}
154154

155155
func (s *captchaNotRobotSession) requestCheckboxCheck() (*captchaCheckResult, error) {
156-
return s.requestCheck("[]", base64.StdEncoding.EncodeToString([]byte("{}")))
156+
return s.requestCheck(generateSliderCursor(0, 1), base64.StdEncoding.EncodeToString([]byte("{}")))
157157
}
158158

159159
func (s *captchaNotRobotSession) requestSliderContent(sliderSettings string) (*sliderCaptchaContent, error) {
@@ -267,6 +267,22 @@ func callCaptchaNotRobotWithSliderPOC(
267267

268268
sliderContent, err := session.requestSliderContent(sliderSettings)
269269
if err != nil {
270+
log.Printf(
271+
"[STREAM %d] [Captcha] Slider getContent failed (status: %v). Trying to solve as a checkbox instead...",
272+
streamID,
273+
err,
274+
)
275+
// Fallback: maybe it's just a checkbox that needs a human-like check
276+
time.Sleep(300 * time.Millisecond)
277+
finalCheck, err2 := session.requestCheckboxCheck()
278+
if err2 == nil && finalCheck.Status == "OK" {
279+
if finalCheck.SuccessToken == "" {
280+
return "", fmt.Errorf("success_token not found in fallback check")
281+
}
282+
log.Printf("[STREAM %d] [Captcha] Fallback checkbox check succeeded!", streamID)
283+
session.requestEndSession()
284+
return finalCheck.SuccessToken, nil
285+
}
270286
return "", fmt.Errorf("check status: %s (slider getContent failed: %w)", initialCheck.Status, err)
271287
}
272288

0 commit comments

Comments
 (0)