@nuxtjs/mdc
Version:
Nuxt MDC module
56 lines (55 loc) • 1.49 kB
JavaScript
export const unsafeLinkPrefix = [
"javascript:",
"data:text/html",
"vbscript:",
"data:text/javascript",
"data:text/vbscript",
"data:text/css",
"data:text/plain",
"data:text/xml"
];
function isAnchorLinkAllowed(value) {
const decodedUrl = decodeURIComponent(value);
const urlSanitized = decodedUrl.replace(/&#x([0-9a-f]+);?/gi, "").replace(/&#(\d+);?/g, "").replace(/&[a-z]+;?/gi, "");
try {
const url = new URL(urlSanitized, "http://example.com");
if (url.origin === "http://example.com") {
return true;
}
if (unsafeLinkPrefix.some((prefix) => url.protocol.toLowerCase().startsWith(prefix))) {
return false;
}
} catch {
return false;
}
return true;
}
export const validateProp = (attribute, value) => {
if (attribute.startsWith("on")) {
return false;
}
if (attribute === "href" || attribute === "src") {
return isAnchorLinkAllowed(value);
}
return true;
};
export const validateProps = (type, props) => {
if (!props) {
return {};
}
props = Object.fromEntries(
Object.entries(props).filter(([name, value]) => {
const isValid = validateProp(name, value);
if (!isValid) {
console.warn(`[@nuxtjs/mdc] removing unsafe attribute: ${name}="${value}"`);
}
return isValid;
})
);
if (type === "pre") {
if (typeof props.highlights === "string") {
props.highlights = props.highlights.split(" ").map((i) => Number.parseInt(i));
}
}
return props;
};