55 lines
1.3 KiB
JavaScript
55 lines
1.3 KiB
JavaScript
// 聊天室前端 HTML 安全工具,供 Blade 内联脚本迁移到 Vite 后复用。
|
|
|
|
const HTML_ESCAPE_MAP = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
};
|
|
|
|
/**
|
|
* 转义可被拼入 innerHTML 的动态文本。
|
|
*
|
|
* @param {unknown} value
|
|
* @returns {string}
|
|
*/
|
|
export function escapeHtml(value) {
|
|
return String(value ?? "").replace(/[&<>"']/g, (char) => HTML_ESCAPE_MAP[char]);
|
|
}
|
|
|
|
/**
|
|
* 转义多行文本,并保留换行展示。
|
|
*
|
|
* @param {unknown} value
|
|
* @returns {string}
|
|
*/
|
|
export function escapeHtmlWithLineBreaks(value) {
|
|
return escapeHtml(value).replace(/\n/g, "<br>");
|
|
}
|
|
|
|
/**
|
|
* 规整广播携带的链接,只允许当前站点的 http(s) 地址进入 innerHTML。
|
|
*
|
|
* @param {string|null|undefined} url 原始链接
|
|
* @param {string} fallback 回退链接
|
|
* @returns {string}
|
|
*/
|
|
export function normalizeSafeChatUrl(url, fallback) {
|
|
try {
|
|
const parsedUrl = new URL(url || fallback, window.location.origin);
|
|
|
|
if (!["http:", "https:"].includes(parsedUrl.protocol)) {
|
|
return fallback;
|
|
}
|
|
|
|
if (parsedUrl.origin !== window.location.origin) {
|
|
return fallback;
|
|
}
|
|
|
|
return parsedUrl.toString();
|
|
} catch (error) {
|
|
return fallback;
|
|
}
|
|
}
|