feat: add proxy support
This commit is contained in:
		| @ -2,6 +2,7 @@ package api | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| @ -78,6 +79,12 @@ var ( | ||||
| 		ErrorCode:        "ERROR_BAD_REQUEST", | ||||
| 		ErrorDescription: "Bad request", | ||||
| 	} | ||||
|  | ||||
| 	errorProxyConnectRefused = &antigateError{ | ||||
| 		ErrorId:          25, | ||||
| 		ErrorCode:        "ERROR_PROXY_CONNECT_REFUSED", | ||||
| 		ErrorDescription: "Bad proxy", | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| func (a *antigateV2Api) getTaskResult(request struct { | ||||
| @ -150,6 +157,35 @@ func (a *antigateV2Api) getTaskResult(request struct { | ||||
| 	return response | ||||
| } | ||||
|  | ||||
| func collectAntiGateV2Proxy(task any) *string { | ||||
| 	var proxy struct { | ||||
| 		ProxyType     string  `json:"proxyType"` | ||||
| 		ProxyAddress  string  `json:"proxyAddress"` | ||||
| 		ProxyPort     uint16  `json:"proxyPort"` | ||||
| 		ProxyLogin    *string `json:"proxyLogin"` | ||||
| 		ProxyPassword *string `json:"proxyPassword"` | ||||
| 	} | ||||
| 	if err := mapstructure.Decode(task, proxy); err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if proxy.ProxyType == "" || proxy.ProxyAddress == "" || proxy.ProxyPort == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	credentials := "" | ||||
| 	if proxy.ProxyLogin != nil { | ||||
| 		credentials += *proxy.ProxyLogin | ||||
| 		if proxy.ProxyPassword != nil { | ||||
| 			credentials += ":" + *proxy.ProxyPassword | ||||
| 		} | ||||
| 		credentials += "@" | ||||
| 	} | ||||
|  | ||||
| 	proxyStr := fmt.Sprintf("%s://%s%s:%d", proxy.ProxyType, credentials, proxy.ProxyAddress, proxy.ProxyPort) | ||||
| 	return &proxyStr | ||||
| } | ||||
|  | ||||
| func (a *antigateV2Api) createTask(request struct { | ||||
| 	Task map[string]any `json:"task"` | ||||
| }) any { | ||||
| @ -157,10 +193,11 @@ func (a *antigateV2Api) createTask(request struct { | ||||
| 	if !ok { | ||||
| 		return errorTaskAbsent | ||||
| 	} | ||||
| 	taskType = strings.ToLower(taskType) | ||||
|  | ||||
| 	var id uint32 | ||||
| 	var satiTask sati.AnyTask | ||||
|  | ||||
| 	switch strings.ToLower(taskType) { | ||||
| 	switch taskType { | ||||
| 	case "turnstiletask", "turnstiletaskproxyless": | ||||
| 		var task struct { | ||||
| 			WebsiteURL string  `json:"websiteURL"` | ||||
| @ -168,21 +205,35 @@ func (a *antigateV2Api) createTask(request struct { | ||||
| 			Action     *string `json:"action"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.TurnstileTask{ | ||||
| 		satiTask = &sati.TurnstileTask{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsiteKey, | ||||
| 			Action:  task.Action, | ||||
| 		}) | ||||
| 		} | ||||
| 		if taskType == "turnstiletask" { | ||||
| 			proxy := collectAntiGateV2Proxy(request.Task) | ||||
| 			if proxy == nil { | ||||
| 				return errorProxyConnectRefused | ||||
| 			} | ||||
| 			satiTask.(*sati.TurnstileTask).Proxy = proxy | ||||
| 		} | ||||
| 	case "recaptchav2task", "recaptchav2taskproxyless": | ||||
| 		var task struct { | ||||
| 			WebsiteURL string `json:"websiteURL"` | ||||
| 			WebsiteKey string `json:"websiteKey"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.ReCaptcha2Task{ | ||||
| 		satiTask = &sati.ReCaptcha2Task{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsiteKey, | ||||
| 		}) | ||||
| 		} | ||||
| 		if taskType == "funcaptchatask" { | ||||
| 			proxy := collectAntiGateV2Proxy(request.Task) | ||||
| 			if proxy == nil { | ||||
| 				return errorProxyConnectRefused | ||||
| 			} | ||||
| 			satiTask.(*sati.ReCaptcha2Task).Proxy = proxy | ||||
| 		} | ||||
| 	case "funcaptchatask", "funcaptchataskproxyless": | ||||
| 		var task struct { | ||||
| 			WebsiteURL       string            `json:"websiteURL"` | ||||
| @ -190,15 +241,24 @@ func (a *antigateV2Api) createTask(request struct { | ||||
| 			Data             map[string]string `json:"data"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.FunCaptchaTask{ | ||||
| 		satiTask = &sati.FunCaptchaTask{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsitePublicKey, | ||||
| 			Data:    task.Data, | ||||
| 		}) | ||||
| 		} | ||||
| 		if taskType == "funcaptchatask" { | ||||
| 			proxy := collectAntiGateV2Proxy(request.Task) | ||||
| 			if proxy == nil { | ||||
| 				return errorProxyConnectRefused | ||||
| 			} | ||||
| 			satiTask.(*sati.FunCaptchaTask).Proxy = proxy | ||||
| 		} | ||||
| 	default: | ||||
| 		return errorTaskNotSupported | ||||
| 	} | ||||
|  | ||||
| 	id := a.ctx.Registry.CreateTask(satiTask) | ||||
|  | ||||
| 	return &struct { | ||||
| 		ErrorId uint32 `json:"errorId"` | ||||
| 		TaskId  uint32 `json:"taskId"` | ||||
|  | ||||
| @ -5,6 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @ -130,6 +131,42 @@ func (a *capSolverApi) getTaskResult(request struct { | ||||
| 	return response | ||||
| } | ||||
|  | ||||
| func collectCapSolverProxy(task any) *string { | ||||
| 	antigateLike := collectAntiGateV2Proxy(task) | ||||
| 	if antigateLike != nil { | ||||
| 		return antigateLike | ||||
| 	} | ||||
|  | ||||
| 	input, _ := task.(map[string]any)["proxy"].(string) | ||||
| 	if input == "" { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	isUrl := strings.Contains(input, "://") | ||||
| 	if isUrl { | ||||
| 		// validate it | ||||
| 		url, err := url.Parse(input) | ||||
| 		if err != nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 		output := url.String() | ||||
| 		return &output | ||||
| 	} | ||||
|  | ||||
| 	fragments := strings.Split(input, ":") | ||||
| 	var output string | ||||
| 	switch len(fragments) { | ||||
| 	case 5: // proto:host:port:user:pwd | ||||
| 		output = fmt.Sprintf("%s://%s:%s@%s:%s", fragments[0], fragments[3], fragments[4], fragments[1], fragments[2]) | ||||
| 	case 4: // host:port:user:pwd, http used by default | ||||
| 		output = fmt.Sprintf("http://%s:%s@%s:%s", fragments[2], fragments[3], fragments[0], fragments[1]) | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return &output | ||||
| } | ||||
|  | ||||
| func (a *capSolverApi) createTask(request struct { | ||||
| 	Task map[string]any `json:"task"` | ||||
| }) any { | ||||
| @ -138,7 +175,7 @@ func (a *capSolverApi) createTask(request struct { | ||||
| 		return csErrorInvalidTaskData | ||||
| 	} | ||||
|  | ||||
| 	var id uint32 | ||||
| 	var satiTask sati.AnyTask | ||||
|  | ||||
| 	switch strings.ToLower(taskType) { | ||||
| 	case "anticloudflaretask": | ||||
| @ -151,22 +188,36 @@ func (a *capSolverApi) createTask(request struct { | ||||
| 			} `json:"metadata"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.TurnstileTask{ | ||||
|  | ||||
| 		proxy := collectCapSolverProxy(request.Task) | ||||
| 		if proxy == nil { | ||||
| 			return csErrorInvalidTaskData | ||||
| 		} | ||||
|  | ||||
| 		satiTask = &sati.TurnstileTask{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsiteKey, | ||||
| 			Action:  task.Metadata.Action, | ||||
| 			CData:   task.Metadata.CData, | ||||
| 		}) | ||||
| 			Proxy:   proxy, | ||||
| 		} | ||||
| 	case "recaptchav2task", "recaptchav2taskproxyless": | ||||
| 		var task struct { | ||||
| 			WebsiteURL string `json:"websiteURL"` | ||||
| 			WebsiteKey string `json:"websiteKey"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.ReCaptcha2Task{ | ||||
| 		satiTask = &sati.ReCaptcha2Task{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsiteKey, | ||||
| 		}) | ||||
| 		} | ||||
| 		if taskType == "recaptchav2task" { | ||||
| 			proxy := collectCapSolverProxy(request.Task) | ||||
| 			if proxy == nil { | ||||
| 				return csErrorInvalidTaskData | ||||
| 			} | ||||
| 			satiTask.(*sati.ReCaptcha2Task).Proxy = proxy | ||||
| 		} | ||||
| 	case "funcaptchatask", "funcaptchataskproxyless": | ||||
| 		var task struct { | ||||
| 			WebsiteURL       string            `json:"websiteURL"` | ||||
| @ -174,15 +225,24 @@ func (a *capSolverApi) createTask(request struct { | ||||
| 			Data             map[string]string `json:"data"` | ||||
| 		} | ||||
| 		mapstructure.Decode(request.Task, &task) | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.FunCaptchaTask{ | ||||
| 		satiTask = &sati.FunCaptchaTask{ | ||||
| 			PageUrl: task.WebsiteURL, | ||||
| 			SiteKey: task.WebsitePublicKey, | ||||
| 			Data:    task.Data, | ||||
| 		}) | ||||
| 		} | ||||
| 		if taskType == "funcaptchatask" { | ||||
| 			proxy := collectCapSolverProxy(request.Task) | ||||
| 			if proxy == nil { | ||||
| 				return csErrorInvalidTaskData | ||||
| 			} | ||||
| 			satiTask.(*sati.FunCaptchaTask).Proxy = proxy | ||||
| 		} | ||||
| 	default: | ||||
| 		return csErrorTaskNotSupported | ||||
| 	} | ||||
|  | ||||
| 	id := a.ctx.Registry.CreateTask(satiTask) | ||||
|  | ||||
| 	return &struct { | ||||
| 		ErrorId uint32 `json:"errorId"` | ||||
| 		TaskId  string `json:"taskId"` | ||||
|  | ||||
| @ -2,6 +2,7 @@ package api | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| @ -90,6 +91,21 @@ func parsePhpAssociativeArray(values map[string][]string, arrayName string) map[ | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func extractRuCaptchaProxy(params url.Values) *string { | ||||
| 	if !params.Has("proxytype") || !params.Has("proxy") { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	proxyUrl := fmt.Sprintf("%s://%s", params.Get("proxytype"), params.Get("proxy")) | ||||
| 	url, err := url.Parse(proxyUrl) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	formatted := url.String() | ||||
| 	return &formatted | ||||
| } | ||||
|  | ||||
| func (a *ruCaptchaApi) endpointIn(params url.Values) ruCaptchaResponse { | ||||
| 	var id uint32 | ||||
| 	switch params.Get("method") { | ||||
| @ -118,6 +134,7 @@ func (a *ruCaptchaApi) endpointIn(params url.Values) ruCaptchaResponse { | ||||
| 		id = a.ctx.Registry.CreateTask(&sati.ReCaptcha2Task{ | ||||
| 			PageUrl: pageUrl, | ||||
| 			SiteKey: siteKey, | ||||
| 			Proxy:   extractRuCaptchaProxy(params), | ||||
| 		}) | ||||
| 	case "turnstile": | ||||
| 		pageUrl := params.Get("pageurl") | ||||
| @ -142,6 +159,7 @@ func (a *ruCaptchaApi) endpointIn(params url.Values) ruCaptchaResponse { | ||||
| 			PageUrl: pageUrl, | ||||
| 			Action:  action, | ||||
| 			CData:   cData, | ||||
| 			Proxy:   extractRuCaptchaProxy(params), | ||||
| 		}) | ||||
| 	case "funcaptcha": | ||||
| 		siteKey := params.Get("publickey") | ||||
| @ -162,6 +180,7 @@ func (a *ruCaptchaApi) endpointIn(params url.Values) ruCaptchaResponse { | ||||
| 			PageUrl:    pageUrl, | ||||
| 			ServiceUrl: serviceUrl, | ||||
| 			Data:       data, | ||||
| 			Proxy:      extractRuCaptchaProxy(params), | ||||
| 		}) | ||||
| 	default: | ||||
| 		return &simpleResponse{0, "ERROR_ZERO_CAPTCHA_FILESIZE"} | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ module git.sati.ac/sati.ac/bridge | ||||
|  | ||||
| go 1.20 | ||||
|  | ||||
| require git.sati.ac/sati.ac/sati-go v0.0.0-20230713145537-57719018ca00 | ||||
| require git.sati.ac/sati.ac/sati-go v0.0.0-20230725102846-8e6b00348696 | ||||
|  | ||||
| require ( | ||||
| 	github.com/gorilla/websocket v1.5.0 // indirect | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @ -6,6 +6,8 @@ git.sati.ac/sati.ac/sati-go v0.0.0-20230630184329-03a405a25122 h1:Uff2QZeRDk+3cm | ||||
| git.sati.ac/sati.ac/sati-go v0.0.0-20230630184329-03a405a25122/go.mod h1:dsLvwV5+2YUjWRAuTYFf/EMvoH/twUu/NWA0t5Yl3pQ= | ||||
| git.sati.ac/sati.ac/sati-go v0.0.0-20230713145537-57719018ca00 h1:emjsk5AubG3EiCbiG0WAG6xAZXoNNwO/yteYj/J0TqA= | ||||
| git.sati.ac/sati.ac/sati-go v0.0.0-20230713145537-57719018ca00/go.mod h1:dsLvwV5+2YUjWRAuTYFf/EMvoH/twUu/NWA0t5Yl3pQ= | ||||
| git.sati.ac/sati.ac/sati-go v0.0.0-20230725102846-8e6b00348696 h1:ld33XeJOBd1skmlVz/TQrcuZPaTIuBt+J1n52oRfPAo= | ||||
| git.sati.ac/sati.ac/sati-go v0.0.0-20230725102846-8e6b00348696/go.mod h1:dsLvwV5+2YUjWRAuTYFf/EMvoH/twUu/NWA0t5Yl3pQ= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= | ||||
|  | ||||
		Reference in New Issue
	
	Block a user