@inboxsdk/core 2.1.33 → 2.1.34

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.
Files changed (23) hide show
  1. package/inboxsdk.js +137 -1567
  2. package/package.json +1 -1
  3. package/pageWorld.js +45 -1530
  4. package/src/common/html-to-text.d.ts +10 -22
  5. package/src/common/html-to-text.d.ts.map +1 -1
  6. package/src/common/removeHtmlTags.d.ts +25 -0
  7. package/src/common/removeHtmlTags.d.ts.map +1 -0
  8. package/src/inboxsdk-js/header.d.ts +1 -0
  9. package/src/inboxsdk-js/header.d.ts.map +1 -1
  10. package/src/injected-js/main.d.ts +1 -1
  11. package/src/injected-js/main.d.ts.map +1 -1
  12. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.d.ts +4 -1
  13. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.d.ts.map +1 -1
  14. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver.d.ts +13 -0
  15. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver.d.ts.map +1 -1
  16. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.d.ts +1 -0
  17. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.d.ts.map +1 -1
  18. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-sidebar-view/primary/add-to-icon-area.d.ts +1 -0
  19. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-sidebar-view/primary/add-to-icon-area.d.ts.map +1 -1
  20. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-collapsible-section-view.d.ts +1 -1
  21. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-collapsible-section-view.d.ts.map +1 -1
  22. package/src/platform-implementation-js/namespaces/global.d.ts +7 -1
  23. package/src/platform-implementation-js/namespaces/global.d.ts.map +1 -1
package/inboxsdk.js CHANGED
@@ -785,31 +785,62 @@ const get = function get(map, key) {
785
785
 
786
786
  /***/ }),
787
787
 
788
- /***/ 9865:
788
+ /***/ 7954:
789
789
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
790
790
 
791
791
  "use strict";
792
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
793
- /* harmony export */ "Z": () => (/* binding */ htmlToText)
794
- /* harmony export */ });
795
- /* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7856);
796
- /* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dompurify__WEBPACK_IMPORTED_MODULE_0__);
797
792
 
798
- const escapeHTMLPolicy = globalThis.trustedTypes?.createPolicy('inboxSdkEscapePolicy', {
799
- createHTML: string => (0,dompurify__WEBPACK_IMPORTED_MODULE_0__.sanitize)(string)
793
+ // EXPORTS
794
+ __webpack_require__.d(__webpack_exports__, {
795
+ "Z": () => (/* binding */ htmlToText)
796
+ });
797
+
798
+ ;// CONCATENATED MODULE: ./src/common/removeHtmlTags.ts
799
+ /**
800
+ * This function removes all HTML tags from a string.
801
+ * The resulting string may still contain HTML entities and not be suitable to display as plain text.
802
+ *
803
+ * This function's output will never contain `<` and therefore will never contain any HTML
804
+ * tags, so it's safe to use this on arbitrary input and assign the result to an element's
805
+ * innerHTML property.
806
+ *
807
+ * @see Use [htmlToText](./html-to-text.ts) instead if you want to convert HTML to
808
+ * unformatted text to display.
809
+ */
810
+ function removeHtmlTags(html) {
811
+ return html.replace(/<[^>]*>?/g, '');
812
+ }
813
+
814
+ /**
815
+ * This policy object is used to strip HTML tags from a string.
816
+ */
817
+ const removeHtmlTagsPolicy = globalThis.trustedTypes?.createPolicy('inboxSdk__removeHtmlTagsPolicy', {
818
+ createHTML(string) {
819
+ return removeHtmlTags(string);
820
+ }
800
821
  }) ?? {
801
822
  createHTML(string) {
802
- return (0,dompurify__WEBPACK_IMPORTED_MODULE_0__.sanitize)(string);
823
+ return removeHtmlTags(string);
803
824
  }
804
825
  };
826
+ ;// CONCATENATED MODULE: ./src/common/html-to-text.ts
827
+
805
828
 
806
829
  /**
807
- * Quick function for converting HTML with entities into text without
808
- * introducing an XSS vulnerability.
830
+ * Converts HTML to unformatted plain text.
831
+ * Works by stripping all HTML tags and converting entities to symbols.
832
+ * Safe to use on arbitrary input.
833
+ *
834
+ * Converts text like `String with <b>html</b> &amp; entities &lt;&gt;` to
835
+ * `String with html & entities <>`.
836
+ *
837
+ * This is *not* for creating "safe HTML" from user input to assign to
838
+ * an element's innerHTML. The result of this function should not be treated
839
+ * as HTML.
809
840
  */
810
841
  function htmlToText(html) {
811
842
  const div = document.createElement('div');
812
- div.innerHTML = escapeHTMLPolicy.createHTML(html);
843
+ div.innerHTML = removeHtmlTagsPolicy.createHTML(html);
813
844
  return div.textContent;
814
845
  }
815
846
 
@@ -844,7 +875,7 @@ function isElementVisible(el) {
844
875
 
845
876
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- SDK_VERSION is injected by webpack
846
877
  ///@ts-ignore
847
- const BUILD_VERSION = "2.1.33-1708967203035-4ab35005d4e5dc83";
878
+ const BUILD_VERSION = "2.1.34-1709323061294-288354aa384296d7";
848
879
  if (false) {}
849
880
 
850
881
  /***/ }),
@@ -1763,6 +1794,7 @@ const GmailElementGetter = {
1763
1794
  }
1764
1795
  return topAccountContainer.querySelectorAll('a[href*="https://plus"][href*="upgrade"]').length === 0;
1765
1796
  },
1797
+ /** @deprecated this doesn't include Gmail themes where the frame is dark and the body is not. Use Global.gmailTheme instead */
1766
1798
  isDarkTheme() {
1767
1799
  return document.body.classList.contains('inboxsdk__gmail_dark_theme');
1768
1800
  },
@@ -1806,7 +1838,7 @@ const GmailElementGetter = {
1806
1838
  /* harmony import */ var lodash_last__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_last__WEBPACK_IMPORTED_MODULE_1__);
1807
1839
  /* harmony import */ var transducers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1095);
1808
1840
  /* harmony import */ var transducers_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(transducers_js__WEBPACK_IMPORTED_MODULE_2__);
1809
- /* harmony import */ var _common_html_to_text__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9865);
1841
+ /* harmony import */ var _common_html_to_text__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7954);
1810
1842
  /* harmony import */ var _common_assert__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9817);
1811
1843
 
1812
1844
 
@@ -10558,7 +10590,7 @@ options.insert = htmlElement => {
10558
10590
  htmlElement.setAttribute('data-inboxsdk-version',
10559
10591
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- this is injected by webpack
10560
10592
  ///@ts-ignore
10561
- "2.1.33-1708967203035-4ab35005d4e5dc83");
10593
+ "2.1.34-1709323061294-288354aa384296d7");
10562
10594
  document.head.append(htmlElement);
10563
10595
  };
10564
10596
  options.domAPI = (styleDomAPI_default());
@@ -15288,7 +15320,7 @@ options.insert = htmlElement => {
15288
15320
  htmlElement.setAttribute('data-inboxsdk-version',
15289
15321
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- this is injected by webpack
15290
15322
  ///@ts-ignore
15291
- "2.1.33-1708967203035-4ab35005d4e5dc83");
15323
+ "2.1.34-1709323061294-288354aa384296d7");
15292
15324
  document.head.append(htmlElement);
15293
15325
  };
15294
15326
  options.domAPI = (styleDomAPI_default());
@@ -15332,7 +15364,9 @@ class GmailCollapsibleSectionView {
15332
15364
  #inboxDropdownButtonView = null;
15333
15365
  #dropdownViewController = null;
15334
15366
  #tableRowsUnmountResolution = null;
15335
- constructor(_driver, groupOrderHint, isSearch, isCollapsible) {
15367
+ #driver;
15368
+ constructor(driver, groupOrderHint, isSearch, isCollapsible) {
15369
+ this.#driver = driver;
15336
15370
  this.#isSearch = isSearch;
15337
15371
  this.#groupOrderHint = groupOrderHint;
15338
15372
  this.#isCollapsible = isCollapsible;
@@ -15369,6 +15403,11 @@ class GmailCollapsibleSectionView {
15369
15403
  const stoppedProperty = collapsibleSectionDescriptorProperty.takeUntilBy(this.#eventStream.filter(() => false).beforeEnd(() => null));
15370
15404
  stoppedProperty.onValue(x => this.#updateValues(x));
15371
15405
  stoppedProperty.take(1).onValue(() => this.#isReadyDeferred.resolve(this));
15406
+ this.#driver.gmailThemeStream.onValue(() => {
15407
+ if (Object.keys(this.#collapsibleSectionDescriptor).length) {
15408
+ this.#updateValues(this.#collapsibleSectionDescriptor);
15409
+ }
15410
+ });
15372
15411
  }
15373
15412
  setCollapsed(value) {
15374
15413
  if (!this.#isCollapsible) {
@@ -17165,7 +17204,9 @@ var events = __webpack_require__(7187);
17165
17204
 
17166
17205
 
17167
17206
 
17168
- const RGB_REGEX = /^rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+)\s*\)/;
17207
+
17208
+ /** should handle rgb and rgba */
17209
+ const RGB_REGEX = /^rgba?\s*\(\s*(\d+),\s*(\d+),\s*(\d+)\s*(,\s*(0\.)?\d+)?\)/;
17169
17210
  function getDensity() {
17170
17211
  const navItemElement = document.querySelector('.aim');
17171
17212
  if (!navItemElement) {
@@ -17192,9 +17233,23 @@ async function checkForDarkThemeSafe() {
17192
17233
  }
17193
17234
  throw e;
17194
17235
  }
17195
- return isDarkTheme();
17236
+ return isFrameDarkTheme();
17196
17237
  }
17197
- function isDarkTheme() {
17238
+ function extractRgbColor(colorString) {
17239
+ const match = RGB_REGEX.exec(colorString);
17240
+ if (!match) {
17241
+ lib_logger/* default.error */.Z.error(new Error('Failed to read color string'), {
17242
+ colorString
17243
+ });
17244
+ return;
17245
+ }
17246
+ return {
17247
+ r: +match[1],
17248
+ g: +match[2],
17249
+ b: +match[3]
17250
+ };
17251
+ }
17252
+ function isFrameDarkTheme() {
17198
17253
  // get the color of the left-nav-menu entries to determine whether Gmail is
17199
17254
  // in dark theme mode.
17200
17255
  const navItem = getNavItem();
@@ -17203,28 +17258,27 @@ function isDarkTheme() {
17203
17258
  return false;
17204
17259
  }
17205
17260
  const colorString = getComputedStyle(navItem).getPropertyValue('color');
17206
- const colorMatch = RGB_REGEX.exec(colorString);
17207
- if (!colorMatch) {
17208
- lib_logger/* default.error */.Z.error(new Error('Failed to read color string'), {
17209
- colorString
17210
- });
17261
+ const {
17262
+ r
17263
+ } = extractRgbColor(colorString) ?? {};
17264
+ if (r === undefined) {
17211
17265
  return false;
17212
17266
  }
17213
- const r = +colorMatch[1],
17214
- g = +colorMatch[2],
17215
- b = +colorMatch[3];
17216
- // rgb(32, 33, 36) is the default color of nav items in Material Gmail
17217
- if (r === 32 && g === 33 && b === 36) {
17267
+ return r > 128;
17268
+ }
17269
+ function isBodyDarkTheme() {
17270
+ const bodyEl = document.querySelector('.bkK > .nH');
17271
+ if (!bodyEl) {
17218
17272
  return false;
17219
17273
  }
17220
- if (r !== g || r !== b) {
17221
- lib_logger/* default.error */.Z.error(new Error('Nav item color not grayscale'), {
17222
- r,
17223
- g,
17224
- b
17225
- });
17274
+ const bgColor = getComputedStyle(bodyEl).backgroundColor;
17275
+ const {
17276
+ r
17277
+ } = extractRgbColor(bgColor) ?? {};
17278
+ if (r != null) {
17279
+ return r < 128;
17226
17280
  }
17227
- return r > 128;
17281
+ return false;
17228
17282
  }
17229
17283
  const stylesStream = kefir_bus_default()();
17230
17284
  async function trackGmailStyles() {
@@ -17243,19 +17297,28 @@ async function trackGmailStyles() {
17243
17297
  currentDensity = newDensity;
17244
17298
  document.body.classList.add('inboxsdk__gmail_density_' + currentDensity);
17245
17299
  }
17246
- const newDarkTheme = isDarkTheme();
17300
+ const newDarkTheme = isFrameDarkTheme();
17247
17301
  if (currentDarkTheme !== newDarkTheme) {
17248
17302
  currentDarkTheme = newDarkTheme;
17249
17303
  if (currentDarkTheme) {
17250
- document.body.classList.add('inboxsdk__gmail_dark_theme');
17304
+ document.body.classList.add("inboxsdk__gmail_dark_theme");
17251
17305
  } else {
17252
- document.body.classList.remove('inboxsdk__gmail_dark_theme');
17306
+ document.body.classList.remove("inboxsdk__gmail_dark_theme");
17253
17307
  }
17254
- stylesStream.emit({
17255
- type: 'theme',
17256
- isDarkMode: newDarkTheme
17257
- });
17258
17308
  }
17309
+ const newBodyDarkTheme = isBodyDarkTheme();
17310
+ if (newBodyDarkTheme) {
17311
+ document.body.classList.add("inboxsdk__gmail_dark_body_theme");
17312
+ } else {
17313
+ document.body.classList.remove("inboxsdk__gmail_dark_body_theme");
17314
+ }
17315
+ stylesStream.emit({
17316
+ type: 'theme',
17317
+ isDarkMode: {
17318
+ frame: currentDarkTheme,
17319
+ body: newBodyDarkTheme
17320
+ }
17321
+ });
17259
17322
  }
17260
17323
  try {
17261
17324
  await (0,wait_for/* default */.Z)(() => document.querySelector('.TO .TN') && document.querySelector(navItemSelector));
@@ -18513,10 +18576,11 @@ var content_panel_view = __webpack_require__(1346);
18513
18576
 
18514
18577
  class Global {
18515
18578
  #driver;
18516
- #piOpts;
18517
- constructor(appId, driver, piOpts) {
18579
+ constructor(appId, driver, _piOpts) {
18518
18580
  this.#driver = driver;
18519
- this.#piOpts = piOpts;
18581
+ }
18582
+ get gmailTheme() {
18583
+ return this.#driver.gmailTheme;
18520
18584
  }
18521
18585
  async addSidebarContentPanel(descriptor) {
18522
18586
  // kefirCast casts to Observable<any, any> which is not what we want
@@ -19346,7 +19410,7 @@ mole_view_module_options.insert = htmlElement => {
19346
19410
  htmlElement.setAttribute('data-inboxsdk-version',
19347
19411
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- this is injected by webpack
19348
19412
  ///@ts-ignore
19349
- "2.1.33-1708967203035-4ab35005d4e5dc83");
19413
+ "2.1.34-1709323061294-288354aa384296d7");
19350
19414
  document.head.append(htmlElement);
19351
19415
  };
19352
19416
  mole_view_module_options.domAPI = (styleDomAPI_default());
@@ -20217,8 +20281,8 @@ function encodeDraftUrlId(syncThreadId, syncMessageId) {
20217
20281
  }
20218
20282
  // EXTERNAL MODULE: ./src/platform-implementation-js/driver-common/getOriginalMessagePage.ts
20219
20283
  var getOriginalMessagePage = __webpack_require__(8102);
20220
- // EXTERNAL MODULE: ./src/common/html-to-text.ts
20221
- var html_to_text = __webpack_require__(9865);
20284
+ // EXTERNAL MODULE: ./src/common/html-to-text.ts + 1 modules
20285
+ var html_to_text = __webpack_require__(7954);
20222
20286
  ;// CONCATENATED MODULE: ./src/platform-implementation-js/dom-driver/gmail/gmail-driver/get-rfc-message-id-for-gmail-message-id.ts
20223
20287
 
20224
20288
 
@@ -23423,6 +23487,12 @@ function parseListPeopleByKnownIdResponse(data) {
23423
23487
  * @internal
23424
23488
  */
23425
23489
  class GmailDriver {
23490
+ #gmailTheme = {
23491
+ isDarkMode: {
23492
+ frame: false,
23493
+ body: false
23494
+ }
23495
+ };
23426
23496
  #appId;
23427
23497
  #logger;
23428
23498
  #opts;
@@ -23892,6 +23962,22 @@ class GmailDriver {
23892
23962
  this.getKeyboardShortcutHelpModifier().delete(keyboardShortcutHandle);
23893
23963
  });
23894
23964
  }
23965
+ get gmailTheme() {
23966
+ return this.#gmailTheme;
23967
+ }
23968
+
23969
+ /**
23970
+ * Listen for if Gmail changes its theme (dark, light, or frame dark / body light mode).
23971
+ */
23972
+ get gmailThemeStream() {
23973
+ return stylesStream.flatMap(event => {
23974
+ if (event.type !== 'theme') {
23975
+ return kefir_esm.never();
23976
+ }
23977
+ this.#gmailTheme.isDarkMode = event.isDarkMode;
23978
+ return kefir_esm.constant(event.isDarkMode);
23979
+ });
23980
+ }
23895
23981
  #setupEventStreams() {
23896
23982
  var result = makeXhrInterceptor();
23897
23983
  this.#xhrInterceptorStream = result.xhrInterceptStream.takeUntilBy(this.#stopper);
@@ -32781,7 +32867,7 @@ module.exports["default"] = exports.default;
32781
32867
 
32782
32868
  var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
32783
32869
  // Module
32784
- ___CSS_LOADER_EXPORT___.push([module.id, ".Wn{--inboxsdk-title-color:rgb(0 0 0 / 87%);--inboxsdk-subtitle-color:rgb(0 0 0 / 54%)}.inboxsdk__gmail_dark_theme .Wn{--inboxsdk-title-color:rgb(255 255 255);--inboxsdk-subtitle-color:rgb(255 255 255 / 70%)}.Wn.inboxsdk__ZWrBCcqtIqrDEdUtPOrg{color:var(--inboxsdk-title-color)}.Wn .inboxsdk__WFNlIHJZA6zYVSDGWS2K{color:var(--inboxsdk-subtitle-color)}.xY.inboxsdk__HBTr58WKm0EhmpKhN5k1{max-width:calc(168px + (30px*2));flex-basis:calc(168px + (30px*2))}.inboxsdk__HBTr58WKm0EhmpKhN5k1 span{text-overflow:ellipsis;display:block;overflow:hidden}.inboxsdk__kN8mmVlzZVbzIS_awdJ_,.inboxsdk__Va73Osg6o8dIKLvkvywn,.inboxsdk__oxF6Ne2PQsND932WpK9J,.inboxsdk__N8BEpD1pdj535bJKkz7u,.inboxsdk__rusCS8I3RyomwIQUtkef{content:\"\"}.inboxsdk__POtXLY2WRLq21pk7OxRg b{font-weight:700}.inboxsdk__N8BEpD1pdj535bJKkz7u.inboxsdk__POtXLY2WRLq21pk7OxRg{color:rgb(95 99 104)}.inboxsdk__gmail_dark_theme .inboxsdk__N8BEpD1pdj535bJKkz7u.inboxsdk__POtXLY2WRLq21pk7OxRg{color:rgb(255 255 255/50%)}", ""]);
32870
+ ___CSS_LOADER_EXPORT___.push([module.id, ".Wn{--inboxsdk-title-color:rgb(0 0 0 / 87%);--inboxsdk-subtitle-color:rgb(0 0 0 / 54%)}.inboxsdk__gmail_dark_body_theme .Wn{--inboxsdk-title-color:rgb(255 255 255);--inboxsdk-subtitle-color:rgb(255 255 255 / 70%)}.Wn.inboxsdk__ZWrBCcqtIqrDEdUtPOrg{color:var(--inboxsdk-title-color)}.Wn .inboxsdk__WFNlIHJZA6zYVSDGWS2K{color:var(--inboxsdk-subtitle-color)}.xY.inboxsdk__HBTr58WKm0EhmpKhN5k1{max-width:calc(168px + (30px*2));flex-basis:calc(168px + (30px*2))}.inboxsdk__HBTr58WKm0EhmpKhN5k1 span{text-overflow:ellipsis;display:block;overflow:hidden}.inboxsdk__kN8mmVlzZVbzIS_awdJ_,.inboxsdk__Va73Osg6o8dIKLvkvywn,.inboxsdk__oxF6Ne2PQsND932WpK9J,.inboxsdk__N8BEpD1pdj535bJKkz7u,.inboxsdk__rusCS8I3RyomwIQUtkef{content:\"\"}.inboxsdk__POtXLY2WRLq21pk7OxRg b{font-weight:700}.inboxsdk__N8BEpD1pdj535bJKkz7u.inboxsdk__POtXLY2WRLq21pk7OxRg{color:rgb(95 99 104)}.inboxsdk__gmail_dark_body_theme .inboxsdk__N8BEpD1pdj535bJKkz7u.inboxsdk__POtXLY2WRLq21pk7OxRg{color:rgb(255 255 255/50%)}", ""]);
32785
32871
  // Exports
32786
32872
  var title = "inboxsdk__ZWrBCcqtIqrDEdUtPOrg";
32787
32873
  var subtitle = "inboxsdk__WFNlIHJZA6zYVSDGWS2K";
@@ -37907,1522 +37993,6 @@ var __WEBPACK_AMD_DEFINE_RESULT__;;(function (globalScope) {
37907
37993
  })(this);
37908
37994
 
37909
37995
 
37910
- /***/ }),
37911
-
37912
- /***/ 7856:
37913
- /***/ (function(module) {
37914
-
37915
- /*! @license DOMPurify 3.0.8 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.8/LICENSE */
37916
-
37917
- (function (global, factory) {
37918
- true ? module.exports = factory() :
37919
- 0;
37920
- })(this, (function () { 'use strict';
37921
-
37922
- const {
37923
- entries,
37924
- setPrototypeOf,
37925
- isFrozen,
37926
- getPrototypeOf,
37927
- getOwnPropertyDescriptor
37928
- } = Object;
37929
- let {
37930
- freeze,
37931
- seal,
37932
- create
37933
- } = Object; // eslint-disable-line import/no-mutable-exports
37934
- let {
37935
- apply,
37936
- construct
37937
- } = typeof Reflect !== 'undefined' && Reflect;
37938
- if (!freeze) {
37939
- freeze = function freeze(x) {
37940
- return x;
37941
- };
37942
- }
37943
- if (!seal) {
37944
- seal = function seal(x) {
37945
- return x;
37946
- };
37947
- }
37948
- if (!apply) {
37949
- apply = function apply(fun, thisValue, args) {
37950
- return fun.apply(thisValue, args);
37951
- };
37952
- }
37953
- if (!construct) {
37954
- construct = function construct(Func, args) {
37955
- return new Func(...args);
37956
- };
37957
- }
37958
- const arrayForEach = unapply(Array.prototype.forEach);
37959
- const arrayPop = unapply(Array.prototype.pop);
37960
- const arrayPush = unapply(Array.prototype.push);
37961
- const stringToLowerCase = unapply(String.prototype.toLowerCase);
37962
- const stringToString = unapply(String.prototype.toString);
37963
- const stringMatch = unapply(String.prototype.match);
37964
- const stringReplace = unapply(String.prototype.replace);
37965
- const stringIndexOf = unapply(String.prototype.indexOf);
37966
- const stringTrim = unapply(String.prototype.trim);
37967
- const regExpTest = unapply(RegExp.prototype.test);
37968
- const typeErrorCreate = unconstruct(TypeError);
37969
-
37970
- /**
37971
- * Creates a new function that calls the given function with a specified thisArg and arguments.
37972
- *
37973
- * @param {Function} func - The function to be wrapped and called.
37974
- * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.
37975
- */
37976
- function unapply(func) {
37977
- return function (thisArg) {
37978
- for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
37979
- args[_key - 1] = arguments[_key];
37980
- }
37981
- return apply(func, thisArg, args);
37982
- };
37983
- }
37984
-
37985
- /**
37986
- * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
37987
- *
37988
- * @param {Function} func - The constructor function to be wrapped and called.
37989
- * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.
37990
- */
37991
- function unconstruct(func) {
37992
- return function () {
37993
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
37994
- args[_key2] = arguments[_key2];
37995
- }
37996
- return construct(func, args);
37997
- };
37998
- }
37999
-
38000
- /**
38001
- * Add properties to a lookup table
38002
- *
38003
- * @param {Object} set - The set to which elements will be added.
38004
- * @param {Array} array - The array containing elements to be added to the set.
38005
- * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.
38006
- * @returns {Object} The modified set with added elements.
38007
- */
38008
- function addToSet(set, array) {
38009
- let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
38010
- if (setPrototypeOf) {
38011
- // Make 'in' and truthy checks like Boolean(set.constructor)
38012
- // independent of any properties defined on Object.prototype.
38013
- // Prevent prototype setters from intercepting set as a this value.
38014
- setPrototypeOf(set, null);
38015
- }
38016
- let l = array.length;
38017
- while (l--) {
38018
- let element = array[l];
38019
- if (typeof element === 'string') {
38020
- const lcElement = transformCaseFunc(element);
38021
- if (lcElement !== element) {
38022
- // Config presets (e.g. tags.js, attrs.js) are immutable.
38023
- if (!isFrozen(array)) {
38024
- array[l] = lcElement;
38025
- }
38026
- element = lcElement;
38027
- }
38028
- }
38029
- set[element] = true;
38030
- }
38031
- return set;
38032
- }
38033
-
38034
- /**
38035
- * Clean up an array to harden against CSPP
38036
- *
38037
- * @param {Array} array - The array to be cleaned.
38038
- * @returns {Array} The cleaned version of the array
38039
- */
38040
- function cleanArray(array) {
38041
- for (let index = 0; index < array.length; index++) {
38042
- if (getOwnPropertyDescriptor(array, index) === undefined) {
38043
- array[index] = null;
38044
- }
38045
- }
38046
- return array;
38047
- }
38048
-
38049
- /**
38050
- * Shallow clone an object
38051
- *
38052
- * @param {Object} object - The object to be cloned.
38053
- * @returns {Object} A new object that copies the original.
38054
- */
38055
- function clone(object) {
38056
- const newObject = create(null);
38057
- for (const [property, value] of entries(object)) {
38058
- if (getOwnPropertyDescriptor(object, property) !== undefined) {
38059
- if (Array.isArray(value)) {
38060
- newObject[property] = cleanArray(value);
38061
- } else if (value && typeof value === 'object' && value.constructor === Object) {
38062
- newObject[property] = clone(value);
38063
- } else {
38064
- newObject[property] = value;
38065
- }
38066
- }
38067
- }
38068
- return newObject;
38069
- }
38070
-
38071
- /**
38072
- * This method automatically checks if the prop is function or getter and behaves accordingly.
38073
- *
38074
- * @param {Object} object - The object to look up the getter function in its prototype chain.
38075
- * @param {String} prop - The property name for which to find the getter function.
38076
- * @returns {Function} The getter function found in the prototype chain or a fallback function.
38077
- */
38078
- function lookupGetter(object, prop) {
38079
- while (object !== null) {
38080
- const desc = getOwnPropertyDescriptor(object, prop);
38081
- if (desc) {
38082
- if (desc.get) {
38083
- return unapply(desc.get);
38084
- }
38085
- if (typeof desc.value === 'function') {
38086
- return unapply(desc.value);
38087
- }
38088
- }
38089
- object = getPrototypeOf(object);
38090
- }
38091
- function fallbackValue(element) {
38092
- console.warn('fallback value for', element);
38093
- return null;
38094
- }
38095
- return fallbackValue;
38096
- }
38097
-
38098
- const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
38099
-
38100
- // SVG
38101
- const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
38102
- const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
38103
-
38104
- // List of SVG elements that are disallowed by default.
38105
- // We still need to know them so that we can do namespace
38106
- // checks properly in case one wants to add them to
38107
- // allow-list.
38108
- const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
38109
- const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
38110
-
38111
- // Similarly to SVG, we want to know all MathML elements,
38112
- // even those that we disallow by default.
38113
- const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
38114
- const text = freeze(['#text']);
38115
-
38116
- const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
38117
- const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
38118
- const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
38119
- const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
38120
-
38121
- // eslint-disable-next-line unicorn/better-regex
38122
- const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
38123
- const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
38124
- const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
38125
- const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
38126
- const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
38127
- const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
38128
- );
38129
-
38130
- const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
38131
- const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
38132
- );
38133
-
38134
- const DOCTYPE_NAME = seal(/^html$/i);
38135
-
38136
- var EXPRESSIONS = /*#__PURE__*/Object.freeze({
38137
- __proto__: null,
38138
- MUSTACHE_EXPR: MUSTACHE_EXPR,
38139
- ERB_EXPR: ERB_EXPR,
38140
- TMPLIT_EXPR: TMPLIT_EXPR,
38141
- DATA_ATTR: DATA_ATTR,
38142
- ARIA_ATTR: ARIA_ATTR,
38143
- IS_ALLOWED_URI: IS_ALLOWED_URI,
38144
- IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
38145
- ATTR_WHITESPACE: ATTR_WHITESPACE,
38146
- DOCTYPE_NAME: DOCTYPE_NAME
38147
- });
38148
-
38149
- const getGlobal = function getGlobal() {
38150
- return typeof window === 'undefined' ? null : window;
38151
- };
38152
-
38153
- /**
38154
- * Creates a no-op policy for internal use only.
38155
- * Don't export this function outside this module!
38156
- * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.
38157
- * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
38158
- * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types
38159
- * are not supported or creating the policy failed).
38160
- */
38161
- const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
38162
- if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
38163
- return null;
38164
- }
38165
-
38166
- // Allow the callers to control the unique policy name
38167
- // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
38168
- // Policy creation with duplicate names throws in Trusted Types.
38169
- let suffix = null;
38170
- const ATTR_NAME = 'data-tt-policy-suffix';
38171
- if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
38172
- suffix = purifyHostElement.getAttribute(ATTR_NAME);
38173
- }
38174
- const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
38175
- try {
38176
- return trustedTypes.createPolicy(policyName, {
38177
- createHTML(html) {
38178
- return html;
38179
- },
38180
- createScriptURL(scriptUrl) {
38181
- return scriptUrl;
38182
- }
38183
- });
38184
- } catch (_) {
38185
- // Policy creation failed (most likely another DOMPurify script has
38186
- // already run). Skip creating the policy, as this will only cause errors
38187
- // if TT are enforced.
38188
- console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
38189
- return null;
38190
- }
38191
- };
38192
- function createDOMPurify() {
38193
- let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
38194
- const DOMPurify = root => createDOMPurify(root);
38195
-
38196
- /**
38197
- * Version label, exposed for easier checks
38198
- * if DOMPurify is up to date or not
38199
- */
38200
- DOMPurify.version = '3.0.8';
38201
-
38202
- /**
38203
- * Array of elements that DOMPurify removed during sanitation.
38204
- * Empty if nothing was removed.
38205
- */
38206
- DOMPurify.removed = [];
38207
- if (!window || !window.document || window.document.nodeType !== 9) {
38208
- // Not running in a browser, provide a factory function
38209
- // so that you can pass your own Window
38210
- DOMPurify.isSupported = false;
38211
- return DOMPurify;
38212
- }
38213
- let {
38214
- document
38215
- } = window;
38216
- const originalDocument = document;
38217
- const currentScript = originalDocument.currentScript;
38218
- const {
38219
- DocumentFragment,
38220
- HTMLTemplateElement,
38221
- Node,
38222
- Element,
38223
- NodeFilter,
38224
- NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
38225
- HTMLFormElement,
38226
- DOMParser,
38227
- trustedTypes
38228
- } = window;
38229
- const ElementPrototype = Element.prototype;
38230
- const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
38231
- const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
38232
- const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
38233
- const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
38234
-
38235
- // As per issue #47, the web-components registry is inherited by a
38236
- // new document created via createHTMLDocument. As per the spec
38237
- // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
38238
- // a new empty registry is used when creating a template contents owner
38239
- // document, so we use that as our parent document to ensure nothing
38240
- // is inherited.
38241
- if (typeof HTMLTemplateElement === 'function') {
38242
- const template = document.createElement('template');
38243
- if (template.content && template.content.ownerDocument) {
38244
- document = template.content.ownerDocument;
38245
- }
38246
- }
38247
- let trustedTypesPolicy;
38248
- let emptyHTML = '';
38249
- const {
38250
- implementation,
38251
- createNodeIterator,
38252
- createDocumentFragment,
38253
- getElementsByTagName
38254
- } = document;
38255
- const {
38256
- importNode
38257
- } = originalDocument;
38258
- let hooks = {};
38259
-
38260
- /**
38261
- * Expose whether this browser supports running the full DOMPurify.
38262
- */
38263
- DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
38264
- const {
38265
- MUSTACHE_EXPR,
38266
- ERB_EXPR,
38267
- TMPLIT_EXPR,
38268
- DATA_ATTR,
38269
- ARIA_ATTR,
38270
- IS_SCRIPT_OR_DATA,
38271
- ATTR_WHITESPACE
38272
- } = EXPRESSIONS;
38273
- let {
38274
- IS_ALLOWED_URI: IS_ALLOWED_URI$1
38275
- } = EXPRESSIONS;
38276
-
38277
- /**
38278
- * We consider the elements and attributes below to be safe. Ideally
38279
- * don't add any new ones but feel free to remove unwanted ones.
38280
- */
38281
-
38282
- /* allowed element names */
38283
- let ALLOWED_TAGS = null;
38284
- const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
38285
-
38286
- /* Allowed attribute names */
38287
- let ALLOWED_ATTR = null;
38288
- const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
38289
-
38290
- /*
38291
- * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
38292
- * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
38293
- * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
38294
- * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
38295
- */
38296
- let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
38297
- tagNameCheck: {
38298
- writable: true,
38299
- configurable: false,
38300
- enumerable: true,
38301
- value: null
38302
- },
38303
- attributeNameCheck: {
38304
- writable: true,
38305
- configurable: false,
38306
- enumerable: true,
38307
- value: null
38308
- },
38309
- allowCustomizedBuiltInElements: {
38310
- writable: true,
38311
- configurable: false,
38312
- enumerable: true,
38313
- value: false
38314
- }
38315
- }));
38316
-
38317
- /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
38318
- let FORBID_TAGS = null;
38319
-
38320
- /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
38321
- let FORBID_ATTR = null;
38322
-
38323
- /* Decide if ARIA attributes are okay */
38324
- let ALLOW_ARIA_ATTR = true;
38325
-
38326
- /* Decide if custom data attributes are okay */
38327
- let ALLOW_DATA_ATTR = true;
38328
-
38329
- /* Decide if unknown protocols are okay */
38330
- let ALLOW_UNKNOWN_PROTOCOLS = false;
38331
-
38332
- /* Decide if self-closing tags in attributes are allowed.
38333
- * Usually removed due to a mXSS issue in jQuery 3.0 */
38334
- let ALLOW_SELF_CLOSE_IN_ATTR = true;
38335
-
38336
- /* Output should be safe for common template engines.
38337
- * This means, DOMPurify removes data attributes, mustaches and ERB
38338
- */
38339
- let SAFE_FOR_TEMPLATES = false;
38340
-
38341
- /* Decide if document with <html>... should be returned */
38342
- let WHOLE_DOCUMENT = false;
38343
-
38344
- /* Track whether config is already set on this instance of DOMPurify. */
38345
- let SET_CONFIG = false;
38346
-
38347
- /* Decide if all elements (e.g. style, script) must be children of
38348
- * document.body. By default, browsers might move them to document.head */
38349
- let FORCE_BODY = false;
38350
-
38351
- /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
38352
- * string (or a TrustedHTML object if Trusted Types are supported).
38353
- * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
38354
- */
38355
- let RETURN_DOM = false;
38356
-
38357
- /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
38358
- * string (or a TrustedHTML object if Trusted Types are supported) */
38359
- let RETURN_DOM_FRAGMENT = false;
38360
-
38361
- /* Try to return a Trusted Type object instead of a string, return a string in
38362
- * case Trusted Types are not supported */
38363
- let RETURN_TRUSTED_TYPE = false;
38364
-
38365
- /* Output should be free from DOM clobbering attacks?
38366
- * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
38367
- */
38368
- let SANITIZE_DOM = true;
38369
-
38370
- /* Achieve full DOM Clobbering protection by isolating the namespace of named
38371
- * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
38372
- *
38373
- * HTML/DOM spec rules that enable DOM Clobbering:
38374
- * - Named Access on Window (§7.3.3)
38375
- * - DOM Tree Accessors (§3.1.5)
38376
- * - Form Element Parent-Child Relations (§4.10.3)
38377
- * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
38378
- * - HTMLCollection (§4.2.10.2)
38379
- *
38380
- * Namespace isolation is implemented by prefixing `id` and `name` attributes
38381
- * with a constant string, i.e., `user-content-`
38382
- */
38383
- let SANITIZE_NAMED_PROPS = false;
38384
- const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
38385
-
38386
- /* Keep element content when removing element? */
38387
- let KEEP_CONTENT = true;
38388
-
38389
- /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
38390
- * of importing it into a new Document and returning a sanitized copy */
38391
- let IN_PLACE = false;
38392
-
38393
- /* Allow usage of profiles like html, svg and mathMl */
38394
- let USE_PROFILES = {};
38395
-
38396
- /* Tags to ignore content of when KEEP_CONTENT is true */
38397
- let FORBID_CONTENTS = null;
38398
- const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
38399
-
38400
- /* Tags that are safe for data: URIs */
38401
- let DATA_URI_TAGS = null;
38402
- const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
38403
-
38404
- /* Attributes safe for values like "javascript:" */
38405
- let URI_SAFE_ATTRIBUTES = null;
38406
- const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
38407
- const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
38408
- const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
38409
- const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
38410
- /* Document namespace */
38411
- let NAMESPACE = HTML_NAMESPACE;
38412
- let IS_EMPTY_INPUT = false;
38413
-
38414
- /* Allowed XHTML+XML namespaces */
38415
- let ALLOWED_NAMESPACES = null;
38416
- const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
38417
-
38418
- /* Parsing of strict XHTML documents */
38419
- let PARSER_MEDIA_TYPE = null;
38420
- const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
38421
- const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
38422
- let transformCaseFunc = null;
38423
-
38424
- /* Keep a reference to config to pass to hooks */
38425
- let CONFIG = null;
38426
-
38427
- /* Ideally, do not touch anything below this line */
38428
- /* ______________________________________________ */
38429
-
38430
- const formElement = document.createElement('form');
38431
- const isRegexOrFunction = function isRegexOrFunction(testValue) {
38432
- return testValue instanceof RegExp || testValue instanceof Function;
38433
- };
38434
-
38435
- /**
38436
- * _parseConfig
38437
- *
38438
- * @param {Object} cfg optional config literal
38439
- */
38440
- // eslint-disable-next-line complexity
38441
- const _parseConfig = function _parseConfig() {
38442
- let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
38443
- if (CONFIG && CONFIG === cfg) {
38444
- return;
38445
- }
38446
-
38447
- /* Shield configuration object from tampering */
38448
- if (!cfg || typeof cfg !== 'object') {
38449
- cfg = {};
38450
- }
38451
-
38452
- /* Shield configuration object from prototype pollution */
38453
- cfg = clone(cfg);
38454
- PARSER_MEDIA_TYPE =
38455
- // eslint-disable-next-line unicorn/prefer-includes
38456
- SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
38457
-
38458
- // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
38459
- transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
38460
-
38461
- /* Set configuration parameters */
38462
- ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
38463
- ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
38464
- ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
38465
- URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
38466
- // eslint-disable-line indent
38467
- cfg.ADD_URI_SAFE_ATTR,
38468
- // eslint-disable-line indent
38469
- transformCaseFunc // eslint-disable-line indent
38470
- ) // eslint-disable-line indent
38471
- : DEFAULT_URI_SAFE_ATTRIBUTES;
38472
- DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
38473
- // eslint-disable-line indent
38474
- cfg.ADD_DATA_URI_TAGS,
38475
- // eslint-disable-line indent
38476
- transformCaseFunc // eslint-disable-line indent
38477
- ) // eslint-disable-line indent
38478
- : DEFAULT_DATA_URI_TAGS;
38479
- FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
38480
- FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
38481
- FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
38482
- USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
38483
- ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
38484
- ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
38485
- ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
38486
- ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
38487
- SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
38488
- WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
38489
- RETURN_DOM = cfg.RETURN_DOM || false; // Default false
38490
- RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
38491
- RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
38492
- FORCE_BODY = cfg.FORCE_BODY || false; // Default false
38493
- SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
38494
- SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
38495
- KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
38496
- IN_PLACE = cfg.IN_PLACE || false; // Default false
38497
- IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
38498
- NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
38499
- CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
38500
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
38501
- CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
38502
- }
38503
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
38504
- CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
38505
- }
38506
- if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
38507
- CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
38508
- }
38509
- if (SAFE_FOR_TEMPLATES) {
38510
- ALLOW_DATA_ATTR = false;
38511
- }
38512
- if (RETURN_DOM_FRAGMENT) {
38513
- RETURN_DOM = true;
38514
- }
38515
-
38516
- /* Parse profile info */
38517
- if (USE_PROFILES) {
38518
- ALLOWED_TAGS = addToSet({}, text);
38519
- ALLOWED_ATTR = [];
38520
- if (USE_PROFILES.html === true) {
38521
- addToSet(ALLOWED_TAGS, html$1);
38522
- addToSet(ALLOWED_ATTR, html);
38523
- }
38524
- if (USE_PROFILES.svg === true) {
38525
- addToSet(ALLOWED_TAGS, svg$1);
38526
- addToSet(ALLOWED_ATTR, svg);
38527
- addToSet(ALLOWED_ATTR, xml);
38528
- }
38529
- if (USE_PROFILES.svgFilters === true) {
38530
- addToSet(ALLOWED_TAGS, svgFilters);
38531
- addToSet(ALLOWED_ATTR, svg);
38532
- addToSet(ALLOWED_ATTR, xml);
38533
- }
38534
- if (USE_PROFILES.mathMl === true) {
38535
- addToSet(ALLOWED_TAGS, mathMl$1);
38536
- addToSet(ALLOWED_ATTR, mathMl);
38537
- addToSet(ALLOWED_ATTR, xml);
38538
- }
38539
- }
38540
-
38541
- /* Merge configuration parameters */
38542
- if (cfg.ADD_TAGS) {
38543
- if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
38544
- ALLOWED_TAGS = clone(ALLOWED_TAGS);
38545
- }
38546
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
38547
- }
38548
- if (cfg.ADD_ATTR) {
38549
- if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
38550
- ALLOWED_ATTR = clone(ALLOWED_ATTR);
38551
- }
38552
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
38553
- }
38554
- if (cfg.ADD_URI_SAFE_ATTR) {
38555
- addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
38556
- }
38557
- if (cfg.FORBID_CONTENTS) {
38558
- if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
38559
- FORBID_CONTENTS = clone(FORBID_CONTENTS);
38560
- }
38561
- addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
38562
- }
38563
-
38564
- /* Add #text in case KEEP_CONTENT is set to true */
38565
- if (KEEP_CONTENT) {
38566
- ALLOWED_TAGS['#text'] = true;
38567
- }
38568
-
38569
- /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
38570
- if (WHOLE_DOCUMENT) {
38571
- addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
38572
- }
38573
-
38574
- /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
38575
- if (ALLOWED_TAGS.table) {
38576
- addToSet(ALLOWED_TAGS, ['tbody']);
38577
- delete FORBID_TAGS.tbody;
38578
- }
38579
- if (cfg.TRUSTED_TYPES_POLICY) {
38580
- if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
38581
- throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
38582
- }
38583
- if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
38584
- throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
38585
- }
38586
-
38587
- // Overwrite existing TrustedTypes policy.
38588
- trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
38589
-
38590
- // Sign local variables required by `sanitize`.
38591
- emptyHTML = trustedTypesPolicy.createHTML('');
38592
- } else {
38593
- // Uninitialized policy, attempt to initialize the internal dompurify policy.
38594
- if (trustedTypesPolicy === undefined) {
38595
- trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
38596
- }
38597
-
38598
- // If creating the internal policy succeeded sign internal variables.
38599
- if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
38600
- emptyHTML = trustedTypesPolicy.createHTML('');
38601
- }
38602
- }
38603
-
38604
- // Prevent further manipulation of configuration.
38605
- // Not available in IE8, Safari 5, etc.
38606
- if (freeze) {
38607
- freeze(cfg);
38608
- }
38609
- CONFIG = cfg;
38610
- };
38611
- const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
38612
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
38613
-
38614
- // Certain elements are allowed in both SVG and HTML
38615
- // namespace. We need to specify them explicitly
38616
- // so that they don't get erroneously deleted from
38617
- // HTML namespace.
38618
- const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
38619
-
38620
- /* Keep track of all possible SVG and MathML tags
38621
- * so that we can perform the namespace checks
38622
- * correctly. */
38623
- const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
38624
- const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
38625
-
38626
- /**
38627
- * @param {Element} element a DOM element whose namespace is being checked
38628
- * @returns {boolean} Return false if the element has a
38629
- * namespace that a spec-compliant parser would never
38630
- * return. Return true otherwise.
38631
- */
38632
- const _checkValidNamespace = function _checkValidNamespace(element) {
38633
- let parent = getParentNode(element);
38634
-
38635
- // In JSDOM, if we're inside shadow DOM, then parentNode
38636
- // can be null. We just simulate parent in this case.
38637
- if (!parent || !parent.tagName) {
38638
- parent = {
38639
- namespaceURI: NAMESPACE,
38640
- tagName: 'template'
38641
- };
38642
- }
38643
- const tagName = stringToLowerCase(element.tagName);
38644
- const parentTagName = stringToLowerCase(parent.tagName);
38645
- if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
38646
- return false;
38647
- }
38648
- if (element.namespaceURI === SVG_NAMESPACE) {
38649
- // The only way to switch from HTML namespace to SVG
38650
- // is via <svg>. If it happens via any other tag, then
38651
- // it should be killed.
38652
- if (parent.namespaceURI === HTML_NAMESPACE) {
38653
- return tagName === 'svg';
38654
- }
38655
-
38656
- // The only way to switch from MathML to SVG is via`
38657
- // svg if parent is either <annotation-xml> or MathML
38658
- // text integration points.
38659
- if (parent.namespaceURI === MATHML_NAMESPACE) {
38660
- return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
38661
- }
38662
-
38663
- // We only allow elements that are defined in SVG
38664
- // spec. All others are disallowed in SVG namespace.
38665
- return Boolean(ALL_SVG_TAGS[tagName]);
38666
- }
38667
- if (element.namespaceURI === MATHML_NAMESPACE) {
38668
- // The only way to switch from HTML namespace to MathML
38669
- // is via <math>. If it happens via any other tag, then
38670
- // it should be killed.
38671
- if (parent.namespaceURI === HTML_NAMESPACE) {
38672
- return tagName === 'math';
38673
- }
38674
-
38675
- // The only way to switch from SVG to MathML is via
38676
- // <math> and HTML integration points
38677
- if (parent.namespaceURI === SVG_NAMESPACE) {
38678
- return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
38679
- }
38680
-
38681
- // We only allow elements that are defined in MathML
38682
- // spec. All others are disallowed in MathML namespace.
38683
- return Boolean(ALL_MATHML_TAGS[tagName]);
38684
- }
38685
- if (element.namespaceURI === HTML_NAMESPACE) {
38686
- // The only way to switch from SVG to HTML is via
38687
- // HTML integration points, and from MathML to HTML
38688
- // is via MathML text integration points
38689
- if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
38690
- return false;
38691
- }
38692
- if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
38693
- return false;
38694
- }
38695
-
38696
- // We disallow tags that are specific for MathML
38697
- // or SVG and should never appear in HTML namespace
38698
- return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
38699
- }
38700
-
38701
- // For XHTML and XML documents that support custom namespaces
38702
- if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
38703
- return true;
38704
- }
38705
-
38706
- // The code should never reach this place (this means
38707
- // that the element somehow got namespace that is not
38708
- // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
38709
- // Return false just in case.
38710
- return false;
38711
- };
38712
-
38713
- /**
38714
- * _forceRemove
38715
- *
38716
- * @param {Node} node a DOM node
38717
- */
38718
- const _forceRemove = function _forceRemove(node) {
38719
- arrayPush(DOMPurify.removed, {
38720
- element: node
38721
- });
38722
- try {
38723
- // eslint-disable-next-line unicorn/prefer-dom-node-remove
38724
- node.parentNode.removeChild(node);
38725
- } catch (_) {
38726
- node.remove();
38727
- }
38728
- };
38729
-
38730
- /**
38731
- * _removeAttribute
38732
- *
38733
- * @param {String} name an Attribute name
38734
- * @param {Node} node a DOM node
38735
- */
38736
- const _removeAttribute = function _removeAttribute(name, node) {
38737
- try {
38738
- arrayPush(DOMPurify.removed, {
38739
- attribute: node.getAttributeNode(name),
38740
- from: node
38741
- });
38742
- } catch (_) {
38743
- arrayPush(DOMPurify.removed, {
38744
- attribute: null,
38745
- from: node
38746
- });
38747
- }
38748
- node.removeAttribute(name);
38749
-
38750
- // We void attribute values for unremovable "is"" attributes
38751
- if (name === 'is' && !ALLOWED_ATTR[name]) {
38752
- if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
38753
- try {
38754
- _forceRemove(node);
38755
- } catch (_) {}
38756
- } else {
38757
- try {
38758
- node.setAttribute(name, '');
38759
- } catch (_) {}
38760
- }
38761
- }
38762
- };
38763
-
38764
- /**
38765
- * _initDocument
38766
- *
38767
- * @param {String} dirty a string of dirty markup
38768
- * @return {Document} a DOM, filled with the dirty markup
38769
- */
38770
- const _initDocument = function _initDocument(dirty) {
38771
- /* Create a HTML document */
38772
- let doc = null;
38773
- let leadingWhitespace = null;
38774
- if (FORCE_BODY) {
38775
- dirty = '<remove></remove>' + dirty;
38776
- } else {
38777
- /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
38778
- const matches = stringMatch(dirty, /^[\r\n\t ]+/);
38779
- leadingWhitespace = matches && matches[0];
38780
- }
38781
- if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
38782
- // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
38783
- dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
38784
- }
38785
- const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
38786
- /*
38787
- * Use the DOMParser API by default, fallback later if needs be
38788
- * DOMParser not work for svg when has multiple root element.
38789
- */
38790
- if (NAMESPACE === HTML_NAMESPACE) {
38791
- try {
38792
- doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
38793
- } catch (_) {}
38794
- }
38795
-
38796
- /* Use createHTMLDocument in case DOMParser is not available */
38797
- if (!doc || !doc.documentElement) {
38798
- doc = implementation.createDocument(NAMESPACE, 'template', null);
38799
- try {
38800
- doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
38801
- } catch (_) {
38802
- // Syntax error if dirtyPayload is invalid xml
38803
- }
38804
- }
38805
- const body = doc.body || doc.documentElement;
38806
- if (dirty && leadingWhitespace) {
38807
- body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
38808
- }
38809
-
38810
- /* Work on whole document or just its body */
38811
- if (NAMESPACE === HTML_NAMESPACE) {
38812
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
38813
- }
38814
- return WHOLE_DOCUMENT ? doc.documentElement : body;
38815
- };
38816
-
38817
- /**
38818
- * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
38819
- *
38820
- * @param {Node} root The root element or node to start traversing on.
38821
- * @return {NodeIterator} The created NodeIterator
38822
- */
38823
- const _createNodeIterator = function _createNodeIterator(root) {
38824
- return createNodeIterator.call(root.ownerDocument || root, root,
38825
- // eslint-disable-next-line no-bitwise
38826
- NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null);
38827
- };
38828
-
38829
- /**
38830
- * _isClobbered
38831
- *
38832
- * @param {Node} elm element to check for clobbering attacks
38833
- * @return {Boolean} true if clobbered, false if safe
38834
- */
38835
- const _isClobbered = function _isClobbered(elm) {
38836
- return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
38837
- };
38838
-
38839
- /**
38840
- * Checks whether the given object is a DOM node.
38841
- *
38842
- * @param {Node} object object to check whether it's a DOM node
38843
- * @return {Boolean} true is object is a DOM node
38844
- */
38845
- const _isNode = function _isNode(object) {
38846
- return typeof Node === 'function' && object instanceof Node;
38847
- };
38848
-
38849
- /**
38850
- * _executeHook
38851
- * Execute user configurable hooks
38852
- *
38853
- * @param {String} entryPoint Name of the hook's entry point
38854
- * @param {Node} currentNode node to work on with the hook
38855
- * @param {Object} data additional hook parameters
38856
- */
38857
- const _executeHook = function _executeHook(entryPoint, currentNode, data) {
38858
- if (!hooks[entryPoint]) {
38859
- return;
38860
- }
38861
- arrayForEach(hooks[entryPoint], hook => {
38862
- hook.call(DOMPurify, currentNode, data, CONFIG);
38863
- });
38864
- };
38865
-
38866
- /**
38867
- * _sanitizeElements
38868
- *
38869
- * @protect nodeName
38870
- * @protect textContent
38871
- * @protect removeChild
38872
- *
38873
- * @param {Node} currentNode to check for permission to exist
38874
- * @return {Boolean} true if node was killed, false if left alive
38875
- */
38876
- const _sanitizeElements = function _sanitizeElements(currentNode) {
38877
- let content = null;
38878
-
38879
- /* Execute a hook if present */
38880
- _executeHook('beforeSanitizeElements', currentNode, null);
38881
-
38882
- /* Check if element is clobbered or can clobber */
38883
- if (_isClobbered(currentNode)) {
38884
- _forceRemove(currentNode);
38885
- return true;
38886
- }
38887
-
38888
- /* Now let's check the element's type and name */
38889
- const tagName = transformCaseFunc(currentNode.nodeName);
38890
-
38891
- /* Execute a hook if present */
38892
- _executeHook('uponSanitizeElement', currentNode, {
38893
- tagName,
38894
- allowedTags: ALLOWED_TAGS
38895
- });
38896
-
38897
- /* Detect mXSS attempts abusing namespace confusion */
38898
- if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
38899
- _forceRemove(currentNode);
38900
- return true;
38901
- }
38902
-
38903
- /* Remove element if anything forbids its presence */
38904
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
38905
- /* Check if we have a custom element to handle */
38906
- if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
38907
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
38908
- return false;
38909
- }
38910
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
38911
- return false;
38912
- }
38913
- }
38914
-
38915
- /* Keep content except for bad-listed elements */
38916
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
38917
- const parentNode = getParentNode(currentNode) || currentNode.parentNode;
38918
- const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
38919
- if (childNodes && parentNode) {
38920
- const childCount = childNodes.length;
38921
- for (let i = childCount - 1; i >= 0; --i) {
38922
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
38923
- }
38924
- }
38925
- }
38926
- _forceRemove(currentNode);
38927
- return true;
38928
- }
38929
-
38930
- /* Check whether element has a valid namespace */
38931
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
38932
- _forceRemove(currentNode);
38933
- return true;
38934
- }
38935
-
38936
- /* Make sure that older browsers don't get fallback-tag mXSS */
38937
- if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
38938
- _forceRemove(currentNode);
38939
- return true;
38940
- }
38941
-
38942
- /* Sanitize element content to be template-safe */
38943
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
38944
- /* Get the element's text content */
38945
- content = currentNode.textContent;
38946
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
38947
- content = stringReplace(content, expr, ' ');
38948
- });
38949
- if (currentNode.textContent !== content) {
38950
- arrayPush(DOMPurify.removed, {
38951
- element: currentNode.cloneNode()
38952
- });
38953
- currentNode.textContent = content;
38954
- }
38955
- }
38956
-
38957
- /* Execute a hook if present */
38958
- _executeHook('afterSanitizeElements', currentNode, null);
38959
- return false;
38960
- };
38961
-
38962
- /**
38963
- * _isValidAttribute
38964
- *
38965
- * @param {string} lcTag Lowercase tag name of containing element.
38966
- * @param {string} lcName Lowercase attribute name.
38967
- * @param {string} value Attribute value.
38968
- * @return {Boolean} Returns true if `value` is valid, otherwise false.
38969
- */
38970
- // eslint-disable-next-line complexity
38971
- const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
38972
- /* Make sure attribute cannot clobber */
38973
- if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
38974
- return false;
38975
- }
38976
-
38977
- /* Allow valid data-* attributes: At least one character after "-"
38978
- (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
38979
- XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
38980
- We don't need to check the value; it's always URI safe. */
38981
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
38982
- if (
38983
- // First condition does a very basic check if a) it's basically a valid custom element tagname AND
38984
- // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
38985
- // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
38986
- _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
38987
- // Alternative, second condition checks if it's an `is`-attribute, AND
38988
- // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
38989
- lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
38990
- return false;
38991
- }
38992
- /* Check value is safe. First, is attr inert? If so, is safe */
38993
- } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
38994
- return false;
38995
- } else ;
38996
- return true;
38997
- };
38998
-
38999
- /**
39000
- * _isBasicCustomElement
39001
- * checks if at least one dash is included in tagName, and it's not the first char
39002
- * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
39003
- *
39004
- * @param {string} tagName name of the tag of the node to sanitize
39005
- * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
39006
- */
39007
- const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
39008
- return tagName.indexOf('-') > 0;
39009
- };
39010
-
39011
- /**
39012
- * _sanitizeAttributes
39013
- *
39014
- * @protect attributes
39015
- * @protect nodeName
39016
- * @protect removeAttribute
39017
- * @protect setAttribute
39018
- *
39019
- * @param {Node} currentNode to sanitize
39020
- */
39021
- const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
39022
- /* Execute a hook if present */
39023
- _executeHook('beforeSanitizeAttributes', currentNode, null);
39024
- const {
39025
- attributes
39026
- } = currentNode;
39027
-
39028
- /* Check if we have attributes; if not we might have a text node */
39029
- if (!attributes) {
39030
- return;
39031
- }
39032
- const hookEvent = {
39033
- attrName: '',
39034
- attrValue: '',
39035
- keepAttr: true,
39036
- allowedAttributes: ALLOWED_ATTR
39037
- };
39038
- let l = attributes.length;
39039
-
39040
- /* Go backwards over all attributes; safely remove bad ones */
39041
- while (l--) {
39042
- const attr = attributes[l];
39043
- const {
39044
- name,
39045
- namespaceURI,
39046
- value: attrValue
39047
- } = attr;
39048
- const lcName = transformCaseFunc(name);
39049
- let value = name === 'value' ? attrValue : stringTrim(attrValue);
39050
-
39051
- /* Execute a hook if present */
39052
- hookEvent.attrName = lcName;
39053
- hookEvent.attrValue = value;
39054
- hookEvent.keepAttr = true;
39055
- hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
39056
- _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
39057
- value = hookEvent.attrValue;
39058
- /* Did the hooks approve of the attribute? */
39059
- if (hookEvent.forceKeepAttr) {
39060
- continue;
39061
- }
39062
-
39063
- /* Remove attribute */
39064
- _removeAttribute(name, currentNode);
39065
-
39066
- /* Did the hooks approve of the attribute? */
39067
- if (!hookEvent.keepAttr) {
39068
- continue;
39069
- }
39070
-
39071
- /* Work around a security issue in jQuery 3.0 */
39072
- if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
39073
- _removeAttribute(name, currentNode);
39074
- continue;
39075
- }
39076
-
39077
- /* Sanitize attribute content to be template-safe */
39078
- if (SAFE_FOR_TEMPLATES) {
39079
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
39080
- value = stringReplace(value, expr, ' ');
39081
- });
39082
- }
39083
-
39084
- /* Is `value` valid for this attribute? */
39085
- const lcTag = transformCaseFunc(currentNode.nodeName);
39086
- if (!_isValidAttribute(lcTag, lcName, value)) {
39087
- continue;
39088
- }
39089
-
39090
- /* Full DOM Clobbering protection via namespace isolation,
39091
- * Prefix id and name attributes with `user-content-`
39092
- */
39093
- if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
39094
- // Remove the attribute with this value
39095
- _removeAttribute(name, currentNode);
39096
-
39097
- // Prefix the value and later re-create the attribute with the sanitized value
39098
- value = SANITIZE_NAMED_PROPS_PREFIX + value;
39099
- }
39100
-
39101
- /* Handle attributes that require Trusted Types */
39102
- if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
39103
- if (namespaceURI) ; else {
39104
- switch (trustedTypes.getAttributeType(lcTag, lcName)) {
39105
- case 'TrustedHTML':
39106
- {
39107
- value = trustedTypesPolicy.createHTML(value);
39108
- break;
39109
- }
39110
- case 'TrustedScriptURL':
39111
- {
39112
- value = trustedTypesPolicy.createScriptURL(value);
39113
- break;
39114
- }
39115
- }
39116
- }
39117
- }
39118
-
39119
- /* Handle invalid data-* attribute set by try-catching it */
39120
- try {
39121
- if (namespaceURI) {
39122
- currentNode.setAttributeNS(namespaceURI, name, value);
39123
- } else {
39124
- /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
39125
- currentNode.setAttribute(name, value);
39126
- }
39127
- arrayPop(DOMPurify.removed);
39128
- } catch (_) {}
39129
- }
39130
-
39131
- /* Execute a hook if present */
39132
- _executeHook('afterSanitizeAttributes', currentNode, null);
39133
- };
39134
-
39135
- /**
39136
- * _sanitizeShadowDOM
39137
- *
39138
- * @param {DocumentFragment} fragment to iterate over recursively
39139
- */
39140
- const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
39141
- let shadowNode = null;
39142
- const shadowIterator = _createNodeIterator(fragment);
39143
-
39144
- /* Execute a hook if present */
39145
- _executeHook('beforeSanitizeShadowDOM', fragment, null);
39146
- while (shadowNode = shadowIterator.nextNode()) {
39147
- /* Execute a hook if present */
39148
- _executeHook('uponSanitizeShadowNode', shadowNode, null);
39149
-
39150
- /* Sanitize tags and elements */
39151
- if (_sanitizeElements(shadowNode)) {
39152
- continue;
39153
- }
39154
-
39155
- /* Deep shadow DOM detected */
39156
- if (shadowNode.content instanceof DocumentFragment) {
39157
- _sanitizeShadowDOM(shadowNode.content);
39158
- }
39159
-
39160
- /* Check attributes, sanitize if necessary */
39161
- _sanitizeAttributes(shadowNode);
39162
- }
39163
-
39164
- /* Execute a hook if present */
39165
- _executeHook('afterSanitizeShadowDOM', fragment, null);
39166
- };
39167
-
39168
- /**
39169
- * Sanitize
39170
- * Public method providing core sanitation functionality
39171
- *
39172
- * @param {String|Node} dirty string or DOM node
39173
- * @param {Object} cfg object
39174
- */
39175
- // eslint-disable-next-line complexity
39176
- DOMPurify.sanitize = function (dirty) {
39177
- let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
39178
- let body = null;
39179
- let importedNode = null;
39180
- let currentNode = null;
39181
- let returnNode = null;
39182
- /* Make sure we have a string to sanitize.
39183
- DO NOT return early, as this will return the wrong type if
39184
- the user has requested a DOM object rather than a string */
39185
- IS_EMPTY_INPUT = !dirty;
39186
- if (IS_EMPTY_INPUT) {
39187
- dirty = '<!-->';
39188
- }
39189
-
39190
- /* Stringify, in case dirty is an object */
39191
- if (typeof dirty !== 'string' && !_isNode(dirty)) {
39192
- if (typeof dirty.toString === 'function') {
39193
- dirty = dirty.toString();
39194
- if (typeof dirty !== 'string') {
39195
- throw typeErrorCreate('dirty is not a string, aborting');
39196
- }
39197
- } else {
39198
- throw typeErrorCreate('toString is not a function');
39199
- }
39200
- }
39201
-
39202
- /* Return dirty HTML if DOMPurify cannot run */
39203
- if (!DOMPurify.isSupported) {
39204
- return dirty;
39205
- }
39206
-
39207
- /* Assign config vars */
39208
- if (!SET_CONFIG) {
39209
- _parseConfig(cfg);
39210
- }
39211
-
39212
- /* Clean up removed elements */
39213
- DOMPurify.removed = [];
39214
-
39215
- /* Check if dirty is correctly typed for IN_PLACE */
39216
- if (typeof dirty === 'string') {
39217
- IN_PLACE = false;
39218
- }
39219
- if (IN_PLACE) {
39220
- /* Do some early pre-sanitization to avoid unsafe root nodes */
39221
- if (dirty.nodeName) {
39222
- const tagName = transformCaseFunc(dirty.nodeName);
39223
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
39224
- throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
39225
- }
39226
- }
39227
- } else if (dirty instanceof Node) {
39228
- /* If dirty is a DOM element, append to an empty document to avoid
39229
- elements being stripped by the parser */
39230
- body = _initDocument('<!---->');
39231
- importedNode = body.ownerDocument.importNode(dirty, true);
39232
- if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
39233
- /* Node is already a body, use as is */
39234
- body = importedNode;
39235
- } else if (importedNode.nodeName === 'HTML') {
39236
- body = importedNode;
39237
- } else {
39238
- // eslint-disable-next-line unicorn/prefer-dom-node-append
39239
- body.appendChild(importedNode);
39240
- }
39241
- } else {
39242
- /* Exit directly if we have nothing to do */
39243
- if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
39244
- // eslint-disable-next-line unicorn/prefer-includes
39245
- dirty.indexOf('<') === -1) {
39246
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
39247
- }
39248
-
39249
- /* Initialize the document to work on */
39250
- body = _initDocument(dirty);
39251
-
39252
- /* Check we have a DOM node from the data */
39253
- if (!body) {
39254
- return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
39255
- }
39256
- }
39257
-
39258
- /* Remove first element node (ours) if FORCE_BODY is set */
39259
- if (body && FORCE_BODY) {
39260
- _forceRemove(body.firstChild);
39261
- }
39262
-
39263
- /* Get node iterator */
39264
- const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
39265
-
39266
- /* Now start iterating over the created document */
39267
- while (currentNode = nodeIterator.nextNode()) {
39268
- /* Sanitize tags and elements */
39269
- if (_sanitizeElements(currentNode)) {
39270
- continue;
39271
- }
39272
-
39273
- /* Shadow DOM detected, sanitize it */
39274
- if (currentNode.content instanceof DocumentFragment) {
39275
- _sanitizeShadowDOM(currentNode.content);
39276
- }
39277
-
39278
- /* Check attributes, sanitize if necessary */
39279
- _sanitizeAttributes(currentNode);
39280
- }
39281
-
39282
- /* If we sanitized `dirty` in-place, return it. */
39283
- if (IN_PLACE) {
39284
- return dirty;
39285
- }
39286
-
39287
- /* Return sanitized string or DOM */
39288
- if (RETURN_DOM) {
39289
- if (RETURN_DOM_FRAGMENT) {
39290
- returnNode = createDocumentFragment.call(body.ownerDocument);
39291
- while (body.firstChild) {
39292
- // eslint-disable-next-line unicorn/prefer-dom-node-append
39293
- returnNode.appendChild(body.firstChild);
39294
- }
39295
- } else {
39296
- returnNode = body;
39297
- }
39298
- if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
39299
- /*
39300
- AdoptNode() is not used because internal state is not reset
39301
- (e.g. the past names map of a HTMLFormElement), this is safe
39302
- in theory but we would rather not risk another attack vector.
39303
- The state that is cloned by importNode() is explicitly defined
39304
- by the specs.
39305
- */
39306
- returnNode = importNode.call(originalDocument, returnNode, true);
39307
- }
39308
- return returnNode;
39309
- }
39310
- let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
39311
-
39312
- /* Serialize doctype if allowed */
39313
- if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
39314
- serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
39315
- }
39316
-
39317
- /* Sanitize final string template-safe */
39318
- if (SAFE_FOR_TEMPLATES) {
39319
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
39320
- serializedHTML = stringReplace(serializedHTML, expr, ' ');
39321
- });
39322
- }
39323
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
39324
- };
39325
-
39326
- /**
39327
- * Public method to set the configuration once
39328
- * setConfig
39329
- *
39330
- * @param {Object} cfg configuration object
39331
- */
39332
- DOMPurify.setConfig = function () {
39333
- let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
39334
- _parseConfig(cfg);
39335
- SET_CONFIG = true;
39336
- };
39337
-
39338
- /**
39339
- * Public method to remove the configuration
39340
- * clearConfig
39341
- *
39342
- */
39343
- DOMPurify.clearConfig = function () {
39344
- CONFIG = null;
39345
- SET_CONFIG = false;
39346
- };
39347
-
39348
- /**
39349
- * Public method to check if an attribute value is valid.
39350
- * Uses last set config, if any. Otherwise, uses config defaults.
39351
- * isValidAttribute
39352
- *
39353
- * @param {String} tag Tag name of containing element.
39354
- * @param {String} attr Attribute name.
39355
- * @param {String} value Attribute value.
39356
- * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
39357
- */
39358
- DOMPurify.isValidAttribute = function (tag, attr, value) {
39359
- /* Initialize shared config vars if necessary. */
39360
- if (!CONFIG) {
39361
- _parseConfig({});
39362
- }
39363
- const lcTag = transformCaseFunc(tag);
39364
- const lcName = transformCaseFunc(attr);
39365
- return _isValidAttribute(lcTag, lcName, value);
39366
- };
39367
-
39368
- /**
39369
- * AddHook
39370
- * Public method to add DOMPurify hooks
39371
- *
39372
- * @param {String} entryPoint entry point for the hook to add
39373
- * @param {Function} hookFunction function to execute
39374
- */
39375
- DOMPurify.addHook = function (entryPoint, hookFunction) {
39376
- if (typeof hookFunction !== 'function') {
39377
- return;
39378
- }
39379
- hooks[entryPoint] = hooks[entryPoint] || [];
39380
- arrayPush(hooks[entryPoint], hookFunction);
39381
- };
39382
-
39383
- /**
39384
- * RemoveHook
39385
- * Public method to remove a DOMPurify hook at a given entryPoint
39386
- * (pops it from the stack of hooks if more are present)
39387
- *
39388
- * @param {String} entryPoint entry point for the hook to remove
39389
- * @return {Function} removed(popped) hook
39390
- */
39391
- DOMPurify.removeHook = function (entryPoint) {
39392
- if (hooks[entryPoint]) {
39393
- return arrayPop(hooks[entryPoint]);
39394
- }
39395
- };
39396
-
39397
- /**
39398
- * RemoveHooks
39399
- * Public method to remove all DOMPurify hooks at a given entryPoint
39400
- *
39401
- * @param {String} entryPoint entry point for the hooks to remove
39402
- */
39403
- DOMPurify.removeHooks = function (entryPoint) {
39404
- if (hooks[entryPoint]) {
39405
- hooks[entryPoint] = [];
39406
- }
39407
- };
39408
-
39409
- /**
39410
- * RemoveAllHooks
39411
- * Public method to remove all DOMPurify hooks
39412
- */
39413
- DOMPurify.removeAllHooks = function () {
39414
- hooks = {};
39415
- };
39416
- return DOMPurify;
39417
- }
39418
- var purify = createDOMPurify();
39419
-
39420
- return purify;
39421
-
39422
- }));
39423
- //# sourceMappingURL=purify.js.map
39424
-
39425
-
39426
37996
  /***/ }),
39427
37997
 
39428
37998
  /***/ 3462: