Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CCL-5528 added Basilisk, Imperva, Binance, ComplexImageRecognition tasks #25

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zennolab_com/capmonstercloud-client",
"version": "1.8.2",
"version": "1.9.0",
"description": "Official JS client library for https://capmonster.cloud/ captcha recognition service",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
54 changes: 54 additions & 0 deletions src/CapMonsterCloudClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ import { TenDIResponse } from './Responses/TenDIResponse';
import { AmazonProxylessRequest } from './Requests/AmazonProxylessRequest';
import { AmazonResponse } from './Responses/AmazonResponse';
import { AmazonRequest } from './Requests/AmazonRequest';
import { BasiliskRequest } from './Requests/BasiliskRequest';
import { BasiliskResponse } from './Responses/BasiliskResponse';
import { ImpervaRequest } from './Requests/ImpervaRequest';
import { ImpervaResponse } from './Responses/ImpervaResponse';
import { BinanceRequest } from './Requests/BinanceRequest';
import { BinanceResponse } from './Responses/BinanceResponse';
import { ComplexImageTaskRecognitionRequest } from './Requests/ComplexImageTaskRecognitionRequest';
import { ComplexImageRecognitionResponse } from './Responses/ComplexImageRecognitionResponse';
import { BinanceProxylessRequest } from './Requests/BinanceProxylessRequest';
/**
* Base type for capmonster.cloud Client exceptions
*/
Expand Down Expand Up @@ -274,6 +283,51 @@ export class CapMonsterCloudClient {
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<TenDIResponse>>;
/**
* Solve Basilisk task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: BasiliskRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<BasiliskResponse>>;
/**
* Solve Imperva task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: ImpervaRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<ImpervaResponse>>;
/**
* Solve Binance task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: BinanceRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<BinanceResponse>>;
/**
* Solve BinanceProxyless task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: BinanceProxylessRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<BinanceResponse>>;
/**
* Solve ComplexImageRecognition task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: ComplexImageTaskRecognitionRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<ComplexImageRecognitionResponse>>;
/**
* Solve AmazonProxyless task
* You will get response within 10 - 180 secs period depending on service workload.
Expand Down
192 changes: 192 additions & 0 deletions src/CapMonsterCloudClientFactory.i.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { ComplexImageHCaptchaRequest } from './Requests/ComplexImageHCaptchaRequ
import { ComplexImageFunCaptchaRequest } from './Requests/ComplexImageFunCaptchaRequest';
import { TenDIRequest } from './Requests/TenDIRequest';
import { AmazonProxylessRequest } from './Requests/AmazonProxylessRequest';
import { BasiliskRequest } from './Requests/BasiliskRequest';
import { ImpervaRequest } from './Requests/ImpervaRequest';
import { BinanceRequest } from './Requests/BinanceRequest';
import { ComplexImageTaskRecognitionRequest } from './Requests/ComplexImageTaskRecognitionRequest';
import { BinanceProxylessRequest } from './Requests/BinanceProxylessRequest';
const { version } = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires

describe('Check integration tests for CapMonsterCloudClientFactory()', () => {
Expand Down Expand Up @@ -561,6 +566,41 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => {
expect(await srv.destroy()).toBeUndefined();
});

it('should solve Basilisk Task', async () => {
expect.assertions(5);

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution":{"data": {"captcha_response": "5620301f30daf284b829fba66fa9b3d0"}, "headers": { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" }}}',
},
],
});

const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: '<your capmonster.cloud API key>', serviceUrl: `http://localhost:${srv.address.port}` }),
);

const basiliskRequest = new BasiliskRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
websiteKey: 'websiteKey',
});

const task = await cmcClient.Solve(basiliskRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"CustomTask","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle","websiteKey":"websiteKey","class":"Basilisk"},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');
expect(task).toHaveProperty('solution.data', { captcha_response: '5620301f30daf284b829fba66fa9b3d0' });

expect(await srv.destroy()).toBeUndefined();
});

it('should solve Amazon Task', async () => {
expect.assertions(5);

Expand Down Expand Up @@ -600,6 +640,158 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => {
'10115f5b-ebd8-45c7-851e-cfd4f6a82e3e:EAoAua1QezAhAAAA:dp7sp2rXIRcnJcmpWOC1vIu+yq/A3EbR6b6K7c67P49usNF1f1bt/Af5pNcZ7TKZlW+jIZ7QfNs8zjjqiu8C9XQq50Pmv2DxUlyFtfPZkGwk0d27Ocznk18/IOOa49Rydx+/XkGA7xoGLNaUelzNX34PlyXjoOtL0rzYBxMAQy0D1tn+Q5u97kJBjs5Mytqu9tXPIPCTSn4dfXv5llSkv9pxBEnnhwz6HEdmdJMdfur+YRW1MgCX7i3L2Y0/CNL8kd8CEhTMzwyoXekrzBM=',
});

expect(await srv.destroy()).toBeUndefined();
});
it('should solve Imperva Task', async () => {
expect.assertions(5);

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution":{"domains": { "site.com" : { "cookies": { "___utmvc": "NMB", "reese84": "reese84"}} } }}',
},
],
});

const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: '<your capmonster.cloud API key>', serviceUrl: `http://localhost:${srv.address.port}` }),
);

const impervaRequest = new ImpervaRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
metadata: {
incapsulaScriptBase64: 'dmFyIF8weGQ2ZmU9Wydce..eDUzXHg2YV',
incapsulaSessionCookie: 'l/LsGnrvyB9lNhXI8borDKa2IGc',
},
});

const task = await cmcClient.Solve(impervaRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"CustomTask","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle","metadata":{"incapsulaScriptBase64":"dmFyIF8weGQ2ZmU9Wydce..eDUzXHg2YV","incapsulaSessionCookie":"l/LsGnrvyB9lNhXI8borDKa2IGc"},"class":"Imperva"},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');

expect(task).toHaveProperty('solution.domains', { 'site.com': { cookies: { ___utmvc: 'NMB', reese84: 'reese84' } } });

expect(await srv.destroy()).toBeUndefined();
});
it('should solve Binance Task', async () => {
expect.assertions(5);

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution":{"token":"captcha#09ba4905a79f44f2a99e44f234439644-ioVA7neog7eRHCDAsC0MixpZvt5kc99maS943qIsquNP9D77","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"}}',
},
],
});

const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: '<your capmonster.cloud API key>', serviceUrl: `http://localhost:${srv.address.port}` }),
);

const binanceRequest = new BinanceRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
websiteKey: 'websiteKey',
validateId: 'validateId',
proxyType: 'http',
proxyAddress: '8.8.8.8',
proxyPort: 8080,
proxyLogin: 'proxyLoginHere',
proxyPassword: 'proxyPasswordHere',
});

const task = await cmcClient.Solve(binanceRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"BinanceTaskProxyless","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle","websiteKey":"websiteKey","validateId":"validateId","proxyType":"http","proxyAddress":"8.8.8.8","proxyPort":8080,"proxyLogin":"proxyLoginHere","proxyPassword":"proxyPasswordHere"},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');
expect(task).toHaveProperty(
'solution.token',
'captcha#09ba4905a79f44f2a99e44f234439644-ioVA7neog7eRHCDAsC0MixpZvt5kc99maS943qIsquNP9D77',
);

expect(await srv.destroy()).toBeUndefined();
});
it('should solve Binance Task Proxyless', async () => {
expect.assertions(5);

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution":{"token":"captcha#09ba4905a79f44f2a99e44f234439644-ioVA7neog7eRHCDAsC0MixpZvt5kc99maS943qIsquNP9D77","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"}}',
},
],
});

const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: '<your capmonster.cloud API key>', serviceUrl: `http://localhost:${srv.address.port}` }),
);

const binanceRequest = new BinanceProxylessRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
websiteKey: 'websiteKey',
validateId: 'validateId',
});

const task = await cmcClient.Solve(binanceRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"BinanceTaskProxyless","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle","websiteKey":"websiteKey","validateId":"validateId"},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');
expect(task).toHaveProperty(
'solution.token',
'captcha#09ba4905a79f44f2a99e44f234439644-ioVA7neog7eRHCDAsC0MixpZvt5kc99maS943qIsquNP9D77',
);

expect(await srv.destroy()).toBeUndefined();
});
it('should solve ComplexImageRecognition Task', async () => {
expect.assertions(5);

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody: '{"errorId":0,"status":"ready","solution":{"answer":[130.90909]}}',
},
],
});

const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: '<your capmonster.cloud API key>', serviceUrl: `http://localhost:${srv.address.port}` }),
);

const binanceRequest = new ComplexImageTaskRecognitionRequest({
imagesBase64: ['/9xwee/'],
metaData: { Task: 'oocl_rotate' },
});

const task = await cmcClient.Solve(binanceRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"ComplexImageTask","class":"recognition","imagesBase64":["/9xwee/"],"metadata":{"Task":"oocl_rotate"}},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');
expect(task).toHaveProperty('solution.answer', [130.90909]);

expect(await srv.destroy()).toBeUndefined();
});
});
10 changes: 10 additions & 0 deletions src/GetResultTimeouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export const AmazonTaskTimeouts = {
timeout: 1000 * 80,
} as GetResultTimeouts;

export const BinanceTaskTimeouts = {
firstRequestDelay: 1000 * 1,
firstRequestNoCacheDelay: 1000 * 10,
requestsInterval: 1000 * 1,
timeout: 1000 * 80,
} as GetResultTimeouts;

export function detectResultTimeouts(task: Task): GetResultTimeouts {
switch (task.type) {
case TaskType.FunCaptchaTaskProxyless:
Expand Down Expand Up @@ -113,6 +120,9 @@ export function detectResultTimeouts(task: Task): GetResultTimeouts {
case TaskType.AmazonTaskProxyless:
case TaskType.AmazonTask:
return AmazonTaskTimeouts;
case TaskType.BinanceTaskProxyless:
case TaskType.BinanceTask:
return BinanceTaskTimeouts;
default:
throw new Error(`Could not detect result timeouts for provided task type = ${task.type}`);
}
Expand Down
10 changes: 9 additions & 1 deletion src/GetTaskResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { ComplexImageResponse } from './Responses/ComplexImageResponse';
import { DataDomeResponse } from './Responses/DataDomeResponse';
import { TenDIResponse } from './Responses/TenDIResponse';
import { AmazonResponse } from './Responses/AmazonResponse';
import { BasiliskResponse } from './Responses/BasiliskResponse';
import { ImpervaResponse } from './Responses/ImpervaResponse';
import { BinanceResponse } from './Responses/BinanceResponse';
import { ComplexImageRecognitionResponse } from './Responses/ComplexImageRecognitionResponse';

export enum TaskResultType {
Failed = 'Failed',
Expand Down Expand Up @@ -37,7 +41,11 @@ export type TaskCompletedSolution =
| ComplexImageResponse
| DataDomeResponse
| TenDIResponse
| AmazonResponse;
| AmazonResponse
| BasiliskResponse
| ImpervaResponse
| BinanceResponse
| ComplexImageRecognitionResponse;

export type TaskCompleted<S extends TaskCompletedSolution> = {
type: TaskResultType.Completed;
Expand Down
13 changes: 13 additions & 0 deletions src/Requests/BasiliskRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TaskType } from '../TaskType';
import { BasiliskRequestBase, BasiliskRequestBaseIn } from './BasiliskRequestBase';

export type BasiliskRequestIn = Pick<BasiliskRequestBaseIn, Exclude<keyof BasiliskRequestBaseIn, 'type' | '_class'>>;
/**
* Basilisk recognition request.
* {@link https://zenno.link/doc-basilisk}
*/
export class BasiliskRequest extends BasiliskRequestBase {
constructor(argsObj: BasiliskRequestIn) {
super({ type: TaskType.CustomTask, _class: 'Basilisk', ...argsObj });
}
}
41 changes: 41 additions & 0 deletions src/Requests/BasiliskRequestBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { CaptchaRequestBase, CaptchaRequestBaseIn } from './CaptchaRequestBase';

export type BasiliskRequestBaseIn = {
websiteURL: string;
websiteKey: string;
userAgent?: string;
_class: string;
} & CaptchaRequestBaseIn;

/**
* Base Basilisk recognition request
*/
export abstract class BasiliskRequestBase extends CaptchaRequestBase {
/**
* Address of a webpage with Basilisk.
*/
public websiteURL!: string;

/**
* Can be found in the html code in the attribute data-sitekey of the captcha container or in the payload of a POST request to the https://basiliskcaptcha.com/challenge/check-site in the field site_key
*/
public websiteKey!: string;

/**
* Browser User-Agent. Pass only the actual UA from Windows OS
*/
public userAgent?: string;

/**
* Class of captcha object
*/
public class: string;

constructor({ type, nocache, websiteURL, userAgent, websiteKey, _class }: BasiliskRequestBaseIn) {
super({ type, nocache });
this.websiteURL = websiteURL;
this.websiteKey = websiteKey;
this.userAgent = userAgent;
this.class = _class;
}
}
Loading