@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
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecaptchaV3Provider = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Google reCAPTCHA v3 Provider
|
|
6
|
+
*
|
|
7
|
+
* Implements invisible, score-based bot detection without user interaction.
|
|
8
|
+
* Returns a risk score (0.0 - 1.0) indicating likelihood of bot activity.
|
|
9
|
+
*
|
|
10
|
+
* v3 is recommended for most web applications as it provides better UX
|
|
11
|
+
* by not requiring user interaction while still detecting bots effectively.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
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
|
+
* if (!result.success) {
|
|
22
|
+
* throw new Error('reCAPTCHA validation failed');
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* if (result.score && result.score < 0.5) {
|
|
26
|
+
* throw new Error('Suspicious activity detected');
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class RecaptchaV3Provider {
|
|
31
|
+
secretKey;
|
|
32
|
+
verifyUrl;
|
|
33
|
+
timeout;
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.secretKey = config.secretKey;
|
|
36
|
+
this.verifyUrl = config.verifyUrl || 'https://www.google.com/recaptcha/api/siteverify';
|
|
37
|
+
this.timeout = config.timeout || 10000;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Verify reCAPTCHA v3 token with Google's API
|
|
41
|
+
*
|
|
42
|
+
* @param token - Token from client
|
|
43
|
+
* @param remoteIp - Client IP address (optional but recommended)
|
|
44
|
+
* @param action - Action name used when generating token (e.g., 'login', 'signup')
|
|
45
|
+
* @returns Verification result with score
|
|
46
|
+
*
|
|
47
|
+
* @throws Error if network request fails or times out
|
|
48
|
+
*/
|
|
49
|
+
async verify(token, remoteIp, _action) {
|
|
50
|
+
// Build request body
|
|
51
|
+
const params = new URLSearchParams({
|
|
52
|
+
secret: this.secretKey,
|
|
53
|
+
response: token,
|
|
54
|
+
});
|
|
55
|
+
if (remoteIp) {
|
|
56
|
+
params.append('remoteip', remoteIp);
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Create abort controller for timeout
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
62
|
+
// Make request to Google's API
|
|
63
|
+
const response = await fetch(this.verifyUrl, {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers: {
|
|
66
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
67
|
+
},
|
|
68
|
+
body: params.toString(),
|
|
69
|
+
signal: controller.signal,
|
|
70
|
+
});
|
|
71
|
+
clearTimeout(timeoutId);
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`reCAPTCHA API returned status ${response.status}`);
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
// Map Google's response to our interface
|
|
77
|
+
return {
|
|
78
|
+
success: data.success === true,
|
|
79
|
+
score: data.score,
|
|
80
|
+
action: data.action,
|
|
81
|
+
hostname: data.hostname,
|
|
82
|
+
errorCodes: data['error-codes'],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Handle network errors
|
|
87
|
+
if (error instanceof Error) {
|
|
88
|
+
if (error.name === 'AbortError') {
|
|
89
|
+
throw new Error(`reCAPTCHA verification timeout after ${this.timeout}ms`);
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`reCAPTCHA verification failed: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
throw new Error('reCAPTCHA verification failed with unknown error');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.RecaptchaV3Provider = RecaptchaV3Provider;
|
|
98
|
+
//# sourceMappingURL=recaptcha-v3.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-v3.provider.js","sourceRoot":"","sources":["../../../src/providers/recaptcha-v3.provider.ts"],"names":[],"mappings":";;;AA2BA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;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,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,IAAI;gBAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,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,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google reCAPTCHA provider interface
|
|
3
|
+
*
|
|
4
|
+
* Supports v2, v3, and Enterprise versions of Google reCAPTCHA.
|
|
5
|
+
* Implementations should handle token verification with Google's API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const provider = new RecaptchaV3Provider({ secretKey: 'your-secret' });
|
|
10
|
+
* const result = await provider.verify(token, clientIp, 'login');
|
|
11
|
+
* if (result.success) {
|
|
12
|
+
* console.log('Valid token');
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export interface RecaptchaProvider {
|
|
17
|
+
/**
|
|
18
|
+
* Verify reCAPTCHA token with Google's API
|
|
19
|
+
*
|
|
20
|
+
* @param token - Token from client (generated by Google reCAPTCHA)
|
|
21
|
+
* @param remoteIp - Client IP address (optional but recommended for security)
|
|
22
|
+
* @param action - Action name for v3/Enterprise (e.g., 'login', 'signup')
|
|
23
|
+
* @returns Verification result with score (v3/Enterprise) or success (v2)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const result = await provider.verify(
|
|
28
|
+
* 'token-from-client',
|
|
29
|
+
* '192.168.1.1',
|
|
30
|
+
* 'login'
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
verify(token: string, remoteIp?: string, action?: string): Promise<RecaptchaVerificationResult>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of reCAPTCHA token verification
|
|
38
|
+
*
|
|
39
|
+
* Different fields are populated depending on reCAPTCHA version:
|
|
40
|
+
* - v2: success, challengeTs, hostname
|
|
41
|
+
* - v3: success, score, action, hostname
|
|
42
|
+
* - Enterprise: success, score, action, hostname
|
|
43
|
+
*/
|
|
44
|
+
export interface RecaptchaVerificationResult {
|
|
45
|
+
/**
|
|
46
|
+
* Whether the token is valid
|
|
47
|
+
*/
|
|
48
|
+
success: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Risk score for v3/Enterprise (0.0 - 1.0)
|
|
51
|
+
*
|
|
52
|
+
* - 0.0: Very likely a bot
|
|
53
|
+
* - 1.0: Very likely a human
|
|
54
|
+
* - Not present for v2
|
|
55
|
+
*/
|
|
56
|
+
score?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Action name that was verified (v3/Enterprise only)
|
|
59
|
+
*/
|
|
60
|
+
action?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Timestamp of the challenge load (v2 only)
|
|
63
|
+
* ISO 8601 format
|
|
64
|
+
*/
|
|
65
|
+
challengeTs?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Hostname of the site where the reCAPTCHA was solved
|
|
68
|
+
*/
|
|
69
|
+
hostname?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Error codes returned by Google (if any)
|
|
72
|
+
*
|
|
73
|
+
* Common errors:
|
|
74
|
+
* - missing-input-secret: Secret key is missing
|
|
75
|
+
* - invalid-input-secret: Secret key is invalid
|
|
76
|
+
* - missing-input-response: Token is missing
|
|
77
|
+
* - invalid-input-response: Token is invalid or expired
|
|
78
|
+
* - timeout-or-duplicate: Token has been used or expired
|
|
79
|
+
*/
|
|
80
|
+
errorCodes?: string[];
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=recaptcha-provider.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-provider.interface.d.ts","sourceRoot":"","sources":["../../src/recaptcha-provider.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACjG;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recaptcha-provider.interface.js","sourceRoot":"","sources":["../../src/recaptcha-provider.interface.ts"],"names":[],"mappings":""}
|