Skip to content

Commit

Permalink
added cloudflare turnstile
Browse files Browse the repository at this point in the history
  • Loading branch information
ghaph committed Jul 6, 2023
1 parent f69a410 commit 780cee1
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 5 deletions.
85 changes: 80 additions & 5 deletions acmethods.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,22 +277,29 @@ func antiCaptchaMethods(solver *Solver, preferredDomain string) *solveMethods {
"isInvisible": o.Invisible,
}

applyProxy(taskData, o.Proxy, "HCaptchaTask")
baseTask := "HCaptchaTask"
if solver.service == CapSolver {
baseTask = "HCaptchaTurboTask"
}

applyProxy(taskData, o.Proxy, baseTask)

if o.UserAgent != "" {
taskData["userAgent"] = o.UserAgent
}

if o.EnterprisePayload != nil {
ep := o.EnterprisePayload

// some apis are slightly different
if o.EnterprisePayload.RQData != "" {
if ep.RQData != "" {
taskData["data"] = o.EnterprisePayload.RQData
}

ep := o.EnterprisePayload
payload := map[string]interface{}{}

payload := map[string]interface{}{
"sentry": ep.Sentry,
if ep.Sentry {
payload["sentry"] = ep.Sentry
}

if ep.RQData != "" {
Expand Down Expand Up @@ -422,6 +429,74 @@ func antiCaptchaMethods(solver *Solver, preferredDomain string) *solveMethods {
UserAgent: userAgent,
}, nil
}

methods.Cloudflare = func(o CloudflareOptions) (*Solution, error) {
if o.Proxy == nil {
return nil, errors.New("proxy is required")
}

if o.Metadata == nil {
o.Metadata = map[string]string{}
}

// only set metadata type if one wasn't provided
if _, ok := o.Metadata["type"]; !ok {
switch o.Type {
case CloudflareTypeChallenge:
o.Metadata["type"] = "challenge"
case CloudflareTypeTurnstile:
o.Metadata["type"] = "turnstile"
default:
o.Metadata["type"] = ""
}
}

if _, ok := o.Metadata["action"]; !ok && o.Action != "" {
o.Metadata["action"] = o.Action
}

if _, ok := o.Metadata["cdata"]; !ok && o.CData != "" {
o.Metadata["cdata"] = o.CData
}

taskData := map[string]interface{}{
"websiteURL": o.PageURL,
"metadata": o.Metadata,
}

if o.SiteKey != "" {
taskData["websiteKey"] = o.SiteKey
}

applyProxy(taskData, o.Proxy, "AntiCloudflareTask")

return createResponse(taskData)
}
} else {
methods.Cloudflare = func(o CloudflareOptions) (*Solution, error) {
if o.Type == CloudflareTypeChallenge {
return nil, errors.New("cloudflare challenge type is not supported by this solver")
}

taskData := map[string]interface{}{
"websiteURL": o.PageURL,
"websiteKey": o.SiteKey,
}

if o.Action != "" {
taskData["action"] = o.Action
}

if o.Metadata != nil {
for k, v := range o.Metadata {
taskData[k] = v
}
}

applyProxy(taskData, o.Proxy, "TurnstileTask")

return createResponse(taskData)
}
}

return methods
Expand Down
37 changes: 37 additions & 0 deletions captchas.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type solveMethods struct {
HCaptcha func(HCaptchaOptions) (*Solution, error)
FunCaptcha func(FunCaptchaOptions) (*Solution, error)
Kasada func(KasadaOptions) (*KasadaSolution, error)
Cloudflare func(CloudflareOptions) (*Solution, error)
}

// GetBalance returns the balance of the account
Expand Down Expand Up @@ -50,6 +51,13 @@ func (s *Solver) FunCaptcha(o FunCaptchaOptions) (*Solution, error) {
return s.methods.FunCaptcha(o)
}

func (s *Solver) Cloudflare(o CloudflareOptions) (*Solution, error) {
if s.methods.Cloudflare == nil {
return nil, errors.New("service does not support cloudflare")
}
return s.methods.Cloudflare(o)
}

// Kasada is only supported with capsolver.com
func (s *Solver) Kasada(o KasadaOptions) (*KasadaSolution, error) {
if s.methods.Kasada == nil {
Expand Down Expand Up @@ -149,6 +157,28 @@ type RecaptchaV2Options struct {
APIDomain string
}

// CloudflareOptions cloudflare challenges only work with capsolver.com, turnstile works with other solvers
type CloudflareOptions struct {
PageURL string
Proxy *Proxy

// SiteKey is only used for CloudflareTypeTurnstile
SiteKey string

// Type must only be CloudflareTypeTurnstile if the solver is not capsolver.com
Type CloudflareType

// Metadata will only be used on capsolver.com, for any other solver it will just append the fields
Metadata map[string]string

// Action and CData are only used for turnstile. CData is only used for 2captcha and capsolver.com
Action string
CData string

// HTML is only needed for cloudflare challenges
HTML string
}

type Solution struct {
Text string

Expand Down Expand Up @@ -183,3 +213,10 @@ type KasadaSolution struct {
// UserAgent is the user agent used to solve the captcha
UserAgent string
}

type CloudflareType int

const (
CloudflareTypeTurnstile CloudflareType = iota
CloudflareTypeChallenge
)
26 changes: 26 additions & 0 deletions examples/cloudflare_turnstile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
"github.com/median/captchago"
)

func main() {
solver, err := captchago.New(captchago.AntiCaptcha, "YOUR_API_KEY")
if err != nil {
panic(err)
}

sol, err := solver.Cloudflare(captchago.CloudflareOptions{
PageURL: "https://demo.turnstile.workers.dev/",
SiteKey: "1x00000000000000000000AA",
Type: captchago.CloudflareTypeTurnstile,
})

if err != nil {
panic(err)
}

fmt.Println(sol.Text)
fmt.Println(fmt.Sprintf("Solved in %v ms", sol.Speed))
}
23 changes: 23 additions & 0 deletions tcmethods.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,29 @@ func twoCaptchaMethods(solver *Solver, preferredDomain string) *solveMethods {
payload["enterprise"] = 1
}

return createResponse(payload)
},
Cloudflare: func(o CloudflareOptions) (*Solution, error) {
payload := map[string]interface{}{
"method": "turnstile",
"sitekey": o.SiteKey,
"pageurl": o.PageURL,
}

if o.Action != "" {
payload["action"] = o.Action
}

if o.CData != "" {
payload["data"] = o.CData
}

if o.Metadata != nil {
for k, v := range o.Metadata {
payload[k] = v
}
}

return createResponse(payload)
},
}
Expand Down

0 comments on commit 780cee1

Please sign in to comment.