${role.displayName}
-${role.desc || ''}
- ¥${role.price} +${name}
+${desc}
+ ¥${price}diff --git a/app.js b/app.js
index ddb42bd..fffe29e 100644
--- a/app.js
+++ b/app.js
@@ -5,6 +5,14 @@
const API_BASE = '/api';
const TOKEN_KEY = 'eternal_ai_token';
+ // 安全:转义 HTML,防止存储型 XSS(用于 innerHTML 插入的用户可控数据)
+ function escapeHtml(str) {
+ return String(str).replace(/[&<>"']/g, (ch) => {
+ const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
+ return map[ch];
+ });
+ }
+
function getToken() {
return localStorage.getItem(TOKEN_KEY) || '';
}
@@ -308,20 +316,25 @@
return;
}
listEl.innerHTML = roles
- .map(
- (role) => `
- ${role.desc || ''} ${desc}
+ .map((role) => {
+ const id = escapeHtml(role.id);
+ const name = escapeHtml(role.displayName);
+ const desc = escapeHtml(role.desc || '');
+ const avatar = escapeHtml(role.avatar || 'https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=anime%20character%20portrait&image_size=square');
+ const price = escapeHtml(role.price);
+ return `
+
${role.displayName}
- ${name}
+
加载失败:${err.message}
`; + listEl.innerHTML = `加载失败:${escapeHtml(err.message)}
`; } } @@ -335,7 +348,7 @@ document.getElementById('detail-hero').style.backgroundImage = `url(${role.avatar || ''})`; document.getElementById('detail-role-name').textContent = role.displayName; document.getElementById('detail-role-desc').textContent = role.desc || role.personality || ''; - document.getElementById('detail-price').innerHTML = `¥${role.price}/ 月`; + document.getElementById('detail-price').innerHTML = `¥${escapeHtml(role.price)}/ 月`; document.getElementById('detail-actions-pre').hidden = false; document.getElementById('detail-paid').hidden = true; @@ -411,20 +424,25 @@ return; } listEl.innerHTML = roles - .map( - (role) => ` -加载失败:${err.message}
`; + listEl.innerHTML = `加载失败:${escapeHtml(err.message)}
`; } } @@ -437,16 +455,19 @@ return; } listEl.innerHTML = income.records - .map( - (r) => ` + .map((r) => { + const role = escapeHtml(r.role); + const time = escapeHtml(r.time); + const amount = r.amount.toFixed(2); + return `