diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..c5518cc --- /dev/null +++ b/.eslintignore @@ -0,0 +1,14 @@ +node_modules +dist +coverage +*.log + +# TypeScript +*.d.ts + +# IDE +.vscode +.idea + +# OS +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 7781f60..24b85cb 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,30 @@ run() }); ``` +## Usage with CommonCaptcha + +Use `CommonCaptcha` when you want to pass a full task payload directly, for example when a new captcha type is not yet covered by a dedicated request class. + +```javascript +const { CapMonsterCloudClientFactory, ClientOptions, CommonCaptcha } = require('@zennolab_com/capmonstercloud-client'); + +async function run() { + const cmcClient = CapMonsterCloudClientFactory.Create(new ClientOptions({ clientKey: '' })); + + const commonCaptcha = new CommonCaptcha({ + task: { + type: 'RecaptchaV2Task', + websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + }, + }); + + console.log(await cmcClient.Solve(commonCaptcha)); +} + +run(); +``` + ## Usage with Browser (with or without Typescript) Browser implementation use [fetch](https://caniuse.com/fetch) instead of [http(s)](https://nodejs.org/api/http.html). diff --git a/js-fix-esm-imports.js b/js-fix-esm-imports.js new file mode 100644 index 0000000..9a17509 --- /dev/null +++ b/js-fix-esm-imports.js @@ -0,0 +1,43 @@ +/* eslint @typescript-eslint/no-var-requires: 0 */ +const fs = require('fs'); +const path = require('path'); + +const esmDir = path.join(__dirname, 'dist', 'esm'); + +function walk(dir) { + return fs.readdirSync(dir).flatMap((entry) => { + const fullPath = path.join(dir, entry); + return fs.statSync(fullPath).isDirectory() ? walk(fullPath) : [fullPath]; + }); +} + +function resolveImportPath(filePath, importPath) { + if (!importPath.startsWith('.')) { + return importPath; + } + + const absoluteTarget = path.resolve(path.dirname(filePath), importPath); + if (fs.existsSync(`${absoluteTarget}.js`)) { + return `${importPath}.js`; + } + + if (fs.existsSync(path.join(absoluteTarget, 'index.js'))) { + return `${importPath}/index.js`; + } + + return importPath; +} + +function fixImports(filePath) { + const source = fs.readFileSync(filePath, 'utf8'); + const fixed = source.replace(/(from\s+['"])([^'"]+)(['"])/g, (_, prefix, importPath, suffix) => { + return `${prefix}${resolveImportPath(filePath, importPath)}${suffix}`; + }); + fs.writeFileSync(filePath, fixed); +} + +if (fs.existsSync(esmDir)) { + walk(esmDir) + .filter((filePath) => filePath.endsWith('.js')) + .forEach(fixImports); +} diff --git a/package.json b/package.json index b6e4e08..ad0f918 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,18 @@ { "name": "@zennolab_com/capmonstercloud-client", - "version": "2.7.0", + "version": "2.8.0", "description": "Official JS client library for https://capmonster.cloud/ captcha recognition service", "main": "dist/index.js", + "module": "dist/esm/index.js", "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/esm/index.js", + "require": "./dist/index.js", + "default": "./dist/esm/index.js" + } + }, "engines": { "node": ">=18" }, @@ -21,10 +30,12 @@ "ZennoPoster" ], "scripts": { - "build": "node js-rimraf.js && npx tsc", + "build": "node js-rimraf.js && npx tsc && npx tsc -p tsconfig.esm.json && node js-fix-esm-imports.js && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({ type: 'module' }, null, 2))\"", "test": "jest", "test-unit": "jest -c jest.config.unit.js", - "test-integr": "jest -c jest.config.integration.js" + "test-integr": "jest -c jest.config.integration.js", + "lint": "eslint . --ext .ts,.js", + "lint:fix": "eslint . --ext .ts,.js --fix" }, "author": "", "license": "ISC", diff --git a/src/CapMonsterCloudClient.ts b/src/CapMonsterCloudClient.ts index 4bcc237..accb184 100644 --- a/src/CapMonsterCloudClient.ts +++ b/src/CapMonsterCloudClient.ts @@ -67,6 +67,8 @@ import { AlibabaRequest } from './Requests/AlibabaRequest'; import { AlibabaResponse } from './Responses/AlibabaResponse'; import { FriendlyRequest } from './Requests/FriendlyRequest'; import { FriendlyResponse } from './Responses/FriendlyResponse'; +import { CommonCaptchaRequest } from './Requests/CommonCaptchaRequest'; +import { CommonCaptchaResponse } from './Responses/CommonCaptchaResponse'; /** * Base type for capmonster.cloud Client exceptions @@ -446,6 +448,14 @@ export class CapMonsterCloudClient { resultTimeouts?: GetResultTimeouts, cancellationController?: AbortController, ): Promise>; + /** + * Solve CommonCaptchaRequest task. + */ + public async Solve( + task: CommonCaptchaRequest, + resultTimeouts?: GetResultTimeouts, + cancellationController?: AbortController, + ): Promise>; /** * Solve {Task} task */ diff --git a/src/CapMonsterCloudClientFactory.i.spec.ts b/src/CapMonsterCloudClientFactory.i.spec.ts index ac54cec..100c8cb 100644 --- a/src/CapMonsterCloudClientFactory.i.spec.ts +++ b/src/CapMonsterCloudClientFactory.i.spec.ts @@ -24,6 +24,7 @@ import { TSPDRequest } from './Requests/TSPDRequest'; import { HuntRequest } from './Requests/HuntRequest'; import { AlibabaRequest } from './Requests/AlibabaRequest'; import { FriendlyRequest } from './Requests/FriendlyRequest'; +import { CommonCaptchaRequest } from './Requests/CommonCaptchaRequest'; const { version } = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires @@ -130,6 +131,45 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { expect(await srv.destroy()).toBeUndefined(); }); + it('should call createTask and getTaskResult methods with specified objects for CommonCaptchaRequest', async () => { + expect.assertions(5); + + const srv = await createServerMock({ + responses: [ + { responseBody: '{"errorId":0,"taskId":7654321}' }, + { responseBody: '{"errorId":0,"status":"ready","solution":{"gRecaptchaResponse":"answer"}}' }, + ], + }); + + const cmcClient = CapMonsterCloudClientFactory.Create( + new ClientOptions({ clientKey: '', serviceUrl: `http://localhost:${srv.address.port}` }), + ); + + const commonCaptchaRequest = new CommonCaptchaRequest({ + task: { + type: 'RecaptchaV2Task', + websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + }, + }); + + const task = await cmcClient.Solve(commonCaptchaRequest, { + firstRequestDelay: 0, + requestsInterval: 1000, + timeout: 1000, + }); + + expect(srv.caughtRequests[0]).toHaveProperty( + 'body', + '{"clientKey":"","task":{"type":"RecaptchaV2Task","websiteURL":"https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high","websiteKey":"6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd"},"softId":54}', + ); + expect(srv.caughtRequests[1]).toHaveProperty('body', '{"clientKey":"","taskId":7654321}'); + expect(task).toHaveProperty('solution'); + expect(task).toHaveProperty('solution.gRecaptchaResponse', 'answer'); + + expect(await srv.destroy()).toBeUndefined(); + }); + it('should call createTask with proxy parameters and getTaskResult methods with specified objects', async () => { expect.assertions(5); @@ -182,7 +222,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', userAgent: 'userAgent', }); @@ -217,7 +257,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', userAgent: 'userAgent', }); @@ -246,7 +286,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', userAgent: 'userAgent', }); @@ -268,7 +308,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { expect(srv.caughtRequests[0]).toHaveProperty( 'body', - '{"clientKey":"","task":{"type":"NoCaptchaTask","websiteURL":"websiteURL","websiteKey":"websiteKey","userAgent":"userAgent"},"softId":54}', + '{"clientKey":"","task":{"type":"NoCaptchaTask","websiteURL":"https://example.com","websiteKey":"websiteKey","userAgent":"userAgent"},"softId":54}', ); expect(task).toBeInstanceOf(CaptchaResult); expect(task.solution).toBeUndefined(); @@ -292,7 +332,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', userAgent: 'userAgent', nocache: true, @@ -315,7 +355,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { expect(srv.caughtRequests[0]).toHaveProperty( 'body', - '{"clientKey":"","task":{"type":"NoCaptchaTask","nocache":true,"websiteURL":"websiteURL","websiteKey":"websiteKey","userAgent":"userAgent"},"softId":54}', + '{"clientKey":"","task":{"type":"NoCaptchaTask","nocache":true,"websiteURL":"https://example.com","websiteKey":"websiteKey","userAgent":"userAgent"},"softId":54}', ); expect(task).toBeInstanceOf(CaptchaResult); expect(task.solution).toBeUndefined(); @@ -339,7 +379,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', }); @@ -352,7 +392,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { expect(srv.caughtRequests[0]).toHaveProperty( 'body', - '{"clientKey":"","task":{"type":"NoCaptchaTask","websiteURL":"websiteURL","websiteKey":"websiteKey"},"softId":54}', + '{"clientKey":"","task":{"type":"NoCaptchaTask","websiteURL":"https://example.com","websiteKey":"websiteKey"},"softId":54}', ); expect(task).toBeInstanceOf(CaptchaResult); expect(task.solution).toBeUndefined(); @@ -379,7 +419,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', }); @@ -408,7 +448,7 @@ describe('Check integration tests for CapMonsterCloudClientFactory()', () => { ); const recaptchaV2Request = new RecaptchaV2Request({ - websiteURL: 'websiteURL', + websiteURL: 'https://example.com', websiteKey: 'websiteKey', }); diff --git a/src/GetResultTimeouts.ts b/src/GetResultTimeouts.ts index d794736..cef0930 100644 --- a/src/GetResultTimeouts.ts +++ b/src/GetResultTimeouts.ts @@ -1,4 +1,5 @@ import { Task } from './Requests/Task'; +import { CommonCaptchaRequest } from './Requests/CommonCaptchaRequest'; import { TaskType } from './TaskType'; export type GetResultTimeouts = { @@ -118,7 +119,13 @@ export const MTCaptchaTaskTimeouts = { } as GetResultTimeouts; export function detectResultTimeouts(task: Task): GetResultTimeouts { - switch (task.type) { + if (task instanceof CommonCaptchaRequest) { + return CustomTaskTimeouts; + } + + const taskType = task.type; + + switch (taskType) { case TaskType.FunCaptchaTask: return FunCaptchaTimeouts; case TaskType.GeeTestTask: @@ -154,6 +161,6 @@ export function detectResultTimeouts(task: Task): GetResultTimeouts { case TaskType.MTCaptchaTask: return MTCaptchaTaskTimeouts; default: - throw new Error(`Could not detect result timeouts for provided task type = ${task.type}`); + throw new Error(`Could not detect result timeouts for provided task type = ${taskType}`); } } diff --git a/src/GetTaskResult.ts b/src/GetTaskResult.ts index 883782e..7302b35 100644 --- a/src/GetTaskResult.ts +++ b/src/GetTaskResult.ts @@ -20,6 +20,7 @@ import { TSPDResponse } from './Responses/TSPDResponse'; import { HuntResponse } from './Responses/HuntResponse'; import { AlibabaResponse } from './Responses/AlibabaResponse'; import { FriendlyResponse } from './Responses/FriendlyResponse'; +import { CommonCaptchaResponse } from './Responses/CommonCaptchaResponse'; export enum TaskResultType { Failed = 'Failed', @@ -57,7 +58,8 @@ export type TaskCompletedSolution = | TSPDResponse | HuntResponse | AlibabaResponse - | FriendlyResponse; + | FriendlyResponse + | CommonCaptchaResponse; export type TaskCompleted = { type: TaskResultType.Completed; diff --git a/src/Requests/AlibabaRequest/AlibabaRequestBase.ts b/src/Requests/AlibabaRequest/AlibabaRequestBase.ts index 3ec72c8..88a6ed9 100644 --- a/src/Requests/AlibabaRequest/AlibabaRequestBase.ts +++ b/src/Requests/AlibabaRequest/AlibabaRequestBase.ts @@ -44,7 +44,7 @@ export abstract class AlibabaRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: AlibabaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.userAgent = userAgent; this.metadata = metadata; this.class = _class; diff --git a/src/Requests/AltchaRequest/AltchaRequestBase.ts b/src/Requests/AltchaRequest/AltchaRequestBase.ts index fedea54..bfbf671 100644 --- a/src/Requests/AltchaRequest/AltchaRequestBase.ts +++ b/src/Requests/AltchaRequest/AltchaRequestBase.ts @@ -46,7 +46,7 @@ export abstract class AltchaRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, userAgent, metadata, _class }: AltchaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.metadata = metadata; this.userAgent = userAgent; diff --git a/src/Requests/AmazonRequest/AmazonRequestBase.ts b/src/Requests/AmazonRequest/AmazonRequestBase.ts index 7473635..1225344 100644 --- a/src/Requests/AmazonRequest/AmazonRequestBase.ts +++ b/src/Requests/AmazonRequest/AmazonRequestBase.ts @@ -68,7 +68,7 @@ export abstract class AmazonRequestBase extends CaptchaRequestBase { userAgent, }: AmazonRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.challengeScript = challengeScript; this.captchaScript = captchaScript; this.websiteKey = websiteKey; diff --git a/src/Requests/BasiliskRequest/BasiliskRequestBase.ts b/src/Requests/BasiliskRequest/BasiliskRequestBase.ts index 1a60c72..0f5fdb4 100644 --- a/src/Requests/BasiliskRequest/BasiliskRequestBase.ts +++ b/src/Requests/BasiliskRequest/BasiliskRequestBase.ts @@ -33,7 +33,7 @@ export abstract class BasiliskRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, websiteKey, _class }: BasiliskRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.class = _class; diff --git a/src/Requests/BinanceRequest/BinanceRequestBase.ts b/src/Requests/BinanceRequest/BinanceRequestBase.ts index 61984e7..d48e26c 100644 --- a/src/Requests/BinanceRequest/BinanceRequestBase.ts +++ b/src/Requests/BinanceRequest/BinanceRequestBase.ts @@ -33,7 +33,7 @@ export abstract class BinanceRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, websiteKey, validateId }: BinanceRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.validateId = validateId; this.userAgent = userAgent; diff --git a/src/Requests/CaptchaRequestBase.ts b/src/Requests/CaptchaRequestBase.ts index f617615..cac2d5d 100644 --- a/src/Requests/CaptchaRequestBase.ts +++ b/src/Requests/CaptchaRequestBase.ts @@ -2,6 +2,20 @@ import { TaskType } from '../TaskType'; export type CaptchaRequestBaseIn = { type: TaskType; nocache?: boolean }; +export function validateWebsiteURL(websiteURL: string): string { + try { + const url = new URL(websiteURL); + + if (url.protocol === 'http:' || url.protocol === 'https:') { + return websiteURL; + } + } catch { + // Handled by the error below to keep one public validation message. + } + + throw new Error('websiteURL must be a valid http or https URL'); +} + /** * Base captcha recognition request */ @@ -21,4 +35,8 @@ export abstract class CaptchaRequestBase { this.type = type; this.nocache = nocache; } + + protected validateWebsiteURL(websiteURL: string): string { + return validateWebsiteURL(websiteURL); + } } diff --git a/src/Requests/CastleRequest/CastleRequestBase.ts b/src/Requests/CastleRequest/CastleRequestBase.ts index a5a5ec2..a927a72 100644 --- a/src/Requests/CastleRequest/CastleRequestBase.ts +++ b/src/Requests/CastleRequest/CastleRequestBase.ts @@ -69,7 +69,7 @@ export abstract class CastleRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, userAgent, metadata, _class }: CastleRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.metadata = metadata; diff --git a/src/Requests/CommonCaptchaRequest.ts b/src/Requests/CommonCaptchaRequest.ts new file mode 100644 index 0000000..2e0cf69 --- /dev/null +++ b/src/Requests/CommonCaptchaRequest.ts @@ -0,0 +1,40 @@ +import { validateWebsiteURL } from './CaptchaRequestBase'; + +export type CommonCaptchaTask = { + type: string; + websiteURL?: string; + nocache?: boolean; + [key: string]: unknown; +}; + +export type CommonCaptchaRequestIn = { + task: CommonCaptchaTask; +}; + +/** + * Common captcha recognition request for passing a full task payload. + */ +export class CommonCaptchaRequest { + public type: string; + + public websiteURL?: string; + + public nocache?: boolean; + + [key: string]: unknown; + + constructor({ task }: CommonCaptchaRequestIn) { + if (task.type.trim().length === 0) { + throw new Error('task.type must be a non-empty string'); + } + + if (task.websiteURL !== undefined) { + validateWebsiteURL(task.websiteURL); + } + + Object.assign(this, task); + this.type = task.type; + } +} + +export class CommonCaptcha extends CommonCaptchaRequest {} diff --git a/src/Requests/ComplexImageRequestBase.ts b/src/Requests/ComplexImageRequestBase.ts index 93de55b..003fd45 100644 --- a/src/Requests/ComplexImageRequestBase.ts +++ b/src/Requests/ComplexImageRequestBase.ts @@ -48,6 +48,6 @@ export class ComplexImageRequestBase extends CaptchaRequestBase { this.imagesBase64 = imagesBase64; this.metadata = metaData; this.userAgent = userAgent; - this.websiteURL = websiteURL; + this.websiteURL = websiteURL === undefined ? undefined : this.validateWebsiteURL(websiteURL); } } diff --git a/src/Requests/DataDomeRequest/DataDomeRequestBase.ts b/src/Requests/DataDomeRequest/DataDomeRequestBase.ts index e164d2d..2fa11f2 100644 --- a/src/Requests/DataDomeRequest/DataDomeRequestBase.ts +++ b/src/Requests/DataDomeRequest/DataDomeRequestBase.ts @@ -54,7 +54,7 @@ export abstract class DataDomeRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: DataDomeRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.metadata = metadata; this.userAgent = userAgent; this.class = _class; diff --git a/src/Requests/FriendlyRequest/FriendlyRequestBase.ts b/src/Requests/FriendlyRequest/FriendlyRequestBase.ts index d332d73..d03b56d 100644 --- a/src/Requests/FriendlyRequest/FriendlyRequestBase.ts +++ b/src/Requests/FriendlyRequest/FriendlyRequestBase.ts @@ -43,7 +43,7 @@ export abstract class FriendlyRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, userAgent, metadata, _class }: FriendlyRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.metadata = metadata; diff --git a/src/Requests/FunCaptchaRequest/FunCaptchaRequestBase.ts b/src/Requests/FunCaptchaRequest/FunCaptchaRequestBase.ts index db36077..911370d 100644 --- a/src/Requests/FunCaptchaRequest/FunCaptchaRequestBase.ts +++ b/src/Requests/FunCaptchaRequest/FunCaptchaRequestBase.ts @@ -55,9 +55,18 @@ export abstract class FunCaptchaRequestBase extends CaptchaRequestBase { */ public userAgent?: string; - constructor({ type, nocache, websiteURL, websitePublicKey, funcaptchaApiJSSubdomain, data, cookies, userAgent }: FunCaptchaRequestBaseIn) { + constructor({ + type, + nocache, + websiteURL, + websitePublicKey, + funcaptchaApiJSSubdomain, + data, + cookies, + userAgent, + }: FunCaptchaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websitePublicKey = websitePublicKey; this.funcaptchaApiJSSubdomain = funcaptchaApiJSSubdomain; this.data = data; diff --git a/src/Requests/GeeTestRequest/GeeTestRequestBase.ts b/src/Requests/GeeTestRequest/GeeTestRequestBase.ts index 07643fd..f259404 100644 --- a/src/Requests/GeeTestRequest/GeeTestRequestBase.ts +++ b/src/Requests/GeeTestRequest/GeeTestRequestBase.ts @@ -86,7 +86,7 @@ export abstract class GeeTestRequestBase extends CaptchaRequestBase { initParameters, }: GeeTestRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.gt = gt; this.challenge = challenge; this.geetestApiServerSubdomain = geetestApiServerSubdomain; diff --git a/src/Requests/HCaptchaRequest/HCaptchaRequestBase.ts b/src/Requests/HCaptchaRequest/HCaptchaRequestBase.ts index f2b9154..055d08f 100644 --- a/src/Requests/HCaptchaRequest/HCaptchaRequestBase.ts +++ b/src/Requests/HCaptchaRequest/HCaptchaRequestBase.ts @@ -58,7 +58,7 @@ export abstract class HCaptchaRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, isInvisible, data, userAgent, cookies, fallbackToActualUA }: HCaptchaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.isInvisible = isInvisible; this.data = data; diff --git a/src/Requests/HuntRequest/HuntRequestBase.ts b/src/Requests/HuntRequest/HuntRequestBase.ts index 2948aea..a7bfc0a 100644 --- a/src/Requests/HuntRequest/HuntRequestBase.ts +++ b/src/Requests/HuntRequest/HuntRequestBase.ts @@ -55,7 +55,7 @@ export abstract class HuntRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: HuntRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.userAgent = userAgent; this.metadata = metadata; this.class = _class; diff --git a/src/Requests/ImpervaRequest/ImpervaRequestBase.ts b/src/Requests/ImpervaRequest/ImpervaRequestBase.ts index 7734aeb..bc66266 100644 --- a/src/Requests/ImpervaRequest/ImpervaRequestBase.ts +++ b/src/Requests/ImpervaRequest/ImpervaRequestBase.ts @@ -48,7 +48,7 @@ export abstract class ImpervaRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: ImpervaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.metadata = metadata; this.userAgent = userAgent; this.class = _class; diff --git a/src/Requests/MTCaptchaRequest/MTCaptchaRequestBase.ts b/src/Requests/MTCaptchaRequest/MTCaptchaRequestBase.ts index 9280386..35291d5 100644 --- a/src/Requests/MTCaptchaRequest/MTCaptchaRequestBase.ts +++ b/src/Requests/MTCaptchaRequest/MTCaptchaRequestBase.ts @@ -39,7 +39,7 @@ export abstract class MTCaptchaRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, userAgent, pageAction, isInvisible }: MTCaptchaRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.pageAction = pageAction; diff --git a/src/Requests/ProsopoRequest/ProsopoRequestBase.ts b/src/Requests/ProsopoRequest/ProsopoRequestBase.ts index 782a94e..4b9a34f 100644 --- a/src/Requests/ProsopoRequest/ProsopoRequestBase.ts +++ b/src/Requests/ProsopoRequest/ProsopoRequestBase.ts @@ -21,7 +21,7 @@ export abstract class ProsopoRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey }: ProsopoRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; } } diff --git a/src/Requests/RecaptchaV2EnterpriseRequest/RecaptchaV2EnterpriseRequestBase.ts b/src/Requests/RecaptchaV2EnterpriseRequest/RecaptchaV2EnterpriseRequestBase.ts index 5bf4f43..60cf243 100644 --- a/src/Requests/RecaptchaV2EnterpriseRequest/RecaptchaV2EnterpriseRequestBase.ts +++ b/src/Requests/RecaptchaV2EnterpriseRequest/RecaptchaV2EnterpriseRequestBase.ts @@ -84,7 +84,7 @@ export abstract class RecaptchaV2EnterpriseRequestBase extends CaptchaRequestBas cookies, }: RecaptchaV2EnterpriseRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.enterprisePayload = enterprisePayload; this.recaptchaDataSValue = recaptchaDataSValue; diff --git a/src/Requests/RecaptchaV2Request/RecaptchaV2RequestBase.ts b/src/Requests/RecaptchaV2Request/RecaptchaV2RequestBase.ts index 8c475ca..9e71ca9 100644 --- a/src/Requests/RecaptchaV2Request/RecaptchaV2RequestBase.ts +++ b/src/Requests/RecaptchaV2Request/RecaptchaV2RequestBase.ts @@ -51,7 +51,7 @@ export abstract class RecaptchaV2RequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey, recaptchaDataSValue, userAgent, cookies, isInvisible }: RecaptchaV2RequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.recaptchaDataSValue = recaptchaDataSValue; this.userAgent = userAgent; diff --git a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts index 12131da..f83c314 100644 --- a/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts +++ b/src/Requests/RecaptchaV3EnterpriseRequest/RecaptchaV3EnterpriseRequestBase.ts @@ -38,7 +38,7 @@ export abstract class RecaptchaV3EnterpriseRequestBase extends CaptchaRequestBas constructor({ type, nocache, websiteURL, websiteKey, userAgent, pageAction, minScore }: RecaptchaV3EnterpriseRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.pageAction = pageAction; diff --git a/src/Requests/RecaptchaV3ProxylessRequest.ts b/src/Requests/RecaptchaV3ProxylessRequest.ts index 47f73ca..12d2a14 100644 --- a/src/Requests/RecaptchaV3ProxylessRequest.ts +++ b/src/Requests/RecaptchaV3ProxylessRequest.ts @@ -52,7 +52,7 @@ export class RecaptchaV3ProxylessRequest extends CaptchaRequestBase { constructor({ nocache, websiteURL, websiteKey, minScore, pageAction = 'verify', isEnterprise }: RecaptchaV3ProxylessRequestIn) { super({ type: TaskType.RecaptchaV3TaskProxyless, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.minScore = minScore; this.pageAction = pageAction; diff --git a/src/Requests/RequestsSerialization.u.spec.ts b/src/Requests/RequestsSerialization.u.spec.ts index b1c2974..2084854 100644 --- a/src/Requests/RequestsSerialization.u.spec.ts +++ b/src/Requests/RequestsSerialization.u.spec.ts @@ -18,8 +18,41 @@ import { AltchaRequest } from './AltchaRequest'; import { AlibabaRequest } from './AlibabaRequest'; import { FriendlyRequest } from './FriendlyRequest'; import { RecaptchaV3EnterpriseRequest } from './RecaptchaV3EnterpriseRequest'; +import { CommonCaptchaRequest } from './CommonCaptchaRequest'; describe('Check unit tests for SerializeObject()', () => { + it(`should serialize CommonCaptchaRequest`, () => { + const serialized = SerializeObject({ + clientKey: '', + task: new CommonCaptchaRequest({ + task: { + type: 'RecaptchaV2Task', + websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + }, + }), + }); + + expect(serialized).toMatchObject({ + clientKey: '', + task: { + type: 'RecaptchaV2Task', + websiteURL: 'https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high', + websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', + }, + }); + }); + + it(`should throw for invalid websiteURL`, () => { + expect( + () => + new RecaptchaV2Request({ + websiteURL: 'websiteURL', + websiteKey: 'websiteKey', + }), + ).toThrow('websiteURL must be a valid http or https URL'); + }); + it(`should serialize RecaptchaV2ProxylessRequest`, () => { const serialized = SerializeObject({ clientKey: '', @@ -572,7 +605,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new DataDomeRequest({ - websiteURL: 'site.com', + websiteURL: 'https://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: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', @@ -587,7 +620,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'DataDome', - websiteURL: 'site.com', + websiteURL: 'https://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: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', @@ -602,7 +635,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new DataDomeRequest({ - websiteURL: 'site.com', + websiteURL: 'https://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: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', @@ -623,7 +656,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'DataDome', - websiteURL: 'site.com', + websiteURL: 'https://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: { captchaUrl: 'https://geo.captcha-delivery.com/captcha/?initialCid=12434324', @@ -710,7 +743,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new AltchaRequest({ - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: 'websiteKey', 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: { @@ -727,7 +760,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'altcha', - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: 'websiteKey', 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: { @@ -744,7 +777,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new AltchaRequest({ - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: 'websiteKey', 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: { @@ -768,7 +801,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'altcha', - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: 'websiteKey', 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: { @@ -790,7 +823,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new TenDIRequest({ - websiteURL: 'site.com', + websiteURL: 'https://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', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', metadata: { @@ -804,7 +837,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'TenDI', - websiteURL: 'site.com', + websiteURL: 'https://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', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', metadata: { @@ -818,7 +851,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new TenDIRequest({ - websiteURL: 'site.com', + websiteURL: 'https://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', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', metadata: { @@ -839,7 +872,7 @@ describe('Check unit tests for SerializeObject()', () => { task: { type: 'CustomTask', class: 'TenDI', - websiteURL: 'site.com', + websiteURL: 'https://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', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', metadata: { @@ -858,7 +891,7 @@ describe('Check unit tests for SerializeObject()', () => { const serialized = SerializeObject({ clientKey: '', task: new AmazonRequest({ - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', 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', @@ -872,7 +905,7 @@ describe('Check unit tests for SerializeObject()', () => { clientKey: '', task: { type: 'AmazonTask', - websiteURL: 'site.com', + websiteURL: 'https://site.com', websiteKey: '6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd', 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', diff --git a/src/Requests/TSPDRequest/TSPDRequestBase.ts b/src/Requests/TSPDRequest/TSPDRequestBase.ts index f732941..a79e842 100644 --- a/src/Requests/TSPDRequest/TSPDRequestBase.ts +++ b/src/Requests/TSPDRequest/TSPDRequestBase.ts @@ -54,7 +54,7 @@ export abstract class TSPDRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: TSPDRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.userAgent = userAgent; this.metadata = metadata; this.class = _class; diff --git a/src/Requests/Task.ts b/src/Requests/Task.ts index 02dd683..b9ad1b4 100644 --- a/src/Requests/Task.ts +++ b/src/Requests/Task.ts @@ -26,6 +26,7 @@ import { HuntRequest } from './HuntRequest'; import { AlibabaRequest } from './AlibabaRequest'; import { FriendlyRequest } from './FriendlyRequest'; import { TSPDRequest } from './TSPDRequest'; +import { CommonCaptchaRequest } from './CommonCaptchaRequest'; /** * Universal type for recognition request @@ -58,4 +59,5 @@ export type Task = | TSPDRequest | HuntRequest | AlibabaRequest - | FriendlyRequest; + | FriendlyRequest + | CommonCaptchaRequest; diff --git a/src/Requests/TemuRequest/TemuRequestBase.ts b/src/Requests/TemuRequest/TemuRequestBase.ts index 04acf99..b0b2526 100644 --- a/src/Requests/TemuRequest/TemuRequestBase.ts +++ b/src/Requests/TemuRequest/TemuRequestBase.ts @@ -36,7 +36,7 @@ export abstract class TemuRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, metadata, _class }: TemuRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.metadata = metadata; this.userAgent = userAgent; this.class = _class; diff --git a/src/Requests/TenDIRequest/TenDIRequestBase.ts b/src/Requests/TenDIRequest/TenDIRequestBase.ts index c386ff6..0893f23 100644 --- a/src/Requests/TenDIRequest/TenDIRequestBase.ts +++ b/src/Requests/TenDIRequest/TenDIRequestBase.ts @@ -43,7 +43,7 @@ export abstract class TenDIRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, userAgent, websiteKey, metadata, _class }: TenDIRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.metadata = metadata; diff --git a/src/Requests/TurnstileRequest/TurnstileRequestBase.ts b/src/Requests/TurnstileRequest/TurnstileRequestBase.ts index 2fd1e18..8427811 100644 --- a/src/Requests/TurnstileRequest/TurnstileRequestBase.ts +++ b/src/Requests/TurnstileRequest/TurnstileRequestBase.ts @@ -21,7 +21,7 @@ export abstract class TurnstileRequestBase extends CaptchaRequestBase { constructor({ type, nocache, websiteURL, websiteKey }: TurnstileRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; } } diff --git a/src/Requests/YidunRequest/YuidunRequestBase.ts b/src/Requests/YidunRequest/YuidunRequestBase.ts index 973a5a7..78080b2 100644 --- a/src/Requests/YidunRequest/YuidunRequestBase.ts +++ b/src/Requests/YidunRequest/YuidunRequestBase.ts @@ -68,7 +68,7 @@ export abstract class YidunRequestBase extends CaptchaRequestBase { hct, }: YidunRequestBaseIn) { super({ type, nocache }); - this.websiteURL = websiteURL; + this.websiteURL = this.validateWebsiteURL(websiteURL); this.websiteKey = websiteKey; this.userAgent = userAgent; this.yidunGetLib = yidunGetLib; diff --git a/src/Responses/CommonCaptchaResponse.ts b/src/Responses/CommonCaptchaResponse.ts new file mode 100644 index 0000000..7790448 --- /dev/null +++ b/src/Responses/CommonCaptchaResponse.ts @@ -0,0 +1 @@ +export type CommonCaptchaResponse = Record; diff --git a/src/index.ts b/src/index.ts index 1daa19f..8b975e7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,6 +33,7 @@ import { HuntRequest, HuntRequestIn } from './Requests/HuntRequest'; import { AltchaRequest, AltchaRequestIn } from './Requests/AltchaRequest'; import { AlibabaRequest, AlibabaRequestIn } from './Requests/AlibabaRequest'; import { FriendlyRequest, FriendlyRequestIn } from './Requests/FriendlyRequest'; +import { CommonCaptcha, CommonCaptchaRequest, CommonCaptchaRequestIn, CommonCaptchaTask } from './Requests/CommonCaptchaRequest'; export default { CapMonsterCloudClientFactory, @@ -66,6 +67,8 @@ export default { AlibabaRequest, FriendlyRequest, RecaptchaV3EnterpriseRequest, + CommonCaptchaRequest, + CommonCaptcha, }; export { @@ -134,4 +137,8 @@ export { FriendlyRequestIn, RecaptchaV3EnterpriseRequest, RecaptchaV3EnterpriseRequestIn, + CommonCaptchaRequest, + CommonCaptcha, + CommonCaptchaRequestIn, + CommonCaptchaTask, }; diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 0000000..a29e338 --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "ES2020", + "moduleResolution": "node", + "outDir": "dist/esm", + "declaration": false + } +}