Files
yunrui_asset/backend/routes/background.js
T
zhang96110 6eda3ae1f2 fix(security): 修复多个严重安全漏洞和运行时崩溃
- devices.js: 修复 hasRoomField 重复 const 声明导致模块加载失败
- devices.js: 修复 batch-status 路由 affectedCount 未定义导致崩溃
- devices.js: 修复 sequelize.literal SQL 注入,转义 LIKE 通配符和字段名
- server.js: 修复 initializeApp() 未 await 导致服务器在初始化前接收请求
- backup.js: 添加 resolveBackupPath() 防止路径遍历攻击(6处)
- inventory.js: 用 bulkCreate 替代原始 SQL 拼接,消除 SQL 注入
- systemSettings.js: 添加全局 authMiddleware,修复敏感操作无认证
- dangerousOperations.js: 添加全局认证,修复日志清理功能完全不可用
- background.js: 添加文件名安全检查、扩展名白名单、路径校验
2026-04-01 06:02:55 +00:00

122 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const express = require('express');
const path = require('path');
const fs = require('fs');
const router = express.Router();
const UPLOAD_DIR = path.join(__dirname, '../uploads');
if (!fs.existsSync(UPLOAD_DIR)) {
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}
const SETTINGS_FILE = path.join(__dirname, '../backgroundSettings.json');
if (!fs.existsSync(SETTINGS_FILE)) {
fs.writeFileSync(
SETTINGS_FILE,
JSON.stringify(
{
type: 'gradient',
image: '',
size: 'contain',
},
null,
2
)
);
}
router.get('/', (req, res) => {
try {
const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
res.json({
success: true,
data: settings,
});
} catch (error) {
console.error('读取背景设置失败:', error);
res.status(500).json({ error: '读取背景设置失败' });
}
});
router.put('/', (req, res) => {
try {
const settings = req.body;
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
res.json({
success: true,
data: settings,
});
} catch (error) {
console.error('保存背景设置失败:', error);
res.status(500).json({ error: '保存背景设置失败' });
}
});
router.post('/upload', (req, res) => {
try {
if (!req.files || !req.files.file) {
return res.status(400).json({ error: '没有上传文件' });
}
const file = req.files.file;
// 安全检查:拒绝路径遍历字符
if (file.name.includes('..') || file.name.includes('/') || file.name.includes('\\')) {
return res.status(400).json({ error: '文件名包含非法字符' });
}
// 白名单校验文件扩展名,只允许图片格式
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp'];
const ext = path.extname(file.name).toLowerCase();
if (!allowedExtensions.includes(ext)) {
return res.status(400).json({ error: '只允许上传图片文件(jpg/png/gif/webp/svg/bmp' });
}
// 使用随机文件名,仅保留安全扩展名
const safeName = `${Date.now()}_${Math.random().toString(36).slice(2, 10)}${ext}`;
const filePath = path.join(UPLOAD_DIR, safeName);
// 二次校验:确保路径在 uploads 目录内
const resolvedPath = path.resolve(filePath);
const resolvedUploadDir = path.resolve(UPLOAD_DIR);
if (!resolvedPath.startsWith(resolvedUploadDir + path.sep)) {
return res.status(400).json({ error: '文件路径不合法' });
}
file.mv(filePath, err => {
if (err) {
console.error('文件保存失败:', err);
return res.status(500).json({ error: '文件保存失败' });
}
const fileUrl = `/uploads/${safeName}`;
res.json({ path: fileUrl });
});
} catch (error) {
console.error('上传错误:', error);
res.status(500).json({ error: '上传失败' });
}
});
router.get('/settings', (req, res) => {
try {
const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
res.json(settings);
} catch (error) {
console.error('读取背景设置失败:', error);
res.status(500).json({ error: '读取背景设置失败' });
}
});
router.post('/settings', (req, res) => {
try {
const settings = req.body;
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
res.json({ success: true });
} catch (error) {
console.error('保存背景设置失败:', error);
res.status(500).json({ error: '保存背景设置失败' });
}
});
module.exports = router;