release: WRNexusJS 0.7.0
This commit is contained in:
@@ -77,6 +77,38 @@ function isHtmlBooleanAttribute(name: string): boolean {
|
||||
return HTML_BOOLEAN_ATTRIBUTES.has(name.toLowerCase());
|
||||
}
|
||||
|
||||
const URL_ATTRIBUTES = new Set([
|
||||
"href",
|
||||
"src",
|
||||
"action",
|
||||
"formaction",
|
||||
"poster",
|
||||
"cite",
|
||||
"background",
|
||||
"xlink:href",
|
||||
]);
|
||||
|
||||
function stripAsciiControlAndSpace(value: string): string {
|
||||
let result = "";
|
||||
for (const character of value) {
|
||||
if (character.charCodeAt(0) > 0x20) result += character;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function sanitizeUrlAttribute(value: string): string {
|
||||
const compact = stripAsciiControlAndSpace(value.trim());
|
||||
const lower = compact.toLowerCase();
|
||||
if (/^(?:javascript|vbscript|file):/.test(lower)) return "about:blank";
|
||||
if (/^data:(?!image\/(?:png|gif|jpeg|webp|avif);)/.test(lower)) return "about:blank";
|
||||
return value;
|
||||
}
|
||||
|
||||
function safeAttributeValue(name: string, value: string): string {
|
||||
if (!URL_ATTRIBUTES.has(name.toLowerCase()) || value.includes("{")) return value;
|
||||
return sanitizeUrlAttribute(value);
|
||||
}
|
||||
|
||||
/** Escape a value placed inside a double-quoted HTML attribute. */
|
||||
function attrEscape(value: string): string {
|
||||
return value
|
||||
@@ -110,7 +142,9 @@ function renderAttr(attr: Attr): string {
|
||||
case "csrText":
|
||||
return "";
|
||||
default:
|
||||
return attr.boolean ? ` ${attr.name}` : ` ${attr.name}="${attrEscape(attr.value)}"`;
|
||||
return attr.boolean
|
||||
? ` ${attr.name}`
|
||||
: ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +210,7 @@ function renderAttrs(
|
||||
const initial = reactiveAttrValue(attr.value, reactive);
|
||||
if (initial === null) return base;
|
||||
const marker = JSON.stringify([attr.name, attr.value]);
|
||||
return ` ${attr.name}="${attrEscape(initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
|
||||
return ` ${attr.name}="${attrEscape(URL_ATTRIBUTES.has(attr.name.toLowerCase()) ? sanitizeUrlAttribute(initial) : initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
|
||||
})
|
||||
.join("");
|
||||
return csrId ? `${rendered} data-wrnexus-csr="${attrEscape(csrId)}"` : rendered;
|
||||
@@ -2148,7 +2182,7 @@ function renderPageComponentAttr(attr: Attr, dynamicExpressions: string[]): stri
|
||||
const expression = wholeAttributeExpression(attr.value);
|
||||
|
||||
if (!expression) {
|
||||
return ` ${attr.name}="${attrEscape(attr.value)}"`;
|
||||
return ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`;
|
||||
}
|
||||
|
||||
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
||||
|
||||
Reference in New Issue
Block a user