@ape.swap/bonds-sdk 7.0.4 → 7.0.5

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.
@@ -1,23 +1,53 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
 
3
+ const TAG_WHITELIST = ['a', 'br', 'span']; // Allowed tags
4
+ const ATTR_WHITELIST = ['target', 'rel', 'style', 'href']; // Allowed attributes
5
+ const URL_PROTOCOL_WHITELIST = ['http:', 'https:', 'mailto:']; // Allowed href schemes
6
+ const STYLE_PROPERTY_WHITELIST = ['color']; // Allowed inline style properties
7
+ // Returns true only for URLs with an allowed scheme. The URL parser strips the whitespace and control
8
+ // characters browsers ignore, so obfuscated values like "java\tscript:" are caught too
9
+ function isSafeURL(value) {
10
+ try {
11
+ return URL_PROTOCOL_WHITELIST.includes(new URL(value, window.location.href).protocol);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ // Keeps only whitelisted style properties, so content can't overlay or restyle the host page
18
+ function sanitizeStyle(el) {
19
+ const { style } = el;
20
+ for (const property of Array.from(style)) {
21
+ if (!STYLE_PROPERTY_WHITELIST.includes(property))
22
+ style.removeProperty(property);
23
+ }
24
+ if (!style.length)
25
+ el.removeAttribute('style');
26
+ }
3
27
  // Custom HTML sanitizer
4
28
  function sanitizeHTML(html) {
5
- const tagWhitelist = ['a', 'br', 'span', 'img']; // Allowed tags
6
- const attrWhitelist = ['target', 'rel', 'style', 'href', 'src', 'alt']; // Allowed attributes
29
+ if (typeof window === 'undefined' || typeof DOMParser === 'undefined')
30
+ return '';
7
31
  const doc = new DOMParser().parseFromString(html, 'text/html');
8
32
  const elements = doc.body.querySelectorAll('*');
9
33
  for (const el of elements) {
10
34
  // Remove elements that are not in the whitelist
11
- if (!tagWhitelist.includes(el.tagName.toLowerCase())) {
35
+ if (!TAG_WHITELIST.includes(el.tagName.toLowerCase())) {
12
36
  el?.parentNode?.removeChild(el);
13
37
  continue;
14
38
  }
15
39
  // Loop through the element's attributes and remove those that are not in the whitelist
16
40
  Array.from(el.attributes).forEach((attr) => {
17
- if (!attrWhitelist.includes(attr.name.toLowerCase())) {
41
+ const name = attr.name.toLowerCase();
42
+ if (!ATTR_WHITELIST.includes(name) || (name === 'href' && !isSafeURL(attr.value))) {
18
43
  el.removeAttribute(attr.name);
19
44
  }
20
45
  });
46
+ if (el.hasAttribute('style'))
47
+ sanitizeStyle(el);
48
+ // Links opening a new tab must not get a handle on the host page (reverse tabnabbing)
49
+ if (el.hasAttribute('target'))
50
+ el.setAttribute('rel', 'noopener noreferrer');
21
51
  }
22
52
  return doc.body.innerHTML;
23
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/SafeHTMLComponent/index.tsx"],"sourcesContent":["import * as React from 'react'\n\n// Custom HTML sanitizer\nfunction sanitizeHTML(html: string) {\n const tagWhitelist = ['a', 'br', 'span', 'img'] // Allowed tags\n const attrWhitelist = ['target', 'rel', 'style', 'href', 'src', 'alt'] // Allowed attributes\n\n const doc = new DOMParser().parseFromString(html, 'text/html')\n const elements = doc.body.querySelectorAll('*')\n\n for (const el of elements) {\n // Remove elements that are not in the whitelist\n if (!tagWhitelist.includes(el.tagName.toLowerCase())) {\n el?.parentNode?.removeChild(el)\n continue\n }\n\n // Loop through the element's attributes and remove those that are not in the whitelist\n Array.from(el.attributes).forEach((attr) => {\n if (!attrWhitelist.includes(attr.name.toLowerCase())) {\n el.removeAttribute(attr.name)\n }\n })\n }\n\n return doc.body.innerHTML\n}\n\nconst SafeHTMLComponent = ({ html }: { html: string }) => {\n const sanitizedHTML = sanitizeHTML(html)\n\n return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />\n}\n\nexport default SafeHTMLComponent\n"],"names":["_jsx"],"mappings":";;AAEA;AACA,SAAS,YAAY,CAAC,IAAY,EAAA;AAChC,IAAA,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;AAC/C,IAAA,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;AAEtE,IAAA,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC;AAE/C,IAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;;AAEzB,QAAA,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE;AACpD,YAAA,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;YAC/B;QACF;;AAGA,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;AACzC,YAAA,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE;AACpD,gBAAA,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B;AACF,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS;AAC3B;AAEA,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,EAAoB,KAAI;AACvD,IAAA,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC;IAExC,OAAOA,GAAA,CAAA,KAAA,EAAA,EAAK,uBAAuB,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,EAAA,CAAI;AACpE;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/SafeHTMLComponent/index.tsx"],"sourcesContent":["import * as React from 'react'\n\nconst TAG_WHITELIST = ['a', 'br', 'span'] // Allowed tags\nconst ATTR_WHITELIST = ['target', 'rel', 'style', 'href'] // Allowed attributes\nconst URL_PROTOCOL_WHITELIST = ['http:', 'https:', 'mailto:'] // Allowed href schemes\nconst STYLE_PROPERTY_WHITELIST = ['color'] // Allowed inline style properties\n\n// Returns true only for URLs with an allowed scheme. The URL parser strips the whitespace and control\n// characters browsers ignore, so obfuscated values like \"java\\tscript:\" are caught too\nfunction isSafeURL(value: string) {\n try {\n return URL_PROTOCOL_WHITELIST.includes(new URL(value, window.location.href).protocol)\n } catch {\n return false\n }\n}\n\n// Keeps only whitelisted style properties, so content can't overlay or restyle the host page\nfunction sanitizeStyle(el: HTMLElement) {\n const { style } = el\n for (const property of Array.from(style)) {\n if (!STYLE_PROPERTY_WHITELIST.includes(property)) style.removeProperty(property)\n }\n if (!style.length) el.removeAttribute('style')\n}\n\n// Custom HTML sanitizer\nfunction sanitizeHTML(html: string) {\n if (typeof window === 'undefined' || typeof DOMParser === 'undefined') return ''\n\n const doc = new DOMParser().parseFromString(html, 'text/html')\n const elements = doc.body.querySelectorAll('*')\n\n for (const el of elements) {\n // Remove elements that are not in the whitelist\n if (!TAG_WHITELIST.includes(el.tagName.toLowerCase())) {\n el?.parentNode?.removeChild(el)\n continue\n }\n\n // Loop through the element's attributes and remove those that are not in the whitelist\n Array.from(el.attributes).forEach((attr) => {\n const name = attr.name.toLowerCase()\n if (!ATTR_WHITELIST.includes(name) || (name === 'href' && !isSafeURL(attr.value))) {\n el.removeAttribute(attr.name)\n }\n })\n\n if (el.hasAttribute('style')) sanitizeStyle(el as HTMLElement)\n\n // Links opening a new tab must not get a handle on the host page (reverse tabnabbing)\n if (el.hasAttribute('target')) el.setAttribute('rel', 'noopener noreferrer')\n }\n\n return doc.body.innerHTML\n}\n\nconst SafeHTMLComponent = ({ html }: { html: string }) => {\n const sanitizedHTML = sanitizeHTML(html)\n\n return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />\n}\n\nexport default SafeHTMLComponent\n"],"names":["_jsx"],"mappings":";;AAEA,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;AACzC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;AACzD,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;AAC7D,MAAM,wBAAwB,GAAG,CAAC,OAAO,CAAC,CAAA;AAE1C;AACA;AACA,SAAS,SAAS,CAAC,KAAa,EAAA;AAC9B,IAAA,IAAI;AACF,QAAA,OAAO,sBAAsB,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;IACvF;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,KAAK;IACd;AACF;AAEA;AACA,SAAS,aAAa,CAAC,EAAe,EAAA;AACpC,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE;IACpB,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACxC,QAAA,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAAE,YAAA,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC;IAClF;IACA,IAAI,CAAC,KAAK,CAAC,MAAM;AAAE,QAAA,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC;AAChD;AAEA;AACA,SAAS,YAAY,CAAC,IAAY,EAAA;IAChC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,SAAS,KAAK,WAAW;AAAE,QAAA,OAAO,EAAE;AAEhF,IAAA,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC;AAE/C,IAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;;AAEzB,QAAA,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE;AACrD,YAAA,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;YAC/B;QACF;;AAGA,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;YACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YACpC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;AACjF,gBAAA,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC;YAAE,aAAa,CAAC,EAAiB,CAAC;;AAG9D,QAAA,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC;AAAE,YAAA,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,qBAAqB,CAAC;IAC9E;AAEA,IAAA,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS;AAC3B;AAEA,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,EAAoB,KAAI;AACvD,IAAA,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC;IAExC,OAAOA,GAAA,CAAA,KAAA,EAAA,EAAK,uBAAuB,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,EAAA,CAAI;AACpE;;;;"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ape Bond SDK",
4
4
  "author": "Ape Bond",
5
5
  "license": "MIT",
6
- "version": "7.0.4",
6
+ "version": "7.0.5",
7
7
  "module": "dist/main.js",
8
8
  "type": "module",
9
9
  "types": "dist/main.d.ts",