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

View file

@ -0,0 +1,481 @@
/**
* Threshold Manager
* Configurable notification thresholds for security threat detection
* CWE-778 Compliance: Logs all threshold configurations and evaluations
*/
const logger = require('./logger');
const logAggregator = require('./logAggregator');
const { db } = require('../database/db');
class ThresholdManager {
constructor() {
this.thresholds = new Map();
this.initialize();
}
/**
* Initialize threshold manager
*/
async initialize() {
await this.createThresholdsTable();
await this.loadThresholds();
logger.info('[ThresholdManager] Initialized with configurable thresholds');
// Log initialization (CWE-778)
logAggregator.aggregate('threshold_manager', 'info', 'security', 'Threshold manager initialized', {
totalThresholds: this.thresholds.size
});
}
/**
* Create thresholds table
*/
async createThresholdsTable() {
return new Promise((resolve, reject) => {
db.run(`
CREATE TABLE IF NOT EXISTS security_thresholds (
id INTEGER PRIMARY KEY AUTOINCREMENT,
threshold_id TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
description TEXT,
pattern_type TEXT NOT NULL,
metric_name TEXT NOT NULL,
operator TEXT NOT NULL,
threshold_value INTEGER NOT NULL,
time_window_minutes INTEGER DEFAULT 30,
severity TEXT NOT NULL,
enabled INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`, async (err) => {
if (err) reject(err);
else {
db.run(`CREATE INDEX IF NOT EXISTS idx_thresholds_pattern ON security_thresholds(pattern_type, enabled)`);
db.run(`CREATE INDEX IF NOT EXISTS idx_thresholds_enabled ON security_thresholds(enabled)`);
await this.createDefaultThresholds();
resolve();
}
});
});
}
/**
* Create default thresholds for common security patterns
*/
async createDefaultThresholds() {
const defaultThresholds = [
{
threshold_id: 'THRESHOLD-BRUTE-FORCE',
name: 'Brute Force Attack Threshold',
description: 'Alert when failed login attempts exceed threshold',
pattern_type: 'brute_force_attack',
metric_name: 'failed_login_count',
operator: '>=',
threshold_value: 5,
time_window_minutes: 10,
severity: 'critical'
},
{
threshold_id: 'THRESHOLD-CREDENTIAL-STUFFING',
name: 'Credential Stuffing Threshold',
description: 'Alert on multiple username attempts from same IP',
pattern_type: 'credential_stuffing',
metric_name: 'unique_username_count',
operator: '>=',
threshold_value: 5,
time_window_minutes: 5,
severity: 'critical'
},
{
threshold_id: 'THRESHOLD-PRIVILEGE-ESC',
name: 'Privilege Escalation Threshold',
description: 'Alert on repeated unauthorized access attempts',
pattern_type: 'privilege_escalation',
metric_name: 'escalation_attempt_count',
operator: '>=',
threshold_value: 3,
time_window_minutes: 30,
severity: 'critical'
},
{
threshold_id: 'THRESHOLD-SUSPICIOUS-IP',
name: 'Suspicious IP Activity Threshold',
description: 'Alert on excessive requests from single IP',
pattern_type: 'suspicious_ip',
metric_name: 'request_count',
operator: '>=',
threshold_value: 100,
time_window_minutes: 15,
severity: 'high'
},
{
threshold_id: 'THRESHOLD-DATA-EXFIL',
name: 'Data Exfiltration Threshold',
description: 'Alert on excessive data downloads',
pattern_type: 'data_exfiltration',
metric_name: 'download_count',
operator: '>=',
threshold_value: 10,
time_window_minutes: 60,
severity: 'high'
},
{
threshold_id: 'THRESHOLD-SESSION-ANOMALY',
name: 'Session Anomaly Threshold',
description: 'Alert on unusual session patterns',
pattern_type: 'session_anomaly',
metric_name: 'anomaly_score',
operator: '>=',
threshold_value: 70,
time_window_minutes: 30,
severity: 'medium'
},
{
threshold_id: 'THRESHOLD-IMPOSSIBLE-TRAVEL',
name: 'Impossible Travel Threshold',
description: 'Alert on geographically impossible travel speed',
pattern_type: 'impossible_travel',
metric_name: 'travel_speed_kmh',
operator: '>=',
threshold_value: 800,
time_window_minutes: 60,
severity: 'high'
},
{
threshold_id: 'THRESHOLD-THREAT-SCORE',
name: 'Critical Threat Score Threshold',
description: 'Alert when overall threat score is critical',
pattern_type: 'threat_score',
metric_name: 'threat_score',
operator: '>=',
threshold_value: 80,
time_window_minutes: 60,
severity: 'critical'
}
];
for (const threshold of defaultThresholds) {
await new Promise((resolve, reject) => {
db.run(
`INSERT OR IGNORE INTO security_thresholds
(threshold_id, name, description, pattern_type, metric_name, operator, threshold_value, time_window_minutes, severity)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
threshold.threshold_id,
threshold.name,
threshold.description,
threshold.pattern_type,
threshold.metric_name,
threshold.operator,
threshold.threshold_value,
threshold.time_window_minutes,
threshold.severity
],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
}
logger.info(`[ThresholdManager] Created ${defaultThresholds.length} default thresholds`);
}
/**
* Load thresholds from database into memory
*/
async loadThresholds() {
return new Promise((resolve, reject) => {
db.all(
`SELECT * FROM security_thresholds WHERE enabled = 1`,
[],
(err, rows) => {
if (err) {
reject(err);
} else {
this.thresholds.clear();
rows.forEach(row => {
this.thresholds.set(row.threshold_id, row);
});
logger.info(`[ThresholdManager] Loaded ${rows.length} active thresholds`);
resolve();
}
}
);
});
}
/**
* Evaluate if a metric value exceeds threshold
* CWE-778: Logs all threshold evaluations
*/
async evaluateThreshold(patternType, metricName, value, context = {}) {
const matchingThresholds = Array.from(this.thresholds.values()).filter(
t => t.pattern_type === patternType && t.metric_name === metricName
);
if (matchingThresholds.length === 0) {
return { exceeded: false, thresholds: [] };
}
const exceededThresholds = [];
for (const threshold of matchingThresholds) {
const exceeded = this.compareValue(value, threshold.operator, threshold.threshold_value);
// Log threshold evaluation (CWE-778)
logAggregator.aggregate('threshold_manager', 'info', 'security', 'Threshold evaluated', {
thresholdId: threshold.threshold_id,
patternType,
metricName,
value,
operator: threshold.operator,
thresholdValue: threshold.threshold_value,
exceeded,
severity: threshold.severity,
context
});
if (exceeded) {
exceededThresholds.push({
...threshold,
actualValue: value,
context
});
logger.warn(`[ThresholdManager] Threshold exceeded: ${threshold.name} (${value} ${threshold.operator} ${threshold.threshold_value})`);
}
}
return {
exceeded: exceededThresholds.length > 0,
thresholds: exceededThresholds
};
}
/**
* Compare value against threshold using operator
*/
compareValue(value, operator, threshold) {
switch (operator) {
case '>=': return value >= threshold;
case '>': return value > threshold;
case '<=': return value <= threshold;
case '<': return value < threshold;
case '==': return value == threshold;
case '!=': return value != threshold;
default: return false;
}
}
/**
* Get all thresholds
*/
async getThresholds(filters = {}) {
const { patternType, enabled, limit = 100 } = filters;
let whereClause = [];
let params = [];
if (patternType) {
whereClause.push('pattern_type = ?');
params.push(patternType);
}
if (enabled !== undefined) {
whereClause.push('enabled = ?');
params.push(enabled ? 1 : 0);
}
const where = whereClause.length > 0 ? `WHERE ${whereClause.join(' AND ')}` : '';
params.push(limit);
return new Promise((resolve, reject) => {
db.all(
`SELECT * FROM security_thresholds ${where}
ORDER BY pattern_type, threshold_value DESC
LIMIT ?`,
params,
(err, rows) => {
if (err) reject(err);
else resolve(rows);
}
);
});
}
/**
* Get threshold by ID
*/
async getThresholdById(thresholdId) {
return new Promise((resolve, reject) => {
db.get(
`SELECT * FROM security_thresholds WHERE threshold_id = ?`,
[thresholdId],
(err, row) => {
if (err) reject(err);
else resolve(row);
}
);
});
}
/**
* Create new threshold
* CWE-778: Logs threshold creation
*/
async createThreshold(data, userId) {
const thresholdId = `THRESHOLD-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
return new Promise((resolve, reject) => {
db.run(
`INSERT INTO security_thresholds
(threshold_id, name, description, pattern_type, metric_name, operator, threshold_value, time_window_minutes, severity, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
thresholdId,
data.name,
data.description || '',
data.pattern_type,
data.metric_name,
data.operator,
data.threshold_value,
data.time_window_minutes || 30,
data.severity,
data.enabled !== undefined ? (data.enabled ? 1 : 0) : 1
],
async (err) => {
if (err) {
reject(err);
} else {
await this.loadThresholds();
// Log threshold creation (CWE-778)
logAggregator.aggregate('threshold_manager', 'info', 'security', 'Threshold created', {
thresholdId,
userId,
name: data.name,
patternType: data.pattern_type,
metricName: data.metric_name,
thresholdValue: data.threshold_value,
severity: data.severity
});
logger.info(`[ThresholdManager] Threshold created: ${thresholdId} by user ${userId}`);
resolve({ thresholdId });
}
}
);
});
}
/**
* Update threshold
* CWE-778: Logs threshold modifications
*/
async updateThreshold(thresholdId, updates, userId) {
const allowedFields = ['name', 'description', 'operator', 'threshold_value', 'time_window_minutes', 'severity', 'enabled'];
const setClause = [];
const params = [];
for (const [key, value] of Object.entries(updates)) {
if (allowedFields.includes(key)) {
setClause.push(`${key} = ?`);
params.push(key === 'enabled' ? (value ? 1 : 0) : value);
}
}
if (setClause.length === 0) {
throw new Error('No valid fields to update');
}
setClause.push('updated_at = CURRENT_TIMESTAMP');
params.push(thresholdId);
return new Promise((resolve, reject) => {
db.run(
`UPDATE security_thresholds
SET ${setClause.join(', ')}
WHERE threshold_id = ?`,
params,
async (err) => {
if (err) {
reject(err);
} else {
await this.loadThresholds();
// Log threshold update (CWE-778)
logAggregator.aggregate('threshold_manager', 'info', 'security', 'Threshold updated', {
thresholdId,
userId,
updates
});
logger.info(`[ThresholdManager] Threshold updated: ${thresholdId} by user ${userId}`);
resolve({ success: true });
}
}
);
});
}
/**
* Delete threshold
* CWE-778: Logs threshold deletion
*/
async deleteThreshold(thresholdId, userId) {
return new Promise((resolve, reject) => {
db.run(
`DELETE FROM security_thresholds WHERE threshold_id = ?`,
[thresholdId],
async (err) => {
if (err) {
reject(err);
} else {
await this.loadThresholds();
// Log threshold deletion (CWE-778)
logAggregator.aggregate('threshold_manager', 'warn', 'security', 'Threshold deleted', {
thresholdId,
userId
});
logger.info(`[ThresholdManager] Threshold deleted: ${thresholdId} by user ${userId}`);
resolve({ success: true });
}
}
);
});
}
/**
* Get threshold statistics
*/
async getStatistics() {
return new Promise((resolve, reject) => {
db.get(
`SELECT
COUNT(*) as total,
SUM(CASE WHEN enabled = 1 THEN 1 ELSE 0 END) as enabled,
SUM(CASE WHEN enabled = 0 THEN 1 ELSE 0 END) as disabled,
COUNT(DISTINCT pattern_type) as unique_patterns,
COUNT(DISTINCT severity) as unique_severities
FROM security_thresholds`,
[],
(err, row) => {
if (err) reject(err);
else resolve(row);
}
);
});
}
}
// Create singleton instance
const thresholdManager = new ThresholdManager();
module.exports = thresholdManager;