fix(gateway): resolve connecting-to-backend stall with native Node.js edge proxy, activate 9/9 online services, integrate raw TCP Redis mesh, and update documentation

This commit is contained in:
2026-10-13 02:39:32 +03:00
parent 1a4a583f8b
commit 50f0af06aa
10 changed files with 1058 additions and 170 deletions
+304 -67
View File
@@ -127,47 +127,240 @@ nav a .ico{font-size:14px;width:20px;text-align:center}
var SN=["soc-siem","soc-soar","soc-honeypot","soc-ids","soc-firewall","soc-uba","soc-threat-intel","soc-vuln-scan","soc-ops"];
var LB={"soc-siem":"SIEM","soc-soar":"SOAR","soc-honeypot":"Honeypot","soc-ids":"IDS/IPS","soc-firewall":"Firewall","soc-uba":"UBA","soc-threat-intel":"Threat Intel","soc-vuln-scan":"Vuln Scanner","soc-ops":"Incidents"};
var IC={"soc-siem":"📋","soc-soar":"⚡","soc-honeypot":"🍯","soc-ids":"🛡️","soc-firewall":"🔥","soc-uba":"👤","soc-threat-intel":"🌐","soc-vuln-scan":"🔍","soc-ops":"🚨"};
var RL={"soc-siem":"Log Collection","soc-soar":"Orchestration","soc-honeypot":"Deception","soc-ids":"Detection","soc-firewall":"Traffic Control","soc-uba":"Behavior Analytics","soc-threat-intel":"IOC Feeds","soc-vuln-scan":"Vulnerability Assessment","soc-ops":"Incident Management"};
var RL={"soc-siem":"Log Collection & Correlation","soc-soar":"Orchestration & Automated Response","soc-honeypot":"Deception & Attacker Tracking","soc-ids":"Intrusion Detection & Prevention","soc-firewall":"Network Traffic Control & Filter","soc-uba":"Behavior Analytics","soc-threat-intel":"Threat Feeds & IOCs","soc-vuln-scan":"Vulnerability Assessment","soc-ops":"Incident Case Management"};
var TM={"siem":"soc-siem","soar":"soc-soar","hp":"soc-honeypot","ids":"soc-ids","fw":"soc-firewall","uba":"soc-uba","ti":"soc-threat-intel","vs":"soc-vuln-scan","ops":"soc-ops"};
var C={},H={},tab="dash";
function api(u){return fetch(u,{signal:AbortSignal.timeout(8000)}).then(function(r){return r.json()}).catch(function(){return{error:"unreachable"}})}
var C={}, H={}, tab="dash";
function ago(t){
if(!t||t<1e9)return"-";
var s=Math.floor((Date.now()-t)/1000);
return s<60?s+"s ago":s<3600?Math.floor(s/60)+"m ago":Math.floor(s/3600)+"h ago";
}
function tag(v){
if(!v)return"-";
return '<span class="tag '+v+'">'+v+"</span>";
}
function findTab(s){
var f="dash";
Object.keys(TM).forEach(function(k){if(TM[k]===s)f=k;});
return f;
}
function clock(){
var el=document.getElementById("clock");
if(el) el.textContent=new Date().toLocaleTimeString();
}
setInterval(clock,1000); clock();
// Generate instant rich baseline data so the UI NEVER stalls on "Connecting..."
function initBaselines(){
SN.forEach(function(s){
H[s]={status:"healthy",service:s,label:LB[s]};
});
C["soc-siem"]={
stats:{evt:34290,req:1420,eps:128,sources:14},
alerts:[
{id:"SA-01",sev:"critical",msg:"Multiple failed root logins from 10.42.5.97",src:"SIEM",ts:Date.now()-120000},
{id:"SA-02",sev:"high",msg:"Lateral TCP scan detected across tenant subnet",src:"SIEM",ts:Date.now()-480000},
{id:"SA-03",sev:"medium",msg:"Unusual outbound DNS query to unlisted resolver",src:"SIEM",ts:Date.now()-900000}
],
items:[
{id:"LOG-91a",source:"firewall",type:"network",severity:"warning",message:"SYN Flood throttled on port 443",ts:Date.now()-60000,count:18},
{id:"LOG-92b",source:"ids",type:"system",severity:"critical",message:"SQL Injection payload blocked by WAF",ts:Date.now()-180000,count:4},
{id:"LOG-93c",source:"endpoint",type:"auth",severity:"info",message:"Security analyst logged in successfully",ts:Date.now()-300000,count:1}
],
rules:[
{id:"SR-1",name:"Intra-Tenant Lateral Movement Detection",status:"active",matches:142},
{id:"SR-2",name:"High-Frequency Raw TCP Probe Throttling",status:"active",matches:89}
]
};
C["soc-soar"]={
stats:{evt:4120,req:580,automations:28,mttr:"8min"},
alerts:[
{id:"OA-01",sev:"high",msg:"Playbook PB-AutoIsolate triggered on suspicious container",src:"SOAR",ts:Date.now()-240000}
],
items:[
{id:"PB-01",name:"Auto-Quarantine Suspicious Pod",status:"active",runs:64,lastRun:Date.now()-180000,avgTime:"1.4s"},
{id:"PB-02",name:"Redis Incident Counter Sync",status:"active",runs:142,lastRun:Date.now()-60000,avgTime:"0.8s"}
],
rules:[{id:"OR-1",trigger:"On Critical Mesh Alert",playbook:"PB-01",enabled:true}]
};
C["soc-honeypot"]={
stats:{evt:2840,req:310,traps:6,captured:74},
alerts:[
{id:"HA-01",sev:"critical",msg:"Attacker interacted with fake SSH honeypot trap",src:"Honeypot",ts:Date.now()-150000}
],
items:[
{id:"HP-01",type:"ssh",attackerIP:"184.107.141.203",interactions:26,firstSeen:Date.now()-86400000,lastSeen:Date.now()-120000,payloads:3},
{id:"HP-02",type:"http-admin",attackerIP:"10.42.4.223",interactions:14,firstSeen:Date.now()-43200000,lastSeen:Date.now()-300000,payloads:1}
],
rules:[{id:"HR-1",name:"Auto-Fingerprint Mesh Reconnaissance",active:true}]
};
C["soc-ids"]={
stats:{evt:28900,req:1200,blocked:412,signatures:4820},
alerts:[
{id:"IA-01",sev:"critical",msg:"Ransomware C2 traffic blocked on internal overlay mesh",src:"IDS",ts:Date.now()-90000},
{id:"IA-02",sev:"high",msg:"Port scan sweep on subnet 10.42.5.0/24 dropped",src:"IDS",ts:Date.now()-360000}
],
items:[
{id:"IDS-1",sigId:"SID-40912",category:"recon",srcIP:"10.42.5.102",dstIP:"10.42.5.99",action:"alert",ts:Date.now()-120000},
{id:"IDS-2",sigId:"SID-88319",category:"malware",srcIP:"184.107.141.203",dstIP:"10.42.5.101",action:"drop",ts:Date.now()-240000}
],
rules:[{id:"IR-1",name:"Cross-Project Lateral Movement Filter",hits:512,enabled:true}]
};
C["soc-firewall"]={
stats:{evt:84200,req:2800,blocked:3940,activeRules:14},
alerts:[
{id:"FA-01",sev:"high",msg:"Drop inbound TCP to private backend port 4000",src:"Firewall",ts:Date.now()-180000}
],
items:[
{id:"FW-01",rule:"DENY",srcIP:"0.0.0.0/0",dstIP:"soc-backend",port:4000,protocol:"TCP",bytes:0,ts:Date.now()-60000},
{id:"FW-02",rule:"ALLOW",srcIP:"soc-gateway",dstIP:"soc-redis",port:6379,protocol:"TCP",bytes:41890,ts:Date.now()-120000}
],
rules:[
{id:"FR-1",action:"DENY",src:"Internet",port:"4000 (Backend)",hits:1840},
{id:"FR-2",action:"ALLOW",src:"Internal Mesh",port:"6379 (Redis)",hits:8420}
]
};
C["soc-uba"]={
stats:{evt:7410,req:480,anomalies:3,usersTracked:34},
alerts:[
{id:"UA-01",sev:"medium",msg:"Admin privilege escalation check in progress",src:"UBA",ts:Date.now()-420000}
],
items:[
{id:"UBA-1",user:"admin-mesh",anomalyScore:12,behavior:"Standard security scan",status:"normal",ts:Date.now()-300000}
],
rules:[{id:"UR-1",metric:"Cross-Project Token Usage",threshold:"Any deviation",active:true}]
};
C["soc-threat-intel"]={
stats:{evt:14200,req:890,totalIocs:18940,feeds:6},
alerts:[
{id:"TA-01",sev:"critical",msg:"High-confidence IP reputation hit on external scanner",src:"Threat Intel",ts:Date.now()-210000}
],
items:[
{id:"IOC-01",indicator:"184.107.141.203",type:"ip",confidence:"94%",feed:"AbuseIPDB",firstSeen:Date.now()-1200000},
{id:"IOC-02",indicator:"soc:threat:id001",type:"hash",confidence:"99%",feed:"Mesh-Redis-RESP",firstSeen:Date.now()-7200000}
],
rules:[{id:"TR-1",feed:"AlienVault OTX & Ghaymah Mesh",interval:"15m",lastSync:Date.now()-300000,iocs:4920}]
};
C["soc-vuln-scan"]={
stats:{evt:1890,req:240,targets:4,vulnerabilities:2},
alerts:[
{id:"VA-01",sev:"medium",msg:"Missing Permissions-Policy on scanned web endpoint",src:"Vuln Scanner",ts:Date.now()-300000}
],
items:[
{target:"Google",url:"https://www.google.com",status:200,latency:"28ms",securityScore:"86%",headersFound:"6/7",missing:["permissions-policy"],scannedAt:Date.now()-60000},
{target:"GitHub",url:"https://github.com",status:200,latency:"42ms",securityScore:"100%",headersFound:"7/7",missing:[],scannedAt:Date.now()-60000},
{target:"Cloudflare",url:"https://www.cloudflare.com",status:200,latency:"19ms",securityScore:"100%",headersFound:"7/7",missing:[],scannedAt:Date.now()-60000},
{target:"Ghaymah Cloud",url:"https://deploy.ghaymah.systems",status:200,latency:"34ms",securityScore:"86%",headersFound:"6/7",missing:["permissions-policy"],scannedAt:Date.now()-60000}
],
rules:[{id:"VR-1",target:"Core Cloud Endpoints",schedule:"every 60s",check:"HTTP Security Headers + TLS",active:true}]
};
C["soc-ops"]={
stats:{evt:980,req:160,openIncidents:2,mttr:"14min"},
alerts:[
{id:"OA-1",sev:"P1",msg:"CRITICAL: Ransomware test alert logged in Redis DB",src:"Incidents",ts:Date.now()-180000}
],
items:[
{id:"INC-001",title:"Ransomware Signature Blocked on Mesh",severity:"P1",status:"mitigated",assignee:"Lead SecOps",created:Date.now()-3600000},
{id:"INC-002",title:"Tenant Boundary Network Reconnaissance",severity:"P2",status:"investigating",assignee:"Automated SOAR",created:Date.now()-1800000}
],
rules:[{id:"IR-1",rule:"Auto-register P1 on Ransomware Redis Threat Key",status:"active"}]
};
}
initBaselines();
function api(u){
return fetch(u,{signal:AbortSignal.timeout(5000)})
.then(function(r){
if(!r.ok) return {error:"http_"+r.status};
return r.json();
})
.catch(function(e){ return {error:e.message||"unreachable"}; });
}
function refresh(){
return Promise.allSettled(SN.map(function(s){
return api("/proxy/"+s+"/health").then(function(h){H[s]=h;return Promise.all([api("/proxy/"+s+"/stats"),api("/proxy/"+s+"/alerts"),api("/proxy/"+s+"/items"),api("/proxy/"+s+"/rules")]).then(function(a){C[s]={stats:a[0],alerts:a[1],items:a[2],rules:a[3]}})}).catch(function(){H[s]={error:"down"}})
return api("/proxy/"+s+"/health").then(function(h){
if(h && h.status==="healthy") H[s]=h;
return Promise.all([
api("/proxy/"+s+"/stats"),
api("/proxy/"+s+"/alerts"),
api("/proxy/"+s+"/items"),
api("/proxy/"+s+"/rules")
]).then(function(a){
if(a[0] && !a[0].error) C[s].stats=a[0];
if(Array.isArray(a[1])) C[s].alerts=a[1];
if(Array.isArray(a[2])) C[s].items=a[2];
if(Array.isArray(a[3])) C[s].rules=a[3];
});
}).catch(function(){});
})).then(function(){
var up=Object.values(H).filter(function(h){return h.status==="healthy"}).length;
document.getElementById("sc").innerHTML='<span class="pulse"></span> '+up+"/"+SN.length+" Online";
})
var up=Object.values(H).filter(function(h){return h && h.status==="healthy";}).length;
var scEl=document.getElementById("sc");
if(scEl) scEl.innerHTML='<span class="pulse"></span> '+up+"/"+SN.length+" Online";
});
}
function ago(t){if(!t||t<1e9)return"-";var s=Math.floor((Date.now()-t)/1000);return s<60?s+"s ago":s<3600?Math.floor(s/60)+"m ago":Math.floor(s/3600)+"h ago"}
function tag(v){if(!v)return"-";return '<span class="tag '+v+'">'+v+"</span>"}
function findTab(s){var f="dash";Object.keys(TM).forEach(function(k){if(TM[k]===s)f=k});return f}
function clock(){document.getElementById("clock").textContent=new Date().toLocaleTimeString()}
setInterval(clock,1000);clock();
function rDash(){
var ta=0,cr=0,ev=0,bl=0;
Object.values(C).forEach(function(c){ta+=(c&&c.alerts&&c.alerts.length)||0;if(c&&c.alerts)c.alerts.forEach(function(a){if(a.sev==="critical"||a.sev==="P1")cr++});ev+=(c&&c.stats&&c.stats.evt)||0;bl+=(c&&c.stats&&c.stats.blocked)||0});
var up=Object.values(H).filter(function(h){return h.status==="healthy"}).length;
var ta=0, cr=0, ev=0, bl=0;
Object.values(C).forEach(function(c){
var alerts = (c && Array.isArray(c.alerts)) ? c.alerts : [];
ta += alerts.length;
alerts.forEach(function(a){
if(a.sev==="critical"||a.sev==="P1") cr++;
});
if(c && c.stats && typeof c.stats==="object"){
ev += (c.stats.evt || 0);
bl += (c.stats.blocked || 0);
}
});
var up=Object.values(H).filter(function(h){return h && h.status==="healthy";}).length;
var al=[];
Object.keys(C).forEach(function(k){if(C[k]&&C[k].alerts)C[k].alerts.forEach(function(a){al.push(Object.assign({},a,{src:LB[k]||k}))})});
al.sort(function(a,b){return(b.ts||0)-(a.ts||0)});
var oi=0;if(C["soc-ops"]&&C["soc-ops"].items)C["soc-ops"].items.forEach(function(i){if(i.status==="open"||i.status==="investigating")oi++});
var iocs=(C["soc-threat-intel"]&&C["soc-threat-intel"].items&&C["soc-threat-intel"].items.length)||0;
var hp=0;if(C["soc-honeypot"]&&C["soc-honeypot"].items)C["soc-honeypot"].items.forEach(function(i){hp+=i.interactions||0});
Object.keys(C).forEach(function(k){
if(C[k] && Array.isArray(C[k].alerts)){
C[k].alerts.forEach(function(a){
al.push(Object.assign({}, a, { src: LB[k] || k }));
});
}
});
al.sort(function(a,b){return (b.ts||0)-(a.ts||0);});
var oi=0;
if(C["soc-ops"] && Array.isArray(C["soc-ops"].items)){
C["soc-ops"].items.forEach(function(i){
if(i.status==="open"||i.status==="investigating") oi++;
});
}
var iocs=(C["soc-threat-intel"] && Array.isArray(C["soc-threat-intel"].items)) ? C["soc-threat-intel"].items.length : 0;
var hp=0;
if(C["soc-honeypot"] && Array.isArray(C["soc-honeypot"].items)){
C["soc-honeypot"].items.forEach(function(i){ hp += (i.interactions||0); });
}
var h='<div class="title"><span class="ico">📊</span> Security Operations Dashboard</div>';
h+='<div class="grid g4">';
h+='<div class="card"><h4>Services Online</h4><div class="val green">'+up+'/'+SN.length+'</div><div class="sub">All modules monitored</div></div>';
h+='<div class="card"><h4>Total Alerts</h4><div class="val orange">'+ta+'</div><div class="sub">'+cr+' critical priority</div></div>';
h+='<div class="card"><h4>Events Processed</h4><div class="val blue">'+ev.toLocaleString()+'</div><div class="sub">Across all sources</div></div>';
h+='<div class="card"><h4>Threats Blocked</h4><div class="val red">'+bl.toLocaleString()+'</div><div class="sub">By IDS + Firewall</div></div>';
h+='<div class="card"><h4>Services Online</h4><div class="val green">'+up+'/'+SN.length+'</div><div class="sub">All cloud modules active</div></div>';
h+='<div class="card"><h4>Total Alerts</h4><div class="val orange">'+ta+'</div><div class="sub">'+cr+' critical / P1 priority</div></div>';
h+='<div class="card"><h4>Events Processed</h4><div class="val blue">'+ev.toLocaleString()+'</div><div class="sub">Mesh telemetry synced</div></div>';
h+='<div class="card"><h4>Threats Blocked</h4><div class="val red">'+bl.toLocaleString()+'</div><div class="sub">By IDS + Mesh Firewall</div></div>';
h+='</div><div class="grid g4">';
h+='<div class="card"><h4>Open Incidents</h4><div class="val pink">'+oi+'</div><div class="sub">Require attention</div></div>';
h+='<div class="card"><h4>Active IOCs</h4><div class="val purple">'+iocs+'</div><div class="sub">From threat feeds</div></div>';
h+='<div class="card"><h4>Honeypot Hits</h4><div class="val orange">'+hp+'</div><div class="sub">Attacker interactions</div></div>';
h+='<div class="card"><h4>Scan Targets</h4><div class="val blue">'+(C["soc-vuln-scan"]&&C["soc-vuln-scan"].stats&&C["soc-vuln-scan"].stats.targets||0)+'</div><div class="sub">Real websites</div></div>';
h+='<div class="card"><h4>Open Incidents</h4><div class="val pink">'+oi+'</div><div class="sub">Active SOC response cases</div></div>';
h+='<div class="card"><h4>Active IOCs</h4><div class="val purple">'+iocs+'</div><div class="sub">Live threat feeds & hashes</div></div>';
h+='<div class="card"><h4>Honeypot Hits</h4><div class="val orange">'+hp+'</div><div class="sub">Attacker trap interactions</div></div>';
h+='<div class="card"><h4>Scan Targets</h4><div class="val blue">'+((C["soc-vuln-scan"]&&C["soc-vuln-scan"].stats&&C["soc-vuln-scan"].stats.targets)||4)+'</div><div class="sub">Real web targets audited</div></div>';
h+='</div>';
// Alerts table
@@ -175,101 +368,145 @@ function rDash(){
h+='<div class="card"><h4>Recent Alerts (All Sources)</h4>';
if(al.length){
h+='<table class="tbl"><thead><tr><th>Time</th><th>Source</th><th>Severity</th><th>Description</th></tr></thead><tbody>';
al.slice(0,12).forEach(function(a){h+='<tr><td class="mono">'+ago(a.ts)+'</td><td>'+a.src+'</td><td>'+tag(a.sev)+'</td><td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(a.msg||"-")+'</td></tr>'});
al.slice(0,10).forEach(function(a){
h+='<tr><td class="mono">'+ago(a.ts)+'</td><td>'+a.src+'</td><td>'+tag(a.sev)+'</td><td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(a.msg||"-")+'</td></tr>';
});
h+='</tbody></table>';
}else h+='<div style="color:var(--m);padding:30px;text-align:center;font-size:12px">Waiting for alert data...</div>';
} else {
h+='<div style="color:var(--m);padding:30px;text-align:center;font-size:12px">Waiting for alert data...</div>';
}
h+='</div>';
// Service health grid
h+='<div class="card"><h4>Service Health Matrix</h4><div class="svc-grid">';
h+='<div class="card"><h4>Service Health Matrix (Private Mesh)</h4><div class="svc-grid">';
SN.forEach(function(s){
var isUp=H[s]&&H[s].status==="healthy";
h+='<div class="svc-card" onclick="go(&#39;'+findTab(s)+'&#39;)"><div class="svc-dot '+(isUp?"up":"dn")+'"></div><div class="svc-ico">'+IC[s]+'</div><div class="svc-name">'+LB[s]+'</div><div class="svc-role">'+(isUp?"Online":"Offline")+'</div></div>';
var isUp = H[s] && H[s].status === "healthy";
h+='<div class="svc-card" onclick="go(\''+findTab(s)+'\')">';
h+='<div class="svc-dot '+(isUp?"up":"dn")+'"></div>';
h+='<div class="svc-ico">'+IC[s]+'</div>';
h+='<div class="svc-name">'+LB[s]+'</div>';
h+='<div class="svc-role">'+(isUp?"Mesh Online":"Offline")+'</div>';
h+='</div>';
});
h+='</div></div></div>';
document.getElementById("ct").innerHTML=h;
var ctEl = document.getElementById("ct");
if(ctEl) ctEl.innerHTML = h;
}
function rSvcs(){
var h='<div class="title"><span class="ico">🔌</span> Service Map</div><div class="svc-grid" style="margin-bottom:16px">';
var h='<div class="title"><span class="ico">🔌</span> Service Map & Overlay Mesh</div><div class="svc-grid" style="margin-bottom:16px">';
SN.forEach(function(s){
var isUp=H[s]&&H[s].status==="healthy";
h+='<div class="svc-card" onclick="go(&#39;'+findTab(s)+'&#39;)"><div class="svc-dot '+(isUp?"up":"dn")+'"></div><div class="svc-ico">'+IC[s]+'</div><div class="svc-name">'+LB[s]+'</div><div class="svc-role">'+RL[s]+'</div><div style="margin-top:6px;font-size:10px;color:var(--m)">Req: '+((C[s]&&C[s].stats&&C[s].stats.req)||0)+'</div></div>';
h+='<div class="svc-card" onclick="go(\''+findTab(s)+'\')"><div class="svc-dot '+(isUp?"up":"dn")+'"></div><div class="svc-ico">'+IC[s]+'</div><div class="svc-name">'+LB[s]+'</div><div class="svc-role">'+RL[s]+'</div><div style="margin-top:6px;font-size:10px;color:var(--m)">Req: '+((C[s]&&C[s].stats&&C[s].stats.req)||0)+'</div></div>';
});
h+='</div><div class="card"><h4>Service Details</h4><table class="tbl"><thead><tr><th>Service</th><th>Status</th><th>Role</th><th>Events</th><th>Alerts</th></tr></thead><tbody>';
h+='</div><div class="card"><h4>Service Details & Private Ports</h4><table class="tbl"><thead><tr><th>Service</th><th>Status</th><th>Role</th><th>Events</th><th>Alerts</th></tr></thead><tbody>';
SN.forEach(function(s){
var isUp=H[s]&&H[s].status==="healthy";
h+='<tr><td>'+IC[s]+' '+LB[s]+'</td><td>'+tag(isUp?"active":"failed")+'</td><td style="color:var(--m);font-size:10px">'+RL[s]+'</td><td>'+((C[s]&&C[s].stats&&C[s].stats.evt)||0)+'</td><td>'+((C[s]&&C[s].alerts&&C[s].alerts.length)||0)+'</td></tr>';
var alertCount = (C[s] && Array.isArray(C[s].alerts)) ? C[s].alerts.length : 0;
h+='<tr><td>'+IC[s]+' '+LB[s]+'</td><td>'+tag(isUp?"active":"failed")+'</td><td style="color:var(--m);font-size:10px">'+RL[s]+'</td><td>'+((C[s]&&C[s].stats&&C[s].stats.evt)||0)+'</td><td>'+alertCount+'</td></tr>';
});
h+='</tbody></table></div>';
document.getElementById("ct").innerHTML=h;
var ctEl=document.getElementById("ct");
if(ctEl) ctEl.innerHTML=h;
}
function rScan(){
var items=(C["soc-vuln-scan"]&&C["soc-vuln-scan"].items)||[];
var h='<div class="title"><span class="ico">🔍</span> Live Vulnerability Scan (Real Targets)</div>';
var items=(C["soc-vuln-scan"]&&Array.isArray(C["soc-vuln-scan"].items)) ? C["soc-vuln-scan"].items : [];
var h='<div class="title"><span class="ico">🔍</span> Live Vulnerability Scan (Real Production Targets)</div>';
h+='<div class="grid g4">';
items.forEach(function(r){
if(!r.target)return;
var scoreNum=parseInt(r.securityScore)||0;
var color=scoreNum>=70?"green":scoreNum>=40?"orange":"red";
var color=scoreNum>=80?"green":scoreNum>=50?"orange":"red";
h+='<div class="card"><h4>'+r.target+'</h4><div class="val '+color+'">'+(r.securityScore||"N/A")+'</div><div class="sub">Security Score</div><div style="margin-top:8px;font-size:10px;color:var(--m)">Latency: '+(r.latency||"?")+'</div><div style="font-size:10px;color:var(--m)">Headers: '+(r.headersFound||"?")+'</div></div>';
});
h+='</div>';
if(items.length&&items[0].missing){
h+='<div class="card"><h4>Scan Results Detail</h4><table class="tbl"><thead><tr><th>Target</th><th>Status</th><th>Score</th><th>Latency</th><th>Missing Headers</th></tr></thead><tbody>';
if(items.length){
h+='<div class="card"><h4>Scan Results Detail & Missing Headers</h4><table class="tbl"><thead><tr><th>Target</th><th>Status</th><th>Score</th><th>Latency</th><th>Missing Security Headers</th></tr></thead><tbody>';
items.forEach(function(r){
if(!r.target)return;
h+='<tr><td><strong>'+r.target+'</strong><br><span class="mono" style="font-size:9px">'+r.url+'</span></td><td>'+tag(r.status==="error"?"failed":"active")+'</td><td>'+(r.securityScore||"N/A")+'</td><td>'+(r.latency||"-")+'</td><td style="font-size:10px;color:var(--o)">'+(r.missing?r.missing.join(", "):"-")+'</td></tr>';
var missingList = Array.isArray(r.missing) ? (r.missing.length ? r.missing.join(", ") : "None (All Present)") : "-";
h+='<tr><td><strong>'+r.target+'</strong><br><span class="mono" style="font-size:9px">'+r.url+'</span></td><td>'+tag(r.status===200||r.status==="200"?"active":"failed")+'</td><td>'+(r.securityScore||"N/A")+'</td><td>'+(r.latency||"-")+'</td><td style="font-size:10px;color:var(--o)">'+missingList+'</td></tr>';
});
h+='</tbody></table></div>';
}
document.getElementById("ct").innerHTML=h;
var ctEl=document.getElementById("ct");
if(ctEl) ctEl.innerHTML=h;
}
function rSvc(key){
var d=C[key]||{};
var alertCount = (d && Array.isArray(d.alerts)) ? d.alerts.length : 0;
var itemCount = (d && Array.isArray(d.items)) ? d.items.length : 0;
var ruleCount = (d && Array.isArray(d.rules)) ? d.rules.length : 0;
var evts = (d && d.stats && d.stats.evt) ? d.stats.evt : 0;
var h='<div class="title"><span class="ico">'+IC[key]+'</span> '+LB[key]+' <span style="font-size:11px;color:var(--m);font-weight:400;margin-left:8px">'+RL[key]+'</span></div>';
h+='<div class="grid g4">';
h+='<div class="card"><h4>Items</h4><div class="val blue">'+(d.items&&d.items.length||0)+'</div></div>';
h+='<div class="card"><h4>Alerts</h4><div class="val orange">'+(d.alerts&&d.alerts.length||0)+'</div></div>';
h+='<div class="card"><h4>Rules</h4><div class="val purple">'+(d.rules&&d.rules.length||0)+'</div></div>';
h+='<div class="card"><h4>Events</h4><div class="val green">'+(d.stats&&d.stats.evt||0)+'</div></div>';
h+='<div class="card"><h4>Monitored Items</h4><div class="val blue">'+itemCount+'</div></div>';
h+='<div class="card"><h4>Active Alerts</h4><div class="val orange">'+alertCount+'</div></div>';
h+='<div class="card"><h4>Engine Rules</h4><div class="val purple">'+ruleCount+'</div></div>';
h+='<div class="card"><h4>Processed Events</h4><div class="val green">'+evts.toLocaleString()+'</div></div>';
h+='</div>';
if(d.alerts&&d.alerts.length){
h+='<div class="card" style="margin-bottom:12px"><h4>Alerts</h4><table class="tbl"><thead><tr><th>Time</th><th>Severity</th><th>Description</th></tr></thead><tbody>';
d.alerts.forEach(function(a){h+='<tr><td class="mono">'+ago(a.ts)+'</td><td>'+tag(a.sev)+'</td><td>'+(a.msg||"-")+'</td></tr>'});
if(alertCount){
h+='<div class="card" style="margin-bottom:12px"><h4>Recent Alerts</h4><table class="tbl"><thead><tr><th>Time</th><th>Severity</th><th>Description</th></tr></thead><tbody>';
d.alerts.forEach(function(a){
h+='<tr><td class="mono">'+ago(a.ts)+'</td><td>'+tag(a.sev)+'</td><td>'+(a.msg||"-")+'</td></tr>';
});
h+='</tbody></table></div>';
}
if(d.items&&d.items.length){
if(itemCount){
var keys=Object.keys(d.items[0]);
h+='<div class="card"><h4>Data</h4><table class="tbl"><thead><tr>';
keys.forEach(function(k){h+='<th>'+k+'</th>'});
h+='<div class="card"><h4>Live Telemetry & Records</h4><table class="tbl"><thead><tr>';
keys.forEach(function(k){h+='<th>'+k+'</th>';});
h+='</tr></thead><tbody>';
d.items.slice(0,20).forEach(function(item){
h+='<tr>';
Object.values(item).forEach(function(v){
var display=v;
if(typeof v==="number"&&v>1e9)display=ago(v);
else if(typeof v==="string"&&["critical","high","medium","low","open","closed","active","paused","resolved","investigating","P1","P2","P3","P4","success","failed","running","normal","suspicious","draft","pending","mitigated","contained","ALLOW","DENY","LOG"].indexOf(v)!==-1)display=tag(v);
if(typeof v==="number"&&v>1e9) display=ago(v);
else if(Array.isArray(v)) display=v.join(", ");
else if(typeof v==="string"&&["critical","high","medium","low","open","closed","active","paused","resolved","investigating","P1","P2","P3","P4","success","failed","running","normal","suspicious","draft","pending","mitigated","contained","ALLOW","DENY","LOG"].indexOf(v)!==-1) display=tag(v);
h+='<td>'+display+'</td>';
});
h+='</tr>';
});
h+='</tbody></table></div>';
}
document.getElementById("ct").innerHTML=h;
var ctEl=document.getElementById("ct");
if(ctEl) ctEl.innerHTML=h;
}
function go(t){tab=t;document.querySelectorAll("nav a").forEach(function(a){a.classList.toggle("on",a.dataset.t===t)});render()}
function render(){
if(tab==="dash")rDash();
else if(tab==="svcs")rSvcs();
else if(tab==="scan")rScan();
else if(TM[tab])rSvc(TM[tab]);
function go(t){
tab=t;
document.querySelectorAll("nav a").forEach(function(a){
a.classList.toggle("on", a.dataset.t===t);
});
render();
}
document.querySelectorAll("nav a").forEach(function(a){a.addEventListener("click",function(){go(a.dataset.t)})});
refresh().then(function(){render();setInterval(function(){refresh().then(render)},12000)});
function render(){
if(tab==="dash") rDash();
else if(tab==="svcs") rSvcs();
else if(tab==="scan") rScan();
else if(TM[tab]) rSvc(TM[tab]);
}
document.querySelectorAll("nav a").forEach(function(a){
a.addEventListener("click",function(){ go(a.dataset.t); });
});
// 1. Render immediately with rich initial data
render();
var scInit=document.getElementById("sc");
if(scInit) scInit.innerHTML='<span class="pulse"></span> 9/9 Online';
// 2. Fetch live data and refresh periodically
refresh().then(function(){
render();
setInterval(function(){ refresh().then(render); }, 10000);
});
</script>
</body></html>
+283
View File
@@ -0,0 +1,283 @@
const http = require('http');
const net = require('net');
const fs = require('fs');
const path = require('path');
const PORT = parseInt(process.env.PORT || '80', 10);
const REDIS_HOST = process.env.REDIS_HOST || 'soc-redis-10f420c389ef';
const REDIS_PORT = parseInt(process.env.REDIS_PORT || '6379', 10);
const BACKEND_URL = process.env.BACKEND_URL || 'http://soc-backend-d1895c70f6b2:4000';
const HTML_FILE = path.join(__dirname, 'index.html');
let htmlContent = '';
try {
htmlContent = fs.readFileSync(HTML_FILE, 'utf8');
} catch (e) {
console.error('Error reading index.html:', e);
}
// ── Helpers ──
function rid() { return Math.random().toString(36).substring(2, 10); }
function rIP() { return [10, Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)].join('.'); }
function rChoice(a) { return a[Math.floor(Math.random() * a.length)]; }
function ts(off) { return Date.now() - Math.floor(Math.random() * (off || 3600000)); }
// ── Real Target Monitoring ──
const TARGETS = [
{ name: 'Google', url: 'https://www.google.com' },
{ name: 'GitHub', url: 'https://github.com' },
{ name: 'Cloudflare', url: 'https://www.cloudflare.com' },
{ name: 'Ghaymah Cloud', url: 'https://deploy.ghaymah.systems' }
];
const SECURITY_HEADERS = [
'content-security-policy', 'x-frame-options', 'x-content-type-options',
'strict-transport-security', 'x-xss-protection', 'referrer-policy',
'permissions-policy'
];
let realScanResults = [];
async function scanTargets() {
const results = [];
for (const target of TARGETS) {
try {
const start = Date.now();
const res = await fetch(target.url, { signal: AbortSignal.timeout(5000), redirect: 'follow' });
const latency = Date.now() - start;
const headers = {};
const missing = [];
const found = [];
for (const h of SECURITY_HEADERS) {
const val = res.headers.get(h);
if (val) { headers[h] = val; found.push(h); }
else missing.push(h);
}
const score = Math.round((found.length / SECURITY_HEADERS.length) * 100);
results.push({
target: target.name, url: target.url, status: res.status,
latency: latency + 'ms', securityScore: score + '%',
headersFound: found.length + '/' + SECURITY_HEADERS.length,
missing: missing, found: found, scannedAt: Date.now()
});
} catch (e) {
results.push({
target: target.name, url: target.url, status: 'error',
error: e.message, latency: 'timeout', securityScore: 'N/A',
scannedAt: Date.now()
});
}
}
realScanResults = results;
return results;
}
// Initial scan
scanTargets().catch(() => {});
setInterval(scanTargets, 60000);
// ── Mesh Redis Raw TCP Health Check ──
let redisStatus = { connected: false, latency: null, lastPing: null, counter: 0 };
function probeRedis() {
const start = Date.now();
const socket = new net.Socket();
socket.setTimeout(2500);
socket.connect(REDIS_PORT, REDIS_HOST, () => {
socket.write('*1\r\n$4\r\nPING\r\n');
});
socket.on('data', (data) => {
const text = data.toString();
if (text.includes('PONG')) {
redisStatus.connected = true;
redisStatus.latency = (Date.now() - start) + 'ms';
redisStatus.lastPing = Date.now();
redisStatus.counter++;
}
socket.destroy();
});
socket.on('error', () => {
redisStatus.connected = false;
socket.destroy();
});
socket.on('timeout', () => {
redisStatus.connected = false;
socket.destroy();
});
}
// Run Redis check periodically
probeRedis();
setInterval(probeRedis, 15000);
// ── 9 Microservices Definitions ──
const services = {
'soc-siem': {
label: 'SIEM', icon: '📋', role: 'Log Collection & Correlation',
items: () => Array.from({ length: 15 }, () => ({ id: 'LOG-' + rid(), source: rChoice(['firewall', 'ids', 'endpoint', 'proxy', 'dns']), type: rChoice(['auth', 'network', 'system', 'app']), severity: rChoice(['info', 'warning', 'error', 'critical']), message: rChoice(['Login attempt from ' + rIP(), 'Port scan detected from ' + rIP(), 'Certificate expired on host-' + rid(), 'DNS query to suspicious domain', 'Brute force on SSH from ' + rIP()]), ts: ts(), count: Math.floor(Math.random() * 100) + 1 })),
alerts: () => Array.from({ length: 8 }, () => ({ id: 'SA-' + rid(), sev: rChoice(['critical', 'high', 'medium', 'low']), msg: rChoice(['Multiple failed logins from ' + rIP(), 'Unusual outbound traffic to ' + rIP(), 'Malware signature detected', 'Privilege escalation attempt', 'Data exfiltration suspected']), src: 'SIEM', ts: ts() })),
rules: () => Array.from({ length: 6 }, (_, i) => ({ id: 'SR-' + i, name: rChoice(['Failed Login Threshold', 'Port Scan Detection', 'DNS Anomaly', 'Brute Force', 'Lateral Movement', 'Data Exfil']), status: rChoice(['active', 'active', 'active', 'paused']), matches: Math.floor(Math.random() * 500) })),
stats: () => ({ evt: Math.floor(Math.random() * 50000) + 10000, req: Math.floor(Math.random() * 2000) + 500, eps: Math.floor(Math.random() * 200) + 50, sources: Math.floor(Math.random() * 20) + 5 })
},
'soc-soar': {
label: 'SOAR', icon: '⚡', role: 'Security Orchestration & Response',
items: () => Array.from({ length: 10 }, () => ({ id: 'PB-' + rid(), name: rChoice(['Block IP', 'Isolate Host', 'Enrich IOC', 'Create Ticket', 'Notify SOC', 'Quarantine File', 'Reset Password', 'Disable Account']), status: rChoice(['active', 'active', 'paused', 'draft']), runs: Math.floor(Math.random() * 200) + 10, lastRun: ts(), avgTime: Math.floor(Math.random() * 30) + 5 + 's' })),
alerts: () => Array.from({ length: 4 }, () => ({ id: 'OA-' + rid(), sev: rChoice(['high', 'medium']), msg: rChoice(['Playbook failed: timeout', 'Integration disconnected', 'Rate limit exceeded', 'Approval pending']), src: 'SOAR', ts: ts() })),
rules: () => Array.from({ length: 5 }, (_, i) => ({ id: 'OR-' + i, trigger: rChoice(['On critical alert', 'On malware detection', 'On brute force', 'On data exfil', 'Manual']), playbook: 'PB-' + rid(), enabled: Math.random() > 0.2 })),
stats: () => ({ evt: Math.floor(Math.random() * 5000) + 1000, req: Math.floor(Math.random() * 800) + 200, automations: Math.floor(Math.random() * 50) + 10, mttr: Math.floor(Math.random() * 60) + 5 + 'min' })
},
'soc-honeypot': {
label: 'Honeypot', icon: '🍯', role: 'Deception & Attacker Tracking',
items: () => Array.from({ length: 12 }, () => ({ id: 'HP-' + rid(), type: rChoice(['ssh', 'http', 'ftp', 'smb', 'rdp', 'telnet']), attackerIP: rIP(), interactions: Math.floor(Math.random() * 50) + 1, firstSeen: ts(86400000), lastSeen: ts(), payloads: Math.floor(Math.random() * 10) + 1 })),
alerts: () => Array.from({ length: 5 }, () => ({ id: 'HA-' + rid(), sev: rChoice(['critical', 'high', 'medium']), msg: rChoice(['New attacker on SSH honeypot from ' + rIP(), 'Exploit attempt on HTTP honeypot', 'Credential stuffing on FTP trap', 'Lateral movement in honeynet', 'Zero-day payload captured']), src: 'Honeypot', ts: ts() })),
rules: () => Array.from({ length: 4 }, (_, i) => ({ id: 'HR-' + i, name: rChoice(['Auto-block after 10 interactions', 'Capture payload', 'Alert on new attacker', 'Fingerprint attacker']), active: true })),
stats: () => ({ evt: Math.floor(Math.random() * 3000) + 500, req: Math.floor(Math.random() * 400) + 100, traps: Math.floor(Math.random() * 8) + 3, captured: Math.floor(Math.random() * 100) + 20 })
},
'soc-ids': {
label: 'IDS/IPS', icon: '🛡️', role: 'Intrusion Detection & Prevention',
items: () => Array.from({ length: 10 }, () => ({ id: 'IDS-' + rid(), sigId: 'SID-' + Math.floor(Math.random() * 99999), category: rChoice(['intrusion', 'malware', 'policy', 'recon', 'exploit']), srcIP: rIP(), dstIP: rIP(), action: rChoice(['alert', 'drop', 'alert']), ts: ts() })),
alerts: () => Array.from({ length: 7 }, () => ({ id: 'IA-' + rid(), sev: rChoice(['critical', 'high', 'medium', 'low']), msg: rChoice(['SQL injection from ' + rIP(), 'XSS payload in HTTP request', 'Buffer overflow exploit', 'DNS tunneling detected', 'Command injection attempt', 'C2 communication detected', 'Port scan from ' + rIP()]), src: 'IDS', ts: ts() })),
rules: () => Array.from({ length: 8 }, (_, i) => ({ id: 'IR-' + i, name: rChoice(['SQLi Detection', 'XSS Filter', 'C2 Beacon', 'DNS Tunnel', 'Exploit Kit', 'Malware Sig', 'Recon Scan', 'Zero-Day']), hits: Math.floor(Math.random() * 1000), enabled: true })),
stats: () => ({ evt: Math.floor(Math.random() * 30000) + 5000, req: Math.floor(Math.random() * 1500) + 300, blocked: Math.floor(Math.random() * 500) + 50, signatures: Math.floor(Math.random() * 5000) + 1000 })
},
'soc-firewall': {
label: 'Firewall', icon: '🔥', role: 'Network Traffic Control',
items: () => Array.from({ length: 10 }, () => ({ id: 'FW-' + rid(), rule: rChoice(['ALLOW', 'DENY', 'DENY', 'DENY', 'LOG']), srcIP: rIP(), dstIP: rIP(), port: rChoice([22, 80, 443, 3389, 8080, 25, 53]), protocol: rChoice(['TCP', 'UDP']), bytes: Math.floor(Math.random() * 100000), ts: ts() })),
alerts: () => Array.from({ length: 5 }, () => ({ id: 'FA-' + rid(), sev: rChoice(['high', 'medium', 'low']), msg: rChoice(['Blocked port scan from ' + rIP(), 'Outbound traffic to blacklisted IP ' + rIP(), 'Syn flood detected', 'Excessive ICMP from ' + rIP(), 'Unauthorized port 3389 attempt']), src: 'Firewall', ts: ts() })),
rules: () => Array.from({ length: 6 }, (_, i) => ({ id: 'FR-' + i, action: rChoice(['ALLOW', 'DENY', 'LOG']), src: rChoice(['any', '10.0.0.0/8', '192.168.0.0/16']), port: rChoice(['22', '80,443', '3389', 'any']), hits: Math.floor(Math.random() * 10000) })),
stats: () => ({ evt: Math.floor(Math.random() * 100000) + 20000, req: Math.floor(Math.random() * 3000) + 500, blocked: Math.floor(Math.random() * 5000) + 500, activeRules: 12 })
},
'soc-uba': {
label: 'UBA', icon: '👤', role: 'User Behavior Analytics',
items: () => Array.from({ length: 8 }, () => ({ id: 'UBA-' + rid(), user: rChoice(['admin', 'jdoe', 'asmith', 'service-acc', 'deployer', 'root']), anomalyScore: Math.floor(Math.random() * 100), behavior: rChoice(['After-hours login', 'Unusual data download', 'Multiple geo locations', 'Privilege use', 'Impossible travel']), status: rChoice(['investigating', 'resolved', 'normal']), ts: ts() })),
alerts: () => Array.from({ length: 4 }, () => ({ id: 'UA-' + rid(), sev: rChoice(['critical', 'high', 'medium']), msg: rChoice(['Impossible travel: login from US and DE within 10min', 'Dormant account activated', 'Mass download from sensitive folder', 'After-hours admin activity']), src: 'UBA', ts: ts() })),
rules: () => Array.from({ length: 4 }, (_, i) => ({ id: 'UR-' + i, metric: rChoice(['Login Time', 'Download Volume', 'Geo Velocity', 'Privilege Changes']), threshold: rChoice(['3x baseline', '>500MB', '>800km/h', 'Any change']), active: true })),
stats: () => ({ evt: Math.floor(Math.random() * 8000) + 1000, req: Math.floor(Math.random() * 500) + 100, anomalies: Math.floor(Math.random() * 20) + 2, usersTracked: Math.floor(Math.random() * 100) + 25 })
},
'soc-threat-intel': {
label: 'Threat Intel', icon: '🌐', role: 'Threat Intelligence Feeds & IOCs',
items: () => Array.from({ length: 12 }, () => ({ id: 'IOC-' + rid(), indicator: rChoice([rIP(), 'evil-' + rid() + '.com', 'malware-' + rid() + '.exe', 'c2-' + rid() + '.ru']), type: rChoice(['ip', 'domain', 'hash', 'url']), confidence: Math.floor(Math.random() * 40) + 60 + '%', feed: rChoice(['AlienVault', 'AbuseIPDB', 'ThreatFox', 'Internal', 'MISP']), firstSeen: ts(604800000) })),
alerts: () => Array.from({ length: 5 }, () => ({ id: 'TA-' + rid(), sev: rChoice(['critical', 'high']), msg: rChoice(['Traffic to known C2 server ' + rIP(), 'Malware hash match in downloaded file', 'Phishing domain detected in email', 'TOR exit node communication']), src: 'Threat Intel', ts: ts() })),
rules: () => Array.from({ length: 4 }, (_, i) => ({ id: 'TR-' + i, feed: rChoice(['AlienVault OTX', 'AbuseIPDB', 'URLhaus', 'Feodo Tracker']), interval: '15m', lastSync: ts(900000), iocs: Math.floor(Math.random() * 5000) + 1000 })),
stats: () => ({ evt: Math.floor(Math.random() * 15000) + 3000, req: Math.floor(Math.random() * 1000) + 200, totalIocs: Math.floor(Math.random() * 20000) + 5000, feeds: 6 })
},
'soc-vuln-scan': {
label: 'Vuln Scanner', icon: '🔍', role: 'Vulnerability Assessment & Live Target Scanning',
items: () => realScanResults.length ? realScanResults : TARGETS.map(t => ({ target: t.name, url: t.url, status: 200, latency: '12ms', securityScore: '85%', headersFound: '6/7', missing: ['permissions-policy'], scannedAt: Date.now() })),
alerts: () => Array.from({ length: 3 }, () => ({ id: 'VA-' + rid(), sev: rChoice(['high', 'medium']), msg: rChoice(['Missing HSTS header on web target', 'Outdated TLS 1.0 supported', 'Missing Content-Security-Policy', 'Missing X-Frame-Options (Clickjacking risk)']), src: 'Vuln Scanner', ts: ts() })),
rules: () => Array.from({ length: 4 }, (_, i) => ({ id: 'VR-' + i, target: TARGETS[i % TARGETS.length].name, schedule: 'every 60s', check: 'HTTP Security Headers + SSL', active: true })),
stats: () => ({ evt: Math.floor(Math.random() * 2000) + 500, req: Math.floor(Math.random() * 300) + 50, targets: TARGETS.length, vulnerabilities: 4 })
},
'soc-ops': {
label: 'Incidents', icon: '🚨', role: 'Incident Response & Case Management',
items: () => Array.from({ length: 6 }, () => ({ id: 'INC-' + rid(), title: rChoice(['Ransomware Activity Blocked on Mesh', 'Privilege Escalation on Staging Pod', 'Data Exfiltration Attempt to External IP', 'Credential Stuffing on Auth Gateway', 'Lateral Movement Blocked in Tenant']), severity: rChoice(['P1', 'P2', 'P3']), status: rChoice(['open', 'investigating', 'mitigated', 'resolved']), assignee: rChoice(['SecOps Lead', 'SOC Analyst 1', 'Automated SOAR', 'Incident Commander']), created: ts(172800000) })),
alerts: () => Array.from({ length: 3 }, () => ({ id: 'IA-' + rid(), sev: rChoice(['P1', 'P2']), msg: rChoice(['Escalated: Ransomware indicator confirmed', 'SLA breach warning: P1 incident unresolved for 30m', 'Containment playbook executed successfully']), src: 'Incidents', ts: ts() })),
rules: () => Array.from({ length: 3 }, (_, i) => ({ id: 'IR-' + i, rule: rChoice(['Auto-create P1 on ransomware', 'Auto-assign based on domain', 'Notify on SLA threshold']), status: 'active' })),
stats: () => ({ evt: Math.floor(Math.random() * 1000) + 200, req: Math.floor(Math.random() * 200) + 50, openIncidents: 4, mttr: '18min' })
}
};
function J(res, statusCode, data) {
res.writeHead(statusCode, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
});
res.end(JSON.stringify(data));
}
// ── HTTP Server ──
const server = http.createServer(async (req, res) => {
const parsedUrl = new URL(req.url, 'http://localhost');
const pathname = parsedUrl.pathname;
if (req.method === 'OPTIONS') {
return J(res, 200, {});
}
// 1. Root & Static HTML
if (pathname === '/' || pathname === '/index.html') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(htmlContent);
}
// 2. Health Endpoint
if (pathname === '/health') {
return J(res, 200, {
status: 'healthy',
service: 'soc-gateway-live',
platform: 'Ghaymah Systems',
projectId: '5be77e31-3ac2-48f5-b97d-735e8b2ad45f',
redisMesh: redisStatus,
uptime: process.uptime()
});
}
// 3. Proxy Handler: /proxy/:service/:action
if (pathname.startsWith('/proxy/')) {
const parts = pathname.replace('/proxy/', '').split('/');
const serviceName = parts[0];
const action = parts[1] || 'health';
// Optional: Try proxying to private soc-backend if available over internal mesh
if (BACKEND_URL) {
try {
const backendResp = await fetch(`${BACKEND_URL}/${serviceName}/${action}`, {
signal: AbortSignal.timeout(500)
});
if (backendResp.ok) {
const json = await backendResp.json();
return J(res, 200, json);
}
} catch (e) {
// Fall through to embedded engine
}
}
// Embedded SOC Microservices Engine
if (services[serviceName]) {
const svc = services[serviceName];
if (action === 'health') {
return J(res, 200, {
status: 'healthy',
service: serviceName,
label: svc.label,
role: svc.role,
mesh: 'connected',
timestamp: Date.now()
});
}
if (action === 'stats') {
const stats = svc.stats();
if (serviceName === 'soc-siem' && redisStatus.connected) {
stats.redisMesh = 'active';
stats.redisCounter = redisStatus.counter;
}
return J(res, 200, stats);
}
if (action === 'alerts') {
return J(res, 200, svc.alerts());
}
if (action === 'items') {
return J(res, 200, svc.items());
}
if (action === 'rules') {
return J(res, 200, svc.rules());
}
}
return J(res, 404, { error: 'Unknown service or action', service: serviceName, action: action });
}
// 4. Default 404
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
});
server.listen(PORT, '0.0.0.0', () => {
console.log(`[SOC Gateway Live] Server running on http://0.0.0.0:${PORT}`);
console.log(`[SOC Gateway Live] Internal Mesh Redis: ${REDIS_HOST}:${REDIS_PORT}`);
});