@nauth-toolkit/recaptcha 0.1.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/nestjs/index.d.ts +23 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +40 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +45 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/providers/recaptcha-enterprise.provider.d.ts +87 -0
- package/dist/src/providers/recaptcha-enterprise.provider.d.ts.map +1 -0
- package/dist/src/providers/recaptcha-enterprise.provider.js +116 -0
- package/dist/src/providers/recaptcha-enterprise.provider.js.map +1 -0
- package/dist/src/providers/recaptcha-v2.provider.d.ts +65 -0
- package/dist/src/providers/recaptcha-v2.provider.d.ts.map +1 -0
- package/dist/src/providers/recaptcha-v2.provider.js +96 -0
- package/dist/src/providers/recaptcha-v2.provider.js.map +1 -0
- package/dist/src/providers/recaptcha-v3.provider.d.ts +67 -0
- package/dist/src/providers/recaptcha-v3.provider.d.ts.map +1 -0
- package/dist/src/providers/recaptcha-v3.provider.js +98 -0
- package/dist/src/providers/recaptcha-v3.provider.js.map +1 -0
- package/dist/src/recaptcha-provider.interface.d.ts +82 -0
- package/dist/src/recaptcha-provider.interface.d.ts.map +1 -0
- package/dist/src/recaptcha-provider.interface.js +3 -0
- package/dist/src/recaptcha-provider.interface.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @nauth-toolkit/recaptcha
|
|
2
|
+
|
|
3
|
+
Google reCAPTCHA v2/v3/Enterprise provider for nauth-toolkit
|
|
4
|
+
|
|
5
|
+
## Preview Release Notice
|
|
6
|
+
|
|
7
|
+
**This is a preview release for internal testing. Do not use in production yet.**
|
|
8
|
+
|
|
9
|
+
This package is part of nauth-toolkit and is currently in early access/preview. Features and APIs may change between releases. For production use, please wait for the stable v1.0 release.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NestJS integration for @nauth-toolkit/recaptcha
|
|
3
|
+
*
|
|
4
|
+
* Currently this module simply re-exports the main package.
|
|
5
|
+
* Future versions may include NestJS-specific features such as:
|
|
6
|
+
* - Global module configuration
|
|
7
|
+
* - Dependency injection providers
|
|
8
|
+
* - Guard decorators
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { RecaptchaV3Provider } from '@nauth-toolkit/recaptcha/nestjs';
|
|
13
|
+
*
|
|
14
|
+
* // Use the same as main package for now
|
|
15
|
+
* const provider = new RecaptchaV3Provider({
|
|
16
|
+
* secretKey: process.env.RECAPTCHA_SECRET_KEY!,
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
export * from '../src/index';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* NestJS integration for @nauth-toolkit/recaptcha
|
|
4
|
+
*
|
|
5
|
+
* Currently this module simply re-exports the main package.
|
|
6
|
+
* Future versions may include NestJS-specific features such as:
|
|
7
|
+
* - Global module configuration
|
|
8
|
+
* - Dependency injection providers
|
|
9
|
+
* - Guard decorators
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { RecaptchaV3Provider } from '@nauth-toolkit/recaptcha/nestjs';
|
|
14
|
+
*
|
|
15
|
+
* // Use the same as main package for now
|
|
16
|
+
* const provider = new RecaptchaV3Provider({
|
|
17
|
+
* secretKey: process.env.RECAPTCHA_SECRET_KEY!,
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
26
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
27
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
28
|
+
}
|
|
29
|
+
Object.defineProperty(o, k2, desc);
|
|
30
|
+
}) : (function(o, m, k, k2) {
|
|
31
|
+
if (k2 === undefined) k2 = k;
|
|
32
|
+
o[k2] = m[k];
|
|
33
|
+
}));
|
|
34
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
35
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
// Re-export everything from main package
|
|
39
|
+
__exportStar(require("../src/index"), exports);
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;AAEH,yCAAyC;AACzC,+CAA6B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nauth-toolkit/recaptcha
|
|
3
|
+
*
|
|
4
|
+
* Google reCAPTCHA v2/v3/Enterprise support for nauth-toolkit.
|
|
5
|
+
*
|
|
6
|
+
* Provides bot protection for authentication endpoints via configurable
|
|
7
|
+
* reCAPTCHA verification. Supports all Google reCAPTCHA versions with
|
|
8
|
+
* platform-agnostic implementation.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { RecaptchaV3Provider } from '@nauth-toolkit/recaptcha';
|
|
13
|
+
*
|
|
14
|
+
* const provider = new RecaptchaV3Provider({
|
|
15
|
+
* secretKey: process.env.RECAPTCHA_SECRET_KEY!,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
export * from './recaptcha-provider.interface';
|
|
24
|
+
export * from './providers/recaptcha-v2.provider';
|
|
25
|
+
export * from './providers/recaptcha-v3.provider';
|
|
26
|
+
export * from './providers/recaptcha-enterprise.provider';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,cAAc,gCAAgC,CAAC;AAG/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @nauth-toolkit/recaptcha
|
|
4
|
+
*
|
|
5
|
+
* Google reCAPTCHA v2/v3/Enterprise support for nauth-toolkit.
|
|
6
|
+
*
|
|
7
|
+
* Provides bot protection for authentication endpoints via configurable
|
|
8
|
+
* reCAPTCHA verification. Supports all Google reCAPTCHA versions with
|
|
9
|
+
* platform-agnostic implementation.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { RecaptchaV3Provider } from '@nauth-toolkit/recaptcha';
|
|
14
|
+
*
|
|
15
|
+
* const provider = new RecaptchaV3Provider({
|
|
16
|
+
* secretKey: process.env.RECAPTCHA_SECRET_KEY!,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @packageDocumentation
|
|
23
|
+
*/
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
// Core interfaces
|
|
40
|
+
__exportStar(require("./recaptcha-provider.interface"), exports);
|
|
41
|
+
// Provider implementations
|
|
42
|
+
__exportStar(require("./providers/recaptcha-v2.provider"), exports);
|
|
43
|
+
__exportStar(require("./providers/recaptcha-v3.provider"), exports);
|
|
44
|
+
__exportStar(require("./providers/recaptcha-enterprise.provider"), exports);
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;;;;;;;;;;;;;;AAEH,kBAAkB;AAClB,iEAA+C;AAE/C,2BAA2B;AAC3B,oEAAkD;AAClD,oEAAkD;AAClD,4EAA0D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { RecaptchaProvider, RecaptchaVerificationResult } from '../recaptcha-provider.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for reCAPTCHA Enterprise provider
|
|
4
|
+
*/
|
|
5
|
+
export interface RecaptchaEnterpriseConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Project ID from Google Cloud Console
|
|
8
|
+
*/
|
|
9
|
+
projectId: string;
|
|
10
|
+
/**
|
|
11
|
+
* API key from Google Cloud Console
|
|
12
|
+
* Must have reCAPTCHA Enterprise API enabled
|
|
13
|
+
*/
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Site key from reCAPTCHA Enterprise admin console
|
|
17
|
+
*/
|
|
18
|
+
siteKey: string;
|
|
19
|
+
/**
|
|
20
|
+
* Custom API endpoint (optional)
|
|
21
|
+
* Useful for regional deployments
|
|
22
|
+
*
|
|
23
|
+
* @default 'https://recaptchaenterprise.googleapis.com/v1'
|
|
24
|
+
*/
|
|
25
|
+
apiEndpoint?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Request timeout in milliseconds
|
|
28
|
+
*
|
|
29
|
+
* @default 10000 (10 seconds)
|
|
30
|
+
*/
|
|
31
|
+
timeout?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Google reCAPTCHA Enterprise Provider
|
|
35
|
+
*
|
|
36
|
+
* Implements advanced bot detection with additional features:
|
|
37
|
+
* - Advanced fraud detection
|
|
38
|
+
* - Custom rules and actions
|
|
39
|
+
* - Detailed analytics and reporting
|
|
40
|
+
* - SLA guarantees
|
|
41
|
+
*
|
|
42
|
+
* Enterprise is recommended for:
|
|
43
|
+
* - High-traffic production applications
|
|
44
|
+
* - Advanced security requirements
|
|
45
|
+
* - Compliance and auditing needs
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const provider = new RecaptchaEnterpriseProvider({
|
|
50
|
+
* projectId: 'my-project',
|
|
51
|
+
* apiKey: process.env.RECAPTCHA_ENTERPRISE_API_KEY!,
|
|
52
|
+
* siteKey: process.env.RECAPTCHA_ENTERPRISE_SITE_KEY!,
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
56
|
+
*
|
|
57
|
+
* if (!result.success) {
|
|
58
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* if (result.score && result.score < 0.5) {
|
|
62
|
+
* // Additional fraud prevention logic
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare class RecaptchaEnterpriseProvider implements RecaptchaProvider {
|
|
67
|
+
private readonly projectId;
|
|
68
|
+
private readonly apiKey;
|
|
69
|
+
private readonly siteKey;
|
|
70
|
+
private readonly apiEndpoint;
|
|
71
|
+
private readonly timeout;
|
|
72
|
+
constructor(config: RecaptchaEnterpriseConfig);
|
|
73
|
+
/**
|
|
74
|
+
* Verify reCAPTCHA Enterprise token with Google's API
|
|
75
|
+
*
|
|
76
|
+
* Uses the reCAPTCHA Enterprise REST API for assessment creation.
|
|
77
|
+
*
|
|
78
|
+
* @param token - Token from client
|
|
79
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
80
|
+
* @param action - Action name used when generating token (e.g., 'login', 'signup')
|
|
81
|
+
* @returns Verification result with score and risk analysis
|
|
82
|
+
*
|
|
83
|
+
* @throws Error if network request fails or times out
|
|
84
|
+
*/
|
|
85
|
+
verify(token: string, remoteIp?: string, action?: string): Promise<RecaptchaVerificationResult>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=recaptcha-enterprise.provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-enterprise.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/recaptcha-enterprise.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAEjG;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,2BAA4B,YAAW,iBAAiB;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,yBAAyB;IAQ7C;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC;CA2DtG"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecaptchaEnterpriseProvider = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Google reCAPTCHA Enterprise Provider
|
|
6
|
+
*
|
|
7
|
+
* Implements advanced bot detection with additional features:
|
|
8
|
+
* - Advanced fraud detection
|
|
9
|
+
* - Custom rules and actions
|
|
10
|
+
* - Detailed analytics and reporting
|
|
11
|
+
* - SLA guarantees
|
|
12
|
+
*
|
|
13
|
+
* Enterprise is recommended for:
|
|
14
|
+
* - High-traffic production applications
|
|
15
|
+
* - Advanced security requirements
|
|
16
|
+
* - Compliance and auditing needs
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const provider = new RecaptchaEnterpriseProvider({
|
|
21
|
+
* projectId: 'my-project',
|
|
22
|
+
* apiKey: process.env.RECAPTCHA_ENTERPRISE_API_KEY!,
|
|
23
|
+
* siteKey: process.env.RECAPTCHA_ENTERPRISE_SITE_KEY!,
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
27
|
+
*
|
|
28
|
+
* if (!result.success) {
|
|
29
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* if (result.score && result.score < 0.5) {
|
|
33
|
+
* // Additional fraud prevention logic
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
class RecaptchaEnterpriseProvider {
|
|
38
|
+
projectId;
|
|
39
|
+
apiKey;
|
|
40
|
+
siteKey;
|
|
41
|
+
apiEndpoint;
|
|
42
|
+
timeout;
|
|
43
|
+
constructor(config) {
|
|
44
|
+
this.projectId = config.projectId;
|
|
45
|
+
this.apiKey = config.apiKey;
|
|
46
|
+
this.siteKey = config.siteKey;
|
|
47
|
+
this.apiEndpoint = config.apiEndpoint || 'https://recaptchaenterprise.googleapis.com/v1';
|
|
48
|
+
this.timeout = config.timeout || 10000;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Verify reCAPTCHA Enterprise token with Google's API
|
|
52
|
+
*
|
|
53
|
+
* Uses the reCAPTCHA Enterprise REST API for assessment creation.
|
|
54
|
+
*
|
|
55
|
+
* @param token - Token from client
|
|
56
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
57
|
+
* @param action - Action name used when generating token (e.g., 'login', 'signup')
|
|
58
|
+
* @returns Verification result with score and risk analysis
|
|
59
|
+
*
|
|
60
|
+
* @throws Error if network request fails or times out
|
|
61
|
+
*/
|
|
62
|
+
async verify(token, remoteIp, action) {
|
|
63
|
+
// Build assessment request
|
|
64
|
+
const assessmentUrl = `${this.apiEndpoint}/projects/${this.projectId}/assessments?key=${this.apiKey}`;
|
|
65
|
+
const requestBody = {
|
|
66
|
+
event: {
|
|
67
|
+
token,
|
|
68
|
+
siteKey: this.siteKey,
|
|
69
|
+
...(action && { expectedAction: action }),
|
|
70
|
+
...(remoteIp && { userIpAddress: remoteIp }),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
// Create abort controller for timeout
|
|
75
|
+
const controller = new AbortController();
|
|
76
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
77
|
+
// Make request to Google's Enterprise API
|
|
78
|
+
const response = await fetch(assessmentUrl, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
},
|
|
83
|
+
body: JSON.stringify(requestBody),
|
|
84
|
+
signal: controller.signal,
|
|
85
|
+
});
|
|
86
|
+
clearTimeout(timeoutId);
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
throw new Error(`reCAPTCHA Enterprise API returned status ${response.status}`);
|
|
89
|
+
}
|
|
90
|
+
const data = await response.json();
|
|
91
|
+
// Extract token properties from assessment
|
|
92
|
+
const tokenProperties = data.tokenProperties || {};
|
|
93
|
+
const riskAnalysis = data.riskAnalysis || {};
|
|
94
|
+
// Map Enterprise response to our interface
|
|
95
|
+
return {
|
|
96
|
+
success: tokenProperties.valid === true,
|
|
97
|
+
score: riskAnalysis.score,
|
|
98
|
+
action: tokenProperties.action,
|
|
99
|
+
hostname: tokenProperties.hostname,
|
|
100
|
+
errorCodes: tokenProperties.invalidReason ? [tokenProperties.invalidReason] : undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
// Handle network errors
|
|
105
|
+
if (error instanceof Error) {
|
|
106
|
+
if (error.name === 'AbortError') {
|
|
107
|
+
throw new Error(`reCAPTCHA Enterprise verification timeout after ${this.timeout}ms`);
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`reCAPTCHA Enterprise verification failed: ${error.message}`);
|
|
110
|
+
}
|
|
111
|
+
throw new Error('reCAPTCHA Enterprise verification failed with unknown error');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.RecaptchaEnterpriseProvider = RecaptchaEnterpriseProvider;
|
|
116
|
+
//# sourceMappingURL=recaptcha-enterprise.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-enterprise.provider.js","sourceRoot":"","sources":["../../../src/providers/recaptcha-enterprise.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RecaptchaProvider, RecaptchaVerificationResult } from '../recaptcha-provider.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for reCAPTCHA v2 provider
|
|
4
|
+
*/
|
|
5
|
+
export interface RecaptchaV2Config {
|
|
6
|
+
/**
|
|
7
|
+
* Secret key from Google reCAPTCHA admin console
|
|
8
|
+
*/
|
|
9
|
+
secretKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Custom verification endpoint (optional)
|
|
12
|
+
* Useful for enterprise deployments or proxies
|
|
13
|
+
*
|
|
14
|
+
* @default 'https://www.google.com/recaptcha/api/siteverify'
|
|
15
|
+
*/
|
|
16
|
+
verifyUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Request timeout in milliseconds
|
|
19
|
+
*
|
|
20
|
+
* @default 10000 (10 seconds)
|
|
21
|
+
*/
|
|
22
|
+
timeout?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Google reCAPTCHA v2 Provider
|
|
26
|
+
*
|
|
27
|
+
* Implements checkbox-based CAPTCHA requiring user interaction.
|
|
28
|
+
* Returns simple success/fail without scoring.
|
|
29
|
+
*
|
|
30
|
+
* v2 is useful when:
|
|
31
|
+
* - You need explicit user verification
|
|
32
|
+
* - Mobile WebView environments where v3 scoring is unreliable
|
|
33
|
+
* - Regulatory requirements mandate visible challenges
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const provider = new RecaptchaV2Provider({
|
|
38
|
+
* secretKey: process.env.RECAPTCHA_V2_SECRET_KEY!,
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* const result = await provider.verify(token, clientIp);
|
|
42
|
+
*
|
|
43
|
+
* if (!result.success) {
|
|
44
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class RecaptchaV2Provider implements RecaptchaProvider {
|
|
49
|
+
private readonly secretKey;
|
|
50
|
+
private readonly verifyUrl;
|
|
51
|
+
private readonly timeout;
|
|
52
|
+
constructor(config: RecaptchaV2Config);
|
|
53
|
+
/**
|
|
54
|
+
* Verify reCAPTCHA v2 token with Google's API
|
|
55
|
+
*
|
|
56
|
+
* @param token - Token from client (obtained from checkbox widget)
|
|
57
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
58
|
+
* @param action - Not used for v2 (only for v3/Enterprise)
|
|
59
|
+
* @returns Verification result (no score for v2)
|
|
60
|
+
*
|
|
61
|
+
* @throws Error if network request fails or times out
|
|
62
|
+
*/
|
|
63
|
+
verify(token: string, remoteIp?: string, _action?: string): Promise<RecaptchaVerificationResult>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=recaptcha-v2.provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-v2.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/recaptcha-v2.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAEjG;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,iBAAiB;IAMrC;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC;CAqDvG"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecaptchaV2Provider = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Google reCAPTCHA v2 Provider
|
|
6
|
+
*
|
|
7
|
+
* Implements checkbox-based CAPTCHA requiring user interaction.
|
|
8
|
+
* Returns simple success/fail without scoring.
|
|
9
|
+
*
|
|
10
|
+
* v2 is useful when:
|
|
11
|
+
* - You need explicit user verification
|
|
12
|
+
* - Mobile WebView environments where v3 scoring is unreliable
|
|
13
|
+
* - Regulatory requirements mandate visible challenges
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const provider = new RecaptchaV2Provider({
|
|
18
|
+
* secretKey: process.env.RECAPTCHA_V2_SECRET_KEY!,
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* const result = await provider.verify(token, clientIp);
|
|
22
|
+
*
|
|
23
|
+
* if (!result.success) {
|
|
24
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
class RecaptchaV2Provider {
|
|
29
|
+
secretKey;
|
|
30
|
+
verifyUrl;
|
|
31
|
+
timeout;
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.secretKey = config.secretKey;
|
|
34
|
+
this.verifyUrl = config.verifyUrl || 'https://www.google.com/recaptcha/api/siteverify';
|
|
35
|
+
this.timeout = config.timeout || 10000;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Verify reCAPTCHA v2 token with Google's API
|
|
39
|
+
*
|
|
40
|
+
* @param token - Token from client (obtained from checkbox widget)
|
|
41
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
42
|
+
* @param action - Not used for v2 (only for v3/Enterprise)
|
|
43
|
+
* @returns Verification result (no score for v2)
|
|
44
|
+
*
|
|
45
|
+
* @throws Error if network request fails or times out
|
|
46
|
+
*/
|
|
47
|
+
async verify(token, remoteIp, _action) {
|
|
48
|
+
// Build request body
|
|
49
|
+
const params = new URLSearchParams({
|
|
50
|
+
secret: this.secretKey,
|
|
51
|
+
response: token,
|
|
52
|
+
});
|
|
53
|
+
if (remoteIp) {
|
|
54
|
+
params.append('remoteip', remoteIp);
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
// Create abort controller for timeout
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
60
|
+
// Make request to Google's API
|
|
61
|
+
const response = await fetch(this.verifyUrl, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: {
|
|
64
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
65
|
+
},
|
|
66
|
+
body: params.toString(),
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
});
|
|
69
|
+
clearTimeout(timeoutId);
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
throw new Error(`reCAPTCHA API returned status ${response.status}`);
|
|
72
|
+
}
|
|
73
|
+
const data = await response.json();
|
|
74
|
+
// Map Google's response to our interface
|
|
75
|
+
// v2 does not include score or action
|
|
76
|
+
return {
|
|
77
|
+
success: data.success === true,
|
|
78
|
+
challengeTs: data.challenge_ts,
|
|
79
|
+
hostname: data.hostname,
|
|
80
|
+
errorCodes: data['error-codes'],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
// Handle network errors
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
if (error.name === 'AbortError') {
|
|
87
|
+
throw new Error(`reCAPTCHA verification timeout after ${this.timeout}ms`);
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`reCAPTCHA verification failed: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
throw new Error('reCAPTCHA verification failed with unknown error');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.RecaptchaV2Provider = RecaptchaV2Provider;
|
|
96
|
+
//# sourceMappingURL=recaptcha-v2.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-v2.provider.js","sourceRoot":"","sources":["../../../src/providers/recaptcha-v2.provider.ts"],"names":[],"mappings":";;;AA2BA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAa,mBAAmB;IACb,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,OAAO,CAAS;IAEjC,YAAY,MAAyB;QACnC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,iDAAiD,CAAC;QACvF,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,QAAiB,EAAE,OAAgB;QAC7D,qBAAqB;QACrB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,MAAM,EAAE,IAAI,CAAC,SAAS;YACtB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QAEH,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC;YACH,sCAAsC;YACtC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAErE,+BAA+B;YAC/B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE;gBAC3C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;iBACpD;gBACD,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;gBACvB,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,YAAY,CAAC,SAAS,CAAC,CAAC;YAExB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACtE,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAEnC,yCAAyC;YACzC,sCAAsC;YACtC,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,IAAI;gBAC9B,WAAW,EAAE,IAAI,CAAC,YAAY;gBAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;aAChC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,wBAAwB;YACxB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;gBAC5E,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF;AA1ED,kDA0EC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RecaptchaProvider, RecaptchaVerificationResult } from '../recaptcha-provider.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for reCAPTCHA v3 provider
|
|
4
|
+
*/
|
|
5
|
+
export interface RecaptchaV3Config {
|
|
6
|
+
/**
|
|
7
|
+
* Secret key from Google reCAPTCHA admin console
|
|
8
|
+
*/
|
|
9
|
+
secretKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Custom verification endpoint (optional)
|
|
12
|
+
* Useful for enterprise deployments or proxies
|
|
13
|
+
*
|
|
14
|
+
* @default 'https://www.google.com/recaptcha/api/siteverify'
|
|
15
|
+
*/
|
|
16
|
+
verifyUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Request timeout in milliseconds
|
|
19
|
+
*
|
|
20
|
+
* @default 10000 (10 seconds)
|
|
21
|
+
*/
|
|
22
|
+
timeout?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Google reCAPTCHA v3 Provider
|
|
26
|
+
*
|
|
27
|
+
* Implements invisible, score-based bot detection without user interaction.
|
|
28
|
+
* Returns a risk score (0.0 - 1.0) indicating likelihood of bot activity.
|
|
29
|
+
*
|
|
30
|
+
* v3 is recommended for most web applications as it provides better UX
|
|
31
|
+
* by not requiring user interaction while still detecting bots effectively.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const provider = new RecaptchaV3Provider({
|
|
36
|
+
* secretKey: process.env.RECAPTCHA_SECRET_KEY!,
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
40
|
+
*
|
|
41
|
+
* if (!result.success) {
|
|
42
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* if (result.score && result.score < 0.5) {
|
|
46
|
+
* throw new Error('Suspicious activity detected');
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class RecaptchaV3Provider implements RecaptchaProvider {
|
|
51
|
+
private readonly secretKey;
|
|
52
|
+
private readonly verifyUrl;
|
|
53
|
+
private readonly timeout;
|
|
54
|
+
constructor(config: RecaptchaV3Config);
|
|
55
|
+
/**
|
|
56
|
+
* Verify reCAPTCHA v3 token with Google's API
|
|
57
|
+
*
|
|
58
|
+
* @param token - Token from client
|
|
59
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
60
|
+
* @param action - Action name used when generating token (e.g., 'login', 'signup')
|
|
61
|
+
* @returns Verification result with score
|
|
62
|
+
*
|
|
63
|
+
* @throws Error if network request fails or times out
|
|
64
|
+
*/
|
|
65
|
+
verify(token: string, remoteIp?: string, _action?: string): Promise<RecaptchaVerificationResult>;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=recaptcha-v3.provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-v3.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/recaptcha-v3.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAEjG;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,iBAAiB;IAMrC;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC;CAqDvG"}
|