waf-captcha-frontend 0.0.5
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 +283 -0
- package/dist/bundle.cjs.js +2 -0
- package/dist/bundle.cjs.js.map +1 -0
- package/dist/bundle.esm.js +2 -0
- package/dist/bundle.esm.js.map +1 -0
- package/dist/createCaptchaFetchHandler.d.ts +2 -0
- package/dist/index.d.ts +41 -0
- package/dist/types.d.ts +44 -0
- package/dist/utils/WAFScriptUtils.d.ts +4 -0
- package/dist/utils/modalUtils.d.ts +7 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# AWS WAF Captcha Interceptor
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
AWS WAF Captcha Interceptor is a lightweight JavaScript/TypeScript library that provides seamless integration with AWS WAF Captcha for fetch-based HTTP requests. The package handles captcha challenges transparently, intercepting requests and displaying captcha modals when required by AWS WAF.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install aws-waf-captcha-interceptor
|
|
11
|
+
# or
|
|
12
|
+
yarn add aws-waf-captcha-interceptor
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
Before using this package, ensure you have AWS WAF configured with CAPTCHA rules
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
|
|
23
|
+
|
|
24
|
+
// Initialize the interceptor
|
|
25
|
+
const captchaFetch = createCaptchaInterceptor({
|
|
26
|
+
API_KEY: 'your-api-key',
|
|
27
|
+
JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
|
|
28
|
+
captchaContainerId: 'captcha-container',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Use it like regular fetch
|
|
32
|
+
const response = await captchaFetch('/api/protected-endpoint', {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/json',
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify({ data: 'example' }),
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
The package accepts the following configuration object:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
export interface AWSWAFInterceptorConfig {
|
|
47
|
+
// Required: API credentials
|
|
48
|
+
API_KEY: string;
|
|
49
|
+
JSAPI_URL: string;
|
|
50
|
+
|
|
51
|
+
// Event handlers
|
|
52
|
+
onSuccess?: () => void;
|
|
53
|
+
onLoad?: () => void;
|
|
54
|
+
onError?: (err: string) => void;
|
|
55
|
+
onPuzzleTimeout?: () => void;
|
|
56
|
+
onPuzzleIncorrect?: () => void;
|
|
57
|
+
onPuzzleCorrect?: () => void;
|
|
58
|
+
|
|
59
|
+
// Container IDs for DOM injection
|
|
60
|
+
captchaContainerId: string; // Main container for captcha modal
|
|
61
|
+
captchaContentId?: string; // Container for captcha form
|
|
62
|
+
overlayId?: string; // Overlay element ID
|
|
63
|
+
modalId?: string; // Modal container ID
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Default Values
|
|
68
|
+
|
|
69
|
+
If containers IDs not provided, the package will use these default IDs:
|
|
70
|
+
- `captchaContentId`: `'captcha-content'`
|
|
71
|
+
- `overlayId`: `'captcha-overlay'`
|
|
72
|
+
- `modalId`: `'captcha-modal'`
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
### Basic Implementation
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
|
|
80
|
+
|
|
81
|
+
const config = {
|
|
82
|
+
API_KEY: 'your-api-key',
|
|
83
|
+
JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
|
|
84
|
+
captchaContainerId: 'aws-captcha-container',
|
|
85
|
+
|
|
86
|
+
// Optional event handlers
|
|
87
|
+
onSuccess: () => console.log('Captcha solved successfully'),
|
|
88
|
+
onError: (err) => console.error('Captcha error:', err),
|
|
89
|
+
onPuzzleTimeout: () => console.error('Captcha puzzle timed out'),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const captchaFetch = createCaptchaInterceptor(config);
|
|
93
|
+
|
|
94
|
+
// Make authenticated requests
|
|
95
|
+
async function fetchProtectedData() {
|
|
96
|
+
try {
|
|
97
|
+
const data = await captchaFetch('/api/data', {
|
|
98
|
+
method: 'GET',
|
|
99
|
+
credentials: 'include',
|
|
100
|
+
});
|
|
101
|
+
return data;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('Request failed:', error);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### React Example
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import React, { useEffect } from 'react';
|
|
113
|
+
import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
|
|
114
|
+
|
|
115
|
+
const App = () => {
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
// Initialize once when component mounts
|
|
118
|
+
const captchaFetch = createCaptchaInterceptor({
|
|
119
|
+
API_KEY: 'your-aws-api-key',
|
|
120
|
+
JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
|
|
121
|
+
captchaContainerId: 'captcha-root',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Store in context or make globally available
|
|
125
|
+
window.captchaFetch = captchaFetch;
|
|
126
|
+
}, []);
|
|
127
|
+
|
|
128
|
+
const handleSubmit = async () => {
|
|
129
|
+
try {
|
|
130
|
+
const response = await window.captchaFetch('/api/submit', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
body: JSON.stringify({ formData: 'test' }),
|
|
133
|
+
});
|
|
134
|
+
console.log('Success:', response);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('Failed:', error);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div>
|
|
142
|
+
{/* Container for captcha - must exist in DOM */}
|
|
143
|
+
<div id="captcha-root" />
|
|
144
|
+
<button onClick={handleSubmit}>Submit</button>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Advanced Configuration with All Options
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const advancedConfig = {
|
|
154
|
+
API_KEY: 'your-aws-api-key',
|
|
155
|
+
JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
|
|
156
|
+
|
|
157
|
+
// Custom container IDs
|
|
158
|
+
captchaContainerId: 'captcha-root-container',
|
|
159
|
+
captchaContentId: 'custom-captcha-content',
|
|
160
|
+
overlayId: 'custom-overlay',
|
|
161
|
+
modalId: 'custom-modal',
|
|
162
|
+
|
|
163
|
+
// Event handlers
|
|
164
|
+
onLoad: () => {
|
|
165
|
+
console.log('Captcha library loaded');
|
|
166
|
+
},
|
|
167
|
+
onSuccess: () => {
|
|
168
|
+
console.log('Captcha verification successful');
|
|
169
|
+
},
|
|
170
|
+
onError: (errorMessage) => {
|
|
171
|
+
console.error('Captcha error:', errorMessage);
|
|
172
|
+
},
|
|
173
|
+
onPuzzleTimeout: () => {
|
|
174
|
+
console.warn('User took too long to solve captcha');
|
|
175
|
+
},
|
|
176
|
+
onPuzzleIncorrect: () => {
|
|
177
|
+
console.log('Incorrect captcha solution');
|
|
178
|
+
},
|
|
179
|
+
onPuzzleCorrect: () => {
|
|
180
|
+
console.log('Captcha solved correctly');
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const captchaFetch = createCaptchaInterceptor(advancedConfig);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## API Reference
|
|
188
|
+
|
|
189
|
+
### `createCaptchaInterceptor(config: AWSWAFInterceptorConfig)`
|
|
190
|
+
|
|
191
|
+
Creates and returns a fetch wrapper function that automatically handles AWS WAF captcha challenges.
|
|
192
|
+
|
|
193
|
+
**Parameters:**
|
|
194
|
+
- `config`: Configuration object as defined in `AWSWAFInterceptorConfig`
|
|
195
|
+
|
|
196
|
+
**Returns:**
|
|
197
|
+
- A function with the same signature as `fetch()`, but with automatic captcha handling.
|
|
198
|
+
|
|
199
|
+
### The Wrapped Fetch Function
|
|
200
|
+
|
|
201
|
+
The returned function has the following signature:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
It behaves exactly like the native `fetch` API, but will automatically:
|
|
208
|
+
1. Detect when AWS WAF requires a captcha challenge
|
|
209
|
+
2. Display the captcha modal when needed
|
|
210
|
+
3. Retry the original request after successful captcha completion
|
|
211
|
+
4. Pass through all response data transparently
|
|
212
|
+
|
|
213
|
+
## How It Works
|
|
214
|
+
|
|
215
|
+
1. **Initialization**: The interceptor is created with your AWS WAF configuration
|
|
216
|
+
2. **Request Interception**: When you make a fetch request, the interceptor checks if AWS WAF returns a captcha challenge
|
|
217
|
+
3. **Modal Display**: If a captcha is required, a modal is automatically injected into your specified container
|
|
218
|
+
4. **User Interaction**: Users solve the captcha puzzle in the modal
|
|
219
|
+
5. **Request Retry**: After successful captcha completion, the original request is retried with the captcha token
|
|
220
|
+
6. **Transparent Response**: You receive the API response as if no captcha interruption occurred
|
|
221
|
+
|
|
222
|
+
For more details check the WAF documentation: https://aws.amazon.com/ru/blogs/networking-and-content-delivery/optimizing-web-application-user-experiences-with-aws-waf-javascript-integrations/. Now realized only the Scenario 5.
|
|
223
|
+
|
|
224
|
+
## Error Handling
|
|
225
|
+
|
|
226
|
+
The interceptor will throw errors in these cases:
|
|
227
|
+
- AWS WAF configuration is incorrect
|
|
228
|
+
- Captcha cannot be displayed (missing container, etc.)
|
|
229
|
+
- User fails to solve captcha within allowed attempts
|
|
230
|
+
- Network errors during the request
|
|
231
|
+
|
|
232
|
+
## DOM Requirements
|
|
233
|
+
|
|
234
|
+
The package requires certain DOM elements to exist or will create them automatically:
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<!-- The container you specify in config must exist -->
|
|
238
|
+
<div id="your-captcha-container-id">
|
|
239
|
+
<!-- The following elements will be created automatically if not present -->
|
|
240
|
+
<!-- <div id="captcha-overlay"> -->
|
|
241
|
+
<!-- <div id="captcha-modal"> -->
|
|
242
|
+
<!-- <div id="captcha-content"></div> -->
|
|
243
|
+
<!-- </div> -->
|
|
244
|
+
<!-- </div> -->
|
|
245
|
+
</div>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## TypeScript Support
|
|
249
|
+
|
|
250
|
+
The package includes full TypeScript definitions. No additional `@types` package is required.
|
|
251
|
+
|
|
252
|
+
## Development
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# Clone the repository
|
|
256
|
+
git clone https://github.com/your-org/aws-waf-captcha-interceptor.git
|
|
257
|
+
|
|
258
|
+
# Install dependencies
|
|
259
|
+
npm install
|
|
260
|
+
|
|
261
|
+
# Build the project
|
|
262
|
+
npm run build
|
|
263
|
+
|
|
264
|
+
# Run tests
|
|
265
|
+
npm test
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Future Roadmap
|
|
269
|
+
|
|
270
|
+
- [ ] Axios interceptor support
|
|
271
|
+
- [ ] Additional WAF captcha scenarios
|
|
272
|
+
- [ ] Custom UI theming options
|
|
273
|
+
|
|
274
|
+
## Security
|
|
275
|
+
|
|
276
|
+
This package handles sensitive operations. Ensure you:
|
|
277
|
+
- Keep your API keys secure
|
|
278
|
+
- Use HTTPS for all requests
|
|
279
|
+
- Follow AWS WAF security best practices
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
**Note**: This package currently only supports fetch-based requests. Axios support is planned for future releases.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const n=(n,e="captchaForm")=>{var t;let o=document.getElementById(e);const l=null!==(t=document.getElementById(n))&&void 0!==t?t:document.body;return o||(o=document.createElement("div"),o.id=e,l.appendChild(o)),o},e=(e,t,o,l)=>{const{overlay:a,modal:d}=((n,e="modalOverlay",t="modal")=>{var o;const l=null!==(o=document.getElementById(n))&&void 0!==o?o:document.body;let a=document.getElementById(e),d=document.getElementById(t);return a||(a=document.createElement("div"),a.id="modalOverlay",a.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n display: none;\n z-index: 9999;\n align-items: center;\n justify-content: center;\n ",l.appendChild(a)),d||(d=document.createElement("div"),d.id="modal",d.style.cssText="\n background: white;\n padding: 20px;\n border-radius: 8px;\n min-width: 300px;\n ",a.appendChild(d)),{overlay:a,modal:d}})(e,o,l),r=n(e,t);r.parentElement!==d&&d.appendChild(r),a.style.display="flex"},t="AwsWAFScript";exports.createCaptchaFetchHandler=o=>{!function(n){if(!n.API_KEY)throw new Error("API_KEY is not set");if(!n.JSAPI_URL)throw new Error("JSAPI_URL is not set");if(!n.captchaContainerId)throw new Error("the captcha container Id is not set")}(o),function(n){if(document.getElementById(t)||!n)return;const e=document.createElement("script");e.id=t,e.async=!1,e.src=n,document.head.appendChild(e)}(o.JSAPI_URL);return(t,l)=>{const a=n(o.captchaContainerId,null==o?void 0:o.captchaContentId);return e(o.captchaContainerId,null==o?void 0:o.captchaContentId,null==o?void 0:o.overlayId,null==o?void 0:o.modalId),new Promise((n,e)=>{window.AwsWafCaptcha?window.AwsWafIntegration?window.AwsWafCaptcha.renderCaptcha(a,{onSuccess:()=>{var e;((n="modalOverlay")=>{const e=document.getElementById(n);e&&(e.style.display="none")})(null==o?void 0:o.overlayId),null===(e=null==o?void 0:o.onSuccess)||void 0===e||e.call(o),n(window.AwsWafIntegration.fetch(t,l))},onLoad:()=>{var n;null===(n=null==o?void 0:o.onLoad)||void 0===n||n.call(o)},onError:n=>{var t;null===(t=null==o?void 0:o.onError)||void 0===t||t.call(o,n),e(n)},onPuzzleTimeout:()=>{var n;null===(n=null==o?void 0:o.onError)||void 0===n||n.call(o,"CAPTCHA timeout"),e(new Error("CAPTCHA timeout"))},onPuzzleIncorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleIncorrect)||void 0===n||n.call(o)},onPuzzleCorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleCorrect)||void 0===n||n.call(o)},apiKey:o.API_KEY}):e(new Error("AwsWafIntegration is not available")):e(new Error("AwsWafCaptcha is not available"))})}};
|
|
2
|
+
//# sourceMappingURL=bundle.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.cjs.js","sources":["../src/utils/modalUtils.ts","../src/utils/WAFScriptUtils.ts","../src/createCaptchaFetchHandler.ts"],"sourcesContent":[null,null,null],"names":["ensureCaptchaContainer","captchaContainerId","captchaContentId","container","document","getElementById","captchaContainer","_a","body","createElement","id","appendChild","showCaptchaModal","overlayId","modalId","overlay","modal","style","cssText","ensureModalContainer","captchaForm","parentElement","display","WAF_SCRIPT_ID","config","API_KEY","Error","JSAPI_URL","checkWAFconfig","AwsWafScript","async","src","head","loadCaptchaScript","path","init","Promise","resolve","reject","window","AwsWafCaptcha","AwsWafIntegration","renderCaptcha","onSuccess","hideCaptchaModal","fetch","onLoad","onError","error","call","onPuzzleTimeout","onPuzzleIncorrect","onPuzzleCorrect","apiKey"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const n=(n,e="captchaForm")=>{var t;let o=document.getElementById(e);const l=null!==(t=document.getElementById(n))&&void 0!==t?t:document.body;return o||(o=document.createElement("div"),o.id=e,l.appendChild(o)),o},e=(e,t,o,l)=>{const{overlay:d,modal:a}=((n,e="modalOverlay",t="modal")=>{var o;const l=null!==(o=document.getElementById(n))&&void 0!==o?o:document.body;let d=document.getElementById(e),a=document.getElementById(t);return d||(d=document.createElement("div"),d.id="modalOverlay",d.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n display: none;\n z-index: 9999;\n align-items: center;\n justify-content: center;\n ",l.appendChild(d)),a||(a=document.createElement("div"),a.id="modal",a.style.cssText="\n background: white;\n padding: 20px;\n border-radius: 8px;\n min-width: 300px;\n ",d.appendChild(a)),{overlay:d,modal:a}})(e,o,l),r=n(e,t);r.parentElement!==a&&a.appendChild(r),d.style.display="flex"},t="AwsWAFScript";const o=o=>{!function(n){if(!n.API_KEY)throw new Error("API_KEY is not set");if(!n.JSAPI_URL)throw new Error("JSAPI_URL is not set");if(!n.captchaContainerId)throw new Error("the captcha container Id is not set")}(o),function(n){if(document.getElementById(t)||!n)return;const e=document.createElement("script");e.id=t,e.async=!1,e.src=n,document.head.appendChild(e)}(o.JSAPI_URL);return(t,l)=>{const d=n(o.captchaContainerId,null==o?void 0:o.captchaContentId);return e(o.captchaContainerId,null==o?void 0:o.captchaContentId,null==o?void 0:o.overlayId,null==o?void 0:o.modalId),new Promise((n,e)=>{window.AwsWafCaptcha?window.AwsWafIntegration?window.AwsWafCaptcha.renderCaptcha(d,{onSuccess:()=>{var e;((n="modalOverlay")=>{const e=document.getElementById(n);e&&(e.style.display="none")})(null==o?void 0:o.overlayId),null===(e=null==o?void 0:o.onSuccess)||void 0===e||e.call(o),n(window.AwsWafIntegration.fetch(t,l))},onLoad:()=>{var n;null===(n=null==o?void 0:o.onLoad)||void 0===n||n.call(o)},onError:n=>{var t;null===(t=null==o?void 0:o.onError)||void 0===t||t.call(o,n),e(n)},onPuzzleTimeout:()=>{var n;null===(n=null==o?void 0:o.onError)||void 0===n||n.call(o,"CAPTCHA timeout"),e(new Error("CAPTCHA timeout"))},onPuzzleIncorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleIncorrect)||void 0===n||n.call(o)},onPuzzleCorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleCorrect)||void 0===n||n.call(o)},apiKey:o.API_KEY}):e(new Error("AwsWafIntegration is not available")):e(new Error("AwsWafCaptcha is not available"))})}};export{o as createCaptchaFetchHandler};
|
|
2
|
+
//# sourceMappingURL=bundle.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.esm.js","sources":["../src/utils/modalUtils.ts","../src/utils/WAFScriptUtils.ts","../src/createCaptchaFetchHandler.ts"],"sourcesContent":[null,null,null],"names":["ensureCaptchaContainer","captchaContainerId","captchaContentId","container","document","getElementById","captchaContainer","_a","body","createElement","id","appendChild","showCaptchaModal","overlayId","modalId","overlay","modal","style","cssText","ensureModalContainer","captchaForm","parentElement","display","WAF_SCRIPT_ID","createCaptchaFetchHandler","config","API_KEY","Error","JSAPI_URL","checkWAFconfig","AwsWafScript","async","src","head","loadCaptchaScript","path","init","Promise","resolve","reject","window","AwsWafCaptcha","AwsWafIntegration","renderCaptcha","onSuccess","hideCaptchaModal","fetch","onLoad","onError","error","call","onPuzzleTimeout","onPuzzleIncorrect","onPuzzleCorrect","apiKey"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
interface AwsWafCaptchaConfig {
|
|
2
|
+
onSuccess: (wafToken: string) => void;
|
|
3
|
+
onLoad?: () => void;
|
|
4
|
+
onError?: (err: string) => void;
|
|
5
|
+
onPuzzleTimeout?: () => void;
|
|
6
|
+
onPuzzleIncorrect?: () => void;
|
|
7
|
+
onPuzzleCorrect?: () => void;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
}
|
|
10
|
+
interface AwsWafCaptcha {
|
|
11
|
+
renderCaptcha: (container: string | HTMLElement, config: AwsWafCaptchaConfig) => void;
|
|
12
|
+
}
|
|
13
|
+
interface AwsWafIntegration {
|
|
14
|
+
fetch: typeof fetch;
|
|
15
|
+
hasToken: () => boolean;
|
|
16
|
+
getToken: () => Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface Window {
|
|
20
|
+
AwsWafIntegration: AwsWafIntegration;
|
|
21
|
+
AwsWafCaptcha: AwsWafCaptcha;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
interface AWSWAFInterceptorConfig {
|
|
25
|
+
API_KEY: string;
|
|
26
|
+
JSAPI_URL: string;
|
|
27
|
+
onSuccess?: () => void;
|
|
28
|
+
onLoad?: () => void;
|
|
29
|
+
onError?: (err: string) => void;
|
|
30
|
+
onPuzzleTimeout?: () => void;
|
|
31
|
+
onPuzzleIncorrect?: () => void;
|
|
32
|
+
onPuzzleCorrect?: () => void;
|
|
33
|
+
captchaContainerId: string;
|
|
34
|
+
captchaContentId?: string;
|
|
35
|
+
overlayId?: string;
|
|
36
|
+
modalId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare const createCaptchaFetchHandler: (config: AWSWAFInterceptorConfig) => (path: RequestInfo | URL, init: RequestInit) => Promise<Response>;
|
|
40
|
+
|
|
41
|
+
export { createCaptchaFetchHandler };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface AwsWafCaptchaConfig {
|
|
2
|
+
onSuccess: (wafToken: string) => void;
|
|
3
|
+
onLoad?: () => void;
|
|
4
|
+
onError?: (err: string) => void;
|
|
5
|
+
onPuzzleTimeout?: () => void;
|
|
6
|
+
onPuzzleIncorrect?: () => void;
|
|
7
|
+
onPuzzleCorrect?: () => void;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AwsWafCaptcha {
|
|
11
|
+
renderCaptcha: (container: string | HTMLElement, config: AwsWafCaptchaConfig) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface AwsWafIntegration {
|
|
14
|
+
fetch: typeof fetch;
|
|
15
|
+
hasToken: () => boolean;
|
|
16
|
+
getToken: () => Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface Window {
|
|
20
|
+
AwsWafIntegration: AwsWafIntegration;
|
|
21
|
+
AwsWafCaptcha: AwsWafCaptcha;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export interface CaptchaOptions {
|
|
25
|
+
apiKey: string;
|
|
26
|
+
captchaContentId: string;
|
|
27
|
+
onCaptchaRequired: () => void;
|
|
28
|
+
onSuccess: () => void;
|
|
29
|
+
onError: (error: string) => void;
|
|
30
|
+
}
|
|
31
|
+
export interface AWSWAFInterceptorConfig {
|
|
32
|
+
API_KEY: string;
|
|
33
|
+
JSAPI_URL: string;
|
|
34
|
+
onSuccess?: () => void;
|
|
35
|
+
onLoad?: () => void;
|
|
36
|
+
onError?: (err: string) => void;
|
|
37
|
+
onPuzzleTimeout?: () => void;
|
|
38
|
+
onPuzzleIncorrect?: () => void;
|
|
39
|
+
onPuzzleCorrect?: () => void;
|
|
40
|
+
captchaContainerId: string;
|
|
41
|
+
captchaContentId?: string;
|
|
42
|
+
overlayId?: string;
|
|
43
|
+
modalId?: string;
|
|
44
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const ensureCaptchaContainer: (captchaContainerId: string, captchaContentId?: string) => HTMLElement;
|
|
2
|
+
export declare const ensureModalContainer: (captchaContainerId: string, overlayId?: string, modalId?: string) => {
|
|
3
|
+
overlay: HTMLElement;
|
|
4
|
+
modal: HTMLElement;
|
|
5
|
+
};
|
|
6
|
+
export declare const showCaptchaModal: (captchaContainerId: string, captchaContentId?: string, overlayId?: string, modalId?: string) => void;
|
|
7
|
+
export declare const hideCaptchaModal: (overlayId?: string) => void;
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "waf-captcha-frontend",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "is a lightweight JavaScript/TypeScript library that provides seamless integration with AWS WAF Captcha for fetch-based HTTP requests. The package handles captcha challenges transparently, intercepting requests and displaying captcha modals when required by AWS WAF.",
|
|
5
|
+
"main": "dist/bundle.cjs.js",
|
|
6
|
+
"module": "dist/bundle.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
14
|
+
"build": "rollup -c",
|
|
15
|
+
"build:types": "tsc --emitDeclarationOnly"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
23
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
24
|
+
"rollup": "^4.55.1",
|
|
25
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
26
|
+
"tslib": "^2.8.1",
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|