fix: address code review feedback - validation, sanitization, docs

- Fix email validation JSDoc comment in chat.js
- Add explicit format validation for devId/project in preview routes
- Sanitize contact field input in build route
- Add detailed token estimation comment in memory-injector
- Add warning log when ws module is not available

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-11 11:50:12 +00:00
parent 6f02d67ecd
commit b4a835b8a7
5 changed files with 25 additions and 4 deletions

View File

@ -129,7 +129,9 @@ function loadProfile(devId) {
}
/**
* 粗略估算 token 数量中文约 1.5 token/英文约 0.25 token/word
* 粗略估算 token 数量
* 中文约 1.5 token/CJK字符经 BPE 分词通常为 1-2 token
* 英文/其他约 0.4 token/字符英文单词平均 4 字符 1 token
*/
function estimateTokens(text) {
if (!text) return 0;

View File

@ -40,6 +40,9 @@ router.post('/start', async (req, res) => {
});
}
// 联系方式输入清理(去除潜在 HTML/script 注入)
const safeContact = contact ? String(contact).replace(/[<>&"']/g, '').substring(0, 100) : null;
// 先立即响应,后台异步处理
res.json({
error: false,
@ -68,7 +71,7 @@ router.post('/start', async (req, res) => {
memoryManager.addProject(dev_id, {
name: result.projectName || 'untitled',
email: email,
contact: contact || null,
contact: safeContact,
status: 'completed',
created_at: new Date().toISOString(),
files: result.files || []

View File

@ -21,9 +21,18 @@ router.get('/:devId/:project', (req, res) => {
});
}
// 安全校验:防止路径遍历
// 安全校验:确保 devId 和 project 匹配预期格式(防止路径遍历
const safeDevId = path.basename(devId);
const safeProject = path.basename(project);
if (!/^[a-zA-Z0-9_-]+$/.test(safeDevId) || !/^[a-zA-Z0-9_.-]+$/.test(safeProject)) {
return res.status(400).json({
error: true,
code: 'INVALID_PARAMS',
message: '参数格式无效'
});
}
const previewDir = path.join(WORKSPACE_DIR, safeDevId, safeProject, 'preview');
const projectDir = path.join(WORKSPACE_DIR, safeDevId, safeProject);
@ -53,6 +62,10 @@ router.get('/:devId/:project/:file', (req, res) => {
const safeProject = path.basename(project);
const safeFile = path.basename(file);
if (!/^[a-zA-Z0-9_-]+$/.test(safeDevId) || !/^[a-zA-Z0-9_.-]+$/.test(safeProject) || !/^[a-zA-Z0-9_.-]+$/.test(safeFile)) {
return res.status(400).send('Invalid parameters');
}
const previewDir = path.join(WORKSPACE_DIR, safeDevId, safeProject, 'preview');
const projectDir = path.join(WORKSPACE_DIR, safeDevId, safeProject);

View File

@ -117,6 +117,7 @@ try {
};
} catch (_e) {
// ws module not installed, WebSocket disabled
console.warn('[Persona Studio] ws module not available, WebSocket features disabled');
app.locals.broadcastToClient = function () {};
}

View File

@ -606,7 +606,9 @@ function closeEmailModal() {
}
/**
* 后端二次校验用的邮箱正则
* 前端邮箱格式校验与后端 build.js 使用相同正则双重校验
* @param {string} email - 邮箱地址
* @returns {boolean} 是否合法
*/
function validateEmail(email) {
var re = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;