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