@microsoft/omnichannel-chat-widget 1.8.4-main.51ef6e3 → 1.8.4-main.5b3f077

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.
@@ -11,6 +11,7 @@ var _appInsightsLogger = require("./loggers/appInsightsLogger");
11
11
  var _ariaTelemetryLogger = require("./loggers/ariaTelemetryLogger");
12
12
  var _consoleLogger = require("./loggers/consoleLogger");
13
13
  var _defaultAriaConfig = require("./defaultConfigs/defaultAriaConfig");
14
+ var _sanitizeSasInPayload = require("./sanitizeSasInPayload");
14
15
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
15
16
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
16
17
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -81,11 +82,15 @@ const RegisterLoggers = () => {
81
82
  };
82
83
  };
83
84
  const logTelemetry = telemetryEvent => {
85
+ // Redact Azure SAS credentials in any URL embedded in the payload (e.g.
86
+ // customer-supplied blob asset URLs in widget customization props) before
87
+ // it fans out to console, Aria, AppInsights, or any custom logger.
88
+ const sanitizedPayload = (0, _sanitizeSasInPayload.sanitizeSasInPayload)(telemetryEvent === null || telemetryEvent === void 0 ? void 0 : telemetryEvent.payload);
84
89
  loggers.map(logger => {
85
90
  var _payload, _telemetryInput$paylo;
86
91
  const logLevel = telemetryEvent.logLevel ?? _TelemetryConstants.LogLevel.INFO;
87
92
  const scenarioType = ((_payload = telemetryEvent.payload) === null || _payload === void 0 ? void 0 : _payload.scenarioType) ?? _TelemetryConstants.ScenarioType.UNDEFINED;
88
- const telemetryInput = parseInput(telemetryEvent === null || telemetryEvent === void 0 ? void 0 : telemetryEvent.payload, scenarioType);
93
+ const telemetryInput = parseInput(sanitizedPayload, scenarioType);
89
94
  telemetryInput.telemetryInfo = {
90
95
  telemetryInfo: _TelemetryHelper.TelemetryHelper.buildTelemetryEvent(logLevel, telemetryInput)
91
96
  };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sanitizeSasInPayload = void 0;
7
+ /**
8
+ * Redacts the values of Azure Shared Access Signature (SAS) query parameters in any
9
+ * URL embedded in a telemetry payload, so customer-supplied SAS URLs (e.g. blob asset
10
+ * URLs in widget customization props) cannot leak credentials through Aria/AppInsights.
11
+ *
12
+ * Trigger: any URL whose query string contains `sig=`. When detected, every well-known
13
+ * SAS parameter value in that query is replaced with `[REDACTED]`. Other URLs and other
14
+ * substrings of the payload pass through unchanged.
15
+ *
16
+ * Coverage of SAS parameter names:
17
+ * - Service/Blob SAS: sig, sv, se, st, sp, spr, sr, sip
18
+ * - Account SAS: ss, srt
19
+ * - User-delegation key SAS: skoid, sktid, skt, ske, sks, skv, saoid, suoid, sce, sdd
20
+ * - Response header overrides: rscc, rscd, rsce, rscl, rsct
21
+ *
22
+ * Reference: https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas
23
+ */
24
+
25
+ const SAS_PARAM_NAMES = new Set(["sig", "sv", "se", "st", "sp", "spr", "sr", "sip", "ss", "srt", "skoid", "sktid", "skt", "ske", "sks", "skv", "saoid", "suoid", "sce", "sdd", "rscc", "rscd", "rsce", "rscl", "rsct"]);
26
+ const REDACTED_VALUE = "[REDACTED]";
27
+
28
+ // Matches any http(s) URL substring up to whitespace / closing quote / angle-bracket / paren.
29
+ const URL_REGEX = /\bhttps?:\/\/[^\s"'<>)]+/gi;
30
+ const redactQueryIfSas = url => {
31
+ const queryIdx = url.indexOf("?");
32
+ if (queryIdx < 0) {
33
+ return url;
34
+ }
35
+ // Separate the fragment (#...) before processing the query — fragments come
36
+ // after the query string in URL syntax and must not be folded into the last
37
+ // query parameter's value when we split on `&`.
38
+ const afterQuestionMark = url.slice(queryIdx + 1);
39
+ const fragIdx = afterQuestionMark.indexOf("#");
40
+ const query = fragIdx < 0 ? afterQuestionMark : afterQuestionMark.slice(0, fragIdx);
41
+ const fragment = fragIdx < 0 ? "" : afterQuestionMark.slice(fragIdx); // includes the leading '#'
42
+ if (!/(^|&)sig=/i.test(query)) {
43
+ // No SAS signature present — leave the URL alone so legitimate non-SAS query
44
+ // strings (e.g. ?utm_source=...) are not mangled.
45
+ return url;
46
+ }
47
+ const base = url.slice(0, queryIdx);
48
+ const sanitizedQuery = query.split("&").map(pair => {
49
+ const eqIdx = pair.indexOf("=");
50
+ if (eqIdx < 0) {
51
+ return pair;
52
+ }
53
+ const name = pair.slice(0, eqIdx).toLowerCase();
54
+ return SAS_PARAM_NAMES.has(name) ? `${pair.slice(0, eqIdx)}=${REDACTED_VALUE}` : pair;
55
+ }).join("&");
56
+ return `${base}?${sanitizedQuery}${fragment}`;
57
+ };
58
+ const sanitizeString = s => s.replace(URL_REGEX, redactQueryIfSas);
59
+
60
+ /**
61
+ * Deep-walk a value and redact SAS credentials in any string it contains.
62
+ * Returns a new object/array (originals are not mutated); non-string leaves are
63
+ * passed through. Tree-shaped, JSON-like values only — not designed for class
64
+ * instances, prototype-bound objects, or cyclic graphs.
65
+ */
66
+ const sanitizeSasInPayload = value => {
67
+ if (typeof value === "string") {
68
+ return sanitizeString(value);
69
+ }
70
+ if (Array.isArray(value)) {
71
+ return value.map(sanitizeSasInPayload);
72
+ }
73
+ if (value !== null && typeof value === "object") {
74
+ const out = {};
75
+ for (const [k, v] of Object.entries(value)) {
76
+ out[k] = sanitizeSasInPayload(v);
77
+ }
78
+ return out;
79
+ }
80
+ return value;
81
+ };
82
+ exports.sanitizeSasInPayload = sanitizeSasInPayload;
@@ -12,7 +12,6 @@ const defaultGeneralPreChatSurveyPaneStyleProps = {
12
12
  borderColor: "#F1F1F1",
13
13
  overflowY: "auto",
14
14
  height: "inherit",
15
- width: "inherit",
16
- overscrollBehavior: "none"
15
+ width: "inherit"
17
16
  };
18
17
  exports.defaultGeneralPreChatSurveyPaneStyleProps = defaultGeneralPreChatSurveyPaneStyleProps;
@@ -11,6 +11,7 @@ import { appInsightsLogger } from "./loggers/appInsightsLogger";
11
11
  import { ariaTelemetryLogger } from "./loggers/ariaTelemetryLogger";
12
12
  import { consoleLogger } from "./loggers/consoleLogger";
13
13
  import { defaultAriaConfig } from "./defaultConfigs/defaultAriaConfig";
14
+ import { sanitizeSasInPayload } from "./sanitizeSasInPayload";
14
15
  export let TelemetryTimers = /*#__PURE__*/_createClass(function TelemetryTimers() {
15
16
  _classCallCheck(this, TelemetryTimers);
16
17
  });
@@ -72,11 +73,15 @@ export const RegisterLoggers = () => {
72
73
  };
73
74
  };
74
75
  const logTelemetry = telemetryEvent => {
76
+ // Redact Azure SAS credentials in any URL embedded in the payload (e.g.
77
+ // customer-supplied blob asset URLs in widget customization props) before
78
+ // it fans out to console, Aria, AppInsights, or any custom logger.
79
+ const sanitizedPayload = sanitizeSasInPayload(telemetryEvent === null || telemetryEvent === void 0 ? void 0 : telemetryEvent.payload);
75
80
  loggers.map(logger => {
76
81
  var _payload, _telemetryInput$paylo;
77
82
  const logLevel = telemetryEvent.logLevel ?? LogLevel.INFO;
78
83
  const scenarioType = ((_payload = telemetryEvent.payload) === null || _payload === void 0 ? void 0 : _payload.scenarioType) ?? ScenarioType.UNDEFINED;
79
- const telemetryInput = parseInput(telemetryEvent === null || telemetryEvent === void 0 ? void 0 : telemetryEvent.payload, scenarioType);
84
+ const telemetryInput = parseInput(sanitizedPayload, scenarioType);
80
85
  telemetryInput.telemetryInfo = {
81
86
  telemetryInfo: TelemetryHelper.buildTelemetryEvent(logLevel, telemetryInput)
82
87
  };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Redacts the values of Azure Shared Access Signature (SAS) query parameters in any
3
+ * URL embedded in a telemetry payload, so customer-supplied SAS URLs (e.g. blob asset
4
+ * URLs in widget customization props) cannot leak credentials through Aria/AppInsights.
5
+ *
6
+ * Trigger: any URL whose query string contains `sig=`. When detected, every well-known
7
+ * SAS parameter value in that query is replaced with `[REDACTED]`. Other URLs and other
8
+ * substrings of the payload pass through unchanged.
9
+ *
10
+ * Coverage of SAS parameter names:
11
+ * - Service/Blob SAS: sig, sv, se, st, sp, spr, sr, sip
12
+ * - Account SAS: ss, srt
13
+ * - User-delegation key SAS: skoid, sktid, skt, ske, sks, skv, saoid, suoid, sce, sdd
14
+ * - Response header overrides: rscc, rscd, rsce, rscl, rsct
15
+ *
16
+ * Reference: https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas
17
+ */
18
+
19
+ const SAS_PARAM_NAMES = new Set(["sig", "sv", "se", "st", "sp", "spr", "sr", "sip", "ss", "srt", "skoid", "sktid", "skt", "ske", "sks", "skv", "saoid", "suoid", "sce", "sdd", "rscc", "rscd", "rsce", "rscl", "rsct"]);
20
+ const REDACTED_VALUE = "[REDACTED]";
21
+
22
+ // Matches any http(s) URL substring up to whitespace / closing quote / angle-bracket / paren.
23
+ const URL_REGEX = /\bhttps?:\/\/[^\s"'<>)]+/gi;
24
+ const redactQueryIfSas = url => {
25
+ const queryIdx = url.indexOf("?");
26
+ if (queryIdx < 0) {
27
+ return url;
28
+ }
29
+ // Separate the fragment (#...) before processing the query — fragments come
30
+ // after the query string in URL syntax and must not be folded into the last
31
+ // query parameter's value when we split on `&`.
32
+ const afterQuestionMark = url.slice(queryIdx + 1);
33
+ const fragIdx = afterQuestionMark.indexOf("#");
34
+ const query = fragIdx < 0 ? afterQuestionMark : afterQuestionMark.slice(0, fragIdx);
35
+ const fragment = fragIdx < 0 ? "" : afterQuestionMark.slice(fragIdx); // includes the leading '#'
36
+ if (!/(^|&)sig=/i.test(query)) {
37
+ // No SAS signature present — leave the URL alone so legitimate non-SAS query
38
+ // strings (e.g. ?utm_source=...) are not mangled.
39
+ return url;
40
+ }
41
+ const base = url.slice(0, queryIdx);
42
+ const sanitizedQuery = query.split("&").map(pair => {
43
+ const eqIdx = pair.indexOf("=");
44
+ if (eqIdx < 0) {
45
+ return pair;
46
+ }
47
+ const name = pair.slice(0, eqIdx).toLowerCase();
48
+ return SAS_PARAM_NAMES.has(name) ? `${pair.slice(0, eqIdx)}=${REDACTED_VALUE}` : pair;
49
+ }).join("&");
50
+ return `${base}?${sanitizedQuery}${fragment}`;
51
+ };
52
+ const sanitizeString = s => s.replace(URL_REGEX, redactQueryIfSas);
53
+
54
+ /**
55
+ * Deep-walk a value and redact SAS credentials in any string it contains.
56
+ * Returns a new object/array (originals are not mutated); non-string leaves are
57
+ * passed through. Tree-shaped, JSON-like values only — not designed for class
58
+ * instances, prototype-bound objects, or cyclic graphs.
59
+ */
60
+ export const sanitizeSasInPayload = value => {
61
+ if (typeof value === "string") {
62
+ return sanitizeString(value);
63
+ }
64
+ if (Array.isArray(value)) {
65
+ return value.map(sanitizeSasInPayload);
66
+ }
67
+ if (value !== null && typeof value === "object") {
68
+ const out = {};
69
+ for (const [k, v] of Object.entries(value)) {
70
+ out[k] = sanitizeSasInPayload(v);
71
+ }
72
+ return out;
73
+ }
74
+ return value;
75
+ };
@@ -6,6 +6,5 @@ export const defaultGeneralPreChatSurveyPaneStyleProps = {
6
6
  borderColor: "#F1F1F1",
7
7
  overflowY: "auto",
8
8
  height: "inherit",
9
- width: "inherit",
10
- overscrollBehavior: "none"
9
+ width: "inherit"
11
10
  };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Redacts the values of Azure Shared Access Signature (SAS) query parameters in any
3
+ * URL embedded in a telemetry payload, so customer-supplied SAS URLs (e.g. blob asset
4
+ * URLs in widget customization props) cannot leak credentials through Aria/AppInsights.
5
+ *
6
+ * Trigger: any URL whose query string contains `sig=`. When detected, every well-known
7
+ * SAS parameter value in that query is replaced with `[REDACTED]`. Other URLs and other
8
+ * substrings of the payload pass through unchanged.
9
+ *
10
+ * Coverage of SAS parameter names:
11
+ * - Service/Blob SAS: sig, sv, se, st, sp, spr, sr, sip
12
+ * - Account SAS: ss, srt
13
+ * - User-delegation key SAS: skoid, sktid, skt, ske, sks, skv, saoid, suoid, sce, sdd
14
+ * - Response header overrides: rscc, rscd, rsce, rscl, rsct
15
+ *
16
+ * Reference: https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas
17
+ */
18
+ /**
19
+ * Deep-walk a value and redact SAS credentials in any string it contains.
20
+ * Returns a new object/array (originals are not mutated); non-string leaves are
21
+ * passed through. Tree-shaped, JSON-like values only — not designed for class
22
+ * instances, prototype-bound objects, or cyclic graphs.
23
+ */
24
+ export declare const sanitizeSasInPayload: <T>(value: T) => T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/omnichannel-chat-widget",
3
- "version": "1.8.4-main.51ef6e3",
3
+ "version": "1.8.4-main.5b3f077",
4
4
  "description": "Microsoft Omnichannel Chat Widget",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/types/index.d.ts",