@droppii-org/chat-sdk 0.1.0 → 0.1.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.
@@ -12,5 +12,18 @@ export declare const urlRegex: RegExp;
12
12
  export declare function extractLinks(text: string): string[];
13
13
  export declare function wrapLinksInHtml(htmlContent: string): string;
14
14
  export declare const getHostFromUrl: (url: string) => string | null;
15
+ /**
16
+ * Sanitizes HTML content to prevent XSS attacks
17
+ * Uses DOMPurify to remove all potentially malicious code
18
+ *
19
+ * @param html - Raw HTML content that may contain malicious scripts
20
+ * @returns Sanitized HTML safe for rendering
21
+ *
22
+ * @example
23
+ * const userInput = '<img src=x onerror=alert("XSS")>';
24
+ * const safe = sanitizeHtml(userInput);
25
+ * // Returns: '<img src="x">' (onerror removed)
26
+ */
27
+ export declare function sanitizeHtml(html: string): string;
15
28
  export {};
16
29
  //# sourceMappingURL=common.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,eAAO,MAAM,iCAAiC,GAC5C,aAAa,WAAW,EACxB,YAAY,MAAM,WAkBnB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,IAAI,GAAG,uBA2CR,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,kBAAc,WA2Cf,CAAC;AAEF,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAqBR;AAED,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqC3D;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAItD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,eAAO,MAAM,iCAAiC,GAC5C,aAAa,WAAW,EACxB,YAAY,MAAM,WAkBnB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,IAAI,GAAG,uBA2CR,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,kBAAc,WA2Cf,CAAC;AAEF,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAqBR;AAED,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqC3D;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwCjD"}
@@ -1,5 +1,6 @@
1
1
  import { MessageType } from "@openim/wasm-client-sdk";
2
2
  import dayjs from "dayjs";
3
+ import DOMPurify from "dompurify";
3
4
  export function renderFileSize(bytes) {
4
5
  if (!bytes || bytes <= 0)
5
6
  return "0 B";
@@ -165,3 +166,53 @@ export const getHostFromUrl = (url) => {
165
166
  return null;
166
167
  }
167
168
  };
169
+ /**
170
+ * Sanitizes HTML content to prevent XSS attacks
171
+ * Uses DOMPurify to remove all potentially malicious code
172
+ *
173
+ * @param html - Raw HTML content that may contain malicious scripts
174
+ * @returns Sanitized HTML safe for rendering
175
+ *
176
+ * @example
177
+ * const userInput = '<img src=x onerror=alert("XSS")>';
178
+ * const safe = sanitizeHtml(userInput);
179
+ * // Returns: '<img src="x">' (onerror removed)
180
+ */
181
+ export function sanitizeHtml(html) {
182
+ if (!html)
183
+ return "";
184
+ // Configure DOMPurify hooks
185
+ DOMPurify.addHook("afterSanitizeAttributes", (node) => {
186
+ // Ensure all links open in new tab with security attributes
187
+ if (node.tagName === "A") {
188
+ node.setAttribute("target", "_blank");
189
+ node.setAttribute("rel", "noopener noreferrer");
190
+ }
191
+ });
192
+ const sanitized = DOMPurify.sanitize(html, {
193
+ ALLOWED_TAGS: [
194
+ // Text formatting
195
+ "b", "i", "u", "strong", "em", "mark", "small", "del", "ins", "sub", "sup",
196
+ // Structure
197
+ "p", "br", "div", "span", "blockquote", "pre", "code",
198
+ // Lists
199
+ "ul", "ol", "li",
200
+ // Links
201
+ "a",
202
+ // Headers
203
+ "h1", "h2", "h3", "h4", "h5", "h6",
204
+ ],
205
+ ALLOWED_ATTR: [
206
+ "href",
207
+ "target",
208
+ "rel",
209
+ "class",
210
+ "style", // Allow style for basic formatting
211
+ ],
212
+ ALLOW_DATA_ATTR: false, // Prevent data-* attributes
213
+ ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
214
+ });
215
+ // Remove hooks after sanitization
216
+ DOMPurify.removeHook("afterSanitizeAttributes");
217
+ return sanitized;
218
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droppii-org/chat-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Droppii React Chat SDK",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -82,6 +82,7 @@
82
82
  "axios": "^1.11.0",
83
83
  "clsx": "^2.0.0",
84
84
  "dayjs": "^1.11.13",
85
+ "dompurify": "^3.3.1",
85
86
  "i18next": "^25.5.2",
86
87
  "jwt-decode": "^4.0.0",
87
88
  "lexical": "^0.34.0",
@@ -105,6 +106,7 @@
105
106
  "react-dom": "^18.0.0"
106
107
  },
107
108
  "devDependencies": {
109
+ "@types/dompurify": "^3.2.0",
108
110
  "@types/lodash": "^4.17.20",
109
111
  "@types/node": "^20.0.0",
110
112
  "@types/react": "^18.2.37",