@microsoft/omnichannel-chat-sdk 2.0.0 → 2.0.1-main.b9e3cb3
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/README.md +13 -31
- package/lib/OmnichannelChatSDK.js +102 -45
- package/lib/OmnichannelChatSDK.js.map +1 -1
- package/lib/config/settings.d.ts +1 -1
- package/lib/config/settings.js +1 -1
- package/lib/core/GetLiveChatConfigOptionalParams.d.ts +60 -0
- package/lib/telemetry/TelemetryEvent.d.ts +3 -1
- package/lib/telemetry/TelemetryEvent.js +2 -0
- package/lib/telemetry/TelemetryEvent.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/validators/prefetchedConfigValidator.d.ts +77 -0
- package/lib/validators/prefetchedConfigValidator.js +152 -0
- package/lib/validators/prefetchedConfigValidator.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { PrefetchedConfigAttestation } from "../core/GetLiveChatConfigOptionalParams";
|
|
2
|
+
/**
|
|
3
|
+
* Reason a prefetched live chat config was not adopted. Emitted as telemetry so a
|
|
4
|
+
* silent fallback to the network is still observable.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum PrefetchedConfigRejectionReason {
|
|
7
|
+
NotProvided = "NotProvided",
|
|
8
|
+
CacheBypass = "CacheBypass",
|
|
9
|
+
MissingAttestation = "MissingAttestation",
|
|
10
|
+
IdentityMismatch = "IdentityMismatch",
|
|
11
|
+
UnverifiedOrgUrl = "UnverifiedOrgUrl",
|
|
12
|
+
OrgUrlMismatch = "OrgUrlMismatch",
|
|
13
|
+
MalformedPayload = "MalformedPayload",
|
|
14
|
+
MissingLiveChatVersion = "MissingLiveChatVersion",
|
|
15
|
+
UnsupportedLiveChatVersion = "UnsupportedLiveChatVersion",
|
|
16
|
+
PayloadOrgIdMismatch = "PayloadOrgIdMismatch",
|
|
17
|
+
PayloadWidgetIdMismatch = "PayloadWidgetIdMismatch"
|
|
18
|
+
}
|
|
19
|
+
export interface PrefetchedConfigValidationResult {
|
|
20
|
+
accepted: boolean;
|
|
21
|
+
reason?: PrefetchedConfigRejectionReason;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decide whether a caller-prefetched live chat config may be adopted in place of a
|
|
25
|
+
* network fetch.
|
|
26
|
+
*
|
|
27
|
+
* The prefetched payload arrives from outside the SDK, so it is treated as
|
|
28
|
+
* untrusted input. It is adopted only when every check passes:
|
|
29
|
+
*
|
|
30
|
+
* 1. A payload was actually supplied.
|
|
31
|
+
* 2. The caller is not deliberately bypassing cache — a cache bypass must reach
|
|
32
|
+
* the network, otherwise `sendCacheHeaders` would be silently defeated.
|
|
33
|
+
* 3. The caller attested which org/widget it fetched the config for.
|
|
34
|
+
* 4. That attestation matches this SDK instance's own configured identity.
|
|
35
|
+
* 5. The payload is shaped like a config (`LiveWSAndLiveChatEngJoin` present, and
|
|
36
|
+
* a `LiveChatVersion`).
|
|
37
|
+
* 6. The payload's OWN identity matches too. The attestation is only a *claim
|
|
38
|
+
* about* the payload; without this step a caller that attests correctly but
|
|
39
|
+
* hands over the wrong object — two widgets on one page with the configs
|
|
40
|
+
* swapped, no attacker required — would be accepted. This is what actually
|
|
41
|
+
* makes a cross-widget or cross-tenant payload harmless.
|
|
42
|
+
*
|
|
43
|
+
* Payload identity is enforced only when the payload carries those fields, since
|
|
44
|
+
* not every config does; a config that omits them is still gated by checks 3-5.
|
|
45
|
+
*
|
|
46
|
+
* Two further conditions block adoption because the network fetch has side effects
|
|
47
|
+
* beyond returning the config:
|
|
48
|
+
*
|
|
49
|
+
* - The first fetch is also what proves the org url currently in use actually
|
|
50
|
+
* resolves. The SDK may rewrite that url at runtime (unq -> Core Services) and
|
|
51
|
+
* nothing else exercises the rewritten one; if it does not resolve, the fetch
|
|
52
|
+
* is what discovers that and falls back. Skipping the fetch skips the proof, so
|
|
53
|
+
* the caller must supply one: it attests the url it fetched from, and the
|
|
54
|
+
* payload is adopted only when that is the same url this instance is about to
|
|
55
|
+
* use. Then the caller's own successful fetch IS the proof. A caller that
|
|
56
|
+
* attests nothing, or attests a different url, takes the network fetch exactly
|
|
57
|
+
* as before.
|
|
58
|
+
* - The fetch also settles the live chat version on the underlying client. Only
|
|
59
|
+
* the version that client already defaults to can be adopted without the fetch,
|
|
60
|
+
* so any other version is rejected rather than half-applied.
|
|
61
|
+
*
|
|
62
|
+
* Any failure is a rejection, never an error: every input is type-checked before
|
|
63
|
+
* it is used, and the caller falls back to its normal network fetch, so a bad
|
|
64
|
+
* prefetch costs a round-trip and nothing else.
|
|
65
|
+
*
|
|
66
|
+
* Identity comparison is case-insensitive because org and widget ids are GUIDs
|
|
67
|
+
* whose casing is not stable across the surfaces that pass them around.
|
|
68
|
+
*
|
|
69
|
+
* @param prefetchedLiveChatConfig The payload supplied by the caller.
|
|
70
|
+
* @param attestation The identity the caller claims the payload was fetched for.
|
|
71
|
+
* @param expected This SDK instance's own configured identity.
|
|
72
|
+
* @param bypassCache Whether the caller requested a deliberate cache bypass.
|
|
73
|
+
* @param effectiveOrgUrl The org url this SDK instance is about to use, after any
|
|
74
|
+
* runtime rewrite. The attested fetch url must match it for the fast path.
|
|
75
|
+
*/
|
|
76
|
+
export declare const validatePrefetchedLiveChatConfig: (prefetchedLiveChatConfig: any, attestation: PrefetchedConfigAttestation | undefined, expected: PrefetchedConfigAttestation, bypassCache: boolean, effectiveOrgUrl: string) => PrefetchedConfigValidationResult;
|
|
77
|
+
export default validatePrefetchedLiveChatConfig;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validatePrefetchedLiveChatConfig = exports.PrefetchedConfigRejectionReason = void 0;
|
|
4
|
+
var LiveChatVersion_1 = require("../core/LiveChatVersion");
|
|
5
|
+
/**
|
|
6
|
+
* Reason a prefetched live chat config was not adopted. Emitted as telemetry so a
|
|
7
|
+
* silent fallback to the network is still observable.
|
|
8
|
+
*/
|
|
9
|
+
var PrefetchedConfigRejectionReason;
|
|
10
|
+
(function (PrefetchedConfigRejectionReason) {
|
|
11
|
+
PrefetchedConfigRejectionReason["NotProvided"] = "NotProvided";
|
|
12
|
+
PrefetchedConfigRejectionReason["CacheBypass"] = "CacheBypass";
|
|
13
|
+
PrefetchedConfigRejectionReason["MissingAttestation"] = "MissingAttestation";
|
|
14
|
+
PrefetchedConfigRejectionReason["IdentityMismatch"] = "IdentityMismatch";
|
|
15
|
+
PrefetchedConfigRejectionReason["UnverifiedOrgUrl"] = "UnverifiedOrgUrl";
|
|
16
|
+
PrefetchedConfigRejectionReason["OrgUrlMismatch"] = "OrgUrlMismatch";
|
|
17
|
+
PrefetchedConfigRejectionReason["MalformedPayload"] = "MalformedPayload";
|
|
18
|
+
PrefetchedConfigRejectionReason["MissingLiveChatVersion"] = "MissingLiveChatVersion";
|
|
19
|
+
PrefetchedConfigRejectionReason["UnsupportedLiveChatVersion"] = "UnsupportedLiveChatVersion";
|
|
20
|
+
PrefetchedConfigRejectionReason["PayloadOrgIdMismatch"] = "PayloadOrgIdMismatch";
|
|
21
|
+
PrefetchedConfigRejectionReason["PayloadWidgetIdMismatch"] = "PayloadWidgetIdMismatch";
|
|
22
|
+
})(PrefetchedConfigRejectionReason || (exports.PrefetchedConfigRejectionReason = PrefetchedConfigRejectionReason = {}));
|
|
23
|
+
var accepted = { accepted: true };
|
|
24
|
+
var rejected = function (reason) { return ({ accepted: false, reason: reason }); };
|
|
25
|
+
/**
|
|
26
|
+
* Whether two org urls address the same endpoint.
|
|
27
|
+
*
|
|
28
|
+
* Compared on ORIGIN rather than on the raw string: the two sides are produced
|
|
29
|
+
* independently (the caller builds a fetch url, the SDK builds its org url), so
|
|
30
|
+
* they can legitimately differ in trailing slash, case, or path while naming the
|
|
31
|
+
* same host. Anything unparsable is not a match — this gates a fast path, so
|
|
32
|
+
* "cannot tell" must mean "take the network fetch".
|
|
33
|
+
*/
|
|
34
|
+
var sameOrigin = function (a, b) {
|
|
35
|
+
try {
|
|
36
|
+
return new URL(a).origin.toLowerCase() === new URL(b).origin.toLowerCase();
|
|
37
|
+
}
|
|
38
|
+
catch (_a) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Decide whether a caller-prefetched live chat config may be adopted in place of a
|
|
44
|
+
* network fetch.
|
|
45
|
+
*
|
|
46
|
+
* The prefetched payload arrives from outside the SDK, so it is treated as
|
|
47
|
+
* untrusted input. It is adopted only when every check passes:
|
|
48
|
+
*
|
|
49
|
+
* 1. A payload was actually supplied.
|
|
50
|
+
* 2. The caller is not deliberately bypassing cache — a cache bypass must reach
|
|
51
|
+
* the network, otherwise `sendCacheHeaders` would be silently defeated.
|
|
52
|
+
* 3. The caller attested which org/widget it fetched the config for.
|
|
53
|
+
* 4. That attestation matches this SDK instance's own configured identity.
|
|
54
|
+
* 5. The payload is shaped like a config (`LiveWSAndLiveChatEngJoin` present, and
|
|
55
|
+
* a `LiveChatVersion`).
|
|
56
|
+
* 6. The payload's OWN identity matches too. The attestation is only a *claim
|
|
57
|
+
* about* the payload; without this step a caller that attests correctly but
|
|
58
|
+
* hands over the wrong object — two widgets on one page with the configs
|
|
59
|
+
* swapped, no attacker required — would be accepted. This is what actually
|
|
60
|
+
* makes a cross-widget or cross-tenant payload harmless.
|
|
61
|
+
*
|
|
62
|
+
* Payload identity is enforced only when the payload carries those fields, since
|
|
63
|
+
* not every config does; a config that omits them is still gated by checks 3-5.
|
|
64
|
+
*
|
|
65
|
+
* Two further conditions block adoption because the network fetch has side effects
|
|
66
|
+
* beyond returning the config:
|
|
67
|
+
*
|
|
68
|
+
* - The first fetch is also what proves the org url currently in use actually
|
|
69
|
+
* resolves. The SDK may rewrite that url at runtime (unq -> Core Services) and
|
|
70
|
+
* nothing else exercises the rewritten one; if it does not resolve, the fetch
|
|
71
|
+
* is what discovers that and falls back. Skipping the fetch skips the proof, so
|
|
72
|
+
* the caller must supply one: it attests the url it fetched from, and the
|
|
73
|
+
* payload is adopted only when that is the same url this instance is about to
|
|
74
|
+
* use. Then the caller's own successful fetch IS the proof. A caller that
|
|
75
|
+
* attests nothing, or attests a different url, takes the network fetch exactly
|
|
76
|
+
* as before.
|
|
77
|
+
* - The fetch also settles the live chat version on the underlying client. Only
|
|
78
|
+
* the version that client already defaults to can be adopted without the fetch,
|
|
79
|
+
* so any other version is rejected rather than half-applied.
|
|
80
|
+
*
|
|
81
|
+
* Any failure is a rejection, never an error: every input is type-checked before
|
|
82
|
+
* it is used, and the caller falls back to its normal network fetch, so a bad
|
|
83
|
+
* prefetch costs a round-trip and nothing else.
|
|
84
|
+
*
|
|
85
|
+
* Identity comparison is case-insensitive because org and widget ids are GUIDs
|
|
86
|
+
* whose casing is not stable across the surfaces that pass them around.
|
|
87
|
+
*
|
|
88
|
+
* @param prefetchedLiveChatConfig The payload supplied by the caller.
|
|
89
|
+
* @param attestation The identity the caller claims the payload was fetched for.
|
|
90
|
+
* @param expected This SDK instance's own configured identity.
|
|
91
|
+
* @param bypassCache Whether the caller requested a deliberate cache bypass.
|
|
92
|
+
* @param effectiveOrgUrl The org url this SDK instance is about to use, after any
|
|
93
|
+
* runtime rewrite. The attested fetch url must match it for the fast path.
|
|
94
|
+
*/
|
|
95
|
+
var validatePrefetchedLiveChatConfig = function (
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
+
prefetchedLiveChatConfig, attestation, expected, bypassCache, effectiveOrgUrl) {
|
|
98
|
+
if (prefetchedLiveChatConfig === undefined || prefetchedLiveChatConfig === null) {
|
|
99
|
+
return rejected(PrefetchedConfigRejectionReason.NotProvided);
|
|
100
|
+
}
|
|
101
|
+
if (bypassCache) {
|
|
102
|
+
return rejected(PrefetchedConfigRejectionReason.CacheBypass);
|
|
103
|
+
}
|
|
104
|
+
if (!attestation || typeof attestation.orgId !== "string" || typeof attestation.widgetId !== "string" || !attestation.orgId || !attestation.widgetId) {
|
|
105
|
+
return rejected(PrefetchedConfigRejectionReason.MissingAttestation);
|
|
106
|
+
}
|
|
107
|
+
if (typeof expected.orgId !== "string" || typeof expected.widgetId !== "string" || !expected.orgId || !expected.widgetId) {
|
|
108
|
+
return rejected(PrefetchedConfigRejectionReason.MissingAttestation);
|
|
109
|
+
}
|
|
110
|
+
var sameIdentity = attestation.orgId.toLowerCase() === expected.orgId.toLowerCase() &&
|
|
111
|
+
attestation.widgetId.toLowerCase() === expected.widgetId.toLowerCase();
|
|
112
|
+
if (!sameIdentity) {
|
|
113
|
+
return rejected(PrefetchedConfigRejectionReason.IdentityMismatch);
|
|
114
|
+
}
|
|
115
|
+
if (typeof attestation.orgUrl !== "string" || !attestation.orgUrl) {
|
|
116
|
+
return rejected(PrefetchedConfigRejectionReason.UnverifiedOrgUrl);
|
|
117
|
+
}
|
|
118
|
+
if (!sameOrigin(attestation.orgUrl, effectiveOrgUrl)) {
|
|
119
|
+
return rejected(PrefetchedConfigRejectionReason.OrgUrlMismatch);
|
|
120
|
+
}
|
|
121
|
+
if (typeof prefetchedLiveChatConfig !== "object" || Array.isArray(prefetchedLiveChatConfig)) {
|
|
122
|
+
return rejected(PrefetchedConfigRejectionReason.MalformedPayload);
|
|
123
|
+
}
|
|
124
|
+
// Every live chat config carries this block; its absence means we were handed
|
|
125
|
+
// something that is not a config, and adopting it would fail later in
|
|
126
|
+
// buildConfigurations() in a much harder place to diagnose.
|
|
127
|
+
if (!prefetchedLiveChatConfig.LiveWSAndLiveChatEngJoin || typeof prefetchedLiveChatConfig.LiveWSAndLiveChatEngJoin !== "object") {
|
|
128
|
+
return rejected(PrefetchedConfigRejectionReason.MalformedPayload);
|
|
129
|
+
}
|
|
130
|
+
if (prefetchedLiveChatConfig.LiveChatVersion === undefined || prefetchedLiveChatConfig.LiveChatVersion === null) {
|
|
131
|
+
return rejected(PrefetchedConfigRejectionReason.MissingLiveChatVersion);
|
|
132
|
+
}
|
|
133
|
+
if (prefetchedLiveChatConfig.LiveChatVersion !== LiveChatVersion_1.default.V2) {
|
|
134
|
+
return rejected(PrefetchedConfigRejectionReason.UnsupportedLiveChatVersion);
|
|
135
|
+
}
|
|
136
|
+
// The attestation above is only the caller's CLAIM about this payload. These
|
|
137
|
+
// two checks verify the payload itself, which is what stops a correctly
|
|
138
|
+
// attested but wrongly selected object from being adopted. Enforced only when
|
|
139
|
+
// present, since not every config carries them.
|
|
140
|
+
var payloadOrgId = prefetchedLiveChatConfig.SalOrgId;
|
|
141
|
+
if (typeof payloadOrgId === "string" && payloadOrgId.length > 0 && payloadOrgId.toLowerCase() !== expected.orgId.toLowerCase()) {
|
|
142
|
+
return rejected(PrefetchedConfigRejectionReason.PayloadOrgIdMismatch);
|
|
143
|
+
}
|
|
144
|
+
var payloadWidgetId = prefetchedLiveChatConfig.LiveWSAndLiveChatEngJoin.msdyn_widgetappid;
|
|
145
|
+
if (typeof payloadWidgetId === "string" && payloadWidgetId.length > 0 && payloadWidgetId.toLowerCase() !== expected.widgetId.toLowerCase()) {
|
|
146
|
+
return rejected(PrefetchedConfigRejectionReason.PayloadWidgetIdMismatch);
|
|
147
|
+
}
|
|
148
|
+
return accepted;
|
|
149
|
+
};
|
|
150
|
+
exports.validatePrefetchedLiveChatConfig = validatePrefetchedLiveChatConfig;
|
|
151
|
+
exports.default = exports.validatePrefetchedLiveChatConfig;
|
|
152
|
+
//# sourceMappingURL=prefetchedConfigValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetchedConfigValidator.js","sourceRoot":"","sources":["../../src/validators/prefetchedConfigValidator.ts"],"names":[],"mappings":"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"}
|