Skip to content

Commit

Permalink
Merge pull request #20 from Bezzz23/task/CCL-4354
Browse files Browse the repository at this point in the history
CCL-4354 added TenDI captcha, added Amazon Captcha recognition
  • Loading branch information
azeriker authored May 23, 2024
2 parents 7ae0ef6 + 2e73d02 commit 451c89c
Show file tree
Hide file tree
Showing 17 changed files with 382 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,5 @@ DEBUG=cmc-* node app.js
- [RecaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-rc-en)
- [HcaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-hc-en)
- [DataDome](https://zenno.link/doc-datadome)
- [TenDI](https://zenno.link/doc-tendi)
- [Amazon](https://zenno.link/doc-amazon)
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.7.0",
"version": "1.8.0",
"description": "Official JS client library for https://capmonster.cloud/ captcha recognition service",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
32 changes: 32 additions & 0 deletions src/CapMonsterCloudClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ import { ComplexImageHCaptchaRequest } from './Requests/ComplexImageHCaptchaRequ
import { ComplexImageFunCaptchaRequest } from './Requests/ComplexImageFunCaptchaRequest';
import { DataDomeResponse } from './Responses/DataDomeResponse';
import { DataDomeRequest } from './Requests/DataDomeRequest';
import { TenDIRequest } from './Requests/TenDIRequest';
import { TenDIResponse } from './Responses/TenDIResponse';
import { AmazonProxylessRequest } from './Requests/AmazonProxylessRequest';
import { AmazonResponse } from './Responses/AmazonResponse';
import { AmazonRequest } from './Requests/AmazonRequest';
/**
* Base type for capmonster.cloud Client exceptions
*/
Expand Down Expand Up @@ -260,6 +265,33 @@ export class CapMonsterCloudClient {
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<DataDomeResponse>>;
/**
* Solve TenDI task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: TenDIRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<TenDIResponse>>;
/**
* Solve AmazonProxyless task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: AmazonProxylessRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<AmazonResponse>>;
/**
* Solve Amazon task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: AmazonRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<AmazonResponse>>;
/**
* Solve TurnstileProxyless task
* You will get response within 10 - 180 secs period depending on service workload.
Expand Down
79 changes: 79 additions & 0 deletions src/CapMonsterCloudClientFactory.i.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { HCaptchaProxylessRequest } from './Requests/HCaptchaProxylessRequest';
import { ComplexImageRecaptchaRequest } from './Requests/ComplexImageRecaptchaRequest';
import { ComplexImageHCaptchaRequest } from './Requests/ComplexImageHCaptchaRequest';
import { ComplexImageFunCaptchaRequest } from './Requests/ComplexImageFunCaptchaRequest';
import { TenDIRequest } from './Requests/TenDIRequest';
import { AmazonProxylessRequest } from './Requests/AmazonProxylessRequest';
const { version } = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires

describe('Check integration tests for CapMonsterCloudClientFactory()', () => {
Expand Down Expand Up @@ -523,4 +525,81 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => {

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

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

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution":{"data": {"randstr": "@EcL", "ticket": "tr03lHUhdnuW3neJZu.....7LrIbs*"}, "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 tenDIRequest = new TenDIRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
websiteKey: 'websiteKey',
});

const task = await cmcClient.Solve(tenDIRequest);

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":"TenDI"},"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', { randstr: '@EcL', ticket: 'tr03lHUhdnuW3neJZu.....7LrIbs*' });

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

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

const srv = await createServerMock({
responses: [
{ responseBody: '{"errorId":0,"taskId":1234567}' },
{
responseBody:
'{"errorId":0,"status":"ready","solution": { "cookies": { "aws-waf-token": "10115f5b-ebd8-45c7-851e-cfd4f6a82e3e:EAoAua1QezAhAAAA:dp7sp2rXIRcnJcmpWOC1vIu+yq/A3EbR6b6K7c67P49usNF1f1bt/Af5pNcZ7TKZlW+jIZ7QfNs8zjjqiu8C9XQq50Pmv2DxUlyFtfPZkGwk0d27Ocznk18/IOOa49Rydx+/XkGA7xoGLNaUelzNX34PlyXjoOtL0rzYBxMAQy0D1tn+Q5u97kJBjs5Mytqu9tXPIPCTSn4dfXv5llSkv9pxBEnnhwz6HEdmdJMdfur+YRW1MgCX7i3L2Y0/CNL8kd8CEhTMzwyoXekrzBM="}, "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 amazonRequest = new AmazonProxylessRequest({
websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle',
websiteKey: 'websiteKey',
challengeScript: 'https://41bcdd4fb3cb.610cd090.us-east-1.token.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/challenge.js',
captchaScript: 'https://41bcdd4fb3cb.610cd090.us-east-1.captcha.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/captcha.js',
context: 'qoJYgnKsc...aormh/dYYK+Y=',
iv: 'CgAAXFFFFSAAABVk',
});

const task = await cmcClient.Solve(amazonRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"AmazonTaskProxyless","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=middle","challengeScript":"https://41bcdd4fb3cb.610cd090.us-east-1.token.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/challenge.js","captchaScript":"https://41bcdd4fb3cb.610cd090.us-east-1.captcha.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/captcha.js","websiteKey":"websiteKey","context":"qoJYgnKsc...aormh/dYYK+Y=","iv":"CgAAXFFFFSAAABVk"},"softId":54}',
);
expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"<your capmonster.cloud API key>","taskId":1234567}');
expect(task).toHaveProperty('solution');
expect(task).toHaveProperty('solution.cookies', {
'aws-waf-token':
'10115f5b-ebd8-45c7-851e-cfd4f6a82e3e:EAoAua1QezAhAAAA:dp7sp2rXIRcnJcmpWOC1vIu+yq/A3EbR6b6K7c67P49usNF1f1bt/Af5pNcZ7TKZlW+jIZ7QfNs8zjjqiu8C9XQq50Pmv2DxUlyFtfPZkGwk0d27Ocznk18/IOOa49Rydx+/XkGA7xoGLNaUelzNX34PlyXjoOtL0rzYBxMAQy0D1tn+Q5u97kJBjs5Mytqu9tXPIPCTSn4dfXv5llSkv9pxBEnnhwz6HEdmdJMdfur+YRW1MgCX7i3L2Y0/CNL8kd8CEhTMzwyoXekrzBM=',
});

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 @@ -75,6 +75,13 @@ export const CustomTaskTimeouts = {
timeout: 1000 * 80,
} as GetResultTimeouts;

export const AmazonTaskTimeouts = {
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 @@ -103,6 +110,9 @@ export function detectResultTimeouts(task: Task): GetResultTimeouts {
return ComplexImageTimeouts;
case TaskType.CustomTask:
return CustomTaskTimeouts;
case TaskType.AmazonTaskProxyless:
case TaskType.AmazonTask:
return AmazonTaskTimeouts;
default:
throw new Error(`Could not detect result timeouts for provided task type = ${task.type}`);
}
Expand Down
6 changes: 5 additions & 1 deletion src/GetTaskResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { RecaptchaV2Response } from './Responses/RecaptchaV2Response';
import { RecaptchaV3Response } from './Responses/RecaptchaV3Response';
import { ComplexImageResponse } from './Responses/ComplexImageResponse';
import { DataDomeResponse } from './Responses/DataDomeResponse';
import { TenDIResponse } from './Responses/TenDIResponse';
import { AmazonResponse } from './Responses/AmazonResponse';

export enum TaskResultType {
Failed = 'Failed',
Expand All @@ -33,7 +35,9 @@ export type TaskCompletedSolution =
| RecaptchaV2Response
| RecaptchaV3Response
| ComplexImageResponse
| DataDomeResponse;
| DataDomeResponse
| TenDIResponse
| AmazonResponse;

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

export type AmazonProxylessRequestIn = Pick<AmazonRequestBaseIn, Exclude<keyof AmazonRequestBaseIn, 'type'>>;

/**
* Amazon recognition request (without proxy).
* {@link https://zenno.link/doc-amazon}
*/
export class AmazonProxylessRequest extends AmazonRequestBase {
constructor(argsObj: AmazonProxylessRequestIn) {
super({ type: TaskType.AmazonTaskProxyless, ...argsObj });
}
}
16 changes: 16 additions & 0 deletions src/Requests/AmazonRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Mixin } from 'ts-mixer';
import { TaskType } from '../TaskType';
import { AmazonRequestBase, AmazonRequestBaseIn } from './AmazonRequestBase';
import { ProxyInfo, ProxyInfoIn } from './ProxyInfo';

export type AmazonRequestIn = Pick<AmazonRequestBaseIn, Exclude<keyof AmazonRequestBaseIn, 'type'>> & ProxyInfoIn;

/**
* Amazon recognition request (without proxy).
* {@link https://zenno.link/doc-amazon}
*/
export class AmazonRequest extends Mixin(AmazonRequestBase, ProxyInfo) {
constructor(argsObj: AmazonRequestIn) {
super({ type: TaskType.AmazonTask, ...argsObj });
}
}
62 changes: 62 additions & 0 deletions src/Requests/AmazonRequestBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { CaptchaRequestBase, CaptchaRequestBaseIn } from './CaptchaRequestBase';

export type AmazonRequestBaseIn = {
websiteURL: string;
challengeScript: string;
captchaScript: string;
websiteKey: string;
context: string;
iv: string;
cookieSolution?: boolean;
} & CaptchaRequestBaseIn;

/**
* Base GeeTest recognition request
*/
export abstract class AmazonRequestBase extends CaptchaRequestBase {
/**
* Address of the page on which the captcha is recognized
*/
public websiteURL!: string;

/**
* Link to challenge.js
*/
public challengeScript!: string;

/**
* Link to captcha.js
*/
public captchaScript!: string;

/**
* A string that can be retrieved from an html page with a captcha or with javascript by executing the window.gokuProps.key
*/
public websiteKey!: string;

/**
* A string that can be retrieved from an html page with a captcha or with javascript by executing the window.gokuProps.context
*/
public context!: string;

/**
* A string that can be retrieved from an html page with a captcha or with javascript by executing the window.gokuProps.iv
*/
public iv!: string;

/**
* By default false. If you need to use cookies "aws-waf-token", specify the value true. Otherwise, what you will get in return is "captcha_voucher" and "existing_token".
*/
public cookieSolution?: boolean = false;

constructor({ type, nocache, websiteURL, challengeScript, captchaScript, websiteKey, context, iv, cookieSolution }: AmazonRequestBaseIn) {
super({ type, nocache });
this.websiteURL = websiteURL;
this.challengeScript = challengeScript;
this.captchaScript = captchaScript;
this.websiteKey = websiteKey;
this.context = context;
this.iv = iv;
this.cookieSolution = cookieSolution;
}
}
11 changes: 10 additions & 1 deletion src/Requests/GeeTestRequestBase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { CaptchaRequestBase, CaptchaRequestBaseIn } from './CaptchaRequestBase';

type InitParamsType = Record<string, string>;

export type GeeTestRequestBaseIn = {
websiteURL: string;
gt: string;
Expand All @@ -8,7 +10,7 @@ export type GeeTestRequestBaseIn = {
geetestGetLib?: string;
userAgent?: string;
version?: '3' | '4';
initParameters?: Record<string, string>;
initParameters?: InitParamsType;
} & CaptchaRequestBaseIn;

/**
Expand Down Expand Up @@ -59,6 +61,11 @@ export abstract class GeeTestRequestBase extends CaptchaRequestBase {
*/
public geetestGetLib?: string;

/**
* Additional parameters for version 4.
*/
public initParameters?: InitParamsType;

/**
* Browser's User-Agent which is used in emulation.
* It is required that you use a signature of a modern browser,
Expand All @@ -76,6 +83,7 @@ export abstract class GeeTestRequestBase extends CaptchaRequestBase {
geetestGetLib,
userAgent,
version,
initParameters,
}: GeeTestRequestBaseIn) {
super({ type, nocache });
this.websiteURL = websiteURL;
Expand All @@ -85,5 +93,6 @@ export abstract class GeeTestRequestBase extends CaptchaRequestBase {
this.geetestGetLib = geetestGetLib;
this.userAgent = userAgent;
this.version = version;
this.initParameters = initParameters;
}
}
Loading

0 comments on commit 451c89c

Please sign in to comment.