135 lines
3.7 KiB
JavaScript
135 lines
3.7 KiB
JavaScript
|
|
const express = require('express');
|
||
|
|
const router = express.Router();
|
||
|
|
const { authenticate } = require('../middleware/auth');
|
||
|
|
const { modifyLimiter, readLimiter } = require('../middleware/rateLimiter');
|
||
|
|
const { db } = require('../database/db');
|
||
|
|
const { validateSettings } = require('../middleware/inputValidation');
|
||
|
|
const logger = require('../utils/logger');
|
||
|
|
|
||
|
|
const SecurityAuditLogger = require('../utils/securityAudit');
|
||
|
|
|
||
|
|
// Get user settings
|
||
|
|
router.get('/', authenticate, readLimiter, async (req, res) => {
|
||
|
|
const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||
|
|
const userAgent = req.headers['user-agent'];
|
||
|
|
|
||
|
|
db.all(
|
||
|
|
'SELECT key, value FROM settings WHERE user_id = ?',
|
||
|
|
[req.user.userId],
|
||
|
|
async (err, settings) => {
|
||
|
|
if (err) {
|
||
|
|
return res.status(500).json({ error: 'Failed to fetch settings' });
|
||
|
|
}
|
||
|
|
|
||
|
|
// CWE-778: Log sensitive data access
|
||
|
|
await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'settings', {
|
||
|
|
ip,
|
||
|
|
userAgent,
|
||
|
|
recordCount: settings.length,
|
||
|
|
scope: 'own',
|
||
|
|
accessMethod: 'view'
|
||
|
|
});
|
||
|
|
|
||
|
|
// Convert array to object
|
||
|
|
const settingsObj = {};
|
||
|
|
settings.forEach(s => {
|
||
|
|
try {
|
||
|
|
settingsObj[s.key] = JSON.parse(s.value);
|
||
|
|
} catch {
|
||
|
|
settingsObj[s.key] = s.value;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
res.json(settingsObj);
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Update setting
|
||
|
|
router.put('/:key', authenticate, modifyLimiter, validateSettings, (req, res) => {
|
||
|
|
const { key } = req.params;
|
||
|
|
const { value } = req.body;
|
||
|
|
|
||
|
|
const jsonValue = typeof value === 'string' ? value : JSON.stringify(value);
|
||
|
|
|
||
|
|
db.run(
|
||
|
|
`INSERT INTO settings (user_id, key, value, updated_at)
|
||
|
|
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
|
||
|
|
ON CONFLICT(user_id, key)
|
||
|
|
DO UPDATE SET value = ?, updated_at = CURRENT_TIMESTAMP`,
|
||
|
|
[req.user.userId, key, jsonValue, jsonValue],
|
||
|
|
function(err) {
|
||
|
|
if (err) {
|
||
|
|
return res.status(500).json({ error: 'Failed to update setting' });
|
||
|
|
}
|
||
|
|
res.json({ key, value });
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Get specific setting
|
||
|
|
router.get('/:key', authenticate, readLimiter, (req, res) => {
|
||
|
|
const { key } = req.params;
|
||
|
|
|
||
|
|
// Validate key format
|
||
|
|
if (!key || !/^[a-zA-Z0-9_.-]+$/.test(key)) {
|
||
|
|
return res.status(400).json({ error: 'Invalid setting key' });
|
||
|
|
}
|
||
|
|
|
||
|
|
// Handle stream_settings specially - return defaults if not found
|
||
|
|
if (key === 'stream_settings') {
|
||
|
|
db.get(
|
||
|
|
'SELECT value FROM settings WHERE user_id = ? AND key = ?',
|
||
|
|
[req.user.userId, key],
|
||
|
|
(err, setting) => {
|
||
|
|
if (err) {
|
||
|
|
return res.status(500).json({ error: 'Failed to fetch setting' });
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return defaults if not found
|
||
|
|
if (!setting) {
|
||
|
|
return res.json({
|
||
|
|
value: {
|
||
|
|
hwaccel: 'auto',
|
||
|
|
hwaccel_device: '/dev/dri/renderD128',
|
||
|
|
codec: 'h264',
|
||
|
|
preset: 'veryfast',
|
||
|
|
buffer_size: '2M',
|
||
|
|
max_bitrate: '8M'
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
res.json({ value: JSON.parse(setting.value) });
|
||
|
|
} catch {
|
||
|
|
res.json({ value: setting.value });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
db.get(
|
||
|
|
'SELECT value FROM settings WHERE user_id = ? AND key = ?',
|
||
|
|
[req.user.userId, key],
|
||
|
|
(err, setting) => {
|
||
|
|
if (err) {
|
||
|
|
return res.status(500).json({ error: 'Failed to fetch setting' });
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!setting) {
|
||
|
|
return res.status(404).json({ error: 'Setting not found' });
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
res.json({ value: JSON.parse(setting.value) });
|
||
|
|
} catch {
|
||
|
|
res.json({ value: setting.value });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = router;
|