config.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*!
  2. * (C) Ionic http://ionicframework.com - MIT License
  3. */
  4. import { p as printIonError } from './index4.js';
  5. /**
  6. * Does a simple sanitization of all elements
  7. * in an untrusted string
  8. */
  9. const sanitizeDOMString = (untrustedString) => {
  10. try {
  11. if (untrustedString instanceof IonicSafeString) {
  12. return untrustedString.value;
  13. }
  14. if (!isSanitizerEnabled() || typeof untrustedString !== 'string' || untrustedString === '') {
  15. return untrustedString;
  16. }
  17. /**
  18. * onload is fired when appending to a document
  19. * fragment in Chrome. If a string
  20. * contains onload then we should not
  21. * attempt to add this to the fragment.
  22. */
  23. if (untrustedString.includes('onload=')) {
  24. return '';
  25. }
  26. /**
  27. * Create a document fragment
  28. * separate from the main DOM,
  29. * create a div to do our work in
  30. */
  31. const documentFragment = document.createDocumentFragment();
  32. const workingDiv = document.createElement('div');
  33. documentFragment.appendChild(workingDiv);
  34. workingDiv.innerHTML = untrustedString;
  35. /**
  36. * Remove any elements
  37. * that are blocked
  38. */
  39. blockedTags.forEach((blockedTag) => {
  40. const getElementsToRemove = documentFragment.querySelectorAll(blockedTag);
  41. for (let elementIndex = getElementsToRemove.length - 1; elementIndex >= 0; elementIndex--) {
  42. const element = getElementsToRemove[elementIndex];
  43. if (element.parentNode) {
  44. element.parentNode.removeChild(element);
  45. }
  46. else {
  47. documentFragment.removeChild(element);
  48. }
  49. /**
  50. * We still need to sanitize
  51. * the children of this element
  52. * as they are left behind
  53. */
  54. const childElements = getElementChildren(element);
  55. /* eslint-disable-next-line */
  56. for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
  57. sanitizeElement(childElements[childIndex]);
  58. }
  59. }
  60. });
  61. /**
  62. * Go through remaining elements and remove
  63. * non-allowed attribs
  64. */
  65. // IE does not support .children on document fragments, only .childNodes
  66. const dfChildren = getElementChildren(documentFragment);
  67. /* eslint-disable-next-line */
  68. for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
  69. sanitizeElement(dfChildren[childIndex]);
  70. }
  71. // Append document fragment to div
  72. const fragmentDiv = document.createElement('div');
  73. fragmentDiv.appendChild(documentFragment);
  74. // First child is always the div we did our work in
  75. const getInnerDiv = fragmentDiv.querySelector('div');
  76. return getInnerDiv !== null ? getInnerDiv.innerHTML : fragmentDiv.innerHTML;
  77. }
  78. catch (err) {
  79. printIonError('sanitizeDOMString', err);
  80. return '';
  81. }
  82. };
  83. /**
  84. * Clean up current element based on allowed attributes
  85. * and then recursively dig down into any child elements to
  86. * clean those up as well
  87. */
  88. // TODO(FW-2832): type (using Element triggers other type errors as well)
  89. const sanitizeElement = (element) => {
  90. // IE uses childNodes, so ignore nodes that are not elements
  91. if (element.nodeType && element.nodeType !== 1) {
  92. return;
  93. }
  94. /**
  95. * If attributes is not a NamedNodeMap
  96. * then we should remove the element entirely.
  97. * This helps avoid DOM Clobbering attacks where
  98. * attributes is overridden.
  99. */
  100. if (typeof NamedNodeMap !== 'undefined' && !(element.attributes instanceof NamedNodeMap)) {
  101. element.remove();
  102. return;
  103. }
  104. for (let i = element.attributes.length - 1; i >= 0; i--) {
  105. const attribute = element.attributes.item(i);
  106. const attributeName = attribute.name;
  107. // remove non-allowed attribs
  108. if (!allowedAttributes.includes(attributeName.toLowerCase())) {
  109. element.removeAttribute(attributeName);
  110. continue;
  111. }
  112. // clean up any allowed attribs
  113. // that attempt to do any JS funny-business
  114. const attributeValue = attribute.value;
  115. /**
  116. * We also need to check the property value
  117. * as javascript: can allow special characters
  118. * such as &Tab; and still be valid (i.e. java&Tab;script)
  119. */
  120. const propertyValue = element[attributeName];
  121. /* eslint-disable */
  122. if ((attributeValue != null && attributeValue.toLowerCase().includes('javascript:')) ||
  123. (propertyValue != null && propertyValue.toLowerCase().includes('javascript:'))) {
  124. element.removeAttribute(attributeName);
  125. }
  126. /* eslint-enable */
  127. }
  128. /**
  129. * Sanitize any nested children
  130. */
  131. const childElements = getElementChildren(element);
  132. /* eslint-disable-next-line */
  133. for (let i = 0; i < childElements.length; i++) {
  134. sanitizeElement(childElements[i]);
  135. }
  136. };
  137. /**
  138. * IE doesn't always support .children
  139. * so we revert to .childNodes instead
  140. */
  141. // TODO(FW-2832): type
  142. const getElementChildren = (el) => {
  143. return el.children != null ? el.children : el.childNodes;
  144. };
  145. const isSanitizerEnabled = () => {
  146. var _a;
  147. const win = window;
  148. const config = (_a = win === null || win === void 0 ? void 0 : win.Ionic) === null || _a === void 0 ? void 0 : _a.config;
  149. if (config) {
  150. if (config.get) {
  151. return config.get('sanitizerEnabled', true);
  152. }
  153. else {
  154. return config.sanitizerEnabled === true || config.sanitizerEnabled === undefined;
  155. }
  156. }
  157. return true;
  158. };
  159. const allowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
  160. const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
  161. class IonicSafeString {
  162. constructor(value) {
  163. this.value = value;
  164. }
  165. }
  166. const setupConfig = (config) => {
  167. const win = window;
  168. const Ionic = win.Ionic;
  169. // eslint-disable-next-line @typescript-eslint/prefer-optional-chain
  170. if (Ionic && Ionic.config && Ionic.config.constructor.name !== 'Object') {
  171. return;
  172. }
  173. win.Ionic = win.Ionic || {};
  174. win.Ionic.config = Object.assign(Object.assign({}, win.Ionic.config), config);
  175. return win.Ionic.config;
  176. };
  177. const getMode = () => {
  178. var _a;
  179. const win = window;
  180. const config = (_a = win === null || win === void 0 ? void 0 : win.Ionic) === null || _a === void 0 ? void 0 : _a.config;
  181. if (config) {
  182. if (config.mode) {
  183. return config.mode;
  184. }
  185. else {
  186. return config.get('mode');
  187. }
  188. }
  189. return 'md';
  190. };
  191. const ENABLE_HTML_CONTENT_DEFAULT = false;
  192. export { ENABLE_HTML_CONTENT_DEFAULT as E, IonicSafeString as I, sanitizeDOMString as a, getMode as g, setupConfig as s };