← back to Designer Wallcoverings
DW-Agents/dw-agents/agent-security/security-agent.ts.backup-oauth-20251112
872 lines
import cookieParser from "cookie-parser";
/**
* DW-Agents: Security Agent
*
* Server security monitoring and management system:
* - System security status monitoring
* - Security updates detection
* - Firewall status monitoring
* - Failed login attempt tracking
* - SSL certificate monitoring
* - Port scanning detection
* - Automatic security issue reporting to Needs Attention agent
* - Real-time security dashboard
*
* Port: 9892
*/
import Anthropic from '@anthropic-ai/sdk';
import express, { Request, Response } from 'express';
import session from 'express-session';
import { exec } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs';
import * as path from 'path';
import fetch from 'node-fetch';
import { chatMiddleware } from '../shared-chat-integration';
const execAsync = promisify(exec);
const app = express();
// Global Authentication
const PORT = 9892;
// Global Authentication - MUST come before any other middleware
app.use(cookieParser());
// Add inter-agent chat widget (after auth)
app.use(chatMiddleware({
agentId: 'agent-security',
agentName: 'Security',
port: 9892,
category: 'agent'
}));
// Authentication
const AUTH_USERNAME = 'admin2025';
const AUTH_PASSWORD = 'Otis';
// Anthropic AI client
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY || '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',
});
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Session configuration
declare module 'express-session' {
interface SessionData {
authenticated: boolean;
chatHistory: Array<{ role: 'user' | 'assistant', content: string }>;
}
}
app.use(
session({
secret: 'dw-agents-security-2025',
resave: false,
saveUninitialized: true,
rolling: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
},
})
);
// Authentication middleware
const requireAuth = (req: Request, res: Response, next: any) => {
if (req.session.authenticated) {
return next();
}
res.redirect('/login');
};
// Security status tracking
interface SecurityIssue {
id: string;
timestamp: string;
severity: 'critical' | 'high' | 'medium' | 'low';
category: string;
title: string;
description: string;
recommendation: string;
resolved: boolean;
reportedToUrgent: boolean;
}
interface SecurityStats {
totalIssues: number;
criticalIssues: number;
highIssues: number;
mediumIssues: number;
lowIssues: number;
resolvedIssues: number;
lastScan: Date;
systemUptime: string;
failedLogins: number;
activeConnections: number;
}
let securityIssues: SecurityIssue[] = [];
let stats: SecurityStats = {
totalIssues: 0,
criticalIssues: 0,
highIssues: 0,
mediumIssues: 0,
lowIssues: 0,
resolvedIssues: 0,
lastScan: new Date(),
systemUptime: '0 days',
failedLogins: 0,
activeConnections: 0,
};
// Load/save issues
const ISSUES_FILE = path.join(__dirname, 'security-issues.json');
function loadIssues() {
if (fs.existsSync(ISSUES_FILE)) {
try {
securityIssues = JSON.parse(fs.readFileSync(ISSUES_FILE, 'utf-8'));
updateStats();
} catch (e) {
console.error('Error loading issues:', e);
}
}
}
function saveIssues() {
fs.writeFileSync(ISSUES_FILE, JSON.stringify(securityIssues, null, 2));
}
function updateStats() {
stats.totalIssues = securityIssues.length;
stats.criticalIssues = securityIssues.filter(i => i.severity === 'critical' && !i.resolved).length;
stats.highIssues = securityIssues.filter(i => i.severity === 'high' && !i.resolved).length;
stats.mediumIssues = securityIssues.filter(i => i.severity === 'medium' && !i.resolved).length;
stats.lowIssues = securityIssues.filter(i => i.severity === 'low' && !i.resolved).length;
stats.resolvedIssues = securityIssues.filter(i => i.resolved).length;
}
loadIssues();
// Report critical issues to Needs Attention agent
async function reportToUrgent(issue: SecurityIssue) {
try {
const response = await fetch('http://45.61.58.125:9886/api/add-urgent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: `🔒 Security: ${issue.title}`,
description: issue.description,
severity: issue.severity,
category: 'security',
source: 'Security Agent',
}),
});
if (response.ok) {
issue.reportedToUrgent = true;
saveIssues();
console.log(`✅ Reported issue ${issue.id} to Needs Attention agent`);
}
} catch (error) {
console.error('Error reporting to Urgent agent:', error);
}
}
// Security check functions
async function checkSystemUpdates(): Promise<SecurityIssue | null> {
try {
const { stdout } = await execAsync('apt list --upgradable 2>/dev/null | grep -i security | wc -l');
const securityUpdates = parseInt(stdout.trim());
if (securityUpdates > 0) {
return {
id: `sec-updates-${Date.now()}`,
timestamp: new Date().toISOString(),
severity: securityUpdates > 10 ? 'high' : 'medium',
category: 'updates',
title: `${securityUpdates} Security Updates Available`,
description: `There are ${securityUpdates} security updates available for the system.`,
recommendation: 'Run: sudo apt update && sudo apt upgrade',
resolved: false,
reportedToUrgent: false,
};
}
} catch (error) {
console.error('Error checking updates:', error);
}
return null;
}
async function checkFirewallStatus(): Promise<SecurityIssue | null> {
try {
const { stdout } = await execAsync('sudo ufw status 2>/dev/null || echo "inactive"');
if (stdout.toLowerCase().includes('inactive')) {
return {
id: `firewall-${Date.now()}`,
timestamp: new Date().toISOString(),
severity: 'high',
category: 'firewall',
title: 'Firewall is Inactive',
description: 'The UFW firewall is not active, leaving the system exposed.',
recommendation: 'Enable firewall: sudo ufw enable',
resolved: false,
reportedToUrgent: false,
};
}
} catch (error) {
// Firewall might not be installed
}
return null;
}
async function checkFailedLogins(): Promise<SecurityIssue | null> {
try {
const { stdout } = await execAsync('grep "Failed password" /var/log/auth.log 2>/dev/null | tail -100 | wc -l');
const failedLogins = parseInt(stdout.trim());
stats.failedLogins = failedLogins;
if (failedLogins > 50) {
return {
id: `failed-logins-${Date.now()}`,
timestamp: new Date().toISOString(),
severity: failedLogins > 100 ? 'critical' : 'high',
category: 'authentication',
title: `${failedLogins} Recent Failed Login Attempts`,
description: `Detected ${failedLogins} failed login attempts in recent logs. Possible brute force attack.`,
recommendation: 'Review /var/log/auth.log and consider implementing fail2ban',
resolved: false,
reportedToUrgent: false,
};
}
} catch (error) {
// Auth log might not be accessible
}
return null;
}
async function checkSSLCertificates(): Promise<SecurityIssue | null> {
try {
const { stdout } = await execAsync('sudo certbot certificates 2>/dev/null | grep "Expiry Date" | head -1');
if (stdout) {
// Parse expiry date and check if within 30 days
const match = stdout.match(/(\d{4}-\d{2}-\d{2})/);
if (match) {
const expiryDate = new Date(match[1]);
const daysUntilExpiry = Math.floor((expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
if (daysUntilExpiry < 30) {
return {
id: `ssl-expiry-${Date.now()}`,
timestamp: new Date().toISOString(),
severity: daysUntilExpiry < 7 ? 'critical' : 'high',
category: 'ssl',
title: `SSL Certificate Expiring in ${daysUntilExpiry} Days`,
description: `SSL certificate will expire on ${expiryDate.toDateString()}`,
recommendation: 'Renew certificate: sudo certbot renew',
resolved: false,
reportedToUrgent: false,
};
}
}
}
} catch (error) {
// Certbot might not be installed
}
return null;
}
async function checkOpenPorts(): Promise<SecurityIssue | null> {
try {
const { stdout } = await execAsync('ss -tuln | grep LISTEN | wc -l');
const openPorts = parseInt(stdout.trim());
stats.activeConnections = openPorts;
// Check for commonly exploited ports
const { stdout: dangerousPorts } = await execAsync('ss -tuln | grep -E ":(23|21|445|3389|5900)" | wc -l');
const dangerous = parseInt(dangerousPorts.trim());
if (dangerous > 0) {
return {
id: `dangerous-ports-${Date.now()}`,
timestamp: new Date().toISOString(),
severity: 'critical',
category: 'network',
title: 'Dangerous Ports Open',
description: `Detected ${dangerous} commonly exploited ports open (Telnet, FTP, SMB, RDP, VNC)`,
recommendation: 'Close unnecessary ports and use secure alternatives',
resolved: false,
reportedToUrgent: false,
};
}
} catch (error) {
console.error('Error checking ports:', error);
}
return null;
}
async function checkSystemUptime() {
try {
const { stdout } = await execAsync('uptime -p');
stats.systemUptime = stdout.trim().replace('up ', '');
} catch (error) {
console.error('Error checking uptime:', error);
}
}
// Run security scan
async function runSecurityScan() {
console.log('🔍 Running security scan...');
const checks = [
checkSystemUpdates(),
checkFirewallStatus(),
checkFailedLogins(),
checkSSLCertificates(),
checkOpenPorts(),
];
const results = await Promise.all(checks);
await checkSystemUptime();
for (const issue of results) {
if (issue) {
// Check if this issue already exists
const existing = securityIssues.find(i => i.category === issue.category && !i.resolved);
if (!existing) {
securityIssues.push(issue);
console.log(`⚠️ New security issue: ${issue.title}`);
// Report critical and high severity issues to Needs Attention
if (issue.severity === 'critical' || issue.severity === 'high') {
await reportToUrgent(issue);
}
}
}
}
stats.lastScan = new Date();
updateStats();
saveIssues();
console.log(`✅ Security scan complete. Found ${stats.criticalIssues + stats.highIssues + stats.mediumIssues + stats.lowIssues} active issues.`);
}
// Run initial scan and schedule periodic scans
runSecurityScan();
setInterval(runSecurityScan, 60 * 60 * 1000); // Every hour
// Login page
app.get('/login', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Login - Security Agent</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: linear-gradient(135deg, #DC143C 0%, #8B0000 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.login-container {
background: white;
padding: 50px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 400px;
width: 100%;
}
.header {
text-align: center;
margin-bottom: 40px;
}
.header h1 {
color: #DC143C;
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
color: #666;
font-size: 1.1em;
}
.form-group {
margin-bottom: 25px;
}
label {
display: block;
color: #333;
margin-bottom: 8px;
font-weight: 600;
}
input {
width: 100%;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 1em;
transition: border-color 0.3s;
}
input:focus {
outline: none;
border-color: #DC143C;
}
button {
width: 100%;
background: linear-gradient(135deg, #DC143C 0%, #8B0000 100%);
color: white;
border: none;
padding: 18px;
border-radius: 10px;
font-size: 1.1em;
cursor: pointer;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(220, 20, 60, 0.3);
}
.error {
background: #fee;
border: 2px solid #f00;
color: #c00;
padding: 15px;
border-radius: 10px;
margin-bottom: 25px;
text-align: center;
font-weight: 500;
}
</style>
</head>
<body>
<div class="login-container">
<div class="header">
<h1>🔒 Security Agent</h1>
<p>System Security Monitor</p>
</div>
${req.query.error ? '<div class="error">Invalid credentials</div>' : ''}
<form method="POST" action="/login">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" required autocomplete="username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" required autocomplete="current-password">
</div>
<button type="submit">Access Security Dashboard</button>
</form>
</div>
</body>
</html>
`);
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === AUTH_USERNAME && password === AUTH_PASSWORD) {
req.session.authenticated = true;
req.session.save((err) => {
if (err) {
console.error('Session save error:', err);
}
res.redirect('/');
});
} else {
res.redirect('/login?error=1');
}
});
app.get('/logout', (req, res) => {
req.session.destroy(() => {
res.redirect('/login');
});
});
// Main dashboard
app.get('/', requireAuth, (req, res) => {
const unresolvedIssues = securityIssues.filter(i => !i.resolved).sort((a, b) => {
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
return severityOrder[a.severity] - severityOrder[b.severity];
});
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Security Agent - DW-Agents</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: linear-gradient(135deg, #DC143C 0%, #8B0000 100%);
min-height: 100vh;
padding: 30px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.header {
background: white;
padding: 40px;
border-radius: 20px;
margin-bottom: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
color: #DC143C;
font-size: 2.5em;
margin-bottom: 10px;
}
.header .subtitle {
color: #666;
font-size: 1.2em;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
text-align: center;
}
.stat-card .icon {
font-size: 3em;
margin-bottom: 15px;
}
.stat-card .value {
font-size: 2.5em;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.stat-card .label {
color: #666;
font-size: 1.1em;
}
.stat-card.critical { border-left: 6px solid #DC143C; }
.stat-card.high { border-left: 6px solid #FF6B35; }
.stat-card.medium { border-left: 6px solid #FFA500; }
.stat-card.low { border-left: 6px solid #4CAF50; }
.section {
background: white;
padding: 30px;
border-radius: 20px;
margin-bottom: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
}
.section h2 {
color: #DC143C;
margin-bottom: 20px;
font-size: 1.8em;
}
.issue-card {
background: #f8f9fa;
padding: 20px;
border-radius: 10px;
margin-bottom: 15px;
border-left: 6px solid;
}
.issue-card.critical { border-left-color: #DC143C; }
.issue-card.high { border-left-color: #FF6B35; }
.issue-card.medium { border-left-color: #FFA500; }
.issue-card.low { border-left-color: #4CAF50; }
.issue-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.issue-title {
font-weight: 600;
font-size: 1.2em;
color: #333;
}
.severity-badge {
padding: 5px 15px;
border-radius: 20px;
font-size: 0.85em;
font-weight: 600;
text-transform: uppercase;
}
.severity-badge.critical {
background: #fee;
color: #DC143C;
}
.severity-badge.high {
background: #fff3e0;
color: #FF6B35;
}
.severity-badge.medium {
background: #fff8e1;
color: #FFA500;
}
.severity-badge.low {
background: #e8f5e9;
color: #4CAF50;
}
.issue-description {
color: #666;
margin-bottom: 10px;
line-height: 1.6;
}
.issue-recommendation {
background: white;
padding: 10px;
border-radius: 5px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
color: #333;
}
.btn {
padding: 12px 30px;
border: none;
border-radius: 10px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
text-decoration: none;
display: inline-block;
}
.btn-primary {
background: linear-gradient(135deg, #DC143C 0%, #8B0000 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(220, 20, 60, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: #333;
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: #4CAF50;
color: white;
}
.no-issues {
text-align: center;
padding: 40px;
color: #666;
font-size: 1.2em;
}
.no-issues .icon {
font-size: 5em;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div>
<h1>🔒 Security Agent</h1>
<div class="subtitle">System Security Monitoring</div>
<div style="margin-top: 10px; color: #888;">Last scan: ${stats.lastScan.toLocaleString()}</div>
</div>
<div>
<a href="/logout" class="btn btn-secondary">Logout</a>
<button onclick="runScan()" class="btn btn-primary" style="margin-left: 10px;">🔍 Run Scan Now</button>
</div>
</div>
<div class="stats-grid">
<div class="stat-card critical">
<div class="icon">🚨</div>
<div class="value">${stats.criticalIssues}</div>
<div class="label">Critical Issues</div>
</div>
<div class="stat-card high">
<div class="icon">⚠️</div>
<div class="value">${stats.highIssues}</div>
<div class="label">High Priority</div>
</div>
<div class="stat-card medium">
<div class="icon">📋</div>
<div class="value">${stats.mediumIssues}</div>
<div class="label">Medium Priority</div>
</div>
<div class="stat-card low">
<div class="icon">ℹ️</div>
<div class="value">${stats.lowIssues}</div>
<div class="label">Low Priority</div>
</div>
<div class="stat-card">
<div class="icon">⏱️</div>
<div class="value" style="font-size: 1.5em;">${stats.systemUptime}</div>
<div class="label">System Uptime</div>
</div>
<div class="stat-card">
<div class="icon">🔌</div>
<div class="value">${stats.activeConnections}</div>
<div class="label">Open Ports</div>
</div>
</div>
<div class="section">
<h2>⚠️ Active Security Issues</h2>
${unresolvedIssues.length === 0 ? `
<div class="no-issues">
<div class="icon">✅</div>
<div>No active security issues detected!</div>
<div style="font-size: 0.9em; margin-top: 10px;">System is secure and up to date.</div>
</div>
` : unresolvedIssues.map(issue => `
<div class="issue-card ${issue.severity}">
<div class="issue-header">
<div class="issue-title">${issue.title}</div>
<span class="severity-badge ${issue.severity}">${issue.severity}</span>
</div>
<div class="issue-description">${issue.description}</div>
<div class="issue-recommendation">
<strong>💡 Recommendation:</strong> ${issue.recommendation}
</div>
<div style="margin-top: 15px;">
<button onclick="resolveIssue('${issue.id}')" class="btn btn-success">Mark as Resolved</button>
${!issue.reportedToUrgent && (issue.severity === 'critical' || issue.severity === 'high') ? `
<button onclick="reportToUrgent('${issue.id}')" class="btn btn-primary" style="margin-left: 10px;">
📢 Report to Urgent
</button>
` : ''}
</div>
</div>
`).join('')}
</div>
</div>
<script>
async function runScan() {
try {
const response = await fetch('/api/scan', { method: 'POST' });
if (response.ok) {
alert('Security scan initiated. Page will reload.');
location.reload();
}
} catch (error) {
alert('Error running scan');
}
}
async function resolveIssue(id) {
try {
const response = await fetch(\`/api/issues/\${id}/resolve\`, { method: 'POST' });
if (response.ok) {
location.reload();
}
} catch (error) {
alert('Error resolving issue');
}
}
async function reportToUrgent(id) {
try {
const response = await fetch(\`/api/issues/\${id}/report\`, { method: 'POST' });
if (response.ok) {
alert('Issue reported to Needs Attention agent');
location.reload();
}
} catch (error) {
alert('Error reporting issue');
}
}
// Auto-refresh every 5 minutes
setTimeout(() => location.reload(), 5 * 60 * 1000);
</script>
</body>
</html>
`);
});
// API endpoints
app.post('/api/scan', requireAuth, async (req, res) => {
runSecurityScan();
res.json({ success: true, message: 'Security scan initiated' });
});
app.post('/api/issues/:id/resolve', requireAuth, (req, res) => {
const issue = securityIssues.find(i => i.id === req.params.id);
if (issue) {
issue.resolved = true;
updateStats();
saveIssues();
res.json({ success: true });
} else {
res.status(404).json({ error: 'Issue not found' });
}
});
app.post('/api/issues/:id/report', requireAuth, async (req, res) => {
const issue = securityIssues.find(i => i.id === req.params.id);
if (issue) {
await reportToUrgent(issue);
res.json({ success: true });
} else {
res.status(404).json({ error: 'Issue not found' });
}
});
app.get('/api/stats', requireAuth, (req, res) => {
res.json(stats);
});
app.get('/api/issues', requireAuth, (req, res) => {
res.json(securityIssues.filter(i => !i.resolved));
});
// Metrics endpoint for daily reporting
app.get("/api/metrics", (req: Request, res: Response) => {
res.json({
status: "online",
uptime: process.uptime(),
responseTime: 0,
tasksCompleted: 0,
errorsToday: 0,
lastActivity: new Date().toISOString(),
qnaReadiness: 100
});
});
app.listen(PORT, '0.0.0.0', () => {
console.log('');
console.log('🔒 DW-Agents: Security Agent');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('🌍 External: http://45.61.58.125:' + PORT);
console.log('🏠 Local: http://localhost:' + PORT);
console.log('');
console.log('✅ Security monitoring active');
console.log('📊 Running security scans every hour');
console.log('🚨 Auto-reporting critical/high issues to Needs Attention agent');
console.log('');
});