admin / SAynapse-Horizon
publicSelf Hosted Cyber Threat Intelligence Hub
SAynapse-Horizon / Synapse-Horizon-v2 / README.md
7182 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | # Synapse-Horizon v2 A modern, dark-mode-first **Cyber Threat Intelligence (CTI) dashboard** for Tier-3 SOC analysts, threat hunters, and security architects. Synapse-Horizon ingests **live** telemetry from multiple CTI sources with divergent schemas, **normalizes** each indicator into a single scannable headline, and surfaces the most critical events on an executive triage radar. Built with **React 18 + Vite + Tailwind CSS + Lucide** on the frontend and a **Node/Express ingestion backend**, packaged for a **Docker Compose** environment. ## What's new in v2 - **Animated radar brandmark** — the static header logo is replaced by a live SVG radar (rotating sweep + pulsing blue contacts). Pure CSS/SVG, and it respects `prefers-reduced-motion` (the sweep freezes for users who opt out of motion). - **Critical-triage alarm** — a flashing red **"Critical · Triage Required"** pill sits next to the Pipeline indicator whenever any Critical Priority Triage event is unacknowledged. Each triage row has an **ACK** button (plus an **Acknowledge all**); the alarm stops only once every item is acknowledged, and re-arms automatically when a fresh pull brings new critical intel. - Runs on offset host ports (frontend `8081`, backend `4001`, dev `5191`) so it can run alongside v1. ## Live data architecture Browsers cannot call these CTI APIs directly (CORS blocks them, and several require secret API keys). So the stack runs two services: ``` ┌────────────────────┐ /api ┌────────────────────────┐ HTTPS ┌─────────────┐ │ horizon (nginx) │ ───proxy───▶ │ api (Node ingestion) │ ───fetch───▶ │ Live CTI │ │ React SPA :8081 │ │ normalize + cache │ │ APIs │ └────────────────────┘ ◀── JSON ── └────────────────────────┘ └─────────────┘ ``` The backend holds the API keys (never the browser), fetches each source on demand, normalizes every record into one uniform IOC schema, and exposes `GET /api/feeds` + `POST /api/sync`. --- ## Feature overview | Area | What it does | |------|--------------| | **Global key metrics** | Active feeds (`7 / 12`-style), latest feed-pull timestamp (`DD-MMM-YYYY HH:mm:ss UTC`), and total aggregated IOCs held in state. | | **Feed Control Panel** (left) | Per-source toggles for URLhaus, ThreatFox, Feodo Tracker, PhishTank, CISA KEV, Blocklist.de, AlienVault OTX, and an RSS parser — toggling instantly filters metrics, radar and feed. | | **Lifecycle controls** | Independent **Auto-Refresh Interval** (display polling: Manual/30s/1m/5m/15m) and **Feed Pull Cadence** (ingestion: On-Demand/1h/6h/24h), plus a prominent **Manual Force Sync**. | | **Critical Priority Triage** | Max 5 highest-severity events, auto-resorting when a lifecycle completes. | | **Normalized CTI Feed** | Full-width uniform rows: UTC time · source tag · normalized headline · **View Details**. | | **Drill-down drawer** | STIX/TAXII attributes, MITRE ATT&CK mappings, raw JSON payload, and a confidence meter. | | **Loading states** | Skeletons + spinners during force sync / cadence changes. | ## SOC alerting palette Restrained by design: **Emerald** = stable/active, **Amber** = suspicious/high, **Rose/Red** = critical / active exploitation, **Sky/Slate** = informational structure. --- ## Live sources & API keys | Source | Key required | Notes | |--------|:---:|-------| | **CISA KEV** | — | Public JSON. Live out of the box. | | **Blocklist.de** | — | Public IP lists. Live out of the box. | | **RSS Parser** | — | Public advisory feeds. Live out of the box. | | **URLhaus** | `ABUSE_CH_AUTH_KEY` | Free [abuse.ch](https://auth.abuse.ch/) account. | | **ThreatFox** | `ABUSE_CH_AUTH_KEY` | Same abuse.ch key. | | **Feodo Tracker** | `ABUSE_CH_AUTH_KEY` | Same abuse.ch key. | | **AlienVault OTX** | `OTX_API_KEY` | From your OTX account. | | **PhishTank** | `PHISHTANK_APP_KEY` | Registered application key. | Copy `.env.example` → `.env` and fill in the keys you have. Sources without a key report as **"needs API key"** in the sidebar instead of failing. Set `HORIZON_DEMO=1` to serve synthetic data for any un-keyed source so the dashboard is populated out of the box. ## Running it ### Production (nginx SPA + ingestion backend) ```bash cp .env.example .env # add any API keys you have (optional) docker compose up -d --build # open http://localhost:8081 (API on http://localhost:4001/api/feeds) ``` ### Hot-reloading dev stack ```bash docker compose --profile dev up # frontend http://localhost:5191 · backend http://localhost:4001 ``` ### Local (no Docker) ```bash # terminal 1 — ingestion backend cd backend && PORT=4001 npm start # http://localhost:4001 # terminal 2 — frontend (Vite proxies /api → :4001) npm install && npm run dev # http://localhost:5191 npm run build # emits ./dist ``` --- ## Architecture ``` backend/ # Node/Express ingestion service ├── src/server.js # routes, in-memory cache, background warm-up sync ├── src/normalize.js # IOC contract + fetch/timeout helpers + severity model └── src/sources/ ├── index.js # registry + concurrent, failure-isolated orchestration ├── cisakev.js blocklistde.js rss.js # no-key live sources ├── urlhaus.js threatfox.js feodo.js # abuse.ch (Auth-Key) ├── otx.js phishtank.js # OTX / PhishTank (keys) └── demo.js # synthetic fallback (HORIZON_DEMO=1) src/ # React frontend ├── App.jsx # layout shell + error banner ├── api/client.js # GET /api/feeds · POST /api/sync ├── hooks/useFeeds.js # single source of truth: toggles, store, cadences, lifecycle ├── data/sources.js # source registry + refresh/cadence option sets ├── utils/{format,theme}.js # UTC formatting · severity/accent/confidence styling └── components/ ├── Header.jsx Sidebar.jsx MetricsRow.jsx ├── CriticalTriagePanel.jsx CTIFeed.jsx DetailsDrawer.jsx └── ToggleSwitch.jsx ``` ### Data normalization Each source fetcher pulls its native schema live and compresses every record into one uniform IOC object (`backend/src/normalize.js → makeIoc`): ```js { id, source, detectedAt, ingestedAt, severity, category, indicator, indicatorType, target, confidence, mitre[], headline, raw, stix } ``` The UI only ever consumes this normalized shape, so URLhaus URLs, ThreatFox C2 IPs, and CISA KEV CVEs all render through the same components. Fetch failures are isolated per source — one API being down never sinks the rest of the pull. |