@netacea/f5 4.3.122 → 4.3.124
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/dist/index.d.ts +549 -0
- package/dist/index.js +2 -0
- package/package.json +9 -6
- package/CHANGELOG.md +0 -2019
- package/dist/package.json +0 -50
- package/dist/src/F5.d.ts +0 -166
- package/dist/src/F5.js +0 -681
- package/dist/src/F5.js.map +0 -1
- package/dist/src/index.d.ts +0 -3
- package/dist/src/index.js +0 -5
- package/dist/src/index.js.map +0 -1
- package/package.json.bak +0 -50
package/dist/src/F5.js
DELETED
|
@@ -1,681 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const netaceaintegrationbase_1 = require("@netacea/netaceaintegrationbase");
|
|
4
|
-
const https = require("https");
|
|
5
|
-
const pack = require("../package.json");
|
|
6
|
-
const kinesisingest_1 = require("@netacea/kinesisingest");
|
|
7
|
-
const defaultTimeout = 3000; // 3 seconds?
|
|
8
|
-
const ONE_HOUR_IN_SECONDS = 60 * 60;
|
|
9
|
-
const ONE_DAY_IN_SECONDS = ONE_HOUR_IN_SECONDS * 24;
|
|
10
|
-
class NetaceaBase {
|
|
11
|
-
constructor({ apiKey, secretKey, timeout = defaultTimeout, mitigationServiceUrl = 'https://mitigations.netacea.net', ingestServiceUrl = 'https://ingest.netacea.net', mitigationType = netaceaintegrationbase_1.NetaceaMitigationType.INGEST, captchaSiteKey, captchaSecretKey, ingestType = netaceaintegrationbase_1.NetaceaIngestType.HTTP, kinesis, mitataCookieExpirySeconds, netaceaCookieExpirySeconds, netaceaCookieName, netaceaCaptchaCookieName }) {
|
|
12
|
-
this.encryptedCookies = [];
|
|
13
|
-
if (apiKey === null || apiKey === undefined) {
|
|
14
|
-
throw new Error('apiKey is a required parameter');
|
|
15
|
-
}
|
|
16
|
-
this.apiKey = apiKey;
|
|
17
|
-
this.secretKey = secretKey;
|
|
18
|
-
this.mitigationServiceUrl = mitigationServiceUrl;
|
|
19
|
-
this.ingestServiceUrl = ingestServiceUrl;
|
|
20
|
-
this.mitigationType = mitigationType;
|
|
21
|
-
this.ingestType = ingestType !== null && ingestType !== void 0 ? ingestType : netaceaintegrationbase_1.NetaceaIngestType.HTTP;
|
|
22
|
-
if (this.ingestType === netaceaintegrationbase_1.NetaceaIngestType.KINESIS) {
|
|
23
|
-
if (kinesis === undefined) {
|
|
24
|
-
console.warn(`NETACEA WARN: no kinesis args provided, when ingestType is ${this.ingestType}`);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
this.kinesis = new kinesisingest_1.default({
|
|
28
|
-
...kinesis,
|
|
29
|
-
apiKey: this.apiKey
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
if (captchaSiteKey !== undefined || captchaSecretKey !== undefined) {
|
|
34
|
-
this.captchaSiteKey = captchaSiteKey;
|
|
35
|
-
this.captchaSecretKey = captchaSecretKey;
|
|
36
|
-
}
|
|
37
|
-
this.timeout = (0, netaceaintegrationbase_1.correctTimeout)(timeout);
|
|
38
|
-
this.netaceaCookieName = netaceaCookieName !== null && netaceaCookieName !== void 0 ? netaceaCookieName : '_mitata';
|
|
39
|
-
this.netaceaCaptchaCookieName = netaceaCaptchaCookieName !== null && netaceaCaptchaCookieName !== void 0 ? netaceaCaptchaCookieName : '_mitatacaptcha';
|
|
40
|
-
this.encryptedCookies = [
|
|
41
|
-
this.netaceaCookieName,
|
|
42
|
-
this.netaceaCaptchaCookieName
|
|
43
|
-
];
|
|
44
|
-
this.mitataCookieExpirySeconds = (0, netaceaintegrationbase_1.configureMitataExpiry)(mitigationType, netaceaCookieExpirySeconds !== null && netaceaCookieExpirySeconds !== void 0 ? netaceaCookieExpirySeconds : mitataCookieExpirySeconds);
|
|
45
|
-
}
|
|
46
|
-
async runMitigation(args) {
|
|
47
|
-
try {
|
|
48
|
-
switch (this.mitigationType) {
|
|
49
|
-
case netaceaintegrationbase_1.NetaceaMitigationType.MITIGATE:
|
|
50
|
-
return await this.mitigate(args);
|
|
51
|
-
case netaceaintegrationbase_1.NetaceaMitigationType.INJECT:
|
|
52
|
-
return await this.inject(args);
|
|
53
|
-
case netaceaintegrationbase_1.NetaceaMitigationType.INGEST:
|
|
54
|
-
return await this.processIngest(args);
|
|
55
|
-
default:
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
57
|
-
throw new Error(`Netacea Error: Mitigation type ${this.mitigationType} not recognised`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
console.error('Netacea FAILOPEN Error:', e);
|
|
62
|
-
const requestArgs = args;
|
|
63
|
-
const isCaptchaPost = this.isUrlCaptchaPost(requestArgs.url, requestArgs.method);
|
|
64
|
-
const isMitigate = this.mitigationType === netaceaintegrationbase_1.NetaceaMitigationType.MITIGATE;
|
|
65
|
-
return {
|
|
66
|
-
injectHeaders: {
|
|
67
|
-
'x-netacea-captcha': '0',
|
|
68
|
-
'x-netacea-match': '0',
|
|
69
|
-
'x-netacea-mitigate': '0'
|
|
70
|
-
},
|
|
71
|
-
sessionStatus: isMitigate && isCaptchaPost ? 'error_open' : ''
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Returns the value of the cookie with the given name from a string or list of cookies.
|
|
77
|
-
* If the cookie name is included in the encryptedCookies class property,
|
|
78
|
-
* then the cookie value will be decrypted automatically.
|
|
79
|
-
* The method may operate of either the HTTP Cookie or Set-Cookie headers.
|
|
80
|
-
* @param cookieName the name of the cookie to find.
|
|
81
|
-
* @param cookies the full list of cookies, either as a string or an array of strings.
|
|
82
|
-
* @returns the value of the cookie, if found.
|
|
83
|
-
*/
|
|
84
|
-
async readCookie(cookieName, cookies) {
|
|
85
|
-
if (cookies === null || cookies === undefined) {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
if (typeof cookies === 'string') {
|
|
89
|
-
return await this.readCookie(cookieName, cookies.split(';'));
|
|
90
|
-
}
|
|
91
|
-
const valuePrefix = `${cookieName}=`;
|
|
92
|
-
for (const cookie of cookies) {
|
|
93
|
-
// split again on ; to handle Set-Cookie header format.
|
|
94
|
-
const trimmedCookie = cookie.split(';')[0].trimStart();
|
|
95
|
-
if (trimmedCookie.startsWith(valuePrefix)) {
|
|
96
|
-
const cookieValue = trimmedCookie.slice(valuePrefix.length);
|
|
97
|
-
if (this.encryptedCookies.includes(cookieName)) {
|
|
98
|
-
try {
|
|
99
|
-
return await this.decryptCookieValue(cookieValue);
|
|
100
|
-
}
|
|
101
|
-
catch (_e) {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return cookieValue;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
async callIngest(args) {
|
|
111
|
-
const body = this.constructWebLog(args);
|
|
112
|
-
if (this.ingestType === netaceaintegrationbase_1.NetaceaIngestType.KINESIS) {
|
|
113
|
-
if (this.kinesis === undefined) {
|
|
114
|
-
console.error('Netacea Error: Unable to log as Kinesis has not been defined.');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
await this.kinesis.ingest({
|
|
119
|
-
...body,
|
|
120
|
-
apiKey: this.apiKey
|
|
121
|
-
}, this.makeRequest.bind(this));
|
|
122
|
-
}
|
|
123
|
-
catch (e) {
|
|
124
|
-
console.error('NETACEA Error: ', e.message);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
const headers = {
|
|
129
|
-
'X-Netacea-API-Key': this.apiKey,
|
|
130
|
-
'content-type': 'application/json'
|
|
131
|
-
};
|
|
132
|
-
const res = await this.makeIngestApiCall(headers, body);
|
|
133
|
-
if (res.status !== 200) {
|
|
134
|
-
throw this.APIError(res);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
async makeIngestApiCall(headers, body) {
|
|
139
|
-
return await this.makeRequest({
|
|
140
|
-
host: this.ingestServiceUrl,
|
|
141
|
-
method: 'POST',
|
|
142
|
-
path: '/',
|
|
143
|
-
headers,
|
|
144
|
-
body: JSON.stringify(body),
|
|
145
|
-
timeout: this.timeout
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
constructV1WebLog({ ip, userAgent, status, method, path, protocol, referer, bytesSent, requestTime, mitataCookie, sessionStatus, integrationType, integrationVersion }) {
|
|
149
|
-
const timestamp = new Date().toUTCString();
|
|
150
|
-
return {
|
|
151
|
-
Request: `${method} ${path} ${protocol}`,
|
|
152
|
-
TimeLocal: timestamp,
|
|
153
|
-
RealIp: ip,
|
|
154
|
-
UserAgent: userAgent,
|
|
155
|
-
Status: status,
|
|
156
|
-
RequestTime: requestTime === null || requestTime === void 0 ? void 0 : requestTime.toString(),
|
|
157
|
-
BytesSent: bytesSent === null || bytesSent === void 0 ? void 0 : bytesSent.toString(),
|
|
158
|
-
Referer: referer === '' ? '-' : referer,
|
|
159
|
-
NetaceaUserIdCookie: mitataCookie !== null && mitataCookie !== void 0 ? mitataCookie : '',
|
|
160
|
-
NetaceaMitigationApplied: sessionStatus !== null && sessionStatus !== void 0 ? sessionStatus : '',
|
|
161
|
-
IntegrationType: integrationType !== null && integrationType !== void 0 ? integrationType : '',
|
|
162
|
-
IntegrationVersion: integrationVersion !== null && integrationVersion !== void 0 ? integrationVersion : ''
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
constructWebLog(args) {
|
|
166
|
-
args.bytesSent = args.bytesSent === '' ? '0' : args.bytesSent;
|
|
167
|
-
return this.constructV1WebLog(args);
|
|
168
|
-
}
|
|
169
|
-
async check(netaceaCookie, clientIP, userAgent, captchaCookie) {
|
|
170
|
-
var _a, _b;
|
|
171
|
-
let status, match, mitigate, captcha, body, setCookie, eventId;
|
|
172
|
-
if (this.secretKey === undefined) {
|
|
173
|
-
throw new Error('Secret key is required to mitigate');
|
|
174
|
-
}
|
|
175
|
-
const cookieInfo = (0, netaceaintegrationbase_1.checkMitataCookie)(netaceaCookie, clientIP, this.secretKey);
|
|
176
|
-
if (!cookieInfo.isPrimaryHashValid || cookieInfo.requiresReissue) {
|
|
177
|
-
// Get latest mitigation information
|
|
178
|
-
const result = await this.makeMitigateAPICall((_a = cookieInfo.mitata) === null || _a === void 0 ? void 0 : _a.userId, clientIP, userAgent, captchaCookie);
|
|
179
|
-
status = result.status;
|
|
180
|
-
match = result.match;
|
|
181
|
-
mitigate = result.mitigate;
|
|
182
|
-
captcha = result.captcha;
|
|
183
|
-
body = result.body;
|
|
184
|
-
setCookie = [
|
|
185
|
-
await this.createMitata(clientIP, (_b = cookieInfo.mitata) === null || _b === void 0 ? void 0 : _b.userId, match, mitigate, captcha, result.mitataMaxAge)
|
|
186
|
-
];
|
|
187
|
-
eventId = result.eventId;
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
status = -1;
|
|
191
|
-
match = cookieInfo.match;
|
|
192
|
-
mitigate = cookieInfo.mitigate;
|
|
193
|
-
captcha = cookieInfo.captcha;
|
|
194
|
-
body = undefined;
|
|
195
|
-
setCookie = [];
|
|
196
|
-
}
|
|
197
|
-
return this.composeResult(body, setCookie, status, match, mitigate, captcha, false, eventId);
|
|
198
|
-
}
|
|
199
|
-
async createMitata(clientIP, userId, match, mitigate, captcha, maxAge = 86400, expiry = undefined) {
|
|
200
|
-
// serve, fail, cookiefail
|
|
201
|
-
const isCaptchaServe = ['1', '3', '5'].includes(captcha);
|
|
202
|
-
const isHardBlocked = mitigate === '3';
|
|
203
|
-
const expiryDelta = (isCaptchaServe || isHardBlocked)
|
|
204
|
-
? -60
|
|
205
|
-
: this.mitataCookieExpirySeconds;
|
|
206
|
-
const mitataExpiry = expiry !== null && expiry !== void 0 ? expiry : Math.floor(Date.now() / 1000) + expiryDelta;
|
|
207
|
-
if (this.secretKey === undefined) {
|
|
208
|
-
throw new Error('Cannot build cookie without secret key.');
|
|
209
|
-
}
|
|
210
|
-
const mitataCode = [match, mitigate, captcha].join('');
|
|
211
|
-
const mitataValue = (0, netaceaintegrationbase_1.createMitataCookie)(clientIP, userId, mitataExpiry, this.secretKey, mitataCode);
|
|
212
|
-
return await this.buildCookieFromValues(this.netaceaCookieName, mitataValue, maxAge, '/');
|
|
213
|
-
}
|
|
214
|
-
async processCaptcha(netaceaCookie, clientIP, userAgent, captchaData) {
|
|
215
|
-
const { status, match, mitigate, captcha, body, setCookie } = await this.makeCaptchaAPICall(netaceaCookie, clientIP, userAgent, captchaData);
|
|
216
|
-
return this.composeResult(body, setCookie, status, match, mitigate, captcha, true);
|
|
217
|
-
}
|
|
218
|
-
async getMitataCaptchaFromHeaders(headers) {
|
|
219
|
-
if (Object.prototype.hasOwnProperty.call(headers, netaceaintegrationbase_1.dictionary.netaceaHeaders.mitataCaptcha)) {
|
|
220
|
-
const mitataCaptcha = headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.mitataCaptcha];
|
|
221
|
-
const mitataCaptchaExpiry = parseInt(headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.mitataCaptchaExpiry]);
|
|
222
|
-
const mitataCaptchaCookie = await this.buildCookieFromValues(this.netaceaCaptchaCookieName, mitataCaptcha, mitataCaptchaExpiry);
|
|
223
|
-
if (mitataCaptchaCookie !== undefined) {
|
|
224
|
-
return mitataCaptchaCookie;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return undefined;
|
|
228
|
-
}
|
|
229
|
-
async makeCaptchaAPICall(netaceaCookie, clientIP, userAgent, captchaData) {
|
|
230
|
-
const headers = {
|
|
231
|
-
'X-Netacea-API-Key': this.apiKey,
|
|
232
|
-
'X-Netacea-Client-IP': clientIP,
|
|
233
|
-
'user-agent': userAgent,
|
|
234
|
-
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
|
235
|
-
};
|
|
236
|
-
const mitata = (0, netaceaintegrationbase_1.matchMitataCookie)(netaceaCookie);
|
|
237
|
-
if (mitata !== undefined) {
|
|
238
|
-
headers['X-Netacea-UserId'] = mitata.userId;
|
|
239
|
-
}
|
|
240
|
-
if (this.captchaSiteKey !== undefined && this.captchaSecretKey !== undefined) {
|
|
241
|
-
headers['X-Netacea-Captcha-Site-Key'] = this.captchaSiteKey;
|
|
242
|
-
headers['X-Netacea-Captcha-Secret-Key'] = this.captchaSecretKey;
|
|
243
|
-
}
|
|
244
|
-
const res = await this.makeRequest({
|
|
245
|
-
host: this.mitigationServiceUrl,
|
|
246
|
-
path: '/AtaVerifyCaptcha',
|
|
247
|
-
headers,
|
|
248
|
-
method: 'POST',
|
|
249
|
-
body: captchaData,
|
|
250
|
-
timeout: this.timeout
|
|
251
|
-
});
|
|
252
|
-
return await this.getApiCallResponseFromResponse(res, mitata === null || mitata === void 0 ? void 0 : mitata.userId, clientIP);
|
|
253
|
-
}
|
|
254
|
-
async getApiCallResponseFromResponse(response, userId, clientIP) {
|
|
255
|
-
var _a, _b, _c, _d, _f, _g;
|
|
256
|
-
if (response.status !== 200) {
|
|
257
|
-
throw this.APIError(response);
|
|
258
|
-
}
|
|
259
|
-
// TODO: why does .toString() fix this?
|
|
260
|
-
const match = (_b = (_a = response.headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.match]) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '0';
|
|
261
|
-
const mitigate = (_d = (_c = response.headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.mitigate]) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : '0';
|
|
262
|
-
const captcha = (_g = (_f = response.headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.captcha]) === null || _f === void 0 ? void 0 : _f.toString()) !== null && _g !== void 0 ? _g : '0';
|
|
263
|
-
let mitataMaxAge = parseInt(response.headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.mitataExpiry]);
|
|
264
|
-
if (isNaN(mitataMaxAge)) {
|
|
265
|
-
mitataMaxAge = 86400;
|
|
266
|
-
}
|
|
267
|
-
const mitata = await this.createMitata(clientIP, userId, match, mitigate, captcha);
|
|
268
|
-
const mitataCaptcha = await this.getMitataCaptchaFromHeaders(response.headers);
|
|
269
|
-
const setCookie = [
|
|
270
|
-
mitata,
|
|
271
|
-
mitataCaptcha
|
|
272
|
-
].filter(c => c !== undefined);
|
|
273
|
-
const eventId = response.headers[netaceaintegrationbase_1.dictionary.netaceaHeaders.eventId];
|
|
274
|
-
return {
|
|
275
|
-
status: response.status,
|
|
276
|
-
match,
|
|
277
|
-
mitigate,
|
|
278
|
-
captcha,
|
|
279
|
-
setCookie,
|
|
280
|
-
body: response.body,
|
|
281
|
-
eventId,
|
|
282
|
-
mitataMaxAge
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
async buildCookieFromValues(cookieName, value, maxAge, path = '/') {
|
|
286
|
-
if (this.encryptedCookies.includes(cookieName)) {
|
|
287
|
-
const encyptedValue = await this.encryptCookieValue(value);
|
|
288
|
-
return `${cookieName}=${encyptedValue}; Max-Age=${maxAge}; Path=${path}`;
|
|
289
|
-
}
|
|
290
|
-
return `${cookieName}=${value}; Max-Age=${maxAge}; Path=${path}`;
|
|
291
|
-
}
|
|
292
|
-
buildCookieHeader(cookies) {
|
|
293
|
-
let cookiestr = '';
|
|
294
|
-
let separator = '';
|
|
295
|
-
for (const cookie in cookies) {
|
|
296
|
-
const cookieValue = cookies[cookie];
|
|
297
|
-
if (cookieValue !== undefined) {
|
|
298
|
-
cookiestr = `${cookiestr}${separator}${cookie}=${cookieValue}`;
|
|
299
|
-
separator = '; ';
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return cookiestr;
|
|
303
|
-
}
|
|
304
|
-
async makeMitigateAPICall(userId, clientIP, userAgent, captchaCookie) {
|
|
305
|
-
const headers = {
|
|
306
|
-
'X-Netacea-API-Key': this.apiKey,
|
|
307
|
-
'X-Netacea-Client-IP': clientIP,
|
|
308
|
-
'user-agent': userAgent,
|
|
309
|
-
cookie: this.buildCookieHeader({
|
|
310
|
-
_mitatacaptcha: captchaCookie
|
|
311
|
-
})
|
|
312
|
-
};
|
|
313
|
-
if (userId !== undefined) {
|
|
314
|
-
headers['X-Netacea-UserId'] = userId;
|
|
315
|
-
}
|
|
316
|
-
if (this.captchaSiteKey !== undefined && this.captchaSecretKey !== undefined) {
|
|
317
|
-
headers['X-Netacea-Captcha-Site-Key'] = this.captchaSiteKey;
|
|
318
|
-
headers['X-Netacea-Captcha-Secret-Key'] = this.captchaSecretKey;
|
|
319
|
-
}
|
|
320
|
-
const res = await this.makeRequest({
|
|
321
|
-
host: this.mitigationServiceUrl,
|
|
322
|
-
path: '/',
|
|
323
|
-
headers,
|
|
324
|
-
method: 'GET',
|
|
325
|
-
timeout: this.timeout
|
|
326
|
-
});
|
|
327
|
-
return await this.getApiCallResponseFromResponse(res, userId, clientIP);
|
|
328
|
-
}
|
|
329
|
-
composeResult(body, setCookie, status, match, mitigate, captcha, isCaptchaPost, eventId) {
|
|
330
|
-
const bestMitigation = this.findBestMitigation(match, mitigate, captcha, isCaptchaPost);
|
|
331
|
-
const result = {
|
|
332
|
-
body,
|
|
333
|
-
apiCallStatus: status,
|
|
334
|
-
setCookie,
|
|
335
|
-
sessionStatus: bestMitigation.sessionStatus,
|
|
336
|
-
mitigation: bestMitigation.mitigation,
|
|
337
|
-
mitigated: [
|
|
338
|
-
netaceaintegrationbase_1.dictionary.mitigationTypes.block,
|
|
339
|
-
netaceaintegrationbase_1.dictionary.mitigationTypes.captcha,
|
|
340
|
-
netaceaintegrationbase_1.dictionary.mitigationTypes.captchaPass
|
|
341
|
-
].includes(bestMitigation.mitigation)
|
|
342
|
-
};
|
|
343
|
-
if (this.mitigationType === netaceaintegrationbase_1.NetaceaMitigationType.INJECT) {
|
|
344
|
-
const injectHeaders = {
|
|
345
|
-
'x-netacea-match': bestMitigation.parts.match.toString(),
|
|
346
|
-
'x-netacea-mitigate': bestMitigation.parts.mitigate.toString(),
|
|
347
|
-
'x-netacea-captcha': bestMitigation.parts.captcha.toString()
|
|
348
|
-
};
|
|
349
|
-
if (eventId !== undefined) {
|
|
350
|
-
injectHeaders['x-netacea-event-id'] = eventId;
|
|
351
|
-
}
|
|
352
|
-
result.injectHeaders = injectHeaders;
|
|
353
|
-
}
|
|
354
|
-
return result;
|
|
355
|
-
}
|
|
356
|
-
findBestMitigation(match, mitigate, captcha, isCaptchaPost) {
|
|
357
|
-
var _a, _b, _c;
|
|
358
|
-
const UNKNOWN = 'unknown';
|
|
359
|
-
if (!isCaptchaPost) {
|
|
360
|
-
if (captcha === '2') {
|
|
361
|
-
captcha = '4';
|
|
362
|
-
}
|
|
363
|
-
else if (captcha === '3') {
|
|
364
|
-
captcha = '5';
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
let sessionStatus = (_a = netaceaintegrationbase_1.dictionary.matchMap[match]) !== null && _a !== void 0 ? _a : (UNKNOWN + '_');
|
|
368
|
-
sessionStatus += (_b = netaceaintegrationbase_1.dictionary.mitigateMap[mitigate]) !== null && _b !== void 0 ? _b : UNKNOWN;
|
|
369
|
-
let mitigation = netaceaintegrationbase_1.dictionary.bestMitigationMap[mitigate];
|
|
370
|
-
if (captcha !== '0') {
|
|
371
|
-
sessionStatus += ',' + ((_c = netaceaintegrationbase_1.dictionary.captchaMap[captcha]) !== null && _c !== void 0 ? _c : UNKNOWN);
|
|
372
|
-
const bestCaptchaMitigation = netaceaintegrationbase_1.dictionary.bestMitigationCaptchaMap[captcha];
|
|
373
|
-
if (bestCaptchaMitigation !== undefined) {
|
|
374
|
-
mitigation = bestCaptchaMitigation;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
if (this.mitigationType === netaceaintegrationbase_1.NetaceaMitigationType.INJECT) {
|
|
378
|
-
mitigation = netaceaintegrationbase_1.dictionary.mitigationTypes.none;
|
|
379
|
-
}
|
|
380
|
-
return {
|
|
381
|
-
sessionStatus,
|
|
382
|
-
mitigation,
|
|
383
|
-
parts: {
|
|
384
|
-
match,
|
|
385
|
-
mitigate,
|
|
386
|
-
captcha
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
APIError(response) {
|
|
391
|
-
let message = 'Unknown error';
|
|
392
|
-
switch (response.status) {
|
|
393
|
-
case 403:
|
|
394
|
-
message = 'Invalid credentials';
|
|
395
|
-
break;
|
|
396
|
-
case 500:
|
|
397
|
-
message = 'Server error';
|
|
398
|
-
break;
|
|
399
|
-
case 502:
|
|
400
|
-
message = 'Bad Gateway';
|
|
401
|
-
break;
|
|
402
|
-
case 503:
|
|
403
|
-
message = 'Service Unavailable';
|
|
404
|
-
break;
|
|
405
|
-
case 400:
|
|
406
|
-
message = 'Invalid request';
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
return new Error(`Error reaching Netacea API (${message}), status: ${response.status}`);
|
|
410
|
-
}
|
|
411
|
-
isUrlCaptchaPost(url, method) {
|
|
412
|
-
return url.includes('/AtaVerifyCaptcha') && method.toLowerCase() === 'post';
|
|
413
|
-
}
|
|
414
|
-
async processMitigateRequest(args) {
|
|
415
|
-
const isCaptchaPost = this.isUrlCaptchaPost(args.url, args.method);
|
|
416
|
-
return await (isCaptchaPost
|
|
417
|
-
? this.processCaptcha(args.mitata, args.clientIp, args.userAgent, await args.getBodyFn())
|
|
418
|
-
: this.check(args.mitata, args.clientIp, args.userAgent, args.mitataCaptcha));
|
|
419
|
-
}
|
|
420
|
-
async setIngestOnlyMitataCookie(userId) {
|
|
421
|
-
const mitataCookie = await this.createMitata(netaceaintegrationbase_1.ingestIgnoredIpValue, userId, '0', '0', '0', ONE_DAY_IN_SECONDS);
|
|
422
|
-
return {
|
|
423
|
-
sessionStatus: '',
|
|
424
|
-
setCookie: [mitataCookie]
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
async processIngest(args) {
|
|
428
|
-
var _a;
|
|
429
|
-
if (this.secretKey === undefined) {
|
|
430
|
-
throw new Error('Secret key is required for ingest');
|
|
431
|
-
}
|
|
432
|
-
const cookies = this.getCookieHeader(args);
|
|
433
|
-
const netaceaCookie = await this.readCookie(this.netaceaCookieName, cookies);
|
|
434
|
-
const cookieInfo = (0, netaceaintegrationbase_1.checkMitataCookie)(netaceaCookie, netaceaintegrationbase_1.ingestIgnoredIpValue, this.secretKey);
|
|
435
|
-
if (!cookieInfo.isPrimaryHashValid) {
|
|
436
|
-
return await this.setIngestOnlyMitataCookie(undefined);
|
|
437
|
-
}
|
|
438
|
-
if (cookieInfo.requiresReissue) {
|
|
439
|
-
return await this.setIngestOnlyMitataCookie((_a = cookieInfo.mitata) === null || _a === void 0 ? void 0 : _a.userId);
|
|
440
|
-
}
|
|
441
|
-
return {
|
|
442
|
-
sessionStatus: '',
|
|
443
|
-
setCookie: []
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
async encryptCookieValue(cookieValue) {
|
|
447
|
-
return cookieValue;
|
|
448
|
-
}
|
|
449
|
-
async decryptCookieValue(encryptedCookieValue) {
|
|
450
|
-
return encryptedCookieValue;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
class F5 extends NetaceaBase {
|
|
454
|
-
constructor(args) {
|
|
455
|
-
var _a, _b;
|
|
456
|
-
super(args);
|
|
457
|
-
if (args.maxSockets === undefined) {
|
|
458
|
-
args.maxSockets = 25;
|
|
459
|
-
}
|
|
460
|
-
this.httpsAgent = new https.Agent({
|
|
461
|
-
timeout: this.timeout,
|
|
462
|
-
keepAlive: true,
|
|
463
|
-
maxSockets: args.maxSockets
|
|
464
|
-
});
|
|
465
|
-
this.mitataCookieName = (_a = args.netaceaCookieName) !== null && _a !== void 0 ? _a : '_mitata';
|
|
466
|
-
this.mitataCaptchaCookieName = (_b = args.netaceaCaptchaCookieName) !== null && _b !== void 0 ? _b : '_mitatacaptcha';
|
|
467
|
-
}
|
|
468
|
-
getInjectHeaders(netaceaResult) {
|
|
469
|
-
var _a, _b, _c, _d;
|
|
470
|
-
if (this.mitigationType === netaceaintegrationbase_1.NetaceaMitigationType.INJECT) {
|
|
471
|
-
const injectRes = netaceaResult;
|
|
472
|
-
if (injectRes.injectHeaders !== undefined) {
|
|
473
|
-
return [
|
|
474
|
-
(_a = injectRes.injectHeaders['x-netacea-match']) !== null && _a !== void 0 ? _a : '0',
|
|
475
|
-
(_b = injectRes.injectHeaders['x-netacea-mitigate']) !== null && _b !== void 0 ? _b : '0',
|
|
476
|
-
(_c = injectRes.injectHeaders['x-netacea-captcha']) !== null && _c !== void 0 ? _c : '0',
|
|
477
|
-
(_d = injectRes.injectHeaders['x-netacea-event-id']) !== null && _d !== void 0 ? _d : ''
|
|
478
|
-
];
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
return [];
|
|
482
|
-
}
|
|
483
|
-
registerMitigateHandler(ilx) {
|
|
484
|
-
ilx.addMethod('handleRequest', async (req, res) => {
|
|
485
|
-
const params = req.params();
|
|
486
|
-
const [ip, userAgent, method, url, cookieHeader] = params;
|
|
487
|
-
const body = params.length === 6 ? this.getArrayValueOrDefault(params, 5, undefined) : undefined;
|
|
488
|
-
try {
|
|
489
|
-
const [mitataCookie, mitataCaptchaCookie] = this.getMitataCookies(cookieHeader);
|
|
490
|
-
const netaceaResult = await this.runMitigation({
|
|
491
|
-
ip,
|
|
492
|
-
method,
|
|
493
|
-
url,
|
|
494
|
-
mitataCaptchaCookie,
|
|
495
|
-
mitataCookie,
|
|
496
|
-
userAgent,
|
|
497
|
-
body
|
|
498
|
-
});
|
|
499
|
-
if ((netaceaResult === null || netaceaResult === void 0 ? void 0 : netaceaResult.sessionStatus) === 'error_open') {
|
|
500
|
-
res.reply(['', 500, [], 'error_open', true, '', []]);
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
if (netaceaResult === undefined) {
|
|
504
|
-
res.reply(['', 0, [], '', false, '', []]);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
let responseBody = '';
|
|
508
|
-
let apiCallStatus = 0;
|
|
509
|
-
let mitigated = false;
|
|
510
|
-
let mitata = this.getValueOrDefault(mitataCookie, '');
|
|
511
|
-
if (netaceaResult.setCookie !== undefined && netaceaResult.setCookie.length > 0) {
|
|
512
|
-
const mitataCookie = netaceaResult.setCookie.find(f => f.includes(`${this.netaceaCookieName}=`));
|
|
513
|
-
if (mitataCookie !== undefined) {
|
|
514
|
-
mitata = mitataCookie.split(';')[0].replace(`${this.netaceaCookieName}=`, '');
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
if (netaceaResult.response !== undefined) {
|
|
518
|
-
apiCallStatus = netaceaResult.response.apiCallStatus;
|
|
519
|
-
responseBody = this.getValueOrDefault(netaceaResult.response.body, 'Forbidden');
|
|
520
|
-
mitigated = this.getValueOrDefault(netaceaResult.response.mitigated, mitigated);
|
|
521
|
-
}
|
|
522
|
-
res.reply([
|
|
523
|
-
responseBody,
|
|
524
|
-
apiCallStatus,
|
|
525
|
-
this.getValueOrDefault(netaceaResult.setCookie, []),
|
|
526
|
-
netaceaResult.sessionStatus,
|
|
527
|
-
mitigated,
|
|
528
|
-
this.getValueOrDefault(mitata, ''),
|
|
529
|
-
this.getInjectHeaders(netaceaResult)
|
|
530
|
-
]);
|
|
531
|
-
}
|
|
532
|
-
catch (err) {
|
|
533
|
-
console.error('Could not reach Netacea mitigation API: ', err.message);
|
|
534
|
-
res.reply(['', 0, [], '', false, '', []]);
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
getValueOrDefault(value, defaultVal) {
|
|
539
|
-
return value !== null && value !== void 0 ? value : defaultVal;
|
|
540
|
-
}
|
|
541
|
-
getArrayValueOrDefault(args, index, defaultVal) {
|
|
542
|
-
var _a;
|
|
543
|
-
return (_a = args[index]) !== null && _a !== void 0 ? _a : defaultVal;
|
|
544
|
-
}
|
|
545
|
-
getMitataCookies(cookieHeader) {
|
|
546
|
-
const cookies = cookieHeader === null || cookieHeader === void 0 ? void 0 : cookieHeader.split('; ');
|
|
547
|
-
const mitataCookie = this.getCookie(this.mitataCookieName, cookies);
|
|
548
|
-
const mitataCaptchaCookie = this.getCookie(this.mitataCaptchaCookieName, cookies);
|
|
549
|
-
return [mitataCookie, mitataCaptchaCookie];
|
|
550
|
-
}
|
|
551
|
-
getCookie(cookieName, cookies) {
|
|
552
|
-
var _a;
|
|
553
|
-
return (_a = cookies === null || cookies === void 0 ? void 0 : cookies.find(c => c.includes(`${cookieName}=`))) === null || _a === void 0 ? void 0 : _a.replace(`${cookieName}=`, '');
|
|
554
|
-
}
|
|
555
|
-
registerIngestHandler(ilx) {
|
|
556
|
-
ilx.addMethod('ingest', (req, res) => {
|
|
557
|
-
const params = req.params();
|
|
558
|
-
const ip = this.getArrayValueOrDefault(params, 0, '');
|
|
559
|
-
const userAgent = this.getArrayValueOrDefault(params, 1, '');
|
|
560
|
-
const status = this.getArrayValueOrDefault(params, 2, '-1');
|
|
561
|
-
const method = this.getArrayValueOrDefault(params, 3, '');
|
|
562
|
-
const path = this.getArrayValueOrDefault(params, 4, '');
|
|
563
|
-
const protocol = this.getArrayValueOrDefault(params, 5, '');
|
|
564
|
-
const referer = this.getArrayValueOrDefault(params, 6, '');
|
|
565
|
-
const bytesSent = this.getArrayValueOrDefault(params, 7, '0');
|
|
566
|
-
const requestTime = this.getArrayValueOrDefault(params, 8, '0');
|
|
567
|
-
const mitataCookie = this.getArrayValueOrDefault(params, 9, '');
|
|
568
|
-
const sessionStatus = this.getArrayValueOrDefault(params, 10, '');
|
|
569
|
-
this.ingest({
|
|
570
|
-
ip, userAgent, status, method, path, protocol, referer, bytesSent, requestTime, mitataCookie, sessionStatus
|
|
571
|
-
}).catch((err) => {
|
|
572
|
-
console.error('Could not reach Netacea ingest API: ' + err.message);
|
|
573
|
-
});
|
|
574
|
-
res.reply('done');
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
async makeRequest(args) {
|
|
578
|
-
return await new Promise((resolve, reject) => {
|
|
579
|
-
args.host = args.host.replace('https://', '');
|
|
580
|
-
// @ts-expect-error no body exists in type
|
|
581
|
-
const request = https.request({
|
|
582
|
-
agent: this.httpsAgent,
|
|
583
|
-
host: args.host,
|
|
584
|
-
path: args.path,
|
|
585
|
-
headers: args.headers,
|
|
586
|
-
method: args.method,
|
|
587
|
-
body: args.body
|
|
588
|
-
}, (res) => {
|
|
589
|
-
let body = '';
|
|
590
|
-
res.on('data', (data) => {
|
|
591
|
-
body += data;
|
|
592
|
-
});
|
|
593
|
-
res.on('end', () => {
|
|
594
|
-
var _a;
|
|
595
|
-
resolve({
|
|
596
|
-
headers: res.headers,
|
|
597
|
-
status: (_a = res.statusCode) !== null && _a !== void 0 ? _a : 0,
|
|
598
|
-
body: body === '' ? undefined : body
|
|
599
|
-
});
|
|
600
|
-
});
|
|
601
|
-
});
|
|
602
|
-
const events = ['error', 'abort', 'timeout'];
|
|
603
|
-
for (const e of events) {
|
|
604
|
-
request.on(e, (err) => {
|
|
605
|
-
reject(err);
|
|
606
|
-
// This is a boolean, typedefs are a bit out of date
|
|
607
|
-
// https://nodejs.org/api/http.html#http_request_aborted
|
|
608
|
-
if (!request.destroyed) {
|
|
609
|
-
request.destroy();
|
|
610
|
-
}
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
if (args.method.toLowerCase() === 'post') {
|
|
614
|
-
request.write(args.body);
|
|
615
|
-
}
|
|
616
|
-
request.end();
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
async mitigate(args) {
|
|
620
|
-
var _a, _b;
|
|
621
|
-
const check = await this.getMitigationResponse(args);
|
|
622
|
-
const response = {
|
|
623
|
-
sessionStatus: check.sessionStatus,
|
|
624
|
-
setCookie: check.setCookie
|
|
625
|
-
};
|
|
626
|
-
if (check.mitigated) {
|
|
627
|
-
response.response = {
|
|
628
|
-
body: (_a = check.body) !== null && _a !== void 0 ? _a : 'Forbidden',
|
|
629
|
-
status: 403,
|
|
630
|
-
apiCallStatus: (_b = check.apiCallStatus) !== null && _b !== void 0 ? _b : -1,
|
|
631
|
-
mitigation: check.mitigation,
|
|
632
|
-
mitigated: check.mitigated
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
return response;
|
|
636
|
-
}
|
|
637
|
-
async inject(args) {
|
|
638
|
-
const check = await this.getMitigationResponse(args);
|
|
639
|
-
return {
|
|
640
|
-
injectHeaders: check.injectHeaders,
|
|
641
|
-
sessionStatus: check.sessionStatus,
|
|
642
|
-
setCookie: check.setCookie
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
async getMitigationResponse({ ip, userAgent, url, method, mitataCookie, mitataCaptchaCookie, body }) {
|
|
646
|
-
return await this.processMitigateRequest({
|
|
647
|
-
clientIp: ip,
|
|
648
|
-
getBodyFn: async () => await Promise.resolve(body),
|
|
649
|
-
method,
|
|
650
|
-
mitata: mitataCookie,
|
|
651
|
-
mitataCaptcha: mitataCaptchaCookie,
|
|
652
|
-
url,
|
|
653
|
-
userAgent
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
|
-
async ingest({ ip, userAgent, status, method, path, protocol, referer, bytesSent, requestTime, mitataCookie, sessionStatus }) {
|
|
657
|
-
await this.callIngest({
|
|
658
|
-
ip,
|
|
659
|
-
userAgent,
|
|
660
|
-
status,
|
|
661
|
-
method,
|
|
662
|
-
bytesSent,
|
|
663
|
-
path,
|
|
664
|
-
protocol,
|
|
665
|
-
referer,
|
|
666
|
-
requestTime,
|
|
667
|
-
mitataCookie,
|
|
668
|
-
sessionStatus,
|
|
669
|
-
integrationType: pack.name.replace('@netacea/', ''),
|
|
670
|
-
integrationVersion: pack.version
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
getCookieHeader(args) {
|
|
674
|
-
if (args.mitataCookie !== undefined) {
|
|
675
|
-
return `${this.mitataCookieName}=${args.mitataCookie}`;
|
|
676
|
-
}
|
|
677
|
-
return undefined;
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
exports.default = F5;
|
|
681
|
-
//# sourceMappingURL=F5.js.map
|