feat(ops/monitoring): add in-memory log buffer, metrics time-series and ops UI integration
This commit is contained in:
@@ -249,7 +249,14 @@ export class OpsViewSecurity extends DeesElement {
|
||||
private renderOverview(metrics: any) {
|
||||
const threatLevel = this.calculateThreatLevel(metrics);
|
||||
const threatScore = this.getThreatScore(metrics);
|
||||
|
||||
|
||||
// Derive active sessions from recent successful auth events (last hour)
|
||||
const allEvents: any[] = metrics.recentEvents || [];
|
||||
const oneHourAgo = Date.now() - 3600000;
|
||||
const recentAuthSuccesses = allEvents.filter(
|
||||
(evt: any) => evt.type === 'authentication' && evt.success === true && evt.timestamp >= oneHourAgo
|
||||
).length;
|
||||
|
||||
const tiles: IStatsTile[] = [
|
||||
{
|
||||
id: 'threatLevel',
|
||||
@@ -271,7 +278,7 @@ export class OpsViewSecurity extends DeesElement {
|
||||
{
|
||||
id: 'blockedThreats',
|
||||
title: 'Blocked Threats',
|
||||
value: metrics.blockedIPs.length + metrics.spamDetected,
|
||||
value: (metrics.blockedIPs?.length || 0) + metrics.spamDetected,
|
||||
type: 'number',
|
||||
icon: 'lucide:ShieldCheck',
|
||||
color: '#ef4444',
|
||||
@@ -280,11 +287,11 @@ export class OpsViewSecurity extends DeesElement {
|
||||
{
|
||||
id: 'activeSessions',
|
||||
title: 'Active Sessions',
|
||||
value: 0,
|
||||
value: recentAuthSuccesses,
|
||||
type: 'number',
|
||||
icon: 'lucide:Users',
|
||||
color: '#22c55e',
|
||||
description: 'Current authenticated sessions',
|
||||
description: 'Authenticated in last hour',
|
||||
},
|
||||
{
|
||||
id: 'authFailures',
|
||||
@@ -349,6 +356,11 @@ export class OpsViewSecurity extends DeesElement {
|
||||
}
|
||||
|
||||
private renderAuthentication(metrics: any) {
|
||||
// Derive auth events from recentEvents
|
||||
const allEvents: any[] = metrics.recentEvents || [];
|
||||
const authEvents = allEvents.filter((evt: any) => evt.type === 'authentication');
|
||||
const successfulLogins = authEvents.filter((evt: any) => evt.success === true).length;
|
||||
|
||||
const tiles: IStatsTile[] = [
|
||||
{
|
||||
id: 'authFailures',
|
||||
@@ -362,7 +374,7 @@ export class OpsViewSecurity extends DeesElement {
|
||||
{
|
||||
id: 'successfulLogins',
|
||||
title: 'Successful Logins',
|
||||
value: 0,
|
||||
value: successfulLogins,
|
||||
type: 'number',
|
||||
icon: 'lucide:Lock',
|
||||
color: '#22c55e',
|
||||
@@ -370,6 +382,15 @@ export class OpsViewSecurity extends DeesElement {
|
||||
},
|
||||
];
|
||||
|
||||
// Map auth events to login history table data
|
||||
const loginHistory = authEvents.map((evt: any) => ({
|
||||
timestamp: evt.timestamp,
|
||||
username: evt.details?.username || 'unknown',
|
||||
ipAddress: evt.ipAddress || 'unknown',
|
||||
success: evt.success ?? false,
|
||||
reason: evt.success ? '' : evt.message || 'Authentication failed',
|
||||
}));
|
||||
|
||||
return html`
|
||||
<dees-statsgrid
|
||||
.tiles=${tiles}
|
||||
@@ -380,7 +401,7 @@ export class OpsViewSecurity extends DeesElement {
|
||||
<dees-table
|
||||
.heading1=${'Login History'}
|
||||
.heading2=${'Recent authentication attempts'}
|
||||
.data=${[]}
|
||||
.data=${loginHistory}
|
||||
.displayFunction=${(item) => ({
|
||||
'Time': new Date(item.timestamp).toLocaleString(),
|
||||
'Username': item.username,
|
||||
@@ -483,48 +504,38 @@ export class OpsViewSecurity extends DeesElement {
|
||||
private getThreatScore(metrics: any): number {
|
||||
// Simple scoring algorithm
|
||||
let score = 100;
|
||||
score -= metrics.blockedIPs.length * 2;
|
||||
score -= metrics.authenticationFailures * 1;
|
||||
score -= metrics.spamDetected * 0.5;
|
||||
score -= metrics.malwareDetected * 3;
|
||||
score -= metrics.phishingDetected * 3;
|
||||
score -= metrics.suspiciousActivities * 2;
|
||||
const blockedCount = Array.isArray(metrics.blockedIPs) ? metrics.blockedIPs.length : (metrics.blockedIPs || 0);
|
||||
score -= blockedCount * 2;
|
||||
score -= (metrics.authenticationFailures || 0) * 1;
|
||||
score -= (metrics.spamDetected || 0) * 0.5;
|
||||
score -= (metrics.malwareDetected || 0) * 3;
|
||||
score -= (metrics.phishingDetected || 0) * 3;
|
||||
score -= (metrics.suspiciousActivities || 0) * 2;
|
||||
return Math.max(0, Math.min(100, Math.round(score)));
|
||||
}
|
||||
|
||||
private getSecurityEvents(metrics: any): any[] {
|
||||
// Mock data - in real implementation, this would come from the server
|
||||
return [
|
||||
{
|
||||
timestamp: Date.now() - 1000 * 60 * 5,
|
||||
event: 'Multiple failed login attempts',
|
||||
severity: 'warning',
|
||||
details: 'IP: 192.168.1.100',
|
||||
},
|
||||
{
|
||||
timestamp: Date.now() - 1000 * 60 * 15,
|
||||
event: 'SPF check failed',
|
||||
severity: 'medium',
|
||||
details: 'Domain: example.com',
|
||||
},
|
||||
{
|
||||
timestamp: Date.now() - 1000 * 60 * 30,
|
||||
event: 'IP blocked due to spam',
|
||||
severity: 'high',
|
||||
details: 'IP: 10.0.0.1',
|
||||
},
|
||||
];
|
||||
const events: any[] = metrics.recentEvents || [];
|
||||
return events.map((evt: any) => ({
|
||||
timestamp: evt.timestamp,
|
||||
event: evt.message,
|
||||
severity: evt.level === 'critical' ? 'critical' : evt.level === 'error' ? 'high' : evt.level === 'warn' ? 'warning' : 'info',
|
||||
details: evt.ipAddress ? `IP: ${evt.ipAddress}` : evt.domain ? `Domain: ${evt.domain}` : evt.type,
|
||||
}));
|
||||
}
|
||||
|
||||
private async clearBlockedIPs() {
|
||||
console.log('Clear blocked IPs');
|
||||
// SmartProxy manages IP blocking — not yet exposed via API
|
||||
alert('Clearing blocked IPs is not yet supported from the UI.');
|
||||
}
|
||||
|
||||
private async unblockIP(ip: string) {
|
||||
console.log('Unblock IP:', ip);
|
||||
// SmartProxy manages IP blocking — not yet exposed via API
|
||||
alert(`Unblocking IP ${ip} is not yet supported from the UI.`);
|
||||
}
|
||||
|
||||
private async saveEmailSecuritySettings() {
|
||||
console.log('Save email security settings');
|
||||
// Config is read-only from the UI for now
|
||||
alert('Email security settings are read-only. Update the dcrouter configuration file to change these settings.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user