迁移聊天消息安全工具

This commit is contained in:
2026-04-25 19:27:39 +08:00
parent 891e18e83f
commit 4cdcaa537f
4 changed files with 125 additions and 63 deletions
+25
View File
@@ -27,3 +27,28 @@ export function escapeHtml(value) {
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;
}
}
+40
View File
@@ -0,0 +1,40 @@
// 聊天消息工具函数,承接主消息渲染脚本里可独立复用的判断逻辑。
/**
* 判断图片消息是否已经超过前端允许展示的保留期。
*
* @param {Record<string, any>|null|undefined} message 聊天消息
* @param {number} retentionDays 图片保留天数
* @param {number} nowTimestamp 当前时间戳
* @returns {boolean}
*/
export function isExpiredChatImageMessage(
message,
retentionDays = Number.parseInt(window.chatContext?.chatImageRetentionDays || 3, 10),
nowTimestamp = Date.now(),
) {
if (!message) {
return false;
}
if (message.message_type === "expired_image") {
return true;
}
if (message.message_type !== "image") {
return false;
}
if (!message.image_url || !message.image_thumb_url) {
return true;
}
const sentAtText = String(message.sent_at || "").replace(" ", "T");
const sentAt = sentAtText ? new Date(sentAtText) : null;
if (!sentAt || Number.isNaN(sentAt.getTime())) {
return false;
}
return nowTimestamp >= sentAt.getTime() + retentionDays * 24 * 60 * 60 * 1000;
}