@commercetools-uikit/rich-text-utils 20.3.1 → 20.5.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.
@@ -26,6 +26,7 @@ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-
26
26
  var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
27
27
  var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
28
28
  var escapeHtml = require('escape-html');
29
+ var DOMPurify = require('dompurify');
29
30
  var slate = require('slate');
30
31
  var slateHyperscript = require('slate-hyperscript');
31
32
  var parse = require('style-to-object');
@@ -72,6 +73,7 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
72
73
  var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
73
74
  var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
74
75
  var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
76
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
75
77
  var parse__default = /*#__PURE__*/_interopDefault(parse);
76
78
  var isEmpty__default = /*#__PURE__*/_interopDefault(isEmpty$2);
77
79
  var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
@@ -449,10 +451,33 @@ function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _
449
451
  // more: https://docs.slatejs.org/concepts/12-typescript
450
452
  // example: https://github.com/ianstormtaylor/slate/blob/main/packages/slate-react/src/custom-types.ts
451
453
 
454
+ /**
455
+ * Escapes HTML but preserves anchor tags with sanitized attributes.
456
+ * This allows <a> tags to remain as clickable links while preventing XSS from other tags.
457
+ * Uses DOMPurify for robust sanitization against XSS attacks.
458
+ */
459
+ const escapeHtmlExceptAnchors = text => {
460
+ // Use DOMPurify to sanitize the text, allowing only anchor tags
461
+ // This is much more secure than regex-based parsing
462
+ const sanitized = DOMPurify__default["default"].sanitize(text, {
463
+ ALLOWED_TAGS: ['a'],
464
+ ALLOWED_ATTR: ['href', 'title', 'target', 'rel'],
465
+ // Block dangerous URL schemes
466
+ ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
467
+ // Prevent DOM clobbering
468
+ SANITIZE_DOM: true,
469
+ // Keep relative URLs
470
+ ALLOW_DATA_ATTR: false,
471
+ // Return a string, not a DOM node
472
+ RETURN_DOM: false,
473
+ RETURN_DOM_FRAGMENT: false
474
+ });
475
+ return sanitized;
476
+ };
452
477
  const serializeNode = node => {
453
478
  var _context, _context5, _context6;
454
479
  if (slate.Text.isText(node)) {
455
- let string = escapeHtml__default["default"](node.text);
480
+ let string = escapeHtmlExceptAnchors(node.text);
456
481
  if (node.bold) {
457
482
  string = "<strong>".concat(string, "</strong>");
458
483
  }
@@ -1972,7 +1997,7 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
1972
1997
  var RichTextEditorBody$1 = RichTextEditorBody;
1973
1998
 
1974
1999
  // NOTE: This string will be replaced on build time with the package version.
1975
- var version = "20.3.1";
2000
+ var version = "20.5.0";
1976
2001
 
1977
2002
  exports.Element = Element;
1978
2003
  exports.HiddenInput = HiddenInput$1;
@@ -26,6 +26,7 @@ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-
26
26
  var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
27
27
  var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
28
28
  var escapeHtml = require('escape-html');
29
+ var DOMPurify = require('dompurify');
29
30
  var slate = require('slate');
30
31
  var slateHyperscript = require('slate-hyperscript');
31
32
  var parse = require('style-to-object');
@@ -72,6 +73,7 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
72
73
  var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
73
74
  var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
74
75
  var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
76
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
75
77
  var parse__default = /*#__PURE__*/_interopDefault(parse);
76
78
  var isEmpty__default = /*#__PURE__*/_interopDefault(isEmpty$2);
77
79
  var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
@@ -449,10 +451,33 @@ function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _
449
451
  // more: https://docs.slatejs.org/concepts/12-typescript
450
452
  // example: https://github.com/ianstormtaylor/slate/blob/main/packages/slate-react/src/custom-types.ts
451
453
 
454
+ /**
455
+ * Escapes HTML but preserves anchor tags with sanitized attributes.
456
+ * This allows <a> tags to remain as clickable links while preventing XSS from other tags.
457
+ * Uses DOMPurify for robust sanitization against XSS attacks.
458
+ */
459
+ const escapeHtmlExceptAnchors = text => {
460
+ // Use DOMPurify to sanitize the text, allowing only anchor tags
461
+ // This is much more secure than regex-based parsing
462
+ const sanitized = DOMPurify__default["default"].sanitize(text, {
463
+ ALLOWED_TAGS: ['a'],
464
+ ALLOWED_ATTR: ['href', 'title', 'target', 'rel'],
465
+ // Block dangerous URL schemes
466
+ ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
467
+ // Prevent DOM clobbering
468
+ SANITIZE_DOM: true,
469
+ // Keep relative URLs
470
+ ALLOW_DATA_ATTR: false,
471
+ // Return a string, not a DOM node
472
+ RETURN_DOM: false,
473
+ RETURN_DOM_FRAGMENT: false
474
+ });
475
+ return sanitized;
476
+ };
452
477
  const serializeNode = node => {
453
478
  var _context, _context5, _context6;
454
479
  if (slate.Text.isText(node)) {
455
- let string = escapeHtml__default["default"](node.text);
480
+ let string = escapeHtmlExceptAnchors(node.text);
456
481
  if (node.bold) {
457
482
  string = "<strong>".concat(string, "</strong>");
458
483
  }
@@ -1913,7 +1938,7 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
1913
1938
  var RichTextEditorBody$1 = RichTextEditorBody;
1914
1939
 
1915
1940
  // NOTE: This string will be replaced on build time with the package version.
1916
- var version = "20.3.1";
1941
+ var version = "20.5.0";
1917
1942
 
1918
1943
  exports.Element = Element;
1919
1944
  exports.HiddenInput = HiddenInput$1;
@@ -22,6 +22,7 @@ import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-st
22
22
  import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
23
23
  import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
24
24
  import escapeHtml from 'escape-html';
25
+ import DOMPurify from 'dompurify';
25
26
  import { Editor, Element as Element$1, Transforms, Text, Range } from 'slate';
26
27
  import { jsx as jsx$1 } from 'slate-hyperscript';
27
28
  import parse from 'style-to-object';
@@ -410,10 +411,33 @@ function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _
410
411
  // more: https://docs.slatejs.org/concepts/12-typescript
411
412
  // example: https://github.com/ianstormtaylor/slate/blob/main/packages/slate-react/src/custom-types.ts
412
413
 
414
+ /**
415
+ * Escapes HTML but preserves anchor tags with sanitized attributes.
416
+ * This allows <a> tags to remain as clickable links while preventing XSS from other tags.
417
+ * Uses DOMPurify for robust sanitization against XSS attacks.
418
+ */
419
+ const escapeHtmlExceptAnchors = text => {
420
+ // Use DOMPurify to sanitize the text, allowing only anchor tags
421
+ // This is much more secure than regex-based parsing
422
+ const sanitized = DOMPurify.sanitize(text, {
423
+ ALLOWED_TAGS: ['a'],
424
+ ALLOWED_ATTR: ['href', 'title', 'target', 'rel'],
425
+ // Block dangerous URL schemes
426
+ ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
427
+ // Prevent DOM clobbering
428
+ SANITIZE_DOM: true,
429
+ // Keep relative URLs
430
+ ALLOW_DATA_ATTR: false,
431
+ // Return a string, not a DOM node
432
+ RETURN_DOM: false,
433
+ RETURN_DOM_FRAGMENT: false
434
+ });
435
+ return sanitized;
436
+ };
413
437
  const serializeNode = node => {
414
438
  var _context, _context5, _context6;
415
439
  if (Text.isText(node)) {
416
- let string = escapeHtml(node.text);
440
+ let string = escapeHtmlExceptAnchors(node.text);
417
441
  if (node.bold) {
418
442
  string = "<strong>".concat(string, "</strong>");
419
443
  }
@@ -1933,6 +1957,6 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
1933
1957
  var RichTextEditorBody$1 = RichTextEditorBody;
1934
1958
 
1935
1959
  // NOTE: This string will be replaced on build time with the package version.
1936
- var version = "20.3.1";
1960
+ var version = "20.5.0";
1937
1961
 
1938
1962
  export { Element, HiddenInput$1 as HiddenInput, Leaf, RichTextEditorBody$1 as RichTextBody, Softbreaker, focusEditor, html$1 as html, isBlockActive, isRichTextEmpty as isEmpty, isMarkActive, index as localized, resetEditor, toggleBlock, toggleMark, validSlateStateAdapter, version, withLinks };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@commercetools-uikit/rich-text-utils",
3
3
  "description": "Utilities for working with rich-text components.",
4
- "version": "20.3.1",
4
+ "version": "20.5.0",
5
5
  "bugs": "https://github.com/commercetools/ui-kit/issues",
6
6
  "repository": {
7
7
  "type": "git",
@@ -24,15 +24,17 @@
24
24
  "dependencies": {
25
25
  "@babel/runtime": "^7.20.13",
26
26
  "@babel/runtime-corejs3": "^7.20.13",
27
- "@commercetools-uikit/design-system": "20.3.1",
28
- "@commercetools-uikit/icons": "20.3.1",
29
- "@commercetools-uikit/input-utils": "20.3.1",
30
- "@commercetools-uikit/spacings-inline": "20.3.1",
31
- "@commercetools-uikit/tooltip": "20.3.1",
32
- "@commercetools-uikit/utils": "20.3.1",
27
+ "@commercetools-uikit/design-system": "20.5.0",
28
+ "@commercetools-uikit/icons": "20.5.0",
29
+ "@commercetools-uikit/input-utils": "20.5.0",
30
+ "@commercetools-uikit/spacings-inline": "20.5.0",
31
+ "@commercetools-uikit/tooltip": "20.5.0",
32
+ "@commercetools-uikit/utils": "20.5.0",
33
33
  "@emotion/react": "^11.10.5",
34
34
  "@emotion/styled": "^11.10.5",
35
+ "@types/dompurify": "^2.4.0",
35
36
  "@types/escape-html": "1.0.4",
37
+ "dompurify": "3.2.7",
36
38
  "downshift": "9.0.10",
37
39
  "escape-html": "1.0.3",
38
40
  "is-hotkey": "0.2.0",