Fix 8166 html tag validation (#8176)

* wip proposal still contains commented old code - tests are missing

* rename isTagNameSafe to makeTagNameSafe

* remove comments

* remove redundant space

* add htmlCustomPrimitives to the $tw.config object

* remove tag-sanitation from element.js

* WIP - add html-element sanitation to the new makeTagNameSafe function, so it can be used globally

* simplify sanitation logic and fix inline docs

* Move top comment into inline comments
This commit is contained in:
Mario Pietsch
2025-10-29 17:42:28 +00:00
committed by GitHub
parent cda8d7ca8c
commit 9a5f4cc0ef
12 changed files with 67 additions and 47 deletions
+1 -3
View File
@@ -35,9 +35,7 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
// Create element
if(this.buttonTag && $tw.config.htmlUnsafeElements.indexOf(this.buttonTag) === -1) {
tag = this.buttonTag;
}
tag = $tw.utils.makeTagNameSafe(this.buttonTag,tag)
domNode = this.document.createElement(tag);
this.domNode = domNode;
// Assign classes
+1 -4
View File
@@ -35,10 +35,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
// Execute our logic
this.execute();
// Sanitise the specified tag
tag = this.draggableTag;
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
tag = "div";
}
tag = $tw.utils.makeTagNameSafe(this.draggableTag,"div");
// Create our element
domNode = this.document.createElement(tag);
// Assign classes
+1 -3
View File
@@ -32,9 +32,7 @@ DroppableWidget.prototype.render = function(parent,nextSibling) {
// Compute attributes and execute state
this.computeAttributes();
this.execute();
if(this.droppableTag && $tw.config.htmlUnsafeElements.indexOf(this.droppableTag) === -1) {
tag = this.droppableTag;
}
tag = $tw.utils.makeTagNameSafe(this.droppableTag,tag);
// Create element and assign classes
domNode = this.document.createElement(tag);
this.domNode = domNode;
+3 -8
View File
@@ -26,15 +26,10 @@ Render this widget into the DOM
ElementWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
// Neuter blacklisted elements
// Eliminate blacklisted elements
this.tag = this.parseTreeNode.tag;
if($tw.config.htmlUnsafeElements.indexOf(this.tag) !== -1) {
this.tag = "safe-" + this.tag;
}
// Restrict tag name to digits, letts and dashes
this.tag = this.tag.replace(/[^0-9a-zA-Z\-]/mg,"");
// Default to a span
this.tag = this.tag || "span";
// Sanitize tag name if needed according to Custom Web-Componenets spec
this.tag = $tw.utils.makeTagNameSafe(this.tag, "safe-" + this.tag);
// Adjust headings by the current base level
var headingLevel = ["h1","h2","h3","h4","h5","h6"].indexOf(this.tag);
if(headingLevel !== -1) {
+1 -3
View File
@@ -32,9 +32,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
this.execute();
// Create element
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.elementTag && $tw.config.htmlUnsafeElements.indexOf(this.elementTag) === -1) {
tag = this.elementTag;
}
tag = $tw.utils.makeTagNameSafe(this.elementTag,tag)
var domNode = this.document.createElement(tag);
this.domNode = domNode;
// Assign classes
+2 -4
View File
@@ -31,9 +31,7 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.tag && $tw.config.htmlUnsafeElements.indexOf(this.tag) === -1) {
tag = this.tag;
}
tag = $tw.utils.makeTagNameSafe(this.tag,tag);
// Create element
var domNode = this.document.createElement(tag);
// Assign classes
@@ -50,7 +48,7 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
};
KeyboardWidget.prototype.handleChangeEvent = function(event) {
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
if($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
return true;
}
+1 -3
View File
@@ -62,9 +62,7 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
var self = this;
// Sanitise the specified tag
var tag = this.linkTag;
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
tag = "a";
}
tag = $tw.utils.makeTagNameSafe(tag,"a");
// Create our element
var namespace = this.getVariable("namespace",{defaultValue: "http://www.w3.org/1999/xhtml"}),
domNode = this.document.createElementNS(namespace,tag);
+3 -5
View File
@@ -30,9 +30,7 @@ RevealWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.revealTag && $tw.config.htmlUnsafeElements.indexOf(this.revealTag) === -1) {
tag = this.revealTag;
}
tag = $tw.utils.makeTagNameSafe(this.revealTag,tag);
var domNode = this.document.createElement(tag);
this.domNode = domNode;
this.assignDomNodeClasses();
@@ -93,9 +91,9 @@ RevealWidget.prototype.positionPopup = function(domNode) {
left = Math.max(0,left);
top = Math.max(0,top);
}
if (this.popup.absolute) {
if(this.popup.absolute) {
// Traverse the offsetParent chain and correct the offset to make it relative to the parent node.
for (var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
for(var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
left -= offsetParentDomNode.offsetLeft;
top -= offsetParentDomNode.offsetTop;
}