@microsoft/omnichannel-chat-components 1.1.16 → 1.1.17-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.
|
@@ -23,7 +23,7 @@ const HiddenTextStyles = {
|
|
|
23
23
|
exports.HiddenTextStyles = HiddenTextStyles;
|
|
24
24
|
const KeyCodes = (_class = class KeyCodes {}, _defineProperty(_class, "ENTER", "Enter"), _defineProperty(_class, "ESCAPE", "Escape"), _defineProperty(_class, "SPACE", "Space"), _defineProperty(_class, "DeclineCallHotKey", "D"), _defineProperty(_class, "AcceptAudioCallHotKey", "S"), _defineProperty(_class, "AcceptVideoCallHotKey", "A"), _defineProperty(_class, "ToggleMicHotKey", "M"), _defineProperty(_class, "ToggleCameraHotKey", "O"), _defineProperty(_class, "EndCallHotKey", "H"), _class);
|
|
25
25
|
exports.KeyCodes = KeyCodes;
|
|
26
|
-
const Regex = (_class2 = class Regex {}, _defineProperty(_class2, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _defineProperty(_class2, "URLRegex", /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi), _class2);
|
|
26
|
+
const Regex = (_class2 = class Regex {}, _defineProperty(_class2, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _defineProperty(_class2, "URLRegex", /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}|mailto:[^\s]+|tel:[^\s]+|sms:[^\s]+)/gi), _class2);
|
|
27
27
|
exports.Regex = Regex;
|
|
28
28
|
let ElementType;
|
|
29
29
|
exports.ElementType = ElementType;
|
package/lib/cjs/common/utils.js
CHANGED
|
@@ -131,20 +131,48 @@ const addNoreferrerNoopenerTag = htmlNode => {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
-
};
|
|
134
|
+
}; // Escape HTML special characters to prevent XSS in string concatenation
|
|
135
|
+
|
|
135
136
|
|
|
136
137
|
exports.addNoreferrerNoopenerTag = addNoreferrerNoopenerTag;
|
|
137
138
|
|
|
139
|
+
const escapeHTML = str => {
|
|
140
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
141
|
+
}; // Escape only characters dangerous in href attribute context
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
const escapeHrefAttribute = url => {
|
|
145
|
+
return url.replace(/"/g, """).replace(/'/g, "'");
|
|
146
|
+
}; // Validate and sanitize URL to prevent javascript: and data: protocols
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
const isValidURL = url => {
|
|
150
|
+
const trimmedUrl = url.trim().toLowerCase(); // Block dangerous protocols
|
|
151
|
+
|
|
152
|
+
if (trimmedUrl.startsWith("javascript:") || trimmedUrl.startsWith("data:") || trimmedUrl.startsWith("vbscript:") || trimmedUrl.startsWith("file:")) {
|
|
153
|
+
return false;
|
|
154
|
+
} // Allow http, https, protocol-relative URLs, and safe contact schemes
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
return trimmedUrl.startsWith("http://") || trimmedUrl.startsWith("https://") || trimmedUrl.startsWith("www.") || trimmedUrl.startsWith("mailto:") || trimmedUrl.startsWith("tel:") || trimmedUrl.startsWith("sms:");
|
|
158
|
+
};
|
|
159
|
+
|
|
138
160
|
const replaceURLWithAnchor = (text, openInNewTab) => {
|
|
139
161
|
if (text) {
|
|
140
162
|
const modifiedText = text.replace(_Constants.Regex.URLRegex, function (url) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return
|
|
144
|
-
}
|
|
163
|
+
// Validate URL to prevent dangerous protocols
|
|
164
|
+
if (!isValidURL(url)) {
|
|
165
|
+
return escapeHTML(url); // Return escaped text, not a link
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const escapedUrl = escapeHrefAttribute(url);
|
|
169
|
+
const displayText = escapeHTML(url);
|
|
145
170
|
|
|
171
|
+
if (openInNewTab) {
|
|
172
|
+
return `<a href="${escapedUrl}" rel="noreferrer noopener" target="_blank">${displayText}</a>`;
|
|
173
|
+
}
|
|
146
174
|
|
|
147
|
-
return
|
|
175
|
+
return `<a href="${escapedUrl}">${displayText}</a>`;
|
|
148
176
|
});
|
|
149
177
|
return modifiedText;
|
|
150
178
|
}
|
|
@@ -13,7 +13,7 @@ export const HiddenTextStyles = {
|
|
|
13
13
|
whiteSpace: "nowrap"
|
|
14
14
|
};
|
|
15
15
|
export const KeyCodes = (_class = class KeyCodes {}, _defineProperty(_class, "ENTER", "Enter"), _defineProperty(_class, "ESCAPE", "Escape"), _defineProperty(_class, "SPACE", "Space"), _defineProperty(_class, "DeclineCallHotKey", "D"), _defineProperty(_class, "AcceptAudioCallHotKey", "S"), _defineProperty(_class, "AcceptVideoCallHotKey", "A"), _defineProperty(_class, "ToggleMicHotKey", "M"), _defineProperty(_class, "ToggleCameraHotKey", "O"), _defineProperty(_class, "EndCallHotKey", "H"), _class);
|
|
16
|
-
export const Regex = (_class2 = class Regex {}, _defineProperty(_class2, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _defineProperty(_class2, "URLRegex", /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi), _class2);
|
|
16
|
+
export const Regex = (_class2 = class Regex {}, _defineProperty(_class2, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _defineProperty(_class2, "URLRegex", /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}|mailto:[^\s]+|tel:[^\s]+|sms:[^\s]+)/gi), _class2);
|
|
17
17
|
export let ElementType;
|
|
18
18
|
|
|
19
19
|
(function (ElementType) {
|
package/lib/esm/common/utils.js
CHANGED
|
@@ -93,17 +93,45 @@ export const addNoreferrerNoopenerTag = htmlNode => {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
}; // Escape HTML special characters to prevent XSS in string concatenation
|
|
97
|
+
|
|
98
|
+
const escapeHTML = str => {
|
|
99
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
100
|
+
}; // Escape only characters dangerous in href attribute context
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
const escapeHrefAttribute = url => {
|
|
104
|
+
return url.replace(/"/g, """).replace(/'/g, "'");
|
|
105
|
+
}; // Validate and sanitize URL to prevent javascript: and data: protocols
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
const isValidURL = url => {
|
|
109
|
+
const trimmedUrl = url.trim().toLowerCase(); // Block dangerous protocols
|
|
110
|
+
|
|
111
|
+
if (trimmedUrl.startsWith("javascript:") || trimmedUrl.startsWith("data:") || trimmedUrl.startsWith("vbscript:") || trimmedUrl.startsWith("file:")) {
|
|
112
|
+
return false;
|
|
113
|
+
} // Allow http, https, protocol-relative URLs, and safe contact schemes
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
return trimmedUrl.startsWith("http://") || trimmedUrl.startsWith("https://") || trimmedUrl.startsWith("www.") || trimmedUrl.startsWith("mailto:") || trimmedUrl.startsWith("tel:") || trimmedUrl.startsWith("sms:");
|
|
96
117
|
};
|
|
118
|
+
|
|
97
119
|
export const replaceURLWithAnchor = (text, openInNewTab) => {
|
|
98
120
|
if (text) {
|
|
99
121
|
const modifiedText = text.replace(Regex.URLRegex, function (url) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return
|
|
103
|
-
}
|
|
122
|
+
// Validate URL to prevent dangerous protocols
|
|
123
|
+
if (!isValidURL(url)) {
|
|
124
|
+
return escapeHTML(url); // Return escaped text, not a link
|
|
125
|
+
}
|
|
104
126
|
|
|
127
|
+
const escapedUrl = escapeHrefAttribute(url);
|
|
128
|
+
const displayText = escapeHTML(url);
|
|
129
|
+
|
|
130
|
+
if (openInNewTab) {
|
|
131
|
+
return `<a href="${escapedUrl}" rel="noreferrer noopener" target="_blank">${displayText}</a>`;
|
|
132
|
+
}
|
|
105
133
|
|
|
106
|
-
return
|
|
134
|
+
return `<a href="${escapedUrl}">${displayText}</a>`;
|
|
107
135
|
});
|
|
108
136
|
return modifiedText;
|
|
109
137
|
}
|