perimeterx-js-core 0.23.3 → 0.24.1
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/utils.js +4 -3
- package/lib/cjs/config/ConfigurationBase.js +14 -0
- package/lib/cjs/config/defaults/DefaultConfigurationParams.js +2 -0
- package/lib/cjs/context/DefaultContext.js +2 -0
- package/lib/cjs/context/SerializedContext.js +1 -0
- package/lib/cjs/enforcer/utils.js +6 -1
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/phase/flow/EndEnforcerFlow.js +4 -4
- package/lib/cjs/phase/flow/FilterFlow.js +1 -1
- package/lib/cjs/phase/flow/PostEnforceFlow.js +2 -2
- package/lib/cjs/phase/impl/IdentifyTelemetryRequestPhase.js +61 -0
- package/lib/cjs/phase/impl/ModifyOutgoingResponsePhase.js +32 -1
- package/lib/cjs/phase/impl/RiskApiPhase.js +1 -0
- package/lib/cjs/phase/impl/{TelemetryPhase.js → SendTelemetryActivityPhase.js} +12 -13
- package/lib/cjs/phase/impl/index.js +2 -1
- package/lib/cjs/risk_api/client/PostRiskApiClientBase.js +5 -4
- package/lib/cjs/risk_api/risk_response/RiskResponseBase.js +9 -0
- package/lib/cjs/risk_api/risk_response/serialize/SerializedRiskResponse.js +1 -0
- package/lib/cjs/snippet_injection/CustomSnippetFunction.js +2 -0
- package/lib/cjs/snippet_injection/index.js +20 -0
- package/lib/cjs/snippet_injection/snippet_injector/ISnippetInjector.js +2 -0
- package/lib/cjs/snippet_injection/snippet_injector/index.js +17 -0
- package/lib/cjs/snippet_injection/snippet_retriever/DefaultSnippetRetriever.js +95 -0
- package/lib/cjs/snippet_injection/snippet_retriever/ISnippetRetriever.js +2 -0
- package/lib/cjs/snippet_injection/snippet_retriever/index.js +18 -0
- package/lib/cjs/snippet_injection/utils.js +5 -0
- package/lib/cjs/utils/constants.js +1 -1
- package/lib/cjs/utils/request_id_generator/SimpleRequestIdGenerator.js +13 -0
- package/lib/cjs/utils/request_id_generator/index.js +1 -0
- package/lib/esm/activities/utils.js +4 -3
- package/lib/esm/config/ConfigurationBase.js +6 -0
- package/lib/esm/config/defaults/DefaultConfigurationParams.js +2 -0
- package/lib/esm/context/DefaultContext.js +3 -0
- package/lib/esm/context/SerializedContext.js +2 -0
- package/lib/esm/enforcer/utils.js +5 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/phase/flow/EndEnforcerFlow.js +3 -3
- package/lib/esm/phase/flow/FilterFlow.js +2 -2
- package/lib/esm/phase/flow/PostEnforceFlow.js +2 -2
- package/lib/esm/phase/impl/IdentifyTelemetryRequestPhase.js +13 -0
- package/lib/esm/phase/impl/ModifyOutgoingResponsePhase.js +17 -1
- package/lib/esm/phase/impl/RiskApiPhase.js +1 -0
- package/lib/esm/phase/impl/{TelemetryPhase.js → SendTelemetryActivityPhase.js} +3 -4
- package/lib/esm/phase/impl/index.js +2 -1
- package/lib/esm/risk_api/client/PostRiskApiClientBase.js +5 -4
- package/lib/esm/risk_api/risk_response/RiskResponseBase.js +4 -0
- package/lib/esm/risk_api/risk_response/serialize/SerializedRiskResponse.js +2 -0
- package/lib/esm/snippet_injection/CustomSnippetFunction.js +1 -0
- package/lib/esm/snippet_injection/index.js +4 -0
- package/lib/esm/snippet_injection/snippet_injector/ISnippetInjector.js +1 -0
- package/lib/esm/snippet_injection/snippet_injector/index.js +1 -0
- package/lib/esm/snippet_injection/snippet_retriever/DefaultSnippetRetriever.js +36 -0
- package/lib/esm/snippet_injection/snippet_retriever/ISnippetRetriever.js +1 -0
- package/lib/esm/snippet_injection/snippet_retriever/index.js +2 -0
- package/lib/esm/snippet_injection/utils.js +9 -0
- package/lib/esm/utils/constants.js +1 -1
- package/lib/esm/utils/request_id_generator/SimpleRequestIdGenerator.js +9 -0
- package/lib/esm/utils/request_id_generator/index.js +1 -0
- package/lib/types/activities/model/CommonActivityDetails.d.ts +1 -0
- package/lib/types/config/ConfigurationBase.d.ts +3 -0
- package/lib/types/config/ConfigurationBuilderBase.d.ts +1 -1
- package/lib/types/config/IConfiguration.d.ts +9 -0
- package/lib/types/config/params/CoreConfigurationParams.d.ts +6 -1
- package/lib/types/context/ContextJson.d.ts +1 -0
- package/lib/types/context/DefaultContext.d.ts +1 -0
- package/lib/types/context/SerializedContext.d.ts +1 -0
- package/lib/types/context/interfaces/IContext.d.ts +4 -0
- package/lib/types/enforcer/EnforcerOptions.d.ts +3 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/phase/flow/EndEnforcerFlow.d.ts +3 -1
- package/lib/types/phase/flow/PostEnforceFlow.d.ts +1 -1
- package/lib/types/phase/impl/IdentifyTelemetryRequestPhase.d.ts +9 -0
- package/lib/types/phase/impl/ModifyOutgoingResponsePhase.d.ts +5 -1
- package/lib/types/phase/impl/{TelemetryPhase.d.ts → SendTelemetryActivityPhase.d.ts} +1 -1
- package/lib/types/phase/impl/index.d.ts +2 -1
- package/lib/types/risk_api/client/PostRiskApiClientBase.d.ts +1 -1
- package/lib/types/risk_api/risk_response/CommonRiskResponsePayload.d.ts +1 -0
- package/lib/types/risk_api/risk_response/IRiskResponse.d.ts +1 -0
- package/lib/types/risk_api/risk_response/RiskResponseBase.d.ts +1 -0
- package/lib/types/risk_api/risk_response/serialize/RiskResponseJson.d.ts +1 -0
- package/lib/types/risk_api/risk_response/serialize/SerializedRiskResponse.d.ts +1 -0
- package/lib/types/snippet_injection/CustomSnippetFunction.d.ts +2 -0
- package/lib/types/snippet_injection/index.d.ts +4 -0
- package/lib/types/snippet_injection/snippet_injector/ISnippetInjector.d.ts +5 -0
- package/lib/types/snippet_injection/snippet_injector/index.d.ts +1 -0
- package/lib/types/snippet_injection/snippet_retriever/DefaultSnippetRetriever.d.ts +10 -0
- package/lib/types/snippet_injection/snippet_retriever/ISnippetRetriever.d.ts +5 -0
- package/lib/types/snippet_injection/snippet_retriever/index.d.ts +2 -0
- package/lib/types/snippet_injection/utils.d.ts +1 -0
- package/lib/types/utils/constants.d.ts +1 -1
- package/lib/types/utils/request_id_generator/SimpleRequestIdGenerator.d.ts +6 -0
- package/lib/types/utils/request_id_generator/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -75,9 +75,10 @@ export function redactCookieSecret(secret) {
|
|
|
75
75
|
return '***'.concat(secret.substring(secret.length - 3, secret.length));
|
|
76
76
|
}
|
|
77
77
|
export const addConfigDataToDetails = (details, config) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
transferExistingProperties(config, details, {
|
|
79
|
+
remoteConfigId: 'remote_config_id',
|
|
80
|
+
remoteConfigVersion: 'remote_config_version',
|
|
81
|
+
});
|
|
81
82
|
};
|
|
82
83
|
export const addCustomParametersToDetails = (details, customParameters) => {
|
|
83
84
|
if (customParameters) {
|
|
@@ -363,6 +363,12 @@ export class ConfigurationBase {
|
|
|
363
363
|
get tokenVersion() {
|
|
364
364
|
return this.configParams.px_token_version;
|
|
365
365
|
}
|
|
366
|
+
get snippetInjectionEnabled() {
|
|
367
|
+
return this.configParams.px_snippet_injection_enabled;
|
|
368
|
+
}
|
|
369
|
+
get createCustomSnippet() {
|
|
370
|
+
return this.configParams.px_create_custom_snippet;
|
|
371
|
+
}
|
|
366
372
|
get enableBlockedUrlOnCaptchaBlockPage() {
|
|
367
373
|
return true;
|
|
368
374
|
}
|
|
@@ -127,6 +127,8 @@ export const defaultConfigurationParams = () => ({
|
|
|
127
127
|
px_remote_config_retry_interval_ms: 1000,
|
|
128
128
|
px_url_decode_reserved_characters: false,
|
|
129
129
|
px_secured_pxhd_enabled: false,
|
|
130
|
+
px_snippet_injection_enabled: false,
|
|
131
|
+
px_create_custom_snippet: null,
|
|
130
132
|
px_custom_is_sensitive_request: null,
|
|
131
133
|
px_custom_is_monitored_request: null,
|
|
132
134
|
px_custom_is_enforced_request: null,
|
|
@@ -34,6 +34,7 @@ export class DefaultContext {
|
|
|
34
34
|
enforcerStartTime;
|
|
35
35
|
logger;
|
|
36
36
|
usedCookieSecret;
|
|
37
|
+
shouldSendTelemetry;
|
|
37
38
|
config;
|
|
38
39
|
urlUtils;
|
|
39
40
|
constructor(config, request, options) {
|
|
@@ -62,6 +63,7 @@ export class DefaultContext {
|
|
|
62
63
|
if (!this.isMobile) {
|
|
63
64
|
this.setCookiesOnContext();
|
|
64
65
|
}
|
|
66
|
+
this.shouldSendTelemetry = false;
|
|
65
67
|
}
|
|
66
68
|
get isMobile() {
|
|
67
69
|
return this.tokenOrigin === TokenOrigin.HEADER;
|
|
@@ -175,6 +177,7 @@ export class DefaultContext {
|
|
|
175
177
|
enforcerStartTime: this.enforcerStartTime,
|
|
176
178
|
blockAction: this.blockAction,
|
|
177
179
|
pxdeVerified: this.pxdeVerified,
|
|
180
|
+
shouldSendTelemetry: this.shouldSendTelemetry,
|
|
178
181
|
logger: this.shouldSendLogs
|
|
179
182
|
? {
|
|
180
183
|
logs: this.logger.getLogs(),
|
|
@@ -27,6 +27,7 @@ export class SerializedContext {
|
|
|
27
27
|
vidSource;
|
|
28
28
|
tokenOrigin;
|
|
29
29
|
uuid;
|
|
30
|
+
shouldSendTelemetry;
|
|
30
31
|
constructor(config, contextJson, request, urlUtils) {
|
|
31
32
|
this.action = contextJson.action;
|
|
32
33
|
this.reasons = contextJson.reasons;
|
|
@@ -53,6 +54,7 @@ export class SerializedContext {
|
|
|
53
54
|
this.graphqlData = contextJson.graphqlData;
|
|
54
55
|
this.enforcerStartTime = contextJson.enforcerStartTime;
|
|
55
56
|
this.blockAction = contextJson.blockAction;
|
|
57
|
+
this.shouldSendTelemetry = contextJson.shouldSendTelemetry;
|
|
56
58
|
}
|
|
57
59
|
createRequestData({ requestData }, request, urlUtils) {
|
|
58
60
|
return {
|
|
@@ -9,6 +9,7 @@ import { HttpActivityClient, HttpBatchedActivityClient } from '../activities';
|
|
|
9
9
|
import { HttpLogServiceClient } from '../logger';
|
|
10
10
|
import { AccountDefender, BotDefender, CredentialIntelligence, HypeSaleChallenge, ProductName, } from '../products';
|
|
11
11
|
import { EnforcerError, isValidTokenVersion } from '../utils';
|
|
12
|
+
import { DefaultSnippetRetriever } from '../snippet_injection';
|
|
12
13
|
export const createEnforcerInitializationBlock = (config, options) => {
|
|
13
14
|
const tokenVersion = config.tokenVersion;
|
|
14
15
|
if (!isValidTokenVersion(tokenVersion)) {
|
|
@@ -50,6 +51,8 @@ export const createEnforcerInitializationBlock = (config, options) => {
|
|
|
50
51
|
hmacUtils,
|
|
51
52
|
})
|
|
52
53
|
: null);
|
|
54
|
+
const snippetInjector = options.snippetInjector ?? null;
|
|
55
|
+
const snippetRetriever = options.snippetRetriever || (snippetInjector ? new DefaultSnippetRetriever(config) : null);
|
|
53
56
|
const allOptions = {
|
|
54
57
|
httpClient,
|
|
55
58
|
base64Utils,
|
|
@@ -69,6 +72,8 @@ export const createEnforcerInitializationBlock = (config, options) => {
|
|
|
69
72
|
remoteConfigStorageClient,
|
|
70
73
|
remoteConfigServiceClient,
|
|
71
74
|
remoteConfigUpdater,
|
|
75
|
+
snippetInjector,
|
|
76
|
+
snippetRetriever,
|
|
72
77
|
};
|
|
73
78
|
const products = createEnforcerProducts(config, options.products, base64Utils, hashUtils, urlUtils, ipRangeChecker);
|
|
74
79
|
return { products, ...allOptions };
|
package/lib/esm/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './context';
|
|
|
7
7
|
export * from './custom_parameters';
|
|
8
8
|
export * from './sensitive_request';
|
|
9
9
|
export * from './monitored_request';
|
|
10
|
+
export * from './snippet_injection';
|
|
10
11
|
export * from './cors';
|
|
11
12
|
export * from './enforcer';
|
|
12
13
|
export * from './filter';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CompositePhase, SendLogsPhase } from '../impl';
|
|
2
|
-
import { ClearLogsPhase } from '../impl
|
|
2
|
+
import { ClearLogsPhase, SendTelemetryActivityPhase } from '../impl';
|
|
3
3
|
export class EndEnforcerFlow extends CompositePhase {
|
|
4
|
-
constructor(config, { logServiceClient }) {
|
|
5
|
-
const phases = [];
|
|
4
|
+
constructor(config, { logServiceClient, telemetry, }) {
|
|
5
|
+
const phases = [new SendTelemetryActivityPhase(telemetry)];
|
|
6
6
|
if (logServiceClient) {
|
|
7
7
|
phases.push(new SendLogsPhase(config, logServiceClient));
|
|
8
8
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProductName } from '../../products';
|
|
2
2
|
import { isNullOrUndefined } from '../../utils';
|
|
3
|
-
import { CompositePhase, FilterPhase, FirstPartyPhase, PreflightPhase,
|
|
3
|
+
import { CompositePhase, FilterPhase, FirstPartyPhase, PreflightPhase, UpdateRemoteConfigPhase, IdentifyTelemetryRequestPhase, } from '../impl';
|
|
4
4
|
export class FilterFlow extends CompositePhase {
|
|
5
5
|
constructor(config, { httpClient, products, cors, telemetry, remoteConfigUpdater, }) {
|
|
6
6
|
const phases = [];
|
|
@@ -13,7 +13,7 @@ export class FilterFlow extends CompositePhase {
|
|
|
13
13
|
phases.push(new FilterPhase(filterProducts));
|
|
14
14
|
}
|
|
15
15
|
phases.push(new PreflightPhase(config, cors));
|
|
16
|
-
phases.push(new
|
|
16
|
+
phases.push(new IdentifyTelemetryRequestPhase(telemetry));
|
|
17
17
|
if (remoteConfigUpdater) {
|
|
18
18
|
const updateRemoteConfigPhase = new UpdateRemoteConfigPhase(config, remoteConfigUpdater);
|
|
19
19
|
phases.push(updateRemoteConfigPhase);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { CompositePhase, EnrichContextFromResponsePhase, ModifyOutgoingResponsePhase, SendAsyncActivitiesOnResponsePhase, } from '../impl';
|
|
2
2
|
export class PostEnforceFlow extends CompositePhase {
|
|
3
|
-
constructor(config, { products, activityClient, }) {
|
|
3
|
+
constructor(config, { products, activityClient, snippetRetriever, snippetInjector, }) {
|
|
4
4
|
super([
|
|
5
5
|
new EnrichContextFromResponsePhase(config, products),
|
|
6
|
-
new ModifyOutgoingResponsePhase(config, Object.values(products)),
|
|
6
|
+
new ModifyOutgoingResponsePhase(config, Object.values(products), snippetRetriever, snippetInjector),
|
|
7
7
|
new SendAsyncActivitiesOnResponsePhase(activityClient),
|
|
8
8
|
]);
|
|
9
9
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class IdentifyTelemetryRequestPhase {
|
|
2
|
+
telemetry;
|
|
3
|
+
constructor(telemetry) {
|
|
4
|
+
this.telemetry = telemetry;
|
|
5
|
+
}
|
|
6
|
+
async execute(context) {
|
|
7
|
+
if (await this.telemetry.isValidTelemetryRequest(context)) {
|
|
8
|
+
context.shouldSendTelemetry = true;
|
|
9
|
+
return { done: true };
|
|
10
|
+
}
|
|
11
|
+
return { done: false };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import { PXHDSource, PXHDUtils } from '../../pxhd';
|
|
2
|
+
import { CONTENT_TYPE_HEADER_NAME, ContentType } from '../../http';
|
|
2
3
|
export class ModifyOutgoingResponsePhase {
|
|
3
4
|
config;
|
|
4
5
|
products;
|
|
5
|
-
|
|
6
|
+
snippetRetriever;
|
|
7
|
+
snippetInjector;
|
|
8
|
+
constructor(config, products, snippetRetriever, snippetInjector) {
|
|
6
9
|
this.config = config;
|
|
7
10
|
this.products = products;
|
|
11
|
+
this.snippetRetriever = snippetRetriever;
|
|
12
|
+
this.snippetInjector = snippetInjector;
|
|
8
13
|
}
|
|
9
14
|
async execute(context) {
|
|
10
15
|
await Promise.all(this.products.map((product) => product?.modifyOutgoingResponse(context)));
|
|
11
16
|
if (context.pxhd?.source === PXHDSource.RISK && context.response) {
|
|
12
17
|
PXHDUtils.addPxhdToOutgoingResponse(this.config, context, context.response);
|
|
13
18
|
}
|
|
19
|
+
await this.handleSnippetInjection(context);
|
|
14
20
|
return { done: false };
|
|
15
21
|
}
|
|
22
|
+
async handleSnippetInjection(context) {
|
|
23
|
+
if (this.snippetRetriever &&
|
|
24
|
+
this.snippetInjector &&
|
|
25
|
+
this.config.snippetInjectionEnabled &&
|
|
26
|
+
!!context.response?.headers?.get(CONTENT_TYPE_HEADER_NAME)?.includes(ContentType.TEXT_HTML)) {
|
|
27
|
+
context.logger.debug('snippet injection enabled');
|
|
28
|
+
const snippet = await this.snippetRetriever.retrieveSnippet(context);
|
|
29
|
+
context.response = await this.snippetInjector.injectSnippet(context.response, snippet);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
16
32
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class SendTelemetryActivityPhase {
|
|
2
2
|
telemetry;
|
|
3
3
|
constructor(telemetry) {
|
|
4
4
|
this.telemetry = telemetry;
|
|
5
5
|
}
|
|
6
6
|
async execute(context) {
|
|
7
|
-
if (
|
|
8
|
-
await this.sendTelemetry(context);
|
|
9
|
-
return { done: true };
|
|
7
|
+
if (context.shouldSendTelemetry) {
|
|
8
|
+
await this.telemetry.sendTelemetry(context);
|
|
10
9
|
}
|
|
11
10
|
return { done: false };
|
|
12
11
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from './FirstPartyPhase';
|
|
2
2
|
export * from './FilterPhase';
|
|
3
3
|
export * from './PreflightPhase';
|
|
4
|
-
export * from './TelemetryPhase';
|
|
5
4
|
export * from './EnrichContextFromRequestPhase';
|
|
6
5
|
export * from './ParseTokenPhase';
|
|
7
6
|
export * from './DecideActionPhase';
|
|
@@ -17,3 +16,5 @@ export * from './CompositePhase';
|
|
|
17
16
|
export * from './SendLogsPhase';
|
|
18
17
|
export * from './/UpdateRemoteConfigPhase';
|
|
19
18
|
export * from './ClearLogsPhase';
|
|
19
|
+
export * from './IdentifyTelemetryRequestPhase';
|
|
20
|
+
export * from './SendTelemetryActivityPhase';
|
|
@@ -23,12 +23,12 @@ export class PostRiskApiClientBase {
|
|
|
23
23
|
const riskActivity = this.createRiskActivity(context);
|
|
24
24
|
response = await this.sendRiskActivity(riskActivity, riskApiData, context);
|
|
25
25
|
if (response?.status !== 200) {
|
|
26
|
-
return await this.handleS2SError(riskApiData, response);
|
|
26
|
+
return await this.handleS2SError(riskApiData, context, response);
|
|
27
27
|
}
|
|
28
28
|
riskResponse = this.createRiskResponse(response);
|
|
29
29
|
riskApiData.riskResponse = riskResponse;
|
|
30
30
|
if (!(await riskResponse.validate())) {
|
|
31
|
-
return await this.handleS2SError(riskApiData, response);
|
|
31
|
+
return await this.handleS2SError(riskApiData, context, response);
|
|
32
32
|
}
|
|
33
33
|
context.logger.debug(`received risk response, score: ${riskResponse.score}, rtt: ${riskApiData.riskRtt}`);
|
|
34
34
|
return riskApiData;
|
|
@@ -38,7 +38,7 @@ export class PostRiskApiClientBase {
|
|
|
38
38
|
return this.handleS2STimeout(riskApiData);
|
|
39
39
|
}
|
|
40
40
|
context.logger.error(`caught error in risk api: ${err} - ${JSON.stringify(context.requestData.url)}`);
|
|
41
|
-
return await this.handleS2SError(riskApiData, response, err);
|
|
41
|
+
return await this.handleS2SError(riskApiData, context, response, err);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
@@ -105,7 +105,7 @@ export class PostRiskApiClientBase {
|
|
|
105
105
|
riskApiData.riskApiCallResult = RiskApiCallResult.TIMEOUT;
|
|
106
106
|
return riskApiData;
|
|
107
107
|
}
|
|
108
|
-
async handleS2SError(riskApiData, response, error) {
|
|
108
|
+
async handleS2SError(riskApiData, context, response, error) {
|
|
109
109
|
riskApiData.riskApiCallResult = RiskApiCallResult.ERROR;
|
|
110
110
|
riskApiData.errorReason = S2SErrorReason.UNKNOWN_ERROR;
|
|
111
111
|
if (response) {
|
|
@@ -131,6 +131,7 @@ export class PostRiskApiClientBase {
|
|
|
131
131
|
const existingMessage = riskApiData.errorMessage;
|
|
132
132
|
riskApiData.errorMessage = existingMessage ? `${existingMessage}, ${errorMessage}` : errorMessage;
|
|
133
133
|
}
|
|
134
|
+
context.logger.debug(`S2S error message: ${riskApiData.errorMessage}`);
|
|
134
135
|
return riskApiData;
|
|
135
136
|
}
|
|
136
137
|
}
|
|
@@ -38,6 +38,9 @@ export class RiskResponseBase {
|
|
|
38
38
|
get additionalRiskInfo() {
|
|
39
39
|
return this.riskResponse?.additional_risk_info;
|
|
40
40
|
}
|
|
41
|
+
get telemetryRequested() {
|
|
42
|
+
return this.riskResponse?.telemetry_requested;
|
|
43
|
+
}
|
|
41
44
|
get drc() {
|
|
42
45
|
return this.riskResponse?.drc;
|
|
43
46
|
}
|
|
@@ -52,6 +55,7 @@ export class RiskResponseBase {
|
|
|
52
55
|
score: this.score,
|
|
53
56
|
drc: this.drc,
|
|
54
57
|
additionalRiskInfo: this.additionalRiskInfo,
|
|
58
|
+
telemetryRequested: this.telemetryRequested,
|
|
55
59
|
uuid: this.uuid,
|
|
56
60
|
};
|
|
57
61
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class SerializedRiskResponse {
|
|
2
2
|
action;
|
|
3
3
|
additionalRiskInfo;
|
|
4
|
+
telemetryRequested;
|
|
4
5
|
dataEnrichment;
|
|
5
6
|
drc;
|
|
6
7
|
message;
|
|
@@ -12,6 +13,7 @@ export class SerializedRiskResponse {
|
|
|
12
13
|
constructor(riskResponseJson) {
|
|
13
14
|
this.action = riskResponseJson.action;
|
|
14
15
|
this.additionalRiskInfo = riskResponseJson.additionalRiskInfo;
|
|
16
|
+
this.telemetryRequested = riskResponseJson.telemetryRequested;
|
|
15
17
|
this.dataEnrichment = riskResponseJson.dataEnrichment;
|
|
16
18
|
this.drc = riskResponseJson.drc;
|
|
17
19
|
this.message = riskResponseJson.message;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ISnippetInjector';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FirstPartySuffix, getMostCustomizedFirstPartyPath } from '../../products';
|
|
2
|
+
import { createDefaultSnippet } from '../utils';
|
|
3
|
+
export class DefaultSnippetRetriever {
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
async retrieveSnippet(context) {
|
|
9
|
+
return (await this.retrieveCustomSnippet(context)) || this.retrieveDefaultSnippet(context);
|
|
10
|
+
}
|
|
11
|
+
async retrieveCustomSnippet(context) {
|
|
12
|
+
if (!this.config.createCustomSnippet) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const snippet = await this.config.createCustomSnippet(this.config.getActiveConfig(), context.requestData.request.getUnderlyingRequest(), context.response.getUnderlyingResponse());
|
|
17
|
+
if (!snippet || typeof snippet !== 'string') {
|
|
18
|
+
context.logger.debug(`invalid custom snippet of type ${typeof snippet}`);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
context.logger.debug('retrieving custom snippet');
|
|
22
|
+
return snippet;
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
context.logger.debug(`failed retrieving custom snippet: ${e}`);
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
retrieveDefaultSnippet(context) {
|
|
30
|
+
const sensorSrc = this.config.firstPartyEnabled
|
|
31
|
+
? getMostCustomizedFirstPartyPath(this.config, FirstPartySuffix.SENSOR)
|
|
32
|
+
: `${this.config.backendClientUrl}/${this.config.appId}/main.min.js`;
|
|
33
|
+
context.logger.debug(`retrieving default snippet with src ${sensorSrc}`);
|
|
34
|
+
return createDefaultSnippet(this.config.appId, sensorSrc);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const createDefaultSnippet = (appId, sensorSrc) => `<script type="text/javascript">
|
|
2
|
+
(function(){
|
|
3
|
+
window._pxAppId = '${appId}';
|
|
4
|
+
var p = document.getElementsByTagName('script')[0], s = document.createElement('script');
|
|
5
|
+
s.async = 1;
|
|
6
|
+
s.src = '${sensorSrc}';
|
|
7
|
+
p.parentNode.insertBefore(s,p);
|
|
8
|
+
}());
|
|
9
|
+
</script>`;
|
|
@@ -11,4 +11,4 @@ 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]+))?)(\/?[^?#]*)(\?[^#]*|)(#.*|)$/;
|
|
13
13
|
export const REGEX_STRUCTURE = /^\/(.+?)\/([gimsuyvd]*)$/;
|
|
14
|
-
export const CORE_MODULE_VERSION = 'JS Core 0.
|
|
14
|
+
export const CORE_MODULE_VERSION = 'JS Core 0.24.1';
|
|
@@ -9,6 +9,7 @@ import { CredentialEndpointConfiguration, CredentialIntelligenceVersion, CustomL
|
|
|
9
9
|
import { CustomRequestFunction } from './CustomRequestFunction';
|
|
10
10
|
import { ExtractGraphQLKeywordsFunction } from '../graphql';
|
|
11
11
|
import { TokenVersion } from '../risk_token';
|
|
12
|
+
import { CustomSnippetFunction } from '../snippet_injection';
|
|
12
13
|
export declare abstract class ConfigurationBase<Req, Res, Added, Removed extends string> implements IConfiguration<Req, Res, Added, Removed> {
|
|
13
14
|
protected configParams: RequiredAllConfigurationParams<Req, Res, Added, Removed>;
|
|
14
15
|
protected readonly staticConfigParams: StaticConfigurationParams<Req, Res, Added, Removed>;
|
|
@@ -115,5 +116,7 @@ export declare abstract class ConfigurationBase<Req, Res, Added, Removed extends
|
|
|
115
116
|
get urlDecodeReservedCharacters(): boolean;
|
|
116
117
|
get securedPxhdEnabled(): boolean;
|
|
117
118
|
get tokenVersion(): `${TokenVersion}`;
|
|
119
|
+
get snippetInjectionEnabled(): boolean;
|
|
120
|
+
get createCustomSnippet(): CustomSnippetFunction<Req, Res, Added, Removed> | null;
|
|
118
121
|
get enableBlockedUrlOnCaptchaBlockPage(): boolean;
|
|
119
122
|
}
|
|
@@ -4,7 +4,7 @@ import { CoreConfigurationParams, StaticConfigurationParams, RemoteConfiguration
|
|
|
4
4
|
import { IBase64Utils } from '../utils';
|
|
5
5
|
export declare abstract class ConfigurationBuilderBase<Req, Res, Added, Removed, ParamsType extends CoreConfigurationParams<Req, Res, Added, Removed>, ConfigurationType extends IConfiguration<Req, Res, Added, Removed>> {
|
|
6
6
|
protected readonly base64Utils: IBase64Utils;
|
|
7
|
-
protected abstract createRemoteConfigStorageClient(staticConfig: ConfigurationType): Promise<IRemoteConfigStorageClient<Req, Res, Added, Removed
|
|
7
|
+
protected abstract createRemoteConfigStorageClient(staticConfig: ConfigurationType): Promise<IRemoteConfigStorageClient<Req, Res, Added, Removed> | null>;
|
|
8
8
|
protected abstract createConfiguration(params: ParamsType | StaticConfigurationParams<Req, Res, Added, Removed>): ConfigurationType;
|
|
9
9
|
protected constructor(base64Utils: IBase64Utils);
|
|
10
10
|
build(params: StaticConfigurationParams<Req, Res, Added, Removed>): Promise<ConfigurationType>;
|
|
@@ -8,6 +8,7 @@ import { CredentialEndpointConfiguration, CredentialIntelligenceVersion, CustomL
|
|
|
8
8
|
import { CustomRequestFunction } from './CustomRequestFunction';
|
|
9
9
|
import { ExtractGraphQLKeywordsFunction } from '../graphql';
|
|
10
10
|
import { TokenVersion } from '../risk_token';
|
|
11
|
+
import { CustomSnippetFunction } from '../snippet_injection';
|
|
11
12
|
export interface IConfiguration<Req, Res, Added, Removed> {
|
|
12
13
|
/**
|
|
13
14
|
* The application ID.
|
|
@@ -370,6 +371,14 @@ export interface IConfiguration<Req, Res, Added, Removed> {
|
|
|
370
371
|
* Whether to add the Secure attribute when setting the PXHD cookie.
|
|
371
372
|
*/
|
|
372
373
|
readonly securedPxhdEnabled: boolean;
|
|
374
|
+
/**
|
|
375
|
+
* Whether snippet injection on response bodies is enabled.
|
|
376
|
+
*/
|
|
377
|
+
readonly snippetInjectionEnabled: boolean;
|
|
378
|
+
/**
|
|
379
|
+
* A custom function that returns a string representing the snippet to be injected.
|
|
380
|
+
*/
|
|
381
|
+
readonly createCustomSnippet: CustomSnippetFunction<Req, Res, Added, Removed> | null;
|
|
373
382
|
/**
|
|
374
383
|
* Whether to include the request url in captcha block page
|
|
375
384
|
*/
|
|
@@ -7,6 +7,7 @@ import { CustomParametersFunction } from '../../custom_parameters';
|
|
|
7
7
|
import { CustomBlockResponseHeadersHandler, CustomPreflightHandler } from '../../cors';
|
|
8
8
|
import { CustomRequestFunction } from '../CustomRequestFunction';
|
|
9
9
|
import { TokenVersion } from '../../risk_token';
|
|
10
|
+
import { CustomSnippetFunction } from '../../snippet_injection';
|
|
10
11
|
export type StaticConfigurationParamsOnly = {
|
|
11
12
|
px_app_id: string;
|
|
12
13
|
px_cookie_secret: string | string[];
|
|
@@ -34,7 +35,11 @@ export type TokenV3ConfigurationParamsOnly = {
|
|
|
34
35
|
px_risk_cookie_min_iterations?: number;
|
|
35
36
|
px_risk_cookie_max_iterations?: number;
|
|
36
37
|
};
|
|
37
|
-
export type
|
|
38
|
+
export type SnippetInjectionParamsOnly<Req, Res, Added, Removed> = {
|
|
39
|
+
px_snippet_injection_enabled?: boolean;
|
|
40
|
+
px_create_custom_snippet?: CustomSnippetFunction<Req, Res, Added, Removed> | null;
|
|
41
|
+
};
|
|
42
|
+
export type CommonConfigurationParams<Req, Res, Added, Removed> = TokenV3ConfigurationParamsOnly & BatchedActivitiesConfigParamsOnly & SnippetInjectionParamsOnly<Req, Res, Added, Removed> & {
|
|
38
43
|
px_s2s_timeout?: number;
|
|
39
44
|
px_backend_url?: string;
|
|
40
45
|
px_user_agent_max_length?: number;
|
|
@@ -44,6 +44,7 @@ export declare class DefaultContext<Req, Res, Added, Removed> implements IContex
|
|
|
44
44
|
enforcerStartTime?: number;
|
|
45
45
|
logger: ILogger;
|
|
46
46
|
usedCookieSecret?: string;
|
|
47
|
+
shouldSendTelemetry: boolean;
|
|
47
48
|
protected readonly config: IConfiguration<Req, Res, Added, Removed>;
|
|
48
49
|
protected readonly urlUtils: IUrlUtils;
|
|
49
50
|
constructor(config: IConfiguration<Req, Res, Added, Removed>, request: IIncomingRequest<Req>, options: DefaultContextOptions);
|
|
@@ -38,6 +38,7 @@ export declare class SerializedContext<Req, Res, Added, Removed> implements ICon
|
|
|
38
38
|
vidSource?: VidSource;
|
|
39
39
|
tokenOrigin: TokenOrigin;
|
|
40
40
|
uuid?: string;
|
|
41
|
+
shouldSendTelemetry: boolean;
|
|
41
42
|
constructor(config: IConfiguration<Req, Res, Added, Removed>, contextJson: ContextJson<Req, Res>, request: IIncomingRequest<Req>, urlUtils: IUrlUtils);
|
|
42
43
|
protected createRequestData({ requestData }: ContextJson<Req, Res>, request: IIncomingRequest<Req>, urlUtils: IUrlUtils): RequestData<Req>;
|
|
43
44
|
protected createTokenData({ tokenData }: ContextJson<Req, Res>, config: IConfiguration<Req, Res, Added, Removed>): TokenData<Req, Res>;
|
|
@@ -10,6 +10,7 @@ import { Products } from '../products';
|
|
|
10
10
|
import { IGraphQLParser } from '../graphql';
|
|
11
11
|
import { ILogServiceClient } from '../logger';
|
|
12
12
|
import { IRemoteConfigStorageClient, IRemoteConfigServiceClient, IRemoteConfigUpdater } from '../config';
|
|
13
|
+
import { ISnippetInjector, ISnippetRetriever } from '../snippet_injection';
|
|
13
14
|
export type EnforcerOptions<Req, Res, Added, Removed> = {
|
|
14
15
|
httpClient: IHttpClient;
|
|
15
16
|
base64Utils: IBase64Utils;
|
|
@@ -30,4 +31,6 @@ export type EnforcerOptions<Req, Res, Added, Removed> = {
|
|
|
30
31
|
remoteConfigUpdater?: IRemoteConfigUpdater<Req, Res> | null;
|
|
31
32
|
remoteConfigStorageClient?: IRemoteConfigStorageClient<Req, Res, Added, Removed> | null;
|
|
32
33
|
remoteConfigServiceClient?: IRemoteConfigServiceClient<Req, Res, Added, Removed> | null;
|
|
34
|
+
snippetRetriever?: ISnippetRetriever<Req, Res> | null;
|
|
35
|
+
snippetInjector?: ISnippetInjector<Res> | null;
|
|
33
36
|
};
|
package/lib/types/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './context';
|
|
|
7
7
|
export * from './custom_parameters';
|
|
8
8
|
export * from './sensitive_request';
|
|
9
9
|
export * from './monitored_request';
|
|
10
|
+
export * from './snippet_injection';
|
|
10
11
|
export * from './cors';
|
|
11
12
|
export * from './enforcer';
|
|
12
13
|
export * from './filter';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IConfiguration } from '../../config';
|
|
2
2
|
import { CompositePhase } from '../impl';
|
|
3
3
|
import { EnforcerOptions } from '../../enforcer';
|
|
4
|
+
type RequiredEndEnforcerFlowOptions = 'logServiceClient' | 'telemetry';
|
|
4
5
|
export declare class EndEnforcerFlow<Req, Res, Added, Removed> extends CompositePhase<Req, Res> {
|
|
5
|
-
constructor(config: IConfiguration<Req, Res, Added, Removed>, { logServiceClient }: Pick<Required<EnforcerOptions<Req, Res, Added, Removed>>,
|
|
6
|
+
constructor(config: IConfiguration<Req, Res, Added, Removed>, { logServiceClient, telemetry, }: Pick<Required<EnforcerOptions<Req, Res, Added, Removed>>, RequiredEndEnforcerFlowOptions>);
|
|
6
7
|
}
|
|
8
|
+
export {};
|
|
@@ -2,5 +2,5 @@ import { IConfiguration } from '../../config';
|
|
|
2
2
|
import { EnforcerOptions } from '../../enforcer';
|
|
3
3
|
import { CompositePhase } from '../impl';
|
|
4
4
|
export declare class PostEnforceFlow<Req, Res, Added, Removed> extends CompositePhase<Req, Res> {
|
|
5
|
-
constructor(config: IConfiguration<Req, Res, Added, Removed>, { products, activityClient, }: Pick<Required<EnforcerOptions<Req, Res, Added, Removed>>, 'products' | 'activityClient'>);
|
|
5
|
+
constructor(config: IConfiguration<Req, Res, Added, Removed>, { products, activityClient, snippetRetriever, snippetInjector, }: Pick<Required<EnforcerOptions<Req, Res, Added, Removed>>, 'products' | 'activityClient' | 'snippetRetriever' | 'snippetInjector'>);
|
|
6
6
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IPhase } from '../IPhase';
|
|
2
|
+
import { PhaseResult } from '../PhaseResult';
|
|
3
|
+
import { IContext } from '../../context';
|
|
4
|
+
import { ITelemetry } from '../../telemetry';
|
|
5
|
+
export declare class IdentifyTelemetryRequestPhase<Req, Res> implements IPhase<Req, Res> {
|
|
6
|
+
protected readonly telemetry: ITelemetry<Req, Res>;
|
|
7
|
+
constructor(telemetry: ITelemetry<Req, Res>);
|
|
8
|
+
execute(context: IContext<Req, Res>): Promise<PhaseResult>;
|
|
9
|
+
}
|
|
@@ -3,9 +3,13 @@ import { IProduct } from '../../products';
|
|
|
3
3
|
import { IPhase } from '../IPhase';
|
|
4
4
|
import { PhaseResult } from '../PhaseResult';
|
|
5
5
|
import { IConfiguration } from '../../config';
|
|
6
|
+
import { ISnippetInjector, ISnippetRetriever } from '../../snippet_injection';
|
|
6
7
|
export declare class ModifyOutgoingResponsePhase<Req, Res, Added, Removed> implements IPhase<Req, Res> {
|
|
7
8
|
protected readonly config: IConfiguration<Req, Res, Added, Removed>;
|
|
8
9
|
protected readonly products: IProduct<any, Req, Res>[];
|
|
9
|
-
|
|
10
|
+
protected readonly snippetRetriever?: ISnippetRetriever<Req, Res> | null;
|
|
11
|
+
protected readonly snippetInjector?: ISnippetInjector<Res> | null;
|
|
12
|
+
constructor(config: IConfiguration<Req, Res, Added, Removed>, products: IProduct<any, Req, Res>[], snippetRetriever?: ISnippetRetriever<Req, Res> | null, snippetInjector?: ISnippetInjector<Res> | null);
|
|
10
13
|
execute(context: IContext<Req, Res>): Promise<PhaseResult>;
|
|
14
|
+
protected handleSnippetInjection(context: IContext<Req, Res>): Promise<void>;
|
|
11
15
|
}
|
|
@@ -2,7 +2,7 @@ import { IPhase } from '../IPhase';
|
|
|
2
2
|
import { PhaseResult } from '../PhaseResult';
|
|
3
3
|
import { IContext } from '../../context';
|
|
4
4
|
import { ITelemetry } from '../../telemetry';
|
|
5
|
-
export declare class
|
|
5
|
+
export declare class SendTelemetryActivityPhase<Req, Res> implements IPhase<Req, Res> {
|
|
6
6
|
protected readonly telemetry: ITelemetry<Req, Res>;
|
|
7
7
|
constructor(telemetry: ITelemetry<Req, Res>);
|
|
8
8
|
execute(context: IContext<Req, Res>): Promise<PhaseResult>;
|