Initial commit: StreamFlow IPTV platform

This commit is contained in:
aiulian25 2025-12-17 00:42:43 +00:00
commit 73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions

218
backend/routes/csp.js Normal file
View file

@ -0,0 +1,218 @@
const express = require('express');
const router = express.Router();
const { authenticate, requireAdmin } = require('../middleware/auth');
const logger = require('../utils/logger');
const { db } = require('../database/db');
// Store CSP violations in database
db.run(`
CREATE TABLE IF NOT EXISTS csp_violations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_uri TEXT,
violated_directive TEXT,
blocked_uri TEXT,
source_file TEXT,
line_number INTEGER,
column_number INTEGER,
user_agent TEXT,
ip_address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// CSP violation reporting endpoint (no auth required)
router.post('/report', express.json({ type: 'application/csp-report' }), (req, res) => {
const report = req.body['csp-report'];
const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const userAgent = req.headers['user-agent'];
if (!report) {
return res.status(400).json({ error: 'Invalid CSP report' });
}
logger.warn('CSP Violation:', {
documentUri: report['document-uri'],
violatedDirective: report['violated-directive'],
blockedUri: report['blocked-uri'],
sourceFile: report['source-file'],
lineNumber: report['line-number'],
columnNumber: report['column-number'],
ip,
userAgent
});
// Store in database
db.run(
`INSERT INTO csp_violations
(document_uri, violated_directive, blocked_uri, source_file, line_number, column_number, user_agent, ip_address)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[
report['document-uri'],
report['violated-directive'],
report['blocked-uri'],
report['source-file'],
report['line-number'],
report['column-number'],
userAgent,
ip
],
(err) => {
if (err) {
logger.error('Failed to store CSP violation:', err);
}
}
);
res.status(204).end();
});
// Get CSP violations (admin only)
router.get('/violations', authenticate, requireAdmin, (req, res) => {
const { limit = 100, offset = 0 } = req.query;
db.all(
`SELECT * FROM csp_violations
ORDER BY created_at DESC
LIMIT ? OFFSET ?`,
[parseInt(limit), parseInt(offset)],
(err, violations) => {
if (err) {
logger.error('Failed to fetch CSP violations:', err);
return res.status(500).json({ error: 'Failed to fetch violations' });
}
// Get total count
db.get('SELECT COUNT(*) as total FROM csp_violations', (countErr, countResult) => {
if (countErr) {
logger.error('Failed to count CSP violations:', countErr);
return res.status(500).json({ error: 'Failed to count violations' });
}
res.json({
violations,
total: countResult.total,
limit: parseInt(limit),
offset: parseInt(offset)
});
});
}
);
});
// Get CSP violation statistics (admin only)
router.get('/stats', authenticate, requireAdmin, (req, res) => {
const { days = 7 } = req.query;
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));
Promise.all([
// Total violations
new Promise((resolve, reject) => {
db.get(
'SELECT COUNT(*) as total FROM csp_violations WHERE created_at >= ?',
[cutoffDate.toISOString()],
(err, row) => err ? reject(err) : resolve(row.total)
);
}),
// By directive
new Promise((resolve, reject) => {
db.all(
`SELECT violated_directive, COUNT(*) as count
FROM csp_violations
WHERE created_at >= ?
GROUP BY violated_directive
ORDER BY count DESC
LIMIT 10`,
[cutoffDate.toISOString()],
(err, rows) => err ? reject(err) : resolve(rows)
);
}),
// By blocked URI
new Promise((resolve, reject) => {
db.all(
`SELECT blocked_uri, COUNT(*) as count
FROM csp_violations
WHERE created_at >= ?
GROUP BY blocked_uri
ORDER BY count DESC
LIMIT 10`,
[cutoffDate.toISOString()],
(err, rows) => err ? reject(err) : resolve(rows)
);
}),
// Recent violations
new Promise((resolve, reject) => {
db.all(
`SELECT * FROM csp_violations
WHERE created_at >= ?
ORDER BY created_at DESC
LIMIT 20`,
[cutoffDate.toISOString()],
(err, rows) => err ? reject(err) : resolve(rows)
);
})
])
.then(([total, byDirective, byUri, recent]) => {
res.json({
total,
byDirective,
byUri,
recent,
days: parseInt(days)
});
})
.catch((err) => {
logger.error('Failed to fetch CSP stats:', err);
res.status(500).json({ error: 'Failed to fetch statistics' });
});
});
// Clear old CSP violations (admin only)
router.delete('/violations', authenticate, requireAdmin, (req, res) => {
const { days = 30 } = req.query;
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));
db.run(
'DELETE FROM csp_violations WHERE created_at < ?',
[cutoffDate.toISOString()],
function(err) {
if (err) {
logger.error('Failed to delete old CSP violations:', err);
return res.status(500).json({ error: 'Failed to delete violations' });
}
res.json({
message: 'Old violations cleared',
deleted: this.changes
});
}
);
});
// Get current CSP policy (authenticated users)
router.get('/policy', authenticate, (req, res) => {
const isProduction = process.env.NODE_ENV === 'production';
res.json({
mode: isProduction ? 'enforce' : 'report-only',
policy: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://www.gstatic.com"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "blob:", "https:", "http:"],
mediaSrc: ["'self'", "blob:", "data:", "mediastream:", "https:", "http:", "*"],
connectSrc: ["'self'", "https:", "http:", "ws:", "wss:", "blob:", "*"],
frameSrc: ["'self'", "https://www.youtube.com", "https://player.vimeo.com"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'self'"],
upgradeInsecureRequests: isProduction
},
reportUri: '/api/csp/report'
});
});
module.exports = router;