Skip to content
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: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ DEBUG=cmc-* node app.js
- [HcaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-hc-en)
- [ImageToTextRequest](https://zenno.link/doc-ImageToTextTask-en)
- [ImpervaRequest](https://zenno.link/doc-imperva-en)
- [MTCaptcha](https://zenno.link/doc-mt-captcha-en)
- [ProsopoRequest](https://zenno.link/doc-prosopo-en)
- [RecaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-rc-en)
- [RecaptchaV2EnterpriseRequest](https://zenno.link/doc-recaptcha2e-proxy-en)
Expand All @@ -91,3 +92,4 @@ DEBUG=cmc-* node app.js
- [Temu](https://zenno.link/doc-temu-en)
- [TenDIRequest](https://zenno.link/doc-tendi-en)
- [TurnstileRequest](https://zenno.link/doc-turnstile-proxy-en)
- [Yidun](https://zenno.link/doc-yidun-en)
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": "2.2.0",
"version": "2.4.0",
"description": "Official JS client library for https://capmonster.cloud/ captcha recognition service",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
25 changes: 25 additions & 0 deletions src/CapMonsterCloudClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ import { ProsopoRequest } from './Requests/ProsopoRequest';
import { ProsopoResponse } from './Responses/ProsopoResponse';
import { TemuRequest } from './Requests/TemuRequest';
import { TemuResponse } from './Responses/TemuResponse';
import { YidunRequest } from './Requests/YidunRequest';
import { YidunResponse } from './Responses/YidunResponse';
import { MTCaptchaRequest } from './Requests/MTCaptchaRequest';
import { MTCaptchaResponse } from './Responses/MTCaptchaResponse';

type CustomTaskUnion = TemuRequest | BasiliskRequest | ImpervaRequest;

Expand Down Expand Up @@ -327,6 +331,27 @@ export class CapMonsterCloudClient {
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<ProsopoResponse>>;

/**
* Solve Yidun task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: YidunRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<YidunResponse>>;

/**
* Solve MTCaptcha task
* You will get response within 10 - 180 secs period depending on service workload.
*/
public async Solve(
task: MTCaptchaRequest,
resultTimeouts?: GetResultTimeouts,
cancellationController?: AbortController,
): Promise<CaptchaResult<MTCaptchaResponse>>;

/**
* Solve Complex Image FunCaptcha Task
* You will get response within 10 - 180 secs period depending on service workload.
Expand Down
80 changes: 80 additions & 0 deletions src/CapMonsterCloudClientFactory.i.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { AmazonRequest } from './Requests/AmazonRequest';
import { HCaptchaRequest } from './Requests/HCaptchaRequest';
import { ProsopoRequest } from './Requests/ProsopoRequest';
import { TemuRequest } from './Requests/TemuRequest';
import { YidunRequest } from './Requests/YidunRequest';
import { MTCaptchaRequest } from './Requests/MTCaptchaRequest';

const { version } = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires

Expand Down Expand Up @@ -1090,4 +1092,82 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => {

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

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

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

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

const yidunRequest = new YidunRequest({
websiteURL: 'https://id7.cloud.example.com/IframeLogin.html',
websiteKey: 'websiteKey',
});

const task = await cmcClient.Solve(yidunRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"YidunTask","websiteURL":"https://id7.cloud.example.com/IframeLogin.html","websiteKey":"websiteKey"},"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',
'0x00016c68747470733a2f2f70726f6e6f6465332e70726f736f706f2e696fc0354550516f4d5a454463354c704e376774784d4d7a5950547a4136',
);

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

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

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

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

const mtCaptchaRequest = new MTCaptchaRequest({
websiteURL: 'https://www.example.com',
websiteKey: 'websiteKey',
pageAction: 'login',
isInvisible: false,
});

const task = await cmcClient.Solve(mtCaptchaRequest);

expect(srv.caughtRequests[0]).toHaveProperty(
'body',
'{"clientKey":"<your capmonster.cloud API key>","task":{"type":"MTCaptchaTask","websiteURL":"https://www.example.com","websiteKey":"websiteKey","pageAction":"login","isInvisible":false},"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',
'0x00016c68747470733a2f2f70726f6e6f6465332e70726f736f706f2e696fc0354550516f4d5a454463354c704e376774784d4d7a5950547a4136',
);

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

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

export const MTCaptchaTaskTimeouts = {
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.FunCaptchaTask:
Expand Down Expand Up @@ -126,6 +140,10 @@ export function detectResultTimeouts(task: Task): GetResultTimeouts {
return BinanceTaskTimeouts;
case TaskType.ProsopoTask:
return ProsopoTaskTimeouts;
case TaskType.YidunTask:
return YidunTaskTimeouts;
case TaskType.MTCaptchaTask:
return MTCaptchaTaskTimeouts;
default:
throw new Error(`Could not detect result timeouts for provided task type = ${task.type}`);
}
Expand Down
18 changes: 18 additions & 0 deletions src/Requests/MTCaptchaRequest/MTCaptchaRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TaskType } from '../../TaskType';
import { MTCaptchaRequestBase, MTCaptchaRequestBaseIn } from './MTCaptchaRequestBase';
import { ProxyInfo, ProxyInfoIn } from '../ProxyInfo';

export type MTCaptchaRequestIn = Pick<MTCaptchaRequestBaseIn, Exclude<keyof MTCaptchaRequestBaseIn, 'type'>> & { proxy?: ProxyInfoIn };
/**
* MTCaptcha recognition request (with proxy).
* {@link https://zenno.link/doc-mt-captcha-en}
*/
export class MTCaptchaRequest extends MTCaptchaRequestBase {
constructor({ proxy, ...restArgsObj }: MTCaptchaRequestIn) {
super({ type: TaskType.MTCaptchaTask, ...restArgsObj });

if (proxy) {
Object.assign(this, new ProxyInfo(proxy));
}
}
}
48 changes: 48 additions & 0 deletions src/Requests/MTCaptchaRequest/MTCaptchaRequestBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { CaptchaRequestBase, CaptchaRequestBaseIn } from '../CaptchaRequestBase';

export type MTCaptchaRequestBaseIn = {
websiteURL: string;
websiteKey: string;
userAgent?: string;
pageAction?: string;
isInvisible?: boolean;
} & CaptchaRequestBaseIn;

/**
* Base MTCaptcha recognition request
*/
export abstract class MTCaptchaRequestBase extends CaptchaRequestBase {
/**
* Full URL of the page with the captcha.
*/
public websiteURL!: string;

/**
* The MTcaptcha key, passed in the request parameters as sk
*/
public websiteKey!: string;

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

/**
* The action parameter is passed in the request as act and displayed when validating the token.
*/
public pageAction?: string;

/**
* true if the captcha is invisible, i.e., has a hidden confirmation field. If bot suspicion occurs, an additional verification is triggered.
*/
public isInvisible?: boolean;

constructor({ type, nocache, websiteURL, websiteKey, userAgent, pageAction, isInvisible }: MTCaptchaRequestBaseIn) {
super({ type, nocache });
this.websiteURL = websiteURL;
this.websiteKey = websiteKey;
this.userAgent = userAgent;
this.pageAction = pageAction;
this.isInvisible = isInvisible;
}
}
1 change: 1 addition & 0 deletions src/Requests/MTCaptchaRequest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './MTCaptchaRequest';
18 changes: 18 additions & 0 deletions src/Requests/YidunRequest/YidunRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TaskType } from '../../TaskType';
import { YidunRequestBase, YidunRequestBaseIn } from './YuidunRequestBase';
import { ProxyInfo, ProxyInfoIn } from '../ProxyInfo';

export type YidunRequestIn = Pick<YidunRequestBaseIn, Exclude<keyof YidunRequestBaseIn, 'type'>> & { proxy?: ProxyInfoIn };
/**
* Yidun recognition request (with proxy).
* {@link https://zenno.link/doc-yidun-en}
*/
export class YidunRequest extends YidunRequestBase {
constructor({ proxy, ...restArgsObj }: YidunRequestIn) {
super({ type: TaskType.YidunTask, ...restArgsObj });

if (proxy) {
Object.assign(this, new ProxyInfo(proxy));
}
}
}
80 changes: 80 additions & 0 deletions src/Requests/YidunRequest/YuidunRequestBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { CaptchaRequestBase, CaptchaRequestBaseIn } from '../CaptchaRequestBase';

export type YidunRequestBaseIn = {
websiteURL: string;
websiteKey: string;
userAgent?: string;
yidunGetLib?: string;
yidunApiServerSubdomain?: string;
challenge?: string;
hcg?: string;
hct?: number;
} & CaptchaRequestBaseIn;

/**
* Base Yidun recognition request
*/
export abstract class YidunRequestBase extends CaptchaRequestBase {
/**
* Full URL of the page with the captcha.
*/
public websiteURL!: string;

/**
* The siteKey value found on the page.
*/
public websiteKey!: string;

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

/**
* Path to the JavaScript file responsible for loading the captcha on the page.
*/
public yidunGetLib?: string;

/**
* Subdomain of the Yidun API server.
*/
public yidunApiServerSubdomain?: string;

/**
* Unique identifier of the current captcha.
*/
public challenge?: string;

/**
* Captcha hash used in the request.
*/
public hcg?: string;

/**
* Numeric timestamp used in Enterprise version validation.
*/
public hct?: number;

constructor({
type,
nocache,
websiteURL,
websiteKey,
userAgent,
yidunGetLib,
yidunApiServerSubdomain,
challenge,
hcg,
hct,
}: YidunRequestBaseIn) {
super({ type, nocache });
this.websiteURL = websiteURL;
this.websiteKey = websiteKey;
this.userAgent = userAgent;
this.yidunGetLib = yidunGetLib;
this.yidunApiServerSubdomain = yidunApiServerSubdomain;
this.challenge = challenge;
this.hcg = hcg;
this.hct = hct;
}
}
1 change: 1 addition & 0 deletions src/Requests/YidunRequest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './YidunRequest';
6 changes: 6 additions & 0 deletions src/Responses/MTCaptchaResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* MTCaptcha recognition response base
*/
export type MTCaptchaResponse = {
token: string;
};
6 changes: 6 additions & 0 deletions src/Responses/YidunResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Yidun recognition response base
*/
export type YidunResponse = {
token: string;
};
2 changes: 2 additions & 0 deletions src/TaskType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export enum TaskType {
AmazonTask = 'AmazonTask',
BinanceTask = 'BinanceTask',
ProsopoTask = 'ProsopoTask',
YidunTask = 'YidunTask',
MTCaptchaTask = 'MTCaptchaTask',
}
Loading