first commit
This commit is contained in:
commit
3d27f14905
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2024, samjblack
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
56
README.md
Normal file
56
README.md
Normal file
@ -0,0 +1,56 @@
|
||||
# EzCaptcha Client Go
|
||||
|
||||
## Supported Captchas
|
||||
- AkamaiWeb
|
||||
- AkamaiBMP
|
||||
- HCaptcha + Enterprise
|
||||
- ReCaptchaV2 + Enterprise
|
||||
- ReCaptchaV3 + Enterprise
|
||||
|
||||
## Installing
|
||||
```sh
|
||||
go get -u github.com/samjblack/ezcaptcha-client-go
|
||||
```
|
||||
|
||||
## Usage
|
||||
```go
|
||||
client, err := ezcaptcha.NewClient("your-api-key", "", 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
task, err := client.NewReCaptchaV2Task(&ezcaptcha.ReCaptchaV2{
|
||||
// For availabe types please refer to ezcaptcha's docs (https://ezcaptcha.atlassian.net/wiki/spaces/IS/pages/7045121/EzCaptcha+API+Docs+English)
|
||||
Type: "ReCaptchaV2TaskProxyless",
|
||||
WebsiteURL: "https://www.google.com/recaptcha/api2/demo",
|
||||
WebsiteKey: "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
|
||||
IsInvisible: false,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result, err := client.GetResult(task)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(result.Solution.GRecaptchaResponse)
|
||||
```
|
||||
|
||||
## AkamaiBMP Example
|
||||
|
||||
```go
|
||||
client, err := ezcaptcha.NewClient("your-api-key", "", 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result, err := client.SolveAkamaiBMP(&ezcaptcha.AkamaiBMP{
|
||||
Type: "AkamaiBMPTaskProxyless",
|
||||
BundleID: "example.bundle.id",
|
||||
Device: "ios",
|
||||
Version: "3.3.5",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(result.Solution.Sensor)
|
||||
```
|
||||
|
71
ezcaptcha.go
Normal file
71
ezcaptcha.go
Normal file
@ -0,0 +1,71 @@
|
||||
package ezcaptcha
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ApiURL string = "https://api.ez-captcha.com"
|
||||
SyncApiURL string = "https://sync.ez-captcha.com"
|
||||
CreateTaskEndPoint string = "/createTask"
|
||||
CreateSyncTaskEndpoint string = "/createSyncTask"
|
||||
GetTaskResultEndPoint string = "/getTaskResult"
|
||||
GetBalanceEndPoint string = "/getBalance"
|
||||
)
|
||||
|
||||
func NewClient(clientKey, appID string, attempts int) (*Client, error) {
|
||||
if attempts == 0 {
|
||||
attempts = 45
|
||||
} else if attempts < 0 {
|
||||
return nil, fmt.Errorf("attempts cannot have a negative value")
|
||||
}
|
||||
return &Client{
|
||||
ClientKey: clientKey,
|
||||
AppID: appID,
|
||||
Attempts: attempts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetResult(task *CreateTaskResponse) (*SolutionResponse, error) {
|
||||
response := &SolutionResponse{}
|
||||
var err error
|
||||
for i := 0; i < c.Attempts; i++ {
|
||||
time.Sleep(3 * time.Second)
|
||||
response, err = c.getResult(task)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.ErrorID != 0 {
|
||||
return nil, errors.New(fmt.Sprintf("%s", response.ErrorDescription))
|
||||
}
|
||||
if response.Status == "ready" {
|
||||
break
|
||||
}
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetBalance() (int, error) {
|
||||
requestData := GetBalanceRequest{
|
||||
ClientKey: c.ClientKey,
|
||||
}
|
||||
b, _ := json.Marshal(requestData)
|
||||
resp, err := http.Post(fmt.Sprintf("%s%s", ApiURL, GetBalanceEndPoint), "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
response := &GetBalanceResponse{}
|
||||
b, _ = io.ReadAll(resp.Body)
|
||||
json.Unmarshal(b, response)
|
||||
if response.ErrorID != 0 {
|
||||
return 0, errors.New(fmt.Sprintf("%s", response.ErrorDescription))
|
||||
}
|
||||
return response.Balance, nil
|
||||
}
|
3
go.mod
Normal file
3
go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/samjblack/ezcaptcha-client-go
|
||||
|
||||
go 1.22.5
|
73
requests.go
Normal file
73
requests.go
Normal file
@ -0,0 +1,73 @@
|
||||
package ezcaptcha
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (c *Client) getResult(task *CreateTaskResponse) (*SolutionResponse, error) {
|
||||
requestData := SolutionRequest{
|
||||
ClientKey: c.ClientKey,
|
||||
TaskID: task.TaskID,
|
||||
}
|
||||
b, _ := json.Marshal(requestData)
|
||||
resp, err := http.Post(fmt.Sprintf("%s%s", ApiURL, GetTaskResultEndPoint), "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := &SolutionResponse{}
|
||||
b, _ = io.ReadAll(resp.Body)
|
||||
json.Unmarshal(b, response)
|
||||
defer resp.Body.Close()
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) createTask(task interface{}) (*CreateTaskResponse, error) {
|
||||
requestData := &TaskRequest{
|
||||
Client: *c,
|
||||
Task: task,
|
||||
}
|
||||
b, _ := json.Marshal(requestData)
|
||||
resp, err := http.Post(fmt.Sprintf("%s%s", ApiURL, CreateTaskEndPoint), "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, _ = io.ReadAll(resp.Body)
|
||||
response := &CreateTaskResponse{}
|
||||
err = json.Unmarshal(b, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.ErrorID != 0 {
|
||||
return nil, fmt.Errorf(response.ErrorDescription)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) solveAkamai(task interface{}) (*AkamaiResponse, error) {
|
||||
requestData := &TaskRequest{
|
||||
Client: *c,
|
||||
Task: task,
|
||||
}
|
||||
b, _ := json.Marshal(requestData)
|
||||
resp, err := http.Post(fmt.Sprintf("%s%s", SyncApiURL, CreateSyncTaskEndpoint), "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, _ = io.ReadAll(resp.Body)
|
||||
response := &AkamaiResponse{}
|
||||
err = json.Unmarshal(b, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.ErrorID != 0 {
|
||||
return nil, errors.New(fmt.Sprintf("%s", response.ErrorDescription))
|
||||
}
|
||||
return response, nil
|
||||
}
|
21
tasks.go
Normal file
21
tasks.go
Normal file
@ -0,0 +1,21 @@
|
||||
package ezcaptcha
|
||||
|
||||
func (c *Client) NewReCaptchaV2Task(task *ReCaptchaV2) (*CreateTaskResponse, error) {
|
||||
return c.createTask(task)
|
||||
}
|
||||
|
||||
func (c *Client) NewReCaptchaV3Task(task *ReCaptchaV3) (*CreateTaskResponse, error) {
|
||||
return c.createTask(task)
|
||||
}
|
||||
|
||||
func (c *Client) NewHCaptchaTask(task *HCaptcha) (*CreateTaskResponse, error) {
|
||||
return c.createTask(task)
|
||||
}
|
||||
|
||||
func (c *Client) SolveAkamai(task *Akamai) (*AkamaiResponse, error) {
|
||||
return c.solveAkamai(task)
|
||||
}
|
||||
|
||||
func (c *Client) SolveAkamaiBMP(task *AkamaiBMP) (*AkamaiResponse, error) {
|
||||
return c.solveAkamai(task)
|
||||
}
|
99
types.go
Normal file
99
types.go
Normal file
@ -0,0 +1,99 @@
|
||||
package ezcaptcha
|
||||
|
||||
type Client struct {
|
||||
ClientKey string `json:"clientKey"`
|
||||
AppID string `json:"appId,omitempty"`
|
||||
Attempts int
|
||||
}
|
||||
|
||||
type GetBalanceRequest struct {
|
||||
ClientKey string `json:"clientKey"`
|
||||
}
|
||||
|
||||
// Structs which are using for creating tasks
|
||||
|
||||
type TaskRequest struct {
|
||||
Client
|
||||
Task any `json:"task"`
|
||||
}
|
||||
|
||||
type SolutionRequest struct {
|
||||
ClientKey string `json:"clientKey"`
|
||||
TaskID string `json:"taskId"`
|
||||
}
|
||||
|
||||
type ReCaptchaV2 struct {
|
||||
Type string `json:"type"`
|
||||
WebsiteURL string `json:"websiteURL"`
|
||||
WebsiteKey string `json:"websiteKey"`
|
||||
IsInvisible bool `json:"isInvisible,omitempty"`
|
||||
Sa string `json:"sa,omitempty"`
|
||||
S string `json:"s,omitempty"`
|
||||
}
|
||||
|
||||
type ReCaptchaV3 struct {
|
||||
Type string `json:"type"`
|
||||
WebsiteURL string `json:"websiteURL"`
|
||||
WebsiteKey string `json:"websiteKey"`
|
||||
IsInvisible bool `json:"isInvisible,omitempty"`
|
||||
PageAction string `json:"pageAction,omitempty"`
|
||||
}
|
||||
|
||||
type HCaptcha struct {
|
||||
Type string `json:"type"`
|
||||
WebsiteURL string `json:"websiteURL"`
|
||||
WebsiteKey string `json:"websiteKey"`
|
||||
EnterpricePayload string `json:"enterprisePayload,omitempty"`
|
||||
IsInvisible bool `json:"isInvisible,omitempty"`
|
||||
}
|
||||
|
||||
type Akamai struct {
|
||||
Type string `json:"type"`
|
||||
PageURL string `json:"pageUrl"`
|
||||
Bmsz string `json:"bmsz"`
|
||||
UA string `json:"ua"`
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
|
||||
type AkamaiBMP struct {
|
||||
Type string `json:"type"`
|
||||
BundleID string `json:"bundleID"`
|
||||
Device string `json:"device"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// Structs to parse the response from their api
|
||||
|
||||
type CreateTaskResponse struct {
|
||||
ErrorID int `json:"errorId"`
|
||||
ErrorCode string `json:"errorCode,omitempty"`
|
||||
ErrorDescription string `json:"errorDescription,omitempty"`
|
||||
TaskID string `json:"taskId,omitempty"`
|
||||
}
|
||||
|
||||
type SolutionResponse struct {
|
||||
ErrorID int `json:"errorId"`
|
||||
ErrorCode any `json:"errorCode,omitempty"`
|
||||
ErrorDescription any `json:"errorDescription,omitempty"`
|
||||
Solution struct {
|
||||
GRecaptchaResponse string `json:"gRecaptchaResponse,omitempty"`
|
||||
} `json:"solution"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type AkamaiResponse struct {
|
||||
ErrorID int `json:"errorId"`
|
||||
ErrorCode any `json:"errorCode,omitempty"`
|
||||
ErrorDescription any `json:"errorDescription,omitempty"`
|
||||
Solution struct {
|
||||
Payload string `json:"payload,omitempty"`
|
||||
Sensor string `json:"sensor,omitempty"`
|
||||
} `json:"solution"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
type GetBalanceResponse struct {
|
||||
Balance int `json:"balance,omitempty"`
|
||||
ErrorID int `json:"errorId"`
|
||||
ErrorCode any `json:"errorCode,omitempty"`
|
||||
ErrorDescription any `json:"errorDescription,omitempty"`
|
||||
}
|
Loading…
Reference in New Issue
Block a user