@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.
@@ -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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/omnichannel-chat-sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.1-main.b9e3cb3",
4
4
  "description": "Microsoft Omnichannel Chat SDK",
5
5
  "files": [
6
6
  "lib/**/*"