@netacea/cloudfront 5.2.54 → 6.0.2

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.
@@ -0,0 +1,508 @@
1
+ import { CloudFrontRequestEvent, CloudFrontResultResponse, CloudFrontRequest, CloudFrontResponseEvent, CloudFrontResponse } from 'aws-lambda';
2
+
3
+ type KinesisMakeRequest = (args: {
4
+ headers: Record<string, string>;
5
+ method: 'POST' | 'GET';
6
+ host: string;
7
+ path: string;
8
+ body?: any;
9
+ }) => Promise<any>;
10
+ interface KinesisIngestWebLog {
11
+ apiKey: string;
12
+ }
13
+ interface KinesisIngestConfigArgs {
14
+ kinesisStreamName: string;
15
+ kinesisAccessKey?: string;
16
+ kinesisSecretKey?: string;
17
+ logBatchSize?: number;
18
+ maxLogAgeSeconds?: number;
19
+ }
20
+ interface KinesisIngestArgs extends KinesisIngestConfigArgs {
21
+ apiKey: string;
22
+ }
23
+ declare class KinesisIngest {
24
+ protected readonly kinesisStreamName: string;
25
+ protected readonly kinesisAccessKey?: string;
26
+ protected readonly kinesisSecretKey?: string;
27
+ protected readonly logBatchSize: number;
28
+ protected readonly maxLogAgeSeconds: number;
29
+ protected logCache: KinesisIngestWebLog[];
30
+ private intervalSet;
31
+ constructor({ kinesisStreamName, kinesisAccessKey, kinesisSecretKey, maxLogAgeSeconds, logBatchSize }: KinesisIngestArgs);
32
+ putToKinesis<MakeRequest extends KinesisMakeRequest>(makeRequest: MakeRequest): Promise<void>;
33
+ ingest<LogFormat extends KinesisIngestWebLog, MakeRequest extends KinesisMakeRequest>(log: LogFormat, makeRequest: MakeRequest): Promise<any>;
34
+ }
35
+
36
+ declare enum NetaceaIngestType {
37
+ /**
38
+ * ORIGIN Ingest mode; data to be ingested is set by headers, so it can be forwarded via a seperate mechanism
39
+ */
40
+ ORIGIN = "ORIGIN",
41
+ /**
42
+ * HTTP Ingest mode, this is the standard implementation
43
+ */
44
+ HTTP = "HTTP",
45
+ /**
46
+ * Ingest over Kinesis, Netacea will inform you if this is required
47
+ * and will provide you with kinesis credentials.
48
+ */
49
+ KINESIS = "KINESIS",
50
+ /**
51
+ * Data to be Ingest via some mechanism native to the host/CDN, e.g. log shipping.
52
+ */
53
+ NATIVE = "NATIVE"
54
+ }
55
+ declare enum NetaceaLogVersion {
56
+ /**
57
+ * Current style log version
58
+ */
59
+ V1 = "V1",
60
+ /**
61
+ * V2 Log format, should only be used if Netacea instructs
62
+ */
63
+ V2 = "V2"
64
+ }
65
+ declare enum NetaceaMitigationType {
66
+ /**
67
+ * Run Netacea with mitigation mode enabled.
68
+ * This will serve Captcha pages and Forbidden pages when instructed to do so
69
+ */
70
+ MITIGATE = "MITIGATE",
71
+ /**
72
+ * Run Netacea with Inject mode enabled.
73
+ * The end-user will only receive a cookie.
74
+ * The origin server will receive 3-4 headers,
75
+ *
76
+ * 'x-netacea-match' indicating what was matched (nothing(0), ua(1), ip(2), etc...)
77
+ *
78
+ * 'x-netacea-mitigate' indicating what action would've be taken (nothing (0), block(1), allow(2), etc...)
79
+ *
80
+ * 'x-netacea-captcha' indicating what captcha action would've been taken
81
+ *
82
+ * 'x-netacea-event-id' event id value that should be injected to the captcha
83
+ * page if using `@netacea/captchafeedback` module on the origin server
84
+ */
85
+ INJECT = "INJECT",
86
+ /**
87
+ * Run Netacea with Ingest only mode
88
+ * No cookies will be set for the end user.
89
+ * No mitigations will be applied.
90
+ *
91
+ * **It's recommended to start in this mode!**
92
+ */
93
+ INGEST = "INGEST"
94
+ }
95
+
96
+ interface MakeRequestArgs {
97
+ /**
98
+ * Hostname of the request. For example https://mitigations.netacea.net
99
+ */
100
+ host: string;
101
+ /**
102
+ * Path for the request, i.e captcha requests will be `/AtaVerifyCaptcha`
103
+ */
104
+ path: string;
105
+ /**
106
+ * Key value collection of the request headers
107
+ */
108
+ headers: Record<string, string>;
109
+ /**
110
+ * HTTP Method
111
+ */
112
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
113
+ /**
114
+ * Request body value
115
+ */
116
+ body?: string;
117
+ /**
118
+ * Request timeout value in ms
119
+ */
120
+ timeout?: number;
121
+ }
122
+ interface NetaceaBaseArgs {
123
+ /**
124
+ * Netacea APIKey
125
+ */
126
+ apiKey: string;
127
+ /**
128
+ * Netacea Secret Key
129
+ */
130
+ secretKey: string;
131
+ /**
132
+ * Google RECaptcha Site Key.
133
+ * This is used for providing your own captcha values without updating these in the Netacea console.
134
+ */
135
+ captchaSiteKey?: string;
136
+ /**
137
+ * Google RECaptcha Secret Key.
138
+ * This is used for providing your own captcha values without updating these in the Netacea console.
139
+ */
140
+ captchaSecretKey?: string;
141
+ /**
142
+ * Request timeout in ms
143
+ */
144
+ timeout?: number;
145
+ /**
146
+ * URL of the Netacea ingest service.
147
+ * DEFAULT: https://ingest.netacea.net
148
+ */
149
+ ingestServiceUrl?: string;
150
+ /**
151
+ * URL of the Netacea mitigation service.
152
+ * DEFAULT: https://mitigations.netacea.net
153
+ */
154
+ mitigationServiceUrl?: string;
155
+ /**
156
+ * Type of mitigation applied, see the `NetaceaMitigationType` ENUM
157
+ * - INGEST - Ingest only mode, no mitigations applied
158
+ * - MITIGATION - Mitigation mode, active blocking/captcha rules will be applied.
159
+ * - INJECT - Inject mode, headers will be sent to your origin server
160
+ * indicating what actions Netacea would have taken.
161
+ * DEFAULT: NetaceaMitigationType.INGEST
162
+ */
163
+ mitigationType?: NetaceaMitigationType;
164
+ /**
165
+ * Type of ingest, see the `NetaceaIngestType` ENUM
166
+ * - HTTP - Ingest via HTTP.
167
+ * - KINESIS - Ingest via KINESIS
168
+ * DEFAULT: NetaceaIngestType.HTTP
169
+ */
170
+ ingestType?: NetaceaIngestType;
171
+ /**
172
+ * Kinesis ingest definition, see the `KinesisIngestConfigArgs` type.
173
+ * Only to be provided if ingestType is set to KINESIS.
174
+ * Netacea will provide you with the details for this stream.
175
+ */
176
+ kinesis?: KinesisIngestConfigArgs;
177
+ /**
178
+ * Version of ingest, see the `NetaceaLogVersion` ENUM
179
+ * - V1 - Standard ingest.
180
+ * - V2 - New BETA ingest.
181
+ * Use NetaceaLogVersion.V1 unless instructed otherwise.
182
+ * DEFAULT: NetaceaLogVersion.V1
183
+ */
184
+ logVersion?: NetaceaLogVersion;
185
+ /**
186
+ * Deprecated: alias for netaceaCookieExpirySeconds.
187
+ * If both are set, netaceaCookieExpirySeconds is prefered.
188
+ * Seconds for the netacea cookie to be revalidated after.
189
+ */
190
+ mitataCookieExpirySeconds?: number;
191
+ /**
192
+ * Seconds for the netacea cookie to be revalidated after.
193
+ */
194
+ netaceaCookieExpirySeconds?: number;
195
+ /**
196
+ * The name of the netacea cookie. Defaults to _mitata.
197
+ */
198
+ netaceaCookieName?: string;
199
+ /**
200
+ * The name of the netacea captcha cookie. Defaults to _mitatacaptcha.
201
+ */
202
+ netaceaCaptchaCookieName?: string;
203
+ }
204
+ interface InjectHeaders {
205
+ 'x-netacea-match': string;
206
+ 'x-netacea-mitigate': string;
207
+ 'x-netacea-captcha': string;
208
+ 'x-netacea-event-id'?: string;
209
+ }
210
+ interface ComposeResultResponse {
211
+ /**
212
+ * Body value of the response, should be in text format
213
+ */
214
+ body?: string;
215
+ /**
216
+ * Response status code
217
+ */
218
+ apiCallStatus: number;
219
+ /**
220
+ * setCookie values
221
+ */
222
+ setCookie: string[];
223
+ /**
224
+ * Netacea session status string for ingest
225
+ */
226
+ sessionStatus: string;
227
+ /**
228
+ * Netacea mitigation string
229
+ */
230
+ mitigation: string;
231
+ /**
232
+ * Indicates if response should be mitigated or not
233
+ */
234
+ mitigated: boolean;
235
+ /**
236
+ * Headers to ingest to origin server
237
+ */
238
+ injectHeaders?: InjectHeaders;
239
+ }
240
+ interface IngestArgs {
241
+ /**
242
+ * Client IP Address
243
+ */
244
+ ip: string;
245
+ /**
246
+ * Client User-Agent header value
247
+ */
248
+ userAgent: string;
249
+ /**
250
+ * Response status code
251
+ * Should be 403 if Netacea mitigated
252
+ */
253
+ status: string;
254
+ /**
255
+ * Request method
256
+ */
257
+ method: string;
258
+ /**
259
+ * Request path
260
+ */
261
+ path: string;
262
+ /**
263
+ * Request protocol
264
+ */
265
+ protocol: string | null;
266
+ /**
267
+ * Request referer header value
268
+ */
269
+ referer: string;
270
+ /**
271
+ * Request content-length header, or body size
272
+ */
273
+ bytesSent: string | number;
274
+ /**
275
+ * Time taken to serve request
276
+ */
277
+ requestTime: string | number;
278
+ /**
279
+ * Netacea mitata cookie value.
280
+ * Should be request's cookie value if Netacea was not called.
281
+ */
282
+ mitataCookie?: string;
283
+ /**
284
+ * Session status from `ComposeResultResponse`
285
+ */
286
+ sessionStatus?: string;
287
+ /**
288
+ * Type of the integration, for example "Cloudflare" or "Cloudfront"
289
+ */
290
+ integrationType?: string;
291
+ /**
292
+ * SEMVER string indicating the version of the integration
293
+ * Example: 1.2.3
294
+ */
295
+ integrationVersion?: string;
296
+ /**
297
+ * IP values set by a CDN under "x-fowarded-for" header
298
+ */
299
+ xForwardedFor?: string;
300
+ headerFingerprint?: string;
301
+ cookieFingerprint?: string;
302
+ }
303
+ interface WebLog {
304
+ Request: string;
305
+ TimeLocal: string;
306
+ RealIp: string;
307
+ UserAgent: string;
308
+ Status: string;
309
+ RequestTime: string;
310
+ BytesSent: string;
311
+ Referer: string;
312
+ NetaceaUserIdCookie: string;
313
+ NetaceaMitigationApplied: string;
314
+ IntegrationType?: string;
315
+ IntegrationVersion?: string;
316
+ XForwardedFor?: string;
317
+ optional?: Record<string, unknown>;
318
+ }
319
+ interface V2WebLog {
320
+ '@timestamp': string;
321
+ bc_type?: string;
322
+ bytes_sent: number;
323
+ client: string;
324
+ domain_name?: string;
325
+ domain_name_orig?: string;
326
+ hour: number;
327
+ integration_type?: string;
328
+ integration_version?: string;
329
+ method: string;
330
+ minute: number;
331
+ path: string;
332
+ protocol: string | null;
333
+ query?: string;
334
+ referrer?: string;
335
+ request: string;
336
+ request_time: number;
337
+ status: string;
338
+ user_agent: string;
339
+ user_id?: string;
340
+ x_forwarded_for?: string;
341
+ optional?: Record<string, unknown>;
342
+ }
343
+ interface NetaceaResponseBase {
344
+ /**
345
+ * Cookies that should be set back to the user.
346
+ */
347
+ setCookie?: string[];
348
+ /**
349
+ * Netacea session status string
350
+ */
351
+ sessionStatus: string;
352
+ }
353
+ interface MitigateResponse<T = any> extends NetaceaResponseBase {
354
+ /**
355
+ * Response value, using Response generic
356
+ */
357
+ response?: T;
358
+ }
359
+ interface InjectResponse<T = any> extends MitigateResponse<T> {
360
+ /**
361
+ * Headers to be sent to the origin server
362
+ * X-Netacea-Match
363
+ * X-Netacea-Mitigate
364
+ * X-Netacea-Captcha
365
+ * X-Netacea-Event-ID (Only sent when CAPTCHA is served)
366
+ */
367
+ injectHeaders: InjectHeaders | undefined;
368
+ /**
369
+ * Response value, using Response generic
370
+ */
371
+ response?: T | undefined;
372
+ }
373
+ type NetaceaMitigationResponse<T> = MitigateResponse<T> | InjectResponse<T> | undefined;
374
+ interface FindBestMitigationResponse {
375
+ sessionStatus: string;
376
+ mitigation: string;
377
+ parts: NetaceaParts;
378
+ }
379
+ interface NetaceaParts {
380
+ match: number;
381
+ mitigate: number;
382
+ captcha: number;
383
+ }
384
+ interface APICallResponse {
385
+ status: number;
386
+ body?: string;
387
+ }
388
+ interface ProcessMitigateRequestArgs {
389
+ url: string;
390
+ method: string;
391
+ mitata: string | undefined;
392
+ mitataCaptcha: string | undefined;
393
+ clientIp: string;
394
+ userAgent: string;
395
+ getBodyFn: () => Promise<string>;
396
+ }
397
+
398
+ interface CloudfrontConstructorArgs extends NetaceaBaseArgs, KinesisIngestArgs {
399
+ ingestEnabled?: boolean;
400
+ cookieEncryptionKey?: string;
401
+ netaceaCaptchaPath?: string;
402
+ captchaHeader?: CustomHeader;
403
+ dynamicCaptchaContentType?: boolean;
404
+ netaceaCookieAttributes?: string;
405
+ netaceaCaptchaCookieAttributes?: string;
406
+ /**
407
+ * The name of the header from which to retrieve the client's IP address.
408
+ */
409
+ ipHeaderName?: string;
410
+ }
411
+ interface CustomHeader {
412
+ name: string;
413
+ value: string;
414
+ }
415
+
416
+ interface MakeRequestResponse {
417
+ status: number;
418
+ headers: Record<string, string | string[]>;
419
+ body?: any;
420
+ }
421
+ declare class Cloudfront {
422
+ static NetaceaCookieHeader: string;
423
+ static NetaceaTrueUserAgentHeader: string;
424
+ private readonly cookieEncryptionKey;
425
+ ingestEnabled: boolean;
426
+ private readonly netaceaCaptchaPath?;
427
+ private readonly captchaHeader?;
428
+ private readonly dynamicCaptchaContentType;
429
+ private readonly ipHeaderName?;
430
+ protected mitataCookieExpirySeconds: number;
431
+ protected apiKey: string;
432
+ protected secretKey?: string;
433
+ protected mitigationServiceUrl: string;
434
+ protected ingestServiceUrl: string;
435
+ protected readonly timeout: number;
436
+ protected readonly captchaSiteKey?: string;
437
+ protected readonly captchaSecretKey?: string;
438
+ protected readonly ingestType: NetaceaIngestType;
439
+ protected readonly logVersion: NetaceaLogVersion;
440
+ protected readonly kinesis?: KinesisIngest;
441
+ protected readonly mitigationType: NetaceaMitigationType;
442
+ protected readonly encryptedCookies: string[];
443
+ protected readonly netaceaCookieName: string;
444
+ protected readonly netaceaCaptchaCookieName: string;
445
+ protected readonly netaceaCookieAttributes: string;
446
+ protected readonly netaceaCaptchaCookieAttributes: string;
447
+ constructor(options: CloudfrontConstructorArgs);
448
+ run(cloudfrontEvent: CloudFrontRequestEvent): Promise<{
449
+ respondWith?: CloudFrontResultResponse;
450
+ }>;
451
+ protected makeRequest({ host, path, method, body, headers, timeout }: MakeRequestArgs): Promise<MakeRequestResponse>;
452
+ protected mitigate(cfRequest: CloudFrontRequest): Promise<MitigateResponse<CloudFrontResultResponse>>;
453
+ protected inject(request: CloudFrontRequest): Promise<InjectResponse>;
454
+ ingest(requestOrEvent: CloudFrontRequestEvent | CloudFrontResponseEvent | CloudFrontRequest, response?: CloudFrontResultResponse | CloudFrontResponse | undefined): Promise<any>;
455
+ addNetaceaCookiesToResponse(cloudfrontEvent: CloudFrontResponseEvent): void;
456
+ private setInjectHeaders;
457
+ private getValueFromHeaderOrDefault;
458
+ private getMitataValueFromHeaderOrDefault;
459
+ private getRequestResponseFromEvent;
460
+ private getMitigationResponse;
461
+ private addNetaceaCookiesToRequest;
462
+ getCookieHeader(request: CloudFrontRequest): string | null;
463
+ protected encryptCookieValue(cookieValue: string): Promise<string>;
464
+ protected decryptCookieValue(encryptedCookieValue: string): Promise<string>;
465
+ /**
466
+ * START -- NETACEA BASE METHODS
467
+ */
468
+ runMitigation(request: CloudFrontRequest): Promise<NetaceaMitigationResponse<CloudFrontResultResponse>>;
469
+ /**
470
+ * Returns the value of the cookie with the given name from a string or list of cookies.
471
+ * If the cookie name is included in the encryptedCookies class property,
472
+ * then the cookie value will be decrypted automatically.
473
+ * The method may operate of either the HTTP Cookie or Set-Cookie headers.
474
+ * @param cookieName the name of the cookie to find.
475
+ * @param cookies the full list of cookies, either as a string or an array of strings.
476
+ * @returns the value of the cookie, if found.
477
+ */
478
+ protected readCookie(cookieName: string, cookies: string | string[] | null | undefined): Promise<string | undefined>;
479
+ protected processMitigateRequest(args: ProcessMitigateRequestArgs & {
480
+ accept: string;
481
+ host: string;
482
+ }): Promise<ComposeResultResponse>;
483
+ protected isUrlCaptchaPost(url: string, method: string): boolean;
484
+ protected isUrlCaptchaGet(url: string, method: string): boolean;
485
+ protected shouldSetCaptchaPass(request: CloudFrontRequest, response: CloudFrontResponse | CloudFrontResultResponse): boolean;
486
+ private processCaptcha;
487
+ private makeCaptchaAPICall;
488
+ private getApiCallResponseFromResponse;
489
+ protected APIError(response: APICallResponse): Error;
490
+ protected createMitata(clientIP: string, userId: string | undefined, match: number, mitigate: number, captcha: number, maxAge?: number, expiry?: number | undefined): Promise<string>;
491
+ protected createMitataCaptcha(headers: Record<string, string | string[]>): Promise<string | undefined>;
492
+ private buildCookieFromValues;
493
+ protected callIngest(args: IngestArgs): Promise<void>;
494
+ protected constructWebLog(args: IngestArgs): WebLog | V2WebLog;
495
+ private constructV2WebLog;
496
+ private constructV1WebLog;
497
+ private makeIngestApiCall;
498
+ protected processIngest(request: CloudFrontRequest): Promise<NetaceaResponseBase>;
499
+ protected setIngestOnlyMitataCookie(userId: string | undefined): Promise<NetaceaResponseBase>;
500
+ protected findBestMitigation(match: number, mitigate: number, captcha: number, isCaptchaPost: boolean): FindBestMitigationResponse;
501
+ private adjustCaptchaCode;
502
+ protected check(netaceaCookie: string | undefined, clientIP: string, userAgent: string, accept: string, host: string, captchaCookie?: string): Promise<ComposeResultResponse>;
503
+ private makeMitigateAPICall;
504
+ private buildCookieHeader;
505
+ private composeResult;
506
+ }
507
+
508
+ export { Cloudfront, type CloudfrontConstructorArgs };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("node:crypto"),t=require("node:buffer"),a=require("axios"),i=require("aws4");function s(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(a){if("default"!==a){var i=Object.getOwnPropertyDescriptor(e,a);Object.defineProperty(t,a,i.get?i:{enumerable:!0,get:function(){return e[a]}})}})),t.default=e,Object.freeze(t)}var o,r,n,c,h=s(require("jose"));!function(e){e.ORIGIN="ORIGIN",e.HTTP="HTTP",e.KINESIS="KINESIS",e.NATIVE="NATIVE"}(o||(o={})),function(e){e.V1="V1",e.V2="V2"}(r||(r={})),function(e){e.MITIGATE="MITIGATE",e.INJECT="INJECT",e.INGEST="INGEST"}(n||(n={})),function(e){e.CAPTCHA_GET="captcha_get",e.CAPTCHA_POST="captcha_post",e.EXPIRED_SESSION="expired_session",e.FORCED_REVALIDATION="forced_revalidation",e.INVALID_SESSION="invalid_session",e.IP_CHANGE="ip_change",e.NO_SESSION="no_session"}(c||(c={}));function u(e,t=0){return isNaN(e)?t:parseInt(e)}const d=3e3;const p="_/@#/",l={none:"",block:"block",captcha:"captcha",allow:"allow",captchaPass:"captchapass"},m={0:l.none,1:l.block,2:l.none,3:l.block,4:l.block},g={1:l.captcha,2:l.captchaPass,3:l.captcha,4:l.allow,5:l.captcha};var y=Object.freeze({__proto__:null,COOKIEDELIMITER:p,bestMitigationCaptchaMap:g,bestMitigationMap:m,captchaMap:{0:"",1:"captcha_serve",2:"captcha_pass",3:"captcha_fail",4:"captcha_cookiepass",5:"captcha_cookiefail"},captchaStatusCodes:{"":0,captchaServe:1,captchaPass:2,captchaFail:3,captchaCookiePass:4,captchaCookieFail:5},matchMap:{0:"",1:"ua_",2:"ip_",3:"visitor_",4:"datacenter_",5:"sev_",6:"organisation_",7:"asn_",8:"country_",9:"combination_"},mitigateMap:{0:"",1:"blocked",2:"allow",3:"hardblocked",4:"block"},mitigationTypes:l,netaceaCookieV3KeyMap:{clientIP:"cip",userId:"uid",gracePeriod:"grp",cookieId:"cid",match:"mat",mitigate:"mit",captcha:"cap",issueTimestamp:"ist",issueReason:"isr"},netaceaCookieV3OptionalKeyMap:{checkAllPostRequests:"fCAPR"},netaceaHeaders:{match:"x-netacea-match",mitigate:"x-netacea-mitigate",captcha:"x-netacea-captcha",mitata:"x-netacea-mitata-value",mitataExpiry:"x-netacea-mitata-expiry",mitataCaptcha:"x-netacea-mitatacaptcha-value",mitataCaptchaExpiry:"x-netacea-mitatacaptcha-expiry",eventId:"x-netacea-event-id"},netaceaSettingsMap:{checkAllPostRequests:"checkAllPostRequests"}});const k="ignored",C="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),f=/^(.*)_\/@#\/(.*)_\/@#\/(.*)_\/@#\/(.*)_\/@#\/((\d)(\d)(\d))$/;function v(e){if(void 0===e)return;const t=e.match(f);if(null!=t){const[,e,a,i,s,o,r,n,c]=t;return{signature:e,expiry:a,userId:i,ipHash:s,mitigationType:o,match:parseInt(r),mitigate:parseInt(n),captcha:parseInt(c)}}}function S(t,a,i,s,o="000"){void 0===a&&(a=function(t=16,a=C){const i=e.randomBytes(t-1);return`c${Array.from(i).map((e=>a[e%a.length])).join("")}`}());const r=[i,a,N(t+"|"+String(i),s),o].join(p);return`${N(r,s)}${p}${r}`}function N(a,i){const s=e.createHmac("sha256",i);return s.update(a),t.Buffer.from(s.digest("hex")).toString("base64")}function I(e,t,a){const i={mitata:void 0,requiresReissue:!1,isExpired:!1,shouldExpire:!1,isSameIP:!1,isPrimaryHashValid:!1,captcha:0,match:0,mitigate:0};if("string"!=typeof e||""===e)return i;const s=v(e);if(void 0!==s){const e=[s.expiry,s.userId,s.ipHash,s.mitigationType].join(p),i=Math.floor(Date.now()/1e3),o=parseInt(s.expiry)<i,r=[1,3,5].includes(s.captcha),n=3===s.mitigate,c=r||n,h=N(t+"|"+s.expiry,a),u=s.ipHash===h;return{mitata:s,requiresReissue:o||!u,isExpired:o,shouldExpire:c,isSameIP:u,isPrimaryHashValid:s.signature===N(e,a),match:s.match,mitigate:s.mitigate,captcha:s.captcha}}return i}function b(e,t){const a=e.split(";").map((e=>e.trim())).filter((e=>e.toLowerCase().startsWith(t.toLowerCase())))[0];return void 0!==a&&a.length>0?a?.replace(`${t}=`,""):void 0}function A(e,t=!1){return"string"!=typeof e&&(e=e.join("; ")),""===e?"":w(e.split(";"),t).join("; ")}function w(e,t=!1){if(t)return w(e.reverse()).reverse();const a=new Set,i=[];for(let t of e){if(t=t.trimStart(),""===t.trim())continue;const e=t.split("=")[0].toUpperCase();a.has(e)||(a.add(e),i.push(t))}return i}var E=Object.freeze({__proto__:null,configureCookiesDomain:function(e,t){let a=e=A(e??"",!0),i=t=A(t??"",!0);if(void 0!==e&&void 0!==t){const s=b(e,"Domain"),o=b(t,"Domain");void 0!==s&&void 0!==o?i=t.replace(o,s):void 0!==s&&void 0===o?i=t+(""!==t?`; Domain=${s}`:`Domain=${s}`):void 0===s&&void 0!==o&&(a=e+(""!==e?`; Domain=${o}`:`Domain=${o}`))}else if(void 0!==e&&void 0===t){const t=b(e,"Domain");void 0!==t&&(i=`Domain=${t}`)}else if(void 0===e&&void 0!==t){const e=b(t,"Domain");void 0!==e&&(a=`Domain=${e}`)}return{cookieAttributes:""!==a?a:void 0,captchaCookieAttributes:""!==i?i:void 0}},extractAndRemoveCookieAttr:function(e,t){const a=b(e,t);if(void 0!==a){return{extractedAttribute:a,cookieAttributes:e.replace(/ /g,"").replace(`${t}=${a}`,"").split(";").filter((e=>e.length>0)).join("; ")}}return{extractedAttribute:void 0,cookieAttributes:e}},extractCookieAttr:b,removeDuplicateAttrs:A});function T(e){const t=A([e.otherAttributes??"",`Max-Age=${e.maxAgeAttribute??86400}`,"Path=/"].join("; "));return`${e.cookieName}=${e.cookieValue}; ${t}`}var K=Object.freeze({__proto__:null,createNetaceaCaptchaSetCookieString:function(e){return T({...e,cookieName:e.cookieName??"_mitatacaptcha"})},createNetaceaSetCookieString:function(e){return T({...e,cookieName:e.cookieName??"_mitata"})},createSetCookieString:T});var x=Object.freeze({__proto__:null,parseSetCookie:function(e){const t=e.indexOf("=");if(t<0)throw new Error("Could not parse the given set-cookie value.");const a=e.slice(0,t),i=e.slice(t+1),s=i.indexOf(";");return{name:a,value:i.slice(0,s),attributes:i.slice(s).trimStart()}}});const P={cookie:{parse:x,attributes:E,netaceaSession:K}};var R={},_={},O={},H={};Object.defineProperty(H,"__esModule",{value:!0}),H.API_VERSION=H.REGION=H.PAYLOAD_TYPE=H.STATE=void 0,H.STATE={ACTIVE:"ACTIVE",UPDATING:"UPDATING",CREATING:"CREATING",DELETING:"DELETING"},H.PAYLOAD_TYPE="string",H.REGION="eu-west-1",H.API_VERSION="2013-12-02",Object.defineProperty(O,"__esModule",{value:!0}),O.signRequest=void 0;const M=i,q=H;function D(e,t){const a=[];for(let i=0;i<e.length;i+=t){const s=e.slice(i,i+t);a.push({Data:Buffer.from(JSON.stringify(s)).toString("base64"),PartitionKey:Date.now().toString()})}return a}O.signRequest=function(e,t,a){const{accessKeyId:i,secretAccessKey:s}=e,o={Records:D(t,a),PartitionKey:Date.now().toString(),StreamName:e.streamName};return M.sign({service:"kinesis",body:JSON.stringify(o),headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"Kinesis_20131202.PutRecords"},region:q.REGION},{accessKeyId:i,secretAccessKey:s})},Object.defineProperty(_,"__esModule",{value:!0});const V=O;_.default=class{constructor({kinesisStreamName:e,kinesisAccessKey:t,kinesisSecretKey:a,maxLogAgeSeconds:i,logBatchSize:s}){this.logBatchSize=20,this.maxLogAgeSeconds=10,this.logCache=[],this.intervalSet=!1,this.kinesisStreamName=e,this.kinesisAccessKey=t,this.kinesisSecretKey=a,void 0!==i&&i<this.maxLogAgeSeconds&&i>0&&(this.maxLogAgeSeconds=i),void 0!==s&&(this.logBatchSize=s)}async putToKinesis(e){if(0===this.logCache.length)return;const t=[...this.logCache];this.logCache=[];try{const a=(0,V.signRequest)({streamName:this.kinesisStreamName,accessKeyId:this.kinesisAccessKey,secretAccessKey:this.kinesisSecretKey},t,this.logBatchSize);await e({headers:a.headers,host:`https://${a.hostname}`,method:a.method,path:a.path,body:a.body})}catch(e){this.logCache.push(...t),console.error(e)}}async ingest(e,t){this.logCache.push(e),this.intervalSet||(this.intervalSet=!0,await async function(e){await new Promise((t=>{setTimeout(t,e)}))}(1e3*this.maxLogAgeSeconds),await this.putToKinesis(t),this.intervalSet=!1),this.logCache.length>=this.logBatchSize&&await this.putToKinesis(t)}},Object.defineProperty(R,"__esModule",{value:!0});const F=_;var $=R.default=F.default;async function j(e,t){const a=h.base64url.decode(t),{plaintext:i}=await h.compactDecrypt(e,a,{keyManagementAlgorithms:["dir"],contentEncryptionAlgorithms:["A256GCM"]});return(new TextDecoder).decode(i)}function U(e,t){const{clientIp:a}=e;if(void 0===t||""===t)return a;const i=e.headers[t]?.[0]?.value;return void 0===i||""===i?a:"x-forwarded-for"===t?i.split(/, ?/).pop()??a:i}async function L(e,t,a){const i=t.cookie?.[0].value.split(";"),s=i?.find((t=>t.includes(`${e}=`)))?.trimStart()?.replace(`${e}=`,"");if(void 0!==s){if(void 0!==a)try{return await j(s,a)}catch(e){return}return s}}function G(e){const t={"set-cookie":[]};for(const a of e)t["set-cookie"]?.push({key:"set-cookie",value:a});return t}function B(e,t){const a=e[t];return"string"==typeof a?a:a?.[0]}function X(e,t){const a=B(e,t);if(void 0!==a)return parseInt(a)}function J(e,t,a){"/"!==t[0]&&(t=`/${t}`);const i=t.split("?"),s=i[0],o=i.length>1?`?${i[1]}`:void 0;return{path:s,query:o,request:`${e} ${s}${o??""}${""!==(a??"")?` ${a}`:""}`}}const{extractCookieAttr:z,extractAndRemoveCookieAttr:W,removeDuplicateAttrs:Y}=P.cookie.attributes,Z=P.cookie.parse.parseSetCookie,{configureCookiesDomain:Q}=P.cookie.attributes,{matchMap:ee,mitigationTypes:te,mitigateMap:ae,bestMitigationMap:ie,bestMitigationCaptchaMap:se,captchaMap:oe,netaceaHeaders:re}=y;class ne{static NetaceaCookieHeader="x-netacea-cloudfront-mitata-cookie";static NetaceaTrueUserAgentHeader="x-netacea-true-useragent-header";cookieEncryptionKey;ingestEnabled=!0;netaceaCaptchaPath;captchaHeader;dynamicCaptchaContentType;ipHeaderName;mitataCookieExpirySeconds;apiKey;secretKey;mitigationServiceUrl;ingestServiceUrl;timeout;captchaSiteKey;captchaSecretKey;ingestType;logVersion;kinesis;mitigationType;encryptedCookies=[];netaceaCookieName;netaceaCaptchaCookieName;netaceaCookieAttributes;netaceaCaptchaCookieAttributes;constructor(e){if(e.ingestType=o.KINESIS,void 0===e.kinesis&&(console.warn(['NETACEA :: Please move kinesis params to "kinesis" object in config.',"Backwards compatibility will soon be removed."].join(" ")),e.kinesis={kinesisStreamName:e.kinesisStreamName,kinesisAccessKey:e.kinesisAccessKey,kinesisSecretKey:e.kinesisSecretKey,maxLogAgeSeconds:1}),null===e.apiKey||void 0===e.apiKey)throw new Error("apiKey is a required parameter");var t;this.apiKey=e.apiKey,this.secretKey=e.secretKey,this.mitigationServiceUrl=e.mitigationServiceUrl??"https://mitigations.netacea.net",this.ingestServiceUrl=e.ingestServiceUrl??"https://ingest.netacea.net",this.mitigationType=e.mitigationType??n.INGEST,this.ingestType=e.ingestType??o.HTTP,this.logVersion=e.logVersion??r.V1,this.ingestType===o.KINESIS&&(void 0===e.kinesis?console.warn(`NETACEA WARN: no kinesis args provided, when ingestType is ${this.ingestType}`):this.kinesis=new $({...e.kinesis,apiKey:this.apiKey})),void 0===e.captchaSiteKey&&void 0===e.captchaSecretKey||(this.captchaSiteKey=e.captchaSiteKey,this.captchaSecretKey=e.captchaSecretKey),this.timeout=(t=e.timeout??3e3)<=0?d:t,this.netaceaCookieName=e.netaceaCookieName??"_mitata",this.netaceaCaptchaCookieName=e.netaceaCaptchaCookieName??"_mitatacaptcha",this.netaceaCaptchaPath=e.netaceaCaptchaPath,this.dynamicCaptchaContentType=e.dynamicCaptchaContentType??!1;const a=Q(e.netaceaCookieAttributes??"",e.netaceaCaptchaCookieAttributes??"");var i,s;this.netaceaCookieAttributes=a.cookieAttributes??"",this.netaceaCaptchaCookieAttributes=a.captchaCookieAttributes??"",this.captchaHeader=e.captchaHeader,this.ipHeaderName=e.ipHeaderName?.toLowerCase()?.trim(),this.encryptedCookies=[this.netaceaCookieName,this.netaceaCaptchaCookieName],this.mitataCookieExpirySeconds=(i=this.mitigationType,void 0===(s=e.netaceaCookieExpirySeconds??e.mitataCookieExpirySeconds)?i===n.INGEST?3600:60:s),this.ingestEnabled=e.ingestEnabled??!0,this.cookieEncryptionKey=e.cookieEncryptionKey}async run(e){try{const{request:t}=this.getRequestResponseFromEvent(e),{uri:a,method:i}=t;if(this.isUrlCaptchaGet(a,i)){const a=await async function({request:e,secretKey:t,mitigationCallFn:a,composeResultFn:i,cookieEncryptionKey:s,netaceaCookieName:o,netaceaCaptchaCookieName:r,ipHeaderName:n}){const{querystring:c}=e,h=U(e,n),u=e.headers["user-agent"]?.[0].value??"",d=e.headers.accept?.[0].value??"text/html",p=e.headers.host?.[0].value??"";if(void 0===t)throw new Error("Secret key needs to be defined to make mitigation calls.");const l=c.split("&").find((e=>e.includes("trackingId=")))?.replace("trackingId=",""),{headers:m}=e,g=await L(o,m,s),y=await L(r,m,s),{userId:k}=v(g)??{},C=await async function({userId:e,clientIp:t,userAgent:a,trackingId:i,accept:s,host:o,captchaCookie:r,mitigationCallFn:n,composeResultFn:c}){const h={match:0,mitigate:0,captcha:1},u=await n({userId:e,clientIP:t,userAgent:a,captchaCookie:r,accept:s,host:o,isCaptchaGet:!0,defaultMitataCodes:h,trackingId:i});return c(u.body,u.setCookie,u.status,u.match,u.mitigate,u.captcha,!0)}({userId:k,clientIp:h,userAgent:u,captchaCookie:y,accept:d,host:p,trackingId:l,mitigationCallFn:a,composeResultFn:i});return{headers:G(C.setCookie),status:"403",body:C.body,statusDescription:"Forbidden"}}({request:t,secretKey:this.secretKey,mitigationCallFn:this.makeMitigateAPICall.bind(this),composeResultFn:this.composeResult.bind(this),cookieEncryptionKey:this.cookieEncryptionKey,netaceaCookieName:this.netaceaCookieName,netaceaCaptchaCookieName:this.netaceaCaptchaCookieName,ipHeaderName:this.ipHeaderName});return this.ingest(e,a),{respondWith:a}}const s=await this.runMitigation(t);return this.addNetaceaCookiesToRequest(t,s),t.headers[ne.NetaceaTrueUserAgentHeader]=[{key:ne.NetaceaTrueUserAgentHeader,value:this.getValueFromHeaderOrDefault(t.headers,"user-agent","-")}],{respondWith:s?.response}}catch(e){return console.error("Netacea FailOpen - ",e.message),{}}}async makeRequest({host:e,path:t,method:i,body:s,headers:o,timeout:r}){const n=`${e}${t}`,c=await a.request({url:n,data:s,headers:o,method:i,timeout:r,transformResponse:e=>e});return{headers:c.headers,status:c.status,body:c.data}}async mitigate(e){try{const{netaceaResult:a,request:i}=await this.getMitigationResponse(e);let s;if(a.mitigated){const e={"set-cookie":[]};for(const t of a.setCookie)e["set-cookie"]=e["set-cookie"]??[],e["set-cookie"].push({key:"set-cookie",value:t});"captcha"===a.mitigation&&void 0!==this.captchaHeader&&(e[this.captchaHeader.name]=[{key:this.captchaHeader.name,value:this.captchaHeader.value}]);s={headers:e,...this.isUrlCaptchaPost(i.uri,i.method)?{status:"200",statusDescription:"OK",body:""}:{status:"403",statusDescription:"Forbidden",body:"Forbidden"}};let o=0;if(void 0!==a.body&&a.body.length>0){o=a.body.length;const e=(t=a.body).includes("captchaRelativeURL")&&t.includes("captchaAbsoluteURL");s.status=e?"403":"200",s.statusDescription=e?"Forbidden":"OK",s.body=a.body,s.bodyEncoding="text"}const r={status:s.status,statusDescription:s.statusDescription??"",headers:{"content-length":[{key:"content-length",value:o.toString()}],"set-cookie":a.setCookie.map((e=>({key:"set-cookie",value:e})))}};this.ingest(i,r)}return this.addNetaceaCookiesToRequest(i,a),{response:s,sessionStatus:a.sessionStatus,setCookie:a.setCookie}}catch(t){if(this.isUrlCaptchaPost(e.uri,e.method)){const t={status:"500",statusDescription:"Internal Server Error",body:"",headers:{}},a={response:t,sessionStatus:"error_open"};return this.ingest(e,t),a}return console.error("Netacea FailOpen Error: ",t),{sessionStatus:""}}var t}async inject(e){try{const{netaceaResult:t}=await this.getMitigationResponse(e);return{injectHeaders:t.injectHeaders,sessionStatus:t.sessionStatus,setCookie:t.setCookie}}catch(e){return console.error("Netacea FailOpen Error: ",e),{sessionStatus:"",injectHeaders:void 0,setCookie:void 0}}}async ingest(e,t=void 0){let a;if(Object.prototype.hasOwnProperty.call(e,"Records")){const i=this.getRequestResponseFromEvent(e);a=i.request,void 0===t&&(t=i.response)}else a=e;if(!this.ingestEnabled)return;if(null==t)throw new Error("Cloudfront response is required to ingest");const i=this.getMitataValueFromHeaderOrDefault(t.headers,"set-cookie"),s=""!==i?i:this.getMitataValueFromHeaderOrDefault(a.headers,"cookie");let o=await this.readCookie(this.netaceaCookieName,s)??"";if(void 0===o||""===o){const e=this.getMitataValueFromHeaderOrDefault(a.headers,"cookie");o=await this.readCookie(this.netaceaCookieName,e)??""}let r=0,n=0,c=0;const h=v(o);void 0!==h&&(r=h.match,n=h.mitigate,c=h.captcha);const u=this.shouldSetCaptchaPass(a,t),d="500"===t.status&&"Internal Server Error"===t.statusDescription,{sessionStatus:p}=this.findBestMitigation(r,n,c,u);await this.callIngest({bytesSent:this.getValueFromHeaderOrDefault(t.headers,"content-length","0"),ip:U(a,this.ipHeaderName),method:a.method,path:a.uri,protocol:null,referer:this.getValueFromHeaderOrDefault(a.headers,"referer"),requestTime:"0",status:t.status,userAgent:this.getValueFromHeaderOrDefault(a.headers,ne.NetaceaTrueUserAgentHeader,this.getValueFromHeaderOrDefault(a.headers,"user-agent")),mitataCookie:o,sessionStatus:d?"error_open":p,integrationType:"@netacea/cloudfront".replace("@netacea/",""),integrationVersion:"6.0.2",xForwardedFor:this.getValueFromHeaderOrDefault(a.headers,"x-forwarded-for")})}addNetaceaCookiesToResponse(e){const{response:t,request:a}=this.getRequestResponseFromEvent(e);if(void 0===t)throw new Error("Response required to add cookies to response");const i=a.headers[ne.NetaceaCookieHeader];if(null!=i&&null!=t.headers){let e=!1;if(void 0===t.headers["set-cookie"]?t.headers["set-cookie"]=[]:e=void 0!==t.headers["set-cookie"].find((e=>e.value.includes(this.netaceaCookieName)||e.value.includes(this.netaceaCaptchaCookieName))),!e)for(const e of i)t.headers["set-cookie"].push({key:"set-cookie",value:e.value})}this.setInjectHeaders(e)}setInjectHeaders(e){const{response:t,request:a}=this.getRequestResponseFromEvent(e);if(null!=t?.headers){const e=a.headers["x-netacea-match"],i=a.headers["x-netacea-mitigate"],s=a.headers["x-netacea-captcha"],o=a.headers["x-netacea-event-id"];void 0!==e&&void 0!==i&&void 0!==s&&(t.headers["x-netacea-match"]=e,t.headers["x-netacea-mitigate"]=i,t.headers["x-netacea-captcha"]=this.shouldSetCaptchaPass(a,t)?[{key:"x-netacea-captcha",value:"2"}]:s),void 0!==o&&(t.headers["x-netacea-event-id"]=o)}}getValueFromHeaderOrDefault(e,t,a=""){if(void 0!==e?.[t]){const a=e[t];if(void 0!==a)return a[0].value}return a}getMitataValueFromHeaderOrDefault(e,t,a=""){if(void 0!==e?.[t]){const a=e[t];if(void 0!==a){const e=a.find((e=>e.value.includes(this.netaceaCookieName)));if(void 0!==e)return e.value}}return a}getRequestResponseFromEvent(e){return e.Records[0].cf}async getMitigationResponse(e){const t=this.getMitataValueFromHeaderOrDefault(e.headers,"cookie"),a=await this.readCookie(this.netaceaCookieName,t),i=await this.readCookie(this.netaceaCaptchaCookieName,t),s=U(e,this.ipHeaderName),o=this.getValueFromHeaderOrDefault(e.headers,"user-agent"),r=this.getValueFromHeaderOrDefault(e.headers,"accept","text/html"),n=this.getValueFromHeaderOrDefault(e.headers,"host");return{netaceaResult:await this.processMitigateRequest({getBodyFn:async()=>await Promise.resolve(Buffer.from(e.body?.data??"","base64").toString()),clientIp:s,method:e.method,url:e.uri,userAgent:o,accept:r,host:n,mitata:a,mitataCaptcha:i}),request:e}}addNetaceaCookiesToRequest(e,t){if(void 0===t)return e;if(e.headers[ne.NetaceaCookieHeader]=[],void 0!==t.setCookie)for(const a of t.setCookie){const t=e.headers[ne.NetaceaCookieHeader]??[];t.push({key:ne.NetaceaCookieHeader,value:a}),e.headers[ne.NetaceaCookieHeader]=t}if(this.mitigationType===n.INJECT)for(const[a,i]of Object.entries(t.injectHeaders??{}))e.headers[a]=[{key:a,value:i}];return e}getCookieHeader(e){return this.getMitataValueFromHeaderOrDefault(e.headers,"cookie")}async encryptCookieValue(e){return void 0!==this.cookieEncryptionKey?await async function(e,t){const a=h.base64url.decode(t),i=(new TextEncoder).encode(e);return await new h.CompactEncrypt(i).setProtectedHeader({alg:"dir",enc:"A256GCM"}).encrypt(a)}(e,this.cookieEncryptionKey):e}async decryptCookieValue(e){return void 0!==this.cookieEncryptionKey?await j(e,this.cookieEncryptionKey):e}async runMitigation(e){try{switch(this.mitigationType){case n.MITIGATE:return await this.mitigate(e);case n.INJECT:return await this.inject(e);case n.INGEST:return await this.processIngest(e);default:throw new Error(`Netacea Error: Mitigation type ${this.mitigationType} not recognised`)}}catch(e){return console.error("Netacea FAILOPEN Error:",e),{injectHeaders:{"x-netacea-captcha":"0","x-netacea-match":"0","x-netacea-mitigate":"0"},sessionStatus:""}}}async readCookie(e,t){if(null==t)return;if("string"==typeof t)return await this.readCookie(e,t.split(";"));const a=`${e}=`;for(const i of t){const t=i.split(";")[0].trimStart();if(t.startsWith(a)){const i=t.slice(a.length);if(this.encryptedCookies.includes(e))try{return await this.decryptCookieValue(i)}catch(e){return}return i}}}async processMitigateRequest(e){const t=this.isUrlCaptchaPost(e.url,e.method);return await(t?this.processCaptcha(e.mitata,e.clientIp,e.userAgent,await e.getBodyFn()):this.check(e.mitata,e.clientIp,e.userAgent,e.accept,e.host,e.mitataCaptcha))}isUrlCaptchaPost(e,t){return e.includes("/AtaVerifyCaptcha")&&"post"===t.toLowerCase()}isUrlCaptchaGet(e,t){return e.toLowerCase()===this.netaceaCaptchaPath?.toLowerCase()&&"get"===t.toLowerCase()}shouldSetCaptchaPass(e,t){if(this.isUrlCaptchaPost(e.uri,e.method))return!0;if(void 0===t)return!1;const a=null!=t.headers?t.headers["set-cookie"]:void 0,i=a?.find((e=>e.value.split("=")[0]===this.netaceaCaptchaCookieName)),s=void 0!==i;return this.mitigationType===n.INJECT&&s}async processCaptcha(e,t,a,i){const{status:s,match:o,mitigate:r,captcha:n,body:c,setCookie:h}=await this.makeCaptchaAPICall(e,t,a,i);return this.composeResult(c,h,s,o,r,n,!0)}async makeCaptchaAPICall(e,t,a,i){const s={"X-Netacea-API-Key":this.apiKey,"X-Netacea-Client-IP":t,"user-agent":a,"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},o=v(e);void 0!==o&&(s["X-Netacea-UserId"]=o.userId),void 0!==this.captchaSiteKey&&void 0!==this.captchaSecretKey&&(s["X-Netacea-Captcha-Site-Key"]=this.captchaSiteKey,s["X-Netacea-Captcha-Secret-Key"]=this.captchaSecretKey);const r=await this.makeRequest({host:this.mitigationServiceUrl,path:"/AtaVerifyCaptcha",headers:s,method:"POST",body:i,timeout:this.timeout});return await this.getApiCallResponseFromResponse(r,o?.userId,t)}async getApiCallResponseFromResponse(e,t,a,i){if(200!==e.status)throw this.APIError(e);let s=X(e.headers,re.match)??NaN,o=X(e.headers,re.mitigate)??NaN,r=X(e.headers,re.captcha)??NaN;isNaN(s)&&(s=i?.match??0),isNaN(o)&&(o=i?.mitigate??0),isNaN(r)&&(r=i?.captcha??0);let n=X(e.headers,re.mitataExpiry)??NaN;isNaN(n)&&(n=86400);const c=[await this.createMitata(a,t,s,o,r),await this.createMitataCaptcha(e.headers)].filter((e=>void 0!==e)),h=B(e.headers,re.eventId);return{status:e.status,match:s,mitigate:o,captcha:r,setCookie:c,body:e.body,eventId:h,mitataMaxAge:n}}APIError(e){let t="Unknown error";switch(e.status){case 403:t="Invalid credentials";break;case 500:t="Server error";break;case 502:t="Bad Gateway";break;case 503:t="Service Unavailable";break;case 400:t="Invalid request"}return new Error(`Error reaching Netacea API (${t}), status: ${e.status}`)}async createMitata(e,t,a,i,s,o=86400,r=void 0){const n=[1,3,5].includes(s)||3===i?-60:this.mitataCookieExpirySeconds,c=r??Math.floor(Date.now()/1e3)+n;if(void 0===this.secretKey)throw new Error("Cannot build cookie without secret key.");const h=[a,i,s].join(""),u=S(e,t,c,this.secretKey,h);let d,p,l=o;if(""!==this.netaceaCookieAttributes){const{extractedAttribute:e,cookieAttributes:t}=W(this.netaceaCookieAttributes,"Max-Age");l=void 0!==e?Number(e):o;const{extractedAttribute:a,cookieAttributes:i}=W(t,"Path");d=a??"/",p=i??void 0}return await this.buildCookieFromValues(this.netaceaCookieName,u,l,p,d)}async createMitataCaptcha(e){let t=e["set-cookie"]??[];t="string"==typeof t?[t]:t;const a=t.find((e=>e.startsWith("_mitatacaptcha=")));let i,s="86400";if(void 0!==a&&""!==a)try{const e=Z(a);i=e.value,s=z(e.attributes,"Max-Age")??"86400"}catch(e){return}if(""===i||void 0===i)return;const o=Y([this.netaceaCaptchaCookieAttributes,"Path=/",`Max-Age=${s}`]);return i=this.encryptedCookies.includes(this.netaceaCaptchaCookieName)?await this.encryptCookieValue(i):i,`${this.netaceaCaptchaCookieName}=${i}; ${o}`}async buildCookieFromValues(e,t,a,i,s="/"){const o=`${e}=${this.encryptedCookies.includes(e)?await this.encryptCookieValue(t):t}; Max-Age=${a}; Path=${s}`;return void 0!==i&&""!==i?`${o}; ${i}`:o}async callIngest(e){const t=this.constructWebLog(e);if(this.ingestType===o.KINESIS){if(void 0===this.kinesis)return void console.error("Netacea Error: Unable to log as Kinesis has not been defined.");try{await this.kinesis.ingest({...t,apiKey:this.apiKey},this.makeRequest.bind(this))}catch(e){console.error("NETACEA Error: ",e.message)}}else{const e={"X-Netacea-API-Key":this.apiKey,"content-type":"application/json"},a=await this.makeIngestApiCall(e,t);if(200!==a.status)throw this.APIError(a)}}constructWebLog(e){return e.bytesSent=""===e.bytesSent?"0":e.bytesSent,this.logVersion===r.V2?this.constructV2WebLog(e):this.constructV1WebLog(e)}constructV2WebLog({ip:e,userAgent:t,status:a,method:i,path:s,protocol:o,referer:r,bytesSent:n,requestTime:c,mitataCookie:h,sessionStatus:d,integrationType:p,integrationVersion:l,xForwardedFor:m}){const g=new Date,{path:y,query:k,request:C}=J(i,s,o),f=v(h)?.userId;return{status:a,method:i,bytes_sent:u(n),referrer:""===r?void 0:r,request:C,request_time:u(c),integration_type:p,integration_version:l,client:e,user_agent:t,bc_type:""===d?void 0:d,hour:g.getUTCHours(),minute:g.getUTCMinutes(),"@timestamp":g.toISOString().replace("Z","+00:00"),path:y,protocol:o,query:k,user_id:f,x_forwarded_for:m}}constructV1WebLog({ip:e,userAgent:t,status:a,method:i,path:s,protocol:o,referer:r,bytesSent:n,requestTime:c,mitataCookie:h,sessionStatus:u,integrationType:d,integrationVersion:p,xForwardedFor:l}){const m=(new Date).toUTCString(),{request:g}=J(i,s,o);return{Request:g,TimeLocal:m,RealIp:e,UserAgent:t,Status:a,RequestTime:c?.toString(),BytesSent:n?.toString(),Referer:""===r?"-":r,NetaceaUserIdCookie:h??"",NetaceaMitigationApplied:u??"",IntegrationType:d??"",IntegrationVersion:p??"",XForwardedFor:l}}async makeIngestApiCall(e,t){return await this.makeRequest({host:this.ingestServiceUrl,method:"POST",path:"/",headers:e,body:JSON.stringify(t),timeout:this.timeout})}async processIngest(e){if(void 0===this.secretKey)throw new Error("Secret key is required for ingest");const t=this.getCookieHeader(e),a=I(await this.readCookie(this.netaceaCookieName,t),k,this.secretKey);return a.isPrimaryHashValid?a.requiresReissue?await this.setIngestOnlyMitataCookie(a.mitata?.userId):{sessionStatus:"",setCookie:[]}:await this.setIngestOnlyMitataCookie(void 0)}async setIngestOnlyMitataCookie(e){return{sessionStatus:"",setCookie:[await this.createMitata(k,e,0,0,0,86400)]}}findBestMitigation(e,t,a,i){const s="unknown";a=this.adjustCaptchaCode(a,i);let o=ee[e]??s+"_";o+=ae[t]??s;let r=ie[t];if(0!==a){o+=","+(oe[a]??s);const e=se[a];void 0!==e&&(r=e)}return this.mitigationType===n.INJECT&&(r=te.none),{sessionStatus:o,mitigation:r,parts:{match:e,mitigate:t,captcha:a}}}adjustCaptchaCode(e,t){let a=e;return t||(2===e?a=4:3===e&&(a=5)),a}async check(e,t,a,i,s,o){let r,n,c,h,u,d,p;if(void 0===this.secretKey)throw new Error("Secret key is required to mitigate");const l=I(e,t,this.secretKey);if(!l.isPrimaryHashValid||l.requiresReissue){const e=await this.makeMitigateAPICall({userId:l.mitata?.userId,clientIP:t,userAgent:a,captchaCookie:o,accept:i,host:s});r=e.status,n=e.match,c=e.mitigate,h=e.captcha,u=e.body,d=[await this.createMitata(t,l.mitata?.userId,n,c,h,e.mitataMaxAge)],p=e.eventId}else r=-1,n=l.match,c=l.mitigate,h=l.captcha,u=void 0,d=[];return this.composeResult(u,d,r,n,c,h,!1,p)}async makeMitigateAPICall({userId:e,clientIP:t,userAgent:a,captchaCookie:i,accept:s,host:o,isCaptchaGet:r=!1,defaultMitataCodes:n,trackingId:c}){const h={"X-Netacea-API-Key":this.apiKey,"X-Netacea-Client-IP":t,"user-agent":a,cookie:this.buildCookieHeader({_mitatacaptcha:i})};void 0!==e&&(h["X-Netacea-UserId"]=e),void 0!==this.captchaSiteKey&&void 0!==this.captchaSecretKey&&(h["X-Netacea-Captcha-Site-Key"]=this.captchaSiteKey,h["X-Netacea-Captcha-Secret-Key"]=this.captchaSecretKey),this.dynamicCaptchaContentType&&void 0!==this.netaceaCaptchaPath&&(h["X-Netacea-Captcha-Content-Type"]=function(e){const t=e?.toLowerCase()??"text/html",a=t?.includes("text/html")||t?.includes("application/html"),i=t?.includes("application/json");return i&&!a?"application/json":"text/html"}(s));const u="application/json"===h["X-Netacea-Captcha-Content-Type"],d=void 0!==c?`?trackingId=${c}`:"",p=await this.makeRequest({host:this.mitigationServiceUrl,path:r?`/captcha${d}`:"/",headers:h,method:"GET",timeout:this.timeout});return u&&void 0!==this.netaceaCaptchaPath&&(p.body=function(e,t,a){let i;if(void 0===e||""===e)return"";if("string"==typeof e&&(i=JSON.parse(e)),!function(e){if(null==e)return!1;const t=e;return void 0!==t?.captchaSiteKey&&void 0!==t?.trackingId&&void 0!==t?.captchaURL}(i))throw new Error("Body is not a Mitigation Service JSON response!");const s=`${a}?trackingId=${i.trackingId}`,o=`https://${t}${s}`;return JSON.stringify({captchaRelativeURL:s,captchaAbsoluteURL:o})}(p.body,o,this.netaceaCaptchaPath)),await this.getApiCallResponseFromResponse(p,e,t,n)}buildCookieHeader(e){let t="",a="";for(const i in e){const s=e[i];void 0!==s&&(t=`${t}${a}${i}=${s}`,a="; ")}return t}composeResult(e,t,a,i,s,o,r,c){const h=this.findBestMitigation(i,s,o,r),u={body:e,apiCallStatus:a,setCookie:t,sessionStatus:h.sessionStatus,mitigation:h.mitigation,mitigated:[te.block,te.captcha,te.captchaPass].includes(h.mitigation)};if(this.mitigationType===n.INJECT){const e={"x-netacea-match":h.parts.match.toString(),"x-netacea-mitigate":h.parts.mitigate.toString(),"x-netacea-captcha":h.parts.captcha.toString()};void 0!==c&&(e["x-netacea-event-id"]=c),u.injectHeaders=e}return u}}exports.Cloudfront=ne;
2
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@netacea/cloudfront",
3
- "version": "5.2.54",
3
+ "version": "6.0.2",
4
4
  "description": "Netacea Cloudfront CDN integration",
5
- "main": "dist/src/index.js",
6
- "types": "dist/src/index.d.ts",
5
+ "files": [
6
+ "dist/index.js",
7
+ "dist/index.d.ts"
8
+ ],
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
7
11
  "scripts": {
8
12
  "prepack": "npx netacea-bundler prepack",
9
13
  "postpack": "npx netacea-bundler postpack"
@@ -14,9 +18,10 @@
14
18
  },
15
19
  "license": "ISC",
16
20
  "dependencies": {
17
- "@netacea/netaceaintegrationbase": "^2.0.36",
21
+ "@types/aws-lambda": "^8.10.138",
22
+ "aws4": "1.11.0",
18
23
  "axios": "^0.21.0",
19
24
  "jose": "^4.11.2"
20
25
  },
21
- "gitHead": "6a7870a1569541c04f792429141980159d5beaf6"
26
+ "gitHead": "de302a0a43e52d7fbe01c36b5b00b6d756b2b5ee"
22
27
  }
@@ -1,21 +0,0 @@
1
- {
2
- "version": "0.2.0",
3
- "configurations": [
4
- {
5
- "type": "node",
6
- "request": "launch",
7
- "name": "Debug Tests",
8
- "program": "${workspaceFolder}/node_modules/.bin/mocha",
9
- "args": [
10
- "-r",
11
- "ts-node/register",
12
- "./tests/mocha/*.test.ts"
13
- ],
14
- "console": "internalConsole",
15
- "skipFiles": [
16
- "<node_internals>/**",
17
- "${workspaceFolder}/node_modules/**"
18
- ],
19
- }
20
- ]
21
- }
@@ -1,5 +0,0 @@
1
- {
2
- "cSpell.words": [
3
- "netaceaintegrationtestrunner"
4
- ]
5
- }