Sessions used to last as long as a 7-day refresh token kept being renewed, and the auth cookies outlived a browser restart. Settings -> Security now sets an idle timeout (default 15 min, 5 min to 3 h) and a maximum session length (default 10 h, 1 to 12 h); both are clamped when read. The refresh token lives exactly the idle timeout and is renewed on activity. The access token lives half of it, at most 30 min. Every token carries sat (sign-in time), copied on refresh: nothing outlives sat + max, and /auth/refresh refuses past it. That holds for password, MFA, passkey, SAML and OIDC sign-ins alike. Refresh tokens from before sat are refused, so everyone signs in once after the upgrade. Auth cookies are session cookies and go when the browser closes. In the SPA, SessionGuard renews on load and on keyboard/mouse activity and takes the page to /login when the idle timeout or maximum age passes, so an abandoned screen does not stay readable. Activity is shared across tabs.
282 lines
10 KiB
TypeScript
282 lines
10 KiB
TypeScript
export interface DashboardStats {
|
|
critical_count: number;
|
|
high_count: number;
|
|
medium_count: number;
|
|
low_count: number;
|
|
total_vulnerabilities: number;
|
|
open_vulnerabilities: number;
|
|
affected_assets: number;
|
|
total_assets: number;
|
|
scanned_assets: number;
|
|
severity_history: { day: string, count: number }[];
|
|
avg_cvss_score: number;
|
|
oldest_vulnerability_days: number;
|
|
}
|
|
|
|
export interface PriorityBreakdown {
|
|
total: number;
|
|
cvss: number;
|
|
exploit_bonus: number;
|
|
exploit_source: 'kev' | 'euvd' | 'kev_and_euvd' | 'epss' | 'wazuh' | 'ssvc' | 'maturity' | 'metasploit' | 'exploit_db' | 'poc_github' | 'none';
|
|
// Plan M — public-exploit catalog counts (already folded into
|
|
// exploit_bonus via max(); shown for transparency).
|
|
exploit_db_count?: number;
|
|
pocs_github_count?: number;
|
|
metasploit_module_count?: number;
|
|
exploit_status?: 'none' | 'poc' | 'active' | 'widespread'; // SSVC exploitation status
|
|
ssvc_addon?: number; // bonus from technical_impact + automatable
|
|
ssvc_technical_impact?: 'partial' | 'total' | null;
|
|
ssvc_automatable?: 'yes' | 'no' | null;
|
|
exploit_maturity?: string | null; // Unproven | PoC | Functional | High
|
|
asset_factor: number;
|
|
age_bonus: number;
|
|
kev_bonus: number;
|
|
euvd_bonus?: number;
|
|
catalog_count?: number;
|
|
cpr?: number | null;
|
|
vpr_score?: number | null; // Tenable VPR mirrored into breakdown
|
|
epss_score?: number | null;
|
|
epss_percentile?: number | null;
|
|
kev_listed: boolean;
|
|
kev_ransomware_use: boolean;
|
|
euvd_listed?: boolean;
|
|
euvd_critical?: boolean;
|
|
}
|
|
|
|
export interface VulnerabilityPackage {
|
|
package_name: string;
|
|
package_version?: string | null;
|
|
fixed_version?: string | null;
|
|
source?: string | null; // wazuh | nessus | manual
|
|
has_fix: boolean; // True iff fixed_version is real (not equal to installed)
|
|
}
|
|
|
|
export interface Vulnerability {
|
|
id: number;
|
|
cve_id: string;
|
|
severity: 'critical' | 'high' | 'medium' | 'low' | 'none';
|
|
cvss_score: number;
|
|
status: 'open' | 'patched' | 'pending_verification' | 'patch_failed' | 'accepted_risk' | 'false_positive' | 'deferred';
|
|
description: string;
|
|
package_name?: string;
|
|
package_vendor?: string | null; // vendor/publisher from Wazuh/Intune/Defender
|
|
package_version?: string;
|
|
fixed_version?: string | null; // when set + status='open' → patch available
|
|
packages?: VulnerabilityPackage[]; // per-package detail (CVE-2023-48795 hits PuTTY + WinSCP both)
|
|
has_fix_any?: boolean; // at least one package has a real fix (not equal to installed)
|
|
published_date: string;
|
|
last_modified_date?: string | null;
|
|
remediation?: string | null; // scanner-provided fix guidance (Nessus solution)
|
|
detected_at?: string;
|
|
asset_id: number;
|
|
asset_hostname?: string;
|
|
runs_on?: { id: number; hostname: string }[]; // Docker host(s) of a container-image finding
|
|
title?: string;
|
|
assigned_user_id?: number | null;
|
|
assigned_user_name?: string | null;
|
|
assigned_group_id?: number | null;
|
|
assigned_group_name?: string | null;
|
|
deferred_until?: string | null;
|
|
defer_reason?: string | null;
|
|
notification_suppressed?: boolean;
|
|
priority_score?: number;
|
|
priority_breakdown?: PriorityBreakdown;
|
|
exploit_available?: boolean;
|
|
exploit_maturity?: string; // Unproven, PoC, Functional, High (from Nessus)
|
|
exploitation_status?: 'none' | 'poc' | 'active' | 'widespread'; // SSVC (from Vulnrichment)
|
|
exploitation_source?: string; // nessus, vulrighment, nvd, manual
|
|
ssvc_technical_impact?: 'partial' | 'total' | null; // SSVC: attacker takeover scope
|
|
ssvc_automatable?: 'yes' | 'no' | null; // SSVC: mass-exploitation feasibility
|
|
// Multi-scanner source attribution (Nessus integration)
|
|
sources?: string[]; // ["wazuh"], ["nessus"], ["wazuh","nessus"]
|
|
cross_confirmed?: boolean; // sources.length >= 2
|
|
first_detected_by?: string | null;
|
|
nessus_plugin_id?: string | null;
|
|
nessus_vpr_score?: number | null; // Tenable's VPR (0-10)
|
|
is_pseudo_cve?: boolean; // NESSUS-PLUGIN-* (Compliance/Cipher) OR EOL-*
|
|
is_eol_finding?: boolean; // endoflife.date pseudo-CVE (cve_id starts with "EOL-")
|
|
// Plan M — public-exploit catalogs
|
|
exploit_db_count?: number;
|
|
exploit_db_ids?: string[] | null;
|
|
pocs_github_count?: number;
|
|
pocs_github_urls?: string[] | null;
|
|
metasploit_module_count?: number;
|
|
metasploit_modules?: string[] | null;
|
|
exploit_intel_updated_at?: string | null;
|
|
last_change?: { // latest audit entry for status tooltip
|
|
timestamp: string | null;
|
|
username: string;
|
|
old_status: string | null;
|
|
new_status: string | null;
|
|
reason: string | null;
|
|
source: string | null; // manual / manual_bulk / nessus_sync / wazuh_sync
|
|
} | null;
|
|
// Threat intel enrichment
|
|
epss_score?: number | null;
|
|
epss_percentile?: number | null;
|
|
kev_listed?: boolean;
|
|
kev_ransomware_use?: boolean;
|
|
kev_date_added?: string | null;
|
|
euvd_listed?: boolean;
|
|
euvd_critical?: boolean;
|
|
euvd_date_added?: string | null;
|
|
euvd_id?: string | null;
|
|
cpr_score?: number | null;
|
|
enrichment_sources?: string | null;
|
|
enrichment_updated_at?: string | null;
|
|
}
|
|
|
|
export interface Asset {
|
|
id: number;
|
|
hostname: string;
|
|
ip_address: string;
|
|
operating_system: string;
|
|
os_version?: string;
|
|
// VMware VMkernel/vpxd build number (e.g. "24784735") — shown in the OS column.
|
|
vmware_build?: string | null;
|
|
last_scan?: string;
|
|
wazuh_agent_id?: string | null;
|
|
nessus_host_uuid?: string | null;
|
|
intune_device_id?: string | null;
|
|
defender_machine_id?: string | null;
|
|
// Entra/AAD device id — survives an Intune deletion, so it is the handle
|
|
// for finding (and excluding) the same device in Defender TVM.
|
|
aad_device_id?: string | null;
|
|
vmware_uuid?: string | null;
|
|
vmware_serial?: string | null;
|
|
igel_unit_id?: string | null;
|
|
igel_serial?: string | null;
|
|
netdisco_device_ip?: string | null;
|
|
netdisco_serial?: string | null;
|
|
xen_host_uuid?: string | null;
|
|
intune_serial?: string | null;
|
|
last_seen_source?: string | null;
|
|
source?: 'wazuh' | 'nessus' | 'manual' | 'intune';
|
|
status: 'active' | 'inactive' | 'decommissioned';
|
|
policy_id?: number | null;
|
|
description?: string;
|
|
location?: string;
|
|
owner?: string;
|
|
assigned_user_id?: number | null;
|
|
assigned_user_name?: string | null;
|
|
groups?: string[]; // List of group names (M2M relationship)
|
|
policy_name?: string | null;
|
|
criticality?: string | null;
|
|
// Network-exposure risk dimension (Wazuh syscollector ports)
|
|
network_exposure_score?: number | null;
|
|
exposed_services?: { port: number; proto: string; service: string; risk: number; local_ip?: string }[] | null;
|
|
high_value_score?: number | null;
|
|
risk_dimensions?: { role: string; label: string; weight: number }[] | null;
|
|
exposure_updated_at?: string | null;
|
|
// Open findings on this asset (same number as the CSV's "Open Vulnerabilities").
|
|
vulnerability_count?: number;
|
|
// Dockhand: a Docker host's number of images, an image's Docker hosts.
|
|
container_image_count?: number;
|
|
runs_on?: { id: number; hostname: string }[];
|
|
}
|
|
|
|
export interface UserInfo {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
role: 'admin' | 'editor' | 'readonly';
|
|
passkey_suggested?: boolean; // show the "add a passkey" hint
|
|
// Limits SessionGuard enforces on screen; expires_at is epoch seconds.
|
|
session?: { idle_timeout_minutes: number; expires_at: number };
|
|
}
|
|
|
|
export interface Group {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
created_at: string;
|
|
member_count: number;
|
|
members: { id: number; username: string }[];
|
|
}
|
|
|
|
export interface NotificationLogEntry {
|
|
id: number;
|
|
vulnerability_id?: number;
|
|
asset_id?: number;
|
|
user_id?: number;
|
|
notification_type: 'sla_breach' | 'assignment' | 'manual';
|
|
sent_at: string;
|
|
subject?: string;
|
|
recipient_email?: string;
|
|
status: 'sent' | 'failed' | 'suppressed';
|
|
error_message?: string;
|
|
cve_id?: string;
|
|
asset_hostname?: string;
|
|
username?: string;
|
|
}
|
|
|
|
export interface Scan {
|
|
id: number;
|
|
asset_id: number;
|
|
asset_hostname?: string;
|
|
scan_type: 'wazuh' | 'nessus' | 'full' | 'syscollector'; // legacy values kept for old history rows
|
|
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
started_at: string;
|
|
completed_at?: string;
|
|
vulnerabilities_found: number;
|
|
}
|
|
|
|
export interface ScanRunSummary {
|
|
scan_ids: number[];
|
|
started_at: string;
|
|
completed_at?: string;
|
|
scan_type: 'wazuh' | 'nessus' | 'full' | 'syscollector'; // legacy values kept for old history rows
|
|
total_assets: number;
|
|
completed: number;
|
|
failed: number;
|
|
running: number;
|
|
total_vulns_found: number;
|
|
failed_assets: { asset_hostname: string; error_message: string }[];
|
|
}
|
|
|
|
export interface Recommendation {
|
|
cve_id: string;
|
|
asset_hostname: string;
|
|
priority: number;
|
|
justification: string;
|
|
remediation_hint: string;
|
|
}
|
|
|
|
export interface AIPriorityResponse {
|
|
recommendations: Recommendation[];
|
|
global_strategy: string;
|
|
error?: string;
|
|
}
|
|
|
|
// --- Sync run ledger (GET /api/v1/scans/sync-runs, /sync-health) ---
|
|
export interface SyncRun {
|
|
id: number;
|
|
source: string;
|
|
source_label: string;
|
|
trigger: 'manual' | 'scheduled' | string;
|
|
status: 'running' | 'completed' | 'failed' | string;
|
|
started_at: string;
|
|
finished_at: string | null;
|
|
error_message: string | null;
|
|
error_count: number;
|
|
stats: Record<string, any>;
|
|
alerted_at: string | null;
|
|
}
|
|
|
|
export interface SyncHealthSource {
|
|
source: string;
|
|
label: string;
|
|
state: 'ok' | 'warning' | 'failed' | 'stale' | 'running' | 'unconfigured';
|
|
configured: boolean;
|
|
last_run: SyncRun | null;
|
|
last_success_at: string | null;
|
|
error_message: string | null;
|
|
}
|
|
|
|
export interface SyncHealthResponse {
|
|
sources: SyncHealthSource[];
|
|
alert_enabled: boolean;
|
|
recipients: string[];
|
|
recipients_setting: string;
|
|
}
|