monaco-editor-core 0.55.0-dev-20251014 → 0.55.0-dev-20251016
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.
- package/esm/nls.keys.json +1 -1
- package/esm/nls.messages.cs.js +9 -0
- package/esm/nls.messages.de.js +2 -2
- package/esm/nls.messages.es.js +2 -2
- package/esm/nls.messages.fr.js +2 -2
- package/esm/nls.messages.it.js +2 -2
- package/esm/nls.messages.ja.js +2 -2
- package/esm/nls.messages.js +1 -1
- package/esm/nls.messages.json +1 -1
- package/esm/nls.messages.ko.js +2 -2
- package/esm/nls.messages.pl.js +9 -0
- package/esm/nls.messages.pt-br.js +9 -0
- package/esm/nls.messages.ru.js +2 -2
- package/esm/nls.messages.tr.js +9 -0
- package/esm/nls.messages.zh-cn.js +2 -2
- package/esm/nls.messages.zh-tw.js +2 -2
- package/esm/nls.metadata.json +10 -0
- package/esm/vs/base/browser/canIUse.js +0 -1
- package/esm/vs/base/browser/canIUse.js.map +1 -1
- package/esm/vs/base/browser/domSanitize.js +31 -23
- package/esm/vs/base/browser/domSanitize.js.map +1 -1
- package/esm/vs/base/browser/dompurify/dompurify.js +188 -385
- package/esm/vs/base/browser/markdownRenderer.js +6 -1
- package/esm/vs/base/browser/markdownRenderer.js.map +1 -1
- package/esm/vs/base/browser/trustedTypes.js.map +1 -1
- package/esm/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- package/esm/vs/base/browser/ui/toggle/toggle.js +6 -0
- package/esm/vs/base/browser/ui/toggle/toggle.js.map +1 -1
- package/esm/vs/base/common/codiconsLibrary.js +1 -0
- package/esm/vs/base/common/codiconsLibrary.js.map +1 -1
- package/esm/vs/base/common/objects.js +0 -1
- package/esm/vs/base/common/objects.js.map +1 -1
- package/esm/vs/editor/browser/controller/mouseTarget.js +2 -1
- package/esm/vs/editor/browser/controller/mouseTarget.js.map +1 -1
- package/esm/vs/editor/browser/coreCommands.js +4 -2
- package/esm/vs/editor/browser/coreCommands.js.map +1 -1
- package/esm/vs/editor/browser/services/abstractCodeEditorService.js +5 -0
- package/esm/vs/editor/browser/services/abstractCodeEditorService.js.map +1 -1
- package/esm/vs/editor/browser/services/codeEditorService.js.map +1 -1
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/copySelection.js +104 -0
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/copySelection.js.map +1 -0
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.js +3 -3
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.js.map +1 -1
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/inlineDiffDeletedCodeMargin.js +25 -24
- package/esm/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/inlineDiffDeletedCodeMargin.js.map +1 -1
- package/esm/vs/editor/browser/widget/diffEditor/diffEditor.contribution.js +5 -5
- package/esm/vs/editor/browser/widget/diffEditor/diffEditorWidget.js +7 -3
- package/esm/vs/editor/browser/widget/diffEditor/diffEditorWidget.js.map +1 -1
- package/esm/vs/editor/browser/widget/diffEditor/features/hideUnchangedRegionsFeature.js +7 -7
- package/esm/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.js +2 -2
- package/esm/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.js +2 -2
- package/esm/vs/editor/browser/widget/diffEditor/registrations.contribution.js +5 -5
- package/esm/vs/editor/browser/widget/diffEditor/style.css +11 -0
- package/esm/vs/editor/browser/widget/multiDiffEditor/colors.js +3 -3
- package/esm/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.js +2 -2
- package/esm/vs/editor/common/config/editorConfigurationSchema.js +54 -54
- package/esm/vs/editor/common/config/editorOptions.js +406 -406
- package/esm/vs/editor/common/core/editorColorRegistry.js +68 -68
- package/esm/vs/editor/common/cursor/cursorMoveCommands.js +10 -1
- package/esm/vs/editor/common/cursor/cursorMoveCommands.js.map +1 -1
- package/esm/vs/editor/common/editorContextKeys.js +46 -46
- package/esm/vs/editor/common/languages/modesRegistry.js +1 -1
- package/esm/vs/editor/common/languages.js +56 -56
- package/esm/vs/editor/common/model/editStack.js +1 -1
- package/esm/vs/editor/common/standaloneStrings.js +10 -10
- package/esm/vs/editor/common/viewLayout/viewLineRenderer.js +2 -2
- package/esm/vs/editor/contrib/anchorSelect/browser/anchorSelect.js +6 -6
- package/esm/vs/editor/contrib/bracketMatching/browser/bracketMatching.js +6 -6
- package/esm/vs/editor/contrib/caretOperations/browser/caretOperations.js +2 -2
- package/esm/vs/editor/contrib/caretOperations/browser/transpose.js +1 -1
- package/esm/vs/editor/contrib/clipboard/browser/clipboard.js +17 -17
- package/esm/vs/editor/contrib/codeAction/browser/codeAction.js +1 -1
- package/esm/vs/editor/contrib/codeAction/browser/codeActionCommands.js +29 -29
- package/esm/vs/editor/contrib/codeAction/browser/codeActionContributions.js +3 -3
- package/esm/vs/editor/contrib/codeAction/browser/codeActionController.js +3 -3
- package/esm/vs/editor/contrib/codeAction/browser/codeActionMenu.js +8 -8
- package/esm/vs/editor/contrib/codeAction/browser/lightBulbWidget.js +9 -9
- package/esm/vs/editor/contrib/codelens/browser/codelensController.js +2 -2
- package/esm/vs/editor/contrib/colorPicker/browser/colorPickerParts/colorPickerCloseButton.js +1 -1
- package/esm/vs/editor/contrib/colorPicker/browser/colorPickerParts/colorPickerHeader.js +1 -1
- package/esm/vs/editor/contrib/colorPicker/browser/standaloneColorPicker/standaloneColorPickerActions.js +7 -7
- package/esm/vs/editor/contrib/comment/browser/comment.js +6 -6
- package/esm/vs/editor/contrib/contextmenu/browser/contextmenu.js +13 -14
- package/esm/vs/editor/contrib/contextmenu/browser/contextmenu.js.map +1 -1
- package/esm/vs/editor/contrib/cursorUndo/browser/cursorUndo.js +2 -2
- package/esm/vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution.js +4 -4
- package/esm/vs/editor/contrib/dropOrPasteInto/browser/copyPasteController.js +9 -9
- package/esm/vs/editor/contrib/dropOrPasteInto/browser/defaultProviders.js +8 -8
- package/esm/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController.js +3 -3
- package/esm/vs/editor/contrib/dropOrPasteInto/browser/postEditWidget.js +2 -2
- package/esm/vs/editor/contrib/editorState/browser/keybindingCancellation.js +1 -1
- package/esm/vs/editor/contrib/find/browser/findController.js +16 -16
- package/esm/vs/editor/contrib/find/browser/findWidget.js +26 -26
- package/esm/vs/editor/contrib/folding/browser/folding.js +20 -20
- package/esm/vs/editor/contrib/folding/browser/foldingDecorations.js +9 -9
- package/esm/vs/editor/contrib/folding/browser/foldingDecorations.js.map +1 -1
- package/esm/vs/editor/contrib/fontZoom/browser/fontZoom.js +3 -3
- package/esm/vs/editor/contrib/format/browser/formatActions.js +2 -2
- package/esm/vs/editor/contrib/gotoError/browser/gotoError.js +8 -8
- package/esm/vs/editor/contrib/gotoError/browser/gotoErrorWidget.js +14 -14
- package/esm/vs/editor/contrib/gotoSymbol/browser/goToCommands.js +39 -39
- package/esm/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.js +1 -1
- package/esm/vs/editor/contrib/gotoSymbol/browser/peek/referencesController.js +3 -3
- package/esm/vs/editor/contrib/gotoSymbol/browser/peek/referencesTree.js +3 -3
- package/esm/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.js +3 -3
- package/esm/vs/editor/contrib/gotoSymbol/browser/referencesModel.js +8 -8
- package/esm/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.js +3 -3
- package/esm/vs/editor/contrib/gpu/browser/gpuActions.js +4 -4
- package/esm/vs/editor/contrib/hover/browser/hoverActionIds.js +2 -2
- package/esm/vs/editor/contrib/hover/browser/hoverActions.js +24 -24
- package/esm/vs/editor/contrib/hover/browser/markdownHoverParticipant.js +9 -9
- package/esm/vs/editor/contrib/hover/browser/markerHoverParticipant.js +5 -5
- package/esm/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace.js +2 -2
- package/esm/vs/editor/contrib/indentation/browser/indentation.js +20 -20
- package/esm/vs/editor/contrib/inlayHints/browser/inlayHintsHover.js +8 -8
- package/esm/vs/editor/contrib/inlineCompletions/browser/controller/commands.js +19 -19
- package/esm/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionContextKeys.js +12 -12
- package/esm/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.js +15 -10
- package/esm/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.js.map +1 -1
- package/esm/vs/editor/contrib/inlineCompletions/browser/hintsWidget/hoverParticipant.js +1 -1
- package/esm/vs/editor/contrib/inlineCompletions/browser/hintsWidget/inlineCompletionsHintsWidget.js +5 -5
- package/esm/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorMenu.js +6 -6
- package/esm/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsModel.js +1 -1
- package/esm/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/theme.js +20 -20
- package/esm/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine.js +1 -1
- package/esm/vs/editor/contrib/lineSelection/browser/lineSelection.js +1 -1
- package/esm/vs/editor/contrib/linesOperations/browser/linesOperations.js +47 -37
- package/esm/vs/editor/contrib/linesOperations/browser/linesOperations.js.map +1 -1
- package/esm/vs/editor/contrib/linkedEditing/browser/linkedEditing.js +2 -2
- package/esm/vs/editor/contrib/links/browser/links.js +10 -10
- package/esm/vs/editor/contrib/message/browser/messageController.js +1 -1
- package/esm/vs/editor/contrib/multicursor/browser/multicursor.js +22 -22
- package/esm/vs/editor/contrib/parameterHints/browser/parameterHints.js +1 -1
- package/esm/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.js +4 -4
- package/esm/vs/editor/contrib/peekView/browser/peekView.js +18 -18
- package/esm/vs/editor/contrib/placeholderText/browser/placeholderText.contribution.js +1 -1
- package/esm/vs/editor/contrib/quickAccess/browser/gotoLineQuickAccess.js +56 -10
- package/esm/vs/editor/contrib/quickAccess/browser/gotoLineQuickAccess.js.map +1 -1
- package/esm/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.js +32 -32
- package/esm/vs/editor/contrib/readOnlyMessage/browser/contribution.js +2 -2
- package/esm/vs/editor/contrib/rename/browser/rename.js +11 -11
- package/esm/vs/editor/contrib/rename/browser/renameWidget.js +7 -7
- package/esm/vs/editor/contrib/smartSelect/browser/smartSelect.js +4 -4
- package/esm/vs/editor/contrib/snippet/browser/snippetController2.js +4 -4
- package/esm/vs/editor/contrib/snippet/browser/snippetVariables.js +4 -4
- package/esm/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.js +11 -11
- package/esm/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.js +2 -2
- package/esm/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.js.map +1 -1
- package/esm/vs/editor/contrib/suggest/browser/suggest.js +8 -8
- package/esm/vs/editor/contrib/suggest/browser/suggestController.js +10 -10
- package/esm/vs/editor/contrib/suggest/browser/suggestWidget.js +17 -17
- package/esm/vs/editor/contrib/suggest/browser/suggestWidgetDetails.js +2 -2
- package/esm/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.js +2 -2
- package/esm/vs/editor/contrib/suggest/browser/wordContextKey.js +1 -1
- package/esm/vs/editor/contrib/symbolIcons/browser/symbolIcons.js +33 -33
- package/esm/vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode.js +4 -4
- package/esm/vs/editor/contrib/tokenization/browser/tokenization.js +1 -1
- package/esm/vs/editor/contrib/unicodeHighlighter/browser/bannerController.js +1 -1
- package/esm/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.js +24 -24
- package/esm/vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators.js +5 -5
- package/esm/vs/editor/contrib/wordHighlighter/browser/highlightDecorations.js +9 -9
- package/esm/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.js +3 -3
- package/esm/vs/editor/contrib/wordOperations/browser/wordOperations.js +1 -1
- package/esm/vs/platform/accessibilitySignal/browser/accessibilitySignalService.js +62 -62
- package/esm/vs/platform/action/common/actionCommonCategories.js +6 -6
- package/esm/vs/platform/actionWidget/browser/actionList.js +4 -4
- package/esm/vs/platform/actionWidget/browser/actionWidget.js +7 -7
- package/esm/vs/platform/actions/browser/menuEntryActionViewItem.js +5 -5
- package/esm/vs/platform/actions/browser/toolbar.js +2 -2
- package/esm/vs/platform/actions/common/actions.js +0 -1
- package/esm/vs/platform/actions/common/actions.js.map +1 -1
- package/esm/vs/platform/actions/common/menuService.js +2 -2
- package/esm/vs/platform/configuration/common/configurationRegistry.js +10 -10
- package/esm/vs/platform/contextkey/browser/contextKeyService.js +1 -1
- package/esm/vs/platform/contextkey/common/contextkey.js +9 -9
- package/esm/vs/platform/contextkey/common/contextkeys.js +9 -9
- package/esm/vs/platform/contextkey/common/scanner.js +5 -5
- package/esm/vs/platform/history/browser/contextScopedHistoryWidget.js +1 -1
- package/esm/vs/platform/keybinding/common/abstractKeybindingService.js +4 -4
- package/esm/vs/platform/list/browser/listService.js +27 -27
- package/esm/vs/platform/markers/common/markerService.js +2 -2
- package/esm/vs/platform/markers/common/markers.js +6 -6
- package/esm/vs/platform/quickinput/browser/commandsQuickAccess.js +7 -7
- package/esm/vs/platform/quickinput/browser/helpQuickAccess.js +1 -1
- package/esm/vs/platform/quickinput/browser/quickInput.js +10 -10
- package/esm/vs/platform/quickinput/browser/quickInputActions.js +5 -5
- package/esm/vs/platform/quickinput/browser/quickInputController.js +6 -6
- package/esm/vs/platform/quickinput/browser/quickInputList.js +1 -1
- package/esm/vs/platform/quickinput/browser/quickInputUtils.js +1 -1
- package/esm/vs/platform/quickinput/browser/tree/quickInputTreeAccessibilityProvider.js +1 -1
- package/esm/vs/platform/quickinput/common/quickInput.js.map +1 -1
- package/esm/vs/platform/theme/common/colorUtils.js +2 -2
- package/esm/vs/platform/theme/common/colors/baseColors.js +17 -17
- package/esm/vs/platform/theme/common/colors/chartsColors.js +8 -8
- package/esm/vs/platform/theme/common/colors/editorColors.js +95 -95
- package/esm/vs/platform/theme/common/colors/inputColors.js +47 -47
- package/esm/vs/platform/theme/common/colors/listColors.js +36 -36
- package/esm/vs/platform/theme/common/colors/menuColors.js +7 -7
- package/esm/vs/platform/theme/common/colors/minimapColors.js +11 -11
- package/esm/vs/platform/theme/common/colors/miscColors.js +15 -15
- package/esm/vs/platform/theme/common/colors/quickpickColors.js +9 -9
- package/esm/vs/platform/theme/common/colors/searchColors.js +3 -3
- package/esm/vs/platform/theme/common/iconRegistry.js +6 -6
- package/esm/vs/platform/undoRedo/common/undoRedoService.js +20 -20
- package/esm/vs/platform/workspace/common/workspace.js +1 -1
- package/package.json +3 -3
- package/version.txt +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.
|
|
1
|
+
/*! @license DOMPurify 3.2.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.7/LICENSE */
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
entries,
|
|
@@ -27,18 +27,26 @@ if (!seal) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
if (!apply) {
|
|
30
|
-
apply = function apply(
|
|
31
|
-
|
|
30
|
+
apply = function apply(func, thisArg) {
|
|
31
|
+
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
32
|
+
args[_key - 2] = arguments[_key];
|
|
33
|
+
}
|
|
34
|
+
return func.apply(thisArg, args);
|
|
32
35
|
};
|
|
33
36
|
}
|
|
34
37
|
if (!construct) {
|
|
35
|
-
construct = function construct(Func
|
|
38
|
+
construct = function construct(Func) {
|
|
39
|
+
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
40
|
+
args[_key2 - 1] = arguments[_key2];
|
|
41
|
+
}
|
|
36
42
|
return new Func(...args);
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
45
|
const arrayForEach = unapply(Array.prototype.forEach);
|
|
46
|
+
const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
|
40
47
|
const arrayPop = unapply(Array.prototype.pop);
|
|
41
48
|
const arrayPush = unapply(Array.prototype.push);
|
|
49
|
+
const arraySplice = unapply(Array.prototype.splice);
|
|
42
50
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
43
51
|
const stringToString = unapply(String.prototype.toString);
|
|
44
52
|
const stringMatch = unapply(String.prototype.match);
|
|
@@ -48,44 +56,44 @@ const stringTrim = unapply(String.prototype.trim);
|
|
|
48
56
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
49
57
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
50
58
|
const typeErrorCreate = unconstruct(TypeError);
|
|
51
|
-
|
|
52
59
|
/**
|
|
53
60
|
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
54
61
|
*
|
|
55
|
-
* @param
|
|
56
|
-
* @returns
|
|
62
|
+
* @param func - The function to be wrapped and called.
|
|
63
|
+
* @returns A new function that calls the given function with a specified thisArg and arguments.
|
|
57
64
|
*/
|
|
58
65
|
function unapply(func) {
|
|
59
66
|
return function (thisArg) {
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
if (thisArg instanceof RegExp) {
|
|
68
|
+
thisArg.lastIndex = 0;
|
|
69
|
+
}
|
|
70
|
+
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
71
|
+
args[_key3 - 1] = arguments[_key3];
|
|
62
72
|
}
|
|
63
73
|
return apply(func, thisArg, args);
|
|
64
74
|
};
|
|
65
75
|
}
|
|
66
|
-
|
|
67
76
|
/**
|
|
68
77
|
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
|
69
78
|
*
|
|
70
|
-
* @param
|
|
71
|
-
* @returns
|
|
79
|
+
* @param func - The constructor function to be wrapped and called.
|
|
80
|
+
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
|
|
72
81
|
*/
|
|
73
|
-
function unconstruct(
|
|
82
|
+
function unconstruct(Func) {
|
|
74
83
|
return function () {
|
|
75
|
-
for (var
|
|
76
|
-
args[
|
|
84
|
+
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
|
|
85
|
+
args[_key4] = arguments[_key4];
|
|
77
86
|
}
|
|
78
|
-
return construct(
|
|
87
|
+
return construct(Func, args);
|
|
79
88
|
};
|
|
80
89
|
}
|
|
81
|
-
|
|
82
90
|
/**
|
|
83
91
|
* Add properties to a lookup table
|
|
84
92
|
*
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @param
|
|
88
|
-
* @returns
|
|
93
|
+
* @param set - The set to which elements will be added.
|
|
94
|
+
* @param array - The array containing elements to be added to the set.
|
|
95
|
+
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
|
96
|
+
* @returns The modified set with added elements.
|
|
89
97
|
*/
|
|
90
98
|
function addToSet(set, array) {
|
|
91
99
|
let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
|
|
@@ -112,12 +120,11 @@ function addToSet(set, array) {
|
|
|
112
120
|
}
|
|
113
121
|
return set;
|
|
114
122
|
}
|
|
115
|
-
|
|
116
123
|
/**
|
|
117
124
|
* Clean up an array to harden against CSPP
|
|
118
125
|
*
|
|
119
|
-
* @param
|
|
120
|
-
* @returns
|
|
126
|
+
* @param array - The array to be cleaned.
|
|
127
|
+
* @returns The cleaned version of the array
|
|
121
128
|
*/
|
|
122
129
|
function cleanArray(array) {
|
|
123
130
|
for (let index = 0; index < array.length; index++) {
|
|
@@ -128,12 +135,11 @@ function cleanArray(array) {
|
|
|
128
135
|
}
|
|
129
136
|
return array;
|
|
130
137
|
}
|
|
131
|
-
|
|
132
138
|
/**
|
|
133
139
|
* Shallow clone an object
|
|
134
140
|
*
|
|
135
|
-
* @param
|
|
136
|
-
* @returns
|
|
141
|
+
* @param object - The object to be cloned.
|
|
142
|
+
* @returns A new object that copies the original.
|
|
137
143
|
*/
|
|
138
144
|
function clone(object) {
|
|
139
145
|
const newObject = create(null);
|
|
@@ -151,13 +157,12 @@ function clone(object) {
|
|
|
151
157
|
}
|
|
152
158
|
return newObject;
|
|
153
159
|
}
|
|
154
|
-
|
|
155
160
|
/**
|
|
156
161
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
157
162
|
*
|
|
158
|
-
* @param
|
|
159
|
-
* @param
|
|
160
|
-
* @returns
|
|
163
|
+
* @param object - The object to look up the getter function in its prototype chain.
|
|
164
|
+
* @param prop - The property name for which to find the getter function.
|
|
165
|
+
* @returns The getter function found in the prototype chain or a fallback function.
|
|
161
166
|
*/
|
|
162
167
|
function lookupGetter(object, prop) {
|
|
163
168
|
while (object !== null) {
|
|
@@ -178,25 +183,21 @@ function lookupGetter(object, prop) {
|
|
|
178
183
|
return fallbackValue;
|
|
179
184
|
}
|
|
180
185
|
|
|
181
|
-
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']);
|
|
182
|
-
|
|
183
|
-
// SVG
|
|
184
|
-
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']);
|
|
186
|
+
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', 'search', 'section', 'select', 'shadow', 'slot', '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']);
|
|
187
|
+
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'slot', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
185
188
|
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']);
|
|
186
|
-
|
|
187
189
|
// List of SVG elements that are disallowed by default.
|
|
188
190
|
// We still need to know them so that we can do namespace
|
|
189
191
|
// checks properly in case one wants to add them to
|
|
190
192
|
// allow-list.
|
|
191
193
|
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']);
|
|
192
194
|
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']);
|
|
193
|
-
|
|
194
195
|
// Similarly to SVG, we want to know all MathML elements,
|
|
195
196
|
// even those that we disallow by default.
|
|
196
197
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
197
198
|
const text = freeze(['#text']);
|
|
198
199
|
|
|
199
|
-
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', 'popover', 'popovertarget', 'popovertargetaction', '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', 'wrap', 'xmlns', 'slot']);
|
|
200
|
+
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', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', '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', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
200
201
|
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', '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', 'exponent', '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', 'intercept', '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', 'slope', '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', 'tablevalues', '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']);
|
|
201
202
|
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']);
|
|
202
203
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
@@ -204,10 +205,10 @@ const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:x
|
|
|
204
205
|
// eslint-disable-next-line unicorn/better-regex
|
|
205
206
|
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
206
207
|
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
207
|
-
const TMPLIT_EXPR = seal(
|
|
208
|
-
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]
|
|
208
|
+
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
209
|
+
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
209
210
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
210
|
-
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
|
|
211
|
+
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
211
212
|
);
|
|
212
213
|
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
213
214
|
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
@@ -217,18 +218,19 @@ const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
|
217
218
|
|
|
218
219
|
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
219
220
|
__proto__: null,
|
|
220
|
-
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
221
|
-
ERB_EXPR: ERB_EXPR,
|
|
222
|
-
TMPLIT_EXPR: TMPLIT_EXPR,
|
|
223
|
-
DATA_ATTR: DATA_ATTR,
|
|
224
221
|
ARIA_ATTR: ARIA_ATTR,
|
|
225
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
226
|
-
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
227
222
|
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
223
|
+
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
|
224
|
+
DATA_ATTR: DATA_ATTR,
|
|
228
225
|
DOCTYPE_NAME: DOCTYPE_NAME,
|
|
229
|
-
|
|
226
|
+
ERB_EXPR: ERB_EXPR,
|
|
227
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
228
|
+
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
229
|
+
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
230
|
+
TMPLIT_EXPR: TMPLIT_EXPR
|
|
230
231
|
});
|
|
231
232
|
|
|
233
|
+
/* eslint-disable @typescript-eslint/indent */
|
|
232
234
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
233
235
|
const NODE_TYPE = {
|
|
234
236
|
element: 1,
|
|
@@ -249,20 +251,18 @@ const NODE_TYPE = {
|
|
|
249
251
|
const getGlobal = function getGlobal() {
|
|
250
252
|
return typeof window === 'undefined' ? null : window;
|
|
251
253
|
};
|
|
252
|
-
|
|
253
254
|
/**
|
|
254
255
|
* Creates a no-op policy for internal use only.
|
|
255
256
|
* Don't export this function outside this module!
|
|
256
|
-
* @param
|
|
257
|
-
* @param
|
|
258
|
-
* @return
|
|
257
|
+
* @param trustedTypes The policy factory.
|
|
258
|
+
* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
|
259
|
+
* @return The policy created (or null, if Trusted Types
|
|
259
260
|
* are not supported or creating the policy failed).
|
|
260
261
|
*/
|
|
261
262
|
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
|
262
263
|
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
263
264
|
return null;
|
|
264
265
|
}
|
|
265
|
-
|
|
266
266
|
// Allow the callers to control the unique policy name
|
|
267
267
|
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
268
268
|
// Policy creation with duplicate names throws in Trusted Types.
|
|
@@ -289,22 +289,25 @@ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedType
|
|
|
289
289
|
return null;
|
|
290
290
|
}
|
|
291
291
|
};
|
|
292
|
+
const _createHooksMap = function _createHooksMap() {
|
|
293
|
+
return {
|
|
294
|
+
afterSanitizeAttributes: [],
|
|
295
|
+
afterSanitizeElements: [],
|
|
296
|
+
afterSanitizeShadowDOM: [],
|
|
297
|
+
beforeSanitizeAttributes: [],
|
|
298
|
+
beforeSanitizeElements: [],
|
|
299
|
+
beforeSanitizeShadowDOM: [],
|
|
300
|
+
uponSanitizeAttribute: [],
|
|
301
|
+
uponSanitizeElement: [],
|
|
302
|
+
uponSanitizeShadowNode: []
|
|
303
|
+
};
|
|
304
|
+
};
|
|
292
305
|
function createDOMPurify() {
|
|
293
306
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
294
307
|
const DOMPurify = root => createDOMPurify(root);
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Version label, exposed for easier checks
|
|
298
|
-
* if DOMPurify is up to date or not
|
|
299
|
-
*/
|
|
300
|
-
DOMPurify.version = '3.1.7';
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Array of elements that DOMPurify removed during sanitation.
|
|
304
|
-
* Empty if nothing was removed.
|
|
305
|
-
*/
|
|
308
|
+
DOMPurify.version = '3.2.7';
|
|
306
309
|
DOMPurify.removed = [];
|
|
307
|
-
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
|
|
310
|
+
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
308
311
|
// Not running in a browser, provide a factory function
|
|
309
312
|
// so that you can pass your own Window
|
|
310
313
|
DOMPurify.isSupported = false;
|
|
@@ -332,7 +335,6 @@ function createDOMPurify() {
|
|
|
332
335
|
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
333
336
|
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
334
337
|
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
|
335
|
-
|
|
336
338
|
// As per issue #47, the web-components registry is inherited by a
|
|
337
339
|
// new document created via createHTMLDocument. As per the spec
|
|
338
340
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
@@ -356,8 +358,7 @@ function createDOMPurify() {
|
|
|
356
358
|
const {
|
|
357
359
|
importNode
|
|
358
360
|
} = originalDocument;
|
|
359
|
-
let hooks =
|
|
360
|
-
|
|
361
|
+
let hooks = _createHooksMap();
|
|
361
362
|
/**
|
|
362
363
|
* Expose whether this browser supports running the full DOMPurify.
|
|
363
364
|
*/
|
|
@@ -375,22 +376,18 @@ function createDOMPurify() {
|
|
|
375
376
|
let {
|
|
376
377
|
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
377
378
|
} = EXPRESSIONS;
|
|
378
|
-
|
|
379
379
|
/**
|
|
380
380
|
* We consider the elements and attributes below to be safe. Ideally
|
|
381
381
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
382
382
|
*/
|
|
383
|
-
|
|
384
383
|
/* allowed element names */
|
|
385
384
|
let ALLOWED_TAGS = null;
|
|
386
385
|
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
387
|
-
|
|
388
386
|
/* Allowed attribute names */
|
|
389
387
|
let ALLOWED_ATTR = null;
|
|
390
388
|
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
391
|
-
|
|
392
389
|
/*
|
|
393
|
-
* Configure how
|
|
390
|
+
* Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
|
|
394
391
|
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
395
392
|
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
396
393
|
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
@@ -415,65 +412,49 @@ function createDOMPurify() {
|
|
|
415
412
|
value: false
|
|
416
413
|
}
|
|
417
414
|
}));
|
|
418
|
-
|
|
419
415
|
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
420
416
|
let FORBID_TAGS = null;
|
|
421
|
-
|
|
422
417
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
423
418
|
let FORBID_ATTR = null;
|
|
424
|
-
|
|
425
419
|
/* Decide if ARIA attributes are okay */
|
|
426
420
|
let ALLOW_ARIA_ATTR = true;
|
|
427
|
-
|
|
428
421
|
/* Decide if custom data attributes are okay */
|
|
429
422
|
let ALLOW_DATA_ATTR = true;
|
|
430
|
-
|
|
431
423
|
/* Decide if unknown protocols are okay */
|
|
432
424
|
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
433
|
-
|
|
434
425
|
/* Decide if self-closing tags in attributes are allowed.
|
|
435
426
|
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
436
427
|
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
437
|
-
|
|
438
428
|
/* Output should be safe for common template engines.
|
|
439
429
|
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
440
430
|
*/
|
|
441
431
|
let SAFE_FOR_TEMPLATES = false;
|
|
442
|
-
|
|
443
432
|
/* Output should be safe even for XML used within HTML and alike.
|
|
444
433
|
* This means, DOMPurify removes comments when containing risky content.
|
|
445
434
|
*/
|
|
446
435
|
let SAFE_FOR_XML = true;
|
|
447
|
-
|
|
448
436
|
/* Decide if document with <html>... should be returned */
|
|
449
437
|
let WHOLE_DOCUMENT = false;
|
|
450
|
-
|
|
451
438
|
/* Track whether config is already set on this instance of DOMPurify. */
|
|
452
439
|
let SET_CONFIG = false;
|
|
453
|
-
|
|
454
440
|
/* Decide if all elements (e.g. style, script) must be children of
|
|
455
441
|
* document.body. By default, browsers might move them to document.head */
|
|
456
442
|
let FORCE_BODY = false;
|
|
457
|
-
|
|
458
443
|
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
459
444
|
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
460
445
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
461
446
|
*/
|
|
462
447
|
let RETURN_DOM = false;
|
|
463
|
-
|
|
464
448
|
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
465
449
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
466
450
|
let RETURN_DOM_FRAGMENT = false;
|
|
467
|
-
|
|
468
451
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
469
452
|
* case Trusted Types are not supported */
|
|
470
453
|
let RETURN_TRUSTED_TYPE = false;
|
|
471
|
-
|
|
472
454
|
/* Output should be free from DOM clobbering attacks?
|
|
473
455
|
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
474
456
|
*/
|
|
475
457
|
let SANITIZE_DOM = true;
|
|
476
|
-
|
|
477
458
|
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
478
459
|
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
479
460
|
*
|
|
@@ -489,25 +470,19 @@ function createDOMPurify() {
|
|
|
489
470
|
*/
|
|
490
471
|
let SANITIZE_NAMED_PROPS = false;
|
|
491
472
|
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
|
492
|
-
|
|
493
473
|
/* Keep element content when removing element? */
|
|
494
474
|
let KEEP_CONTENT = true;
|
|
495
|
-
|
|
496
475
|
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
497
476
|
* of importing it into a new Document and returning a sanitized copy */
|
|
498
477
|
let IN_PLACE = false;
|
|
499
|
-
|
|
500
478
|
/* Allow usage of profiles like html, svg and mathMl */
|
|
501
479
|
let USE_PROFILES = {};
|
|
502
|
-
|
|
503
480
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
504
481
|
let FORBID_CONTENTS = null;
|
|
505
482
|
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']);
|
|
506
|
-
|
|
507
483
|
/* Tags that are safe for data: URIs */
|
|
508
484
|
let DATA_URI_TAGS = null;
|
|
509
485
|
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
510
|
-
|
|
511
486
|
/* Attributes safe for values like "javascript:" */
|
|
512
487
|
let URI_SAFE_ATTRIBUTES = null;
|
|
513
488
|
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
@@ -517,32 +492,33 @@ function createDOMPurify() {
|
|
|
517
492
|
/* Document namespace */
|
|
518
493
|
let NAMESPACE = HTML_NAMESPACE;
|
|
519
494
|
let IS_EMPTY_INPUT = false;
|
|
520
|
-
|
|
521
495
|
/* Allowed XHTML+XML namespaces */
|
|
522
496
|
let ALLOWED_NAMESPACES = null;
|
|
523
497
|
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
524
|
-
|
|
498
|
+
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
499
|
+
let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
|
500
|
+
// Certain elements are allowed in both SVG and HTML
|
|
501
|
+
// namespace. We need to specify them explicitly
|
|
502
|
+
// so that they don't get erroneously deleted from
|
|
503
|
+
// HTML namespace.
|
|
504
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
525
505
|
/* Parsing of strict XHTML documents */
|
|
526
506
|
let PARSER_MEDIA_TYPE = null;
|
|
527
507
|
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
528
508
|
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
529
509
|
let transformCaseFunc = null;
|
|
530
|
-
|
|
531
510
|
/* Keep a reference to config to pass to hooks */
|
|
532
511
|
let CONFIG = null;
|
|
533
|
-
|
|
534
512
|
/* Ideally, do not touch anything below this line */
|
|
535
513
|
/* ______________________________________________ */
|
|
536
|
-
|
|
537
514
|
const formElement = document.createElement('form');
|
|
538
515
|
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
539
516
|
return testValue instanceof RegExp || testValue instanceof Function;
|
|
540
517
|
};
|
|
541
|
-
|
|
542
518
|
/**
|
|
543
519
|
* _parseConfig
|
|
544
520
|
*
|
|
545
|
-
* @param
|
|
521
|
+
* @param cfg optional config literal
|
|
546
522
|
*/
|
|
547
523
|
// eslint-disable-next-line complexity
|
|
548
524
|
const _parseConfig = function _parseConfig() {
|
|
@@ -550,42 +526,26 @@ function createDOMPurify() {
|
|
|
550
526
|
if (CONFIG && CONFIG === cfg) {
|
|
551
527
|
return;
|
|
552
528
|
}
|
|
553
|
-
|
|
554
529
|
/* Shield configuration object from tampering */
|
|
555
530
|
if (!cfg || typeof cfg !== 'object') {
|
|
556
531
|
cfg = {};
|
|
557
532
|
}
|
|
558
|
-
|
|
559
533
|
/* Shield configuration object from prototype pollution */
|
|
560
534
|
cfg = clone(cfg);
|
|
561
535
|
PARSER_MEDIA_TYPE =
|
|
562
536
|
// eslint-disable-next-line unicorn/prefer-includes
|
|
563
537
|
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
|
|
564
|
-
|
|
565
538
|
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
566
539
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
567
|
-
|
|
568
540
|
/* Set configuration parameters */
|
|
569
541
|
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
570
542
|
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
571
543
|
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
572
|
-
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
|
|
573
|
-
|
|
574
|
-
cfg.ADD_URI_SAFE_ATTR,
|
|
575
|
-
// eslint-disable-line indent
|
|
576
|
-
transformCaseFunc // eslint-disable-line indent
|
|
577
|
-
) // eslint-disable-line indent
|
|
578
|
-
: DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
579
|
-
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
|
|
580
|
-
// eslint-disable-line indent
|
|
581
|
-
cfg.ADD_DATA_URI_TAGS,
|
|
582
|
-
// eslint-disable-line indent
|
|
583
|
-
transformCaseFunc // eslint-disable-line indent
|
|
584
|
-
) // eslint-disable-line indent
|
|
585
|
-
: DEFAULT_DATA_URI_TAGS;
|
|
544
|
+
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
545
|
+
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
586
546
|
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
587
|
-
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
|
588
|
-
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
547
|
+
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
|
|
548
|
+
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
|
|
589
549
|
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
|
590
550
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
591
551
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
@@ -604,6 +564,8 @@ function createDOMPurify() {
|
|
|
604
564
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
605
565
|
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
606
566
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
567
|
+
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
|
|
568
|
+
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
|
|
607
569
|
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
608
570
|
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
609
571
|
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
@@ -620,7 +582,6 @@ function createDOMPurify() {
|
|
|
620
582
|
if (RETURN_DOM_FRAGMENT) {
|
|
621
583
|
RETURN_DOM = true;
|
|
622
584
|
}
|
|
623
|
-
|
|
624
585
|
/* Parse profile info */
|
|
625
586
|
if (USE_PROFILES) {
|
|
626
587
|
ALLOWED_TAGS = addToSet({}, text);
|
|
@@ -645,7 +606,6 @@ function createDOMPurify() {
|
|
|
645
606
|
addToSet(ALLOWED_ATTR, xml);
|
|
646
607
|
}
|
|
647
608
|
}
|
|
648
|
-
|
|
649
609
|
/* Merge configuration parameters */
|
|
650
610
|
if (cfg.ADD_TAGS) {
|
|
651
611
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
@@ -668,17 +628,14 @@ function createDOMPurify() {
|
|
|
668
628
|
}
|
|
669
629
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
670
630
|
}
|
|
671
|
-
|
|
672
631
|
/* Add #text in case KEEP_CONTENT is set to true */
|
|
673
632
|
if (KEEP_CONTENT) {
|
|
674
633
|
ALLOWED_TAGS['#text'] = true;
|
|
675
634
|
}
|
|
676
|
-
|
|
677
635
|
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
|
678
636
|
if (WHOLE_DOCUMENT) {
|
|
679
637
|
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
|
680
638
|
}
|
|
681
|
-
|
|
682
639
|
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
|
683
640
|
if (ALLOWED_TAGS.table) {
|
|
684
641
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
@@ -691,10 +648,8 @@ function createDOMPurify() {
|
|
|
691
648
|
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
|
692
649
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
693
650
|
}
|
|
694
|
-
|
|
695
651
|
// Overwrite existing TrustedTypes policy.
|
|
696
652
|
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
|
697
|
-
|
|
698
653
|
// Sign local variables required by `sanitize`.
|
|
699
654
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
700
655
|
} else {
|
|
@@ -702,13 +657,11 @@ function createDOMPurify() {
|
|
|
702
657
|
if (trustedTypesPolicy === undefined) {
|
|
703
658
|
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
704
659
|
}
|
|
705
|
-
|
|
706
660
|
// If creating the internal policy succeeded sign internal variables.
|
|
707
661
|
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
|
708
662
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
709
663
|
}
|
|
710
664
|
}
|
|
711
|
-
|
|
712
665
|
// Prevent further manipulation of configuration.
|
|
713
666
|
// Not available in IE8, Safari 5, etc.
|
|
714
667
|
if (freeze) {
|
|
@@ -716,30 +669,19 @@ function createDOMPurify() {
|
|
|
716
669
|
}
|
|
717
670
|
CONFIG = cfg;
|
|
718
671
|
};
|
|
719
|
-
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
720
|
-
const HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
|
721
|
-
|
|
722
|
-
// Certain elements are allowed in both SVG and HTML
|
|
723
|
-
// namespace. We need to specify them explicitly
|
|
724
|
-
// so that they don't get erroneously deleted from
|
|
725
|
-
// HTML namespace.
|
|
726
|
-
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
727
|
-
|
|
728
672
|
/* Keep track of all possible SVG and MathML tags
|
|
729
673
|
* so that we can perform the namespace checks
|
|
730
674
|
* correctly. */
|
|
731
675
|
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
|
|
732
676
|
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
|
|
733
|
-
|
|
734
677
|
/**
|
|
735
|
-
* @param
|
|
736
|
-
* @returns
|
|
678
|
+
* @param element a DOM element whose namespace is being checked
|
|
679
|
+
* @returns Return false if the element has a
|
|
737
680
|
* namespace that a spec-compliant parser would never
|
|
738
681
|
* return. Return true otherwise.
|
|
739
682
|
*/
|
|
740
683
|
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
741
684
|
let parent = getParentNode(element);
|
|
742
|
-
|
|
743
685
|
// In JSDOM, if we're inside shadow DOM, then parentNode
|
|
744
686
|
// can be null. We just simulate parent in this case.
|
|
745
687
|
if (!parent || !parent.tagName) {
|
|
@@ -760,14 +702,12 @@ function createDOMPurify() {
|
|
|
760
702
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
761
703
|
return tagName === 'svg';
|
|
762
704
|
}
|
|
763
|
-
|
|
764
705
|
// The only way to switch from MathML to SVG is via`
|
|
765
706
|
// svg if parent is either <annotation-xml> or MathML
|
|
766
707
|
// text integration points.
|
|
767
708
|
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
768
709
|
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
769
710
|
}
|
|
770
|
-
|
|
771
711
|
// We only allow elements that are defined in SVG
|
|
772
712
|
// spec. All others are disallowed in SVG namespace.
|
|
773
713
|
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
@@ -779,13 +719,11 @@ function createDOMPurify() {
|
|
|
779
719
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
780
720
|
return tagName === 'math';
|
|
781
721
|
}
|
|
782
|
-
|
|
783
722
|
// The only way to switch from SVG to MathML is via
|
|
784
723
|
// <math> and HTML integration points
|
|
785
724
|
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
786
725
|
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
787
726
|
}
|
|
788
|
-
|
|
789
727
|
// We only allow elements that are defined in MathML
|
|
790
728
|
// spec. All others are disallowed in MathML namespace.
|
|
791
729
|
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
@@ -800,28 +738,24 @@ function createDOMPurify() {
|
|
|
800
738
|
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
801
739
|
return false;
|
|
802
740
|
}
|
|
803
|
-
|
|
804
741
|
// We disallow tags that are specific for MathML
|
|
805
742
|
// or SVG and should never appear in HTML namespace
|
|
806
743
|
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
807
744
|
}
|
|
808
|
-
|
|
809
745
|
// For XHTML and XML documents that support custom namespaces
|
|
810
746
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
811
747
|
return true;
|
|
812
748
|
}
|
|
813
|
-
|
|
814
749
|
// The code should never reach this place (this means
|
|
815
750
|
// that the element somehow got namespace that is not
|
|
816
751
|
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
|
817
752
|
// Return false just in case.
|
|
818
753
|
return false;
|
|
819
754
|
};
|
|
820
|
-
|
|
821
755
|
/**
|
|
822
756
|
* _forceRemove
|
|
823
757
|
*
|
|
824
|
-
* @param
|
|
758
|
+
* @param node a DOM node
|
|
825
759
|
*/
|
|
826
760
|
const _forceRemove = function _forceRemove(node) {
|
|
827
761
|
arrayPush(DOMPurify.removed, {
|
|
@@ -834,46 +768,43 @@ function createDOMPurify() {
|
|
|
834
768
|
remove(node);
|
|
835
769
|
}
|
|
836
770
|
};
|
|
837
|
-
|
|
838
771
|
/**
|
|
839
772
|
* _removeAttribute
|
|
840
773
|
*
|
|
841
|
-
* @param
|
|
842
|
-
* @param
|
|
774
|
+
* @param name an Attribute name
|
|
775
|
+
* @param element a DOM node
|
|
843
776
|
*/
|
|
844
|
-
const _removeAttribute = function _removeAttribute(name,
|
|
777
|
+
const _removeAttribute = function _removeAttribute(name, element) {
|
|
845
778
|
try {
|
|
846
779
|
arrayPush(DOMPurify.removed, {
|
|
847
|
-
attribute:
|
|
848
|
-
from:
|
|
780
|
+
attribute: element.getAttributeNode(name),
|
|
781
|
+
from: element
|
|
849
782
|
});
|
|
850
783
|
} catch (_) {
|
|
851
784
|
arrayPush(DOMPurify.removed, {
|
|
852
785
|
attribute: null,
|
|
853
|
-
from:
|
|
786
|
+
from: element
|
|
854
787
|
});
|
|
855
788
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
if (name === 'is' && !ALLOWED_ATTR[name]) {
|
|
789
|
+
element.removeAttribute(name);
|
|
790
|
+
// We void attribute values for unremovable "is" attributes
|
|
791
|
+
if (name === 'is') {
|
|
860
792
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
861
793
|
try {
|
|
862
|
-
_forceRemove(
|
|
794
|
+
_forceRemove(element);
|
|
863
795
|
} catch (_) {}
|
|
864
796
|
} else {
|
|
865
797
|
try {
|
|
866
|
-
|
|
798
|
+
element.setAttribute(name, '');
|
|
867
799
|
} catch (_) {}
|
|
868
800
|
}
|
|
869
801
|
}
|
|
870
802
|
};
|
|
871
|
-
|
|
872
803
|
/**
|
|
873
804
|
* _initDocument
|
|
874
805
|
*
|
|
875
|
-
* @param
|
|
876
|
-
* @return
|
|
806
|
+
* @param dirty - a string of dirty markup
|
|
807
|
+
* @return a DOM, filled with the dirty markup
|
|
877
808
|
*/
|
|
878
809
|
const _initDocument = function _initDocument(dirty) {
|
|
879
810
|
/* Create a HTML document */
|
|
@@ -900,7 +831,6 @@ function createDOMPurify() {
|
|
|
900
831
|
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
|
901
832
|
} catch (_) {}
|
|
902
833
|
}
|
|
903
|
-
|
|
904
834
|
/* Use createHTMLDocument in case DOMParser is not available */
|
|
905
835
|
if (!doc || !doc.documentElement) {
|
|
906
836
|
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
|
@@ -914,112 +844,86 @@ function createDOMPurify() {
|
|
|
914
844
|
if (dirty && leadingWhitespace) {
|
|
915
845
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
916
846
|
}
|
|
917
|
-
|
|
918
847
|
/* Work on whole document or just its body */
|
|
919
848
|
if (NAMESPACE === HTML_NAMESPACE) {
|
|
920
849
|
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
921
850
|
}
|
|
922
851
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
923
852
|
};
|
|
924
|
-
|
|
925
853
|
/**
|
|
926
854
|
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
|
|
927
855
|
*
|
|
928
|
-
* @param
|
|
929
|
-
* @return
|
|
856
|
+
* @param root The root element or node to start traversing on.
|
|
857
|
+
* @return The created NodeIterator
|
|
930
858
|
*/
|
|
931
859
|
const _createNodeIterator = function _createNodeIterator(root) {
|
|
932
860
|
return createNodeIterator.call(root.ownerDocument || root, root,
|
|
933
861
|
// eslint-disable-next-line no-bitwise
|
|
934
862
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
|
935
863
|
};
|
|
936
|
-
|
|
937
864
|
/**
|
|
938
865
|
* _isClobbered
|
|
939
866
|
*
|
|
940
|
-
* @param
|
|
941
|
-
* @return
|
|
867
|
+
* @param element element to check for clobbering attacks
|
|
868
|
+
* @return true if clobbered, false if safe
|
|
942
869
|
*/
|
|
943
|
-
const _isClobbered = function _isClobbered(
|
|
944
|
-
return
|
|
870
|
+
const _isClobbered = function _isClobbered(element) {
|
|
871
|
+
return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
|
|
945
872
|
};
|
|
946
|
-
|
|
947
873
|
/**
|
|
948
874
|
* Checks whether the given object is a DOM node.
|
|
949
875
|
*
|
|
950
|
-
* @param
|
|
951
|
-
* @return
|
|
876
|
+
* @param value object to check whether it's a DOM node
|
|
877
|
+
* @return true is object is a DOM node
|
|
952
878
|
*/
|
|
953
|
-
const _isNode = function _isNode(
|
|
954
|
-
return typeof Node === 'function' &&
|
|
879
|
+
const _isNode = function _isNode(value) {
|
|
880
|
+
return typeof Node === 'function' && value instanceof Node;
|
|
955
881
|
};
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
* _executeHook
|
|
959
|
-
* Execute user configurable hooks
|
|
960
|
-
*
|
|
961
|
-
* @param {String} entryPoint Name of the hook's entry point
|
|
962
|
-
* @param {Node} currentNode node to work on with the hook
|
|
963
|
-
* @param {Object} data additional hook parameters
|
|
964
|
-
*/
|
|
965
|
-
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
|
966
|
-
if (!hooks[entryPoint]) {
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
arrayForEach(hooks[entryPoint], hook => {
|
|
882
|
+
function _executeHooks(hooks, currentNode, data) {
|
|
883
|
+
arrayForEach(hooks, hook => {
|
|
970
884
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
971
885
|
});
|
|
972
|
-
}
|
|
973
|
-
|
|
886
|
+
}
|
|
974
887
|
/**
|
|
975
888
|
* _sanitizeElements
|
|
976
889
|
*
|
|
977
890
|
* @protect nodeName
|
|
978
891
|
* @protect textContent
|
|
979
892
|
* @protect removeChild
|
|
980
|
-
*
|
|
981
|
-
* @
|
|
982
|
-
* @return {Boolean} true if node was killed, false if left alive
|
|
893
|
+
* @param currentNode to check for permission to exist
|
|
894
|
+
* @return true if node was killed, false if left alive
|
|
983
895
|
*/
|
|
984
896
|
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
985
897
|
let content = null;
|
|
986
|
-
|
|
987
898
|
/* Execute a hook if present */
|
|
988
|
-
|
|
989
|
-
|
|
899
|
+
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
990
900
|
/* Check if element is clobbered or can clobber */
|
|
991
901
|
if (_isClobbered(currentNode)) {
|
|
992
902
|
_forceRemove(currentNode);
|
|
993
903
|
return true;
|
|
994
904
|
}
|
|
995
|
-
|
|
996
905
|
/* Now let's check the element's type and name */
|
|
997
906
|
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
998
|
-
|
|
999
907
|
/* Execute a hook if present */
|
|
1000
|
-
|
|
908
|
+
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
1001
909
|
tagName,
|
|
1002
910
|
allowedTags: ALLOWED_TAGS
|
|
1003
911
|
});
|
|
1004
|
-
|
|
1005
912
|
/* Detect mXSS attempts abusing namespace confusion */
|
|
1006
|
-
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
|
913
|
+
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
|
|
1007
914
|
_forceRemove(currentNode);
|
|
1008
915
|
return true;
|
|
1009
916
|
}
|
|
1010
|
-
|
|
1011
917
|
/* Remove any occurrence of processing instructions */
|
|
1012
918
|
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
1013
919
|
_forceRemove(currentNode);
|
|
1014
920
|
return true;
|
|
1015
921
|
}
|
|
1016
|
-
|
|
1017
922
|
/* Remove any kind of possibly harmful comments */
|
|
1018
923
|
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
|
1019
924
|
_forceRemove(currentNode);
|
|
1020
925
|
return true;
|
|
1021
926
|
}
|
|
1022
|
-
|
|
1023
927
|
/* Remove element if anything forbids its presence */
|
|
1024
928
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1025
929
|
/* Check if we have a custom element to handle */
|
|
@@ -1031,7 +935,6 @@ function createDOMPurify() {
|
|
|
1031
935
|
return false;
|
|
1032
936
|
}
|
|
1033
937
|
}
|
|
1034
|
-
|
|
1035
938
|
/* Keep content except for bad-listed elements */
|
|
1036
939
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1037
940
|
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
@@ -1048,19 +951,16 @@ function createDOMPurify() {
|
|
|
1048
951
|
_forceRemove(currentNode);
|
|
1049
952
|
return true;
|
|
1050
953
|
}
|
|
1051
|
-
|
|
1052
954
|
/* Check whether element has a valid namespace */
|
|
1053
955
|
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
|
1054
956
|
_forceRemove(currentNode);
|
|
1055
957
|
return true;
|
|
1056
958
|
}
|
|
1057
|
-
|
|
1058
959
|
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
1059
960
|
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
|
1060
961
|
_forceRemove(currentNode);
|
|
1061
962
|
return true;
|
|
1062
963
|
}
|
|
1063
|
-
|
|
1064
964
|
/* Sanitize element content to be template-safe */
|
|
1065
965
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
1066
966
|
/* Get the element's text content */
|
|
@@ -1075,19 +975,17 @@ function createDOMPurify() {
|
|
|
1075
975
|
currentNode.textContent = content;
|
|
1076
976
|
}
|
|
1077
977
|
}
|
|
1078
|
-
|
|
1079
978
|
/* Execute a hook if present */
|
|
1080
|
-
|
|
979
|
+
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
|
1081
980
|
return false;
|
|
1082
981
|
};
|
|
1083
|
-
|
|
1084
982
|
/**
|
|
1085
983
|
* _isValidAttribute
|
|
1086
984
|
*
|
|
1087
|
-
* @param
|
|
1088
|
-
* @param
|
|
1089
|
-
* @param
|
|
1090
|
-
* @return
|
|
985
|
+
* @param lcTag Lowercase tag name of containing element.
|
|
986
|
+
* @param lcName Lowercase attribute name.
|
|
987
|
+
* @param value Attribute value.
|
|
988
|
+
* @return Returns true if `value` is valid, otherwise false.
|
|
1091
989
|
*/
|
|
1092
990
|
// eslint-disable-next-line complexity
|
|
1093
991
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
@@ -1095,7 +993,6 @@ function createDOMPurify() {
|
|
|
1095
993
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1096
994
|
return false;
|
|
1097
995
|
}
|
|
1098
|
-
|
|
1099
996
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
1100
997
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1101
998
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
@@ -1105,7 +1002,7 @@ function createDOMPurify() {
|
|
|
1105
1002
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1106
1003
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1107
1004
|
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1108
|
-
_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)) ||
|
|
1005
|
+
_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, lcTag)) ||
|
|
1109
1006
|
// Alternative, second condition checks if it's an `is`-attribute, AND
|
|
1110
1007
|
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1111
1008
|
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 {
|
|
@@ -1117,19 +1014,17 @@ function createDOMPurify() {
|
|
|
1117
1014
|
} else ;
|
|
1118
1015
|
return true;
|
|
1119
1016
|
};
|
|
1120
|
-
|
|
1121
1017
|
/**
|
|
1122
1018
|
* _isBasicCustomElement
|
|
1123
1019
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1124
1020
|
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1125
1021
|
*
|
|
1126
|
-
* @param
|
|
1127
|
-
* @returns
|
|
1022
|
+
* @param tagName name of the tag of the node to sanitize
|
|
1023
|
+
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
|
1128
1024
|
*/
|
|
1129
1025
|
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
|
1130
1026
|
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
|
|
1131
1027
|
};
|
|
1132
|
-
|
|
1133
1028
|
/**
|
|
1134
1029
|
* _sanitizeAttributes
|
|
1135
1030
|
*
|
|
@@ -1138,27 +1033,26 @@ function createDOMPurify() {
|
|
|
1138
1033
|
* @protect removeAttribute
|
|
1139
1034
|
* @protect setAttribute
|
|
1140
1035
|
*
|
|
1141
|
-
* @param
|
|
1036
|
+
* @param currentNode to sanitize
|
|
1142
1037
|
*/
|
|
1143
1038
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1144
1039
|
/* Execute a hook if present */
|
|
1145
|
-
|
|
1040
|
+
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
|
1146
1041
|
const {
|
|
1147
1042
|
attributes
|
|
1148
1043
|
} = currentNode;
|
|
1149
|
-
|
|
1150
1044
|
/* Check if we have attributes; if not we might have a text node */
|
|
1151
|
-
if (!attributes) {
|
|
1045
|
+
if (!attributes || _isClobbered(currentNode)) {
|
|
1152
1046
|
return;
|
|
1153
1047
|
}
|
|
1154
1048
|
const hookEvent = {
|
|
1155
1049
|
attrName: '',
|
|
1156
1050
|
attrValue: '',
|
|
1157
1051
|
keepAttr: true,
|
|
1158
|
-
allowedAttributes: ALLOWED_ATTR
|
|
1052
|
+
allowedAttributes: ALLOWED_ATTR,
|
|
1053
|
+
forceKeepAttr: undefined
|
|
1159
1054
|
};
|
|
1160
1055
|
let l = attributes.length;
|
|
1161
|
-
|
|
1162
1056
|
/* Go backwards over all attributes; safely remove bad ones */
|
|
1163
1057
|
while (l--) {
|
|
1164
1058
|
const attr = attributes[l];
|
|
@@ -1168,65 +1062,60 @@ function createDOMPurify() {
|
|
|
1168
1062
|
value: attrValue
|
|
1169
1063
|
} = attr;
|
|
1170
1064
|
const lcName = transformCaseFunc(name);
|
|
1171
|
-
|
|
1172
|
-
|
|
1065
|
+
const initValue = attrValue;
|
|
1066
|
+
let value = name === 'value' ? initValue : stringTrim(initValue);
|
|
1173
1067
|
/* Execute a hook if present */
|
|
1174
1068
|
hookEvent.attrName = lcName;
|
|
1175
1069
|
hookEvent.attrValue = value;
|
|
1176
1070
|
hookEvent.keepAttr = true;
|
|
1177
1071
|
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
1178
|
-
|
|
1072
|
+
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
|
1179
1073
|
value = hookEvent.attrValue;
|
|
1180
|
-
|
|
1074
|
+
/* Full DOM Clobbering protection via namespace isolation,
|
|
1075
|
+
* Prefix id and name attributes with `user-content-`
|
|
1076
|
+
*/
|
|
1077
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1078
|
+
// Remove the attribute with this value
|
|
1079
|
+
_removeAttribute(name, currentNode);
|
|
1080
|
+
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1081
|
+
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1082
|
+
}
|
|
1083
|
+
/* Work around a security issue with comments inside attributes */
|
|
1084
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
|
|
1085
|
+
_removeAttribute(name, currentNode);
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
/* Make sure we cannot easily use animated hrefs, even if animations are allowed */
|
|
1089
|
+
if (lcName === 'attributename' && stringMatch(value, 'href')) {
|
|
1090
|
+
_removeAttribute(name, currentNode);
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1181
1093
|
/* Did the hooks approve of the attribute? */
|
|
1182
1094
|
if (hookEvent.forceKeepAttr) {
|
|
1183
1095
|
continue;
|
|
1184
1096
|
}
|
|
1185
|
-
|
|
1186
|
-
/* Remove attribute */
|
|
1187
|
-
_removeAttribute(name, currentNode);
|
|
1188
|
-
|
|
1189
1097
|
/* Did the hooks approve of the attribute? */
|
|
1190
1098
|
if (!hookEvent.keepAttr) {
|
|
1099
|
+
_removeAttribute(name, currentNode);
|
|
1191
1100
|
continue;
|
|
1192
1101
|
}
|
|
1193
|
-
|
|
1194
1102
|
/* Work around a security issue in jQuery 3.0 */
|
|
1195
1103
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
1196
1104
|
_removeAttribute(name, currentNode);
|
|
1197
1105
|
continue;
|
|
1198
1106
|
}
|
|
1199
|
-
|
|
1200
1107
|
/* Sanitize attribute content to be template-safe */
|
|
1201
1108
|
if (SAFE_FOR_TEMPLATES) {
|
|
1202
1109
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1203
1110
|
value = stringReplace(value, expr, ' ');
|
|
1204
1111
|
});
|
|
1205
1112
|
}
|
|
1206
|
-
|
|
1207
1113
|
/* Is `value` valid for this attribute? */
|
|
1208
1114
|
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1209
1115
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
/* Full DOM Clobbering protection via namespace isolation,
|
|
1214
|
-
* Prefix id and name attributes with `user-content-`
|
|
1215
|
-
*/
|
|
1216
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1217
|
-
// Remove the attribute with this value
|
|
1218
|
-
_removeAttribute(name, currentNode);
|
|
1219
|
-
|
|
1220
|
-
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1221
|
-
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
/* Work around a security issue with comments inside attributes */
|
|
1225
|
-
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
|
1226
1116
|
_removeAttribute(name, currentNode);
|
|
1227
1117
|
continue;
|
|
1228
1118
|
}
|
|
1229
|
-
|
|
1230
1119
|
/* Handle attributes that require Trusted Types */
|
|
1231
1120
|
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
1232
1121
|
if (namespaceURI) ; else {
|
|
@@ -1244,67 +1133,53 @@ function createDOMPurify() {
|
|
|
1244
1133
|
}
|
|
1245
1134
|
}
|
|
1246
1135
|
}
|
|
1247
|
-
|
|
1248
1136
|
/* Handle invalid data-* attribute set by try-catching it */
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1137
|
+
if (value !== initValue) {
|
|
1138
|
+
try {
|
|
1139
|
+
if (namespaceURI) {
|
|
1140
|
+
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
1141
|
+
} else {
|
|
1142
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
1143
|
+
currentNode.setAttribute(name, value);
|
|
1144
|
+
}
|
|
1145
|
+
if (_isClobbered(currentNode)) {
|
|
1146
|
+
_forceRemove(currentNode);
|
|
1147
|
+
} else {
|
|
1148
|
+
arrayPop(DOMPurify.removed);
|
|
1149
|
+
}
|
|
1150
|
+
} catch (_) {
|
|
1151
|
+
_removeAttribute(name, currentNode);
|
|
1260
1152
|
}
|
|
1261
|
-
}
|
|
1153
|
+
}
|
|
1262
1154
|
}
|
|
1263
|
-
|
|
1264
1155
|
/* Execute a hook if present */
|
|
1265
|
-
|
|
1156
|
+
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
|
|
1266
1157
|
};
|
|
1267
|
-
|
|
1268
1158
|
/**
|
|
1269
1159
|
* _sanitizeShadowDOM
|
|
1270
1160
|
*
|
|
1271
|
-
* @param
|
|
1161
|
+
* @param fragment to iterate over recursively
|
|
1272
1162
|
*/
|
|
1273
1163
|
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1274
1164
|
let shadowNode = null;
|
|
1275
1165
|
const shadowIterator = _createNodeIterator(fragment);
|
|
1276
|
-
|
|
1277
1166
|
/* Execute a hook if present */
|
|
1278
|
-
|
|
1167
|
+
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
|
|
1279
1168
|
while (shadowNode = shadowIterator.nextNode()) {
|
|
1280
1169
|
/* Execute a hook if present */
|
|
1281
|
-
|
|
1282
|
-
|
|
1170
|
+
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
|
|
1283
1171
|
/* Sanitize tags and elements */
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1172
|
+
_sanitizeElements(shadowNode);
|
|
1173
|
+
/* Check attributes next */
|
|
1174
|
+
_sanitizeAttributes(shadowNode);
|
|
1288
1175
|
/* Deep shadow DOM detected */
|
|
1289
1176
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1290
1177
|
_sanitizeShadowDOM(shadowNode.content);
|
|
1291
1178
|
}
|
|
1292
|
-
|
|
1293
|
-
/* Check attributes, sanitize if necessary */
|
|
1294
|
-
_sanitizeAttributes(shadowNode);
|
|
1295
1179
|
}
|
|
1296
|
-
|
|
1297
1180
|
/* Execute a hook if present */
|
|
1298
|
-
|
|
1181
|
+
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
|
1299
1182
|
};
|
|
1300
|
-
|
|
1301
|
-
/**
|
|
1302
|
-
* Sanitize
|
|
1303
|
-
* Public method providing core sanitation functionality
|
|
1304
|
-
*
|
|
1305
|
-
* @param {String|Node} dirty string or DOM node
|
|
1306
|
-
* @param {Object} cfg object
|
|
1307
|
-
*/
|
|
1308
1183
|
// eslint-disable-next-line complexity
|
|
1309
1184
|
DOMPurify.sanitize = function (dirty) {
|
|
1310
1185
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -1319,7 +1194,6 @@ function createDOMPurify() {
|
|
|
1319
1194
|
if (IS_EMPTY_INPUT) {
|
|
1320
1195
|
dirty = '<!-->';
|
|
1321
1196
|
}
|
|
1322
|
-
|
|
1323
1197
|
/* Stringify, in case dirty is an object */
|
|
1324
1198
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1325
1199
|
if (typeof dirty.toString === 'function') {
|
|
@@ -1331,20 +1205,16 @@ function createDOMPurify() {
|
|
|
1331
1205
|
throw typeErrorCreate('toString is not a function');
|
|
1332
1206
|
}
|
|
1333
1207
|
}
|
|
1334
|
-
|
|
1335
1208
|
/* Return dirty HTML if DOMPurify cannot run */
|
|
1336
1209
|
if (!DOMPurify.isSupported) {
|
|
1337
1210
|
return dirty;
|
|
1338
1211
|
}
|
|
1339
|
-
|
|
1340
1212
|
/* Assign config vars */
|
|
1341
1213
|
if (!SET_CONFIG) {
|
|
1342
1214
|
_parseConfig(cfg);
|
|
1343
1215
|
}
|
|
1344
|
-
|
|
1345
1216
|
/* Clean up removed elements */
|
|
1346
1217
|
DOMPurify.removed = [];
|
|
1347
|
-
|
|
1348
1218
|
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1349
1219
|
if (typeof dirty === 'string') {
|
|
1350
1220
|
IN_PLACE = false;
|
|
@@ -1378,45 +1248,34 @@ function createDOMPurify() {
|
|
|
1378
1248
|
dirty.indexOf('<') === -1) {
|
|
1379
1249
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1380
1250
|
}
|
|
1381
|
-
|
|
1382
1251
|
/* Initialize the document to work on */
|
|
1383
1252
|
body = _initDocument(dirty);
|
|
1384
|
-
|
|
1385
1253
|
/* Check we have a DOM node from the data */
|
|
1386
1254
|
if (!body) {
|
|
1387
1255
|
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
|
1388
1256
|
}
|
|
1389
1257
|
}
|
|
1390
|
-
|
|
1391
1258
|
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1392
1259
|
if (body && FORCE_BODY) {
|
|
1393
1260
|
_forceRemove(body.firstChild);
|
|
1394
1261
|
}
|
|
1395
|
-
|
|
1396
1262
|
/* Get node iterator */
|
|
1397
1263
|
const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
|
|
1398
|
-
|
|
1399
1264
|
/* Now start iterating over the created document */
|
|
1400
1265
|
while (currentNode = nodeIterator.nextNode()) {
|
|
1401
1266
|
/* Sanitize tags and elements */
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1267
|
+
_sanitizeElements(currentNode);
|
|
1268
|
+
/* Check attributes next */
|
|
1269
|
+
_sanitizeAttributes(currentNode);
|
|
1406
1270
|
/* Shadow DOM detected, sanitize it */
|
|
1407
1271
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1408
1272
|
_sanitizeShadowDOM(currentNode.content);
|
|
1409
1273
|
}
|
|
1410
|
-
|
|
1411
|
-
/* Check attributes, sanitize if necessary */
|
|
1412
|
-
_sanitizeAttributes(currentNode);
|
|
1413
1274
|
}
|
|
1414
|
-
|
|
1415
1275
|
/* If we sanitized `dirty` in-place, return it. */
|
|
1416
1276
|
if (IN_PLACE) {
|
|
1417
1277
|
return dirty;
|
|
1418
1278
|
}
|
|
1419
|
-
|
|
1420
1279
|
/* Return sanitized string or DOM */
|
|
1421
1280
|
if (RETURN_DOM) {
|
|
1422
1281
|
if (RETURN_DOM_FRAGMENT) {
|
|
@@ -1441,12 +1300,10 @@ function createDOMPurify() {
|
|
|
1441
1300
|
return returnNode;
|
|
1442
1301
|
}
|
|
1443
1302
|
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1444
|
-
|
|
1445
1303
|
/* Serialize doctype if allowed */
|
|
1446
1304
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
1447
1305
|
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
1448
1306
|
}
|
|
1449
|
-
|
|
1450
1307
|
/* Sanitize final string template-safe */
|
|
1451
1308
|
if (SAFE_FOR_TEMPLATES) {
|
|
1452
1309
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
@@ -1455,39 +1312,15 @@ function createDOMPurify() {
|
|
|
1455
1312
|
}
|
|
1456
1313
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
1457
1314
|
};
|
|
1458
|
-
|
|
1459
|
-
/**
|
|
1460
|
-
* Public method to set the configuration once
|
|
1461
|
-
* setConfig
|
|
1462
|
-
*
|
|
1463
|
-
* @param {Object} cfg configuration object
|
|
1464
|
-
*/
|
|
1465
1315
|
DOMPurify.setConfig = function () {
|
|
1466
1316
|
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1467
1317
|
_parseConfig(cfg);
|
|
1468
1318
|
SET_CONFIG = true;
|
|
1469
1319
|
};
|
|
1470
|
-
|
|
1471
|
-
/**
|
|
1472
|
-
* Public method to remove the configuration
|
|
1473
|
-
* clearConfig
|
|
1474
|
-
*
|
|
1475
|
-
*/
|
|
1476
1320
|
DOMPurify.clearConfig = function () {
|
|
1477
1321
|
CONFIG = null;
|
|
1478
1322
|
SET_CONFIG = false;
|
|
1479
1323
|
};
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* Public method to check if an attribute value is valid.
|
|
1483
|
-
* Uses last set config, if any. Otherwise, uses config defaults.
|
|
1484
|
-
* isValidAttribute
|
|
1485
|
-
*
|
|
1486
|
-
* @param {String} tag Tag name of containing element.
|
|
1487
|
-
* @param {String} attr Attribute name.
|
|
1488
|
-
* @param {String} value Attribute value.
|
|
1489
|
-
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
|
1490
|
-
*/
|
|
1491
1324
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
|
1492
1325
|
/* Initialize shared config vars if necessary. */
|
|
1493
1326
|
if (!CONFIG) {
|
|
@@ -1497,54 +1330,24 @@ function createDOMPurify() {
|
|
|
1497
1330
|
const lcName = transformCaseFunc(attr);
|
|
1498
1331
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1499
1332
|
};
|
|
1500
|
-
|
|
1501
|
-
/**
|
|
1502
|
-
* AddHook
|
|
1503
|
-
* Public method to add DOMPurify hooks
|
|
1504
|
-
*
|
|
1505
|
-
* @param {String} entryPoint entry point for the hook to add
|
|
1506
|
-
* @param {Function} hookFunction function to execute
|
|
1507
|
-
*/
|
|
1508
1333
|
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
1509
1334
|
if (typeof hookFunction !== 'function') {
|
|
1510
1335
|
return;
|
|
1511
1336
|
}
|
|
1512
|
-
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
1513
1337
|
arrayPush(hooks[entryPoint], hookFunction);
|
|
1514
1338
|
};
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
* (pops it from the stack of hooks if more are present)
|
|
1520
|
-
*
|
|
1521
|
-
* @param {String} entryPoint entry point for the hook to remove
|
|
1522
|
-
* @return {Function} removed(popped) hook
|
|
1523
|
-
*/
|
|
1524
|
-
DOMPurify.removeHook = function (entryPoint) {
|
|
1525
|
-
if (hooks[entryPoint]) {
|
|
1526
|
-
return arrayPop(hooks[entryPoint]);
|
|
1339
|
+
DOMPurify.removeHook = function (entryPoint, hookFunction) {
|
|
1340
|
+
if (hookFunction !== undefined) {
|
|
1341
|
+
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
|
|
1342
|
+
return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
|
|
1527
1343
|
}
|
|
1344
|
+
return arrayPop(hooks[entryPoint]);
|
|
1528
1345
|
};
|
|
1529
|
-
|
|
1530
|
-
/**
|
|
1531
|
-
* RemoveHooks
|
|
1532
|
-
* Public method to remove all DOMPurify hooks at a given entryPoint
|
|
1533
|
-
*
|
|
1534
|
-
* @param {String} entryPoint entry point for the hooks to remove
|
|
1535
|
-
*/
|
|
1536
1346
|
DOMPurify.removeHooks = function (entryPoint) {
|
|
1537
|
-
|
|
1538
|
-
hooks[entryPoint] = [];
|
|
1539
|
-
}
|
|
1347
|
+
hooks[entryPoint] = [];
|
|
1540
1348
|
};
|
|
1541
|
-
|
|
1542
|
-
/**
|
|
1543
|
-
* RemoveAllHooks
|
|
1544
|
-
* Public method to remove all DOMPurify hooks
|
|
1545
|
-
*/
|
|
1546
1349
|
DOMPurify.removeAllHooks = function () {
|
|
1547
|
-
hooks =
|
|
1350
|
+
hooks = _createHooksMap();
|
|
1548
1351
|
};
|
|
1549
1352
|
return DOMPurify;
|
|
1550
1353
|
}
|