UI
Three files under static/:
| File | Content |
|---|---|
socrates.html |
HTML shell |
static/socrates.css |
All styles |
static/socrates.js |
All JavaScript |
socrates.html loads the CSS and JS via <link> and <script src> tags. D3 and d3-sankey are vendored in static/ for offline use.
UI States
Welcome Screen (no analysis loaded)
├── URL input + file upload
└── Previous analyses list
Analysis View (analysis loaded)
├── Header (back button, name, path, date range)
├── Visualizations bar (Diagram toggle, Aggregation toggle)
├── Filter Bar (active search and filters as removable chips)
├── Stats Grid (clickable event-type cards, shows filtered/total counts when active)
├── Sankey Diagram (diagram mode — Source IP → Dest IP → Dest Port, reflects current filters)
├── Aggregations (frequency counts per column)
└── Data Sections (tabbed tables)
JavaScript Architecture
Global state:
let allEvents = []; // Loaded for "All Events" tab
let eventTypes = []; // available types for current analysis
let currentMd5 = ''; // current analysis MD5
let currentFileName = ''; // display name
let currentFilters = {}; // {columnName: value} — global, flat
let currentSearch = []; // server-side full-text search terms (array)
let baseEventStats = {}; // unfiltered totals for stats card denominator
let advancedMode = false; // advanced toggle state
let tabDataCache = {}; // cached event data per type
Key function groups:
| Group | Functions | Purpose |
|---|---|---|
| Navigation | showWelcome(), loadAnalysis(), showTab(), showWelcomeUI(), showAnalysisUI() |
Screen/tab switching |
| Data Loading | loadTabData(), loadFromUrl(), uploadPcap(), checkStatus() |
Fetch data from API |
| Rendering | buildStats(), buildSections(), buildSection(), buildAllEvents(), buildRowForEvent(), updateSankeyDiagram() |
Build HTML |
| Aggregation | buildAggregationTablesCore(), buildAggregationTables(), buildAggregationTablesAll(), buildAggregationsSection(), buildAggregationsSectionAll() |
Frequency grids |
| Search | performSearch(), clearSearchTerm(), refreshAnalysisData() |
Full-text search via server |
| Filtering | applyFilter(), applyFilters(), clearFilter(), clearAllFilters(), getFilteredEvents(), getSankeyEvents(), refreshCurrentView() |
Column filter management |
| Streams | downloadPcap(), loadAsciiTranscript(), loadHexdumpData(), switchStreamView(), togglePacket(), toggleRow() |
Stream analysis |
| Utilities | escapeHtml(), formatEvent(), extractValue(), extractAllValue(), getColumnsForType(), clearAnalysisContainers() |
Helpers |
Column System
Each event type has its own column set. The "All Events" view uses a unified column set.
Shared columns (all types): Time, Protocol, Source IP, Source Port, Dest IP, Dest Port
Per-type columns: e.g. Alert/Category/Severity (alerts), Query/Type (DNS), Method/Host/URL/Status (HTTP). Every event type on the Event Types page has its own set — 30+ types by now — defined in getColumnsForType() (static/socrates.js), which is the source of truth; this doc intentionally doesn't enumerate all of them; a full list here would just drift out of sync with every new protocol added (the same problem already found and fixed once in filtering.md's old "Column Overlap" table).
All-events columns: Type (event type), Detail (type-specific summary)
Filtering Design
Filters are global — currentFilters is a flat {columnName: value} object. When switching tabs, filters for columns that don't exist in the new view are silently skipped (the column lookup returns -1 and the filter is ignored).
See filtering.md for full details.