perimeterx-js-core 0.15.2 → 0.16.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/activities/HttpActivityClient.js +4 -4
- package/lib/cjs/activities/HttpBatchedActivityClient.js +7 -7
- package/lib/cjs/additional_activity_handler/AdditionalActivityHandlerUtils.js +2 -2
- package/lib/cjs/config/ConfigurationBase.js +4 -1
- package/lib/cjs/config/remote_config/DefaultRemoteConfigUpdater.js +25 -30
- package/lib/cjs/config/remote_config/RemoteConfigUtils.js +14 -0
- package/lib/cjs/config/remote_config/index.js +1 -0
- package/lib/cjs/context/DefaultContext.js +18 -7
- package/lib/cjs/custom_parameters/CustomParametersUtils.js +1 -1
- package/lib/cjs/enforcer/EnforcerBase.js +40 -31
- package/lib/cjs/graphql/DefaultGraphQLParser.js +20 -22
- package/lib/cjs/impl/url/DefaultUrlUtils.js +7 -1
- package/lib/cjs/logger/DefaultLogger.js +2 -2
- package/lib/cjs/logger/HttpLogServiceClient.js +32 -27
- package/lib/cjs/logger/LoggerBase.js +5 -1
- package/lib/cjs/monitored_request/MonitoredRequestUtils.js +8 -8
- package/lib/cjs/phase/impl/CreateBlockResponsePhase.js +2 -2
- package/lib/cjs/phase/impl/DecideActionPhase.js +3 -4
- package/lib/cjs/phase/impl/EnrichContextFromRequestPhase.js +3 -2
- package/lib/cjs/phase/impl/EnrichContextFromResponsePhase.js +1 -1
- package/lib/cjs/phase/impl/FirstPartyPhase.js +4 -4
- package/lib/cjs/phase/impl/RiskApiPhase.js +1 -1
- package/lib/cjs/phase/impl/SendLogsPhase.js +2 -2
- package/lib/cjs/phase/impl/UpdateRemoteConfigPhase.js +0 -1
- package/lib/cjs/products/account_defender/AccountDefender.js +9 -8
- package/lib/cjs/products/bot_defender/filter/DefaultBotDefenderFilter.js +10 -10
- package/lib/cjs/products/bot_defender/first_party/DefaultBotDefenderFirstParty.js +17 -17
- package/lib/cjs/products/credential_intelligence/endpoint/CredentialEndpoint.js +8 -9
- package/lib/cjs/products/credential_intelligence/endpoint/CredentialEndpointManager.js +13 -15
- package/lib/cjs/pxde/DefaultDataEnrichment.js +11 -11
- package/lib/cjs/risk_api/client/PostRiskApiClientBase.js +5 -5
- package/lib/cjs/risk_token/parser/TokenParserBase.js +12 -13
- package/lib/cjs/risk_token/token/v2/DefaultTokenV2.js +5 -5
- package/lib/cjs/risk_token/token/v3/DefaultTokenV3.js +11 -11
- package/lib/cjs/sensitive_request/SensitiveRequestUtils.js +4 -4
- package/lib/cjs/telemetry/DefaultTelemetry.js +7 -7
- package/lib/cjs/utils/constants.js +1 -1
- package/lib/cjs/utils/timestamp_hmac_header_validator/DefaultTimestampHmacHeaderValidator.js +7 -7
- package/lib/esm/activities/HttpActivityClient.js +4 -4
- package/lib/esm/activities/HttpBatchedActivityClient.js +7 -7
- package/lib/esm/additional_activity_handler/AdditionalActivityHandlerUtils.js +2 -2
- package/lib/esm/config/ConfigurationBase.js +4 -1
- package/lib/esm/config/remote_config/DefaultRemoteConfigUpdater.js +21 -23
- package/lib/esm/config/remote_config/RemoteConfigUtils.js +9 -0
- package/lib/esm/config/remote_config/index.js +1 -0
- package/lib/esm/context/DefaultContext.js +18 -8
- package/lib/esm/custom_parameters/CustomParametersUtils.js +1 -1
- package/lib/esm/enforcer/EnforcerBase.js +18 -7
- package/lib/esm/graphql/DefaultGraphQLParser.js +9 -10
- package/lib/esm/impl/url/DefaultUrlUtils.js +7 -1
- package/lib/esm/logger/DefaultLogger.js +2 -2
- package/lib/esm/logger/HttpLogServiceClient.js +25 -27
- package/lib/esm/logger/LoggerBase.js +6 -1
- package/lib/esm/monitored_request/MonitoredRequestUtils.js +8 -8
- package/lib/esm/phase/impl/CreateBlockResponsePhase.js +2 -2
- package/lib/esm/phase/impl/DecideActionPhase.js +2 -6
- package/lib/esm/phase/impl/EnrichContextFromRequestPhase.js +4 -2
- package/lib/esm/phase/impl/EnrichContextFromResponsePhase.js +1 -1
- package/lib/esm/phase/impl/FirstPartyPhase.js +4 -4
- package/lib/esm/phase/impl/RiskApiPhase.js +1 -1
- package/lib/esm/phase/impl/SendLogsPhase.js +2 -2
- package/lib/esm/phase/impl/UpdateRemoteConfigPhase.js +0 -1
- package/lib/esm/products/account_defender/AccountDefender.js +9 -8
- package/lib/esm/products/bot_defender/filter/DefaultBotDefenderFilter.js +8 -8
- package/lib/esm/products/bot_defender/first_party/DefaultBotDefenderFirstParty.js +16 -15
- package/lib/esm/products/credential_intelligence/endpoint/CredentialEndpoint.js +8 -10
- package/lib/esm/products/credential_intelligence/endpoint/CredentialEndpointManager.js +5 -5
- package/lib/esm/pxde/DefaultDataEnrichment.js +11 -11
- package/lib/esm/risk_api/client/PostRiskApiClientBase.js +5 -5
- package/lib/esm/risk_token/parser/TokenParserBase.js +12 -11
- package/lib/esm/risk_token/token/v2/DefaultTokenV2.js +5 -5
- package/lib/esm/risk_token/token/v3/DefaultTokenV3.js +11 -11
- package/lib/esm/sensitive_request/SensitiveRequestUtils.js +4 -4
- package/lib/esm/telemetry/DefaultTelemetry.js +7 -7
- package/lib/esm/utils/constants.js +1 -1
- package/lib/esm/utils/timestamp_hmac_header_validator/DefaultTimestampHmacHeaderValidator.js +7 -7
- package/lib/types/activities/HttpActivityClient.d.ts +4 -3
- package/lib/types/activities/HttpBatchedActivityClient.d.ts +8 -7
- package/lib/types/activities/utils.d.ts +270 -0
- package/lib/types/blocker/utils.d.ts +27 -0
- package/lib/types/config/ConfigurationBase.d.ts +6 -5
- package/lib/types/config/remote_config/DefaultRemoteConfigUpdater.d.ts +5 -5
- package/lib/types/config/remote_config/RemoteConfigUtils.d.ts +4 -0
- package/lib/types/config/remote_config/index.d.ts +1 -0
- package/lib/types/context/DefaultContext.d.ts +7 -2
- package/lib/types/context/interfaces/IContext.d.ts +11 -2
- package/lib/types/enforcer/EnforcerBase.d.ts +2 -1
- package/lib/types/graphql/DefaultGraphQLParser.d.ts +1 -2
- package/lib/types/logger/DefaultLogger.d.ts +1 -1
- package/lib/types/logger/HttpLogServiceClient.d.ts +5 -10
- package/lib/types/logger/ILogServiceClient.d.ts +1 -2
- package/lib/types/logger/LoggerBase.d.ts +2 -1
- package/lib/types/logger/model/LogMetadata.d.ts +1 -0
- package/lib/types/monitored_request/MonitoredRequestUtils.d.ts +1353 -2
- package/lib/types/phase/impl/DecideActionPhase.d.ts +0 -3
- package/lib/types/phase/impl/EnrichContextFromRequestPhase.d.ts +1 -0
- package/lib/types/phase/impl/FirstPartyPhase.d.ts +1 -1
- package/lib/types/products/account_defender/AccountDefender.d.ts +4 -5
- package/lib/types/products/bot_defender/filter/DefaultBotDefenderFilter.d.ts +2 -3
- package/lib/types/products/bot_defender/first_party/DefaultBotDefenderFirstParty.d.ts +3 -4
- package/lib/types/products/credential_intelligence/endpoint/CredentialEndpoint.d.ts +3 -5
- package/lib/types/products/credential_intelligence/endpoint/CredentialEndpointManager.d.ts +2 -2
- package/lib/types/products/credential_intelligence/endpoint/ICredentialEndpoint.d.ts +3 -4
- package/lib/types/pxhd/PXHDUtils.d.ts +54 -0
- package/lib/types/risk_api/client/PostRiskApiClientBase.d.ts +1 -1
- package/lib/types/risk_token/parser/TokenParserBase.d.ts +4 -5
- package/lib/types/risk_token/token/v3/DefaultTokenV3.d.ts +1 -1
- package/lib/types/sensitive_request/SensitiveRequestUtils.d.ts +705 -17
- package/lib/types/telemetry/DefaultTelemetry.d.ts +1 -1
- package/lib/types/utils/constants.d.ts +1 -1
- package/lib/types/utils/timestamp_hmac_header_validator/DefaultTimestampHmacHeaderValidator.d.ts +3 -2
- package/lib/types/utils/timestamp_hmac_header_validator/ITimestampHmacHeaderValidator.d.ts +2 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ export class AccountDefender {
|
|
|
9
9
|
}
|
|
10
10
|
async enrichContextFromRequest(context) {
|
|
11
11
|
const crossTabSession = context.requestData.cookies[CROSS_TAB_SESSION_COOKIE_NAME];
|
|
12
|
-
const jwtData = this.getJwtData(context
|
|
12
|
+
const jwtData = this.getJwtData(context);
|
|
13
13
|
return { crossTabSession, ...jwtData };
|
|
14
14
|
}
|
|
15
15
|
async enrichContextFromRiskApi(context) {
|
|
@@ -24,10 +24,11 @@ export class AccountDefender {
|
|
|
24
24
|
async modifyOutgoingResponse(context) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
getJwtData(
|
|
27
|
+
getJwtData(context) {
|
|
28
28
|
let jwtToken;
|
|
29
29
|
let userIdFieldName;
|
|
30
30
|
let additionalFieldNames;
|
|
31
|
+
const { requestData } = context;
|
|
31
32
|
if (this.config.jwtCookieName) {
|
|
32
33
|
jwtToken = requestData.cookies[this.config.jwtCookieName];
|
|
33
34
|
if (jwtToken) {
|
|
@@ -42,11 +43,11 @@ export class AccountDefender {
|
|
|
42
43
|
additionalFieldNames = this.config.jwtHeaderAdditionalFieldNames;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
return jwtToken ? this.extractJwtData(jwtToken, userIdFieldName, additionalFieldNames) : null;
|
|
46
|
+
return jwtToken ? this.extractJwtData(jwtToken, userIdFieldName, additionalFieldNames, context) : null;
|
|
46
47
|
}
|
|
47
|
-
extractJwtData(jwt, userIdFieldName, additionalFieldNames) {
|
|
48
|
+
extractJwtData(jwt, userIdFieldName, additionalFieldNames, context) {
|
|
48
49
|
try {
|
|
49
|
-
const decodedJwt = this.getDecodedJwt(jwt);
|
|
50
|
+
const decodedJwt = this.getDecodedJwt(jwt, context);
|
|
50
51
|
if (decodedJwt) {
|
|
51
52
|
const appUserId = getPropertyFromObject(decodedJwt, ...userIdFieldName.split('.'));
|
|
52
53
|
const additionalFields = additionalFieldNames.reduce((matchedFields, fieldName) => {
|
|
@@ -61,18 +62,18 @@ export class AccountDefender {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
catch (e) {
|
|
64
|
-
|
|
65
|
+
context.logger.debug(`unable to get account defender JWT data: ${e}`);
|
|
65
66
|
}
|
|
66
67
|
return null;
|
|
67
68
|
}
|
|
68
|
-
getDecodedJwt(jwt) {
|
|
69
|
+
getDecodedJwt(jwt, context) {
|
|
69
70
|
try {
|
|
70
71
|
const encodedPayload = jwt.split('.')?.[1];
|
|
71
72
|
const base64 = encodedPayload.replace('-', '+').replace('_', '/');
|
|
72
73
|
return JSON.parse(this.base64Utils.base64Decode(base64));
|
|
73
74
|
}
|
|
74
75
|
catch (e) {
|
|
75
|
-
|
|
76
|
+
context.logger.debug(`unable to decode account defender jwt token: ${e}`);
|
|
76
77
|
return null;
|
|
77
78
|
}
|
|
78
79
|
}
|
|
@@ -9,15 +9,15 @@ export class DefaultBotDefenderFilter {
|
|
|
9
9
|
this.ipRangeChecker = ipRangeChecker;
|
|
10
10
|
}
|
|
11
11
|
async shouldFilter(context) {
|
|
12
|
-
const
|
|
13
|
-
const filterReason = await this.getFilterReason(requestData);
|
|
12
|
+
const filterReason = await this.getFilterReason(context);
|
|
14
13
|
if (filterReason !== FilterReason.NONE) {
|
|
15
|
-
|
|
14
|
+
context.logger.debug(`filter request due to ${filterReason}`);
|
|
16
15
|
return true;
|
|
17
16
|
}
|
|
18
17
|
return false;
|
|
19
18
|
}
|
|
20
|
-
async getFilterReason(
|
|
19
|
+
async getFilterReason(context) {
|
|
20
|
+
const { requestData } = context;
|
|
21
21
|
if (this.shouldFilterByExtension(requestData)) {
|
|
22
22
|
return FilterReason.EXTENSION;
|
|
23
23
|
}
|
|
@@ -33,7 +33,7 @@ export class DefaultBotDefenderFilter {
|
|
|
33
33
|
if (this.shouldFilterByIp(requestData.ip)) {
|
|
34
34
|
return FilterReason.IP;
|
|
35
35
|
}
|
|
36
|
-
if (await this.shouldFilterByCustomFunction(
|
|
36
|
+
if (await this.shouldFilterByCustomFunction(context)) {
|
|
37
37
|
return FilterReason.CUSTOM;
|
|
38
38
|
}
|
|
39
39
|
return FilterReason.NONE;
|
|
@@ -57,13 +57,13 @@ export class DefaultBotDefenderFilter {
|
|
|
57
57
|
shouldFilterByUserAgent(userAgent) {
|
|
58
58
|
return this.config.filteredUserAgents.includes(userAgent);
|
|
59
59
|
}
|
|
60
|
-
async shouldFilterByCustomFunction(
|
|
60
|
+
async shouldFilterByCustomFunction(context) {
|
|
61
61
|
if (this.config.customIsFilteredRequest && typeof this.config.customIsFilteredRequest === 'function') {
|
|
62
62
|
try {
|
|
63
|
-
return await this.config.customIsFilteredRequest(request.getUnderlyingRequest());
|
|
63
|
+
return await this.config.customIsFilteredRequest(context.requestData.request.getUnderlyingRequest());
|
|
64
64
|
}
|
|
65
65
|
catch (err) {
|
|
66
|
-
|
|
66
|
+
context.logger.debug(`caught custom filtered request error - ${err}`);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
return false;
|
|
@@ -30,12 +30,12 @@ export class DefaultBotDefenderFirstParty {
|
|
|
30
30
|
if (!this.config.firstPartyEnabled) {
|
|
31
31
|
return { defaultResponse };
|
|
32
32
|
}
|
|
33
|
-
const url = this.getThirdPartySensorScriptUrl();
|
|
33
|
+
const url = this.getThirdPartySensorScriptUrl(context);
|
|
34
34
|
if (!url) {
|
|
35
35
|
return { defaultResponse };
|
|
36
36
|
}
|
|
37
37
|
const request = await this.getOutgoingRequest(url, context);
|
|
38
|
-
|
|
38
|
+
context.logger.debug(`proxying first party sensor script ${context.requestData.url.pathname} to ${url}`);
|
|
39
39
|
return { request, defaultResponse };
|
|
40
40
|
}
|
|
41
41
|
async proxyXhrRequest(context, prefix) {
|
|
@@ -48,7 +48,7 @@ export class DefaultBotDefenderFirstParty {
|
|
|
48
48
|
return { defaultResponse };
|
|
49
49
|
}
|
|
50
50
|
const request = await this.getOutgoingRequest(url, context);
|
|
51
|
-
|
|
51
|
+
context.logger.debug(`proxying first party XHR request ${context.requestData.url.pathname} to ${url}`);
|
|
52
52
|
return { request, defaultResponse };
|
|
53
53
|
}
|
|
54
54
|
static getDefaultXhrResponse(path) {
|
|
@@ -69,18 +69,19 @@ export class DefaultBotDefenderFirstParty {
|
|
|
69
69
|
return { defaultResponse };
|
|
70
70
|
}
|
|
71
71
|
const request = await this.getOutgoingRequest(url, context);
|
|
72
|
-
|
|
72
|
+
context.logger.debug(`proxying first party captcha script ${context.requestData.url.pathname} to ${url}`);
|
|
73
73
|
return { request, defaultResponse };
|
|
74
74
|
}
|
|
75
|
-
async getOutgoingRequest(url,
|
|
75
|
+
async getOutgoingRequest(url, context) {
|
|
76
76
|
return new OutgoingRequestImpl({
|
|
77
77
|
url: url.href,
|
|
78
|
-
method: requestData.method,
|
|
79
|
-
headers: this.prepareFirstPartyHeaders(url,
|
|
80
|
-
body: requestData.request.body,
|
|
78
|
+
method: context.requestData.method,
|
|
79
|
+
headers: this.prepareFirstPartyHeaders(url, context),
|
|
80
|
+
body: context.requestData.request.body,
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
prepareFirstPartyHeaders(url,
|
|
83
|
+
prepareFirstPartyHeaders(url, context) {
|
|
84
|
+
const { requestData, vid } = context;
|
|
84
85
|
let headers = toMutableHeaders(requestData.headers);
|
|
85
86
|
try {
|
|
86
87
|
headers = removeSensitiveHeaders(headers, this.config.sensitiveHeaders);
|
|
@@ -93,7 +94,7 @@ export class DefaultBotDefenderFirstParty {
|
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
catch (e) {
|
|
96
|
-
|
|
97
|
+
context.logger.error(`Caught error preparing first party headers: ${e}`);
|
|
97
98
|
}
|
|
98
99
|
return headers;
|
|
99
100
|
}
|
|
@@ -108,12 +109,12 @@ export class DefaultBotDefenderFirstParty {
|
|
|
108
109
|
headers[FIRST_PARTY_HEADER_NAME] = [FIRST_PARTY_HEADER_VALUE];
|
|
109
110
|
headers[X_PX_ENFORCER_TRUE_IP_HEADER_NAME] = [ip];
|
|
110
111
|
}
|
|
111
|
-
getThirdPartySensorScriptUrl() {
|
|
112
|
+
getThirdPartySensorScriptUrl(context) {
|
|
112
113
|
try {
|
|
113
114
|
return this.urlUtils.createUrl(`${this.config.backendClientUrl}/${this.config.appId}/main.min.js`);
|
|
114
115
|
}
|
|
115
116
|
catch (e) {
|
|
116
|
-
|
|
117
|
+
context.logger.debug(`unable to create third party sensor URL: ${e}`);
|
|
117
118
|
return null;
|
|
118
119
|
}
|
|
119
120
|
}
|
|
@@ -124,7 +125,7 @@ export class DefaultBotDefenderFirstParty {
|
|
|
124
125
|
return this.urlUtils.createUrl(`${backendCaptchaUrl}/${appId}${FirstPartySuffix.CAPTCHA}.js${originalUrl.search}`);
|
|
125
126
|
}
|
|
126
127
|
catch (e) {
|
|
127
|
-
|
|
128
|
+
context.logger.debug(`unable to create third party captcha URL: ${e}`);
|
|
128
129
|
return null;
|
|
129
130
|
}
|
|
130
131
|
}
|
|
@@ -135,13 +136,13 @@ export class DefaultBotDefenderFirstParty {
|
|
|
135
136
|
const thirdPartyUrl = this.urlUtils.createUrl(`${this.config.backendCollectorUrl}${pathname}${originalUrl.search}`);
|
|
136
137
|
const { host } = this.urlUtils.createUrl(this.config.backendCollectorUrl);
|
|
137
138
|
if (!this.isValidThirdPartyUrl(thirdPartyUrl, host, pathname)) {
|
|
138
|
-
|
|
139
|
+
context.logger.debug(`invalid third party url: ${thirdPartyUrl}`);
|
|
139
140
|
return null;
|
|
140
141
|
}
|
|
141
142
|
return thirdPartyUrl;
|
|
142
143
|
}
|
|
143
144
|
catch (e) {
|
|
144
|
-
|
|
145
|
+
context.logger.debug(`unable to create third party XHR URL: ${e}`);
|
|
145
146
|
return null;
|
|
146
147
|
}
|
|
147
148
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export class CredentialEndpoint {
|
|
2
|
-
config;
|
|
3
2
|
matcher;
|
|
4
3
|
extractor;
|
|
5
4
|
protocol;
|
|
6
5
|
loginSuccessfulParser;
|
|
7
6
|
constructor(config, matcher, extractor, protocol, loginSuccessfulParser) {
|
|
8
|
-
this.config = config;
|
|
9
7
|
this.matcher = matcher;
|
|
10
8
|
this.extractor = extractor;
|
|
11
9
|
this.protocol = protocol;
|
|
@@ -14,27 +12,27 @@ export class CredentialEndpoint {
|
|
|
14
12
|
matches(requestData) {
|
|
15
13
|
return this.matcher.matches(requestData);
|
|
16
14
|
}
|
|
17
|
-
async getCredentialData(
|
|
15
|
+
async getCredentialData(context) {
|
|
18
16
|
try {
|
|
19
|
-
const credentials = await this.extractor.extractCredentials(request);
|
|
17
|
+
const credentials = await this.extractor.extractCredentials(context.requestData.request);
|
|
20
18
|
if (!credentials?.user && !credentials?.pass) {
|
|
21
|
-
|
|
19
|
+
context.logger.debug('unable to extract credentials');
|
|
22
20
|
return null;
|
|
23
21
|
}
|
|
24
|
-
|
|
22
|
+
context.logger.debug(`successfully extracted credentials`);
|
|
25
23
|
return await this.protocol.hashCredentials(credentials);
|
|
26
24
|
}
|
|
27
25
|
catch (e) {
|
|
28
|
-
|
|
26
|
+
context.logger.debug(`caught error extracting credentials: ${e}`);
|
|
29
27
|
return null;
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
|
-
async isLoginSuccessful(
|
|
30
|
+
async isLoginSuccessful(context) {
|
|
33
31
|
try {
|
|
34
|
-
return this.loginSuccessfulParser.isLoginSuccessful(response);
|
|
32
|
+
return this.loginSuccessfulParser.isLoginSuccessful(context.response);
|
|
35
33
|
}
|
|
36
34
|
catch (e) {
|
|
37
|
-
|
|
35
|
+
context.logger.debug(`caught error determining login successful: ${e}`);
|
|
38
36
|
return null;
|
|
39
37
|
}
|
|
40
38
|
}
|
|
@@ -7,13 +7,13 @@ export class CredentialEndpointManager {
|
|
|
7
7
|
getEndpointIndex({ requestData }) {
|
|
8
8
|
return this.endpoints.findIndex((endpoint) => endpoint.matches(requestData));
|
|
9
9
|
}
|
|
10
|
-
async getCredentialsData(endpointIndex,
|
|
11
|
-
return await this.endpoints[endpointIndex]?.getCredentialData(
|
|
10
|
+
async getCredentialsData(endpointIndex, context) {
|
|
11
|
+
return await this.endpoints[endpointIndex]?.getCredentialData(context);
|
|
12
12
|
}
|
|
13
|
-
async isLoginSuccessful(endpointIndex,
|
|
14
|
-
if (!response) {
|
|
13
|
+
async isLoginSuccessful(endpointIndex, context) {
|
|
14
|
+
if (!context.response) {
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
17
|
-
return await this.endpoints[endpointIndex]?.isLoginSuccessful(
|
|
17
|
+
return await this.endpoints[endpointIndex]?.isLoginSuccessful(context);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -13,48 +13,48 @@ export class DefaultDataEnrichment {
|
|
|
13
13
|
try {
|
|
14
14
|
const pxdeCookie = context.requestData.cookies[PXDE_COOKIE_NAME];
|
|
15
15
|
if (pxdeCookie) {
|
|
16
|
-
return await this.parsePxde(pxdeCookie);
|
|
16
|
+
return await this.parsePxde(pxdeCookie, context);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
catch (e) {
|
|
20
|
-
|
|
20
|
+
context.logger.debug(`unable to parse pxde cookie - ${e}`);
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
-
async parsePxde(pxdeCookie) {
|
|
24
|
+
async parsePxde(pxdeCookie, context) {
|
|
25
25
|
const pxdeParts = pxdeCookie.split(PXDE_COOKIE_DELIMITER);
|
|
26
26
|
if (pxdeParts.length !== PXDE_COOKIE_PARTS_COUNT) {
|
|
27
|
-
|
|
27
|
+
context.logger.debug(`malformed pxde cookie: ${pxdeCookie}`);
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
const hmac = pxdeParts[PXDE_HMAC_INDEX];
|
|
31
31
|
const encodedPayload = pxdeParts[PXDE_PAYLOAD_INDEX];
|
|
32
32
|
if (!hmac || !encodedPayload) {
|
|
33
|
-
|
|
33
|
+
context.logger.debug(`malformed pxde cookie: hmac: ${hmac}, payload: ${encodedPayload}`);
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
return {
|
|
37
|
-
pxde: await this.parsePxdePayload(encodedPayload),
|
|
38
|
-
pxdeVerified: await this.verifyPxdeHmac(hmac, encodedPayload),
|
|
37
|
+
pxde: await this.parsePxdePayload(encodedPayload, context),
|
|
38
|
+
pxdeVerified: await this.verifyPxdeHmac(hmac, encodedPayload, context),
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
async verifyPxdeHmac(givenHmac, encodedPayload) {
|
|
41
|
+
async verifyPxdeHmac(givenHmac, encodedPayload, context) {
|
|
42
42
|
try {
|
|
43
43
|
return (givenHmac ===
|
|
44
44
|
(await this.hmacUtils.createHmac(Algorithm.SHA256, encodedPayload, this.config.cookieSecret)));
|
|
45
45
|
}
|
|
46
46
|
catch (e) {
|
|
47
|
-
|
|
47
|
+
context.logger.debug(`failed verifying pxde hmac: ${e}`);
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
async parsePxdePayload(encodedPayload) {
|
|
51
|
+
async parsePxdePayload(encodedPayload, context) {
|
|
52
52
|
try {
|
|
53
53
|
const decodedPayload = this.base64Utils.base64Decode(encodedPayload);
|
|
54
54
|
return JSON.parse(decodedPayload);
|
|
55
55
|
}
|
|
56
56
|
catch (e) {
|
|
57
|
-
|
|
57
|
+
context.logger.debug(`failed parsing pxde payload: ${e}`);
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -20,7 +20,7 @@ export class PostRiskApiClientBase {
|
|
|
20
20
|
const riskApiData = { riskApiCallResult: RiskApiCallResult.NONE };
|
|
21
21
|
try {
|
|
22
22
|
const riskActivity = this.createRiskActivity(context);
|
|
23
|
-
response = await this.sendRiskActivity(riskActivity, riskApiData);
|
|
23
|
+
response = await this.sendRiskActivity(riskActivity, riskApiData, context);
|
|
24
24
|
if (response?.status !== 200) {
|
|
25
25
|
return await this.handleS2SError(riskApiData, response);
|
|
26
26
|
}
|
|
@@ -29,14 +29,14 @@ export class PostRiskApiClientBase {
|
|
|
29
29
|
if (!(await riskResponse.validate())) {
|
|
30
30
|
return await this.handleS2SError(riskApiData, response);
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
context.logger.debug(`received risk response, score: ${riskResponse.score}, rtt: ${riskApiData.riskRtt}`);
|
|
33
33
|
return riskApiData;
|
|
34
34
|
}
|
|
35
35
|
catch (err) {
|
|
36
36
|
if (err.name === EnforcerErrorName.ENFORCER_TIMEOUT_ERROR) {
|
|
37
37
|
return this.handleS2STimeout(riskApiData);
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
context.logger.error(`caught error in risk api: ${err} - ${JSON.stringify(context.requestData.url)}`);
|
|
40
40
|
return await this.handleS2SError(riskApiData, response, err);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -77,13 +77,13 @@ export class PostRiskApiClientBase {
|
|
|
77
77
|
const headersWithoutSensitive = removeSensitiveHeaders(headers, this.config.sensitiveHeaders);
|
|
78
78
|
return toHeaderEntryArray(headersWithoutSensitive);
|
|
79
79
|
}
|
|
80
|
-
async sendRiskActivity(riskActivity, riskApiData) {
|
|
80
|
+
async sendRiskActivity(riskActivity, riskApiData, context) {
|
|
81
81
|
const url = this.getRiskUrl();
|
|
82
82
|
const headers = this.getRiskHeaders();
|
|
83
83
|
const body = JSON.stringify(riskActivity);
|
|
84
84
|
const method = HttpMethod.POST;
|
|
85
85
|
const riskRequest = new OutgoingRequestImpl({ url, method, headers, body });
|
|
86
|
-
|
|
86
|
+
context.logger.debug(`sending risk api to ${url}`);
|
|
87
87
|
const startTime = Date.now();
|
|
88
88
|
const response = await this.httpClient.send(riskRequest, { timeoutMs: this.config.s2sTimeout });
|
|
89
89
|
const endTime = Date.now();
|
|
@@ -13,33 +13,34 @@ export class TokenParserBase {
|
|
|
13
13
|
const tokenData = this.initializeToken(context);
|
|
14
14
|
try {
|
|
15
15
|
if (!tokenData.token) {
|
|
16
|
-
|
|
16
|
+
context.logger.debug('no token found');
|
|
17
17
|
await this.handleMobileErrorIfNeeded(context, tokenData);
|
|
18
18
|
return tokenData;
|
|
19
19
|
}
|
|
20
20
|
tokenData.tokenParseResult = await tokenData.token.verify(context);
|
|
21
21
|
}
|
|
22
22
|
catch (e) {
|
|
23
|
-
|
|
23
|
+
context.logger.debug(`could not parse token - ${e}`);
|
|
24
24
|
tokenData.tokenParseResult = tokenData.token ? TokenParseResult.DECRYPTION_FAILED : TokenParseResult.NONE;
|
|
25
25
|
}
|
|
26
26
|
return tokenData;
|
|
27
27
|
}
|
|
28
|
-
initializeToken(
|
|
29
|
-
if (isMobile) {
|
|
30
|
-
return this.createMobileTokenData(
|
|
28
|
+
initializeToken(context) {
|
|
29
|
+
if (context.isMobile) {
|
|
30
|
+
return this.createMobileTokenData(context);
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
|
-
return this.createWebTokenData(requestData.cookies);
|
|
33
|
+
return this.createWebTokenData(context.requestData.cookies);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
createMobileTokenData(
|
|
36
|
+
createMobileTokenData(context) {
|
|
37
|
+
const { requestData: { request }, } = context;
|
|
37
38
|
const mobileToken = request.headers.get(X_PX_AUTHORIZATION_HEADER_NAME);
|
|
38
39
|
const tokenData = {
|
|
39
40
|
tokenParseResult: TokenParseResult.NONE,
|
|
40
|
-
token: this.getMobileToken(mobileToken),
|
|
41
|
+
token: this.getMobileToken(mobileToken, context),
|
|
41
42
|
mobileData: {
|
|
42
|
-
originalToken: this.getMobileToken(request.headers.get(X_PX_ORIGINAL_TOKEN_HEADER_NAME)),
|
|
43
|
+
originalToken: this.getMobileToken(request.headers.get(X_PX_ORIGINAL_TOKEN_HEADER_NAME), context),
|
|
43
44
|
bypassReason: request.headers.get(X_PX_BYPASS_REASON_HEADER_NAME) || '',
|
|
44
45
|
},
|
|
45
46
|
};
|
|
@@ -48,7 +49,7 @@ export class TokenParserBase {
|
|
|
48
49
|
}
|
|
49
50
|
return tokenData;
|
|
50
51
|
}
|
|
51
|
-
getMobileToken(mobileToken) {
|
|
52
|
+
getMobileToken(mobileToken, context) {
|
|
52
53
|
try {
|
|
53
54
|
if (!mobileToken || mobileToken?.indexOf(COOKIE_SPLIT_DELIMITER) === -1) {
|
|
54
55
|
return null;
|
|
@@ -61,7 +62,7 @@ export class TokenParserBase {
|
|
|
61
62
|
return this.createToken(this.config, { [cookieName]: cookieString.join(COOKIE_SPLIT_DELIMITER) }, this.options);
|
|
62
63
|
}
|
|
63
64
|
catch (e) {
|
|
64
|
-
|
|
65
|
+
context.logger.debug(`error extracting mobile token - ${e}, token: ${mobileToken}`);
|
|
65
66
|
return null;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
@@ -15,13 +15,13 @@ export class DefaultTokenV2 extends TokenBase {
|
|
|
15
15
|
try {
|
|
16
16
|
const payload = this.decode(this.cookieString);
|
|
17
17
|
if (payload?.t == null || payload?.h == null || payload?.u == null || payload?.v == null) {
|
|
18
|
-
|
|
18
|
+
context.logger.debug(`missing cookie v2 fields: ${JSON.stringify(payload)}`);
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
21
|
return payload;
|
|
22
22
|
}
|
|
23
23
|
catch (e) {
|
|
24
|
-
|
|
24
|
+
context.logger.debug(`cookie v2 decryption failed: ${e}`);
|
|
25
25
|
}
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
@@ -30,7 +30,7 @@ export class DefaultTokenV2 extends TokenBase {
|
|
|
30
30
|
!isValidUuid(this.payload.v) ||
|
|
31
31
|
!isValidUuid(this.payload.u) ||
|
|
32
32
|
!this.payload.h) {
|
|
33
|
-
|
|
33
|
+
context.logger.debug(`invalid cookie v2 structure: ${JSON.stringify(this.payload)}`);
|
|
34
34
|
return false;
|
|
35
35
|
}
|
|
36
36
|
try {
|
|
@@ -45,10 +45,10 @@ export class DefaultTokenV2 extends TokenBase {
|
|
|
45
45
|
this.isHighRisk = true;
|
|
46
46
|
return true;
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
context.logger.debug(`unknown cookie v2 hmac (${this.payload.h}), does not match pass (${passHmac}) or block (${blockHmac})`);
|
|
49
49
|
}
|
|
50
50
|
catch (e) {
|
|
51
|
-
|
|
51
|
+
context.logger.debug(`cookie v2 validation caught error: ${e}`);
|
|
52
52
|
}
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
@@ -22,7 +22,7 @@ export class DefaultTokenV3 extends TokenBase {
|
|
|
22
22
|
try {
|
|
23
23
|
const data = this.cookieString.split(COOKIE_SPLIT_DELIMITER);
|
|
24
24
|
if (data.length !== COOKIE_V3_PARTS_COUNT) {
|
|
25
|
-
|
|
25
|
+
context.logger.debug(`invalid cookie v3 structure: ${data}`);
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
this.hash = data[COOKIE_V3_HMAC_INDEX];
|
|
@@ -32,29 +32,29 @@ export class DefaultTokenV3 extends TokenBase {
|
|
|
32
32
|
: Number(data[COOKIE_V3_ITERATIONS_INDEX]);
|
|
33
33
|
const encryptedCookie = data[COOKIE_V3_PAYLOAD_INDEX];
|
|
34
34
|
if (!iterations || iterations > this.maxIterations || iterations < this.minIterations) {
|
|
35
|
-
|
|
35
|
+
context.logger.debug(`invalid cookie v3 iterations: ${iterations} is not between ${this.minIterations} and ${this.maxIterations}`);
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
if (!salt || typeof salt !== 'string' || salt.length > COOKIE_V3_MAXIMUM_SALT_LENGTH) {
|
|
39
|
-
|
|
39
|
+
context.logger.debug(`invalid cookie v3 salt: ${salt}`);
|
|
40
40
|
return null;
|
|
41
41
|
}
|
|
42
42
|
if (!encryptedCookie || typeof encryptedCookie !== 'string') {
|
|
43
|
-
|
|
43
|
+
context.logger.debug(`invalid cookie v3 encrypted payload: ${encryptedCookie}`);
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
|
-
return await this.decryptPayload(encryptedCookie, salt, iterations);
|
|
46
|
+
return await this.decryptPayload(encryptedCookie, salt, iterations, context);
|
|
47
47
|
}
|
|
48
48
|
catch (e) {
|
|
49
|
-
|
|
49
|
+
context.logger.debug(`cookie v3 decryption failed: ${e}`);
|
|
50
50
|
}
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
|
-
async decryptPayload(encryptedCookie, salt, iterations) {
|
|
53
|
+
async decryptPayload(encryptedCookie, salt, iterations, context) {
|
|
54
54
|
try {
|
|
55
55
|
const decryptedCookie = await this.cipherUtils.pbkdf2Decrypt(this.cookieSecret, encryptedCookie, iterations, salt);
|
|
56
56
|
if (!decryptedCookie) {
|
|
57
|
-
|
|
57
|
+
context.logger.debug(`cookie v3 decryption returned falsy value: ${decryptedCookie}`);
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
60
|
const payload = JSON.parse(decryptedCookie);
|
|
@@ -63,13 +63,13 @@ export class DefaultTokenV3 extends TokenBase {
|
|
|
63
63
|
payload?.t == null ||
|
|
64
64
|
payload?.u == null ||
|
|
65
65
|
payload?.v == null) {
|
|
66
|
-
|
|
66
|
+
context.logger.debug(`invalid cookie v3 structure: ${JSON.stringify(payload)}`);
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
return payload;
|
|
70
70
|
}
|
|
71
71
|
catch (e) {
|
|
72
|
-
|
|
72
|
+
context.logger.debug(`error decrypting cookie v3: ${e}`);
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -82,7 +82,7 @@ export class DefaultTokenV3 extends TokenBase {
|
|
|
82
82
|
return hash === this.hmac;
|
|
83
83
|
}
|
|
84
84
|
catch (e) {
|
|
85
|
-
|
|
85
|
+
context.logger.debug(`error validating cookie v3: ${e}`);
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -4,7 +4,7 @@ export var SensitiveRequestUtils;
|
|
|
4
4
|
SensitiveRequestUtils.isSensitiveRequest = async (config, context) => {
|
|
5
5
|
return (SensitiveRequestUtils.isSensitiveRoute(context.requestData.url, config.sensitiveRoutes) ||
|
|
6
6
|
SensitiveRequestUtils.isSensitiveGraphqlOperation(context.graphqlData) ||
|
|
7
|
-
(await SensitiveRequestUtils.invokeCustomIsSensitiveRequest(config, context
|
|
7
|
+
(await SensitiveRequestUtils.invokeCustomIsSensitiveRequest(config, context)));
|
|
8
8
|
};
|
|
9
9
|
SensitiveRequestUtils.isSensitiveRoute = (url, sensitiveRoutes) => {
|
|
10
10
|
return isRouteInPatterns(url.pathname, sensitiveRoutes);
|
|
@@ -12,13 +12,13 @@ export var SensitiveRequestUtils;
|
|
|
12
12
|
SensitiveRequestUtils.isSensitiveGraphqlOperation = (graphQLData) => {
|
|
13
13
|
return !!graphQLData?.some((operation) => operation.sensitive);
|
|
14
14
|
};
|
|
15
|
-
SensitiveRequestUtils.invokeCustomIsSensitiveRequest = async (config,
|
|
15
|
+
SensitiveRequestUtils.invokeCustomIsSensitiveRequest = async (config, context) => {
|
|
16
16
|
if (config.customIsSensitiveRequest && typeof config.customIsSensitiveRequest === 'function') {
|
|
17
17
|
try {
|
|
18
|
-
return await config.customIsSensitiveRequest(request.getUnderlyingRequest());
|
|
18
|
+
return await config.customIsSensitiveRequest(context.requestData.request.getUnderlyingRequest());
|
|
19
19
|
}
|
|
20
20
|
catch (err) {
|
|
21
|
-
|
|
21
|
+
context.logger.debug(`caught custom sensitive request error - ${err}`);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
return false;
|
|
@@ -14,10 +14,10 @@ export class DefaultTelemetry {
|
|
|
14
14
|
async isValidTelemetryRequest(context) {
|
|
15
15
|
try {
|
|
16
16
|
const telemetryHeader = this.getTelemetryHeader(context);
|
|
17
|
-
return !!telemetryHeader && (await this.isTelemetryHeaderValid(telemetryHeader));
|
|
17
|
+
return !!telemetryHeader && (await this.isTelemetryHeaderValid(telemetryHeader, context));
|
|
18
18
|
}
|
|
19
19
|
catch (e) {
|
|
20
|
-
|
|
20
|
+
context.logger.debug(`error validating telemetry - ${e}`);
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -26,19 +26,19 @@ export class DefaultTelemetry {
|
|
|
26
26
|
await this.sendTelemetryActivity(context);
|
|
27
27
|
}
|
|
28
28
|
catch (e) {
|
|
29
|
-
|
|
29
|
+
context.logger.debug(`error sending telemetry - ${e}`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
getTelemetryHeader(context) {
|
|
33
33
|
return context.requestData.request.headers.get(TELEMETRY_HEADER_NAME) || '';
|
|
34
34
|
}
|
|
35
|
-
async isTelemetryHeaderValid(headerValue) {
|
|
36
|
-
|
|
37
|
-
return this.timestampHmacHeaderValidator.isValid(headerValue);
|
|
35
|
+
async isTelemetryHeaderValid(headerValue, context) {
|
|
36
|
+
context.logger.debug('received command to send enforcer telemetry');
|
|
37
|
+
return this.timestampHmacHeaderValidator.isValid(headerValue, context.logger);
|
|
38
38
|
}
|
|
39
39
|
async sendTelemetryActivity(context) {
|
|
40
40
|
const telemetryRequest = this.createTelemetryRequest(context);
|
|
41
|
-
|
|
41
|
+
context.logger.debug(`sending telemetry to ${telemetryRequest.url}`);
|
|
42
42
|
await this.httpClient.send(telemetryRequest);
|
|
43
43
|
}
|
|
44
44
|
createTelemetryRequest(context) {
|
|
@@ -10,4 +10,4 @@ export const PUSH_DATA_HMAC_HEADER_NAME = 'x-px-pushdata';
|
|
|
10
10
|
export const PUSH_DATA_FEATURE_HEADER_NAME = 'x-px-feature';
|
|
11
11
|
export const EMAIL_ADDRESS_REGEX = /^[a-zA-Z0-9_+&*-]+(?:\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,7}$/;
|
|
12
12
|
export const URL_REGEX = /^(https?\:)\/\/(([^@\s:]+):?([^@\s]*)@)?(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/;
|
|
13
|
-
export const CORE_MODULE_VERSION = 'JS Core 0.
|
|
13
|
+
export const CORE_MODULE_VERSION = 'JS Core 0.16.0';
|