|
|
const fs = require('fs'); |
|
|
const path = require('path'); |
|
|
|
|
|
class SecurityLogger { |
|
|
constructor(config = {}) { |
|
|
this.config = config; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const isHF = !!process.env.SPACE_ID; |
|
|
const basePath = isHF |
|
|
? '/tmp/akira_data' |
|
|
: process.env.DATA_PATH || path.resolve('data'); |
|
|
|
|
|
this.logsPath = path.join(basePath, 'security_logs'); |
|
|
this.alertsPath = path.join(this.logsPath, 'alerts.json'); |
|
|
this.opsPath = path.join(this.logsPath, 'operations.json'); |
|
|
|
|
|
try { |
|
|
fs.mkdirSync(this.logsPath, { recursive: true }); |
|
|
console.log(`✅ SecurityLogger: Diretório ativo: ${this.logsPath}`); |
|
|
} catch (err) { |
|
|
console.error('❌ SecurityLogger: Falha ao criar diretório:', err.message); |
|
|
this.logsPath = null; |
|
|
} |
|
|
|
|
|
this.operations = this.logsPath ? this._loadJSON(this.opsPath, []) : []; |
|
|
this.alerts = this.logsPath ? this._loadJSON(this.alertsPath, []) : []; |
|
|
|
|
|
console.log('✅ SecurityLogger inicializado'); |
|
|
} |
|
|
|
|
|
logOperation(operacao) { |
|
|
if (!this.logsPath) return; |
|
|
|
|
|
try { |
|
|
const entry = { |
|
|
id: `${Date.now()}_${Math.random().toString(36).slice(2, 9)}`, |
|
|
timestamp: new Date().toISOString(), |
|
|
usuario: operacao.usuario || 'UNKNOWN', |
|
|
tipoOperacao: operacao.tipo, |
|
|
alvo: operacao.alvo, |
|
|
resultado: operacao.resultado, |
|
|
risco: operacao.risco || 'BAIXO', |
|
|
detalhes: operacao.detalhes || {}, |
|
|
ipOrigem: operacao.ipOrigem || 'N/A', |
|
|
duracao: operacao.duracao || 0 |
|
|
}; |
|
|
|
|
|
this.operations.push(entry); |
|
|
this._saveJSON(this.opsPath, this.operations); |
|
|
|
|
|
if (this._isSuspicious(entry)) { |
|
|
this._createAlert(entry); |
|
|
} |
|
|
|
|
|
console.log(`📋 [SECURITY] ${entry.tipoOperacao} → ${entry.alvo}`); |
|
|
return entry; |
|
|
} catch (e) { |
|
|
console.error('Erro ao logar operação:', e); |
|
|
} |
|
|
} |
|
|
|
|
|
_createAlert(operacao) { |
|
|
const alert = { |
|
|
id: `alert_${Date.now()}`, |
|
|
timestamp: new Date().toISOString(), |
|
|
severidade: 'ALTO', |
|
|
operacaoId: operacao.id, |
|
|
usuario: operacao.usuario, |
|
|
descricao: `Operação suspeita: ${operacao.tipoOperacao}`, |
|
|
motivo: this._getSuspiciousReason(operacao), |
|
|
status: 'NOVO' |
|
|
}; |
|
|
|
|
|
this.alerts.push(alert); |
|
|
this._saveJSON(this.alertsPath, this.alerts); |
|
|
|
|
|
console.log(`🚨 [SECURITY ALERT] ${alert.descricao}`); |
|
|
return alert; |
|
|
} |
|
|
|
|
|
_isSuspicious(operacao) { |
|
|
const recentOps = this.operations.filter(o => |
|
|
new Date(operacao.timestamp) - new Date(o.timestamp) < 60000 |
|
|
); |
|
|
|
|
|
if (recentOps.length > 5) return true; |
|
|
if (operacao.tipoOperacao === 'NMAP_SCAN' && operacao.risco === 'ALTO') return true; |
|
|
if (operacao.tipoOperacao === 'SQLMAP_TEST' && operacao.resultado === 'VULNERÁVEL') return true; |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
_getSuspiciousReason(operacao) { |
|
|
const reasons = []; |
|
|
|
|
|
if (operacao.tipoOperacao === 'NMAP_SCAN') reasons.push('Port scan'); |
|
|
if (operacao.tipoOperacao === 'SQLMAP_TEST') reasons.push('SQL Injection'); |
|
|
if (operacao.risco === 'CRÍTICO') reasons.push('Risco crítico'); |
|
|
|
|
|
return reasons.join(', ') || 'Atividade incomum'; |
|
|
} |
|
|
|
|
|
_loadJSON(file, fallback) { |
|
|
try { |
|
|
if (fs.existsSync(file)) { |
|
|
return JSON.parse(fs.readFileSync(file, 'utf8')); |
|
|
} |
|
|
} catch {} |
|
|
return fallback; |
|
|
} |
|
|
|
|
|
_saveJSON(file, data) { |
|
|
try { |
|
|
fs.writeFileSync(file, JSON.stringify(data, null, 2)); |
|
|
} catch (e) { |
|
|
console.error(`Erro ao salvar ${file}:`, e.message); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = SecurityLogger; |
|
|
|