perimeterx-js-core 1.0.0 → 1.1.0
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/lib/cjs/action/Action.js +8 -0
- package/lib/cjs/action/ActionPriorityOrder.js +2 -0
- package/lib/cjs/activities/ActivityType.js +1 -0
- package/lib/cjs/activities/HttpActivityClient.js +28 -7
- package/lib/cjs/activities/utils.js +20 -1
- package/lib/cjs/blocker/model/BlockAction.js +1 -0
- package/lib/cjs/flow/EnforceFlow.js +1 -0
- package/lib/cjs/impl/http/undici/UndiciHttpClient.js +1 -2
- package/lib/cjs/phase/impl/CreateRedirectResponsePhase.js +100 -0
- package/lib/cjs/phase/impl/RiskApiPhase.js +4 -0
- package/lib/cjs/phase/impl/SendAsyncActivitiesPhase.js +7 -1
- package/lib/cjs/phase/impl/index.js +1 -0
- package/lib/cjs/products/bot_defender/BotDefender.js +16 -3
- package/lib/cjs/products/bot_defender/reasons/BotDefenderRedirectReason.js +7 -0
- package/lib/cjs/products/bot_defender/reasons/index.js +1 -0
- package/lib/cjs/risk_api/model/GetRiskResponseHeaders.js +3 -0
- package/lib/cjs/risk_api/risk_response/RiskResponseBase.js +27 -0
- package/lib/cjs/risk_api/risk_response/serialize/SerializedRiskResponse.js +3 -0
- package/lib/cjs/risk_api/risk_response/v2/GetRiskResponseV2.js +6 -0
- package/lib/cjs/utils/constants.js +1 -1
- package/lib/esm/action/Action.js +8 -0
- package/lib/esm/action/ActionPriorityOrder.js +2 -0
- package/lib/esm/activities/ActivityType.js +1 -0
- package/lib/esm/activities/HttpActivityClient.js +28 -7
- package/lib/esm/activities/utils.js +18 -0
- package/lib/esm/blocker/model/BlockAction.js +1 -0
- package/lib/esm/context/DefaultContext.js +1 -0
- package/lib/esm/flow/EnforceFlow.js +2 -1
- package/lib/esm/impl/http/undici/UndiciHttpClient.js +1 -2
- package/lib/esm/phase/impl/CreateRedirectResponsePhase.js +40 -0
- package/lib/esm/phase/impl/RiskApiPhase.js +4 -0
- package/lib/esm/phase/impl/SendAsyncActivitiesPhase.js +7 -1
- package/lib/esm/phase/impl/index.js +1 -0
- package/lib/esm/products/bot_defender/BotDefender.js +16 -4
- package/lib/esm/products/bot_defender/reasons/BotDefenderRedirectReason.js +4 -0
- package/lib/esm/products/bot_defender/reasons/index.js +1 -0
- package/lib/esm/risk_api/model/GetRiskResponseHeaders.js +3 -0
- package/lib/esm/risk_api/risk_response/RiskResponseBase.js +12 -0
- package/lib/esm/risk_api/risk_response/serialize/SerializedRiskResponse.js +6 -0
- package/lib/esm/risk_api/risk_response/v2/GetRiskResponseV2.js +6 -0
- package/lib/esm/utils/constants.js +1 -1
- package/lib/types/action/Action.d.ts +9 -1
- package/lib/types/activities/ActivityType.d.ts +2 -1
- package/lib/types/activities/HttpActivityClient.d.ts +12 -0
- package/lib/types/activities/model/AsyncActivityDetails.d.ts +11 -1
- package/lib/types/activities/utils.d.ts +2 -1
- package/lib/types/blocker/model/BlockAction.d.ts +2 -1
- package/lib/types/context/DefaultContext.d.ts +1 -0
- package/lib/types/context/interfaces/IContext.d.ts +4 -0
- package/lib/types/phase/impl/CreateRedirectResponsePhase.d.ts +17 -0
- package/lib/types/phase/impl/index.d.ts +1 -0
- package/lib/types/products/bot_defender/BotDefender.d.ts +1 -1
- package/lib/types/products/bot_defender/reasons/BotDefenderReasonType.d.ts +2 -1
- package/lib/types/products/bot_defender/reasons/BotDefenderRedirectReason.d.ts +3 -0
- package/lib/types/products/bot_defender/reasons/index.d.ts +1 -0
- package/lib/types/risk_api/risk_response/CommonRiskResponsePayload.d.ts +3 -0
- package/lib/types/risk_api/risk_response/IRiskResponse.d.ts +3 -0
- package/lib/types/risk_api/risk_response/RiskResponseBase.d.ts +3 -0
- package/lib/types/risk_api/risk_response/serialize/RiskResponseJson.d.ts +3 -0
- package/lib/types/risk_api/risk_response/serialize/SerializedRiskResponse.d.ts +3 -0
- package/lib/types/utils/constants.d.ts +1 -1
- package/package.json +1 -1
package/lib/cjs/action/Action.js
CHANGED
|
@@ -22,4 +22,12 @@ var Action;
|
|
|
22
22
|
* Indicates that the request should be blocked and a block response should be returned.
|
|
23
23
|
*/
|
|
24
24
|
Action["BLOCK"] = "block";
|
|
25
|
+
/**
|
|
26
|
+
* Indicates that the client should be redirected to a specified URL with a 302 response.
|
|
27
|
+
*/
|
|
28
|
+
Action["REDIRECT"] = "redirect";
|
|
29
|
+
/**
|
|
30
|
+
* Indicates that the client would be redirected, but no redirect response will be returned (monitor mode).
|
|
31
|
+
*/
|
|
32
|
+
Action["SIMULATED_REDIRECT"] = "simulated_redirect";
|
|
25
33
|
})(Action || (exports.Action = Action = {}));
|
|
@@ -7,6 +7,8 @@ var Action_1 = require("./Action.js");
|
|
|
7
7
|
* and the first action that matches a product recommendation will be taken.
|
|
8
8
|
*/
|
|
9
9
|
exports.ACTION_PRIORITY_ORDER = [
|
|
10
|
+
Action_1.Action.REDIRECT,
|
|
11
|
+
Action_1.Action.SIMULATED_REDIRECT,
|
|
10
12
|
Action_1.Action.BLOCK,
|
|
11
13
|
Action_1.Action.SIMULATED_BLOCK,
|
|
12
14
|
Action_1.Action.TRIGGER_RISK_API,
|
|
@@ -7,4 +7,5 @@ var ActivityType;
|
|
|
7
7
|
ActivityType["BLOCK"] = "block";
|
|
8
8
|
ActivityType["ADDITIONAL_S2S"] = "additional_s2s";
|
|
9
9
|
ActivityType["ENFORCER_TELEMETRY"] = "enforcer_telemetry";
|
|
10
|
+
ActivityType["PAGE_REDIRECTED"] = "page_redirected";
|
|
10
11
|
})(ActivityType || (exports.ActivityType = ActivityType = {}));
|
|
@@ -89,17 +89,30 @@ var HttpActivityClient = /** @class */ (function () {
|
|
|
89
89
|
*/
|
|
90
90
|
HttpActivityClient.prototype.createActivities = function (context) {
|
|
91
91
|
var activities = [];
|
|
92
|
-
if (this.
|
|
93
|
-
activities.push(this.
|
|
92
|
+
if (this.shouldCreatePageRedirectedActivity(context)) {
|
|
93
|
+
activities.push(this.createPageRedirectedActivity(context));
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
else {
|
|
96
|
+
if (this.shouldCreateBlockActivity(context)) {
|
|
97
|
+
activities.push(this.createBlockActivity(context));
|
|
98
|
+
}
|
|
99
|
+
if (this.shouldCreatePageRequestedActivity(context)) {
|
|
100
|
+
activities.push(this.createPageRequestedActivity(context));
|
|
101
|
+
}
|
|
102
|
+
if (this.shouldCreateAdditionalS2SActivity(context)) {
|
|
103
|
+
activities.push(this.createAdditionalS2SActivity(context));
|
|
104
|
+
}
|
|
100
105
|
}
|
|
101
106
|
return activities.map(this.finalizeActivity);
|
|
102
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* Whether to create a page_redirected activity based on the context.
|
|
110
|
+
* @param context
|
|
111
|
+
* @protected
|
|
112
|
+
*/
|
|
113
|
+
HttpActivityClient.prototype.shouldCreatePageRedirectedActivity = function (context) {
|
|
114
|
+
return context.action === action_1.Action.REDIRECT || context.action === action_1.Action.SIMULATED_REDIRECT;
|
|
115
|
+
};
|
|
103
116
|
/**
|
|
104
117
|
* Whether to create a block activity based on the context.
|
|
105
118
|
* @param context
|
|
@@ -126,6 +139,14 @@ var HttpActivityClient = /** @class */ (function () {
|
|
|
126
139
|
!!context.productData.ci &&
|
|
127
140
|
this.config.ciAutomaticAdditionalS2SEnabled);
|
|
128
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* Creates a page_redirected activity based on the context.
|
|
144
|
+
* @param context
|
|
145
|
+
* @protected
|
|
146
|
+
*/
|
|
147
|
+
HttpActivityClient.prototype.createPageRedirectedActivity = function (context) {
|
|
148
|
+
return (0, utils_2.createAsyncActivity)(ActivityType_1.ActivityType.PAGE_REDIRECTED, this.config, context);
|
|
149
|
+
};
|
|
129
150
|
/**
|
|
130
151
|
* Creates a block activity based on the context.
|
|
131
152
|
* @param context
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toHeaderEntryArray = exports.createAdditionalS2SActivityDetails = exports.createBlockActivityDetails = exports.createPageRequestedActivityDetails = exports.addResponseDataToAsyncActivityCommonDetails = exports.addRiskApiDataToAsyncActivityCommonDetails = exports.addTokenDataToDetails = exports.addRequestDataToDetails = exports.addServerDataToDetails = exports.addTlsDataToDetails = exports.addProductDataToDetails = exports.addCustomParametersToDetails = exports.addConfigDataToDetails = exports.addRootContextDataToDetails = exports.createCommonActivityDetails = exports.createAsyncActivityCommonDetails = exports.createActivityDetails = exports.createAsyncActivity = void 0;
|
|
3
|
+
exports.toHeaderEntryArray = exports.createPageRedirectedActivityDetails = exports.createAdditionalS2SActivityDetails = exports.createBlockActivityDetails = exports.createPageRequestedActivityDetails = exports.addResponseDataToAsyncActivityCommonDetails = exports.addRiskApiDataToAsyncActivityCommonDetails = exports.addTokenDataToDetails = exports.addRequestDataToDetails = exports.addServerDataToDetails = exports.addTlsDataToDetails = exports.addProductDataToDetails = exports.addCustomParametersToDetails = exports.addConfigDataToDetails = exports.addRootContextDataToDetails = exports.createCommonActivityDetails = exports.createAsyncActivityCommonDetails = exports.createActivityDetails = exports.createAsyncActivity = void 0;
|
|
4
4
|
exports.redactCookieSecret = redactCookieSecret;
|
|
5
5
|
var utils_1 = require("../utils/index.js");
|
|
6
6
|
var products_1 = require("../products/index.js");
|
|
@@ -52,6 +52,9 @@ var createActivityDetails = function (activityType, config, context) {
|
|
|
52
52
|
case ActivityType_1.ActivityType.ADDITIONAL_S2S:
|
|
53
53
|
specificActivityDetails = (0, exports.createAdditionalS2SActivityDetails)(config, context);
|
|
54
54
|
break;
|
|
55
|
+
case ActivityType_1.ActivityType.PAGE_REDIRECTED:
|
|
56
|
+
specificActivityDetails = (0, exports.createPageRedirectedActivityDetails)(context);
|
|
57
|
+
break;
|
|
55
58
|
}
|
|
56
59
|
return Object.assign(commonActivityDetails, commonAsyncActivityDetails, specificActivityDetails);
|
|
57
60
|
};
|
|
@@ -325,6 +328,22 @@ var createAdditionalS2SActivityDetails = function (_a, _b) {
|
|
|
325
328
|
return details;
|
|
326
329
|
};
|
|
327
330
|
exports.createAdditionalS2SActivityDetails = createAdditionalS2SActivityDetails;
|
|
331
|
+
var createPageRedirectedActivityDetails = function (context) {
|
|
332
|
+
var details = {
|
|
333
|
+
redirect_url: context.redirectUrl,
|
|
334
|
+
redirect_reason: 's2s',
|
|
335
|
+
simulated_redirect: context.action === action_1.Action.SIMULATED_REDIRECT,
|
|
336
|
+
};
|
|
337
|
+
var riskResponse = context.riskApiData.riskResponse;
|
|
338
|
+
if (riskResponse === null || riskResponse === void 0 ? void 0 : riskResponse.redirectRuleId) {
|
|
339
|
+
details.redirect_rule_id = riskResponse.redirectRuleId;
|
|
340
|
+
}
|
|
341
|
+
if (riskResponse === null || riskResponse === void 0 ? void 0 : riskResponse.redirectRuleName) {
|
|
342
|
+
details.redirect_rule_name = riskResponse.redirectRuleName;
|
|
343
|
+
}
|
|
344
|
+
return details;
|
|
345
|
+
};
|
|
346
|
+
exports.createPageRedirectedActivityDetails = createPageRedirectedActivityDetails;
|
|
328
347
|
var toHeaderEntryArray = function (headers) {
|
|
329
348
|
return Object.entries(headers).flatMap(function (_a) {
|
|
330
349
|
var key = _a[0], values = _a[1];
|
|
@@ -27,6 +27,7 @@ var EnforceFlow = /** @class */ (function (_super) {
|
|
|
27
27
|
new phase_1.EnrichContextFromRequestPhase(config, products, dataEnrichment, graphQLParser),
|
|
28
28
|
new phase_1.RiskApiPhase(products, riskApiClient),
|
|
29
29
|
new phase_1.AdditionalActivityHandlerPhase(config),
|
|
30
|
+
new phase_1.CreateRedirectResponsePhase(config, cors),
|
|
30
31
|
new phase_1.CreateBlockResponsePhase(config, phase_1.CreateBlockResponsePhase.getBlockers(products), cors),
|
|
31
32
|
new phase_1.ModifyIncomingRequestPhase(Object.values(products)),
|
|
32
33
|
]) || this;
|
|
@@ -71,8 +71,7 @@ var UndiciHttpClient = /** @class */ (function () {
|
|
|
71
71
|
method: request.method,
|
|
72
72
|
headers: (0, http_1.joinHeaderValues)(request.headers),
|
|
73
73
|
body: request.body,
|
|
74
|
-
|
|
75
|
-
bodyTimeout: options === null || options === void 0 ? void 0 : options.timeoutMs,
|
|
74
|
+
signal: (options === null || options === void 0 ? void 0 : options.timeoutMs) !== undefined ? AbortSignal.timeout(options.timeoutMs) : undefined,
|
|
76
75
|
dispatcher: this.getDispatcher(request),
|
|
77
76
|
})];
|
|
78
77
|
case 1:
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CreateRedirectResponsePhase = void 0;
|
|
40
|
+
var http_1 = require("../../http/index.js");
|
|
41
|
+
var action_1 = require("../../action/index.js");
|
|
42
|
+
var pxhd_1 = require("../../pxhd/index.js");
|
|
43
|
+
/**
|
|
44
|
+
* `CreateRedirectResponsePhase` is a phase that creates a 302 redirect response when the enforcer
|
|
45
|
+
* action is REDIRECT. It mirrors the structure of `CreateBlockResponsePhase`.
|
|
46
|
+
*/
|
|
47
|
+
var CreateRedirectResponsePhase = /** @class */ (function () {
|
|
48
|
+
function CreateRedirectResponsePhase(config, cors) {
|
|
49
|
+
this.config = config;
|
|
50
|
+
if (cors) {
|
|
51
|
+
this.cors = cors;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
CreateRedirectResponsePhase.prototype.execute = function (context) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
56
|
+
var response;
|
|
57
|
+
return __generator(this, function (_a) {
|
|
58
|
+
switch (_a.label) {
|
|
59
|
+
case 0:
|
|
60
|
+
if (context.action !== action_1.Action.REDIRECT) {
|
|
61
|
+
return [2 /*return*/, { done: false }];
|
|
62
|
+
}
|
|
63
|
+
context.logger.debug('create redirect response phase');
|
|
64
|
+
response = new http_1.MinimalResponseImpl({
|
|
65
|
+
status: 302,
|
|
66
|
+
headers: { location: [context.redirectUrl] },
|
|
67
|
+
body: '',
|
|
68
|
+
});
|
|
69
|
+
return [4 /*yield*/, this.addHeadersToResponse(response, context)];
|
|
70
|
+
case 1:
|
|
71
|
+
response = _a.sent();
|
|
72
|
+
return [2 /*return*/, { done: true, response: response }];
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
CreateRedirectResponsePhase.prototype.addHeadersToResponse = function (response, context) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
79
|
+
var corsHeaders;
|
|
80
|
+
var _a;
|
|
81
|
+
return __generator(this, function (_b) {
|
|
82
|
+
switch (_b.label) {
|
|
83
|
+
case 0:
|
|
84
|
+
if (!context.isMobile && ((_a = context.pxhd) === null || _a === void 0 ? void 0 : _a.source) === pxhd_1.PXHDSource.RISK) {
|
|
85
|
+
response = pxhd_1.PXHDUtils.addPxhdToMinimalResponse(this.config, context, response);
|
|
86
|
+
}
|
|
87
|
+
if (!(this.config.corsSupportEnabled && this.cors && this.cors.isCorsRequest(context))) return [3 /*break*/, 2];
|
|
88
|
+
return [4 /*yield*/, this.cors.getCorsBlockHeaders(context)];
|
|
89
|
+
case 1:
|
|
90
|
+
corsHeaders = _b.sent();
|
|
91
|
+
response = http_1.MinimalResponseUtils.appendHeaders(response, corsHeaders);
|
|
92
|
+
_b.label = 2;
|
|
93
|
+
case 2: return [2 /*return*/, response];
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
return CreateRedirectResponsePhase;
|
|
99
|
+
}());
|
|
100
|
+
exports.CreateRedirectResponsePhase = CreateRedirectResponsePhase;
|
|
@@ -55,6 +55,7 @@ exports.RiskApiPhase = void 0;
|
|
|
55
55
|
var action_1 = require("../../action/index.js");
|
|
56
56
|
var utils_1 = require("../../utils/index.js");
|
|
57
57
|
var pxhd_1 = require("../../pxhd/index.js");
|
|
58
|
+
var blocker_1 = require("../../blocker/index.js");
|
|
58
59
|
var DecideActionPhase_1 = require("./DecideActionPhase.js");
|
|
59
60
|
/**
|
|
60
61
|
* The `RiskApiPhase` class is responsible for making the synchronous Risk API request when necessary. If a Risk API call
|
|
@@ -152,6 +153,9 @@ var RiskApiPhase = /** @class */ (function (_super) {
|
|
|
152
153
|
source: pxhd_1.PXHDSource.RISK,
|
|
153
154
|
};
|
|
154
155
|
}
|
|
156
|
+
if (riskResponse.action === blocker_1.BlockAction.REDIRECT && riskResponse.redirectUrl) {
|
|
157
|
+
context.redirectUrl = riskResponse.redirectUrl;
|
|
158
|
+
}
|
|
155
159
|
};
|
|
156
160
|
RiskApiPhase.prototype.enrichContextWithProductDataFromRiskApi = function (context) {
|
|
157
161
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -52,7 +52,13 @@ var SendAsyncActivitiesPhase = /** @class */ (function () {
|
|
|
52
52
|
return __generator(this, function (_a) {
|
|
53
53
|
switch (_a.label) {
|
|
54
54
|
case 0:
|
|
55
|
-
if (![
|
|
55
|
+
if (![
|
|
56
|
+
action_1.Action.PASS_REQUEST,
|
|
57
|
+
action_1.Action.BLOCK,
|
|
58
|
+
action_1.Action.SIMULATED_BLOCK,
|
|
59
|
+
action_1.Action.REDIRECT,
|
|
60
|
+
action_1.Action.SIMULATED_REDIRECT,
|
|
61
|
+
].includes(context.action)) return [3 /*break*/, 2];
|
|
56
62
|
promise = this.activityClient.sendActivities(context);
|
|
57
63
|
if (!this.config.awaitAsyncHttpRequests) return [3 /*break*/, 2];
|
|
58
64
|
return [4 /*yield*/, promise];
|
|
@@ -22,6 +22,7 @@ __exportStar(require("./ParseTokenPhase.js"), exports);
|
|
|
22
22
|
__exportStar(require("./DecideActionPhase.js"), exports);
|
|
23
23
|
__exportStar(require("./RiskApiPhase.js"), exports);
|
|
24
24
|
__exportStar(require("./CreateBlockResponsePhase.js"), exports);
|
|
25
|
+
__exportStar(require("./CreateRedirectResponsePhase.js"), exports);
|
|
25
26
|
__exportStar(require("./ModifyIncomingRequestPhase.js"), exports);
|
|
26
27
|
__exportStar(require("./EnrichContextFromResponsePhase.js"), exports);
|
|
27
28
|
__exportStar(require("./ModifyOutgoingResponsePhase.js"), exports);
|
|
@@ -58,6 +58,7 @@ var block_1 = require("./block/index.js");
|
|
|
58
58
|
var filter_1 = require("./filter/index.js");
|
|
59
59
|
var first_party_1 = require("./first_party/index.js");
|
|
60
60
|
var reasons_1 = require("./reasons/index.js");
|
|
61
|
+
var blocker_1 = require("../../blocker/index.js");
|
|
61
62
|
var BotDefenderActionData_1 = require("./BotDefenderActionData.js");
|
|
62
63
|
var BotDefenderUtils_1 = require("./BotDefenderUtils.js");
|
|
63
64
|
var BotDefender = /** @class */ (function () {
|
|
@@ -161,7 +162,8 @@ var BotDefender = /** @class */ (function () {
|
|
|
161
162
|
};
|
|
162
163
|
BotDefender.prototype.getRiskApiActionData = function (_a) {
|
|
163
164
|
return __awaiter(this, arguments, void 0, function (_b) {
|
|
164
|
-
var
|
|
165
|
+
var riskResponse, isMonitored, actionData;
|
|
166
|
+
var riskApiData = _b.riskApiData, bd = _b.productData.bd, logger = _b.logger;
|
|
165
167
|
return __generator(this, function (_c) {
|
|
166
168
|
switch (riskApiData.riskApiCallResult) {
|
|
167
169
|
case risk_api_1.RiskApiCallResult.NONE:
|
|
@@ -170,14 +172,25 @@ var BotDefender = /** @class */ (function () {
|
|
|
170
172
|
return [2 /*return*/, new BotDefenderActionData_1.BotDefenderActionData(action_1.Action.PASS_REQUEST, reasons_1.BotDefenderPassReason.S2S_ERROR)];
|
|
171
173
|
case risk_api_1.RiskApiCallResult.TIMEOUT:
|
|
172
174
|
return [2 /*return*/, new BotDefenderActionData_1.BotDefenderActionData(action_1.Action.PASS_REQUEST, reasons_1.BotDefenderPassReason.S2S_TIMEOUT)];
|
|
173
|
-
case risk_api_1.RiskApiCallResult.SUCCESSFUL:
|
|
174
|
-
|
|
175
|
+
case risk_api_1.RiskApiCallResult.SUCCESSFUL: {
|
|
176
|
+
riskResponse = riskApiData.riskResponse;
|
|
177
|
+
isMonitored = !!(bd === null || bd === void 0 ? void 0 : bd.isMonitoredRequest);
|
|
178
|
+
actionData = this.getSuccessfulRiskApiAction(riskResponse, isMonitored);
|
|
179
|
+
logger.debug("bot defender action: ".concat(actionData.action, ", risk action: ").concat(riskResponse.action, ", redirect url: ").concat(riskResponse.redirectUrl, ", score: ").concat(riskResponse.score, ", monitored: ").concat(isMonitored));
|
|
180
|
+
return [2 /*return*/, actionData];
|
|
181
|
+
}
|
|
175
182
|
}
|
|
176
183
|
return [2 /*return*/];
|
|
177
184
|
});
|
|
178
185
|
});
|
|
179
186
|
};
|
|
180
187
|
BotDefender.prototype.getSuccessfulRiskApiAction = function (riskResponse, isMonitored) {
|
|
188
|
+
if (riskResponse.action === blocker_1.BlockAction.REDIRECT) {
|
|
189
|
+
if (!riskResponse.redirectUrl) {
|
|
190
|
+
return new BotDefenderActionData_1.BotDefenderActionData(action_1.Action.PASS_REQUEST, reasons_1.BotDefenderPassReason.S2S_ERROR);
|
|
191
|
+
}
|
|
192
|
+
return new BotDefenderActionData_1.BotDefenderActionData(isMonitored ? action_1.Action.SIMULATED_REDIRECT : action_1.Action.REDIRECT, reasons_1.BotDefenderRedirectReason.S2S);
|
|
193
|
+
}
|
|
181
194
|
if (riskResponse.score >= this.config.blockingScore) {
|
|
182
195
|
return new BotDefenderActionData_1.BotDefenderActionData(isMonitored ? action_1.Action.SIMULATED_BLOCK : action_1.Action.BLOCK, reasons_1.BotDefenderBlockReason.S2S_HIGH_SCORE);
|
|
183
196
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BotDefenderRedirectReason = void 0;
|
|
4
|
+
var BotDefenderRedirectReason;
|
|
5
|
+
(function (BotDefenderRedirectReason) {
|
|
6
|
+
BotDefenderRedirectReason["S2S"] = "s2s";
|
|
7
|
+
})(BotDefenderRedirectReason || (exports.BotDefenderRedirectReason = BotDefenderRedirectReason = {}));
|
|
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./BotDefenderBlockReason.js"), exports);
|
|
18
18
|
__exportStar(require("./BotDefenderPassReason.js"), exports);
|
|
19
|
+
__exportStar(require("./BotDefenderRedirectReason.js"), exports);
|
|
19
20
|
__exportStar(require("./BotDefenderS2SCallReason.js"), exports);
|
|
20
21
|
__exportStar(require("./BotDefenderReasonType.js"), exports);
|
|
@@ -13,4 +13,7 @@ exports.GetRiskResponseHeaders = {
|
|
|
13
13
|
Status: 'x-px-status',
|
|
14
14
|
TelemetryRequested: 'x-px-telemetry-requested',
|
|
15
15
|
Uuid: 'x-px-uuid',
|
|
16
|
+
RedirectUrl: 'x-px-redirect-url',
|
|
17
|
+
RedirectRuleId: 'x-px-redirect-rule-id',
|
|
18
|
+
RedirectRuleName: 'x-px-redirect-rule-name',
|
|
16
19
|
};
|
|
@@ -145,6 +145,30 @@ var RiskResponseBase = /** @class */ (function () {
|
|
|
145
145
|
enumerable: false,
|
|
146
146
|
configurable: true
|
|
147
147
|
});
|
|
148
|
+
Object.defineProperty(RiskResponseBase.prototype, "redirectUrl", {
|
|
149
|
+
get: function () {
|
|
150
|
+
var _a;
|
|
151
|
+
return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.redirect_url;
|
|
152
|
+
},
|
|
153
|
+
enumerable: false,
|
|
154
|
+
configurable: true
|
|
155
|
+
});
|
|
156
|
+
Object.defineProperty(RiskResponseBase.prototype, "redirectRuleId", {
|
|
157
|
+
get: function () {
|
|
158
|
+
var _a;
|
|
159
|
+
return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.redirect_rule_id;
|
|
160
|
+
},
|
|
161
|
+
enumerable: false,
|
|
162
|
+
configurable: true
|
|
163
|
+
});
|
|
164
|
+
Object.defineProperty(RiskResponseBase.prototype, "redirectRuleName", {
|
|
165
|
+
get: function () {
|
|
166
|
+
var _a;
|
|
167
|
+
return (_a = this.riskResponse) === null || _a === void 0 ? void 0 : _a.redirect_rule_name;
|
|
168
|
+
},
|
|
169
|
+
enumerable: false,
|
|
170
|
+
configurable: true
|
|
171
|
+
});
|
|
148
172
|
RiskResponseBase.prototype.toJSON = function () {
|
|
149
173
|
return {
|
|
150
174
|
status: this.status,
|
|
@@ -158,6 +182,9 @@ var RiskResponseBase = /** @class */ (function () {
|
|
|
158
182
|
additionalRiskInfo: this.additionalRiskInfo,
|
|
159
183
|
telemetryRequested: this.telemetryRequested,
|
|
160
184
|
uuid: this.uuid,
|
|
185
|
+
redirectUrl: this.redirectUrl,
|
|
186
|
+
redirectRuleId: this.redirectRuleId,
|
|
187
|
+
redirectRuleName: this.redirectRuleName,
|
|
161
188
|
};
|
|
162
189
|
};
|
|
163
190
|
return RiskResponseBase;
|
|
@@ -15,6 +15,9 @@ var SerializedRiskResponse = /** @class */ (function () {
|
|
|
15
15
|
this.score = riskResponseJson.score;
|
|
16
16
|
this.status = riskResponseJson.status;
|
|
17
17
|
this.uuid = riskResponseJson.uuid;
|
|
18
|
+
this.redirectUrl = riskResponseJson.redirectUrl;
|
|
19
|
+
this.redirectRuleId = riskResponseJson.redirectRuleId;
|
|
20
|
+
this.redirectRuleName = riskResponseJson.redirectRuleName;
|
|
18
21
|
}
|
|
19
22
|
SerializedRiskResponse.prototype.validate = function () {
|
|
20
23
|
throw new utils_1.EnforcerError('SerializedRiskResponse.validate() should not be invoked');
|
|
@@ -39,6 +39,9 @@ var GetRiskResponseV2 = /** @class */ (function (_super) {
|
|
|
39
39
|
var telemetryRequested = this.getHeader(response, model_1.GetRiskResponseHeaders.TelemetryRequested);
|
|
40
40
|
var uuid = this.getHeader(response, model_1.GetRiskResponseHeaders.Uuid);
|
|
41
41
|
var action = this.getHeader(response, model_1.GetRiskResponseHeaders.Action);
|
|
42
|
+
var redirectUrl = this.getHeader(response, model_1.GetRiskResponseHeaders.RedirectUrl);
|
|
43
|
+
var redirectRuleId = this.getHeader(response, model_1.GetRiskResponseHeaders.RedirectRuleId);
|
|
44
|
+
var redirectRuleName = this.getHeader(response, model_1.GetRiskResponseHeaders.RedirectRuleName);
|
|
42
45
|
return {
|
|
43
46
|
status: status,
|
|
44
47
|
action: action,
|
|
@@ -51,6 +54,9 @@ var GetRiskResponseV2 = /** @class */ (function (_super) {
|
|
|
51
54
|
telemetry_requested: telemetryRequested === 'true',
|
|
52
55
|
drc: drc ? parseInt(drc) : undefined,
|
|
53
56
|
cookie_cfg_block_result: blockResult,
|
|
57
|
+
redirect_url: redirectUrl,
|
|
58
|
+
redirect_rule_id: redirectRuleId,
|
|
59
|
+
redirect_rule_name: redirectRuleName,
|
|
54
60
|
};
|
|
55
61
|
};
|
|
56
62
|
GetRiskResponseV2.prototype.getHeader = function (response, header) {
|
|
@@ -15,4 +15,4 @@ exports.PUSH_DATA_FEATURE_HEADER_NAME = 'x-px-feature';
|
|
|
15
15
|
exports.EMAIL_ADDRESS_REGEX = /^[a-zA-Z0-9_+&*-]+(?:\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,7}$/;
|
|
16
16
|
exports.URL_REGEX = /^(https?:)\/\/(([^@\s:\/]+):?([^@\s\/]*)@)?(([^:\/?#]*)(?:\:([0-9]+))?)(\/?[^?#]*)(\?[^#]*|)(#.*|)$/;
|
|
17
17
|
exports.REGEX_STRUCTURE = /^\/(.+?)\/([gimsuyvd]*)$/;
|
|
18
|
-
exports.CORE_MODULE_VERSION = 'JS Core 1.
|
|
18
|
+
exports.CORE_MODULE_VERSION = 'JS Core 1.1.0';
|
package/lib/esm/action/Action.js
CHANGED
|
@@ -19,4 +19,12 @@ export var Action;
|
|
|
19
19
|
* Indicates that the request should be blocked and a block response should be returned.
|
|
20
20
|
*/
|
|
21
21
|
Action["BLOCK"] = "block";
|
|
22
|
+
/**
|
|
23
|
+
* Indicates that the client should be redirected to a specified URL with a 302 response.
|
|
24
|
+
*/
|
|
25
|
+
Action["REDIRECT"] = "redirect";
|
|
26
|
+
/**
|
|
27
|
+
* Indicates that the client would be redirected, but no redirect response will be returned (monitor mode).
|
|
28
|
+
*/
|
|
29
|
+
Action["SIMULATED_REDIRECT"] = "simulated_redirect";
|
|
22
30
|
})(Action || (Action = {}));
|
|
@@ -4,6 +4,8 @@ import { Action } from './Action.js';
|
|
|
4
4
|
* and the first action that matches a product recommendation will be taken.
|
|
5
5
|
*/
|
|
6
6
|
export const ACTION_PRIORITY_ORDER = [
|
|
7
|
+
Action.REDIRECT,
|
|
8
|
+
Action.SIMULATED_REDIRECT,
|
|
7
9
|
Action.BLOCK,
|
|
8
10
|
Action.SIMULATED_BLOCK,
|
|
9
11
|
Action.TRIGGER_RISK_API,
|
|
@@ -46,17 +46,30 @@ export class HttpActivityClient {
|
|
|
46
46
|
*/
|
|
47
47
|
createActivities(context) {
|
|
48
48
|
const activities = [];
|
|
49
|
-
if (this.
|
|
50
|
-
activities.push(this.
|
|
49
|
+
if (this.shouldCreatePageRedirectedActivity(context)) {
|
|
50
|
+
activities.push(this.createPageRedirectedActivity(context));
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
else {
|
|
53
|
+
if (this.shouldCreateBlockActivity(context)) {
|
|
54
|
+
activities.push(this.createBlockActivity(context));
|
|
55
|
+
}
|
|
56
|
+
if (this.shouldCreatePageRequestedActivity(context)) {
|
|
57
|
+
activities.push(this.createPageRequestedActivity(context));
|
|
58
|
+
}
|
|
59
|
+
if (this.shouldCreateAdditionalS2SActivity(context)) {
|
|
60
|
+
activities.push(this.createAdditionalS2SActivity(context));
|
|
61
|
+
}
|
|
57
62
|
}
|
|
58
63
|
return activities.map(this.finalizeActivity);
|
|
59
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Whether to create a page_redirected activity based on the context.
|
|
67
|
+
* @param context
|
|
68
|
+
* @protected
|
|
69
|
+
*/
|
|
70
|
+
shouldCreatePageRedirectedActivity(context) {
|
|
71
|
+
return context.action === Action.REDIRECT || context.action === Action.SIMULATED_REDIRECT;
|
|
72
|
+
}
|
|
60
73
|
/**
|
|
61
74
|
* Whether to create a block activity based on the context.
|
|
62
75
|
* @param context
|
|
@@ -83,6 +96,14 @@ export class HttpActivityClient {
|
|
|
83
96
|
!!context.productData.ci &&
|
|
84
97
|
this.config.ciAutomaticAdditionalS2SEnabled);
|
|
85
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates a page_redirected activity based on the context.
|
|
101
|
+
* @param context
|
|
102
|
+
* @protected
|
|
103
|
+
*/
|
|
104
|
+
createPageRedirectedActivity(context) {
|
|
105
|
+
return createAsyncActivity(ActivityType.PAGE_REDIRECTED, this.config, context);
|
|
106
|
+
}
|
|
86
107
|
/**
|
|
87
108
|
* Creates a block activity based on the context.
|
|
88
109
|
* @param context
|
|
@@ -46,6 +46,9 @@ export const createActivityDetails = (activityType, config, context) => {
|
|
|
46
46
|
case ActivityType.ADDITIONAL_S2S:
|
|
47
47
|
specificActivityDetails = createAdditionalS2SActivityDetails(config, context);
|
|
48
48
|
break;
|
|
49
|
+
case ActivityType.PAGE_REDIRECTED:
|
|
50
|
+
specificActivityDetails = createPageRedirectedActivityDetails(context);
|
|
51
|
+
break;
|
|
49
52
|
}
|
|
50
53
|
return Object.assign(commonActivityDetails, commonAsyncActivityDetails, specificActivityDetails);
|
|
51
54
|
};
|
|
@@ -297,6 +300,21 @@ export const createAdditionalS2SActivityDetails = ({ ciSendRawUsernameOnAddition
|
|
|
297
300
|
}
|
|
298
301
|
return details;
|
|
299
302
|
};
|
|
303
|
+
export const createPageRedirectedActivityDetails = (context) => {
|
|
304
|
+
const details = {
|
|
305
|
+
redirect_url: context.redirectUrl,
|
|
306
|
+
redirect_reason: 's2s',
|
|
307
|
+
simulated_redirect: context.action === Action.SIMULATED_REDIRECT,
|
|
308
|
+
};
|
|
309
|
+
const { riskResponse } = context.riskApiData;
|
|
310
|
+
if (riskResponse?.redirectRuleId) {
|
|
311
|
+
details.redirect_rule_id = riskResponse.redirectRuleId;
|
|
312
|
+
}
|
|
313
|
+
if (riskResponse?.redirectRuleName) {
|
|
314
|
+
details.redirect_rule_name = riskResponse.redirectRuleName;
|
|
315
|
+
}
|
|
316
|
+
return details;
|
|
317
|
+
};
|
|
300
318
|
export const toHeaderEntryArray = (headers) => {
|
|
301
319
|
return Object.entries(headers).flatMap(([key, values]) => values.map((value) => ({
|
|
302
320
|
name: key,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdditionalActivityHandlerPhase, CreateBlockResponsePhase, EnrichContextFromRequestPhase, ModifyIncomingRequestPhase, ParseTokenPhase, RiskApiPhase, } from '../phase/index.js';
|
|
1
|
+
import { AdditionalActivityHandlerPhase, CreateBlockResponsePhase, CreateRedirectResponsePhase, EnrichContextFromRequestPhase, ModifyIncomingRequestPhase, ParseTokenPhase, RiskApiPhase, } from '../phase/index.js';
|
|
2
2
|
import { Flow } from './Flow.js';
|
|
3
3
|
export class EnforceFlow extends Flow {
|
|
4
4
|
constructor(config, { dataEnrichment, tokenParser, riskApiClient, cors, products, graphQLParser, }) {
|
|
@@ -7,6 +7,7 @@ export class EnforceFlow extends Flow {
|
|
|
7
7
|
new EnrichContextFromRequestPhase(config, products, dataEnrichment, graphQLParser),
|
|
8
8
|
new RiskApiPhase(products, riskApiClient),
|
|
9
9
|
new AdditionalActivityHandlerPhase(config),
|
|
10
|
+
new CreateRedirectResponsePhase(config, cors),
|
|
10
11
|
new CreateBlockResponsePhase(config, CreateBlockResponsePhase.getBlockers(products), cors),
|
|
11
12
|
new ModifyIncomingRequestPhase(Object.values(products)),
|
|
12
13
|
]);
|
|
@@ -15,8 +15,7 @@ export class UndiciHttpClient {
|
|
|
15
15
|
method: request.method,
|
|
16
16
|
headers: joinHeaderValues(request.headers),
|
|
17
17
|
body: request.body,
|
|
18
|
-
|
|
19
|
-
bodyTimeout: options?.timeoutMs,
|
|
18
|
+
signal: options?.timeoutMs !== undefined ? AbortSignal.timeout(options.timeoutMs) : undefined,
|
|
20
19
|
dispatcher: this.getDispatcher(request),
|
|
21
20
|
});
|
|
22
21
|
return new UndiciIncomingResponse({
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MinimalResponseImpl, MinimalResponseUtils } from '../../http/index.js';
|
|
2
|
+
import { Action } from '../../action/index.js';
|
|
3
|
+
import { PXHDSource, PXHDUtils } from '../../pxhd/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* `CreateRedirectResponsePhase` is a phase that creates a 302 redirect response when the enforcer
|
|
6
|
+
* action is REDIRECT. It mirrors the structure of `CreateBlockResponsePhase`.
|
|
7
|
+
*/
|
|
8
|
+
export class CreateRedirectResponsePhase {
|
|
9
|
+
config;
|
|
10
|
+
cors;
|
|
11
|
+
constructor(config, cors) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
if (cors) {
|
|
14
|
+
this.cors = cors;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async execute(context) {
|
|
18
|
+
if (context.action !== Action.REDIRECT) {
|
|
19
|
+
return { done: false };
|
|
20
|
+
}
|
|
21
|
+
context.logger.debug('create redirect response phase');
|
|
22
|
+
let response = new MinimalResponseImpl({
|
|
23
|
+
status: 302,
|
|
24
|
+
headers: { location: [context.redirectUrl] },
|
|
25
|
+
body: '',
|
|
26
|
+
});
|
|
27
|
+
response = await this.addHeadersToResponse(response, context);
|
|
28
|
+
return { done: true, response };
|
|
29
|
+
}
|
|
30
|
+
async addHeadersToResponse(response, context) {
|
|
31
|
+
if (!context.isMobile && context.pxhd?.source === PXHDSource.RISK) {
|
|
32
|
+
response = PXHDUtils.addPxhdToMinimalResponse(this.config, context, response);
|
|
33
|
+
}
|
|
34
|
+
if (this.config.corsSupportEnabled && this.cors && this.cors.isCorsRequest(context)) {
|
|
35
|
+
const corsHeaders = await this.cors.getCorsBlockHeaders(context);
|
|
36
|
+
response = MinimalResponseUtils.appendHeaders(response, corsHeaders);
|
|
37
|
+
}
|
|
38
|
+
return response;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Action, getReasonForHighestPriorityProduct } from '../../action/index.js';
|
|
2
2
|
import { isNullOrUndefined } from '../../utils/index.js';
|
|
3
3
|
import { PXHDSource } from '../../pxhd/index.js';
|
|
4
|
+
import { BlockAction } from '../../blocker/index.js';
|
|
4
5
|
import { DecideActionPhase } from './DecideActionPhase.js';
|
|
5
6
|
/**
|
|
6
7
|
* The `RiskApiPhase` class is responsible for making the synchronous Risk API request when necessary. If a Risk API call
|
|
@@ -64,6 +65,9 @@ export class RiskApiPhase extends DecideActionPhase {
|
|
|
64
65
|
source: PXHDSource.RISK,
|
|
65
66
|
};
|
|
66
67
|
}
|
|
68
|
+
if (riskResponse.action === BlockAction.REDIRECT && riskResponse.redirectUrl) {
|
|
69
|
+
context.redirectUrl = riskResponse.redirectUrl;
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
async enrichContextWithProductDataFromRiskApi(context) {
|
|
69
73
|
await Promise.all(Object.entries(this.products).map(async ([name, product]) => {
|
|
@@ -10,7 +10,13 @@ export class SendAsyncActivitiesPhase {
|
|
|
10
10
|
this.activityClient = activityClient;
|
|
11
11
|
}
|
|
12
12
|
async execute(context) {
|
|
13
|
-
if ([
|
|
13
|
+
if ([
|
|
14
|
+
Action.PASS_REQUEST,
|
|
15
|
+
Action.BLOCK,
|
|
16
|
+
Action.SIMULATED_BLOCK,
|
|
17
|
+
Action.REDIRECT,
|
|
18
|
+
Action.SIMULATED_REDIRECT,
|
|
19
|
+
].includes(context.action)) {
|
|
14
20
|
// ensure error handling is done in the sendActivities method
|
|
15
21
|
const promise = this.activityClient.sendActivities(context);
|
|
16
22
|
if (this.config.awaitAsyncHttpRequests) {
|
|
@@ -6,6 +6,7 @@ export * from './ParseTokenPhase.js';
|
|
|
6
6
|
export * from './DecideActionPhase.js';
|
|
7
7
|
export * from './RiskApiPhase.js';
|
|
8
8
|
export * from './CreateBlockResponsePhase.js';
|
|
9
|
+
export * from './CreateRedirectResponsePhase.js';
|
|
9
10
|
export * from './ModifyIncomingRequestPhase.js';
|
|
10
11
|
export * from './EnrichContextFromResponsePhase.js';
|
|
11
12
|
export * from './ModifyOutgoingResponsePhase.js';
|
|
@@ -7,7 +7,8 @@ import { MonitoredRequestUtils } from '../../monitored_request/index.js';
|
|
|
7
7
|
import { DefaultBotDefenderBlocker } from './block/index.js';
|
|
8
8
|
import { DefaultBotDefenderFilter } from './filter/index.js';
|
|
9
9
|
import { DefaultBotDefenderFirstParty } from './first_party/index.js';
|
|
10
|
-
import { BotDefenderBlockReason, BotDefenderPassReason, BotDefenderS2SCallReason } from './reasons/index.js';
|
|
10
|
+
import { BotDefenderBlockReason, BotDefenderPassReason, BotDefenderRedirectReason, BotDefenderS2SCallReason, } from './reasons/index.js';
|
|
11
|
+
import { BlockAction } from '../../blocker/index.js';
|
|
11
12
|
import { BotDefenderActionData } from './BotDefenderActionData.js';
|
|
12
13
|
import { BotDefenderUtils } from './BotDefenderUtils.js';
|
|
13
14
|
export class BotDefender {
|
|
@@ -77,7 +78,7 @@ export class BotDefender {
|
|
|
77
78
|
async enrichContextFromRiskApi(context) {
|
|
78
79
|
return await this.getRiskApiActionData(context);
|
|
79
80
|
}
|
|
80
|
-
async getRiskApiActionData({ riskApiData, productData: { bd }, }) {
|
|
81
|
+
async getRiskApiActionData({ riskApiData, productData: { bd }, logger, }) {
|
|
81
82
|
switch (riskApiData.riskApiCallResult) {
|
|
82
83
|
case RiskApiCallResult.NONE:
|
|
83
84
|
throw new EnforcerError('risk api call result should not be none!');
|
|
@@ -85,11 +86,22 @@ export class BotDefender {
|
|
|
85
86
|
return new BotDefenderActionData(Action.PASS_REQUEST, BotDefenderPassReason.S2S_ERROR);
|
|
86
87
|
case RiskApiCallResult.TIMEOUT:
|
|
87
88
|
return new BotDefenderActionData(Action.PASS_REQUEST, BotDefenderPassReason.S2S_TIMEOUT);
|
|
88
|
-
case RiskApiCallResult.SUCCESSFUL:
|
|
89
|
-
|
|
89
|
+
case RiskApiCallResult.SUCCESSFUL: {
|
|
90
|
+
const riskResponse = riskApiData.riskResponse;
|
|
91
|
+
const isMonitored = !!bd?.isMonitoredRequest;
|
|
92
|
+
const actionData = this.getSuccessfulRiskApiAction(riskResponse, isMonitored);
|
|
93
|
+
logger.debug(`bot defender action: ${actionData.action}, risk action: ${riskResponse.action}, redirect url: ${riskResponse.redirectUrl}, score: ${riskResponse.score}, monitored: ${isMonitored}`);
|
|
94
|
+
return actionData;
|
|
95
|
+
}
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
getSuccessfulRiskApiAction(riskResponse, isMonitored) {
|
|
99
|
+
if (riskResponse.action === BlockAction.REDIRECT) {
|
|
100
|
+
if (!riskResponse.redirectUrl) {
|
|
101
|
+
return new BotDefenderActionData(Action.PASS_REQUEST, BotDefenderPassReason.S2S_ERROR);
|
|
102
|
+
}
|
|
103
|
+
return new BotDefenderActionData(isMonitored ? Action.SIMULATED_REDIRECT : Action.REDIRECT, BotDefenderRedirectReason.S2S);
|
|
104
|
+
}
|
|
93
105
|
if (riskResponse.score >= this.config.blockingScore) {
|
|
94
106
|
return new BotDefenderActionData(isMonitored ? Action.SIMULATED_BLOCK : Action.BLOCK, BotDefenderBlockReason.S2S_HIGH_SCORE);
|
|
95
107
|
}
|
|
@@ -10,4 +10,7 @@ export const GetRiskResponseHeaders = {
|
|
|
10
10
|
Status: 'x-px-status',
|
|
11
11
|
TelemetryRequested: 'x-px-telemetry-requested',
|
|
12
12
|
Uuid: 'x-px-uuid',
|
|
13
|
+
RedirectUrl: 'x-px-redirect-url',
|
|
14
|
+
RedirectRuleId: 'x-px-redirect-rule-id',
|
|
15
|
+
RedirectRuleName: 'x-px-redirect-rule-name',
|
|
13
16
|
};
|
|
@@ -48,6 +48,15 @@ export class RiskResponseBase {
|
|
|
48
48
|
get drc() {
|
|
49
49
|
return this.riskResponse?.drc;
|
|
50
50
|
}
|
|
51
|
+
get redirectUrl() {
|
|
52
|
+
return this.riskResponse?.redirect_url;
|
|
53
|
+
}
|
|
54
|
+
get redirectRuleId() {
|
|
55
|
+
return this.riskResponse?.redirect_rule_id;
|
|
56
|
+
}
|
|
57
|
+
get redirectRuleName() {
|
|
58
|
+
return this.riskResponse?.redirect_rule_name;
|
|
59
|
+
}
|
|
51
60
|
toJSON() {
|
|
52
61
|
return {
|
|
53
62
|
status: this.status,
|
|
@@ -61,6 +70,9 @@ export class RiskResponseBase {
|
|
|
61
70
|
additionalRiskInfo: this.additionalRiskInfo,
|
|
62
71
|
telemetryRequested: this.telemetryRequested,
|
|
63
72
|
uuid: this.uuid,
|
|
73
|
+
redirectUrl: this.redirectUrl,
|
|
74
|
+
redirectRuleId: this.redirectRuleId,
|
|
75
|
+
redirectRuleName: this.redirectRuleName,
|
|
64
76
|
};
|
|
65
77
|
}
|
|
66
78
|
}
|
|
@@ -11,6 +11,9 @@ export class SerializedRiskResponse {
|
|
|
11
11
|
score;
|
|
12
12
|
status;
|
|
13
13
|
uuid;
|
|
14
|
+
redirectUrl;
|
|
15
|
+
redirectRuleId;
|
|
16
|
+
redirectRuleName;
|
|
14
17
|
constructor(riskResponseJson) {
|
|
15
18
|
this.action = riskResponseJson.action;
|
|
16
19
|
this.additionalRiskInfo = riskResponseJson.additionalRiskInfo;
|
|
@@ -23,6 +26,9 @@ export class SerializedRiskResponse {
|
|
|
23
26
|
this.score = riskResponseJson.score;
|
|
24
27
|
this.status = riskResponseJson.status;
|
|
25
28
|
this.uuid = riskResponseJson.uuid;
|
|
29
|
+
this.redirectUrl = riskResponseJson.redirectUrl;
|
|
30
|
+
this.redirectRuleId = riskResponseJson.redirectRuleId;
|
|
31
|
+
this.redirectRuleName = riskResponseJson.redirectRuleName;
|
|
26
32
|
}
|
|
27
33
|
validate() {
|
|
28
34
|
throw new EnforcerError('SerializedRiskResponse.validate() should not be invoked');
|
|
@@ -20,6 +20,9 @@ export class GetRiskResponseV2 extends RiskResponseBase {
|
|
|
20
20
|
const telemetryRequested = this.getHeader(response, GetRiskResponseHeaders.TelemetryRequested);
|
|
21
21
|
const uuid = this.getHeader(response, GetRiskResponseHeaders.Uuid);
|
|
22
22
|
const action = this.getHeader(response, GetRiskResponseHeaders.Action);
|
|
23
|
+
const redirectUrl = this.getHeader(response, GetRiskResponseHeaders.RedirectUrl);
|
|
24
|
+
const redirectRuleId = this.getHeader(response, GetRiskResponseHeaders.RedirectRuleId);
|
|
25
|
+
const redirectRuleName = this.getHeader(response, GetRiskResponseHeaders.RedirectRuleName);
|
|
23
26
|
return {
|
|
24
27
|
status,
|
|
25
28
|
action,
|
|
@@ -32,6 +35,9 @@ export class GetRiskResponseV2 extends RiskResponseBase {
|
|
|
32
35
|
telemetry_requested: telemetryRequested === 'true',
|
|
33
36
|
drc: drc ? parseInt(drc) : undefined,
|
|
34
37
|
cookie_cfg_block_result: blockResult,
|
|
38
|
+
redirect_url: redirectUrl,
|
|
39
|
+
redirect_rule_id: redirectRuleId,
|
|
40
|
+
redirect_rule_name: redirectRuleName,
|
|
35
41
|
};
|
|
36
42
|
}
|
|
37
43
|
getHeader(response, header) {
|
|
@@ -12,4 +12,4 @@ export const PUSH_DATA_FEATURE_HEADER_NAME = 'x-px-feature';
|
|
|
12
12
|
export const EMAIL_ADDRESS_REGEX = /^[a-zA-Z0-9_+&*-]+(?:\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,7}$/;
|
|
13
13
|
export const URL_REGEX = /^(https?:)\/\/(([^@\s:\/]+):?([^@\s\/]*)@)?(([^:\/?#]*)(?:\:([0-9]+))?)(\/?[^?#]*)(\?[^#]*|)(#.*|)$/;
|
|
14
14
|
export const REGEX_STRUCTURE = /^\/(.+?)\/([gimsuyvd]*)$/;
|
|
15
|
-
export const CORE_MODULE_VERSION = 'JS Core 1.
|
|
15
|
+
export const CORE_MODULE_VERSION = 'JS Core 1.1.0';
|
|
@@ -17,5 +17,13 @@ export declare enum Action {
|
|
|
17
17
|
/**
|
|
18
18
|
* Indicates that the request should be blocked and a block response should be returned.
|
|
19
19
|
*/
|
|
20
|
-
BLOCK = "block"
|
|
20
|
+
BLOCK = "block",
|
|
21
|
+
/**
|
|
22
|
+
* Indicates that the client should be redirected to a specified URL with a 302 response.
|
|
23
|
+
*/
|
|
24
|
+
REDIRECT = "redirect",
|
|
25
|
+
/**
|
|
26
|
+
* Indicates that the client would be redirected, but no redirect response will be returned (monitor mode).
|
|
27
|
+
*/
|
|
28
|
+
SIMULATED_REDIRECT = "simulated_redirect"
|
|
21
29
|
}
|
|
@@ -29,6 +29,12 @@ export declare class HttpActivityClient<Req, Res, Supported extends string, Adde
|
|
|
29
29
|
* @protected
|
|
30
30
|
*/
|
|
31
31
|
protected createActivities(context: ReadonlyContext<Req, Res>): AsyncActivity[];
|
|
32
|
+
/**
|
|
33
|
+
* Whether to create a page_redirected activity based on the context.
|
|
34
|
+
* @param context
|
|
35
|
+
* @protected
|
|
36
|
+
*/
|
|
37
|
+
protected shouldCreatePageRedirectedActivity(context: ReadonlyContext<Req, Res>): boolean;
|
|
32
38
|
/**
|
|
33
39
|
* Whether to create a block activity based on the context.
|
|
34
40
|
* @param context
|
|
@@ -47,6 +53,12 @@ export declare class HttpActivityClient<Req, Res, Supported extends string, Adde
|
|
|
47
53
|
* @protected
|
|
48
54
|
*/
|
|
49
55
|
protected shouldCreateAdditionalS2SActivity(context: ReadonlyContext<Req, Res>): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a page_redirected activity based on the context.
|
|
58
|
+
* @param context
|
|
59
|
+
* @protected
|
|
60
|
+
*/
|
|
61
|
+
protected createPageRedirectedActivity(context: ReadonlyContext<Req, Res>): AsyncActivity;
|
|
50
62
|
/**
|
|
51
63
|
* Creates a block activity based on the context.
|
|
52
64
|
* @param context
|
|
@@ -12,7 +12,7 @@ export type AsyncActivityCommonDetails = Partial<RiskAdditionalData> & {
|
|
|
12
12
|
http_status_code?: number;
|
|
13
13
|
credentials_compromised?: boolean;
|
|
14
14
|
};
|
|
15
|
-
export type ActivityTypeDetails = PageRequestedActivityDetails | BlockActivityDetails | AdditionalS2SActivityDetails;
|
|
15
|
+
export type ActivityTypeDetails = PageRequestedActivityDetails | BlockActivityDetails | AdditionalS2SActivityDetails | PageRedirectedActivityDetails;
|
|
16
16
|
/**
|
|
17
17
|
* Activity details that should be included in page_requested activities.
|
|
18
18
|
*/
|
|
@@ -39,3 +39,13 @@ export type AdditionalS2SActivityDetails = {
|
|
|
39
39
|
login_successful: boolean;
|
|
40
40
|
raw_username?: string;
|
|
41
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Activity details that should be included in page_redirected activities.
|
|
44
|
+
*/
|
|
45
|
+
export type PageRedirectedActivityDetails = {
|
|
46
|
+
redirect_url: string;
|
|
47
|
+
redirect_reason: 's2s';
|
|
48
|
+
simulated_redirect: boolean;
|
|
49
|
+
redirect_rule_id?: string;
|
|
50
|
+
redirect_rule_name?: string;
|
|
51
|
+
};
|
|
@@ -3,7 +3,7 @@ import { ReadonlyContext, RequestData, ServerData, TlsData, TokenData } from '..
|
|
|
3
3
|
import { IConfiguration } from '../config';
|
|
4
4
|
import { ProductData } from '../products';
|
|
5
5
|
import { ActivityType } from './ActivityType';
|
|
6
|
-
import { AdditionalS2SActivityDetails, AsyncActivity, AsyncActivityCommonDetails, AsyncActivityDetails, BlockActivityDetails, CommonActivityDetails, HeaderEntry, PageRequestedActivityDetails } from './model';
|
|
6
|
+
import { AdditionalS2SActivityDetails, AsyncActivity, AsyncActivityCommonDetails, AsyncActivityDetails, BlockActivityDetails, CommonActivityDetails, HeaderEntry, PageRedirectedActivityDetails, PageRequestedActivityDetails } from './model';
|
|
7
7
|
import { CustomParameters, ResponseCustomParameters } from '../custom_parameters';
|
|
8
8
|
/**
|
|
9
9
|
* Creates an async activity object based on the provided parameters.
|
|
@@ -37,4 +37,5 @@ export declare const addResponseDataToAsyncActivityCommonDetails: <Req, Res>(det
|
|
|
37
37
|
export declare const createPageRequestedActivityDetails: <Req, Res>(context: ReadonlyContext<Req, Res>) => PageRequestedActivityDetails;
|
|
38
38
|
export declare const createBlockActivityDetails: <Req, Res>(context: ReadonlyContext<Req, Res>) => BlockActivityDetails;
|
|
39
39
|
export declare const createAdditionalS2SActivityDetails: <Req, Res, Supported extends string, Added>({ ciSendRawUsernameOnAdditionalS2SActivity }: IConfiguration<Req, Res, Supported, Added>, { productData }: ReadonlyContext<Req, Res>) => AdditionalS2SActivityDetails;
|
|
40
|
+
export declare const createPageRedirectedActivityDetails: <Req, Res>(context: ReadonlyContext<Req, Res>) => PageRedirectedActivityDetails;
|
|
40
41
|
export declare const toHeaderEntryArray: (headers: Record<string, string[]>) => HeaderEntry[];
|
|
@@ -40,6 +40,7 @@ export declare class DefaultContext<Req, Res, Supported extends string, Added> i
|
|
|
40
40
|
reasons: Partial<Record<ProductName, string>>;
|
|
41
41
|
score?: number;
|
|
42
42
|
blockAction: BlockAction;
|
|
43
|
+
redirectUrl?: string;
|
|
43
44
|
pxhd?: PXHD;
|
|
44
45
|
pxde?: PXDE;
|
|
45
46
|
pxdeVerified?: boolean;
|
|
@@ -95,6 +95,10 @@ export interface IContext<Req, Res> {
|
|
|
95
95
|
* The type of block page to present in case of a block.
|
|
96
96
|
*/
|
|
97
97
|
blockAction: BlockAction;
|
|
98
|
+
/**
|
|
99
|
+
* The URL to redirect the client to when the action is REDIRECT.
|
|
100
|
+
*/
|
|
101
|
+
redirectUrl?: string;
|
|
98
102
|
/**
|
|
99
103
|
* The PXHD (PerimeterX Hashed Data) cookie value, if it exists on the request.
|
|
100
104
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IConfiguration } from '../../config';
|
|
2
|
+
import { IContext, ReadonlyContext } from '../../context';
|
|
3
|
+
import { IMinimalResponse } from '../../http';
|
|
4
|
+
import { ICors } from '../../cors';
|
|
5
|
+
import { IPhase } from '../IPhase';
|
|
6
|
+
import { PhaseResult } from '../PhaseResult';
|
|
7
|
+
/**
|
|
8
|
+
* `CreateRedirectResponsePhase` is a phase that creates a 302 redirect response when the enforcer
|
|
9
|
+
* action is REDIRECT. It mirrors the structure of `CreateBlockResponsePhase`.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CreateRedirectResponsePhase<Req, Res, Supported extends string, Added> implements IPhase<Req, Res> {
|
|
12
|
+
protected readonly config: IConfiguration<Req, Res, Supported, Added>;
|
|
13
|
+
protected readonly cors?: ICors<Req, Res>;
|
|
14
|
+
constructor(config: IConfiguration<Req, Res, Supported, Added>, cors?: ICors<Req, Res>);
|
|
15
|
+
execute(context: IContext<Req, Res>): Promise<PhaseResult>;
|
|
16
|
+
protected addHeadersToResponse(response: IMinimalResponse, context: ReadonlyContext<Req, Res>): Promise<IMinimalResponse>;
|
|
17
|
+
}
|
|
@@ -6,6 +6,7 @@ export * from './ParseTokenPhase';
|
|
|
6
6
|
export * from './DecideActionPhase';
|
|
7
7
|
export * from './RiskApiPhase';
|
|
8
8
|
export * from './CreateBlockResponsePhase';
|
|
9
|
+
export * from './CreateRedirectResponsePhase';
|
|
9
10
|
export * from './ModifyIncomingRequestPhase';
|
|
10
11
|
export * from './EnrichContextFromResponsePhase';
|
|
11
12
|
export * from './ModifyOutgoingResponsePhase';
|
|
@@ -42,7 +42,7 @@ export declare class BotDefender<Req, Res, Supported extends string, Added> impl
|
|
|
42
42
|
protected getNoTokenS2SCallReason({ pxhd, isMobile, tokenData, }: ReadonlyContext<Req, Res>): BotDefenderS2SCallReason;
|
|
43
43
|
protected getActionForSuccessfulTokenParse(token: IToken<Req, Res>, isMonitoredRequest: boolean, isSensitiveRequest: boolean): ActionData;
|
|
44
44
|
enrichContextFromRiskApi(context: ReadonlyContext<Req, Res>): Promise<Partial<BotDefenderData>>;
|
|
45
|
-
protected getRiskApiActionData({ riskApiData, productData: { bd }, }: ReadonlyContext<Req, Res>): Promise<ActionData>;
|
|
45
|
+
protected getRiskApiActionData({ riskApiData, productData: { bd }, logger, }: ReadonlyContext<Req, Res>): Promise<ActionData>;
|
|
46
46
|
protected getSuccessfulRiskApiAction(riskResponse: DeepReadonly<IRiskResponse>, isMonitored: boolean): ActionData;
|
|
47
47
|
shouldBlock(context: ReadonlyContext<Req, Res>): boolean;
|
|
48
48
|
createBlockResponse(context: ReadonlyContext<Req, Res>): IMinimalResponse;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Action } from '../../../action';
|
|
2
2
|
import { BotDefenderBlockReason } from './BotDefenderBlockReason';
|
|
3
3
|
import { BotDefenderPassReason } from './BotDefenderPassReason';
|
|
4
|
+
import { BotDefenderRedirectReason } from './BotDefenderRedirectReason';
|
|
4
5
|
import { BotDefenderS2SCallReason } from './BotDefenderS2SCallReason';
|
|
5
|
-
export type BotDefenderReasonType<A extends Action> = A extends Action.BLOCK ? BotDefenderBlockReason : A extends Action.SIMULATED_BLOCK ? BotDefenderBlockReason : A extends Action.PASS_REQUEST ? BotDefenderPassReason : A extends Action.TRIGGER_RISK_API ? BotDefenderS2SCallReason : never;
|
|
6
|
+
export type BotDefenderReasonType<A extends Action> = A extends Action.BLOCK ? BotDefenderBlockReason : A extends Action.SIMULATED_BLOCK ? BotDefenderBlockReason : A extends Action.PASS_REQUEST ? BotDefenderPassReason : A extends Action.TRIGGER_RISK_API ? BotDefenderS2SCallReason : A extends Action.REDIRECT ? BotDefenderRedirectReason : never;
|
|
@@ -15,6 +15,9 @@ export interface IRiskResponse {
|
|
|
15
15
|
readonly drc?: number;
|
|
16
16
|
readonly additionalRiskInfo?: string;
|
|
17
17
|
readonly telemetryRequested?: boolean;
|
|
18
|
+
readonly redirectUrl?: string;
|
|
19
|
+
readonly redirectRuleId?: string;
|
|
20
|
+
readonly redirectRuleName?: string;
|
|
18
21
|
validate(): AsyncOrSync<boolean>;
|
|
19
22
|
toJSON(): RiskResponseJson;
|
|
20
23
|
}
|
|
@@ -25,5 +25,8 @@ export declare abstract class RiskResponseBase<TokenV extends TokenVersion> impl
|
|
|
25
25
|
get additionalRiskInfo(): string | undefined;
|
|
26
26
|
get telemetryRequested(): boolean | undefined;
|
|
27
27
|
get drc(): number | undefined;
|
|
28
|
+
get redirectUrl(): string | undefined;
|
|
29
|
+
get redirectRuleId(): string | undefined;
|
|
30
|
+
get redirectRuleName(): string | undefined;
|
|
28
31
|
toJSON(): RiskResponseJson;
|
|
29
32
|
}
|
|
@@ -15,6 +15,9 @@ export declare class SerializedRiskResponse implements IRiskResponse {
|
|
|
15
15
|
readonly score: number | undefined;
|
|
16
16
|
readonly status?: RiskStatus;
|
|
17
17
|
readonly uuid: string | undefined;
|
|
18
|
+
readonly redirectUrl: string | undefined;
|
|
19
|
+
readonly redirectRuleId: string | undefined;
|
|
20
|
+
readonly redirectRuleName: string | undefined;
|
|
18
21
|
constructor(riskResponseJson: RiskResponseJson);
|
|
19
22
|
validate(): boolean;
|
|
20
23
|
toJSON(): RiskResponseJson;
|
|
@@ -12,4 +12,4 @@ export declare const PUSH_DATA_FEATURE_HEADER_NAME = "x-px-feature";
|
|
|
12
12
|
export declare const EMAIL_ADDRESS_REGEX: RegExp;
|
|
13
13
|
export declare const URL_REGEX: RegExp;
|
|
14
14
|
export declare const REGEX_STRUCTURE: RegExp;
|
|
15
|
-
export declare const CORE_MODULE_VERSION = "JS Core 1.
|
|
15
|
+
export declare const CORE_MODULE_VERSION = "JS Core 1.1.0";
|