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:
parent
6f02d67ecd
commit
b4a835b8a7
|
|
@ -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) {
|
function estimateTokens(text) {
|
||||||
if (!text) return 0;
|
if (!text) return 0;
|
||||||
|
|
|
||||||
|
|
@ -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({
|
res.json({
|
||||||
error: false,
|
error: false,
|
||||||
|
|
@ -68,7 +71,7 @@ router.post('/start', async (req, res) => {
|
||||||
memoryManager.addProject(dev_id, {
|
memoryManager.addProject(dev_id, {
|
||||||
name: result.projectName || 'untitled',
|
name: result.projectName || 'untitled',
|
||||||
email: email,
|
email: email,
|
||||||
contact: contact || null,
|
contact: safeContact,
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
created_at: new Date().toISOString(),
|
created_at: new Date().toISOString(),
|
||||||
files: result.files || []
|
files: result.files || []
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,18 @@ router.get('/:devId/:project', (req, res) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安全校验:防止路径遍历
|
// 安全校验:确保 devId 和 project 匹配预期格式(防止路径遍历)
|
||||||
const safeDevId = path.basename(devId);
|
const safeDevId = path.basename(devId);
|
||||||
const safeProject = path.basename(project);
|
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 previewDir = path.join(WORKSPACE_DIR, safeDevId, safeProject, 'preview');
|
||||||
const projectDir = path.join(WORKSPACE_DIR, safeDevId, safeProject);
|
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 safeProject = path.basename(project);
|
||||||
const safeFile = path.basename(file);
|
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 previewDir = path.join(WORKSPACE_DIR, safeDevId, safeProject, 'preview');
|
||||||
const projectDir = path.join(WORKSPACE_DIR, safeDevId, safeProject);
|
const projectDir = path.join(WORKSPACE_DIR, safeDevId, safeProject);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ try {
|
||||||
};
|
};
|
||||||
} catch (_e) {
|
} catch (_e) {
|
||||||
// ws module not installed, WebSocket disabled
|
// ws module not installed, WebSocket disabled
|
||||||
|
console.warn('[Persona Studio] ws module not available, WebSocket features disabled');
|
||||||
app.locals.broadcastToClient = function () {};
|
app.locals.broadcastToClient = function () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -606,7 +606,9 @@ function closeEmailModal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 后端二次校验用的邮箱正则
|
* 前端邮箱格式校验(与后端 build.js 使用相同正则,双重校验)
|
||||||
|
* @param {string} email - 邮箱地址
|
||||||
|
* @returns {boolean} 是否合法
|
||||||
*/
|
*/
|
||||||
function validateEmail(email) {
|
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])?)*$/;
|
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])?)*$/;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue