From 8cfeb11be35e49dd1cfde7e3c24dd4b9d0346702 Mon Sep 17 00:00:00 2001 From: Kirill Bushmin Date: Wed, 21 Jan 2026 17:56:40 +0300 Subject: [PATCH 1/4] CCL-7162 added new Captchas and fixed olds --- README.md | 4 +- src/CapMonsterCloudClient.ts | 22 ++++ src/CapMonsterCloudClientFactory.i.spec.ts | 37 ------ src/GetTaskResult.ts | 4 +- src/Requests/AltchaRequest/AltchaRequest.ts | 20 ++++ .../AltchaRequest/AltchaRequestBase.ts | 55 +++++++++ src/Requests/AltchaRequest/index.ts | 1 + .../DataDomeRequest/DataDomeRequestBase.ts | 8 +- src/Requests/ImpervaRequest/ImpervaRequest.ts | 7 +- .../RecaptchaV2EnterpriseRequestBase.ts | 6 + .../RecaptchaV3EnterpriseRequest.ts | 18 +++ .../RecaptchaV3EnterpriseRequestBase.ts | 48 ++++++++ .../RecaptchaV3EnterpriseRequest/index.ts | 1 + src/Requests/RequestsSerialization.u.spec.ts | 106 +++++++++++++++++- .../TurnstileRequest/TurnstileRequest.ts | 2 +- src/Responses/AltchaResponse.ts | 1 + src/Responses/FunCaptchaResponse.ts | 11 +- src/Responses/MTCaptchaResponse.ts | 1 + src/Responses/ProsopoResponse.ts | 1 + .../RecaptchaV3EnterpriseResponse.ts | 6 + src/Responses/TurnstileResponse.ts | 11 +- src/Responses/YidunResponse.ts | 1 + src/index.ts | 8 ++ 23 files changed, 315 insertions(+), 64 deletions(-) create mode 100644 src/Requests/AltchaRequest/AltchaRequest.ts create mode 100644 src/Requests/AltchaRequest/AltchaRequestBase.ts create mode 100644 src/Requests/AltchaRequest/index.ts create mode 100644 src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts create mode 100644 src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts create mode 100644 src/Requests/RecaptchaV3EnterpriseRequest/index.ts create mode 100644 src/Responses/AltchaResponse.ts create mode 100644 src/Responses/RecaptchaV3EnterpriseResponse.ts diff --git a/README.md b/README.md index 8c0155e..bf80625 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ async function run() { websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', }); - console.log(await cmcClient.Solve(recaptchaV2ProxylessRequest)); + console.log(await cmcClient.Solve(recaptchaV2Request)); } run() @@ -87,9 +87,11 @@ DEBUG=cmc-* node app.js - [ProsopoRequest](https://zenno.link/doc-prosopo-en) - [RecaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-rc-en) - [RecaptchaV2EnterpriseRequest](https://zenno.link/doc-recaptcha2e-proxy-en) +- [RecaptchaV3EnterpriseRequest](https://zenno.link/doc-recaptcha3e-proxy-en) - [RecaptchaV2Request](https://zenno.link/doc-recaptcha2-proxy-en) - [RecaptchaV3ProxylessRequest](https://zenno.link/doc-recaptcha3-en) - [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) +- [Altcha](https://zenno.link/doc-altcha-en) diff --git a/src/CapMonsterCloudClient.ts b/src/CapMonsterCloudClient.ts index 83ca14e..5a999d3 100644 --- a/src/CapMonsterCloudClient.ts +++ b/src/CapMonsterCloudClient.ts @@ -53,6 +53,10 @@ import { YidunRequest } from './Requests/YidunRequest'; import { YidunResponse } from './Responses/YidunResponse'; import { MTCaptchaRequest } from './Requests/MTCaptchaRequest'; import { MTCaptchaResponse } from './Responses/MTCaptchaResponse'; +import { AltchaRequest } from './Requests/AltchaRequest'; +import { AltchaResponse } from './Responses/AltchaResponse'; +import { RecaptchaV3EnterpriseRequest } from './Requests/RecaptchaV3EnterpriseRequest'; +import { RecaptchaV3EnterpriseResponse } from './Responses/RecaptchaV3EnterpriseResponse'; type CustomTaskUnion = TemuRequest | BasiliskRequest | ImpervaRequest; @@ -214,6 +218,15 @@ export class CapMonsterCloudClient { resultTimeouts?: GetResultTimeouts, cancellationController?: AbortController, ): Promise>; + /** + * Solve RecaptchaV3EnterpriseTask task + * You will get response within 10 - 180 secs period depending on service workload. + */ + public async Solve( + task: RecaptchaV3EnterpriseRequest, + resultTimeouts?: GetResultTimeouts, + cancellationController?: AbortController, + ): Promise>; /** * Solve NoCaptchaTask task * You will get response within 10 - 180 secs period depending on service workload. @@ -241,6 +254,15 @@ export class CapMonsterCloudClient { resultTimeouts?: GetResultTimeouts, cancellationController?: AbortController, ): Promise>; + /** + * Solve AltchaRequest task + * You will get response within 10 - 180 secs period depending on service workload. + */ + public async Solve( + task: AltchaRequest, + resultTimeouts?: GetResultTimeouts, + cancellationController?: AbortController, + ): Promise>; /** * Solve TenDI task * You will get response within 10 - 180 secs period depending on service workload. diff --git a/src/CapMonsterCloudClientFactory.i.spec.ts b/src/CapMonsterCloudClientFactory.i.spec.ts index adbfde3..0c2ac67 100644 --- a/src/CapMonsterCloudClientFactory.i.spec.ts +++ b/src/CapMonsterCloudClientFactory.i.spec.ts @@ -731,44 +731,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { 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: '', 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":"","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":"","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 Imperva Task with Proxy', async () => { expect.assertions(5); diff --git a/src/GetTaskResult.ts b/src/GetTaskResult.ts index ff9777f..f8adc6c 100644 --- a/src/GetTaskResult.ts +++ b/src/GetTaskResult.ts @@ -14,6 +14,7 @@ import { BasiliskResponse } from './Responses/BasiliskResponse'; import { ImpervaResponse } from './Responses/ImpervaResponse'; import { BinanceResponse } from './Responses/BinanceResponse'; import { ComplexImageRecognitionResponse } from './Responses/ComplexImageRecognitionResponse'; +import { AltchaResponse } from './Responses/AltchaResponse'; export enum TaskResultType { Failed = 'Failed', @@ -45,7 +46,8 @@ export type TaskCompletedSolution = | BasiliskResponse | ImpervaResponse | BinanceResponse - | ComplexImageRecognitionResponse; + | ComplexImageRecognitionResponse + | AltchaResponse; export type TaskCompleted = { type: TaskResultType.Completed; diff --git a/src/Requests/AltchaRequest/AltchaRequest.ts b/src/Requests/AltchaRequest/AltchaRequest.ts new file mode 100644 index 0000000..45d0424 --- /dev/null +++ b/src/Requests/AltchaRequest/AltchaRequest.ts @@ -0,0 +1,20 @@ +import { TaskType } from '../../TaskType'; +import { AltchaRequestBase, AltchaRequestBaseIn } from './AltchaRequestBase'; +import { ProxyInfo, ProxyInfoIn } from '../ProxyInfo'; + +export type AltchaRequestIn = Pick> & { + proxy?: ProxyInfoIn; +}; +/** + * DataDome recognition request. + * {@link https://zenno.link/doc-altcha} + */ +export class AltchaRequest extends AltchaRequestBase { + constructor({ proxy, ...argsObj }: AltchaRequestIn) { + super({ type: TaskType.CustomTask, _class: 'altcha', ...argsObj }); + + if (proxy) { + Object.assign(this, new ProxyInfo(proxy)); + } + } +} diff --git a/src/Requests/AltchaRequest/AltchaRequestBase.ts b/src/Requests/AltchaRequest/AltchaRequestBase.ts new file mode 100644 index 0000000..8fcd05a --- /dev/null +++ b/src/Requests/AltchaRequest/AltchaRequestBase.ts @@ -0,0 +1,55 @@ +import { CaptchaRequestBase, CaptchaRequestBaseIn } from '../CaptchaRequestBase'; + +export type AltchaRequestBaseIn = { + websiteURL: string; + userAgent?: string; + _class: string; + metadata: Metadata; +} & CaptchaRequestBaseIn; + +export type Metadata = { + challenge: string; + iterations: string; + salt: string; + signature: string; +}; + +/** + * Base DataDome recognition request + */ +export abstract class AltchaRequestBase extends CaptchaRequestBase { + /** + * Address of a webpage with DataDome. + */ + public websiteURL!: string; + + /** + * DataDome website key. + */ + public websiteKey!: string; + + /** + * The object that contains additional data about the captcha - captchaUrl: "captchaUrl": "..." + * You can take the link from the page with the captcha. + * Often it looks like https://geo.captcha-delivery.com/captcha/?initialCid=... + */ + public metadata!: Record; + + /** + * 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, metadata, _class }: AltchaRequestBaseIn) { + super({ type, nocache }); + this.websiteURL = websiteURL; + this.metadata = metadata; + this.userAgent = userAgent; + this.class = _class; + } +} diff --git a/src/Requests/AltchaRequest/index.ts b/src/Requests/AltchaRequest/index.ts new file mode 100644 index 0000000..1dbc364 --- /dev/null +++ b/src/Requests/AltchaRequest/index.ts @@ -0,0 +1 @@ +export * from './AltchaRequest'; diff --git a/src/Requests/DataDomeRequest/DataDomeRequestBase.ts b/src/Requests/DataDomeRequest/DataDomeRequestBase.ts index f52d38a..e164d2d 100644 --- a/src/Requests/DataDomeRequest/DataDomeRequestBase.ts +++ b/src/Requests/DataDomeRequest/DataDomeRequestBase.ts @@ -8,15 +8,17 @@ export type DataDomeRequestBaseIn = { } & CaptchaRequestBaseIn; export type MetadataWithHtml = { - [key: string]: string; + [key: string]: string | undefined; htmlPageBase64: string; datadomeCookie: string; + datadomeVersion?: string; }; export type MetadataCaptchaUrl = { - [key: string]: string; + [key: string]: string | undefined; captchaUrl: string; datadomeCookie: string; + datadomeVersion?: string; }; /** @@ -38,7 +40,7 @@ export abstract class DataDomeRequestBase extends CaptchaRequestBase { * You can take the link from the page with the captcha. * Often it looks like https://geo.captcha-delivery.com/captcha/?initialCid=... */ - public metadata!: Record; + public metadata!: Record; /** * Browser User-Agent. Pass only the actual UA from Windows OS diff --git a/src/Requests/ImpervaRequest/ImpervaRequest.ts b/src/Requests/ImpervaRequest/ImpervaRequest.ts index 2c2aea0..ff8ced7 100644 --- a/src/Requests/ImpervaRequest/ImpervaRequest.ts +++ b/src/Requests/ImpervaRequest/ImpervaRequest.ts @@ -2,7 +2,7 @@ import { TaskType } from '../../TaskType'; import { ImpervaRequestBase, ImpervaRequestBaseIn } from './ImpervaRequestBase'; import { ProxyInfo, ProxyInfoIn } from '../ProxyInfo'; -export type ImpervaRequestIn = Pick> & { proxy?: ProxyInfoIn }; +export type ImpervaRequestIn = Pick> & { proxy: ProxyInfoIn }; /** * Imperva recognition request. * {@link https://zenno.link/doc-imperva-en} @@ -10,9 +10,6 @@ export type ImpervaRequestIn = Pick; recaptchaDataSValue?: string; userAgent?: string; + pageAction?: string; } & CaptchaRequestBaseIn; /** @@ -55,6 +56,9 @@ export abstract class RecaptchaV2EnterpriseRequestBase extends CaptchaRequestBas */ public userAgent?: string; + // The action name passed to grecaptcha.execute(). + public pageAction?: string; + constructor({ type, nocache, @@ -63,6 +67,7 @@ export abstract class RecaptchaV2EnterpriseRequestBase extends CaptchaRequestBas enterprisePayload, recaptchaDataSValue, userAgent, + pageAction, }: RecaptchaV2EnterpriseRequestBaseIn) { super({ type, nocache }); this.websiteURL = websiteURL; @@ -70,5 +75,6 @@ export abstract class RecaptchaV2EnterpriseRequestBase extends CaptchaRequestBas this.enterprisePayload = enterprisePayload; this.recaptchaDataSValue = recaptchaDataSValue; this.userAgent = userAgent; + this.pageAction = pageAction; } } diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts new file mode 100644 index 0000000..090d185 --- /dev/null +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts @@ -0,0 +1,18 @@ +import { TaskType } from '../../TaskType'; +import { RecaptchaV3EnterpriseRequestBase, RecaptchaV3EnterpriseRequestBaseIn } from './RecaptchaV3EnterpriseRequestBase'; + +export type RecaptchaV3EnterpriseRequestIn = Pick< + RecaptchaV3EnterpriseRequestBaseIn, + Exclude +>; + +/** + * Recaptcha V2 Enterprise recognition request. + * {@link https://zenno.link/doc-recaptcha2e-proxy-en} + */ + +export class RecaptchaV3EnterpriseRequest extends RecaptchaV3EnterpriseRequestBase { + constructor({ ...restArgsObj }: RecaptchaV3EnterpriseRequestIn) { + super({ type: TaskType.RecaptchaV2EnterpriseTask, ...restArgsObj }); + } +} diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts new file mode 100644 index 0000000..43e8c89 --- /dev/null +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts @@ -0,0 +1,48 @@ +import { CaptchaRequestBase, CaptchaRequestBaseIn } from '../CaptchaRequestBase'; + +export type RecaptchaV3EnterpriseRequestBaseIn = { + websiteURL: string; + websiteKey: string; + userAgent?: string; + minScore?: number; + pageAction?: string; +} & CaptchaRequestBaseIn; + +/** + * Base Recaptcha V2 Enterprise recognition request + */ +export abstract class RecaptchaV3EnterpriseRequestBase extends CaptchaRequestBase { + /** + * Address of a webpage with Google ReCaptcha + */ + public websiteURL!: string; + + /** + * Recaptcha website key. + * @example + * ]]> + */ + public websiteKey!: string; + + /** + * Browser's User-Agent which is used in emulation. + * It is required that you use a signature of a modern browser, + * otherwise Google will ask you to "update your browser". + */ + public userAgent?: string; + + // The action name passed to grecaptcha.execute(). + public pageAction?: string; + + // Can have a value from 0.1 to 0.9 + public minScore?: number; + + constructor({ type, nocache, websiteURL, websiteKey, userAgent, pageAction, minScore }: RecaptchaV3EnterpriseRequestBaseIn) { + super({ type, nocache }); + this.websiteURL = websiteURL; + this.websiteKey = websiteKey; + this.userAgent = userAgent; + this.pageAction = pageAction; + this.minScore = minScore; + } +} diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/index.ts b/src/Requests/RecaptchaV3EnterpriseRequest/index.ts new file mode 100644 index 0000000..1df1765 --- /dev/null +++ b/src/Requests/RecaptchaV3EnterpriseRequest/index.ts @@ -0,0 +1 @@ +export * from './RecaptchaV3EnterpriseRequest'; diff --git a/src/Requests/RequestsSerialization.u.spec.ts b/src/Requests/RequestsSerialization.u.spec.ts index 6aad932..23bdf11 100644 --- a/src/Requests/RequestsSerialization.u.spec.ts +++ b/src/Requests/RequestsSerialization.u.spec.ts @@ -7,12 +7,14 @@ import { RecaptchaV3ProxylessRequest } from './RecaptchaV3ProxylessRequest'; import { FunCaptchaRequest } from './FunCaptchaRequest'; import { HCaptchaRequest } from './HCaptchaRequest'; import { GeeTestRequest } from './GeeTestRequest'; -import { TenDIRequest } from './TenDIRequest/TenDIRequest'; +import { TenDIRequest } from './TenDIRequest'; import { RecaptchaV2EnterpriseRequest } from './RecaptchaV2EnterpriseRequest'; import { ComplexImageHCaptchaRequest } from './ComplexImageHCaptchaRequest'; import { ComplexImageRecaptchaRequest } from './ComplexImageRecaptchaRequest'; import { ComplexImageFunCaptchaRequest } from './ComplexImageFunCaptchaRequest'; import { AmazonRequest } from './AmazonRequest'; +import { AltchaRequest } from './AltchaRequest'; +import { RecaptchaV3EnterpriseRequest } from './RecaptchaV3EnterpriseRequest'; describe('Check unit tests for SerializeObject()', () => { it(`should serialize RecaptchaV2ProxylessRequest`, () => { @@ -405,6 +407,7 @@ describe('Check unit tests for SerializeObject()', () => { enterprisePayload: { s: 'SOME_ADDITIONAL_TOKEN', }, + pageAction: 'login', proxy: { proxyType: 'http', proxyAddress: '8.8.8.8', @@ -434,6 +437,29 @@ describe('Check unit tests for SerializeObject()', () => { }); }); + it(`should serialize RecaptchaV3EnterpriseProxylessRequest`, () => { + const serialized = SerializeObject({ + clientKey: '', + task: new RecaptchaV3EnterpriseRequest({ + websiteURL: 'https://mydomain.com/page-with-recaptcha-enterprise', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + minScore: 0.7, + pageAction: 'login', + }), + }); + + expect(serialized).toMatchObject({ + clientKey: '', + task: { + type: 'RecaptchaV2EnterpriseTask', + websiteURL: 'https://mydomain.com/page-with-recaptcha-enterprise', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + minScore: 0.7, + pageAction: 'login', + }, + }); + }); + it(`should serialize ComplexImageHCaptchaRequest`, () => { const serialized = SerializeObject({ clientKey: '', @@ -529,6 +555,7 @@ describe('Check unit tests for SerializeObject()', () => { metadata: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', datadomeCookie: '', + datadomeVersion: 'new', }, }), }); @@ -543,6 +570,7 @@ describe('Check unit tests for SerializeObject()', () => { metadata: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', datadomeCookie: '', + datadomeVersion: 'new', }, }, }); @@ -588,6 +616,82 @@ describe('Check unit tests for SerializeObject()', () => { }); }); + it(`should serialize AltchaRequest`, () => { + const serialized = SerializeObject({ + clientKey: '', + task: new AltchaRequest({ + websiteURL: 'site.com', + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + metadata: { + challenge: '3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c', + iterations: '5000', + salt: '46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664', + signature: '4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18', + }, + }), + }); + + expect(serialized).toMatchObject({ + clientKey: '', + task: { + type: 'CustomTask', + class: 'altcha', + websiteURL: 'site.com', + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + metadata: { + challenge: '3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c', + iterations: '5000', + salt: '46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664', + signature: '4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18', + }, + }, + }); + }); + + it(`should serialize AltchaRequest with proxy`, () => { + const serialized = SerializeObject({ + clientKey: '', + task: new AltchaRequest({ + websiteURL: 'site.com', + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + metadata: { + challenge: '3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c', + iterations: '5000', + salt: '46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664', + signature: '4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18', + }, + proxy: { + proxyType: 'socks4', + proxyAddress: 'https://proxy.com', + proxyPort: 6045, + proxyLogin: 'login', + proxyPassword: 'p@ssword', + }, + }), + }); + + expect(serialized).toMatchObject({ + clientKey: '', + task: { + type: 'CustomTask', + class: 'altcha', + websiteURL: 'site.com', + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + metadata: { + challenge: '3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c', + iterations: '5000', + salt: '46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664', + signature: '4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18', + }, + proxyType: 'socks4', + proxyAddress: 'https://proxy.com', + proxyPort: 6045, + proxyLogin: 'login', + proxyPassword: 'p@ssword', + }, + }); + }); + it(`should serialize TenDIRequest`, () => { const serialized = SerializeObject({ clientKey: '', diff --git a/src/Requests/TurnstileRequest/TurnstileRequest.ts b/src/Requests/TurnstileRequest/TurnstileRequest.ts index e3c4370..6a7b62e 100644 --- a/src/Requests/TurnstileRequest/TurnstileRequest.ts +++ b/src/Requests/TurnstileRequest/TurnstileRequest.ts @@ -28,7 +28,7 @@ export type TurnstileRequestIn = (TurnstileTokenType | TurnstileCfClearanceType) * {@link https://zennolab.atlassian.net/wiki/spaces/APIS/pages/2313814017/TurnstileTask+Cloudflare+Challenge} */ export class TurnstileRequest extends TurnstileRequestBase { - cloudflareTaskType?: 'token' | 'cf_clearance'; + cloudflareTaskType?: 'token' | 'cf_clearance' | 'wait_room'; userAgent?: string; pageAction?: string; htmlPageBase64?: string; diff --git a/src/Responses/AltchaResponse.ts b/src/Responses/AltchaResponse.ts new file mode 100644 index 0000000..bd6ea5f --- /dev/null +++ b/src/Responses/AltchaResponse.ts @@ -0,0 +1 @@ +export type AltchaResponse = { number: number }; diff --git a/src/Responses/FunCaptchaResponse.ts b/src/Responses/FunCaptchaResponse.ts index 775c4db..0dc6e42 100644 --- a/src/Responses/FunCaptchaResponse.ts +++ b/src/Responses/FunCaptchaResponse.ts @@ -1,13 +1,4 @@ -/** - * FunCaptcha recognition response - */ export type FunCaptchaResponse = { - /** - * FunCaptcha token that needs to be substituted into the form. - * @example - * - */ token: string; + userAgent: string; }; diff --git a/src/Responses/MTCaptchaResponse.ts b/src/Responses/MTCaptchaResponse.ts index 9279750..e3186d9 100644 --- a/src/Responses/MTCaptchaResponse.ts +++ b/src/Responses/MTCaptchaResponse.ts @@ -3,4 +3,5 @@ */ export type MTCaptchaResponse = { token: string; + userAgent: string; }; diff --git a/src/Responses/ProsopoResponse.ts b/src/Responses/ProsopoResponse.ts index acd556c..4dcb33c 100644 --- a/src/Responses/ProsopoResponse.ts +++ b/src/Responses/ProsopoResponse.ts @@ -3,4 +3,5 @@ */ export type ProsopoResponse = { token: string; + userAgent: string; }; diff --git a/src/Responses/RecaptchaV3EnterpriseResponse.ts b/src/Responses/RecaptchaV3EnterpriseResponse.ts new file mode 100644 index 0000000..debbdd0 --- /dev/null +++ b/src/Responses/RecaptchaV3EnterpriseResponse.ts @@ -0,0 +1,6 @@ +import { RecaptchaResponseBase } from './RecaptchaResponseBase'; + +/** + * RecaptchaV3 Enterprise recognition response + */ +export type RecaptchaV3EnterpriseResponse = RecaptchaResponseBase; diff --git a/src/Responses/TurnstileResponse.ts b/src/Responses/TurnstileResponse.ts index b786085..f9fcfce 100644 --- a/src/Responses/TurnstileResponse.ts +++ b/src/Responses/TurnstileResponse.ts @@ -2,8 +2,9 @@ * Turnstile recognition response */ export type TurnstileResponse = { - /** - * Captcha answer - */ - token: string; - }; \ No newline at end of file + /** + * Captcha answer + */ + token: string; + userAgent: string; +}; diff --git a/src/Responses/YidunResponse.ts b/src/Responses/YidunResponse.ts index ed5fc85..2b8a4bb 100644 --- a/src/Responses/YidunResponse.ts +++ b/src/Responses/YidunResponse.ts @@ -3,4 +3,5 @@ */ export type YidunResponse = { token: string; + userAgent: string; }; diff --git a/src/index.ts b/src/index.ts index 2b77078..bf631ff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import { HCaptchaRequest, HCaptchaRequestIn } from './Requests/HCaptchaRequest'; import { ImageToTextRequest, ImageToTextRequestIn } from './Requests/ImageToTextRequest'; import { RecaptchaV2EnterpriseRequest, RecaptchaV2EnterpriseRequestIn } from './Requests/RecaptchaV2EnterpriseRequest'; import { RecaptchaV2Request, RecaptchaV2RequestIn } from './Requests/RecaptchaV2Request'; +import { RecaptchaV3EnterpriseRequest, RecaptchaV3EnterpriseRequestIn } from './Requests/RecaptchaV3EnterpriseRequest'; import { RecaptchaV3ProxylessRequest, RecaptchaV3ProxylessRequestIn } from './Requests/RecaptchaV3ProxylessRequest'; import { TurnstileRequest, TurnstileRequestIn } from './Requests/TurnstileRequest'; import { CapMonsterModules } from './CapMonsterModules'; @@ -26,6 +27,7 @@ import { ProsopoRequest, ProsopoRequestIn } from './Requests/ProsopoRequest'; import { TemuRequest, TemuRequestIn } from './Requests/TemuRequest'; import { YidunRequest, YidunRequestIn } from './Requests/YidunRequest'; import { MTCaptchaRequest, MTCaptchaRequestIn } from './Requests/MTCaptchaRequest'; +import { AltchaRequest, AltchaRequestIn } from './Requests/AltchaRequest'; export default { CapMonsterCloudClientFactory, @@ -52,6 +54,8 @@ export default { TemuRequest, YidunRequest, MTCaptchaRequest, + AltchaRequest, + RecaptchaV3EnterpriseRequest, }; export { @@ -105,4 +109,8 @@ export { YidunRequestIn, MTCaptchaRequest, MTCaptchaRequestIn, + AltchaRequest, + AltchaRequestIn, + RecaptchaV3EnterpriseRequest, + RecaptchaV3EnterpriseRequestIn, }; From 5ffad2a8afc88f9410e5a6f1103e71d81ce895e6 Mon Sep 17 00:00:00 2001 From: Kirill Bushmin Date: Thu, 22 Jan 2026 12:25:58 +0300 Subject: [PATCH 2/4] CCL-7162 fixed comments --- src/Requests/AltchaRequest/AltchaRequest.ts | 2 +- src/Requests/AltchaRequest/AltchaRequestBase.ts | 10 ++++------ .../RecaptchaV3EnterpriseRequest.ts | 6 +++--- .../RecaptchaV3EnterpriseRequestBase.ts | 2 -- src/Requests/RequestsSerialization.u.spec.ts | 2 +- src/TaskType.ts | 1 + 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Requests/AltchaRequest/AltchaRequest.ts b/src/Requests/AltchaRequest/AltchaRequest.ts index 45d0424..459745b 100644 --- a/src/Requests/AltchaRequest/AltchaRequest.ts +++ b/src/Requests/AltchaRequest/AltchaRequest.ts @@ -6,7 +6,7 @@ export type AltchaRequestIn = Pick; + public metadata!: Metadata; /** * Browser User-Agent. Pass only the actual UA from Windows OS diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts index 090d185..40a644f 100644 --- a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequest.ts @@ -7,12 +7,12 @@ export type RecaptchaV3EnterpriseRequestIn = Pick< >; /** - * Recaptcha V2 Enterprise recognition request. - * {@link https://zenno.link/doc-recaptcha2e-proxy-en} + * Recaptcha V3 Enterprise recognition request. + * {@link https://zenno.link/doc-recaptcha3e-proxy-en} */ export class RecaptchaV3EnterpriseRequest extends RecaptchaV3EnterpriseRequestBase { constructor({ ...restArgsObj }: RecaptchaV3EnterpriseRequestIn) { - super({ type: TaskType.RecaptchaV2EnterpriseTask, ...restArgsObj }); + super({ type: TaskType.RecaptchaV3EnterpriseTask, ...restArgsObj }); } } diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts index 43e8c89..cfa736f 100644 --- a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts @@ -19,8 +19,6 @@ export abstract class RecaptchaV3EnterpriseRequestBase extends CaptchaRequestBas /** * Recaptcha website key. - * @example - * ]]> */ public websiteKey!: string; diff --git a/src/Requests/RequestsSerialization.u.spec.ts b/src/Requests/RequestsSerialization.u.spec.ts index 23bdf11..b42d787 100644 --- a/src/Requests/RequestsSerialization.u.spec.ts +++ b/src/Requests/RequestsSerialization.u.spec.ts @@ -451,7 +451,7 @@ describe('Check unit tests for SerializeObject()', () => { expect(serialized).toMatchObject({ clientKey: '', task: { - type: 'RecaptchaV2EnterpriseTask', + type: 'RecaptchaV3EnterpriseTask', websiteURL: 'https://mydomain.com/page-with-recaptcha-enterprise', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', minScore: 0.7, diff --git a/src/TaskType.ts b/src/TaskType.ts index 2589e23..31626b9 100644 --- a/src/TaskType.ts +++ b/src/TaskType.ts @@ -5,6 +5,7 @@ export enum TaskType { HCaptchaTask = 'HCaptchaTask', ImageToTextTask = 'ImageToTextTask', RecaptchaV2EnterpriseTask = 'RecaptchaV2EnterpriseTask', + RecaptchaV3EnterpriseTask = 'RecaptchaV3EnterpriseTask', NoCaptchaTaskProxyless = 'NoCaptchaTaskProxyless', NoCaptchaTask = 'NoCaptchaTask', RecaptchaV3TaskProxyless = 'RecaptchaV3TaskProxyless', From e29a0fe1ba32aa20fe9b1432172bdb97e506c408 Mon Sep 17 00:00:00 2001 From: Kirill Bushmin Date: Thu, 22 Jan 2026 12:37:38 +0300 Subject: [PATCH 3/4] CCL-7162 fixed comments --- .../RecaptchaV3EnterpriseRequestBase.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts index cfa736f..12131da 100644 --- a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts @@ -9,7 +9,7 @@ export type RecaptchaV3EnterpriseRequestBaseIn = { } & CaptchaRequestBaseIn; /** - * Base Recaptcha V2 Enterprise recognition request + * Base Recaptcha V3 Enterprise recognition request */ export abstract class RecaptchaV3EnterpriseRequestBase extends CaptchaRequestBase { /** @@ -18,7 +18,8 @@ export abstract class RecaptchaV3EnterpriseRequestBase extends CaptchaRequestBas public websiteURL!: string; /** - * Recaptcha website key. + * The ReCaptcha v3 site key on the target page. + * https://www.google.com/recaptcha/enterprise.js?render=THIS_ONE */ public websiteKey!: string; From 0c445ddf865146dc534b3250f71a90514b6af931 Mon Sep 17 00:00:00 2001 From: Kirill Bushmin Date: Mon, 26 Jan 2026 12:22:12 +0300 Subject: [PATCH 4/4] CCL-7162 version up --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index af8666e..39a0cda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zennolab_com/capmonstercloud-client", - "version": "2.4.0", + "version": "2.5.0", "description": "Official JS client library for https://capmonster.cloud/ captcha recognition service", "main": "dist/index.js", "types": "dist/index.d.ts",