From aab8c8adfe8ba1a16af3b2ae07358ab5f43ea6e0 Mon Sep 17 00:00:00 2001 From: XSS3cut10n3r Date: Wed, 30 Sep 2026 06:38:12 +0100 Subject: [PATCH 1/5] feat(web): new UI with runs, presets, options and saved analyses --- src/web/analysis.rs | 458 +++++++++++++++++++++ src/web/api.rs | 310 ++++++++++++++- src/web/assets.rs | 64 ++- src/web/assets/OFL.txt | 93 ----- src/web/assets/app.css | 729 ---------------------------------- src/web/assets/app.js | 214 +++------- src/web/assets/catalog.js | 94 ----- src/web/assets/core.js | 29 +- src/web/assets/hex.js | 321 --------------- src/web/assets/index.html | 101 ++--- src/web/assets/layout.js | 86 ++++ src/web/assets/mark.svg | 5 - src/web/assets/mono-400.woff2 | Bin 21076 -> 0 bytes src/web/assets/mono-700.woff2 | Bin 21436 -> 0 bytes src/web/assets/options.js | 115 ++++++ src/web/assets/palette.js | 398 ------------------- src/web/assets/presets.js | 74 ++++ src/web/assets/procdata.js | 135 +++++++ src/web/assets/procs.js | 515 ------------------------ src/web/assets/quickstart.js | 256 ++++++++++++ src/web/assets/result.js | 359 ----------------- src/web/assets/results.js | 230 +++++++++++ src/web/assets/rules.js | 107 +++++ src/web/assets/table.js | 138 ++++++- src/web/assets/ui.css | 642 ++++++++++++++++++++++++++++++ src/web/assets/views.js | 656 ------------------------------ src/web/assets/workspace.js | 521 ++++++++++++++++++++++++ src/web/mod.rs | 140 ++++++- src/web/options.rs | 330 +++++++++++++++ src/web/picker.rs | 81 ++++ src/web/presets.rs | 254 ++++++++++++ src/web/runs.rs | 245 +++++++++++- src/web/session.rs | 18 +- src/web/tests.rs | 12 +- 34 files changed, 4270 insertions(+), 3460 deletions(-) create mode 100644 src/web/analysis.rs delete mode 100644 src/web/assets/OFL.txt delete mode 100644 src/web/assets/app.css delete mode 100644 src/web/assets/hex.js create mode 100644 src/web/assets/layout.js delete mode 100644 src/web/assets/mark.svg delete mode 100644 src/web/assets/mono-400.woff2 delete mode 100644 src/web/assets/mono-700.woff2 create mode 100644 src/web/assets/options.js delete mode 100644 src/web/assets/palette.js create mode 100644 src/web/assets/presets.js create mode 100644 src/web/assets/procdata.js delete mode 100644 src/web/assets/procs.js create mode 100644 src/web/assets/quickstart.js delete mode 100644 src/web/assets/result.js create mode 100644 src/web/assets/results.js create mode 100644 src/web/assets/rules.js create mode 100644 src/web/assets/ui.css delete mode 100644 src/web/assets/views.js create mode 100644 src/web/assets/workspace.js create mode 100644 src/web/options.rs create mode 100644 src/web/picker.rs create mode 100644 src/web/presets.rs diff --git a/src/web/analysis.rs b/src/web/analysis.rs new file mode 100644 index 0000000..09c3a47 --- /dev/null +++ b/src/web/analysis.rs @@ -0,0 +1,458 @@ +//! Saved analyses: `~/.fvol/-metadata.json` plus the result rows of each plugin in +//! `~/.fvol///.jsonl` (layout in docs/web-ui.md, Saved files). `dump_id` is the +//! key of the image caches in `~/.cache/fastvol`, so a reopened dump finds them warm. + +use super::jsonw::{self, W}; +use super::runs::{ErrInfo, Run, SavedRun, Status}; +use super::table::{K_ABSENT, K_DEC, K_HEX, K_NA, K_TEXT, Table}; +use crate::cli::json::{self, Json}; +use crate::renderers::{ColType, Column}; +use std::collections::HashSet; +use std::io::{BufRead, Write}; +use std::path::{Path, PathBuf}; + +const FORMAT: i128 = 1; +/// Largest metadata file read (runs and their plugins, not their rows). +const MAX_META: u64 = 16 << 20; + +/// The dump's identity: `(dump_id, canonical path, size, mtime in ns)`. +pub fn dump_id(image: &Path) -> Option<(String, PathBuf, u64, i128)> { + let canon = crate::util::paths::canonicalize(image).ok()?; + let (size, mtime) = crate::util::paths::file_stamp(&canon)?; + let c = canon.to_string_lossy(); + // the key material of the image caches (automagic/mod.rs `cache::key_for`) without their + // per-cache kind and format version + let mut k: Vec = Vec::with_capacity(c.len() + 32); + k.extend_from_slice(&(c.len() as u64).to_le_bytes()); + k.extend_from_slice(c.as_bytes()); + k.extend_from_slice(&size.to_le_bytes()); + k.extend_from_slice(&mtime.to_le_bytes()); + Some((format!("{:016x}", crate::layers::scancache::key_hash(&k)), canon, size, mtime)) +} + +pub fn metadata_path(id: &str) -> PathBuf { + super::presets::fvol_dir().join(format!("{id}-metadata.json")) +} + +fn results_dir(id: &str) -> PathBuf { + super::presets::fvol_dir().join(id) +} + +fn valid_id(id: &str) -> bool { + id.len() == 16 && id.bytes().all(|c| c.is_ascii_hexdigit()) +} + +/// Write `data` to `path` through a temporary file, readable by the user only. +fn write_private(path: &Path, data: &[u8]) -> std::io::Result<()> { + use std::os::unix::fs::OpenOptionsExt; + let dir = path.parent().ok_or_else(|| std::io::Error::other("no parent"))?; + super::presets::ensure_private_dir(dir)?; + let tmp = dir.join(format!(".{}.tmp-{}", path.file_name().map(|n| n.to_string_lossy().into_owned()).unwrap_or_default(), std::process::id())); + let r = std::fs::OpenOptions::new().write(true).create(true).truncate(true).mode(0o600).open(&tmp).and_then(|mut f| f.write_all(data)).and_then(|_| std::fs::rename(&tmp, path)); + if r.is_err() { + let _ = std::fs::remove_file(&tmp); + } + r +} + +// ------------------------------------------------------------------------------------------ +// result rows (sidecars) + +pub fn coltype_from(name: &str) -> ColType { + match name { + "Int" => ColType::Int, + "Bytes" => ColType::Bytes, + "Float" => ColType::Float, + "Bool" => ColType::Bool, + "DateTime" => ColType::DateTime, + "Hex" => ColType::Hex, + "Bin" => ColType::Bin, + "HexBytes" => ColType::HexBytes, + "MultiTypeData" => ColType::MultiTypeData, + "Disassembly" => ColType::Disassembly, + "LayerData" => ColType::LayerData, + _ => ColType::Str, + } +} + +/// A run's rows as JSON lines: a header, then `[depth, "kinds", cell, ...]` per row, `kinds` +/// holding each cell's kind (text, absent, N/A, decimal, hex) so the table comes back exactly. +pub fn write_rows(path: &Path, plugin: &str, columns: &[Column], t: &Table) -> std::io::Result<()> { + let mut out = Vec::with_capacity(t.text.len() + t.rows() * 16 + 256); + let mut h = W::new(); + h.obj().ks("fastvol_results", "1").ks("plugin", plugin).key("columns").arr(); + for c in columns { + h.obj().ks("name", &c.name).ks("type", super::runs::coltype_name(c.ty)).end_obj(); + } + h.end_arr().end_obj(); + out.extend_from_slice(&h.done()); + out.push(b'\n'); + for r in 0..t.rows() { + out.push(b'['); + out.extend_from_slice(t.depth[r].to_string().as_bytes()); + out.extend_from_slice(b",\""); + for c in 0..t.ncols { + out.push(b'0' + t.kind(r, c)); + } + out.push(b'"'); + for c in 0..t.ncols { + out.push(b','); + match t.kind(r, c) { + K_DEC | K_HEX => out.extend_from_slice(t.value(r, c).unwrap_or(0).to_string().as_bytes()), + K_TEXT => jsonw::bytes_str(&mut out, t.cell(r, c)), + _ => out.extend_from_slice(b"null"), + } + } + out.extend_from_slice(b"]\n"); + } + write_private(path, &out) +} + +/// Read rows written by [`write_rows`] into a table of `ncols` columns. +pub fn read_rows(path: &Path, ncols: usize) -> Result { + let f = std::fs::File::open(path).map_err(|e| format!("{}: {e}", path.display()))?; + let mut t = Table::new(ncols); + let bad = |n: usize| format!("{}: damaged saved results (line {n})", path.display()); + for (n, line) in std::io::BufReader::new(f).lines().enumerate() { + let line = line.map_err(|e| format!("{}: {e}", path.display()))?; + if n == 0 || line.is_empty() { + continue; + } + let Ok(Json::Arr(v)) = json::parse(&line) else { return Err(bad(n + 1)) }; + let (Some(Json::Int(depth)), Some(Json::Str(kinds))) = (v.first(), v.get(1)) else { return Err(bad(n + 1)) }; + if kinds.len() != ncols || v.len() != ncols + 2 { + return Err(bad(n + 1)); + } + for (c, k) in kinds.bytes().enumerate() { + match (k.wrapping_sub(b'0'), &v[c + 2]) { + (K_TEXT, Json::Str(s)) => { + t.text.extend_from_slice(s.as_bytes()); + t.push_cell(K_TEXT); + } + (K_DEC, Json::Int(i)) => t.push_num(K_DEC, *i as i64 as u64), + (K_HEX, Json::Int(i)) => t.push_num(K_HEX, *i as u64), + (K_ABSENT, _) => t.push_cell(K_ABSENT), + (K_NA, _) => t.push_cell(K_NA), + _ => return Err(bad(n + 1)), + } + } + t.depth.push((*depth).clamp(0, u16::MAX as i128) as u16); + } + Ok(t) +} + +// ------------------------------------------------------------------------------------------ +// the open analysis + +/// The analysis of the open dump. +pub struct Analysis { + pub id: String, + pub image: PathBuf, + pub size: u64, + pub mtime: i128, + pub created_ms: u64, + /// plugin executions whose rows are on disk + pub saved_rows: HashSet, + /// the metadata last written (only a change is written again) + pub last: Vec, +} + +impl Analysis { + pub fn new(image: &Path) -> Option { + let (id, canon, size, mtime) = dump_id(image)?; + Some(Analysis { id, image: canon, size, mtime, created_ms: super::runs::now_ms(), saved_rows: HashSet::new(), last: Vec::new() }) + } +} + +/// The saved metadata of a dump, if there is any. +pub fn load(id: &str) -> Option { + let p = metadata_path(id); + if std::fs::metadata(&p).ok()?.len() > MAX_META { + return None; + } + let j = json::parse(&std::fs::read_to_string(p).ok()?).ok()?; + matches!(j.get("fastvol_analysis"), Some(Json::Int(FORMAT))).then_some(j) +} + +fn sidecar_path(id: &str, batch: u64, n: usize) -> PathBuf { + results_dir(id).join(batch.to_string()).join(format!("{n}.jsonl")) +} + +fn write_error(w: &mut W, e: &Option) { + match e { + None => { + w.key("error").null(); + } + Some(e) => { + w.key("error").obj().ks("kind", e.kind).ks("title", &e.title).ks("message", &e.message).key("hints").arr(); + for h in &e.hints { + w.s(h); + } + w.end_arr().ks("detail", &e.detail).end_obj(); + } + } +} + +/// Save the open analysis: rows of newly finished plugins, then the metadata when it changed. +pub fn save(app: &super::App) { + let session = app.session(); + let mut guard = app.analysis.lock().unwrap_or_else(|e| e.into_inner()); + let Some(a) = guard.as_mut() else { return }; + let batches: Vec<_> = app.runs.batches().into_iter().filter(|b| b.session == session.id).collect(); + let mut w = W::new(); + w.obj().ki("fastvol_analysis", FORMAT).ks("dump_id", &a.id).ks("image", &a.image.to_string_lossy()); + w.ks("name", &a.image.file_name().map(|n| n.to_string_lossy().into_owned()).unwrap_or_default()); + w.ku("size", a.size).ki("mtime_ns", a.mtime).ku("created", a.created_ms); + w.key("options"); + app.options.lock().unwrap_or_else(|e| e.into_inner()).write(&mut w); + match &*app.rules.lock().unwrap_or_else(|e| e.into_inner()) { + Some((file, text)) => { + w.key("rules").obj().ks("file", file).ks("text", text).end_obj(); + } + None => { + w.key("rules").null(); + } + } + let mut keep_dirs: HashSet = HashSet::new(); + w.key("runs").arr(); + for b in &batches { + keep_dirs.insert(b.id.to_string()); + w.obj().ku("id", b.id).ks("name", &b.name.lock().unwrap_or_else(|e| e.into_inner())).ks("filter", &b.filter.lock().unwrap_or_else(|e| e.into_inner())).ku("created", b.created_ms); + w.key("entries").arr(); + for (n, rid) in b.runs.iter().enumerate() { + let Some(run) = app.runs.get(*rid) else { continue }; + let sidecar = sidecar_path(&a.id, b.id, n); + save_rows(a, &run, &sidecar); + let d = run.read(); + w.obj().ks("plugin", run.plugin.name()); + w.key("args").raw(run.req_args.lock().unwrap_or_else(|e| e.into_inner()).dump(None).as_bytes()); + w.key("argv").arr(); + for x in &run.args { + w.s(x); + } + w.end_arr(); + // a plugin still going when the server stops comes back as interrupted + w.ks("status", d.status.as_str()).ku("rows", d.produced).ku("created", run.created_ms).ku("started", d.started_ms).ku("elapsed", d.elapsed_ms); + w.key("columns").arr(); + for c in &d.columns { + w.obj().ks("name", &c.name).ks("type", super::runs::coltype_name(c.ty)).end_obj(); + } + w.end_arr(); + write_error(&mut w, &d.error); + w.ks("out_dir", &run.out_dir.to_string_lossy()); + match run.sidecar.lock().unwrap_or_else(|e| e.into_inner()).as_ref().filter(|_| a.saved_rows.contains(&run.id)) { + Some(p) => w.ks("results", &p.to_string_lossy()), + None => w.key("results").null(), + }; + w.end_obj(); + } + w.end_arr().end_obj(); + } + w.end_arr().end_obj(); + let mut data = w.done(); + data.push(b'\n'); + if data != a.last && write_private(&metadata_path(&a.id), &data).is_ok() { + a.last = data; + } + // results of runs that were removed + if let Ok(rd) = std::fs::read_dir(results_dir(&a.id)) { + for e in rd.flatten() { + let name = e.file_name().to_string_lossy().into_owned(); + if name.bytes().all(|c| c.is_ascii_digit()) && !keep_dirs.contains(&name) { + let _ = std::fs::remove_dir_all(e.path()); + } + } + } +} + +/// Write a finished plugin's rows once (only complete tables: a truncated or dropped one is not +/// saved, and the metadata says so). +fn save_rows(a: &mut Analysis, run: &Run, path: &Path) { + if a.saved_rows.contains(&run.id) { + return; + } + let d = run.read(); + if d.status != Status::Done || d.truncated || d.evicted || d.busy || (d.table.rows() as u64) < d.produced { + return; + } + if write_rows(path, run.plugin.name(), &d.columns, &d.table).is_ok() { + drop(d); + *run.sidecar.lock().unwrap_or_else(|e| e.into_inner()) = Some(path.to_path_buf()); + a.saved_rows.insert(run.id); + } +} + +/// Bring back the runs of a saved analysis into `session`. +pub fn restore(app: &super::App, session: &std::sync::Arc, meta: &Json) { + let text = |j: &Json, k: &str| j.get(k).and_then(|v| v.as_str()).unwrap_or("").to_string(); + let num = |j: &Json, k: &str| match j.get(k) { + Some(Json::Int(i)) if *i >= 0 => *i as u64, + _ => 0, + }; + let mut guard = app.analysis.lock().unwrap_or_else(|e| e.into_inner()); + let Some(a) = guard.as_mut() else { return }; + a.created_ms = num(meta, "created").max(1); + for b in meta.get("runs").map(|r| r.as_arr()).unwrap_or(&[]) { + let mut runs = Vec::new(); + for e in b.get("entries").map(|r| r.as_arr()).unwrap_or(&[]) { + let Some(plugin) = app.plugins.iter().copied().find(|p| Some(p.name()) == e.get("plugin").and_then(|x| x.as_str())) else { continue }; + let req = e.get("args").cloned().unwrap_or(Json::Null); + let Ok((cfg, argv)) = super::api::parse_config(plugin, Some(&req)) else { continue }; + let key = super::api::config_key(plugin, &cfg); + let columns: Vec = e.get("columns").map(|c| c.as_arr()).unwrap_or(&[]).iter().map(|c| Column { name: text(c, "name"), ty: coltype_from(&text(c, "type")) }).collect(); + let (status, error) = match text(e, "status").as_str() { + "done" => (Status::Done, None), + "failed" => (Status::Failed, e.get("error").map(read_error)), + "cancelled" => (Status::Cancelled, e.get("error").map(read_error)), + _ => (Status::Cancelled, Some(ErrInfo { kind: "cancelled", title: "Interrupted".into(), message: "fvol serve stopped before this plugin finished. Run it again to get its results.".into(), ..Default::default() })), + }; + let sidecar = e.get("results").and_then(|r| r.as_str()).map(PathBuf::from).filter(|p| p.is_file()); + let saved = SavedRun { + status, + rows: num(e, "rows"), + columns, + error, + created_ms: num(e, "created"), + started_ms: num(e, "started"), + elapsed_ms: num(e, "elapsed"), + out_dir: PathBuf::from(text(e, "out_dir")), + sidecar: sidecar.clone(), + }; + let run = app.runs.restore(session.clone(), plugin, cfg, argv, key, req, saved); + if sidecar.is_some() { + a.saved_rows.insert(run.id); + } + runs.push(run); + } + let id = num(b, "id"); + if id > 0 { + app.runs.restore_batch(id, session.id, text(b, "name"), text(b, "filter"), num(b, "created"), &runs); + } + } +} + +fn read_error(j: &Json) -> ErrInfo { + let s = |k: &str| j.get(k).and_then(|v| v.as_str()).unwrap_or("").to_string(); + // the kinds the server itself gives (a static set) + let kind = ["cancelled", "crash", "error", "io", "layer", "page", "requirement", "symbol", "symbols", "wrong-os"].into_iter().find(|k| *k == s("kind")).unwrap_or("error"); + ErrInfo { kind, title: s("title"), message: s("message"), hints: j.get("hints").map(|h| h.as_arr().iter().filter_map(|x| x.as_str().map(String::from)).collect()).unwrap_or_default(), detail: s("detail") } +} + +/// Delete a saved analysis from `root` (`~/.fvol`): its metadata and its result rows. The dump +/// itself is never touched. +pub fn delete_in(root: &Path, id: &str) -> Result<(), String> { + if !valid_id(id) { + return Err("no such analysis".into()); + } + std::fs::remove_file(root.join(format!("{id}-metadata.json"))).map_err(|e| if e.kind() == std::io::ErrorKind::NotFound { "no such analysis".to_string() } else { e.to_string() })?; + match std::fs::remove_dir_all(root.join(id)) { + Err(e) if e.kind() != std::io::ErrorKind::NotFound => Err(e.to_string()), + _ => Ok(()), + } +} + +/// Every saved analysis, newest first: for the Quick Start's "Previous" list. +pub fn list(w: &mut W) { + let mut items: Vec<(u64, Json)> = Vec::new(); + if let Ok(rd) = std::fs::read_dir(super::presets::fvol_dir()) { + for e in rd.flatten() { + let name = e.file_name().to_string_lossy().into_owned(); + let Some(id) = name.strip_suffix("-metadata.json").filter(|i| valid_id(i)) else { continue }; + let Some(j) = load(id) else { continue }; + let updated = e.metadata().ok().and_then(|m| m.modified().ok()).and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()).map(|d| d.as_millis() as u64).unwrap_or(0); + items.push((updated, j)); + } + } + items.sort_by(|a, b| b.0.cmp(&a.0)); + w.arr(); + for (updated, j) in &items { + let text = |k: &str| j.get(k).and_then(|v| v.as_str()).unwrap_or("").to_string(); + let image = text("image"); + let (size, mtime) = (j.get("size").cloned(), j.get("mtime_ns").cloned()); + // is the dump still there, unchanged? + let state = match crate::util::paths::file_stamp(Path::new(&image)) { + None => "missing", + Some((s, m)) if Some(Json::Int(s as i128)) == size && Some(Json::Int(m)) == mtime => "ok", + Some(_) => "changed", + }; + let runs = j.get("runs").map(|r| r.as_arr()).unwrap_or(&[]); + let plugins: usize = runs.iter().map(|b| b.get("entries").map(|e| e.as_arr().len()).unwrap_or(0)).sum(); + w.obj().ks("dump_id", &text("dump_id")).ks("image", &image).ks("name", &text("name")).ks("state", state); + w.key("size").raw(size.unwrap_or(Json::Int(0)).dump(None).as_bytes()); + w.ku("updated", *updated).ku("runs", runs.len() as u64).ku("plugins", plugins as u64).end_obj(); + } + w.end_arr(); +} + +/// Save in the background: after any change (every run, rename, filter, option), at most once +/// a second. +pub fn start_saver(app: std::sync::Arc) { + let _ = std::thread::Builder::new().name("analysis-saver".into()).spawn(move || { + let mut seen = 0u64; + loop { + let now = app.hub.wait(seen, std::time::Duration::from_secs(30)); + if now != seen { + seen = now; + save(&app); + } + std::thread::sleep(std::time::Duration::from_secs(1)); + } + }); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rows_round_trip_exactly() { + let cols = vec![Column { name: "PID".into(), ty: ColType::Int }, Column { name: "Offset".into(), ty: ColType::Hex }, Column { name: "Name".into(), ty: ColType::Str }]; + let mut t = Table::new(3); + t.push_num(K_DEC, (-5i64) as u64); + t.push_num(K_HEX, u64::MAX); + t.text.extend_from_slice("sv\"c\\host\n\u{e9}".as_bytes()); + t.push_cell(K_TEXT); + t.depth.push(0); + t.push_cell(K_ABSENT); + t.push_cell(K_NA); + t.push_cell(K_TEXT); + t.depth.push(2); + let p = std::env::temp_dir().join(format!("fastvol-rows-{}.jsonl", std::process::id())); + write_rows(&p, "windows.pslist.PsList", &cols, &t).unwrap(); + let back = read_rows(&p, 3).unwrap(); + assert_eq!((back.text, back.ends, back.kinds, back.depth), (t.text.clone(), t.ends.clone(), t.kinds.clone(), t.depth.clone())); + use std::os::unix::fs::PermissionsExt; + assert_eq!(std::fs::metadata(&p).unwrap().permissions().mode() & 0o777, 0o600); + std::fs::write(&p, "{}\n[0,\"9\",1]\n").unwrap(); + assert!(matches!(read_rows(&p, 1), Err(e) if e.contains("damaged"))); + let _ = std::fs::remove_file(&p); + } + + #[test] + fn delete_removes_metadata_and_rows_only() { + let root = std::env::temp_dir().join(format!("fastvol-analyses-{}", std::process::id())); + let id = "0123456789abcdef"; + std::fs::create_dir_all(root.join(id).join("1")).unwrap(); + std::fs::write(root.join(format!("{id}-metadata.json")), "{}").unwrap(); + std::fs::write(root.join(id).join("1").join("0.jsonl"), "{}").unwrap(); + std::fs::create_dir_all(root.join("presets")).unwrap(); + assert!(delete_in(&root, id).is_ok()); + assert!(!root.join(format!("{id}-metadata.json")).exists() && !root.join(id).exists()); + assert!(root.join("presets").is_dir()); + assert!(delete_in(&root, id).unwrap_err().contains("no such")); + assert!(delete_in(&root, "../presets").is_err()); + let _ = std::fs::remove_dir_all(&root); + } + + #[test] + fn dump_id_follows_the_cache_key_material() { + let p = std::env::temp_dir().join(format!("fastvol-dump-{}.raw", std::process::id())); + std::fs::write(&p, b"abc").unwrap(); + let (a, ..) = dump_id(&p).unwrap(); + assert!(valid_id(&a)); + assert_eq!(dump_id(&p).unwrap().0, a); + std::fs::write(&p, b"abcd").unwrap(); + assert_ne!(dump_id(&p).unwrap().0, a); + let _ = std::fs::remove_file(&p); + } +} diff --git a/src/web/api.rs b/src/web/api.rs index a4bedcf..05e7e11 100644 --- a/src/web/api.rs +++ b/src/web/api.rs @@ -10,6 +10,8 @@ use super::App; use super::assets; use super::http::{Body, Method, Request, Response}; +use super::picker; +use super::presets; use super::jsonw::W; use super::runs::{Run, Status, coltype_name, list_files}; use super::security; @@ -86,14 +88,14 @@ pub fn handle(app: &Arc, req: &Request) -> Response { // the page itself holds no secret: the token lives in the browser (URL fragment -> // localStorage of this exact origin) and goes out in a header on every API call (Method::Get | Method::Head, "/") => { - let html = assets::INDEX_HTML.replace("{{VERSION}}", crate::VERSION_BANNER); + let html = assets::index_html().replace("{{VERSION}}", crate::VERSION_BANNER); Response::new(200).header("cache-control", "no-store").bytes("text/html; charset=utf-8", html.into_bytes()) } (Method::Get | Method::Head, "/favicon.svg") | (Method::Get | Method::Head, "/favicon.ico") => { - assets::get("favicon.svg").map(|a| assets::respond(a, req)).unwrap_or_else(|| Response::text(404, "not found")) + assets::serve("favicon.svg", req) } (Method::Get | Method::Head, p) if p.starts_with("/assets/") => { - assets::get(&p["/assets/".len()..]).map(|a| assets::respond(a, req)).unwrap_or_else(|| Response::text(404, "not found")) + assets::serve(&p["/assets/".len()..], req) } (_, p) if p.starts_with("/api/") => { if security::cross_site(req, &host) { @@ -179,10 +181,75 @@ fn api(app: &Arc, req: &Request, rest: &str) -> Response { ok(w) } (["runs"], _, Method::Post) => create_run(app, req), + (["batches"], true, _) => { + let mut w = W::new(); + w.arr(); + for b in app.runs.batches() { + b.json(&mut w); + } + w.end_arr(); + ok(w) + } + (["batches"], _, Method::Post) => create_batch(app, req), + (["batches", id, tail @ ..], _, _) => { + let Some(b) = id.parse::().ok().and_then(|i| app.runs.batch(i)) else { + return err(404, "no such run"); + }; + match (tail, m) { + ([], Method::Delete) => { + app.runs.remove_batch(b.id); + err(200, "removed") + } + (["cancel"], Method::Post) => { + for id in &b.runs { + if let Some(r) = app.runs.get(*id) { + app.runs.cancel(&r); + } + } + err(200, "cancelled") + } + (["filter"], Method::Post) => { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + match j.get("q").and_then(|q| q.as_str()).filter(|q| q.chars().count() <= 1000) { + Some(q) => { + app.runs.set_batch_filter(&b, q.to_string()); + err(200, "saved") + } + None => err(422, "\"q\" is text of at most 1000 characters"), + } + } + (["name"], Method::Post) => { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + match j.get("name").and_then(|n| n.as_str()).map(str::trim).filter(|n| !n.is_empty() && n.chars().count() <= 80) { + Some(n) => { + app.runs.rename_batch(&b, n.to_string()); + let mut w = W::new(); + b.json(&mut w); + ok(w) + } + None => err(422, "a run name is 1 to 80 characters"), + } + } + _ => err(404, "unknown API endpoint"), + } + } (["runs", id, tail @ ..], _, _) => { let Some(run) = id.parse::().ok().and_then(|i| app.runs.get(i)) else { return err(404, "no such run"); }; + // a run of a reopened analysis reads its saved rows on first use + if !tail.is_empty() + && !matches!(tail, ["cancel"] | ["vol"] | ["files", ..] | ["files.zip"]) + && let Err(e) = app.runs.load_saved(&run) + { + return err(500, &e); + } match (tail, m) { ([], Method::Get | Method::Head) => { let mut w = W::new(); @@ -222,6 +289,82 @@ fn api(app: &Arc, req: &Request, rest: &str) -> Response { (["mem"], true, _) => mem(app, req), (["disasm"], true, _) => disasm(app, req), (["fs"], true, _) => fs_list(req), + (["pick-file"], true, _) => { + let mut w = W::new(); + let t = picker_tool(app); + w.obj().kb("available", t.is_some()).ks("tool", t.map_or("", |t| t.name())).end_obj(); + ok(w) + } + (["pick-file"], _, Method::Post) => pick_file(app, req), + (["options"], true, _) => { + let mut w = W::new(); + app.options.lock().unwrap_or_else(|e| e.into_inner()).write(&mut w); + ok(w) + } + (["options"], _, Method::Post) => { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + let cwd = std::env::current_dir().unwrap_or_else(|_| "/".into()); + let o = match super::options::Options::from_json(&j, &cwd) { + Ok(o) => o, + Err(e) => return err(422, &e), + }; + match app.set_options(o) { + Ok(reopened) => { + let mut w = W::new(); + w.obj().kb("reopened", reopened).key("options"); + app.options.lock().unwrap_or_else(|e| e.into_inner()).write(&mut w); + w.end_obj(); + ok(w) + } + Err(e) => err(422, &e), + } + } + (["rules"], true, _) => { + let mut w = W::new(); + match &*app.rules.lock().unwrap_or_else(|e| e.into_inner()) { + Some((file, text)) => w.obj().ks("file", file).ks("text", text).end_obj(), + None => w.null(), + }; + ok(w) + } + (["rules"], _, Method::Post) => { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + let (Some(file), Some(text)) = (j.get("file").and_then(|f| f.as_str()), j.get("text").and_then(|t| t.as_str())) else { + return err(422, "{\"file\", \"text\"} are required"); + }; + if json::parse(text).is_err() { + return err(422, "the rules file is not valid JSON"); + } + *app.rules.lock().unwrap_or_else(|e| e.into_inner()) = Some((file.chars().take(200).collect(), text.to_string())); + app.hub.bump(); + err(200, "saved") + } + (["rules"], _, Method::Delete) => { + *app.rules.lock().unwrap_or_else(|e| e.into_inner()) = None; + app.hub.bump(); + err(200, "removed") + } + (["analyses", id], _, Method::Delete) => match app.delete_analysis(id) { + Ok(()) => err(200, "removed"), + Err(e) => err(404, &e), + }, + (["analyses"], true, _) => { + let mut w = W::new(); + super::analysis::list(&mut w); + ok(w) + } + (["presets"], true, _) => list_presets(app), + (["presets"], _, Method::Post) => save_preset(app, req), + (["presets", id], _, Method::Delete) => match presets::delete_in(&presets::presets_dir(), id) { + Ok(()) => err(200, "removed"), + Err(e) => err(404, &e), + }, _ => err(404, "unknown API endpoint"), } } @@ -249,12 +392,19 @@ fn open_session(app: &Arc, req: &Request) -> Response { if let Err(e) = std::fs::File::open(&path) { return err(422, &format!("{} can't be read: {e}", path.display())); } - let mut o = app.base_opts.lock().unwrap_or_else(|e| e.into_inner()).clone(); - o.image = Some(path); - if let Some(Json::Arr(dirs)) = j.get("symbol_dirs") { - o.symbol_dirs = dirs.iter().filter_map(|d| d.as_str()).map(|d| cwd.join(d).to_string_lossy().into_owned()).collect(); - } - match app.open(o) { + let opened = app.open(path).and_then(|s| { + // `symbol_dirs` in the request (kept for scripts) is set like the Options dialog's -s + match j.get("symbol_dirs") { + Some(Json::Arr(dirs)) => { + let mut o = app.options.lock().unwrap_or_else(|e| e.into_inner()).clone(); + o.symbol_dirs = dirs.iter().filter_map(|d| d.as_str()).map(|d| cwd.join(d).to_string_lossy().into_owned()).collect(); + app.set_options(o)?; + Ok(app.session()) + } + _ => Ok(s), + } + }); + match opened { Ok(s) => { let mut w = W::new(); s.json(&mut w); @@ -480,7 +630,7 @@ pub fn parse_config(plugin: &dyn Plugin, args: Option<&Json>) -> Result<(Config, Ok((cfg, argv)) } -fn config_key(plugin: &dyn Plugin, cfg: &Config) -> String { +pub fn config_key(plugin: &dyn Plugin, cfg: &Config) -> String { let mut items: Vec<(&String, String)> = cfg.values.iter().map(|(k, v)| (k, format!("{v:?}"))).collect(); items.sort(); let mut s = plugin.name().to_string(); @@ -500,7 +650,11 @@ fn create_run(app: &Arc, req: &Request) -> Response { }; let Some(name) = j.get("plugin").and_then(|p| p.as_str()) else { return err(422, "\"plugin\" is required") }; let Some(plugin) = app.plugins.iter().copied().find(|p| p.name() == name) else { return err(404, &format!("unknown plugin {name}")) }; - let (cfg, argv) = match parse_config(plugin, j.get("args")) { + let args = match app.options.lock().unwrap_or_else(|e| e.into_inner()).run_args(plugin, j.get("args")) { + Ok(a) => a, + Err(e) => return err(422, &e), + }; + let (cfg, argv) = match parse_config(plugin, Some(&args)) { Ok(x) => x, Err(e) => return err(422, &e), }; @@ -515,6 +669,7 @@ fn create_run(app: &Arc, req: &Request) -> Response { Some(r) => (r, true), None => { let r = app.runs.create(session, plugin, cfg, argv, key, origin); + *r.req_args.lock().unwrap_or_else(|e| e.into_inner()) = args; app.runs.submit(r.clone()); (r, false) } @@ -526,6 +681,48 @@ fn create_run(app: &Arc, req: &Request) -> Response { ok(w) } +/// Start a run of several plugins: `{"name": "...", "entries": [{"plugin", "args"}]}`. Every +/// entry's options are checked first, so a mistake starts nothing. +fn create_batch(app: &Arc, req: &Request) -> Response { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + let session = app.session(); + if session.image.is_none() { + return err(409, "open a memory image first"); + } + let entries = match j.get("entries") { + Some(Json::Arr(a)) if !a.is_empty() && a.len() <= 200 => a, + _ => return err(422, "\"entries\" must list 1 to 200 plugins"), + }; + let mut parsed = Vec::with_capacity(entries.len()); + for e in entries { + let Some(name) = e.get("plugin").and_then(|p| p.as_str()) else { return err(422, "every entry needs a \"plugin\"") }; + let Some(plugin) = app.plugins.iter().copied().find(|p| p.name() == name) else { return err(404, &format!("unknown plugin {name}")) }; + let args = match app.options.lock().unwrap_or_else(|e| e.into_inner()).run_args(plugin, e.get("args")) { + Ok(a) => a, + Err(x) => return err(422, &format!("{name}: {x}")), + }; + match parse_config(plugin, Some(&args)) { + Ok((cfg, argv)) => parsed.push((plugin, cfg, argv, args)), + Err(x) => return err(422, &format!("{name}: {x}")), + } + } + let n = app.runs.batches().iter().filter(|b| b.session == session.id).count() + 1; + let name = j.get("name").and_then(|n| n.as_str()).map(str::trim).filter(|s| !s.is_empty()).map(|s| s.chars().take(80).collect()).unwrap_or_else(|| format!("Run {n}")); + let runs = parsed.into_iter().map(|(plugin, cfg, argv, args)| { + let key = config_key(plugin, &cfg); + let r = app.runs.create(session.clone(), plugin, cfg, argv, key, "user"); + *r.req_args.lock().unwrap_or_else(|e| e.into_inner()) = args; + r + }).collect(); + let b = app.runs.submit_batch(session.id, name, runs); + let mut w = W::new(); + b.json(&mut w); + ok(w) +} + // ------------------------------------------------------------------------------------------ // views and rows @@ -997,7 +1194,9 @@ fn md_cell(out: &mut Vec, s: &[u8]) { /// Re-run the plugin with a CLI renderer: byte-identical to `fvol -r ...`. fn vol_export(app: &Arc, run: Arc, req: &Request) -> Response { - let renderer = req.param("renderer").unwrap_or("jsonl").to_string(); + let opts = app.options.lock().unwrap_or_else(|e| e.into_inner()).clone(); + let renderer = req.param("renderer").map(str::to_string).or_else(|| opts.renderer.clone()).unwrap_or_else(|| "quick".into()); + let ropts = opts.render_options(); if !crate::renderers::text::RENDERER_NAMES.contains(&renderer.as_str()) { return err(422, "unknown renderer"); } @@ -1027,7 +1226,7 @@ fn vol_export(app: &Arc, run: Arc, req: &Request) -> Response { } else { run.session.ctx.clone() }; - let mut r = crate::renderers::text::create(&renderer, w, Default::default()).ok_or_else(|| std::io::Error::other("renderer"))?; + let mut r = crate::renderers::text::create(&renderer, w, ropts).ok_or_else(|| std::io::Error::other("renderer"))?; let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| crate::context::with_output_dir(&dir, || run.plugin.run(&ctx, &run.cfg, &mut *r)))); match res { Ok(Ok(())) => r.finish().map_err(|e| std::io::Error::other(e.to_string())), @@ -1118,6 +1317,77 @@ fn disasm(app: &Arc, req: &Request) -> Response { ok(w) } +/// The desktop file dialog, when the page's user sits at this machine (loopback only). +fn picker_tool(app: &App) -> Option { + if app.hosts.wildcard || !app.hosts.bind.is_some_and(|ip| ip.is_loopback()) { + return None; + } + picker::tool() +} + +/// Show the desktop's "open file" dialog and return the chosen path: `{"dir": ""}`. +fn pick_file(app: &App, req: &Request) -> Response { + let Some(tool) = picker_tool(app) else { return err(501, "no desktop file dialog here (the server needs a display and a loopback address)") }; + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + let cwd = std::env::current_dir().unwrap_or_else(|_| "/".into()); + let dir = j.get("dir").and_then(|d| d.as_str()).map(|d| cwd.join(d)).filter(|d| d.is_dir()).unwrap_or(cwd); + let mut w = W::new(); + match picker::pick(tool, &dir) { + Ok(picker::Picked::Path(p)) => w.obj().ks("path", &p.to_string_lossy()).end_obj(), + Ok(picker::Picked::Cancelled) => w.obj().kb("cancelled", true).end_obj(), + Err(e) => return err(409, &e), + }; + ok(w) +} + +/// The user's presets in `~/.fvol/presets` (plus files that could not be read, with the reason). +fn list_presets(app: &App) -> Response { + let known = |n: &str| app.plugins.iter().any(|p| p.name() == n); + let dir = presets::presets_dir(); + let (ok_list, bad) = presets::list_in(&dir, &known); + let mut w = W::new(); + w.obj().ks("dir", &dir.to_string_lossy()).key("presets").arr(); + for p in &ok_list { + presets::write(&mut w, p, true); + } + w.end_arr().key("errors").arr(); + for (file, e) in &bad { + w.obj().ks("file", file).ks("error", e).end_obj(); + } + w.end_arr().end_obj(); + ok(w) +} + +/// Save a preset: `{"name", "os", "plugins": [{"plugin", "args"}], "overwrite"}`. +fn save_preset(app: &App, req: &Request) -> Response { + let j = match body_json(req) { + Ok(j) => j, + Err(r) => return r, + }; + let Some(id) = j.get("name").and_then(|n| n.as_str()).and_then(presets::slug) else { + return err(422, "the name needs at least one letter or digit"); + }; + let known = |n: &str| app.plugins.iter().any(|p| p.name() == n); + let mut p = match presets::from_json(&id, &j, &known) { + Ok(p) => p, + Err(e) => return err(422, &e), + }; + p.created = presets::now(); + let overwrite = matches!(j.get("overwrite"), Some(Json::Bool(true))); + match presets::save_in(&presets::presets_dir(), &p, overwrite) { + Ok(_) => { + let mut w = W::new(); + presets::write(&mut w, &p, true); + ok(w) + } + Err(presets::SaveError::Exists) => err(409, &format!("a preset named \"{}\" already exists", p.name)), + Err(presets::SaveError::Io(e)) => err(500, &e), + } +} + /// Directory listing for the "open image" dialog (names, sizes; no contents). fn fs_list(req: &Request) -> Response { let cwd = std::env::current_dir().unwrap_or_else(|_| "/".into()); @@ -1159,6 +1429,7 @@ fn events(app: &Arc) -> Response { Box::new(move |w: &mut dyn Write| { let _slot = slot; let mut last_session: Vec = Vec::new(); + let mut last_batches: Vec = Vec::new(); let mut sent_seq: std::collections::HashMap = std::collections::HashMap::new(); let mut seen = 0u64; let mut first = true; @@ -1174,6 +1445,19 @@ fn events(app: &Arc) -> Response { out.extend_from_slice(b"}\n"); last_session = sj; } + let mut bj = W::new(); + bj.arr(); + for b in app.runs.batches() { + b.json(&mut bj); + } + bj.end_arr(); + let bj = bj.done(); + if bj != last_batches { + out.extend_from_slice(b"{\"t\":\"batches\",\"batches\":"); + out.extend_from_slice(&bj); + out.extend_from_slice(b"}\n"); + last_batches = bj; + } let runs = app.runs.all(); let mut changed = W::new(); changed.obj().ks("t", "runs").kb("full", first).key("runs").arr(); diff --git a/src/web/assets.rs b/src/web/assets.rs index 5183c35..8c8de9e 100644 --- a/src/web/assets.rs +++ b/src/web/assets.rs @@ -1,5 +1,5 @@ -//! The UI: hand-written HTML/CSS/vanilla JS (ES modules) and a subset of JetBrains Mono, -//! embedded in the binary. No build step, no external requests. +//! The UI: hand-written HTML/CSS/vanilla JS (ES modules), embedded in the binary. No build step, +//! no external requests. use super::http::{Body, Request, Response}; @@ -18,28 +18,68 @@ macro_rules! asset { } pub static ASSETS: &[Asset] = &[ - asset!("app.css", "text/css; charset=utf-8"), asset!("app.js", "text/javascript; charset=utf-8"), asset!("theme.js", "text/javascript; charset=utf-8"), asset!("core.js", "text/javascript; charset=utf-8"), asset!("table.js", "text/javascript; charset=utf-8"), - asset!("palette.js", "text/javascript; charset=utf-8"), - asset!("views.js", "text/javascript; charset=utf-8"), - asset!("procs.js", "text/javascript; charset=utf-8"), - asset!("hex.js", "text/javascript; charset=utf-8"), asset!("catalog.js", "text/javascript; charset=utf-8"), - asset!("result.js", "text/javascript; charset=utf-8"), + asset!("ui.css", "text/css; charset=utf-8"), + asset!("quickstart.js", "text/javascript; charset=utf-8"), + asset!("workspace.js", "text/javascript; charset=utf-8"), + asset!("procdata.js", "text/javascript; charset=utf-8"), + asset!("rules.js", "text/javascript; charset=utf-8"), + asset!("presets.js", "text/javascript; charset=utf-8"), + asset!("results.js", "text/javascript; charset=utf-8"), + asset!("layout.js", "text/javascript; charset=utf-8"), + asset!("options.js", "text/javascript; charset=utf-8"), asset!("favicon.svg", "image/svg+xml"), - asset!("mark.svg", "image/svg+xml"), - asset!("mono-400.woff2", "font/woff2"), - asset!("mono-700.woff2", "font/woff2"), - asset!("OFL.txt", "text/plain; charset=utf-8"), ]; pub fn get(name: &str) -> Option<&'static Asset> { ASSETS.iter().find(|a| a.name == name) } +/// `FASTVOL_WEB_DEV=`: serve the page and its assets from `` (read on every request) +/// instead of the copies compiled in, so UI work shows up on a browser refresh. Development only. +pub fn dev_dir() -> Option<&'static std::path::Path> { + static DIR: std::sync::OnceLock> = std::sync::OnceLock::new(); + DIR.get_or_init(|| std::env::var_os("FASTVOL_WEB_DEV").filter(|d| !d.is_empty()).map(Into::into)).as_deref() +} + +/// The page, from the dev directory when there is one. +pub fn index_html() -> String { + match dev_dir().and_then(|d| std::fs::read_to_string(d.join("index.html")).ok()) { + Some(s) => s, + None => INDEX_HTML.to_string(), + } +} + +/// An asset read from the dev directory: plain file names only (no paths, no dot files). +fn dev_asset(dir: &std::path::Path, name: &str) -> Option { + if name.is_empty() || name.starts_with('.') || !name.bytes().all(|c| c.is_ascii_alphanumeric() || matches!(c, b'.' | b'-' | b'_')) { + return None; + } + let data = std::fs::read(dir.join(name)).ok()?; + let ctype = match name.rsplit('.').next().unwrap_or("") { + "html" => "text/html; charset=utf-8", + "css" => "text/css; charset=utf-8", + "js" => "text/javascript; charset=utf-8", + "svg" => "image/svg+xml", + "woff2" => "font/woff2", + "png" => "image/png", + _ => "text/plain; charset=utf-8", + }; + Some(Response::new(200).header("cache-control", "no-store").bytes(ctype, data)) +} + +/// Serve an asset by name: from the dev directory when set, else the compiled-in copy. +pub fn serve(name: &str, req: &Request) -> Response { + if let Some(dir) = dev_dir() { + return dev_asset(dir, name).unwrap_or_else(|| Response::text(404, "not found")); + } + get(name).map(|a| respond(a, req)).unwrap_or_else(|| Response::text(404, "not found")) +} + /// FNV-1a of the content: a strong-enough ETag for embedded, immutable-per-binary files. fn etag(a: &Asset) -> String { let mut h: u64 = 0xcbf29ce484222325; diff --git a/src/web/assets/OFL.txt b/src/web/assets/OFL.txt deleted file mode 100644 index 8bee414..0000000 --- a/src/web/assets/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -https://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/web/assets/app.css b/src/web/assets/app.css deleted file mode 100644 index 802916a..0000000 --- a/src/web/assets/app.css +++ /dev/null @@ -1,729 +0,0 @@ -/* fastvol web UI — "evidence bench": an instrument for reading memory. - Mono-first (embedded JetBrains Mono subset, OFL), graphite + signal amber in the dark, - manila case-file + stamp red in the light. No external resources. */ - -@font-face { font-family: "RsMono"; src: url("/assets/mono-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; } -@font-face { font-family: "RsMono"; src: url("/assets/mono-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; } - -:root { - --mono: "RsMono", ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; - --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", "Noto Sans", "Helvetica Neue", Arial, sans-serif; - --fs: 12.5px; - --fs-s: 11px; - --fs-xs: 10px; - --row: 24px; - --r: 3px; - --rail: 300px; - --ease: cubic-bezier(.2, .7, .2, 1); - - /* graphite (dark) */ - --bg: #0c0e10; - --bg-grid: rgba(255, 255, 255, .022); - --panel: #111417; - --panel2: #15191d; - --raise: #1a1f24; - --raise2: #20262c; - --line: #22282e; - --line2: #2e363e; - --text: #d7dde3; - --text2: #a4aeb8; - --muted: #76818c; - --faint: #4b545d; - --accent: #f3a83b; - --accent-2: #ffc46b; - --accent-ink: #1b1204; - --accent-soft: rgba(243, 168, 59, .13); - --addr: #5cc5d1; - --addr-soft: rgba(92, 197, 209, .12); - --ok: #7dd08a; - --bad: #ff6a5c; - --bad-soft: rgba(255, 106, 92, .12); - --warn: #f3a83b; - --sel: rgba(92, 197, 209, .10); - --sel-strong: rgba(92, 197, 209, .20); - --focus: #5cc5d1; - --stripe: rgba(255, 255, 255, .016); - --uniq: rgba(243, 168, 59, .10); - --shadow: 0 18px 60px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .4); - --scrim: rgba(4, 6, 8, .62); - color-scheme: dark; -} - -:root[data-theme="light"] { - /* manila case file */ - --bg: #ebe5d8; - --bg-grid: rgba(80, 60, 20, .045); - --panel: #f4efe4; - --panel2: #f8f4eb; - --raise: #fffcf5; - --raise2: #fffefa; - --line: #d9d0bd; - --line2: #c8bda6; - --text: #1e1a13; - --text2: #4b4436; - --muted: #6f6656; - --faint: #a2977f; - --accent: #c2410c; - --accent-2: #9a3412; - --accent-ink: #fff7ed; - --accent-soft: rgba(194, 65, 12, .10); - --addr: #0b6a77; - --addr-soft: rgba(11, 106, 119, .10); - --ok: #2f7d3b; - --bad: #b42318; - --bad-soft: rgba(180, 35, 24, .08); - --warn: #b45309; - --sel: rgba(11, 106, 119, .09); - --sel-strong: rgba(11, 106, 119, .17); - --focus: #0b6a77; - --stripe: rgba(90, 70, 30, .028); - --uniq: rgba(194, 65, 12, .09); - --shadow: 0 18px 50px rgba(60, 40, 10, .22), 0 2px 8px rgba(60, 40, 10, .12); - --scrim: rgba(40, 30, 10, .32); - color-scheme: light; -} - -* { box-sizing: border-box; } -html, body { height: 100%; } -body { - margin: 0; - background-color: var(--bg); - background-image: - linear-gradient(var(--bg-grid) 1px, transparent 1px), - linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px); - background-size: 24px 24px; - color: var(--text); - font: 400 var(--fs)/1.45 var(--mono); - font-variant-ligatures: none; - font-feature-settings: "zero" 1; - -webkit-font-smoothing: antialiased; - overflow: hidden; -} -::selection { background: var(--accent); color: var(--accent-ink); } -button, input, select, textarea { font: inherit; color: inherit; } -button { cursor: pointer; } -:focus { outline: none; } -:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; } -kbd { - font: 400 var(--fs-xs)/1 var(--mono); - padding: 2px 5px 3px; - border: 1px solid var(--line2); - border-bottom-width: 2px; - border-radius: 3px; - color: var(--text2); - background: var(--panel2); - white-space: nowrap; -} -.skip { position: absolute; left: -999px; top: 4px; z-index: 100; background: var(--accent); color: var(--accent-ink); padding: 4px 8px; } -.skip:focus { left: 4px; } -[hidden] { display: none !important; } -.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } -.muted { color: var(--muted); } -.faint { color: var(--faint); } -.addr { color: var(--addr); } -.prose { font-family: var(--sans); font-size: 13px; line-height: 1.5; } - -/* scrollbars */ -* { scrollbar-width: thin; scrollbar-color: var(--line2) transparent; } -::-webkit-scrollbar { width: 10px; height: 10px; } -::-webkit-scrollbar-thumb { background: var(--line2); border: 3px solid transparent; background-clip: padding-box; border-radius: 6px; } -::-webkit-scrollbar-corner { background: transparent; } - -/* ---------------------------------------------------------------- buttons & inputs */ -.btn { - display: inline-flex; align-items: center; gap: 6px; - height: 26px; padding: 0 10px; - border: 1px solid var(--line2); border-radius: var(--r); - background: var(--raise); color: var(--text); - font-size: var(--fs-s); letter-spacing: .02em; white-space: nowrap; - transition: background .12s, border-color .12s, color .12s; -} -.btn:hover { border-color: var(--muted); background: var(--raise2); } -.btn:disabled { opacity: .45; cursor: default; } -.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 700; } -.btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); } -.btn.danger { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 45%, var(--line2)); } -.btn.danger:hover { background: var(--bad-soft); } -.btn.ghost { background: transparent; border-color: transparent; color: var(--text2); } -.btn.ghost:hover { background: var(--raise); border-color: var(--line2); color: var(--text); } -.btn kbd { margin-left: 2px; } -.btn svg { flex: none; } -.iconbtn { - width: 28px; height: 28px; display: grid; place-items: center; - border: 1px solid transparent; border-radius: var(--r); background: transparent; color: var(--text2); -} -.iconbtn:hover { background: var(--raise); border-color: var(--line2); color: var(--text); } -.mini { - width: 20px; height: 20px; padding: 0; display: grid; place-items: center; - border: 1px solid transparent; border-radius: 3px; background: transparent; color: var(--muted); font-size: 13px; line-height: 1; -} -.mini:hover { color: var(--text); border-color: var(--line2); background: var(--raise); } -.input, input[type="search"], input[type="text"] { - height: 26px; padding: 0 8px; - border: 1px solid var(--line2); border-radius: var(--r); - background: var(--bg); color: var(--text); - font-size: var(--fs); -} -.input:focus, input[type="search"]:focus, input[type="text"]:focus { border-color: var(--focus); box-shadow: 0 0 0 3px var(--sel); } -input::placeholder { color: var(--faint); } -input.invalid { border-color: var(--bad) !important; box-shadow: 0 0 0 3px var(--bad-soft) !important; } -select.input { padding-right: 20px; } -.label { - font-size: var(--fs-xs); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); -} - -/* ---------------------------------------------------------------- top bar */ -.topbar { - height: 40px; display: flex; align-items: center; gap: 10px; padding: 0 10px 0 12px; - background: var(--panel); border-bottom: 1px solid var(--line); - position: relative; z-index: 5; -} -.topbar::after { /* a hairline of signal colour */ - content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; - background: linear-gradient(90deg, var(--accent) 0, var(--accent) 64px, transparent 64px); -} -.brand { display: flex; align-items: center; gap: 6px; color: var(--text); padding-right: 4px; } -.brand .brand-logo { display: block; } -.mascot { display: block; width: 96px; height: 64px; margin: 0 auto; image-rendering: pixelated; } -.login-box .mascot { margin: 4px auto 0; } -.evidence { - display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 auto; - height: 28px; padding: 0 10px 0 0; border: 1px solid transparent; border-radius: var(--r); - background: transparent; text-align: left; overflow: hidden; -} -.evidence:hover { border-color: var(--line2); background: var(--panel2); } -.ev-tag { - flex: none; font-size: 9px; font-weight: 700; letter-spacing: .16em; padding: 3px 6px 3px 8px; - color: var(--accent-ink); background: var(--accent); - clip-path: polygon(0 0, 100% 0, calc(100% - 5px) 50%, 100% 100%, 0 100%); - padding-right: 10px; -} -.ev-name { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; } -.ev-meta { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-s); flex: 1 1 auto; } -.ev-meta b { color: var(--text2); font-weight: 400; } -.cmdk { - flex: 0 0 auto; display: flex; align-items: center; gap: 8px; height: 28px; padding: 0 6px 0 10px; min-width: 250px; - border: 1px solid var(--line2); border-radius: var(--r); background: var(--bg); color: var(--muted); -} -.cmdk span { flex: 1; text-align: left; } -.cmdk:hover { border-color: var(--accent); color: var(--text2); } -.activity { display: flex; align-items: center; gap: 6px; font-size: var(--fs-s); color: var(--muted); min-width: 0; white-space: nowrap; } -.activity .pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 0 var(--accent); animation: pulse 1.4s infinite; } -@keyframes pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); } 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } - -/* ---------------------------------------------------------------- shell */ -.shell { display: flex; height: calc(100% - 40px); } -.rail { - width: var(--rail); min-width: 200px; max-width: 60vw; flex: none; - display: flex; flex-direction: column; background: var(--panel); border-right: 1px solid var(--line); -} -.rail-resize { width: 5px; margin-left: -3px; margin-right: -2px; cursor: col-resize; z-index: 3; flex: none; } -.rail-resize:hover, .rail-resize.drag, .rail-resize:focus-visible { background: var(--accent); outline: none; } -.rail-sec { display: flex; flex-direction: column; min-height: 0; } -.rail-sec.procs { flex: 1 1 62%; } -.rail-sec.history { flex: 1 1 38%; } -.rail-split { height: 5px; margin: -2px 0; cursor: row-resize; z-index: 2; flex: none; } -.rail-split:hover, .rail-split.drag { background: var(--accent); } -.rail-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 10px 6px 12px; } -.rail-head h2 { margin: 0; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); } -.rail-head .count { color: var(--faint); letter-spacing: 0; margin-left: 4px; font-weight: 400; } -.rail-tools { display: flex; gap: 2px; } -.rail-filter { padding: 0 10px 6px 10px; } -.rail-filter input { width: 100%; } -.history { border-top: 1px solid var(--line); } -.work { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; } - -/* ---------------------------------------------------------------- process tree */ -.lifeaxis { position: relative; height: 14px; margin: 0 10px 2px 12px; font-size: 9px; color: var(--faint); } -.lifeaxis .ticks { position: absolute; right: 10px; width: 58px; top: 0; height: 14px; } -.lifeaxis .ticks span { position: absolute; top: 0; font-size: 8.5px; color: var(--faint); white-space: nowrap; } -.tree { flex: 1 1 auto; overflow: auto; padding: 0 0 12px; outline-offset: -2px; } -.tree:focus-visible { outline: 1px solid var(--line2); } -.tnode { - display: grid; grid-template-columns: 1fr 58px; align-items: center; gap: 6px; - height: 22px; padding: 0 10px 0 calc(6px + var(--lvl, 0) * 13px); cursor: pointer; position: relative; - white-space: nowrap; -} -.tnode::before { /* indent guides */ - content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: calc(6px + var(--lvl, 0) * 13px); - background-image: repeating-linear-gradient(90deg, transparent 0 12px, var(--line) 12px 13px); - background-position: 6px 0; background-repeat: no-repeat; - background-size: calc(var(--lvl, 0) * 13px) 100%; -} -.tnode:hover { background: var(--raise); } -.tnode[aria-selected="true"] { background: var(--sel-strong); } -.tnode[aria-selected="true"]::after { content: ""; position: absolute; left: 0; top: 2px; bottom: 2px; width: 2px; background: var(--accent); } -.tree:focus .tnode.cursor { box-shadow: inset 0 0 0 1px var(--focus); } -.tnode .tl { display: flex; align-items: center; gap: 4px; min-width: 0; } -.tnode .tw { width: 12px; flex: none; color: var(--muted); font-size: 9px; text-align: center; } -.tnode .nm { overflow: hidden; text-overflow: ellipsis; } -.tnode .pid { color: var(--muted); font-size: var(--fs-s); flex: none; } -.tnode.exited .nm { color: var(--muted); text-decoration: line-through; text-decoration-color: var(--faint); } -.tnode.flag .nm { color: var(--accent); } -.tnode.ctx .nm, .tnode.ctx .pid { opacity: .5; } -.tnode mark { background: var(--accent-soft); color: inherit; border-radius: 2px; } -.life { position: relative; height: 8px; border-radius: 1px; background: var(--line); overflow: hidden; } -.life i { position: absolute; top: 0; bottom: 0; background: color-mix(in srgb, var(--muted) 60%, transparent); border-radius: 1px; min-width: 2px; } -.life i.recent { background: var(--accent); } -.life i.dead { background: color-mix(in srgb, var(--faint) 60%, transparent); } -.tree-empty { padding: 16px 14px; color: var(--muted); font-size: var(--fs-s); line-height: 1.6; } - -/* run list */ -.runlist { list-style: none; margin: 0; padding: 0 0 10px; overflow: auto; flex: 1 1 auto; } -.runlist li { - display: grid; grid-template-columns: 14px 1fr auto; gap: 6px; align-items: center; - padding: 3px 10px 3px 12px; cursor: pointer; font-size: var(--fs-s); min-height: 22px; -} -.runlist li:hover { background: var(--raise); } -.runlist li.active { background: var(--sel); } -.runlist .rn { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.runlist .ra { color: var(--muted); } -.runlist .rm { color: var(--faint); white-space: nowrap; } -.runlist .rs { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); justify-self: center; } -.rs.done { background: var(--ok); } -.rs.failed { background: var(--bad); } -.rs.cancelled { background: var(--faint); border: 1px solid var(--muted); } -.rs.running { background: var(--accent); animation: blink 1s steps(2) infinite; } -.rs.queued { background: transparent; border: 1px solid var(--accent); } -@keyframes blink { 50% { opacity: .35; } } -.runlist .origin { color: var(--faint); font-size: var(--fs-xs); } - -/* ---------------------------------------------------------------- tabs */ -.tabs { - display: flex; align-items: flex-end; gap: 1px; height: 34px; padding: 0 8px; flex: none; - background: var(--panel); border-bottom: 1px solid var(--line); overflow-x: auto; overflow-y: hidden; - scrollbar-width: none; -} -.tabs::-webkit-scrollbar { display: none; } -.tab { - display: flex; align-items: center; gap: 7px; height: 28px; max-width: 260px; padding: 0 6px 0 11px; - border: 1px solid transparent; border-bottom: none; border-radius: 4px 4px 0 0; - background: transparent; color: var(--muted); font-size: var(--fs-s); white-space: nowrap; flex: none; - position: relative; top: 1px; -} -.tab:hover { color: var(--text); background: var(--panel2); } -.tab[aria-selected="true"] { color: var(--text); background: var(--bg); border-color: var(--line); } -.tab[aria-selected="true"]::before { content: ""; position: absolute; left: -1px; right: -1px; top: -1px; height: 2px; background: var(--accent); border-radius: 3px 3px 0 0; } -.tab .tt { overflow: hidden; text-overflow: ellipsis; } -.tab .tk { color: var(--faint); font-size: var(--fs-xs); } -.tab .x { width: 16px; height: 16px; display: grid; place-items: center; border-radius: 3px; color: var(--faint); font-size: 12px; } -.tab .x:hover { background: var(--raise2); color: var(--text); } -.tab .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; } -.tab .dot.running { background: var(--accent); animation: blink 1s steps(2) infinite; } -.tab .dot.failed { background: var(--bad); } -.panes { flex: 1 1 auto; min-height: 0; position: relative; } -.pane { position: absolute; inset: 0; display: flex; flex-direction: column; min-height: 0; } -.pane[hidden] { display: none; } -.scrollpane { overflow: auto; } - -/* ---------------------------------------------------------------- overview */ -.ov { padding: 22px 26px 40px; max-width: 1400px; display: grid; gap: 18px; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); align-content: start; } -.ov > .full { grid-column: 1 / -1; } -.card { background: var(--panel); border: 1px solid var(--line); border-radius: 5px; position: relative; } -.card-h { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--line); } -.card-h h3 { margin: 0; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); } -.card-b { padding: 12px 14px; } -.evcard { overflow: hidden; } -.evcard .card-b { padding: 18px 18px 16px; } -.evcard::before { /* perforated evidence-tag edge */ - content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px; - background: repeating-linear-gradient(180deg, var(--accent) 0 9px, transparent 9px 14px); - opacity: .85; -} -.ev-title { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; } -.ev-title h1 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.01em; overflow-wrap: anywhere; } -.ev-path { color: var(--muted); font-size: var(--fs-s); overflow-wrap: anywhere; margin-bottom: 16px; } -.facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px 22px; } -.fact .k { font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 2px; } -.fact .v { font-size: 14px; overflow-wrap: anywhere; } -.fact .v.big { font-size: 26px; font-weight: 700; line-height: 1.1; } -.fact.banner { margin-top: 14px; } -.fact.banner .v { font-size: var(--fs-s); color: var(--text2); } -.fact .v small { color: var(--muted); font-size: var(--fs-s); } -.oslogo { display: inline-block; padding: 1px 7px; border: 1px solid var(--line2); border-radius: 3px; font-size: var(--fs-s); color: var(--text2); } -.warming { display: flex; align-items: center; gap: 10px; color: var(--text2); } -.spinner { width: 14px; height: 14px; border: 2px solid var(--line2); border-top-color: var(--accent); border-radius: 50%; animation: spin .8s linear infinite; flex: none; } -@keyframes spin { to { transform: rotate(360deg); } } -.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; } -.tile { - display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; align-content: start; text-align: left; - padding: 10px 11px 11px; border: 1px solid var(--line); border-radius: 4px; background: var(--panel2); - transition: border-color .12s, transform .12s var(--ease), background .12s; -} -.tile:hover { border-color: var(--accent); background: var(--raise); transform: translateY(-1px); } -.tile .tn { font-weight: 700; } -.tile .tp { grid-column: 1 / -1; color: var(--faint); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.tile .td { grid-column: 1 / -1; color: var(--text2); font: 12px/1.4 var(--sans); margin-top: 3px; } -.tile .ts { font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; } -.tile .ts.done { color: var(--ok); } -.tile .ts.running { color: var(--accent); } -.tile .ts.failed { color: var(--bad); } -.tile kbd { justify-self: end; } -.triage { display: flex; flex-direction: column; } -.tri { display: grid; grid-template-columns: 34px 1fr; gap: 10px; align-items: start; padding: 9px 14px; border-top: 1px solid var(--line); } -.tri:first-child { border-top: none; } -.tri .n { font-size: 20px; font-weight: 700; line-height: 1; text-align: right; color: var(--text2); } -.tri.hot .n { color: var(--accent); } -.tri .t { font: 13px/1.45 var(--sans); } -.tri .t small { display: block; color: var(--muted); font-size: 12px; } -.chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; } -.chip { - display: inline-flex; align-items: center; gap: 5px; height: 21px; padding: 0 7px; - border: 1px solid var(--line2); border-radius: 11px; background: var(--panel2); font-size: var(--fs-s); color: var(--text2); - white-space: nowrap; -} -button.chip:hover { border-color: var(--accent); color: var(--text); } -.chip .x { color: var(--faint); } -.recent li { cursor: pointer; } -.openbox { display: grid; gap: 10px; } -.openbox .row { display: flex; gap: 8px; } -.openbox .row .input { flex: 1; } -.fslist { max-height: 260px; overflow: auto; border: 1px solid var(--line); border-radius: 4px; background: var(--bg); } -.fslist button { display: grid; grid-template-columns: 18px 1fr auto; gap: 6px; width: 100%; padding: 3px 8px; border: 0; background: transparent; text-align: left; font-size: var(--fs-s); } -.fslist button:hover, .fslist button:focus-visible { background: var(--raise); } -.fslist .sz { color: var(--muted); } - -/* ---------------------------------------------------------------- result view */ -.rv-head { display: flex; align-items: center; gap: 12px; padding: 10px 14px 8px; flex-wrap: wrap; flex: none; } -.rv-title { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex: 1 1 auto; flex-wrap: wrap; } -.rv-title h2 { margin: 0; font-size: 15px; font-weight: 700; white-space: nowrap; } -.rv-title .ns { color: var(--muted); font-weight: 400; } -.rv-title .args { color: var(--addr); font-size: var(--fs-s); } -.rv-meta { color: var(--muted); font-size: var(--fs-s); white-space: nowrap; } -.rv-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; } -.stamp { - display: inline-block; padding: 2px 7px 1px; border: 1.5px solid currentColor; border-radius: 3px; - font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; line-height: 1.4; - transform: rotate(-2deg); opacity: .92; white-space: nowrap; -} -.stamp.done { color: var(--ok); } -.stamp.failed { color: var(--bad); } -.stamp.cancelled { color: var(--muted); } -.stamp.running, .stamp.queued { color: var(--accent); transform: none; } -.rv-bar { display: flex; align-items: center; gap: 8px; padding: 0 14px 8px; flex: none; flex-wrap: wrap; } -.rv-bar .q { width: 320px; max-width: 45vw; } -.rv-bar .spacer { flex: 1; } -.rv-bar .count { color: var(--muted); font-size: var(--fs-s); white-space: nowrap; } -.rv-bar .count b { color: var(--text); font-weight: 400; } -.progress { height: 2px; margin: 0 14px; background: var(--line); overflow: hidden; flex: none; position: relative; } -.progress i { position: absolute; top: 0; bottom: 0; width: 30%; background: var(--accent); animation: slide 1.2s var(--ease) infinite; } -.progress.eta i { animation: none; width: auto; left: 0; transition: right .5s linear; } -@keyframes slide { from { left: -30%; } to { left: 100%; } } -.errcard { margin: 6px 14px 10px; border: 1px solid color-mix(in srgb, var(--bad) 40%, var(--line)); background: var(--bad-soft); border-radius: 5px; padding: 12px 14px; flex: none; } -.errcard.soft { border-color: var(--line2); background: var(--panel2); } -.errcard h4 { margin: 0 0 4px; font-size: 13px; color: var(--bad); } -.errcard.soft h4 { color: var(--text2); } -.errcard p { margin: 0 0 6px; font: 13px/1.5 var(--sans); } -.errcard ul { margin: 4px 0 6px 18px; padding: 0; font: 12.5px/1.5 var(--sans); color: var(--text2); } -.errcard details summary { cursor: pointer; color: var(--muted); font-size: var(--fs-s); } -.errcard pre { margin: 6px 0 0; white-space: pre-wrap; font-size: var(--fs-s); color: var(--text2); max-height: 200px; overflow: auto; } -.files { margin: 0 14px 8px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; flex: none; font-size: var(--fs-s); } -.files a { color: var(--addr); text-decoration: none; border-bottom: 1px dotted var(--addr); } -.files a:hover { color: var(--text); } -.rv-body { flex: 1 1 auto; min-height: 0; display: flex; position: relative; border-top: 1px solid var(--line); } -.rv-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; } - -/* timeline strip (categorical slots from the validated reference palette; dark steps below) */ -:root { - --s1: #3987e5; --s2: #d95926; --s3: #199e70; --s4: #c98500; --s5: #d55181; --s6: #008300; --so: #4b545d; -} -:root[data-theme="light"] { - --s1: #2a78d6; --s2: #eb6834; --s3: #1baf7a; --s4: #eda100; --s5: #e87ba4; --s6: #008300; --so: #b5ab96; -} -.hist { flex: none; margin: 0; padding: 6px 14px 6px; border-bottom: 1px solid var(--line); background: var(--panel); position: relative; user-select: none; } -.hist svg { width: 100%; display: block; cursor: crosshair; } -.hist rect.b { fill: var(--muted); } -.hist rect.b.in { fill: var(--accent); } -.hist rect.b.s1, .sw.s1 { fill: var(--s1); background: var(--s1); } -.hist rect.b.s2, .sw.s2 { fill: var(--s2); background: var(--s2); } -.hist rect.b.s3, .sw.s3 { fill: var(--s3); background: var(--s3); } -.hist rect.b.s4, .sw.s4 { fill: var(--s4); background: var(--s4); } -.hist rect.b.s5, .sw.s5 { fill: var(--s5); background: var(--s5); } -.hist rect.b.s6, .sw.s6 { fill: var(--s6); background: var(--s6); } -.hist rect.b.so, .sw.so { fill: var(--so); background: var(--so); } -.hist rect.b.out { opacity: .3; } -.hist rect.brush { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1; vector-effect: non-scaling-stroke; } -.hist .axis { display: flex; justify-content: space-between; font-size: 9.5px; color: var(--muted); margin-top: 3px; } -.hist .axis .out { color: var(--accent); margin: 0 8px; } -.hist .hl { display: flex; gap: 8px; align-items: center; font-size: var(--fs-xs); color: var(--muted); margin-bottom: 5px; } -.hist .hl select { height: 22px; font-size: var(--fs-xs); padding: 0 4px; } -.hist .hl .rl { margin-left: auto; } -.hist .legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 5px; font-size: var(--fs-xs); color: var(--text2); } -.hist .legend .li { display: inline-flex; align-items: center; gap: 5px; } -.hist .legend .n, .htip .n { color: var(--muted); } -.sw { display: inline-block; width: 9px; height: 9px; border-radius: 2px; flex: none; } -.htip { position: absolute; z-index: 6; min-width: 200px; max-width: 320px; padding: 7px 9px; background: var(--raise2); border: 1px solid var(--line2); border-radius: 4px; box-shadow: var(--shadow); font-size: var(--fs-xs); color: var(--text); pointer-events: none; } -.htip b { font-weight: 700; display: block; margin-bottom: 2px; } -.htip .tr { display: grid; grid-template-columns: 12px 1fr auto; gap: 6px; align-items: center; } -.rv-bar .btn[aria-pressed="true"] { color: var(--accent); border-color: var(--line2); } - -/* ---------------------------------------------------------------- virtual table */ -.vt { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; outline: none; } -.vt:focus-visible { box-shadow: inset 0 0 0 1px var(--focus); } -.vt-scroll { flex: 1 1 auto; overflow: auto; position: relative; contain: strict; } -.vt-head { position: sticky; top: 0; z-index: 2; background: var(--panel); border-bottom: 1px solid var(--line2); min-width: 100%; width: max-content; } -.vt-hrow, .vt-row { display: grid; grid-template-columns: var(--vt-cols); min-width: 100%; width: max-content; } -.vt-hcell { - position: relative; height: 28px; display: flex; align-items: center; gap: 4px; padding: 0 8px; - font-size: var(--fs-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text2); - border-right: 1px solid var(--line); cursor: pointer; user-select: none; white-space: nowrap; overflow: hidden; -} -.vt-hcell:hover { color: var(--text); background: var(--panel2); } -.vt-hcell .hn { overflow: hidden; text-overflow: ellipsis; } -.vt-hcell .ht { color: var(--faint); font-weight: 400; letter-spacing: 0; text-transform: none; margin-left: auto; } -.vt-hcell .so { color: var(--accent); font-size: 10px; letter-spacing: 0; } -.vt-hcell.filtered .hn { color: var(--accent); } -.vt-hcell .grip { position: absolute; right: -3px; top: 0; bottom: 0; width: 7px; cursor: col-resize; z-index: 1; } -.vt-hcell .grip:hover, .vt-hcell .grip.drag { background: var(--accent); } -.vt-frow { display: grid; grid-template-columns: var(--vt-cols); border-top: 1px solid var(--line); background: var(--panel2); } -.vt-frow input { height: 24px; border-radius: 0; border: 0; border-right: 1px solid var(--line); background: transparent; padding: 0 8px; font-size: var(--fs-s); width: 100%; min-width: 0; } -.vt-frow input:focus { background: var(--bg); box-shadow: inset 0 0 0 1px var(--focus); } -.vt-spacer { position: relative; } -.vt-rows { position: absolute; left: 0; top: 0; min-width: 100%; will-change: transform; } -.vt-row { height: var(--row); cursor: default; } -.vt-row:nth-child(even) { background: var(--stripe); } -.vt-row:hover { background: var(--raise); } -.vt-row.cur { background: var(--sel); } -.vt-row.ctx .vt-cell { opacity: .45; } -.vt-row.uniq { background: var(--uniq); box-shadow: inset 2px 0 0 var(--accent); } -.vt-row.loading .vt-cell::after { content: ""; display: block; height: 8px; width: 60%; background: var(--line); border-radius: 2px; opacity: .6; } -.vt-cell { - height: var(--row); line-height: var(--row); padding: 0 8px; white-space: pre; overflow: hidden; text-overflow: ellipsis; - border-right: 1px solid transparent; font-variant-numeric: tabular-nums; -} -.vt-row.cur .vt-cell.cc { box-shadow: inset 0 0 0 1px var(--focus); } -.vt-cell.num { text-align: right; } -.vt-cell.hex { color: var(--addr); } -.vt-cell.hex.link { cursor: pointer; } -.vt-cell.hex.link:hover { text-decoration: underline; text-underline-offset: 3px; } -.vt-cell.ab { color: var(--muted); } -.vt-cell.t0 { padding-left: calc(8px + var(--d, 0) * 16px); position: relative; } -.vt-cell.t0.tree::before { content: "└"; position: absolute; left: calc(var(--d, 0) * 16px - 6px); color: var(--faint); } -.vt-cell .dim { color: var(--faint); } -.vt-cell .ml { display: inline-block; margin-left: 6px; padding: 0 5px; line-height: 15px; border-radius: 8px; background: var(--raise2); color: var(--muted); font-size: var(--fs-xs); vertical-align: 1px; } -.vt-cell.pidlink { cursor: pointer; } -.vt-cell.pidlink:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; } -.vt-empty { position: absolute; left: 0; right: 0; top: 60px; text-align: center; color: var(--muted); font: 13px/1.6 var(--sans); padding: 0 20px; pointer-events: none; } -.vt-foot { flex: none; display: flex; gap: 14px; align-items: center; height: 22px; padding: 0 12px; border-top: 1px solid var(--line); background: var(--panel); font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; overflow: hidden; } -.vt-foot .sp { flex: 1; } -.vt.busy .vt-foot { background-image: linear-gradient(90deg, transparent, var(--accent-soft), transparent); background-size: 40% 100%; background-repeat: no-repeat; animation: busy 1s linear infinite; } -.vt.busy .vt-rows { opacity: .55; transition: opacity .15s; } -@keyframes busy { from { background-position: -40% 0; } to { background-position: 140% 0; } } - -/* row detail drawer */ -.drawer { - flex: none; width: min(460px, 42%); border-left: 1px solid var(--line); background: var(--panel); - display: flex; flex-direction: column; min-height: 0; animation: drawerIn .18s var(--ease); -} -@keyframes drawerIn { from { transform: translateX(12px); opacity: 0; } } -.drawer-h { display: flex; align-items: center; gap: 8px; padding: 8px 10px 8px 14px; border-bottom: 1px solid var(--line); } -.drawer-h h3 { margin: 0; flex: 1; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); } -.drawer-b { overflow: auto; padding: 6px 0 20px; } -.kv { display: grid; grid-template-columns: minmax(90px, 34%) 1fr; gap: 0 10px; padding: 5px 14px; border-bottom: 1px dashed var(--line); align-items: start; } -.kv:hover { background: var(--panel2); } -.kv .k { color: var(--muted); font-size: var(--fs-s); padding-top: 1px; overflow-wrap: anywhere; } -.kv .v { overflow-wrap: anywhere; white-space: pre-wrap; min-width: 0; } -.kv .v.block { grid-column: 1 / -1; margin-top: 4px; } -.kv .acts { grid-column: 2; display: flex; gap: 4px; margin-top: 3px; } -pre.code { margin: 0; padding: 8px 10px; background: var(--bg); border: 1px solid var(--line); border-radius: 4px; font-size: 11.5px; line-height: 1.5; overflow: auto; white-space: pre; max-height: 420px; } -pre.code .a { color: var(--faint); } -pre.code .m { color: var(--accent); } -pre.code .o { color: var(--text); } -pre.code .x { color: var(--addr); } -.linkbtn { border: 0; background: none; padding: 0; color: var(--addr); cursor: pointer; font-size: var(--fs-s); text-decoration: underline dotted; text-underline-offset: 3px; } -.linkbtn:hover { color: var(--text); } - -/* menus / popovers */ -.menu { - position: fixed; z-index: 50; min-width: 220px; max-height: 70vh; overflow: auto; padding: 4px; - background: var(--raise); border: 1px solid var(--line2); border-radius: 5px; box-shadow: var(--shadow); - animation: pop .12s var(--ease); -} -@keyframes pop { from { transform: translateY(-3px); opacity: 0; } } -.menu .mi { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 10px; border: 0; border-radius: 3px; background: none; text-align: left; font-size: var(--fs-s); } -.menu .mi:hover, .menu .mi:focus-visible { background: var(--sel-strong); outline: none; } -.menu .mi small { margin-left: auto; color: var(--muted); } -.menu .sep { height: 1px; background: var(--line); margin: 4px 2px; } -.menu .mh { padding: 6px 10px 3px; font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); } -.menu label.mi { cursor: pointer; } -.menu input[type="checkbox"] { accent-color: var(--accent); margin: 0; } - -/* ---------------------------------------------------------------- palette */ -.scrim { position: fixed; inset: 0; z-index: 40; background: var(--scrim); backdrop-filter: blur(2px); animation: fade .12s; } -@keyframes fade { from { opacity: 0; } } -.palette { - position: fixed; z-index: 41; left: 50%; top: 9vh; transform: translateX(-50%); - width: min(980px, 94vw); height: min(640px, 82vh); display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); grid-template-rows: auto 1fr auto; - background: var(--panel); border: 1px solid var(--line2); border-radius: 7px; box-shadow: var(--shadow); overflow: hidden; - animation: pal .16s var(--ease); -} -@keyframes pal { from { transform: translate(-50%, -8px); opacity: 0; } } -.pal-in { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px; padding: 0 14px; border-bottom: 1px solid var(--line); height: 50px; } -.pal-in input { flex: 1; height: 48px; border: 0; background: transparent; font-size: 16px; padding: 0; box-shadow: none !important; } -.pal-in .os { display: flex; gap: 4px; } -.pal-in .os button { height: 22px; padding: 0 8px; border: 1px solid var(--line2); border-radius: 11px; background: transparent; color: var(--muted); font-size: var(--fs-xs); letter-spacing: .06em; } -.pal-in .os button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); } -.pal-list { overflow: auto; border-right: 1px solid var(--line); padding: 4px 0 10px; } -.pal-grp { padding: 10px 14px 4px; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--faint); } -.pal-item { display: grid; grid-template-columns: 1fr auto; gap: 1px 10px; padding: 6px 14px; cursor: pointer; border-left: 2px solid transparent; } -.pal-item .pn { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.pal-item .pn .ns { color: var(--muted); } -.pal-item .pn mark { background: none; color: var(--accent); font-weight: 700; } -.pal-item .pd { grid-column: 1 / -1; color: var(--muted); font: 12px/1.35 var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.pal-item .pb { font-size: var(--fs-xs); color: var(--faint); align-self: center; } -.pal-item .pb.ok { color: var(--ok); } -.pal-item[aria-selected="true"] { background: var(--sel-strong); border-left-color: var(--accent); } -.pal-item.other-os { opacity: .5; } -.pal-detail { overflow: auto; padding: 16px 18px; } -.pal-detail h3 { margin: 0 0 2px; font-size: 16px; overflow-wrap: anywhere; } -.pal-detail .full { color: var(--muted); font-size: var(--fs-s); overflow-wrap: anywhere; margin-bottom: 10px; } -.pal-detail .desc { font: 13.5px/1.55 var(--sans); color: var(--text2); margin: 0 0 12px; white-space: pre-line; } -.pal-detail .blurb { font: 13.5px/1.55 var(--sans); margin: 0 0 8px; } -.pal-foot { grid-column: 1 / -1; display: flex; gap: 14px; align-items: center; padding: 8px 14px; border-top: 1px solid var(--line); font-size: var(--fs-xs); color: var(--muted); } -.pal-foot .sp { flex: 1; } -.pal-empty { padding: 30px 16px; color: var(--muted); text-align: center; font: 13px/1.6 var(--sans); } - -/* option forms */ -.form { display: grid; gap: 12px; } -.fld { display: grid; gap: 4px; } -.fld > label, .fld > .fl { display: flex; align-items: baseline; gap: 8px; font-size: var(--fs-s); color: var(--text); } -.fld .fl code { color: var(--addr); } -.fld .req { color: var(--accent); font-size: var(--fs-xs); letter-spacing: .1em; } -.fld .help { color: var(--muted); font: 12px/1.4 var(--sans); } -.fld .err { color: var(--bad); font-size: var(--fs-s); } -.fld .input { width: 100%; } -.check { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: var(--fs-s); } -.check input { width: 15px; height: 15px; accent-color: var(--accent); margin: 0; } -.tokens { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; min-height: 28px; padding: 2px 4px; border: 1px solid var(--line2); border-radius: var(--r); background: var(--bg); cursor: text; } -.tokens:focus-within { border-color: var(--focus); box-shadow: 0 0 0 3px var(--sel); } -.tokens input { flex: 1; min-width: 80px; border: 0 !important; box-shadow: none !important; height: 22px; background: transparent; padding: 0 4px; } -.tokens .chip { height: 20px; } -.tokens .chip button { border: 0; background: none; padding: 0 0 0 2px; color: var(--faint); } -.suggest { position: relative; } -.suggest-list { position: absolute; z-index: 5; left: 0; right: 0; top: calc(100% + 2px); max-height: 220px; overflow: auto; background: var(--raise); border: 1px solid var(--line2); border-radius: 4px; box-shadow: var(--shadow); } -.suggest-list div { display: grid; grid-template-columns: 60px 1fr auto; gap: 8px; padding: 4px 8px; cursor: pointer; font-size: var(--fs-s); } -.suggest-list div[aria-selected="true"], .suggest-list div:hover { background: var(--sel-strong); } -.suggest-list .sp { color: var(--muted); text-align: right; } -.cmdline { margin-top: 14px; padding: 8px 10px; border: 1px dashed var(--line2); border-radius: 4px; font-size: var(--fs-s); color: var(--text2); overflow-wrap: anywhere; } -.cmdline b { color: var(--muted); font-weight: 400; } - -/* ---------------------------------------------------------------- process view */ -.pv-head { padding: 14px 18px 10px; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 20px; flex: none; border-bottom: 1px solid var(--line); background: var(--panel); } -.pv-name { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; } -.pv-name h2 { margin: 0; font-size: 20px; } -.pv-name .pid { color: var(--muted); } -.pv-name .pid b { color: var(--accent); font-weight: 700; } -.pv-cmd { grid-column: 1 / -1; font-size: var(--fs-s); color: var(--text2); overflow-wrap: anywhere; min-height: 1.4em; } -.pv-cmd .lbl { color: var(--faint); margin-right: 6px; } -.pv-facts { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px 22px; font-size: var(--fs-s); } -.pv-facts span { color: var(--muted); } -.pv-facts b { color: var(--text); font-weight: 400; } -.pv-facts button.linkbtn { font-size: var(--fs-s); } -.pv-life { grid-column: 1 / -1; position: relative; height: 26px; margin: 6px 0 0; } -.pv-life .track { position: absolute; left: 0; right: 0; top: 5px; height: 2px; background: var(--line2); } -.pv-life .span { position: absolute; top: 2px; height: 8px; background: var(--accent); border-radius: 1px; min-width: 3px; } -.pv-life .span.dead { background: var(--muted); } -.pv-life .tick { position: absolute; top: 0; width: 1px; height: 12px; background: var(--faint); } -.pv-life .lab { position: absolute; top: 13px; font-size: 9.5px; color: var(--muted); white-space: nowrap; transform: translateX(-50%); } -.pv-life .lab.first { transform: none; } -.pv-life .lab.last { transform: translateX(-100%); } -.pv-flags { grid-column: 1 / -1; display: flex; gap: 6px; flex-wrap: wrap; } -.flagchip { display: inline-flex; gap: 6px; align-items: center; padding: 2px 8px; border-radius: 3px; background: var(--accent-soft); color: var(--accent); font-size: var(--fs-s); } -.subtabs { display: flex; gap: 2px; padding: 6px 14px 0; flex: none; border-bottom: 1px solid var(--line); overflow-x: auto; background: var(--panel); } -.subtab { display: flex; align-items: center; gap: 6px; height: 28px; padding: 0 11px; border: 0; border-bottom: 2px solid transparent; background: none; color: var(--muted); font-size: var(--fs-s); white-space: nowrap; } -.subtab:hover { color: var(--text); } -.subtab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); } -.subtab .n { color: var(--faint); font-size: var(--fs-xs); } -.subtab.na { opacity: .45; } -.subpanes { flex: 1 1 auto; min-height: 0; position: relative; } - -/* ---------------------------------------------------------------- hex viewer */ -.hx { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; } -.hx-bar { display: flex; gap: 8px; align-items: center; padding: 10px 14px; flex-wrap: wrap; flex: none; border-bottom: 1px solid var(--line); background: var(--panel); } -.hx-bar .addrin { width: 220px; } -.hx-bar .lay { max-width: 240px; } -.hx-body { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, 30%); } -.hx-dis pre.code { font-size: 11px; } -.hx-grid { overflow: auto; position: relative; outline: none; padding: 6px 0 20px; } -.hx-grid:focus-visible { box-shadow: inset 0 0 0 1px var(--focus); } -.hx-row { display: grid; grid-template-columns: 20ch repeat(8, 3ch) 1ch repeat(8, 3ch) 2ch 17ch; height: 20px; line-height: 20px; padding: 0 14px; white-space: pre; } -.hx-row:hover { background: var(--panel2); } -.hx-row .o { color: var(--muted); } -.hx-row .o.here { color: var(--accent); } -.hx-row b { font-weight: 400; cursor: pointer; text-align: center; } -.hx-row b.z { color: var(--faint); } -.hx-row b.bad { color: var(--faint); opacity: .55; } -.hx-row b.sel, .hx-row u.sel { background: var(--accent); color: var(--accent-ink); border-radius: 2px; } -.hx-row b.rng, .hx-row u.rng { background: var(--accent-soft); } -.hx-row .asc { color: var(--text2); display: flex; } -.hx-row u { text-decoration: none; width: 1ch; cursor: pointer; } -.hx-row u.np { color: var(--faint); } -.hx-side { border-left: 1px solid var(--line); overflow: auto; background: var(--panel); } -.hx-side h4 { margin: 0; padding: 10px 14px 6px; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); } -.insp { display: grid; grid-template-columns: 88px 1fr; gap: 3px 10px; padding: 0 14px 10px; font-size: var(--fs-s); } -.insp .k { color: var(--muted); } -.insp .v { overflow-wrap: anywhere; } -.hx-dis { padding: 0 14px 20px; } -.hx-dis pre.code { max-height: none; } -.hx-note { padding: 10px 14px; color: var(--muted); font: 12.5px/1.5 var(--sans); } - -/* ---------------------------------------------------------------- compare */ -.cmp { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; } -.cmp-bar { display: flex; gap: 10px; align-items: center; padding: 10px 14px; flex-wrap: wrap; border-bottom: 1px solid var(--line); background: var(--panel); flex: none; } -.cmp-bar select { max-width: 320px; } -.cmp-grid { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; } -.cmp-side { display: flex; flex-direction: column; min-height: 0; min-width: 0; } -.cmp-side + .cmp-side { border-left: 1px solid var(--line2); } -.cmp-side .cmp-h { padding: 6px 12px; font-size: var(--fs-s); color: var(--text2); border-bottom: 1px solid var(--line); display: flex; gap: 8px; align-items: center; background: var(--panel2); } -.cmp-side .cmp-h b { color: var(--accent); font-weight: 400; } -.cmp-side .rv-bar .q { width: 170px; } -.cmp-side .rv-bar { flex-wrap: nowrap; overflow: hidden; } - -/* ---------------------------------------------------------------- dialogs, toasts */ -.dialog { - position: fixed; z-index: 41; left: 50%; top: 12vh; transform: translateX(-50%); width: min(640px, 92vw); max-height: 76vh; overflow: auto; - background: var(--panel); border: 1px solid var(--line2); border-radius: 7px; box-shadow: var(--shadow); animation: pal .16s var(--ease); -} -.dialog .card-h { position: sticky; top: 0; background: var(--panel); z-index: 1; } -.keys { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; padding: 14px 18px 18px; font-size: var(--fs-s); align-items: center; } -.keys h5 { grid-column: 1 / -1; margin: 10px 0 0; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); } -.keys h5:first-child { margin-top: 0; } -.keys .kk { display: flex; gap: 4px; justify-content: flex-end; } -.toasts { position: fixed; right: 14px; bottom: 14px; z-index: 60; display: flex; flex-direction: column; gap: 6px; align-items: flex-end; pointer-events: none; } -.toast { padding: 7px 12px; border-radius: 4px; background: var(--raise2); border: 1px solid var(--line2); box-shadow: var(--shadow); font-size: var(--fs-s); animation: pop .15s var(--ease); max-width: 60vw; } -.toast.bad { border-color: var(--bad); color: var(--bad); } -.conn { position: fixed; left: 50%; top: 48px; transform: translateX(-50%); z-index: 70; padding: 6px 14px; border-radius: 4px; background: var(--bad); color: #fff; font-size: var(--fs-s); box-shadow: var(--shadow); } -.noscript { padding: 20px; } -.empty-state { margin: 10vh auto 0; max-width: 520px; text-align: center; color: var(--muted); font: 14px/1.6 var(--sans); } -.empty-state h2 { font: 700 18px/1.3 var(--mono); color: var(--text); margin: 0 0 8px; } - -/* ---------------------------------------------------------------- responsive */ -@media (max-width: 1280px) { - :root { --rail: 260px; } - .cmdk { min-width: 190px; } - .ev-meta { display: none; } - .ov { grid-template-columns: 1fr; padding: 16px; } - .hx-body { grid-template-columns: minmax(0, 1fr) 260px; } -} -@media (max-width: 1024px) { - :root { --rail: 220px; } - .cmdk span { display: none; } - .cmdk { min-width: 0; } - .activity .txt { display: none; } - .drawer { position: absolute; right: 0; top: 0; bottom: 0; width: min(420px, 90%); z-index: 4; box-shadow: var(--shadow); } - .hx-body { grid-template-columns: 1fr; } - .hx-side { display: none; } - .palette { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; } - .pal-detail { display: none; } - .palette.form-mode .pal-list { display: none; } - .palette.form-mode .pal-detail { display: block; } - .rv-bar .q { width: 200px; } -} -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition: none !important; } -} - -/* login */ -.login-box { top: 18vh; width: min(520px, 92vw); } -.prose.flush { margin: 0; } -.bad { color: var(--bad); margin: 0; font-size: var(--fs-s); } diff --git a/src/web/assets/app.js b/src/web/assets/app.js index 720f4c8..45ecc83 100644 --- a/src/web/assets/app.js +++ b/src/web/assets/app.js @@ -1,191 +1,85 @@ -// Bootstrap: load plugins and session, start the event stream, wire global shortcuts. +// Bootstrap: token, plugins, session and runs; the workspace panels; the Quick Start. -import { store, api, on, emit, el, startEvents, prefs, fmtBytes, fmtTime, toast, closeMenu, TOKEN, setToken, modal } from './core.js'; -import { openTab, activate, cycleTab, nthTab, closeTab, activeView, Overview, renderRunList, restoreTabs, closeSessionTabs, helpDialog, memoryPrompt, openImageDialog, openCompare, refreshTabs } from './views.js'; -import { initTree, loadProcs, resetTree, renderTree } from './procs.js'; -import { openPalette, paletteOpen } from './palette.js'; -import { captureTime } from './result.js'; +import { store, api, on, el, startEvents, TOKEN, setToken } from './core.js'; +import { renderAll, wire } from './workspace.js'; +import { loadProcesses } from './procdata.js'; +import { showQuickStart } from './quickstart.js'; +import { initSplitters } from './layout.js'; +import { showOptions } from './options.js'; +import { wireResults, closeResults, stepTab, openBatchId, focusResultsFilter } from './results.js'; function applyTheme(t) { document.documentElement.setAttribute('data-theme', t); try { localStorage.setItem('fastvol.theme', t); } catch (e) { /* ignore */ } } +const toggleTheme = () => applyTheme(document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'); -function renderTopbar() { - const s = store.session; - const name = document.getElementById('ev-name'); - const meta = document.getElementById('ev-meta'); - if (!s || !s.image) { name.textContent = 'no image — click to open one'; meta.textContent = ''; return; } - name.textContent = s.name; - const F = Object.fromEntries(s.facts || []); - const parts = [fmtBytes(s.size)]; - if (s.os === 'windows') parts.push(`Windows ${(F['Major/Minor'] || '').split('.').pop() || ''} ${s.arch === 'intel64' ? 'x64' : 'x86'}`.replace(/\s+/g, ' ').trim()); - else if (s.os === 'linux') parts.push('Linux ' + ((F.Banner || '').match(/Linux version (\S+)/) || [, ''])[1]); - else if (s.os === 'mac') parts.push('macOS ' + ((F.Banner || '').match(/Darwin Kernel Version (\S+?):/) || [, ''])[1]); - const cap = captureTime(); - if (cap) parts.push('captured ' + fmtTime(cap) + ' UTC'); - if (s.state === 'warming') parts.push((s.phase || 'preparing') + '…'); - if (s.state === 'failed') parts.push('⚠ not recognised'); - meta.textContent = parts.join(' · '); - document.title = `${s.name} — fastvol`; -} - -function railResize() { - const handle = document.getElementById('rail-resize'); - const rail = document.getElementById('rail'); - const w = prefs.get('railW', null); - if (w) document.documentElement.style.setProperty('--rail', w + 'px'); - const set = px => { const v = Math.max(200, Math.min(innerWidth * 0.6, px)); document.documentElement.style.setProperty('--rail', v + 'px'); prefs.set('railW', v); }; - handle.addEventListener('mousedown', e => { - e.preventDefault(); - handle.classList.add('drag'); - const move = ev => set(ev.clientX); - const up = () => { handle.classList.remove('drag'); removeEventListener('mousemove', move); removeEventListener('mouseup', up); }; - addEventListener('mousemove', move); - addEventListener('mouseup', up); - }); - handle.addEventListener('keydown', e => { - if (e.key === 'ArrowLeft') set(rail.offsetWidth - 20); - if (e.key === 'ArrowRight') set(rail.offsetWidth + 20); - }); - const split = document.getElementById('rail-split'); - const procs = rail.querySelector('.procs'), hist = rail.querySelector('.history'); - const hf = prefs.get('histFrac', null); - const setFrac = f => { f = Math.max(0.12, Math.min(0.8, f)); procs.style.flex = `1 1 ${(1 - f) * 100}%`; hist.style.flex = `1 1 ${f * 100}%`; prefs.set('histFrac', f); }; - if (hf) setFrac(hf); - split.addEventListener('mousedown', e => { - e.preventDefault(); - split.classList.add('drag'); - const r = rail.getBoundingClientRect(); - const move = ev => setFrac(1 - (ev.clientY - r.top) / r.height); - const up = () => { split.classList.remove('drag'); removeEventListener('mousemove', move); removeEventListener('mouseup', up); }; - addEventListener('mousemove', move); - addEventListener('mouseup', up); - }); -} - -function typing(e) { - const t = e.target; - return t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.tagName === 'SELECT' || t.isContentEditable); -} - -function shortcuts() { - document.addEventListener('keydown', e => { - const ctrl = e.ctrlKey || e.metaKey; - if (ctrl && (e.key === 'k' || e.key === 'K')) { e.preventDefault(); closeMenu(); openPalette(); return; } - if (e.altKey && /^[1-9]$/.test(e.key)) { e.preventDefault(); nthTab(+e.key - 1); return; } - if (e.altKey && (e.key === 'w' || e.key === 'W' || e.code === 'KeyW')) { e.preventDefault(); const v = document.querySelector('.tab[aria-selected="true"]'); if (v) closeTab(v.id.slice(4)); return; } - if (paletteOpen() || typing(e) || ctrl || e.altKey || document.querySelector('.dialog, .palette')) return; - const v = activeView(); - switch (e.key) { - case '/': e.preventDefault(); if (v && v.focusFilter) v.focusFilter(); break; - case '?': e.preventDefault(); helpDialog(); break; - case 't': e.preventDefault(); document.getElementById('proc-filter').focus(); break; - case 'T': e.preventDefault(); applyTheme(document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'); break; - case 'o': case 'O': e.preventDefault(); activate('overview'); break; - case 'm': case 'M': e.preventDefault(); memoryPrompt(); break; - case '[': e.preventDefault(); cycleTab(-1); break; - case ']': e.preventDefault(); cycleTab(1); break; - case 'Escape': if (v && v.panel && v.panel.drawer) { v.panel.closeDrawer(); } break; - default: return; - } - }); -} - -/** No (valid) token: ask for it. The token is printed by `fvol serve` (in the URL it prints). */ +/** No valid token: ask for it (it is in the URL `fvol serve` prints). */ function lockScreen(wrong) { - const inp = el('input.input', { type: 'password', autocomplete: 'off', spellcheck: false, placeholder: 'access token', 'aria-label': 'Access token' }); + const inp = el('input.qs-input', { type: 'password', autocomplete: 'off', spellcheck: false, placeholder: 'access token', 'aria-label': 'Access token' }); const go = () => { if (inp.value.trim()) { setToken(inp.value.trim()); location.reload(); } }; inp.addEventListener('keydown', e => { if (e.key === 'Enter') go(); }); - const box = el('div.dialog.login-box', { 'aria-label': 'Access token needed' }, - el('div.card-h', {}, el('h3', { text: 'fastvol · locked' })), - el('div.card-b.openbox', {}, - el('img.mascot', { src: '/assets/mark.svg', alt: '' }), - el('p.prose.flush', { text: 'This server gives access to a memory image. Open the URL printed by fvol serve (it carries the token), or paste the token here.' }), - wrong ? el('p.bad', { role: 'alert', text: 'The saved token is not valid for this server (it changes every time fvol serve starts).' }) : null, - el('div.row', {}, inp, el('button.btn.primary', { type: 'button', text: 'Unlock', on: { click: go } })))); - document.body.append(el('div.scrim'), box); + const logo = document.querySelector('.brand-logo').cloneNode(true); + document.body.append(el('div.qs', { role: 'dialog', 'aria-label': 'Access token needed' }, + el('div.qs-lock', {}, + el('div.qs-brand', {}, logo), + el('h2.qs-title', { text: 'Locked' }), + el('p.qs-sub', { text: 'This server gives access to a memory image. Open the URL printed by fvol serve (it carries the token), or paste the token here.' }), + wrong ? el('p.qs-err', { role: 'alert', text: 'The saved token is not valid for this server (it changes every time fvol serve starts).' }) : null, + el('div.qs-pathrow', {}, inp, el('button.qs-btn.primary', { type: 'button', text: 'Unlock', on: { click: go } }))))); inp.focus(); } -/** Deep links: #proc/4, #run/12, #plugin/windows.pslist.PsList, #hex/kernel/0xfffff800..., #palette/malfind, #compare/3/5, #help. */ -async function route() { - const h = decodeURIComponent(location.hash.slice(1)); - if (!h || h.startsWith('token=')) return; - const [kind, ...rest] = h.split('/'); - try { - if (kind === 'proc' && rest[0]) emit('nav', { kind: 'proc', pid: +rest[0] }); - else if (kind === 'run' && rest[0]) emit('nav', { kind: 'run', id: +rest[0] }); - else if (kind === 'plugin' && rest[0]) { - const [name, qs] = rest.join('/').split('?'); - const args = Object.fromEntries(new URLSearchParams(qs || '')); - const { runPlugin } = await import('./core.js'); - const run = await runPlugin(name, args, { reuse: true }); - emit('nav', { kind: 'run', id: run.id }); - } else if (kind === 'hex' && rest.length >= 2) emit('nav', { kind: 'hex', layer: rest[0], addr: rest[1] }); - else if (kind === 'palette') openPalette({ query: rest.join('/') }); - else if (kind === 'compare') emit('nav', { kind: 'compare', a: +rest[0] || null, b: +rest[1] || null }); - else if (kind === 'help') helpDialog(); - else if (kind === 'overview') activate('overview'); - } catch (e) { toast(e.message, 'bad'); } +function shortcuts() { + document.addEventListener('keydown', e => { + if (openBatchId() !== null && (e.ctrlKey || e.metaKey) && (e.key === 'ArrowLeft' || e.key === 'ArrowRight') && !(e.target && e.target.tagName === 'INPUT')) { e.preventDefault(); stepTab(e.key === 'ArrowRight' ? 1 : -1); return; } + const t = e.target; + if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable) || e.ctrlKey || e.metaKey || e.altKey) return; + if (document.querySelector('.qs, .wb-dialog, .menu')) return; + if (e.key === 'T') { e.preventDefault(); toggleTheme(); } + // results: [ and ] step through the plugin tabs, / filters, Esc closes + if (openBatchId() !== null) { + if (e.key === '[' || e.key === ']') { e.preventDefault(); stepTab(e.key === ']' ? 1 : -1); } + if (e.key === '/' && focusResultsFilter()) e.preventDefault(); + if (e.key === 'Escape') { e.preventDefault(); closeResults(); } + } + }); } async function main() { - document.getElementById('theme').addEventListener('click', () => applyTheme(document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light')); - document.getElementById('help').addEventListener('click', helpDialog); - document.getElementById('cmdk').addEventListener('click', () => openPalette()); - document.getElementById('evidence').addEventListener('click', () => openImageDialog()); - document.getElementById('compare-btn').addEventListener('click', () => openCompare(null, null)); - railResize(); + document.getElementById('wb-theme').addEventListener('click', toggleTheme); + document.getElementById('wb-quickstart').addEventListener('click', () => showQuickStart()); + document.getElementById('wb-options').addEventListener('click', () => showOptions()); + // narrow windows hide the File Overview first; this button slides it in over the plugins + const ovBtn = document.getElementById('wb-ovbtn'); + const setOv = open => { document.body.classList.toggle('ov-open', open); ovBtn.setAttribute('aria-pressed', String(open)); }; + ovBtn.addEventListener('click', () => setOv(!document.body.classList.contains('ov-open'))); + document.addEventListener('keydown', e => { if (e.key === 'Escape' && document.body.classList.contains('ov-open')) setOv(false); }); + matchMedia('(min-width: 1280px)').addEventListener('change', m => { if (m.matches) setOv(false); }); shortcuts(); - initTree(); + wireResults(); + initSplitters(); if (!TOKEN) { lockScreen(false); return; } try { - const [plugins, session, runs] = await Promise.all([api('plugins'), api('session'), api('runs')]); + const [plugins, session, runs, batches] = await Promise.all([api('plugins'), api('session'), api('runs'), api('batches').catch(() => [])]); + store.batches = batches; store.plugins = plugins; store.pluginMap = new Map(plugins.map(p => [p.name, p])); store.session = session; for (const r of runs) store.runs.set(r.id, r); } catch (e) { if (e.status === 401) { lockScreen(true); return; } - document.getElementById('panes').append(el('div.empty-state', {}, el('h2', { text: 'Can\'t reach the fastvol server' }), e.message)); + document.getElementById('main').replaceChildren(el('div.wb-empty', {}, el('div', { text: 'Can’t reach the fastvol server' }), el('div.wb-empty-sub', { text: e.message }))); return; } - renderTopbar(); - openTab('overview', () => new Overview(), { focus: false }); - renderRunList(); - let sessionId = store.session.id; - let restored = false; - const onReady = () => { - const s = store.session; - if (s.state === 'ready') { - loadProcs().then(() => { if (!restored) { restored = true; restoreTabs(); } }); - } else if (s.state === 'failed' || s.state === 'idle') { - document.getElementById('tree').replaceChildren(el('div.tree-empty', { text: s.state === 'idle' ? 'Open a memory image to see its processes.' : 'The kernel could not be identified, so there is no process list.' })); - } - }; - on('session', ({ prev, cur }) => { - if (cur.id !== sessionId) { - sessionId = cur.id; - closeSessionTabs(); - resetTree(); - restored = false; - activate('overview'); - } - renderTopbar(); - onReady(); - renderRunList(); - }); - on('runs', () => { renderRunList(); refreshTabs(); }); - on('procs', () => renderTopbar()); - onReady(); + wire(); + renderAll(); + // the process list feeds the triage hints; load it whenever an image is ready + const procs = () => { if (store.session && store.session.state === 'ready') loadProcesses(); }; + on('session', procs); + procs(); startEvents(); - addEventListener('hashchange', route); - if (location.hash) { - // wait for the process list so process views have their data - if (store.session.state === 'ready') await loadProcs().catch(() => {}); - route(); - } + await showQuickStart(); document.getElementById('main').focus(); } diff --git a/src/web/assets/catalog.js b/src/web/assets/catalog.js index 0d19235..bfc15f2 100644 --- a/src/web/assets/catalog.js +++ b/src/web/assets/catalog.js @@ -16,12 +16,6 @@ const CATS = [ ['System info', /info|banners|frameworkinfo|isfinfo|crashinfo|statistics|layerwriter|configwriter|vmcoreinfo|boottime|lime/i], ]; -export function category(name) { - const n = name.toLowerCase(); - for (const [c, re] of CATS) if (re.test(n)) return c; - return 'Other'; -} - /** Short, analyst-oriented explanations (keyed by the name without OS prefix and class). */ export const BLURBS = { 'pslist': 'Active processes from the kernel\'s process list. The baseline for everything else.', @@ -121,52 +115,6 @@ export function blurb(name) { return BLURBS[key] || BLURBS[noOs[noOs.length - 2]] || ''; } -/** Overview quick actions: [label, [candidate plugin names], key hint]. */ -export const QUICK = { - windows: [ - ['Process tree', ['windows.pstree.PsTree', 'windows.pslist.PsList']], - ['Command lines', ['windows.cmdline.CmdLine']], - ['Network', ['windows.netscan.NetScan', 'windows.netstat.NetStat']], - ['Injected code', ['windows.malware.malfind.Malfind', 'windows.malfind.Malfind']], - ['Hidden processes', ['windows.malware.psxview.PsXView', 'windows.psxview.PsXView', 'windows.psscan.PsScan']], - ['Services', ['windows.svcscan.SvcScan', 'windows.svclist.SvcList']], - ['Loaded DLLs', ['windows.dlllist.DllList']], - ['Open files', ['windows.filescan.FileScan']], - ['Kernel drivers', ['windows.modules.Modules']], - ['Registry hives', ['windows.registry.hivelist.HiveList']], - ['Executed programs', ['windows.registry.userassist.UserAssist', 'windows.registry.amcache.Amcache', 'windows.shimcachemem.ShimcacheMem']], - ['Timeline', ['timeliner.Timeliner']], - ], - linux: [ - ['Process tree', ['linux.pstree.PsTree', 'linux.pslist.PsList']], - ['Command lines', ['linux.psaux.PsAux']], - ['Network', ['linux.sockstat.Sockstat', 'linux.netstat.Netstat']], - ['Injected code', ['linux.malware.malfind.Malfind', 'linux.malfind.Malfind']], - ['Hidden processes', ['linux.psscan.PsScan', 'linux.pidhashtable.PIDHashTable']], - ['Shell history', ['linux.bash.Bash']], - ['Process spoofing', ['linux.malware.process_spoofing.ProcessSpoofing']], - ['Open files', ['linux.lsof.Lsof']], - ['Kernel modules', ['linux.lsmod.Lsmod']], - ['Hidden modules', ['linux.malware.hidden_modules.Hidden_modules', 'linux.hidden_modules.Hidden_modules']], - ['Syscall hooks', ['linux.malware.check_syscall.Check_syscall', 'linux.check_syscall.Check_syscall']], - ['Kernel log', ['linux.kmsg.Kmsg']], - ['Mounts', ['linux.mountinfo.MountInfo']], - ['Timeline', ['timeliner.Timeliner']], - ], - mac: [ - ['Process tree', ['mac.pstree.PsTree', 'mac.pslist.PsList']], - ['Command lines', ['mac.psaux.Psaux']], - ['Network', ['mac.netstat.Netstat']], - ['Injected code', ['mac.malfind.Malfind']], - ['Shell history', ['mac.bash.Bash']], - ['Open files', ['mac.lsof.Lsof']], - ['Kernel extensions', ['mac.lsmod.Lsmod']], - ['Syscall hooks', ['mac.check_syscall.Check_syscall']], - ['Kernel log', ['mac.dmesg.Dmesg']], - ['Timeline', ['timeliner.Timeliner']], - ], -}; - /** Process list per OS and how to read its columns. */ export const PROCLIST = { windows: ['windows.pslist.PsList'], @@ -187,48 +135,6 @@ export const PCOLS = { uid: ['UID'], }; -/** Per-process pivots: [label, [candidates], {pidCol}] — plugins with a pid option get - * `--pid N`, the others run once and are filtered on their PID column. */ -export const PIVOTS = { - windows: [ - ['Handles', ['windows.handles.Handles']], - ['DLLs', ['windows.dlllist.DllList']], - ['Memory regions', ['windows.vadinfo.VadInfo']], - ['Environment', ['windows.envars.Envars']], - ['Network', ['windows.netscan.NetScan', 'windows.netstat.NetStat']], - ['Threads', ['windows.threads.Threads']], - ['Injected code', ['windows.malware.malfind.Malfind', 'windows.malfind.Malfind']], - ['Unlinked DLLs', ['windows.malware.ldrmodules.LdrModules', 'windows.ldrmodules.LdrModules']], - ['SIDs', ['windows.getsids.GetSIDs']], - ['Privileges', ['windows.privileges.Privs']], - ['Sessions', ['windows.sessions.Sessions']], - ], - linux: [ - ['Open files', ['linux.lsof.Lsof']], - ['Memory maps', ['linux.proc.Maps']], - ['Environment', ['linux.envars.Envars']], - ['Sockets', ['linux.sockstat.Sockstat']], - ['Injected code', ['linux.malware.malfind.Malfind', 'linux.malfind.Malfind']], - ['ELF files', ['linux.elfs.Elfs']], - ['Libraries', ['linux.library_list.LibraryList']], - ['Call stacks', ['linux.pscallstack.PsCallStack']], - ['Capabilities', ['linux.capabilities.Capabilities']], - ], - mac: [ - ['Open files', ['mac.lsof.Lsof']], - ['Memory maps', ['mac.proc_maps.Maps']], - ['Injected code', ['mac.malfind.Malfind']], - ['Arguments', ['mac.psaux.Psaux']], - ], -}; - -/** Plugins that print a process's command line: [plugin, column]. */ -export const CMDLINE = { - windows: [['windows.cmdline.CmdLine', 'Args']], - linux: [['linux.psaux.PsAux', 'ARGS']], - mac: [['mac.psaux.Psaux', 'Arguments']], -}; - /** Windows "find evil": expected parents and singleton processes. */ export const WIN_PARENTS = { 'svchost.exe': ['services.exe', 'MsMpEng.exe'], diff --git a/src/web/assets/core.js b/src/web/assets/core.js index e3fd3c7..9c4d65e 100644 --- a/src/web/assets/core.js +++ b/src/web/assets/core.js @@ -19,7 +19,6 @@ export function setToken(t) { TOKEN = t; try { localStorage.setItem('fastvol.token', t); } catch (e) { /* ignore */ } } -export const VERSION = document.querySelector('meta[name="fastvol-version"]').content; export class ApiError extends Error { constructor(status, message) { super(message); this.status = status; } @@ -55,13 +54,15 @@ export const store = { session: null, plugins: [], pluginMap: new Map(), - runs: new Map(), // id -> summary + runs: new Map(), // id -> summary of one plugin execution + batches: [], // runs as the user sees them: several plugins started together procRun: null, // run id of the process list }; -export function sessionRuns() { +/** The open image's runs (batches), newest first. */ +export function sessionBatches() { const sid = store.session && store.session.id; - return [...store.runs.values()].filter(r => r.session === sid).sort((a, b) => b.id - a.id); + return store.batches.filter(b => b.session === sid).sort((a, b) => b.id - a.id); } export function pluginOs(name) { @@ -109,7 +110,10 @@ export async function startEvents() { } function handleEvent(ev) { - if (ev.t === 'session') { + if (ev.t === 'batches') { + store.batches = ev.batches; + emit('batches', ev.batches); + } else if (ev.t === 'session') { const prev = store.session; store.session = ev.session; emit('session', { prev, cur: ev.session }); @@ -257,13 +261,6 @@ export function fmtTime(secs, withDate = true) { const iso = new Date(secs * 1000).toISOString(); return withDate ? iso.slice(0, 19).replace('T', ' ') : iso.slice(11, 19); } -export function fmtSpan(secs) { - secs = Math.abs(secs); - if (secs < 60) return `${Math.round(secs)}s`; - if (secs < 3600) return `${Math.round(secs / 60)}m`; - if (secs < 86400) return `${(secs / 3600).toFixed(1)}h`; - return `${(secs / 86400).toFixed(1)}d`; -} // ------------------------------------------------------------------ python int(x, 0) /** Parse like python int(x, 0); returns a BigInt or null. */ @@ -316,14 +313,6 @@ export const prefs = { set(k, v) { try { localStorage.setItem('fastvol.' + k, JSON.stringify(v)); } catch (e) { /* quota / blocked */ } }, }; -/** Remember plugin durations to show an ETA next time. */ -export function rememberDuration(plugin, ms) { - const d = prefs.get('durations', {}); - d[plugin] = ms; - prefs.set('durations', d); -} -export function expectedDuration(plugin) { return prefs.get('durations', {})[plugin]; } - // ------------------------------------------------------------------ menus let openMenu = null; export function closeMenu() { if (openMenu) { openMenu.remove(); openMenu = null; } } diff --git a/src/web/assets/hex.js b/src/web/assets/hex.js deleted file mode 100644 index 2793274..0000000 --- a/src/web/assets/hex.js +++ /dev/null @@ -1,321 +0,0 @@ -// Hex viewer over any layer (physical, kernel, a process's address space), with a data -// inspector, pointer following, history and disassembly. - -import { api, store, el, clear, copy, int0, toast, emit, fmtTime } from './core.js'; -import { disasmBlock, captureTime } from './result.js'; - -const ROWS = 65536; // rows in the scrollable window (1 MiB) -const RH = 20; -const CHUNK = 16384n; - -function hex(n, w = 16) { return n.toString(16).padStart(w, '0'); } -function hx(n) { return '0x' + n.toString(16); } - -let hexSeq = 0; - -export class HexTab { - constructor({ layer = 'kernel', addr = '0x0' }) { - this.key = 'hex' + (++hexSeq); - this.layer = layer; - this.chunks = new Map(); // chunk base (BigInt) -> {data: Uint8Array, bad: Uint8Array} | 'loading' | {error} - this.history = []; - this.sel = null; - this.anchor = null; - this.pane = el('div.pane'); - this.build(); - this.goto(BigInt(addr), true); - } - - get title() { return 'mem ' + hx(this.sel ?? 0n); } - get subtitle() { return this.layerLabel(this.layer); } - - layerLabel(id) { - if (id === 'phys') return 'physical'; - if (id === 'kernel') return 'kernel'; - const pid = id.slice(4); - const p = (store.procs || []).find(x => String(x.pid) === pid); - return `pid ${pid}${p ? ' ' + p.name : ''}`; - } - - build() { - this.addrIn = el('input.input.addrin', { type: 'text', spellcheck: false, autocomplete: 'off', 'aria-label': 'Address (python int syntax: 0x..., decimal)', placeholder: '0x… address (G)' }); - this.addrIn.addEventListener('keydown', e => { - if (e.key === 'Enter') { - const v = int0(this.addrIn.value.trim().match(/^[0-9a-f]+$/i) && !/^\d+$/.test(this.addrIn.value.trim()) ? '0x' + this.addrIn.value.trim() : this.addrIn.value); - if (v === null || v < 0n) { this.addrIn.classList.add('invalid'); return; } - this.addrIn.classList.remove('invalid'); - this.goto(v); - this.grid.focus(); - } - if (e.key === 'Escape') { this.grid.focus(); e.stopPropagation(); } - }); - this.laySel = el('select.input.lay', { 'aria-label': 'Address space' }); - this.fillLayers(); - this.laySel.addEventListener('change', () => { this.layer = this.laySel.value; this.chunks.clear(); this.render(); this.inspect(); emit('tabs-changed'); }); - const back = el('button.btn.ghost', { type: 'button', title: 'Back (Backspace)', on: { click: () => this.back() } }, '← Back'); - const follow = el('button.btn.ghost', { type: 'button', title: 'Follow the pointer at the cursor (Enter)', on: { click: () => this.follow() } }, 'Follow ptr'); - const dis = el('button.btn', { type: 'button', title: 'Disassemble from the cursor (D)', on: { click: () => this.disasm() } }, 'Disassemble'); - const cp = el('button.btn.ghost', { type: 'button', title: 'Copy the selection as hex (C)', on: { click: () => this.copySel() } }, 'Copy hex'); - this.statusEl = el('span.muted', { style: { fontSize: '11px', marginLeft: 'auto' } }); - const bar = el('div.hx-bar', {}, this.laySel, this.addrIn, back, follow, dis, cp, this.statusEl); - this.grid = el('div.hx-grid', { tabindex: 0, role: 'grid', 'aria-label': 'Memory bytes' }); - this.spacer = el('div', { style: { position: 'relative', height: ROWS * RH + 'px' } }); - this.rowsEl = el('div', { style: { position: 'absolute', left: 0, right: 0, top: 0 } }); - this.spacer.append(this.rowsEl); - this.grid.append(this.spacer); - this.side = el('div.hx-side'); - this.insp = el('div.insp'); - this.dis = el('div.hx-dis'); - this.side.append(el('h4', { text: 'Inspector' }), this.insp, el('h4', { text: 'Disassembly' }), this.dis); - this.dis.append(el('div.hx-note', { text: 'Press D (or Disassemble) to disassemble from the cursor.' })); - this.pane.append(el('div.hx', {}, bar, el('div.hx-body', {}, this.grid, this.side))); - this.pool = []; - this.grid.addEventListener('scroll', () => this.schedule(), { passive: true }); - new ResizeObserver(() => this.schedule()).observe(this.grid); - this.grid.addEventListener('mousedown', e => { - const t = e.target.closest('[data-o]'); - if (!t) return; - const a = this.base + BigInt(t.dataset.o); - if (e.shiftKey && this.sel !== null) { this.anchor ??= this.sel; this.sel = a; } - else { this.anchor = null; this.sel = a; } - this.grid.focus({ preventScroll: true }); - this.render(); - this.inspect(); - e.preventDefault(); - }); - this.grid.addEventListener('keydown', e => this.onKey(e)); - } - - fillLayers() { - clear(this.laySel); - const opts = [['kernel', 'Kernel virtual'], ['phys', 'Physical']]; - for (const p of (store.procs || []).filter(p => p.exit === null)) opts.push([`pid:${p.pid}`, `Process ${p.pid} ${p.name}`]); - if (!opts.some(([v]) => v === this.layer)) opts.push([this.layer, this.layerLabel(this.layer)]); - for (const [v, t] of opts) this.laySel.append(el('option', { value: v, text: t, selected: v === this.layer })); - } - - goto(addr, initial = false) { - if (!initial && this.sel !== null) this.history.push(this.sel); - this.sel = addr; - this.anchor = null; - // window of ROWS*16 bytes around the address - const half = BigInt(ROWS / 2) * 16n; - let base = addr > half ? ((addr - half) & ~0xfffn) : 0n; - this.base = base; - this.addrIn.value = hx(addr); - const row = Number((addr - base) / 16n); - requestAnimationFrame(() => { - this.grid.scrollTop = Math.max(0, row * RH - this.grid.clientHeight / 3); - this.render(); - }); - this.inspect(); - emit('tabs-changed'); - } - - back() { if (this.history.length) { const a = this.history.pop(); this.sel = null; this.goto(a, true); } } - - chunk(base) { - const c = this.chunks.get(base); - if (c) return c === 'loading' ? null : c; - this.chunks.set(base, 'loading'); - const layer = this.layer; - api(`mem?layer=${encodeURIComponent(layer)}&addr=${hx(base)}&len=${CHUNK}`).then(r => { - if (layer !== this.layer) return; - const data = new Uint8Array(r.len); - for (let i = 0; i < r.len; i++) data[i] = parseInt(r.hex.substr(i * 2, 2), 16); - const bad = new Uint8Array(r.len); - for (const [o, l] of r.bad) bad.fill(1, o, o + l); - this.chunks.set(base, { data, bad, name: r.name }); - this.statusEl.textContent = ''; - if (this.chunks.size > 96) for (const k of [...this.chunks.keys()].slice(0, 32)) this.chunks.delete(k); - this.schedule(); - this.inspect(); - }).catch(e => { - this.chunks.set(base, { error: e.message }); - this.statusEl.textContent = e.message; - this.schedule(); - }); - return null; - } - - byte(a) { - const base = a & ~(CHUNK - 1n); - const c = this.chunk(base); - if (!c) return undefined; - if (c.error) return null; - const i = Number(a - base); - return c.bad[i] ? null : c.data[i]; - } - - schedule() { if (!this.raf) this.raf = requestAnimationFrame(() => { this.raf = 0; this.render(); }); } - - render() { - if (!this.grid.isConnected) return; - const first = Math.floor(this.grid.scrollTop / RH); - const n = Math.ceil(this.grid.clientHeight / RH) + 2; - this.rowsEl.style.transform = `translateY(${first * RH}px)`; - while (this.pool.length < n) { - const r = el('div.hx-row', { role: 'row' }); - r._o = el('span.o'); - r.append(r._o); - r._b = []; - for (let i = 0; i < 16; i++) { if (i === 8) r.append(el('span')); const b = el('b', { role: 'gridcell' }); r._b.push(b); r.append(b); } - r.append(el('span')); - r._a = el('span.asc'); - r._u = []; - for (let i = 0; i < 16; i++) { const u = el('u'); r._u.push(u); r._a.append(u); } - r.append(r._a); - this.rowsEl.append(r); - this.pool.push(r); - } - const lo = this.anchor !== null && this.sel !== null ? (this.anchor < this.sel ? this.anchor : this.sel) : null; - const hi = this.anchor !== null && this.sel !== null ? (this.anchor < this.sel ? this.sel : this.anchor) : null; - for (let k = 0; k < this.pool.length; k++) { - const r = this.pool[k]; - const row = first + k; - if (row >= ROWS || k >= n) { r.hidden = true; continue; } - r.hidden = false; - const a0 = this.base + BigInt(row) * 16n; - r._o.textContent = hex(a0); - r._o.className = 'o' + (this.sel !== null && a0 <= this.sel && this.sel < a0 + 16n ? ' here' : ''); - for (let i = 0; i < 16; i++) { - const a = a0 + BigInt(i); - const v = this.byte(a); - const b = r._b[i], u = r._u[i]; - const off = String(row * 16 + i); - b.dataset.o = off; u.dataset.o = off; - let cls = ''; - if (v === undefined) { b.textContent = '··'; u.textContent = ' '; cls = 'bad'; } - else if (v === null) { b.textContent = '??'; u.textContent = '·'; cls = 'bad'; } - else { - b.textContent = v.toString(16).padStart(2, '0'); - const printable = v >= 0x20 && v < 0x7f; - u.textContent = printable ? String.fromCharCode(v) : '.'; - cls = v === 0 ? 'z' : ''; - u.className = printable ? '' : 'np'; - } - const isSel = this.sel === a; - const inRange = lo !== null && a >= lo && a <= hi; - b.className = cls + (isSel ? ' sel' : inRange ? ' rng' : ''); - if (isSel) u.className = 'sel'; else if (inRange) u.className = 'rng'; else if (v === null || v === undefined) u.className = 'np'; - } - } - } - - readLE(a, n) { - let v = 0n; - for (let i = n - 1; i >= 0; i--) { - const b = this.byte(a + BigInt(i)); - if (b === undefined || b === null) return null; - v = (v << 8n) | BigInt(b); - } - return v; - } - - inspect() { - clear(this.insp); - if (this.sel === null) return; - const a = this.sel; - const row = (k, v, extra) => { this.insp.append(el('span.k', { text: k }), el('span.v', {}, v ?? '—', extra || '')); }; - row('address', hx(a)); - if (this.anchor !== null) { const n = (this.sel > this.anchor ? this.sel - this.anchor : this.anchor - this.sel) + 1n; row('selection', `${n} bytes`); } - const u8 = this.readLE(a, 1), u16 = this.readLE(a, 2), u32 = this.readLE(a, 4), u64 = this.readLE(a, 8); - const s = (v, bits) => (v === null ? null : v >= 1n << BigInt(bits - 1) ? v - (1n << BigInt(bits)) : v); - row('u8 / i8', u8 === null ? null : `${u8} / ${s(u8, 8)}`); - row('u16 le', u16 === null ? null : `${u16} ${hx(u16)}`); - row('u32 le', u32 === null ? null : `${u32} ${hx(u32)}`); - row('i32 le', u32 === null ? null : String(s(u32, 32))); - const ptr = u64 === null ? null : el('button.linkbtn', { type: 'button', text: hx(u64), title: 'Follow (Enter)', on: { click: () => this.follow() } }); - row('u64 / ptr', ptr); - if (u64 !== null) { - const ft = Number(u64) / 1e7 - 11644473600; - if (ft > 0 && ft < 4102444800) row('FILETIME', fmtTime(ft) + ' UTC'); - } - if (u32 !== null) { - // only plausible timestamps: within ten years of the capture - const ut = Number(u32); - const cap = captureTime() || Date.now() / 1000; - if (Math.abs(ut - cap) < 10 * 365 * 86400) row('unix time', fmtTime(ut) + ' UTC'); - } - let str = ''; - for (let i = 0n; i < 96n; i++) { const b = this.byte(a + i); if (b === null || b === undefined || b === 0) break; str += b >= 0x20 && b < 0x7f ? String.fromCharCode(b) : '.'; } - row('ascii', str ? JSON.stringify(str) : null); - let w = ''; - for (let i = 0n; i < 192n; i += 2n) { const v = this.readLE(a + i, 2); if (v === null || v === 0n) break; w += String.fromCharCode(Number(v)); } - row('utf-16le', w ? JSON.stringify(w) : null); - } - - follow() { - if (this.sel === null) return; - const bits = store.session && store.session.arch === 'intel' ? 4 : 8; - const v = this.readLE(this.sel, bits); - if (v === null) { toast('No readable pointer at the cursor', 'bad'); return; } - this.goto(v); - } - - async disasm() { - if (this.sel === null) return; - clear(this.dis); - this.dis.append(el('div.hx-note', { text: 'Disassembling…' })); - try { - const r = await api(`disasm?layer=${encodeURIComponent(this.layer)}&addr=${hx(this.sel)}&len=256`); - clear(this.dis); - this.dis.append(el('div.hx-note', { text: `${r.arch} from ${r.addr}${r.partial ? ' (partly unreadable)' : ''}` }), disasmBlock(r.text || '(nothing decodable)')); - } catch (e) { - clear(this.dis); - this.dis.append(el('div.hx-note', { text: e.message })); - } - } - - copySel() { - if (this.sel === null) return; - let lo = this.sel, hi = this.sel; - if (this.anchor !== null) { lo = this.anchor < this.sel ? this.anchor : this.sel; hi = this.anchor < this.sel ? this.sel : this.anchor; } - if (hi - lo > 65536n) { toast('Selection too large to copy (max 64 KiB)', 'bad'); return; } - const out = []; - for (let a = lo; a <= hi; a++) { const b = this.byte(a); out.push(b === null || b === undefined ? '??' : b.toString(16).padStart(2, '0')); } - copy(out.join(' '), `Copied ${out.length} bytes`); - } - - onKey(e) { - if (this.sel === null) this.sel = this.base; - const page = BigInt(Math.max(1, Math.floor(this.grid.clientHeight / RH) - 1) * 16); - const move = d => { - if (e.shiftKey) this.anchor ??= this.sel; else this.anchor = null; - let n = this.sel + d; - if (n < 0n) n = 0n; - this.sel = n; - const row = Number((n - this.base) / 16n); - if (row < 0 || row >= ROWS) { const s = this.sel; this.sel = null; this.goto(s, true); return; } - const y = row * RH; - if (y < this.grid.scrollTop) this.grid.scrollTop = y; - else if (y + RH > this.grid.scrollTop + this.grid.clientHeight) this.grid.scrollTop = y + RH - this.grid.clientHeight; - this.render(); this.inspect(); - this.addrIn.value = hx(this.sel); - emit('tabs-changed'); - }; - switch (e.key) { - case 'ArrowRight': move(1n); break; - case 'ArrowLeft': move(-1n); break; - case 'ArrowDown': move(16n); break; - case 'ArrowUp': move(-16n); break; - case 'PageDown': move(page); break; - case 'PageUp': move(-page); break; - case 'Home': move(-(this.sel % 16n)); break; - case 'End': move(15n - (this.sel % 16n)); break; - case 'Enter': this.follow(); break; - case 'Backspace': this.back(); break; - case 'g': case 'G': this.addrIn.focus(); this.addrIn.select(); break; - case 'd': case 'D': this.disasm(); break; - case 'c': case 'C': if ((e.ctrlKey || e.metaKey) && window.getSelection().toString()) return; this.copySel(); break; - default: return; - } - e.preventDefault(); - e.stopPropagation(); - } - - onShow() { this.fillLayers(); this.schedule(); } - focus() { this.grid.focus({ preventScroll: true }); } - focusFilter() { this.addrIn.focus(); this.addrIn.select(); } - destroy() {} -} diff --git a/src/web/assets/index.html b/src/web/assets/index.html index e5b804e..8cdd298 100644 --- a/src/web/assets/index.html +++ b/src/web/assets/index.html @@ -7,63 +7,64 @@ fastvol - - + - - +
+ + + +
+

Runs

+
+
+ +
+

Triage Hints

+
+
+ +
+ + diff --git a/src/web/assets/layout.js b/src/web/assets/layout.js new file mode 100644 index 0000000..e679e58 --- /dev/null +++ b/src/web/assets/layout.js @@ -0,0 +1,86 @@ +// Splitters between the workspace panels: File Overview | middle (Plugins or Results) | right +// column, and Runs / Triage Hints inside the right column. Drag, or focus one and use the arrow +// keys; double-click resets. Sizes are CSS variables on .wb, remembered in this browser. + +import { prefs } from './core.js'; + +// minimum sizes (px); the CSS has the same minimums, these keep the drag from overshooting +const MIN = { c1: 220, mid: 360, c3: 260, r1: 90, r2: 90 }; +const STEP = 16; + +export function initSplitters() { + const wb = document.querySelector('.wb'); + const size = prefs.get('layout', {}); + const apply = () => { + for (const k of ['c1', 'c3', 'r1']) { + if (size[k]) wb.style.setProperty('--' + k, size[k] + 'px'); else wb.style.removeProperty('--' + k); + } + }; + const save = () => { prefs.set('layout', size); apply(); }; + apply(); + + const shown = sel => { const e = document.querySelector(sel); return e && getComputedStyle(e).display !== 'none'; }; + + // the value each splitter sets, from a pointer position + const calc = { + s1: (x, y, r) => clamp(x - r.left, MIN.c1, r.width - 10 - MIN.mid - current('s2')), + s2: (x, y, r) => clamp(r.right - x, MIN.c3, r.width - 10 - MIN.mid - (shown('.wb-overview') ? leftWidth() : 0)), + s3: (x, y, r) => clamp(y - r.top, MIN.r1, r.height - 5 - MIN.r2), + }; + const key = { s1: 'c1', s2: 'c3', s3: 'r1' }; + const leftWidth = () => document.querySelector('.wb-overview').getBoundingClientRect().width; + const current = id => { + if (id === 's1') return leftWidth(); + if (id === 's2') return document.querySelector('.wb-runs').getBoundingClientRect().width; + return document.querySelector('.wb-runs').getBoundingClientRect().height; + }; + + for (const id of ['s1', 's2', 's3']) { + const sp = document.getElementById(id); + const vertical = id !== 's3'; + sp.addEventListener('pointerdown', e => { + if (e.button !== 0) return; + e.preventDefault(); + sp.setPointerCapture(e.pointerId); + sp.classList.add('drag'); + document.body.classList.add('resizing', vertical ? 'v' : 'h'); + const move = ev => { size[key[id]] = Math.round(calc[id](ev.clientX, ev.clientY, wb.getBoundingClientRect())); apply(); }; + const up = () => { + sp.classList.remove('drag'); + document.body.classList.remove('resizing', 'v', 'h'); + sp.removeEventListener('pointermove', move); + sp.removeEventListener('pointerup', up); + sp.removeEventListener('pointercancel', up); + save(); + }; + sp.addEventListener('pointermove', move); + sp.addEventListener('pointerup', up); + sp.addEventListener('pointercancel', up); + }); + sp.addEventListener('dblclick', () => { delete size[key[id]]; save(); }); + sp.addEventListener('keydown', e => { + const grow = { s1: ['ArrowRight', 'ArrowLeft'], s2: ['ArrowLeft', 'ArrowRight'], s3: ['ArrowDown', 'ArrowUp'] }[id]; + const d = e.key === grow[0] ? STEP : e.key === grow[1] ? -STEP : 0; + if (!d) return; + e.preventDefault(); + const r = wb.getBoundingClientRect(); + const now = size[key[id]] || current(id); + // express the new size as the pointer position that would produce it, then clamp as a drag would + const pos = id === 's1' ? r.left + now + d : id === 's2' ? r.right - (now + d) : r.top + now + d; + size[key[id]] = Math.round(calc[id](pos, pos, r)); + save(); + }); + } + + // keep remembered sizes inside a smaller window + addEventListener('resize', () => { + const r = wb.getBoundingClientRect(); + let changed = false; + if (size.c1 && size.c1 > r.width - 10 - MIN.mid - (size.c3 || MIN.c3)) { size.c1 = Math.max(MIN.c1, Math.round(r.width - 10 - MIN.mid - (size.c3 || MIN.c3))); changed = true; } + if (size.c3 && size.c3 > r.width - 10 - MIN.mid) { size.c3 = Math.max(MIN.c3, Math.round(r.width - 10 - MIN.mid)); changed = true; } + if (size.r1 && size.r1 > r.height - 5 - MIN.r2) { size.r1 = Math.max(MIN.r1, Math.round(r.height - 5 - MIN.r2)); changed = true; } + if (changed) apply(); + }); +} + +const clamp = (v, lo, hi) => Math.max(lo, Math.min(Math.max(lo, hi), v)); diff --git a/src/web/assets/mark.svg b/src/web/assets/mark.svg deleted file mode 100644 index dfcbfc8..0000000 --- a/src/web/assets/mark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/web/assets/mono-400.woff2 b/src/web/assets/mono-400.woff2 deleted file mode 100644 index 11b4cac303489b22df61c68b9d59a45f91af4c1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21076 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 bL645Ry(2nxXoKs`ZWRU(UyQHe4FCWDnyrh7 diff --git a/src/web/assets/options.js b/src/web/assets/options.js new file mode 100644 index 0000000..c27e161 --- /dev/null +++ b/src/web/assets/options.js @@ -0,0 +1,115 @@ +// Options: every global fvol option, ticked on or off, with a short note on what it does. Saved +// with the analysis on the server; options that decide how the image is opened reopen it. + +import { api, el, toast } from './core.js'; + +// kind: flag (on/off), text, list (split by `sep`), lines (one per line), number, choice +const GROUPS = [ + ['Opening the image', 'Changing these reopens the image (quick: the caches stay warm).', [ + { key: 'symbol_dirs', flag: '-s, --symbol-dirs', kind: 'list', sep: ';', hint: 'folder1;folder2', note: 'Extra folders to look for symbol tables in.' }, + { key: 'offline', flag: '--offline', kind: 'flag', note: 'Never download symbol tables.' }, + { key: 'remote_isf_url', flag: '-u, --remote-isf-url', kind: 'text', hint: 'https://…', note: 'Look symbol tables up in this online index.' }, + { key: 'cache_path', flag: '--cache-path', kind: 'text', hint: '/path/to/folder', note: "Use another folder for python volatility3's cache." }, + { key: 'clear_cache', flag: '--clear-cache', kind: 'flag', note: "Empty fastvol's caches once, when the image reopens." }, + { key: 'single_location', flag: '--single-location', kind: 'text', hint: 'file:///… or https://…', note: 'Open this location instead of the image file.' }, + { key: 'stackers', flag: '--stackers', kind: 'list', sep: ' ', hint: 'LayerStacker names', note: 'Use only these layer stackers.' }, + { key: 'single_swap_locations', flag: '--single-swap-locations', kind: 'list', sep: ' ', hint: 'file:///…/pagefile.sys', note: 'Swap files (e.g. pagefile.sys) to read with the image.' }, + { key: 'verbosity', flag: '-v, --verbosity', kind: 'number', min: 1, max: 5, hint: '1', note: "More detail in the server's log output." }, + { key: 'output_dir', flag: '-o, --output-dir', kind: 'text', hint: '/path/to/folder', note: 'Folder for files plugins write.' }, + ]], + ['Each run', 'Applied to plugins started from now on.', [ + { key: 'config', flag: '-c, --config', kind: 'text', hint: '/path/to/config.json', note: 'Take plugin option values from this JSON file.' }, + { key: 'extend', flag: '-e, --extend', kind: 'lines', hint: 'plugins.PsList.pid=[4]', note: 'Set a configuration value (one per line).' }, + { key: 'write_config', flag: '--write-config', kind: 'flag', note: "Write each run's configuration to config.json in its output folder." }, + { key: 'save_config', flag: '--save-config', kind: 'text', hint: 'file name', note: 'Same, with this file name.' }, + { key: 'log', flag: '-l, --log', kind: 'text', hint: '/path/to/fvol.log', note: 'Log every run to this file.' }, + { key: 'parallelism', flag: '--parallelism', kind: 'choice', choices: ['processes', 'threads', 'off'], note: '"off" runs one plugin at a time.' }, + ]], + ['fvol output export', 'The "fvol output" export: exactly what the command line prints.', [ + { key: 'renderer', flag: '-r, --renderer', kind: 'choice', choices: ['quick', 'none', 'csv', 'pretty', 'json', 'jsonl', 'mermaid'], note: 'Output format.' }, + { key: 'filters', flag: '--filters', kind: 'lines', hint: '+ImageFileName,svchost', note: 'Keep or drop rows: [+-]column,pattern[!] (one per line).' }, + { key: 'hide_columns', flag: '--hide-columns', kind: 'list', sep: ' ', hint: 'Offset Handles', note: 'Leave out columns starting with these names.' }, + ]], + ['No effect in the web UI', 'Accepted so a saved analysis records them.', [ + { key: 'quiet', flag: '-q, --quiet', kind: 'flag', note: 'The web UI shows no console progress to remove.' }, + { key: 'plugin_dirs', flag: '-p, --plugin-dirs', kind: 'text', hint: 'folder1;folder2', note: 'fastvol does not load python plugins.' }, + ]], +]; + +const isSet = (o, v) => o.kind === 'flag' ? v === true : o.kind === 'number' ? v > 0 : Array.isArray(v) ? v.length > 0 : v !== null && v !== undefined && v !== ''; +const shown = (o, v) => Array.isArray(v) ? v.join(o.kind === 'lines' ? '\n' : o.sep === ';' ? ';' : ' ') : v ?? ''; + +/** Open the Options dialog. */ +export async function showOptions() { + if (document.querySelector('.wb-dialog')) return; + let cur; + try { cur = await api('options'); } catch (e) { toast('Could not read the options: ' + e.message, 'bad'); return; } + const rows = []; + const body = el('div.op-body'); + for (const [title, sub, list] of GROUPS) { + body.append(el('div.op-group', {}, el('h3', { text: title }), el('p', { text: sub }))); + for (const o of list) { + const v = cur[o.key]; + const id = 'op-' + o.key; + const on = el('input.wb-check', { id, type: 'checkbox', checked: isSet(o, v) }); + let input = null; + if (o.kind === 'choice') { + input = el('select.wb-select', {}, ...o.choices.map(c => el('option', { value: c, text: c }))); + if (v) input.value = v; + } else if (o.kind === 'lines') { + input = el('textarea.wb-input.op-lines', { rows: 2, spellcheck: false, placeholder: o.hint }); + input.value = shown(o, v); + } else if (o.kind === 'number') { + input = el('input.wb-input.op-num', { type: 'number', min: o.min, max: o.max, value: v > 0 ? v : 1 }); + } else if (o.kind !== 'flag') { + input = el('input.wb-input', { type: 'text', spellcheck: false, autocomplete: 'off', placeholder: o.hint, value: shown(o, v) }); + } + const sync = () => row.classList.toggle('on', on.checked); + // the flag and its note toggle the option; the value box stays usable, and typing ticks it + const row = el('div.op-row', {}, on, el('label.op-text', { for: id }, el('code', { text: o.flag }), el('span.op-note', { text: o.note })), input || el('span')); + if (input) { + input.setAttribute('aria-label', o.flag + ' value'); + const tick = () => { if (!on.checked) { on.checked = true; sync(); } }; + input.addEventListener('input', tick); + input.addEventListener('change', tick); + } + on.addEventListener('change', sync); + sync(); + rows.push({ o, on, input }); + body.append(row); + } + } + const errBox = el('div.dl-err', { role: 'alert' }); + const save = el('button.wb-btn.primary', { type: 'button', text: 'Save' }); + const cancel = el('button.wb-btn.ghost', { type: 'button', text: 'Cancel' }); + const scrim = el('div.wb-scrim'); + const box = el('div.wb-dialog.op-dialog', { role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'op-h' }, + el('div.op-head', {}, el('h2#op-h', { text: 'Options' }), el('span.op-sub', { text: 'The fvol command-line options. Saved with this analysis.' })), + body, errBox, el('div.dl-actions', {}, cancel, save)); + const close = () => { scrim.remove(); box.remove(); removeEventListener('keydown', onKey, true); }; + const onKey = e => { if (e.key === 'Escape') { e.preventDefault(); close(); } }; + cancel.addEventListener('click', close); + scrim.addEventListener('click', close); + save.addEventListener('click', async () => { + const out = {}; + for (const { o, on, input } of rows) { + if (!on.checked) { out[o.key] = o.kind === 'flag' ? false : o.kind === 'number' ? 0 : null; continue; } + if (o.kind === 'flag') out[o.key] = true; + else if (o.kind === 'number') out[o.key] = Math.max(o.min, Math.min(o.max, Number(input.value) || 1)); + else if (o.kind === 'list') out[o.key] = input.value.split(o.sep === ';' ? ';' : /\s+/).map(x => x.trim()).filter(Boolean); + else if (o.kind === 'lines') out[o.key] = input.value.split('\n').map(x => x.trim()).filter(Boolean); + else out[o.key] = input.value.trim() || null; + } + save.disabled = true; + errBox.textContent = ''; + try { + const r = await api('options', { method: 'POST', body: out }); + close(); + toast(r.reopened ? 'Options saved: reopening the image with them' : 'Options saved'); + } catch (e) { errBox.textContent = e.message; } + save.disabled = false; + }); + addEventListener('keydown', onKey, true); + document.body.append(scrim, box); + save.focus(); +} diff --git a/src/web/assets/palette.js b/src/web/assets/palette.js deleted file mode 100644 index 6c71815..0000000 --- a/src/web/assets/palette.js +++ /dev/null @@ -1,398 +0,0 @@ -// Command palette (Ctrl+K): fuzzy search over every plugin, with the plugin's options as an -// auto-generated form (python int(x, 0) validation, PID pickers that know the process list). - -import { store, el, clear, int0, modal, runPlugin, emit, shortName, pluginOs, sessionRuns, fmtCount, toast, fmtMs, expectedDuration } from './core.js'; -import { category, blurb } from './catalog.js'; - -let open = null; - -function score(p, tokens) { - if (!tokens.length) return 1; - const name = p.name.toLowerCase(); - const short = shortName(p.name).toLowerCase(); - const desc = (p.description + ' ' + blurb(p.name)).toLowerCase(); - let s = 0; - for (const t of tokens) { - const i = short.indexOf(t); - if (i >= 0) { s += 120 - Math.min(i, 40) + (i === 0 || short[i - 1] === '.' ? 40 : 0); continue; } - if (name.includes(t)) { s += 60; continue; } - if (subseq(short, t)) { s += 35; continue; } - if (desc.includes(t)) { s += 12; continue; } - return 0; - } - return s; -} - -function subseq(h, n) { - let j = 0; - for (let i = 0; i < h.length && j < n.length; i++) if (h[i] === n[j]) j++; - return j === n.length && n.length > 2; -} - -function highlight(text, tokens) { - const frag = []; - const low = text.toLowerCase(); - let i = 0; - const marks = new Array(text.length).fill(false); - for (const t of tokens) { - const k = low.indexOf(t); - if (k >= 0) for (let j = k; j < k + t.length; j++) marks[j] = true; - } - while (i < text.length) { - let j = i; - while (j < text.length && marks[j] === marks[i]) j++; - frag.push(marks[i] ? el('mark', { text: text.slice(i, j) }) : text.slice(i, j)); - i = j; - } - return frag; -} - -/** Open the palette. opts: {query, plugin, args} to preselect a plugin and prefill options. */ -export function openPalette(opts = {}) { - if (open) { open.input.focus(); return; } - const os = store.session && store.session.os; - let osFilter = os || 'all'; - let items = []; - let sel = 0; - let current = null; // selected plugin - let form = null; // form controller - - const input = el('input', { type: 'text', placeholder: opts.pidFor ? `Plugins that take a PID — prefilled with ${opts.pidFor}` : 'Search ' + store.plugins.length + ' plugins — name, purpose or keyword', 'aria-label': 'Search plugins', autocomplete: 'off', spellcheck: false, role: 'combobox', 'aria-expanded': 'true', 'aria-controls': 'pal-list', 'aria-autocomplete': 'list' }); - const osBtns = el('div.os', { role: 'group', 'aria-label': 'Operating system' }); - for (const o of ['all', 'windows', 'linux', 'mac', 'generic']) { - const b = el('button', { type: 'button', text: o === 'generic' ? 'other' : o, 'aria-pressed': String(o === osFilter), on: { click: () => { osFilter = o; for (const x of osBtns.children) x.setAttribute('aria-pressed', String(x === b)); refresh(); input.focus(); } } }); - osBtns.append(b); - } - const list = el('div.pal-list#pal-list', { role: 'listbox', 'aria-label': 'Plugins' }); - const detail = el('div.pal-detail', { 'aria-live': 'polite' }); - const foot = el('div.pal-foot', {}, - el('span', {}, el('kbd', { text: '↑↓' }), ' choose'), - el('span', {}, el('kbd', { text: 'Enter' }), ' run / options'), - el('span', {}, el('kbd', { text: 'Tab' }), ' edit options'), - el('span', {}, el('kbd', { text: 'Ctrl Enter' }), ' run'), - el('span.sp'), - el('span', {}, el('kbd', { text: 'Esc' }), ' close')); - const root = el('div.palette', { 'aria-label': 'Run a plugin' }, - el('div.pal-in', {}, el('svg', {}), input, osBtns), list, detail, foot); - root.querySelector('svg').outerHTML = ''; - - function refresh() { - const q = input.value.trim().toLowerCase(); - const tokens = q.split(/\s+/).filter(Boolean); - let ps = store.plugins.filter(p => osFilter === 'all' || pluginOs(p.name) === osFilter); - if (opts.pidFor) ps = ps.filter(p => p.reqs.some(r => /^pids?$/i.test(r.name) && (r.kind === 'list_int' || r.kind === 'int'))); - const scored = ps.map(p => { - let s = score(p, tokens); - if (!s) return null; - if (os && pluginOs(p.name) !== os && pluginOs(p.name) !== 'generic') s -= 60; - if (/deprecated/i.test(p.description)) s -= 25; - return { p, s }; - }).filter(Boolean); - clear(list); - items = []; - if (!tokens.length) { - const groups = new Map(); - for (const { p } of scored) { - const c = category(p.name); - if (!groups.has(c)) groups.set(c, []); - groups.get(c).push(p); - } - const order = ['Processes & threads', 'Malware & injection', 'Network', 'Memory', 'Files', 'Registry', 'Services', 'Credentials', 'Kernel & drivers', 'Timeline', 'System info', 'Other']; - for (const g of order) { - const ps2 = groups.get(g); - if (!ps2) continue; - ps2.sort((a, b) => (/deprecated/i.test(a.description) - /deprecated/i.test(b.description)) || a.name.localeCompare(b.name)); - list.append(el('div.pal-grp', { text: g, role: 'presentation' })); - for (const p of ps2) list.append(item(p, [])); - } - } else { - scored.sort((a, b) => b.s - a.s || a.p.name.localeCompare(b.p.name)); - for (const { p } of scored.slice(0, 80)) list.append(item(p, tokens)); - } - if (!items.length) list.append(el('div.pal-empty', { text: `No plugin matches “${input.value}”.` })); - sel = Math.min(sel, Math.max(0, items.length - 1)); - if (opts.plugin && !current) { - const k = items.findIndex(x => x.p.name === opts.plugin); - if (k >= 0) sel = k; - } - select(sel, false); - } - - function item(p, tokens) { - const idx = items.length; - const runs = sessionRuns().filter(r => r.plugin === p.name); - const last = runs[0]; - const other = os && pluginOs(p.name) !== os && pluginOs(p.name) !== 'generic'; - const node = el('div.pal-item', { role: 'option', id: 'pal-o' + idx, 'aria-selected': 'false', class: 'pal-item' + (other ? ' other-os' : ''), on: { mousedown: e => { e.preventDefault(); select(idx); }, dblclick: () => submit() } }, - el('div.pn', {}, el('span.ns', { text: pluginOs(p.name) === 'generic' ? '' : pluginOs(p.name) + '.' }), ...highlight(shortName(p.name), tokens)), - el('span.pb', { class: 'pb' + (last && last.status === 'done' ? ' ok' : ''), text: last ? (last.status === 'done' ? `✓ ${fmtCount(last.rows)}` : last.status) : '' }), - el('div.pd', { text: blurb(p.name) || p.description.split('\n')[0] || '—' })); - items.push({ p, node }); - return node; - } - - function select(i, scroll = true) { - if (!items.length) { current = null; clear(detail); return; } - sel = (i + items.length) % items.length; - for (const [k, it] of items.entries()) it.node.setAttribute('aria-selected', String(k === sel)); - const it = items[sel]; - input.setAttribute('aria-activedescendant', it.node.id); - if (scroll) it.node.scrollIntoView({ block: 'nearest' }); - if (current !== it.p) { - current = it.p; - renderDetail(it.p); - } - } - - function renderDetail(p) { - clear(detail); - const b = blurb(p.name); - detail.append(...[ - el('h3', { text: shortName(p.name) }), - el('div.full', { text: p.name }), - b ? el('p.blurb', { text: b }) : null, - p.description ? el('p.desc', { text: p.description + (p.epilog ? '\n\n' + p.epilog : '') }) : null].filter(Boolean)); - const exp = expectedDuration(p.name); - let pre = opts.plugin === p.name ? opts.args || {} : {}; - if (opts.pidFor) { - const r = p.reqs.find(x => /^pids?$/i.test(x.name)); - if (r) pre = { [r.name]: r.kind === 'list_int' ? [String(opts.pidFor)] : String(opts.pidFor) }; - } - form = buildForm(p, pre); - detail.append(form.node); - const runBtn = el('button.btn.primary', { type: 'button', on: { click: () => submit() } }, 'Run', el('kbd', { text: 'Ctrl ↵' })); - detail.append(el('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', marginTop: '14px' } }, runBtn, - exp ? el('span.muted', { text: `took ${fmtMs(exp)} last time` }) : null)); - detail.append(form.cmd); - const prev = sessionRuns().filter(r => r.plugin === p.name).slice(0, 5); - if (prev.length) { - detail.append(el('div.label', { text: 'Earlier runs', style: { marginTop: '16px', marginBottom: '4px' } })); - for (const r of prev) { - detail.append(el('button.chip', { type: 'button', style: { marginRight: '4px' }, on: { click: () => { close(); emit('nav', { kind: 'run', id: r.id }); } } }, - `#${r.id} ${r.args.join(' ') || 'defaults'} · ${r.status === 'done' ? fmtCount(r.rows) + ' rows' : r.status}`)); - } - } - } - - async function submit() { - if (!current) return; - const vals = form.values(); - if (!vals) { form.focusFirstError(); return; } - try { - const run = await runPlugin(current.name, vals, { origin: 'user' }); - close(); - emit('nav', { kind: 'run', id: run.id }); - } catch (e) { - form.showError(e.message); - } - } - - input.addEventListener('input', () => { sel = 0; current = null; refresh(); }); - input.addEventListener('keydown', e => { - if (e.key === 'ArrowDown') { e.preventDefault(); select(sel + 1); } - else if (e.key === 'ArrowUp') { e.preventDefault(); select(sel - 1); } - else if (e.key === 'PageDown') { e.preventDefault(); select(Math.min(items.length - 1, sel + 10)); } - else if (e.key === 'PageUp') { e.preventDefault(); select(Math.max(0, sel - 10)); } - else if (e.key === 'Enter') { - e.preventDefault(); - if (!current) return; - if (e.ctrlKey || e.metaKey || !form.needsInput()) submit(); - else { root.classList.add('form-mode'); form.focus(); } - } else if (e.key === 'Tab' && !e.shiftKey && current && form.hasFields()) { - e.preventDefault(); - root.classList.add('form-mode'); - form.focus(); - } - }); - root.addEventListener('keydown', e => { - if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); submit(); } - }); - - const m = modal(root, { onClose: () => { open = null; } }); - const close = m.close; - open = { input, close }; - input.value = opts.query || ''; - refresh(); - input.focus(); - if (opts.plugin && opts.focusForm) setTimeout(() => form && form.focus(), 0); -} - -/** Build the options form for a plugin. */ -export function buildForm(p, prefill = {}) { - const node = el('div.form'); - const fields = []; - const err = el('div.fld', {}, el('div.err', { role: 'alert' })); - const cmd = el('div.cmdline', { title: 'The equivalent command line' }); - const img = store.session && store.session.image ? store.session.image : 'IMAGE'; - - function update() { - const parts = ['fvol', '-f', quote(img)]; - if (store.session && store.session.symbol_dirs.length) parts.push('-s', quote(store.session.symbol_dirs.join(';'))); - parts.push(p.name); - for (const f of fields) parts.push(...f.argv()); - clear(cmd); - cmd.append(el('b', { text: '$ ' }), parts.join(' ')); - } - - for (const r of p.reqs) { - const f = field(r, prefill[r.name], update); - fields.push(f); - node.append(f.node); - } - if (!p.reqs.length) node.append(el('p.muted', { text: 'This plugin has no options.', style: { margin: 0, fontSize: '12px' } })); - node.append(err); - update(); - return { - node, cmd, - hasFields: () => fields.some(f => !f.disabled), - needsInput: () => fields.some(f => f.required && f.empty()), - focus: () => { const f = fields.find(x => x.required && x.empty()) || fields.find(x => !x.disabled); if (f) f.focus(); }, - focusFirstError: () => { const f = fields.find(x => x.error()); if (f) f.focus(); }, - showError: m => { err.firstChild.textContent = m; }, - values: () => { - const out = {}; - let ok = true; - for (const f of fields) { - const e = f.validate(); - if (e) ok = false; - const v = f.value(); - if (v !== undefined) out[f.name] = v; - } - if (!ok) { err.firstChild.textContent = 'Fix the highlighted options.'; return null; } - err.firstChild.textContent = ''; - return out; - }, - }; -} - -function quote(s) { return /^[\w./:=,@%+-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`; } - -function field(r, pre, onChange) { - const id = 'f-' + r.name + '-' + Math.random().toString(36).slice(2, 7); - const required = !r.optional && r.default === null; - const label = el('label', { for: id }, el('code', { text: r.flag }), required ? el('span.req', { text: 'REQUIRED' }) : null); - const help = el('div.help', { text: r.description + (r.default !== null && r.default !== false && !(Array.isArray(r.default) && !r.default.length) ? ` (default: ${JSON.stringify(r.default)})` : '') }); - const errEl = el('div.err', { role: 'alert' }); - const f = { name: r.name, required, disabled: false, node: null, _err: '' }; - let get, empty, focus, argv; - const setErr = m => { f._err = m || ''; errEl.textContent = f._err; }; - - if (r.kind === 'bool') { - const cb = el('input', { type: 'checkbox', id, checked: pre === true || r.default === true }); - cb.addEventListener('change', onChange); - f.node = el('div.fld', {}, el('label.check', { for: id }, cb, el('code', { text: r.flag, style: { color: 'var(--addr)' } })), help); - get = () => (cb.checked ? true : undefined); - empty = () => !cb.checked; - focus = () => cb.focus(); - argv = () => (cb.checked ? [r.flag] : []); - } else if (r.kind === 'choice') { - const s = el('select.input', { id }); - if (r.optional) s.append(el('option', { value: '', text: r.default ? `(default: ${r.default})` : '—' })); - for (const c of r.choices) s.append(el('option', { value: c, text: c, selected: pre === c })); - s.addEventListener('change', onChange); - f.node = el('div.fld', {}, label, s, help, errEl); - get = () => s.value || undefined; - empty = () => !s.value; - focus = () => s.focus(); - argv = () => (s.value ? [r.flag, s.value] : []); - } else if (r.kind === 'list_int' || r.kind === 'list_str') { - const isPid = /^pids?$/i.test(r.name) || /process id/i.test(r.description); - const tok = tokensInput(id, r.kind === 'list_int', isPid, pre, () => { validate(); onChange(); }); - f.node = el('div.fld', {}, label, tok.node, help, errEl); - get = () => (tok.values().length ? tok.values() : undefined); - empty = () => !tok.values().length; - focus = () => tok.focus(); - argv = () => (tok.values().length ? [r.flag, ...tok.values().map(v => String(r.kind === 'list_int' ? (int0(v) ?? v) : quote(v)))] : []); - f.validate0 = () => { - if (r.kind !== 'list_int') return ''; - const bad = tok.values().filter(v => int0(v) === null); - return bad.length ? `invalid int value: '${bad[0]}' (python int(x, 0): 42, 0x2a, 0o52, 0b101010)` : ''; - }; - } else { - const inp = el('input.input', { id, type: 'text', value: pre ?? '', spellcheck: false, autocomplete: 'off', placeholder: r.kind === 'int' ? 'e.g. 1234 or 0x4d2' : r.kind === 'uri' ? 'path or file:// URL' : '' }); - if (r.kind === 'bytes') { inp.disabled = true; inp.placeholder = 'not settable (volatility3 rejects bytes options on the command line too)'; f.disabled = true; } - inp.addEventListener('input', () => { validate(); onChange(); }); - f.node = el('div.fld', {}, label, inp, help, errEl); - get = () => (inp.value.trim() ? inp.value.trim() : undefined); - empty = () => !inp.value.trim(); - focus = () => inp.focus(); - argv = () => (inp.value.trim() ? [r.flag, r.kind === 'int' ? String(int0(inp.value) ?? inp.value) : quote(inp.value.trim())] : []); - f.validate0 = () => (r.kind === 'int' && inp.value.trim() && int0(inp.value) === null ? `invalid int value: '${inp.value.trim()}' (python int(x, 0): 42, 0x2a, 0o52, 0b101010)` : ''); - f.input = inp; - } - function validate() { - let m = f.validate0 ? f.validate0() : ''; - setErr(m); - if (f.input) f.input.classList.toggle('invalid', !!m); - return m; - } - Object.assign(f, { - value: get, empty, focus, argv, - error: () => f._err, - validate: () => { - const m = validate(); - if (m) return m; - if (required && empty()) { setErr('required'); return 'required'; } - return ''; - }, - }); - return f; -} - -/** Chips input; for PIDs suggests processes from the process list. */ -function tokensInput(id, ints, pidPicker, pre, onChange) { - const vals = Array.isArray(pre) ? pre.map(String) : pre !== undefined && pre !== null ? [String(pre)] : []; - const wrap = el('div.tokens'); - const inp = el('input', { id, type: 'text', autocomplete: 'off', spellcheck: false, placeholder: pidPicker ? 'PID or process name…' : ints ? 'numbers, space separated' : 'values, space separated' }); - const box = el('div.suggest', {}, wrap); - let sugg = null, sidx = 0, matches = []; - function render() { - for (const c of [...wrap.querySelectorAll('.chip')]) c.remove(); - for (const [i, v] of vals.entries()) { - const p = pidPicker && store.procs ? store.procs.find(x => String(x.pid) === String(int0(v) ?? v)) : null; - wrap.insertBefore(el('span.chip', { style: ints && int0(v) === null ? { borderColor: 'var(--bad)', color: 'var(--bad)' } : {} }, - v, p ? el('span.muted', { text: p.name }) : null, - el('button', { type: 'button', 'aria-label': 'Remove ' + v, text: '×', on: { click: () => { vals.splice(i, 1); render(); onChange(); } } })), inp); - } - } - function add(text) { - for (const t of text.split(/[\s,]+/).filter(Boolean)) vals.push(t); - inp.value = ''; - render(); hide(); onChange(); - } - function hide() { if (sugg) { sugg.remove(); sugg = null; } } - function suggest() { - hide(); - if (!pidPicker || !store.procs || !store.procs.length) return; - const q = inp.value.trim().toLowerCase(); - matches = store.procs.filter(p => !q || String(p.pid).startsWith(q) || p.name.toLowerCase().includes(q)).slice(0, 50); - if (!matches.length) return; - sidx = 0; - sugg = el('div.suggest-list', { role: 'listbox' }); - matches.forEach((p, i) => sugg.append(el('div', { role: 'option', 'aria-selected': String(i === 0), on: { mousedown: e => { e.preventDefault(); add(String(p.pid)); inp.focus(); } } }, - el('span', { text: String(p.pid) }), el('span', { text: p.name }), el('span.sp', { text: p.ppid !== undefined ? 'ppid ' + p.ppid : '' })))); - box.append(sugg); - } - inp.addEventListener('input', () => { if (/[\s,]$/.test(inp.value)) add(inp.value); else suggest(); }); - inp.addEventListener('focus', suggest); - inp.addEventListener('blur', () => { setTimeout(hide, 100); if (inp.value.trim()) add(inp.value); }); - inp.addEventListener('keydown', e => { - if (sugg && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) { - e.preventDefault(); - sidx = (sidx + (e.key === 'ArrowDown' ? 1 : -1) + matches.length) % matches.length; - [...sugg.children].forEach((c, i) => c.setAttribute('aria-selected', String(i === sidx))); - sugg.children[sidx].scrollIntoView({ block: 'nearest' }); - } else if (e.key === 'Enter' && !e.ctrlKey && !e.metaKey) { - if (sugg && matches[sidx] && !/^\d+$/.test(inp.value.trim()) && inp.value.trim()) { e.preventDefault(); add(String(matches[sidx].pid)); } - else if (inp.value.trim()) { e.preventDefault(); add(inp.value); } - } else if (e.key === 'Backspace' && !inp.value && vals.length) { vals.pop(); render(); onChange(); } - else if (e.key === 'Escape' && sugg) { e.stopPropagation(); hide(); } - }); - wrap.append(inp); - wrap.addEventListener('mousedown', e => { if (e.target === wrap) { e.preventDefault(); inp.focus(); } }); - render(); - return { node: box, values: () => vals.slice(), focus: () => inp.focus() }; -} - -export function paletteOpen() { return !!open; } -export { toast }; diff --git a/src/web/assets/presets.js b/src/web/assets/presets.js new file mode 100644 index 0000000..69a74a8 --- /dev/null +++ b/src/web/assets/presets.js @@ -0,0 +1,74 @@ +// Presets: named sets of plugins (each with its options) to run together. Built-in ones ship +// with fastvol; the user's own live in ~/.fvol/presets/.json on the server. + +import { api, store } from './core.js'; + +const P = (plugin, args = {}) => ({ plugin, args }); + +// os "any": one preset for every system; "byOs" picks its plugins for the open image's OS +export const BUILTIN = [ + { id: 'builtin:system-info', os: 'any', name: 'System Information', + byOs: { + windows: [P('windows.info.Info'), P('windows.sessions.Sessions'), P('windows.envars.Envars'), P('windows.registry.hivelist.HiveList')], + linux: [P('banners.Banners'), P('linux.boottime.Boottime'), P('linux.ip.Addr'), P('linux.ip.Link'), P('linux.mountinfo.MountInfo'), P('linux.kmsg.Kmsg')], + mac: [P('banners.Banners'), P('mac.ifconfig.Ifconfig'), P('mac.mount.Mount'), P('mac.dmesg.Dmesg')], + } }, + { id: 'builtin:windows-triage', os: 'windows', name: 'Windows Triage', + plugins: [P('windows.pslist.PsList'), P('windows.pstree.PsTree'), P('windows.psscan.PsScan'), P('windows.cmdline.CmdLine'), + P('windows.netscan.NetScan'), P('windows.svcscan.SvcScan'), P('windows.malware.psxview.PsXView'), P('windows.malware.malfind.Malfind'), + P('windows.cmdscan.CmdScan'), P('windows.consoles.Consoles')] }, + { id: 'builtin:windows-malware-persistence', os: 'windows', name: 'Windows Malware and Persistence', + plugins: [P('windows.malware.hollowprocesses.HollowProcesses'), P('windows.malware.ldrmodules.LdrModules'), P('windows.malware.processghosting.ProcessGhosting'), + P('windows.malware.pebmasquerade.PebMasquerade'), P('windows.malware.suspicious_threads.SuspiciousThreads'), + P('windows.malware.drivermodule.DriverModule'), P('windows.malware.svcdiff.SvcDiff'), P('windows.callbacks.Callbacks'), P('windows.ssdt.SSDT'), + P('windows.registry.scheduled_tasks.ScheduledTasks'), P('windows.registry.userassist.UserAssist'), P('windows.shimcachemem.ShimcacheMem'), + P('windows.registry.amcache.Amcache')] }, + { id: 'builtin:linux-triage', os: 'linux', name: 'Linux Triage', + plugins: [P('linux.pslist.PsList'), P('linux.pstree.PsTree'), P('linux.psscan.PsScan'), P('linux.psaux.PsAux'), P('linux.bash.Bash'), + P('linux.envars.Envars'), P('linux.sockstat.Sockstat'), P('linux.lsmod.Lsmod'), P('linux.malware.malfind.Malfind'), + P('linux.malware.check_creds.Check_creds')] }, + { id: 'builtin:linux-rootkit', os: 'linux', name: 'Linux Rootkit Hunt', + plugins: [P('linux.malware.check_syscall.Check_syscall'), P('linux.malware.check_idt.Check_idt'), P('linux.malware.check_afinfo.Check_afinfo'), + P('linux.malware.check_modules.Check_modules'), P('linux.malware.hidden_modules.Hidden_modules'), P('linux.malware.modxview.Modxview'), + P('linux.malware.keyboard_notifiers.Keyboard_notifiers'), P('linux.malware.netfilter.Netfilter'), P('linux.malware.tty_check.Tty_Check'), + P('linux.malware.process_spoofing.ProcessSpoofing'), P('linux.tracing.ftrace.CheckFtrace'), P('linux.tracing.tracepoints.CheckTracepoints'), + P('linux.ebpf.EBPF')] }, + { id: 'builtin:mac-triage', os: 'mac', name: 'macOS Triage', + plugins: [P('mac.pslist.PsList'), P('mac.pstree.PsTree'), P('mac.psaux.Psaux'), P('mac.bash.Bash'), P('mac.netstat.Netstat'), + P('mac.lsof.Lsof'), P('mac.lsmod.Lsmod'), P('mac.malfind.Malfind'), P('mac.check_syscall.Check_syscall'), P('mac.check_sysctl.Check_sysctl'), + P('mac.check_trap_table.Check_trap_table'), P('mac.kauth_listeners.Kauth_listeners'), P('mac.trustedbsd.Trustedbsd'), + P('mac.socket_filters.Socket_filters')] }, +]; + +/** Built-in presets for `os` (all systems when unknown), with the plugins this build has. */ +export function builtinPresets(os) { + const out = []; + for (const p of BUILTIN) { + if (os && p.os !== os && p.os !== 'any') continue; + const plugins = p.byOs ? (os ? p.byOs[os] || [] : []) : p.plugins; + const have = plugins.filter(e => store.pluginMap.has(e.plugin)); + if (have.length) out.push({ ...p, builtin: true, plugins: have }); + } + return out; +} + +// the user's presets, as last listed by the server +export const userPresets = { list: [], errors: [], dir: '', loaded: false, error: null }; + +export async function loadUserPresets() { + try { + const r = await api('presets'); + Object.assign(userPresets, { list: r.presets, errors: r.errors, dir: r.dir, loaded: true, error: null }); + } catch (e) { Object.assign(userPresets, { loaded: true, error: e.message }); } + return userPresets; +} + +/** Save a preset from the current selection (a Map plugin -> options). */ +export function savePreset({ name, os, selection, overwrite = false }) { + const plugins = [...selection].map(([plugin, args]) => ({ plugin, args })); + return api('presets', { method: 'POST', body: { name, os, plugins, overwrite } }); +} + +export function deletePreset(id) { + return api('presets/' + encodeURIComponent(id), { method: 'DELETE' }); +} diff --git a/src/web/assets/procdata.js b/src/web/assets/procdata.js new file mode 100644 index 0000000..8f36178 --- /dev/null +++ b/src/web/assets/procdata.js @@ -0,0 +1,135 @@ +// The process list of the open image, as data: parents, children and "find evil" flags. +// No DOM here; the triage panel and (later) the process tree both read store.procs. + +import { store, emit, runPlugin, whenDone, allRows, cellText, parseTime } from './core.js'; +import { PROCLIST, PCOLS, WIN_PARENTS, WIN_SINGLETONS, SUSPICIOUS_CHILDREN } from './catalog.js'; + +const state = { loadedFor: null, loading: null, byPid: new Map(), t0: null, t1: null }; + +export const firstPlugin = cands => cands.find(n => store.pluginMap.has(n)); + +function col(cols, names) { + for (const n of names) { const i = cols.findIndex(c => c.name === n); if (i >= 0) return i; } + return -1; +} + +/** Capture time of the image: SystemTime from the kernel, else the latest process time seen. */ +export function captureTime() { + const s = store.session; + if (!s) return null; + const f = (s.facts || []).find(([k]) => k === 'SystemTime'); + return f ? parseTime(f[1]) : store.captureGuess || null; +} + +export function relToCapture(t, cap) { + const span = Math.abs(cap - t); + if (span < 1) return 'at capture time'; + const txt = span < 60 ? `${Math.round(span)} s` : span < 3600 ? `${Math.round(span / 60)} min` : span < 172800 ? `${(span / 3600).toFixed(1)} h` : `${Math.round(span / 86400)} days`; + return cap - t > 0 ? `${txt} before capture` : `${txt} after capture`; +} + +/** Load the process list of the current session once (the server keeps the run). */ +export function loadProcesses() { + const s = store.session; + if (!s || s.state !== 'ready' || !s.os) return Promise.resolve(null); + if (state.loadedFor === s.id && state.loading) return state.loading; + state.loadedFor = s.id; + store.procs = null; + store.procError = null; + state.loading = loadFor(s).catch(e => { store.procError = e.message; emit('procs', null); return null; }); + return state.loading; +} + +async function loadFor(s) { + const name = firstPlugin(PROCLIST[s.os] || []); + if (!name) throw new Error('No process list plugin for this OS in this build.'); + const run = await runPlugin(name, {}, { reuse: true, origin: 'spine' }); + store.procRun = run.id; + const done = await whenDone(run.id); + if (done.status !== 'done') throw new Error((done.error && (done.error.title || done.error.message)) || 'The process list failed.'); + const rows = await allRows(run.id); + const ix = Object.fromEntries(Object.entries(PCOLS).map(([k, names]) => [k, col(done.cols, names)])); + const g = (row, k) => (ix[k] >= 0 ? row[ix[k] + 2] : null); + const procs = rows.map((row, i) => ({ + i, pid: Number(cellText(g(row, 'pid'))), ppid: Number(cellText(g(row, 'ppid'))), name: cellText(g(row, 'name')), + create: parseTime(g(row, 'create')), exit: parseTime(g(row, 'exit')), offset: g(row, 'offset'), + threads: g(row, 'threads'), handles: g(row, 'handles'), session: g(row, 'session'), wow64: g(row, 'wow64'), uid: g(row, 'uid'), + row, cols: done.cols, flags: [], kids: [], parent: null, + })); + link(procs); + flag(procs, s.os); + store.procs = procs; + emit('procs', procs); + enrich(s, procs); + return procs; +} + +/** Image paths and command lines from pstree (Windows), filled in the background. */ +function enrich(s, procs) { + const name = s.os === 'windows' && firstPlugin(['windows.pstree.PsTree']); + if (!name) return; + runPlugin(name, {}, { reuse: true, origin: 'spine' }).then(r => whenDone(r.id)).then(async r => { + if (r.status !== 'done' || store.procs !== procs) return; + const rows = await allRows(r.id); + const pi = col(r.cols, ['PID']), path = col(r.cols, ['Path']), cmd = col(r.cols, ['Cmd']); + for (const row of rows) { + const p = state.byPid.get(Number(row[pi + 2])); + if (!p) continue; + if (path >= 0 && typeof row[path + 2] === 'string') p.path = row[path + 2]; + if (cmd >= 0 && typeof row[cmd + 2] === 'string') p.cmd = row[cmd + 2]; + } + emit('procs', procs); + }).catch(() => {}); +} + +function isAncestor(a, b) { for (let x = b, n = 0; x && n < 512; x = x.parent, n++) if (x === a) return true; return false; } + +function link(procs) { + state.byPid = new Map(); + for (const p of procs) if (!state.byPid.has(p.pid) || p.exit === null) state.byPid.set(p.pid, p); + for (const p of procs) { + const par = p.ppid !== 0 || p.pid === 0 ? state.byPid.get(p.ppid) : null; + if (par && par !== p && !isAncestor(p, par)) { p.parent = par; par.kids.push(p); } + } + const times = procs.flatMap(p => [p.create, p.exit]).filter(t => t !== null && t > 0); + const cap = captureTime() || (times.length ? Math.max(...times) : null); + store.captureGuess = cap; + const starts = procs.map(p => p.create).filter(t => t !== null && t > 0); + state.t0 = starts.length ? Math.min(...starts) : null; + state.t1 = cap; +} + +/** "Find evil" hints: recent starts; on Windows also unexpected parents, duplicated + * singletons and shells spawned by services. Heuristics, not verdicts. */ +function flag(procs, os) { + const cap = state.t1, t0 = state.t0; + const uptime = t0 && cap ? cap - t0 : 0; + const recentWin = Math.min(3600, Math.max(60, uptime * 0.1)); + for (const p of procs) { + if (cap && p.create && cap - p.create >= 0 && cap - p.create < recentWin && p.create - t0 > Math.min(300, uptime * 0.3) && p.exit === null) p.flags.push(`started ${relToCapture(p.create, cap)}`); + } + if (os !== 'windows') return; + const lower = n => (n || '').toLowerCase(); + const counts = new Map(); + for (const p of procs) if (p.exit === null) counts.set(lower(p.name), (counts.get(lower(p.name)) || 0) + 1); + for (const p of procs) { + const exp = Object.entries(WIN_PARENTS).find(([k]) => lower(k) === lower(p.name)); + if (exp && p.parent && !exp[1].some(n => lower(n) === lower(p.parent.name))) p.flags.push(`unexpected parent ${p.parent.name} (${p.ppid})`); + if (exp && !p.parent && lower(p.name) === 'svchost.exe') p.flags.push(`parent ${p.ppid} not in the process list`); + if (WIN_SINGLETONS.some(n => lower(n) === lower(p.name)) && counts.get(lower(p.name)) > 1 && p.exit === null) p.flags.push(`${counts.get(lower(p.name))} instances of a normally unique process`); + if (SUSPICIOUS_CHILDREN.test(p.name) && p.parent && !/^(explorer|cmd|powershell|pwsh|conhost|windowsterminal|code)\.exe$/i.test(p.parent.name)) p.flags.push(`${p.name} spawned by ${p.parent.name}`); + } +} + +/** The triage groups shown in the Triage hints panel. */ +export function triageGroups() { + const s = store.session, procs = store.procs || []; + const groups = [ + { key: 'look', title: 'Processes worth a look', sub: s.os === 'windows' ? 'Unexpected parents, duplicated singletons, shells spawned by services.' : 'Heuristic flags.', hot: true, list: procs.filter(p => p.flags.some(f => !f.startsWith('started'))) }, + { key: 'recent', title: 'Started shortly before capture', sub: 'New processes are where an intrusion is most likely to be visible.', hot: true, list: procs.filter(p => p.flags.some(f => f.startsWith('started'))) }, + ]; + // smss.exe and userinit.exe exit by design, so their children are expected orphans + if (s.os === 'windows') groups.push({ key: 'orphan', title: 'Parent not in the process list', sub: 'Normal for some (parent exited), odd for others.', list: procs.filter(p => !p.parent && p.ppid !== 0 && !/^(System|smss\.exe|Registry|MemCompression|csrss\.exe|wininit\.exe|winlogon\.exe|explorer\.exe)$/i.test(p.name)) }); + groups.push({ key: 'exited', title: 'Exited but still listed', sub: 'Terminated processes whose objects are still in memory.', list: procs.filter(p => p.exit !== null) }); + return groups; +} diff --git a/src/web/assets/procs.js b/src/web/assets/procs.js deleted file mode 100644 index 53fd519..0000000 --- a/src/web/assets/procs.js +++ /dev/null @@ -1,515 +0,0 @@ -// The process spine: an interactive process tree (with lifelines on the capture's time axis -// and "find evil" hints) and the per-process view that pivots every relevant plugin to one PID. - -import { store, on, emit, el, clear, runPlugin, whenDone, allRows, cellText, parseTime, fmtTime, fmtCount, copy, shortName, prefs } from './core.js'; -import { PROCLIST, PCOLS, PIVOTS, CMDLINE, WIN_PARENTS, WIN_SINGLETONS, SUSPICIOUS_CHILDREN, blurb } from './catalog.js'; -import { ResultPanel, captureTime, relToCapture, hexTarget } from './result.js'; - - -const tree = { nodes: [], byPid: new Map(), roots: [], expanded: new Set(), cursor: 0, flat: [], filter: '', selected: null, loadedFor: null }; - -function pick(cols, names) { - for (const n of names) { const i = cols.findIndex(c => c.name === n); if (i >= 0) return i; } - return -1; -} - -export function plugin(name) { return store.pluginMap.get(name); } -export function firstPlugin(cands) { return cands.find(n => store.pluginMap.has(n)); } - -/** Load the process list for the current session (runs pslist once, cached server-side). */ -export function loadProcs() { - const s = store.session; - if (!s || s.state !== 'ready' || !s.os) return Promise.resolve(); - if (tree.loadedFor === s.id && tree.loading) return tree.loading; - tree.loadedFor = s.id; - tree.loading = loadProcsFor(s); - return tree.loading; -} - -async function loadProcsFor(s) { - const name = firstPlugin(PROCLIST[s.os] || []); - const treeEl = document.getElementById('tree'); - if (!name) { treeEl.replaceChildren(el('div.tree-empty', { text: 'No process list plugin for this OS in this build.' })); return; } - treeEl.replaceChildren(el('div.tree-empty', {}, el('span.spinner', { style: { display: 'inline-block', verticalAlign: '-3px', marginRight: '8px' } }), 'Walking the process list…')); - let run; - try { - run = await runPlugin(name, {}, { reuse: true, origin: 'spine' }); - } catch (e) { - treeEl.replaceChildren(el('div.tree-empty', { text: 'Could not list processes: ' + e.message })); - return; - } - store.procRun = run.id; - const done = await whenDone(run.id); - if (done.status !== 'done') { - treeEl.replaceChildren(el('div.tree-empty', {}, el('b', { text: (done.error && done.error.title) || 'The process list failed.' }), el('br'), done.error ? done.error.message : '')); - return; - } - const rows = await allRows(run.id); - const cols = done.cols; - const ix = Object.fromEntries(Object.entries(PCOLS).map(([k, names]) => [k, pick(cols, names)])); - const g = (row, k) => (ix[k] >= 0 ? row[ix[k] + 2] : null); - const procs = rows.map((row, i) => { - const pid = Number(cellText(g(row, 'pid'))); - const create = parseTime(g(row, 'create')); - const exit = parseTime(g(row, 'exit')); - return { - i, pid, ppid: Number(cellText(g(row, 'ppid'))), name: cellText(g(row, 'name')), - create, exit, offset: g(row, 'offset'), threads: g(row, 'threads'), handles: g(row, 'handles'), - session: g(row, 'session'), wow64: g(row, 'wow64'), uid: g(row, 'uid'), row, cols, flags: [], - }; - }); - store.procs = procs; - build(procs); - emit('procs', procs); - // enrich with image paths / command lines from pstree (windows) in the background - const pst = s.os === 'windows' && firstPlugin(['windows.pstree.PsTree']); - if (pst) { - runPlugin(pst, {}, { reuse: true, origin: 'spine' }).then(r => whenDone(r.id)).then(async r => { - if (r.status !== 'done') return; - const prow = await allRows(r.id); - const pi = pick(r.cols, ['PID']), path = pick(r.cols, ['Path']), cmd = pick(r.cols, ['Cmd']); - for (const row of prow) { - const p = tree.byPid.get(Number(row[pi + 2])); - if (!p) continue; - if (path >= 0 && typeof row[path + 2] === 'string') p.path = row[path + 2]; - if (cmd >= 0 && typeof row[cmd + 2] === 'string') p.cmd = row[cmd + 2]; - } - emit('procs', procs); - }).catch(() => {}); - } -} - -function build(procs) { - tree.byPid = new Map(); - for (const p of procs) if (!tree.byPid.has(p.pid) || (p.exit === null)) tree.byPid.set(p.pid, p); - for (const p of procs) { p.kids = []; p.parent = null; } - for (const p of procs) { - const par = p.ppid !== 0 || p.pid === 0 ? tree.byPid.get(p.ppid) : null; - if (par && par !== p && !isAncestor(p, par)) { p.parent = par; par.kids.push(p); } - } - for (const p of procs) p.kids.sort((a, b) => (a.create ?? 0) - (b.create ?? 0) || a.pid - b.pid); - tree.roots = procs.filter(p => !p.parent).sort((a, b) => (a.create ?? 0) - (b.create ?? 0) || a.pid - b.pid); - // time axis: first process creation .. capture time - const times = procs.flatMap(p => [p.create, p.exit]).filter(t => t !== null && t > 0); - const cap = captureTime() || (times.length ? Math.max(...times) : null); - store.captureGuess = cap; - const starts = procs.map(p => p.create).filter(t => t !== null && t > 0); - tree.t0 = starts.length ? Math.min(...starts) : null; - tree.t1 = cap; - triage(procs); - const saved = prefs.get('expanded:' + (store.session && store.session.image), null); - tree.expanded = new Set(saved || procs.filter(p => p.kids.length && depth(p) < 2).map(p => p.i)); - if (!saved) for (const p of procs) if (p.flags.length) for (let a = p.parent; a; a = a.parent) tree.expanded.add(a.i); - document.getElementById('proc-count').textContent = fmtCount(procs.length); - renderAxis(); - renderTree(); -} - -function isAncestor(a, b) { for (let x = b, n = 0; x && n < 512; x = x.parent, n++) if (x === a) return true; return false; } -function depth(p) { let d = 0; for (let x = p.parent; x && d < 512; x = x.parent) d++; return d; } - -/** "Find evil" hints (Windows): unexpected parents, duplicated singletons, shells spawned by services, recent starts. */ -function triage(procs) { - const s = store.session; - const cap = tree.t1; - const uptime = tree.t0 && cap ? cap - tree.t0 : 0; - const recentWin = Math.min(3600, Math.max(60, uptime * 0.1)); - for (const p of procs) { - p.flags = []; - if (cap && p.create && cap - p.create >= 0 && cap - p.create < recentWin && p.create - tree.t0 > Math.min(300, uptime * 0.3) && p.exit === null) p.flags.push(`started ${relToCapture(p.create, cap)}`); - } - if (s.os !== 'windows') return; - const lower = n => (n || '').toLowerCase(); - const counts = new Map(); - for (const p of procs) if (p.exit === null) counts.set(lower(p.name), (counts.get(lower(p.name)) || 0) + 1); - for (const p of procs) { - const exp = Object.entries(WIN_PARENTS).find(([k]) => lower(k) === lower(p.name)); - if (exp && p.parent && !exp[1].some(n => lower(n) === lower(p.parent.name))) p.flags.push(`unexpected parent ${p.parent.name} (${p.ppid})`); - if (exp && !p.parent && lower(p.name) === 'svchost.exe') p.flags.push(`parent ${p.ppid} not in the process list`); - if (WIN_SINGLETONS.some(n => lower(n) === lower(p.name)) && counts.get(lower(p.name)) > 1 && p.exit === null) p.flags.push(`${counts.get(lower(p.name))} instances of a normally unique process`); - if (SUSPICIOUS_CHILDREN.test(p.name) && p.parent && !/^(explorer|cmd|powershell|pwsh|conhost|windowsterminal|code)\.exe$/i.test(p.parent.name)) p.flags.push(`${p.name} spawned by ${p.parent.name}`); - } -} - -// ------------------------------------------------------------------ rendering -/** Position of time t on the lifeline axis: log scale of "time before capture", so boot-time - * processes share the left edge and the minutes before capture get most of the width. */ -export function lifePos(t) { - if (tree.t0 === null || tree.t1 === null || t === null) return null; - const up = Math.max(2, tree.t1 - tree.t0); - const before = Math.max(0, tree.t1 - t); - return Math.max(0, Math.min(1, 1 - Math.log1p(before) / Math.log1p(up))); -} - -function lifeBar(p) { - const bar = el('span.life', { 'aria-hidden': 'true' }); - if (tree.t0 === null || tree.t1 === null || p.create === null || p.create <= 0) return bar; - const a = lifePos(p.create); - const b = lifePos(p.exit ?? tree.t1); - const i = el('i', { class: p.exit !== null ? 'dead' : p.flags.some(f => f.startsWith('started')) ? 'recent' : '' }); - i.style.left = (a * 100).toFixed(2) + '%'; - i.style.width = Math.max(0, (b - a) * 100).toFixed(2) + '%'; - bar.append(i); - return bar; -} - -function renderAxis() { - const ax = document.getElementById('lifeaxis'); - clear(ax); - if (tree.t0 === null || tree.t1 === null) return; - // ticks over the 58px lifeline column at the right edge of the tree - const up = tree.t1 - tree.t0; - const ticks = [[tree.t0, 'boot']]; - for (const [s, l] of [[86400, '-1d'], [3600, '-1h'], [600, '-10m'], [60, '-1m']]) if (s < up * 0.7) ticks.push([tree.t1 - s, l]); - const track = el('span.ticks'); - for (const [t, l] of ticks) { - const x = lifePos(t); - const s = el('span', { text: l }); - s.style.left = `calc(${(x * 100).toFixed(1)}% - ${l === 'boot' ? 0 : 8}px)`; - track.append(s); - } - ax.append(track); - ax.title = `Process lifelines, log scale: boot ${fmtTime(tree.t0)} → capture ${fmtTime(tree.t1)} UTC (${Math.round(up / 60)} min uptime)`; -} - -function matches(p, q) { - return String(p.pid) === q || String(p.pid).startsWith(q) || p.name.toLowerCase().includes(q) || (p.path || '').toLowerCase().includes(q); -} - -export function renderTree() { - const treeEl = document.getElementById('tree'); - const q = tree.filter.trim().toLowerCase(); - const show = new Set(); - if (q) { - for (const p of store.procs || []) if (matches(p, q)) for (let x = p; x; x = x.parent) show.add(x); - } - tree.flat = []; - const walk = (p, lvl) => { - if (q && !show.has(p)) return; - tree.flat.push({ p, lvl }); - if (p.kids.length && (q || tree.expanded.has(p.i))) for (const k of p.kids) walk(k, lvl + 1); - }; - for (const r of tree.roots) walk(r, 0); - const frag = document.createDocumentFragment(); - tree.flat.forEach(({ p, lvl }, k) => { - const open = q ? true : tree.expanded.has(p.i); - const isMatch = q && matches(p, q); - const node = el('div.tnode', { - role: 'treeitem', 'aria-level': lvl + 1, 'aria-expanded': p.kids.length ? String(open) : undefined, - 'aria-selected': String(tree.selected === p.pid), id: 'tn-' + k, - class: 'tnode' + (p.exit !== null ? ' exited' : '') + (p.flags.length > (p.flags.some(f => f.startsWith('started')) ? 1 : 0) ? ' flag' : '') + (q && !isMatch ? ' ctx' : '') + (k === tree.cursor ? ' cursor' : ''), - title: `${p.name} (PID ${p.pid}, PPID ${p.ppid})${p.create ? '\nstarted ' + fmtTime(p.create) : ''}${p.exit !== null ? '\nexited ' + fmtTime(p.exit) : ''}${p.path ? '\n' + p.path : ''}${p.flags.length ? '\n⚑ ' + p.flags.join('\n⚑ ') : ''}`, - dataset: { k }, - }, - el('span.tl', {}, el('span.tw', { text: p.kids.length ? (open ? '▾' : '▸') : '' }), el('span.nm', { text: p.name || '(no name)' }), el('span.pid', { text: String(p.pid) })), - lifeBar(p)); - node.style.setProperty('--lvl', lvl); - frag.append(node); - }); - treeEl.replaceChildren(frag); - if (!tree.flat.length) treeEl.append(el('div.tree-empty', { text: q ? `No process matches “${tree.filter}”.` : 'No processes.' })); - if (tree.flat[tree.cursor]) treeEl.setAttribute('aria-activedescendant', 'tn-' + tree.cursor); -} - -function moveCursor(k, scroll = true) { - if (!tree.flat.length) return; - tree.cursor = Math.max(0, Math.min(tree.flat.length - 1, k)); - const treeEl = document.getElementById('tree'); - for (const n of treeEl.querySelectorAll('.tnode.cursor')) n.classList.remove('cursor'); - const n = treeEl.querySelector(`[data-k="${tree.cursor}"]`); - if (n) { n.classList.add('cursor'); if (scroll) n.scrollIntoView({ block: 'nearest' }); } - treeEl.setAttribute('aria-activedescendant', 'tn-' + tree.cursor); -} - -export function selectPid(pid, reveal = true) { - tree.selected = pid; - const p = tree.byPid.get(pid); - if (p && reveal) { - for (let a = p.parent; a; a = a.parent) tree.expanded.add(a.i); - renderTree(); - const k = tree.flat.findIndex(x => x.p === p); - if (k >= 0) moveCursor(k); - } else { - renderTree(); - } -} - -function saveExpanded() { prefs.set('expanded:' + (store.session && store.session.image), [...tree.expanded]); } - -export function initTree() { - const treeEl = document.getElementById('tree'); - const filter = document.getElementById('proc-filter'); - filter.addEventListener('input', () => { tree.filter = filter.value; tree.cursor = 0; renderTree(); }); - filter.addEventListener('keydown', e => { - if (e.key === 'ArrowDown' || e.key === 'Enter') { e.preventDefault(); treeEl.focus(); moveCursor(tree.cursor); if (e.key === 'Enter' && tree.flat[tree.cursor]) emit('nav', { kind: 'proc', pid: tree.flat[tree.cursor].p.pid }); } - if (e.key === 'Escape') { filter.value = ''; tree.filter = ''; renderTree(); treeEl.focus(); e.stopPropagation(); } - }); - treeEl.addEventListener('click', e => { - const n = e.target.closest('.tnode'); - if (!n) return; - const k = +n.dataset.k; - const { p } = tree.flat[k]; - tree.cursor = k; - if (e.target.closest('.tw') && p.kids.length) { toggle(p); return; } - emit('nav', { kind: 'proc', pid: p.pid }); - }); - let typeBuf = '', typeT = 0; - treeEl.addEventListener('keydown', e => { - const cur = tree.flat[tree.cursor]; - const p = cur && cur.p; - switch (e.key) { - case 'ArrowDown': moveCursor(tree.cursor + 1); break; - case 'ArrowUp': moveCursor(tree.cursor - 1); break; - case 'PageDown': moveCursor(tree.cursor + 15); break; - case 'PageUp': moveCursor(tree.cursor - 15); break; - case 'Home': moveCursor(0); break; - case 'End': moveCursor(tree.flat.length - 1); break; - case 'ArrowRight': - if (!p) break; - if (p.kids.length && !tree.expanded.has(p.i) && !tree.filter) toggle(p); - else moveCursor(tree.cursor + 1); - break; - case 'ArrowLeft': - if (!p) break; - if (p.kids.length && tree.expanded.has(p.i) && !tree.filter) toggle(p); - else if (p.parent) { const k = tree.flat.findIndex(x => x.p === p.parent); if (k >= 0) moveCursor(k); } - break; - case 'Enter': case ' ': if (p) emit('nav', { kind: 'proc', pid: p.pid }); break; - case '*': expandAll(true); break; - default: - if (e.key.length === 1 && /\S/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) { - const now = Date.now(); - typeBuf = now - typeT > 700 ? e.key.toLowerCase() : typeBuf + e.key.toLowerCase(); - typeT = now; - const n = tree.flat.length; - for (let j = 1; j <= n; j++) { - const k = (tree.cursor + (typeBuf.length > 1 ? 0 : j)) % n; - if (tree.flat[k].p.name.toLowerCase().startsWith(typeBuf) || String(tree.flat[k].p.pid).startsWith(typeBuf)) { moveCursor(k); break; } - } - break; - } - return; - } - e.preventDefault(); - }); - treeEl.addEventListener('focus', () => moveCursor(tree.cursor, false)); - document.getElementById('tree-expand').addEventListener('click', () => expandAll(true)); - document.getElementById('tree-collapse').addEventListener('click', () => expandAll(false)); -} - -function toggle(p) { - if (tree.expanded.has(p.i)) tree.expanded.delete(p.i); else tree.expanded.add(p.i); - saveExpanded(); - const k = tree.cursor; - renderTree(); - moveCursor(k, false); -} - -function expandAll(open) { - tree.expanded = open ? new Set((store.procs || []).filter(p => p.kids.length).map(p => p.i)) : new Set(); - saveExpanded(); - renderTree(); -} - -export function resetTree() { - tree.loadedFor = null; - tree.loading = null; - tree.selected = null; - store.procs = null; - document.getElementById('proc-count').textContent = ''; - clear(document.getElementById('lifeaxis')); -} - -export function procByPid(pid) { return tree.byPid.get(pid); } -export function treeTimes() { return { t0: tree.t0, t1: tree.t1 }; } - -// ------------------------------------------------------------------ process view -export class ProcessTab { - constructor(pid) { - this.pid = pid; - this.pane = el('div.pane'); - this.head = el('div.pv-head'); - this.sub = el('div.subtabs', { role: 'tablist', 'aria-label': 'Process details' }); - this.subpanes = el('div.subpanes'); - this.pane.append(this.head, this.sub, this.subpanes); - this.panels = new Map(); - this.offProcs = on('procs', () => this.renderHead()); - this.renderHead(); - this.buildTabs(); - this.loadCmdline(); - } - - get title() { const p = procByPid(this.pid); return p ? `${p.name}` : `PID ${this.pid}`; } - get subtitle() { return String(this.pid); } - - renderHead() { - const p = procByPid(this.pid); - clear(this.head); - if (!p) { this.head.append(el('div.pv-name', {}, el('h2', { text: `PID ${this.pid}` }), el('span.muted', { text: 'not in the process list (exited or hidden?) — pivots still work' }))); return; } - const par = p.parent; - const facts = el('div.pv-facts'); - const f = (k, v) => { if (v !== null && v !== undefined && v !== '') facts.append(el('span', {}, k + ' ', v instanceof Node ? v : el('b', { text: String(cellText(v)) }))); }; - f('PPID', par ? el('button.linkbtn', { type: 'button', text: `${p.ppid} ${par.name}`, on: { click: () => emit('nav', { kind: 'proc', pid: par.pid }) } }) : el('b', { text: `${p.ppid} (not listed)` })); - f('threads', p.threads); - f('handles', p.handles); - f('session', p.session); - f('wow64', p.wow64); - f('uid', p.uid); - if (p.offset && typeof p.offset === 'string') f({ windows: 'EPROCESS', linux: 'task_struct', mac: 'proc' }[store.session.os] || 'object', el('button.linkbtn', { type: 'button', text: p.offset, title: 'View this structure in memory', on: { click: () => emit('nav', { kind: 'hex', layer: 'kernel', addr: p.offset }) } })); - f('started', p.create ? fmtTime(p.create) : null); - if (p.exit !== null) f('exited', fmtTime(p.exit)); - const kids = p.kids.length ? el('span', {}, 'children ', ...p.kids.slice(0, 8).flatMap((k, i) => [i ? ', ' : '', el('button.linkbtn', { type: 'button', text: `${k.name} ${k.pid}`, on: { click: () => emit('nav', { kind: 'proc', pid: k.pid }) } })]), p.kids.length > 8 ? ` +${p.kids.length - 8}` : '') : null; - if (kids) facts.append(kids); - const life = el('div.pv-life', { title: 'Lifetime on a log scale of time before capture' }); - const { t0, t1 } = treeTimes(); - if (t0 !== null && t1 !== null && p.create) { - const a = lifePos(p.create), b = lifePos(p.exit ?? t1); - const sp = el('div.span', { class: 'span' + (p.exit !== null ? ' dead' : '') }); - sp.style.left = (a * 100) + '%'; sp.style.width = Math.max(0.3, (b - a) * 100) + '%'; - life.append(el('div.track'), sp); - const up = t1 - t0; - const ticks = [[t0, 'boot ' + fmtTime(t0).slice(11)]]; - for (const [s, l] of [[86400, '-1d'], [3600, '-1h'], [600, '-10m'], [60, '-1m']]) if (s < up * 0.7) ticks.push([t1 - s, l]); - ticks.push([t1, 'capture ' + fmtTime(t1).slice(11)]); - for (const [t, l] of ticks) { - const x = lifePos(t); - const lab = el('span.lab', { text: l }); - if (x <= 0.02) lab.classList.add('first'); else if (x >= 0.98) lab.classList.add('last'); - lab.style.left = (x * 100) + '%'; - life.append(el('span.tick', { style: { left: (x * 100) + '%' } }), lab); - } - f('age', relToCapture(p.create, t1) + (p.exit !== null ? `, ran ${Math.max(0, Math.round(p.exit - p.create))} s` : '')); - } - this.cmdEl = el('div.pv-cmd', {}, el('span.lbl', { text: 'cmd' }), this.cmd || p.cmd || '…'); - const pathEl = p.path ? el('div.pv-cmd', {}, el('span.lbl', { text: 'path' }), p.path) : null; - const flags = p.flags.length ? el('div.pv-flags', {}, ...p.flags.map(x => el('span.flagchip', { text: '⚑ ' + x }))) : null; - const actions = el('div.rv-actions', {}, - el('button.btn', { type: 'button', title: 'Other plugins that accept --pid, prefilled', on: { click: () => emit('palette', { query: '', pidFor: this.pid }) } }, 'More plugins for this PID…'), - el('button.btn.ghost', { type: 'button', on: { click: () => copy(String(this.pid)) } }, 'Copy PID')); - this.head.append(...[ - el('div.pv-name', {}, el('h2', { text: p.name || '(no name)' }), el('span.pid', {}, 'PID ', el('b', { text: String(p.pid) })), p.exit !== null ? el('span.stamp.cancelled', { text: 'exited' }) : null), - actions, this.cmdEl, pathEl, facts, life, flags].filter(Boolean)); - } - - async loadCmdline() { - const os = store.session && store.session.os; - const c = (CMDLINE[os] || []).find(([n]) => store.pluginMap.has(n)); - if (!c) { this.cmd = '(no command-line plugin for this OS)'; this.renderHead(); return; } - const [name, colName] = c; - try { - const run = await runPlugin(name, pidArgs(name, this.pid), { reuse: true, origin: 'pivot' }); - const r = await whenDone(run.id); - if (r.status !== 'done') { this.cmd = '(unavailable)'; this.renderHead(); return; } - const rows = await allRows(r.id, 50); - const ci = r.cols.findIndex(x => x.name === colName); - const pi = r.cols.findIndex(x => /^(PID|Pid)$/.test(x.name)); - const row = rows.find(x => pi < 0 || Number(x[pi + 2]) === this.pid); - this.cmd = row && ci >= 0 ? cellText(row[ci + 2]) : '(no command line)'; - } catch (e) { this.cmd = '(unavailable)'; } - this.renderHead(); - } - - buildTabs() { - const os = store.session && store.session.os; - const defs = (PIVOTS[os] || []).map(([label, cands]) => ({ label, plugin: firstPlugin(cands) })); - this.defs = defs; - const last = prefs.get('pivot', 'Handles'); - let first = null; - defs.forEach((d, k) => { - const b = el('button.subtab', { role: 'tab', type: 'button', 'aria-selected': 'false', class: 'subtab' + (d.plugin ? '' : ' na'), title: d.plugin ? `${d.plugin}\n${blurb(d.plugin)}` : 'Not available in this build', disabled: !d.plugin, on: { click: () => this.show(k) } }, d.label, el('span.n')); - d.btn = b; - this.sub.append(b); - if (d.plugin && (first === null || d.label === last)) first = k; - }); - this.sub.addEventListener('keydown', e => { - if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return; - const avail = defs.map((d, k) => (d.plugin ? k : -1)).filter(k => k >= 0); - const i = avail.indexOf(this.current); - const n = avail[(i + (e.key === 'ArrowRight' ? 1 : -1) + avail.length) % avail.length]; - this.show(n); - defs[n].btn.focus(); - e.preventDefault(); - }); - if (first !== null) this.show(first); - else this.subpanes.append(el('div.empty-state', {}, el('h2', { text: 'No pivots' }), 'This build has none of the per-process plugins for this OS yet.')); - } - - async show(k) { - const d = this.defs[k]; - if (!d || !d.plugin) return; - this.current = k; - prefs.set('pivot', d.label); - for (const x of this.defs) if (x.btn) x.btn.setAttribute('aria-selected', String(x === d)); - for (const [kk, p] of this.panels) p.node.hidden = kk !== k; - if (this.panels.has(k)) { this.panels.get(k).table.root.focus({ preventScroll: true }); return; } - const holder = { node: el('div.pane') }; - this.panels.set(k, holder); - this.subpanes.append(holder.node); - const wait = el('div.empty-state', {}, el('span.spinner', { style: { display: 'inline-block', verticalAlign: '-3px', marginRight: '8px' } }), `Running ${d.plugin}…`); - holder.node.append(wait); - try { - const args = pidArgs(d.plugin, this.pid); - const byArg = Object.keys(args).length > 0; - const run = await runPlugin(d.plugin, args, { reuse: true, origin: 'pivot' }); - const fixed = {}; - if (!byArg) { - // no --pid option: run once for everything, filter on the PID column - const cols = run.cols && run.cols.length ? run.cols : (await waitCols(run.id)); - const pc = cols.findIndex(c => /^(PID|Pid|Owner PID)$/i.test(c.name)); - if (pc >= 0) fixed[pc] = '=' + this.pid; - } - const panel = new ResultPanel({ - runId: run.id, fixed, label: `${d.label} of PID ${this.pid}`, fixedLabel: byArg ? null : `PID = ${this.pid}`, - onUpdate: r => { d.btn.querySelector('.n').textContent = r.status === 'done' ? (byArg ? fmtCount(r.rows) : '') : r.status === 'failed' ? '!' : '…'; }, - extraBar: [el('button.btn.ghost', { type: 'button', title: 'Open this result in its own tab', on: { click: () => emit('nav', { kind: 'run', id: run.id }) } }, 'Open ↗')], - }); - holder.panel = panel; - holder.table = panel.table; - wait.remove(); - holder.node.append(panel.node); - if (this.current === k) holder.node.hidden = false; - const r = await whenDone(run.id); - if (r.status === 'failed' && r.error) { - holder.node.prepend(errCard(r.error)); - } - } catch (e) { - wait.remove(); - holder.node.append(el('div.errcard', {}, el('h4', { text: 'Could not run ' + d.plugin }), el('p', { text: e.message }))); - } - } - - focus() { - const h = this.panels.get(this.current); - if (h && h.table) h.table.root.focus({ preventScroll: true }); - } - - focusFilter() { const h = this.panels.get(this.current); if (h && h.panel) h.panel.focusFilter(); } - - onShow() { selectPid(this.pid); } - - destroy() { this.offProcs(); for (const h of this.panels.values()) if (h.panel) h.panel.destroy(); } -} - -async function waitCols(id) { - const r = await whenDone(id); - return r.cols || []; -} - -/** Arguments that restrict a plugin to one PID (empty when it has no pid option). */ -export function pidArgs(name, pid) { - const p = store.pluginMap.get(name); - if (!p) return {}; - const r = p.reqs.find(x => /^pids?$/i.test(x.name) && (x.kind === 'list_int' || x.kind === 'int')); - if (!r) return {}; - return { [r.name]: r.kind === 'list_int' ? [pid] : pid }; -} - -export function errCard(e) { - return el('div.errcard', { class: 'errcard' + (e.kind === 'cancelled' ? ' soft' : '') }, - el('h4', { text: e.title }), - e.message ? el('p', { text: e.message }) : null, - e.hints && e.hints.length ? el('ul', {}, ...e.hints.map(h => el('li', { text: h }))) : null, - e.detail ? el('details', {}, el('summary', { text: 'Technical details' }), el('pre', { text: e.detail })) : null); -} - -export { hexTarget }; diff --git a/src/web/assets/quickstart.js b/src/web/assets/quickstart.js new file mode 100644 index 0000000..471a9cd --- /dev/null +++ b/src/web/assets/quickstart.js @@ -0,0 +1,256 @@ +// Quick Start: the launch screen, like a desktop tool's start dialog. Choose to open a memory +// image, to continue with the image the server already has, to work without one ("go"), or to +// reopen a saved analysis. The workspace stays behind it and appears when a choice is made. + +import { store, api, el, clear, prefs, fmtBytes, fmtAgo, debounce } from './core.js'; + +// icons: small inline SVG (not markup from the network, so no CSP concern) +const ICONS = { + open: '', + cont: '', + prev: '', + dir: '', + file: '', + chip: '', + up: '', +}; + +function icon(name, cls) { + const t = document.createElement('template'); + t.innerHTML = ``; + return t.content.firstChild; +} + +// what a memory image looks like in a directory listing: a known extension, or simply big +const IMAGE_EXT = /\.(raw|mem|vmem|vmss|vmsn|lime|dmp|img|bin|elf|core|dump|avml|sav|qcow2?|gz|xz|bz2)$/i; +const looksLikeImage = e => !e.dir && (IMAGE_EXT.test(e.name) || e.size >= 64 << 20); + +const joinPath = (dir, name) => (dir.endsWith('/') ? dir : dir + '/') + name; +const parentOf = dir => dir.replace(/\/[^/]+\/?$/, '') || '/'; + +/** Show the Quick Start. Resolves when the user has made a choice and it has closed. */ +export function showQuickStart() { + if (document.querySelector('.qs')) return Promise.resolve(); + return new Promise(resolve => { + const s = store.session; + const hasImage = !!(s && s.image); + const root = el('div.qs', { role: 'dialog', 'aria-modal': 'true', 'aria-label': 'fastvol quick start' }); + + const done = () => { root.remove(); removeEventListener('keydown', onKey, true); resolve(); }; + + // ---- left: logo, choices + const logo = document.querySelector('.brand-logo').cloneNode(true); + const version = (document.querySelector('meta[name="fastvol-version"]') || {}).content || ''; + const choices = []; + if (hasImage) choices.push({ id: 'cont', ico: 'cont', title: 'Continue', desc: s.name, render: renderContinue }); + choices.push( + { id: 'open', ico: 'open', title: 'New analysis', desc: 'Open a memory image', render: renderOpen }, + { id: 'prev', ico: 'prev', title: 'Previous', desc: 'Reopen a saved analysis', render: renderPrev }, + ); + const buttons = choices.map((c, i) => el('button.qs-choice', { type: 'button', 'aria-pressed': 'false', on: { click: () => select(c.id) } }, + el('span.qs-ico', {}, icon(c.ico)), + el('span', {}, el('div.qs-ct', { text: c.title }), el('div.qs-cd', { text: c.desc, title: c.desc })), + el('span.qs-key', { text: String(i + 1) }))); + + const side = el('div.qs-side', {}, + el('div.qs-brand', {}, logo, el('div.qs-ver', { text: version })), + el('div.qs-h', { text: 'Start' }), + el('div.qs-choices', {}, buttons), + el('div.qs-foot', {}, el('span', { text: 'Esc — straight to the workspace' }))); + + const main = el('div.qs-main'); + root.append(el('div.qs-win', {}, side, main)); + document.body.append(root); + + function select(id) { + const i = choices.findIndex(c => c.id === id); + buttons.forEach((b, j) => b.setAttribute('aria-pressed', String(i === j))); + clear(main); + choices[i].render(); + } + + function onKey(e) { + if (e.target && e.target.tagName === 'INPUT') { if (e.key === 'Escape') e.target.blur(); return; } + if (e.key === 'Escape') { e.preventDefault(); done(); return; } + const n = +e.key; + if (n >= 1 && n <= choices.length && !e.ctrlKey && !e.altKey && !e.metaKey) { e.preventDefault(); select(choices[n - 1].id); buttons[n - 1].focus(); } + } + addEventListener('keydown', onKey, true); + + // ---- right: one panel per choice + function renderContinue() { + const F = Object.fromEntries(s.facts || []); + const rows = [['File', s.image], ['Size', fmtBytes(s.size)]]; + if (s.os) rows.push(['System', [s.os, s.arch, F['Major/Minor'] || ''].filter(Boolean).join(' · ')]); + rows.push(['State', s.state === 'ready' ? 'analysed, ready' : (s.phase || s.state)]); + const go = el('button.qs-btn.primary', { type: 'button', text: 'Open workspace', on: { click: done } }); + main.append( + el('h2.qs-title', { text: 'Continue with ' + s.name }), + el('p.qs-sub', { text: 'This image was given to fvol serve when it started.' }), + el('dl.qs-current', {}, rows.map(([k, v]) => [el('dt', { text: k }), el('dd', { text: v, title: v })])), + el('div.qs-actions', {}, el('span.qs-picked'), go)); + go.focus(); + } + + function renderOpen() { + let dir = null; + let picked = null; + const path = el('input.qs-input', { type: 'text', spellcheck: false, autocomplete: 'off', placeholder: '/cases/host1/memory.raw', 'aria-label': 'Folder or file path' }); + const crumbs = el('nav.qs-crumbs', { 'aria-label': 'Folder' }); + const list = el('div.qs-files', { role: 'listbox', 'aria-label': 'Files' }); + const pickedLabel = el('span.qs-picked', { text: 'Choose a memory image' }); + const errBox = el('span.qs-err', { role: 'alert' }); + const openBtn = el('button.qs-btn.primary', { type: 'button', text: 'Open image', disabled: true, on: { click: () => submit() } }); + + function pick(full, row) { + picked = full; + for (const r of list.children) r.setAttribute('aria-selected', String(r === row)); + pickedLabel.textContent = full; + pickedLabel.title = full; + errBox.textContent = ''; + openBtn.disabled = false; + } + + async function browse(p) { + errBox.textContent = ''; + let r; + try { r = await api('fs?path=' + encodeURIComponent(p || '.')); } catch (e) { errBox.textContent = e.message; return; } + dir = r.dir; + prefs.set('qsDir', dir); + if (document.activeElement !== path) path.value = dir; + // breadcrumbs + clear(crumbs); + const parts = dir.split('/').filter(Boolean); + crumbs.append(el('button', { type: 'button', text: '/', on: { click: () => browse('/') } })); + parts.forEach((part, i) => { + if (i) crumbs.append(el('span', { text: '/' })); + const to = '/' + parts.slice(0, i + 1).join('/'); + crumbs.append(el('button', { type: 'button', text: part, on: { click: () => browse(to) } })); + }); + // listing: folders, then memory images, then everything else + const filter = (!path.value.endsWith('/') && document.activeElement === path) ? path.value.slice(path.value.lastIndexOf('/') + 1).toLowerCase() : ''; + const entries = r.entries.filter(e => !e.name.startsWith('.') && (!filter || e.name.toLowerCase().startsWith(filter))); + const rank = e => (e.dir ? 0 : looksLikeImage(e) ? 1 : 2); + entries.sort((a, b) => rank(a) - rank(b) || a.name.localeCompare(b.name)); + clear(list); + picked = null; + openBtn.disabled = true; + pickedLabel.textContent = 'Choose a memory image'; + if (dir !== '/') { + list.append(el('button.qs-file.dir', { type: 'button', on: { click: () => browse(parentOf(dir)) } }, + el('span.fi', {}, icon('up')), el('span.fn', { text: 'Parent folder' }), el('span'), el('span.fs'))); + } + for (const e of entries) { + const full = joinPath(dir, e.name); + const img = looksLikeImage(e); + const row = el('button.qs-file', { type: 'button', role: 'option', 'aria-selected': 'false', class: 'qs-file ' + (e.dir ? 'dir' : img ? 'image' : 'other') }, + el('span.fi', {}, icon(e.dir ? 'dir' : img ? 'chip' : 'file')), + el('span.fn', { text: e.name, title: e.name }), + img ? el('span.qs-tag', { text: 'image' }) : el('span'), + el('span.fs', { text: e.dir ? '' : fmtBytes(e.size) })); + if (e.dir) row.addEventListener('click', () => browse(full)); + else { + row.addEventListener('click', () => pick(full, row)); + row.addEventListener('dblclick', () => { pick(full, row); submit(); }); + } + list.append(row); + } + if (!entries.length) list.append(el('div.qs-empty', { text: filter ? 'Nothing here starts with “' + filter + '”.' : 'This folder is empty.' })); + } + + async function submit() { + const file = picked || path.value.trim(); + if (!file) return; + openBtn.disabled = true; + errBox.textContent = ''; + try { + await api('session', { method: 'POST', body: { file } }); + done(); + } catch (e) { errBox.textContent = e.message; openBtn.disabled = false; } + } + + // the desktop's own file dialog, opened by the server (browsers never reveal full paths) + const nativeBtn = el('button.qs-btn.outline', { type: 'button', hidden: true, on: { click: () => nativePick() } }, icon('open', 'btn-ico'), 'Open file…'); + api('pick-file').then(r => { if (r.available) { nativeBtn.hidden = false; nativeBtn.title = 'Choose the image in your desktop’s file dialog (' + r.tool + ')'; } }).catch(() => {}); + async function nativePick() { + nativeBtn.disabled = true; + const label = nativeBtn.lastChild; + label.textContent = 'Choose in the dialog…'; + pickedLabel.textContent = 'The file dialog is open on your desktop — it may be behind this window.'; + errBox.textContent = ''; + try { + const r = await api('pick-file', { method: 'POST', body: { dir: dir || '' } }); + if (r.path) { picked = r.path; pickedLabel.textContent = r.path; await submit(); } + else pickedLabel.textContent = 'Choose a memory image'; + } catch (e) { errBox.textContent = e.message; pickedLabel.textContent = ''; } + label.textContent = 'Open file…'; + nativeBtn.disabled = false; + } + + path.addEventListener('input', debounce(() => browse(path.value.endsWith('/') ? path.value : path.value.slice(0, path.value.lastIndexOf('/') + 1) || '/'), 150)); + path.addEventListener('keydown', e => { + if (e.key === 'Enter') { e.preventDefault(); if (path.value.endsWith('/')) browse(path.value); else { picked = null; submit(); } } + if (e.key === 'ArrowDown') { e.preventDefault(); const f = list.querySelector('.qs-file'); if (f) f.focus(); } + }); + list.addEventListener('keydown', e => { + const rows = [...list.querySelectorAll('.qs-file')]; + const i = rows.indexOf(document.activeElement); + if (e.key === 'ArrowDown' && i < rows.length - 1) { e.preventDefault(); rows[i + 1].focus(); } + if (e.key === 'ArrowUp') { e.preventDefault(); (i > 0 ? rows[i - 1] : path).focus(); } + if (e.key === 'Backspace') { e.preventDefault(); browse(parentOf(dir)); } + }); + + main.append( + el('h2.qs-title', { text: 'Open a memory image' }), + el('p.qs-sub', { text: 'Raw, LiME, ELF core, crash dump, VMware, QEMU, AVML, Xen - also gzip, bzip2 and xz. The file is only read, never changed.' }), + el('div.qs-pathrow', {}, path, nativeBtn), crumbs, list, + el('div.qs-actions', {}, pickedLabel, errBox, openBtn)); + const start = hasImage ? parentOf(s.image) : prefs.get('qsDir', '.'); + browse(start); + path.focus(); + } + + function renderPrev() { + const list = el('div.qs-files', { role: 'listbox', 'aria-label': 'Saved analyses' }, el('div.qs-empty', { text: 'Reading saved analyses…' })); + const errBox = el('span.qs-err', { role: 'alert' }); + main.append( + el('h2.qs-title', { text: 'Reopen a saved analysis' }), + el('p.qs-sub', { text: 'Every dump you analyse is saved in ~/.fvol: its runs, results, filters, options and rules come back when you reopen it.' }), + list, el('div.qs-actions', {}, errBox)); + api('analyses').then(items => { + clear(list); + if (!items.length) { list.append(el('div.qs-empty', { text: 'No saved analyses yet: open a memory image and run some plugins.' })); return; } + for (const a of items) { + const ok = a.state === 'ok'; + const why = a.state === 'missing' ? 'the dump is no longer at this path' : a.state === 'changed' ? 'the dump changed since (a different size or date)' : ''; + const open = async () => { + errBox.textContent = ''; + try { await api('session', { method: 'POST', body: { file: a.image } }); done(); } + catch (e) { errBox.textContent = e.message; } + }; + const del = el('button.qs-del', { type: 'button', text: 'Delete', title: 'Delete this saved analysis from ~/.fvol', on: { click: async e => { + e.stopPropagation(); + const current = store.session && store.session.image === a.image; + if (!confirm(`Delete the saved analysis of ${a.name}?\n\nIts runs, results, filters and options are removed from ~/.fvol. The dump itself is not touched.` + (current ? '\n\nThis dump is open: its runs are removed and it starts over.' : ''))) return; + try { await api('analyses/' + encodeURIComponent(a.dump_id), { method: 'DELETE' }); row.remove(); if (!list.querySelector('.qs-prev')) list.append(el('div.qs-empty', { text: 'No saved analyses left.' })); } + catch (x) { errBox.textContent = x.message; } + } } }); + // a row, not a button: it holds the Delete button + const row = el('div.qs-file.qs-prev', { role: 'option', tabindex: ok ? 0 : -1, 'aria-disabled': String(!ok), class: 'qs-file qs-prev' + (ok ? '' : ' off'), title: ok ? a.image : `${a.image}: ${why}` }, + el('span.fi', {}, icon('chip')), + el('span.fn', {}, el('span.qs-pn', { text: a.name }), el('span.qs-pp', { text: a.image })), + ok ? el('span.qs-pm', { text: `${a.runs} run${a.runs === 1 ? '' : 's'} · ${a.plugins} plugin${a.plugins === 1 ? '' : 's'}` }) : el('span.qs-tag.warn', { text: a.state }), + el('span.fs', { text: `${fmtBytes(a.size)} · ${fmtAgo(a.updated)}` }), + del); + if (ok) { + row.addEventListener('click', open); + row.addEventListener('keydown', e => { if (e.key === 'Enter') { e.preventDefault(); open(); } if (e.key === 'Delete') del.click(); }); + } + list.append(row); + } + }).catch(e => { clear(list); list.append(el('div.qs-empty', { text: 'Could not read the saved analyses: ' + e.message })); }); + } + + select(hasImage ? 'cont' : 'open'); + }); +} diff --git a/src/web/assets/result.js b/src/web/assets/result.js deleted file mode 100644 index c88f96c..0000000 --- a/src/web/assets/result.js +++ /dev/null @@ -1,359 +0,0 @@ -// A result panel: toolbar + virtual table + row detail drawer + (optional) timeline strip. -// Used for plugin tabs, process pivots and the compare view. - -import { store, api, on, emit, el, clear, copy, menu, cellText, fmtCount, fmtMs, fmtTime, parseTime, toast, shortName, prefs, expectedDuration, download } from './core.js'; -import { VirtualTable } from './table.js'; - -/** Where to look at a Hex value: physical, kernel or a process address space. */ -export function hexTarget(text, colName, row, cols, run) { - const addr = text; - if (/\(P\)|phys/i.test(colName)) return { layer: 'phys', addr }; - const n = BigInt(text); - const pidCol = cols.findIndex(c => /^(PID|Pid)$/.test(c.name)); - let pid = pidCol >= 0 && typeof row[pidCol + 2] === 'string' ? row[pidCol + 2] : null; - if (!pid && run && run.args) { - const k = run.args.indexOf('--pid'); - if (k >= 0 && /^\d+$/.test(run.args[k + 1] || '')) pid = run.args[k + 1]; - } - const os = store.session && store.session.os; - const userSpace = os === 'windows' ? n < 0x800000000000n : n < 0xffff800000000000n && n < 0x800000000000n; - if (pid && userSpace && pid !== '4' && pid !== '0') return { layer: 'pid:' + pid, addr }; - return { layer: 'kernel', addr }; -} - -export class ResultPanel { - /** opts: runId, fixed, compact, cmp, label, onState */ - constructor(opts) { - this.o = opts; - this.runId = opts.runId; - this.run = store.runs.get(opts.runId) || { cols: [], status: 'queued', plugin: opts.plugin || '' }; - this.node = el('div.rv-main'); - this.bar = el('div.rv-bar'); - this.q = el('input', { type: 'search', class: 'q', placeholder: 'Filter rows… ( / )', 'aria-label': 'Filter rows (all columns)', spellcheck: false, autocomplete: 'off' }); - this.count = el('span.count'); - this.histBox = el('div.hist', { hidden: true }); - this.body = el('div.rv-body'); - this.table = new VirtualTable({ - runId: opts.runId, - plugin: this.run.plugin, - fixed: opts.fixed, - cmp: opts.cmp, - label: opts.label || shortName(this.run.plugin || ''), - onHex: (text, colName, row) => this.openHex(text, colName, row), - onPid: pid => emit('nav', { kind: 'proc', pid }), - onOpen: row => this.openDrawer(row), - onCursor: row => { if (this.drawer) this.openDrawer(row, true); }, - onState: () => this.updateCount(), - }); - this.q.addEventListener('input', () => this.table.setQuery(this.q.value.trim())); - this.q.addEventListener('keydown', e => { - if (e.key === 'ArrowDown' || e.key === 'Enter') { e.preventDefault(); this.table.root.focus(); } - if (e.key === 'Escape') { if (this.q.value) { this.q.value = ''; this.table.setQuery(''); } else this.table.root.focus(); e.stopPropagation(); } - }); - const filtersBtn = el('button.btn.ghost', { type: 'button', title: 'Per-column filters (F)', on: { click: () => this.table.toggleFilters() } }, 'Filters'); - const colsBtn = el('button.btn.ghost', { type: 'button', title: 'Show / hide columns', on: { click: () => this.columnsMenu(colsBtn) } }, 'Columns'); - this.timeBtn = el('button.btn.ghost', { type: 'button', title: 'Time histogram of a DateTime column; drag to filter a time range', hidden: true, on: { click: () => this.toggleHist() } }, 'Timeline'); - const exportBtn = el('button.btn.ghost', { type: 'button', title: 'Export', on: { click: () => this.exportMenu(exportBtn) } }, 'Export ▾'); - this.bar.append(this.q, filtersBtn, colsBtn, this.timeBtn, el('span.spacer')); - if (opts.fixedLabel) this.bar.append(el('span.chip', { title: 'This plugin has no PID option: it ran for every process and this view keeps only this one', text: opts.fixedLabel })); - this.bar.append(this.count, exportBtn); - if (opts.extraBar) this.bar.append(...opts.extraBar); - this.body.append(this.table.root); - this.node.append(this.bar, this.histBox, this.body); - this.off = on('run:' + this.runId, r => this.update(r)); - this.update(this.run); - } - - update(r) { - this.run = r; - this.table.update(r); - const nTime = (r.cols || []).filter(c => c.type === 'DateTime').length; - this.timeBtn.hidden = !nTime; - if (this.hist === undefined && nTime > 1 && /timeliner/i.test(r.plugin) && r.status === 'done') this.toggleHist(true); - if (this.hist && r.status === 'done' && this.histDoneSeq !== r.seq) { this.histDoneSeq = r.seq; this.loadHist(); } - this.updateCount(); - if (this.o.onUpdate) this.o.onUpdate(r); - } - - updateCount() { - const t = this.table; - clear(this.count); - if (!t.built) return; - if (t.hasSpec() && t.view) this.count.append(el('b', { text: fmtCount(t.total) }), ` of ${fmtCount(t.stored)}`); - else this.count.append(el('b', { text: fmtCount(t.total) }), ' rows'); - } - - focusFilter() { this.q.focus(); this.q.select(); } - - columnsMenu(anchor) { - const t = this.table; - const items = [{ header: 'Columns' }]; - t.cols.forEach((c, i) => { - const cb = el('input', { type: 'checkbox', checked: !t.hidden.has(i) }); - cb.addEventListener('change', () => t.setHidden(i, !cb.checked)); - items.push({ node: el('label.mi', {}, cb, c.name, el('small', { text: c.type })) }); - }); - items.push('sep', { label: 'Show all', act: () => { t.hidden.clear(); t.saveCols(); t.buildHead(); } }); - menu(anchor, items); - } - - exportMenu(anchor) { - const t = this.table; - const dl = url => download(url); - const r = this.run; - const cli = () => { - const s = store.session; - const parts = ['fvol', '-f', s.image]; - if (s.symbol_dirs.length) parts.push('-s', s.symbol_dirs.join(';')); - parts.push(r.plugin, ...r.args); - return parts.map(p => (/^[\w./:=,@%+-]+$/.test(p) ? p : `'${p.replace(/'/g, `'\\''`)}'`)).join(' '); - }; - menu(anchor, [ - { header: 'Current view (filters, sort, visible columns)' }, - { label: 'CSV', hint: '.csv', act: () => dl(t.exportUrl('csv')) }, - { label: 'TSV', hint: '.tsv', act: () => dl(t.exportUrl('tsv')) }, - { label: 'JSON', hint: '.json', act: () => dl(t.exportUrl('json')) }, - { label: 'JSON Lines', hint: '.jsonl', act: () => dl(t.exportUrl('jsonl')) }, - { label: 'Markdown table', hint: '.md', act: () => dl(t.exportUrl('md')) }, - 'sep', - { header: 'Exactly as vol prints it (re-runs the plugin)' }, - { label: 'fvol -r jsonl', act: () => dl(`/api/runs/${this.runId}/vol?renderer=jsonl`) }, - { label: 'fvol -r json', act: () => dl(`/api/runs/${this.runId}/vol?renderer=json`) }, - { label: 'fvol -r csv', act: () => dl(`/api/runs/${this.runId}/vol?renderer=csv`) }, - { label: 'fvol (quick text)', act: () => dl(`/api/runs/${this.runId}/vol?renderer=quick`) }, - 'sep', - { label: 'Copy visible rows as TSV', hint: '≤ 20k', act: () => this.copyRows() }, - { label: 'Copy the fvol command', act: () => copy(cli(), 'Command copied') }, - ]); - } - - async copyRows() { - const t = this.table; - const out = [t.headerTsv()]; - const n = Math.min(t.total, 20000); - for (let from = 0; from < n; from += 5000) { - const r = await api(`runs/${this.runId}/rows?view=${t.view}&from=${from}&count=${Math.min(5000, n - from)}`); - for (const row of r.rows) out.push(t.rowTsv(row)); - } - copy(out.join('\n'), `Copied ${out.length - 1} rows`); - } - - openHex(text, colName, row) { - const tgt = hexTarget(text, colName, row, this.table.cols, this.run); - emit('nav', { kind: 'hex', ...tgt }); - } - - // ---------------------------------------------------------------- drawer - openDrawer(row, follow = false) { - if (follow && !this.drawer) return; - if (!this.drawer) { - this.drawer = el('aside.drawer', { 'aria-label': 'Row details' }); - this.body.append(this.drawer); - } - const d = this.drawer; - clear(d); - const cols = this.table.cols; - const closeBtn = el('button.iconbtn', { type: 'button', 'aria-label': 'Close details (Esc)', text: '×', on: { click: () => this.closeDrawer() } }); - d.append(el('div.drawer-h', {}, el('h3', { text: `Row ${row[0] + 1}` }), - el('button.btn.ghost', { type: 'button', on: { click: () => copy(cols.map((c, i) => `${c.name}: ${cellText(row[i + 2])}`).join('\n'), 'Row copied') } }, 'Copy all'), - closeBtn)); - const b = el('div.drawer-b'); - cols.forEach((c, i) => { - const v = row[i + 2]; - const text = cellText(v); - const multi = typeof v === 'string' && v.includes('\n'); - const kv = el('div.kv', {}, el('div.k', { text: c.name })); - if (multi) { - kv.append(el('div.v.block', {}, c.type === 'Disassembly' ? disasmBlock(v) : el('pre.code', { text: v.replace(/^\n/, '') }))); - } else { - const vEl = el('div.v', { class: 'v' + (v === null || v === 0 ? ' faint' : c.type === 'Hex' ? ' addr' : '') , text }); - kv.append(vEl); - } - const acts = el('div.acts'); - if (c.type === 'Hex' && typeof v === 'string') acts.append(el('button.linkbtn', { type: 'button', text: 'view memory', on: { click: () => this.openHex(v, c.name, row) } })); - if (/^(PID|PPID|Pid)$/.test(c.name) && typeof v === 'string') acts.append(el('button.linkbtn', { type: 'button', text: 'open process', on: { click: () => emit('nav', { kind: 'proc', pid: Number(v) }) } })); - if (c.type === 'DateTime' && typeof v === 'string') { - const t = parseTime(v); - const cap = captureTime(); - if (t && cap) acts.append(el('span.muted', { text: relToCapture(t, cap), style: { fontSize: '11px' } })); - } - if (typeof v === 'string') acts.append(el('button.linkbtn', { type: 'button', text: 'copy', on: { click: () => copy(v.replace(/^\n/, '')) } })); - if (acts.childNodes.length) kv.append(acts); - b.append(kv); - }); - d.append(b); - d.addEventListener('keydown', e => { if (e.key === 'Escape') { e.stopPropagation(); this.closeDrawer(); } }); - if (!follow) closeBtn.focus(); - } - - closeDrawer() { - if (this.drawer) { this.drawer.remove(); this.drawer = null; this.table.root.focus(); } - } - - // ---------------------------------------------------------------- time histogram - toggleHist(force) { - this.hist = force ?? !this.hist; - this.histBox.hidden = !this.hist; - this.timeBtn.setAttribute('aria-pressed', String(!!this.hist)); - if (this.hist) this.loadHist(); - else if (this.table.range) this.table.setRange(null); - } - - /** Time histogram of the result: every timestamp of the chosen DateTime column(s), optionally - * stacked by a text column (e.g. timeliner's Plugin). Drag to filter the table to a range. */ - async loadHist() { - const cols = this.table.cols; - const timeCols = cols.map((c, i) => [c, i]).filter(([c]) => c.type === 'DateTime'); - if (!timeCols.length) return; - const textCols = cols.map((c, i) => [c, i]).filter(([c]) => c.type === 'Str'); - if (this.histCol === undefined) this.histCol = timeCols.length > 1 ? 'all' : String(timeCols[0][1]); - if (this.histBy === undefined) { - const pc = textCols.find(([c]) => /^(Plugin|Source|Type|Process|ImageFileName|COMM)$/i.test(c.name)); - this.histBy = pc && timeCols.length > 1 ? String(pc[1]) : ''; - } - const w = Math.max(40, Math.floor((this.histBox.clientWidth || 800) / 6)); - const gen = (this.histGen = (this.histGen || 0) + 1); - let h; - try { - // a brushed range zooms the axis into it (the table is filtered to it too) - const win = this.table.range ? `&from=${parseTime(this.table.range.from)}&to=${parseTime(this.table.range.to)}` : ''; - h = await api(`runs/${this.runId}/hist?col=${this.histCol}&view=${this.table.range ? 0 : this.table.view}&buckets=${Math.min(240, w)}${this.histBy ? '&by=' + this.histBy : ''}${win}`); - } catch (e) { return; } - if (gen !== this.histGen) return; - const box = this.histBox; - clear(box); - box.classList.toggle('tall', !!(h.cats && h.cats.length)); - // controls: one row above the chart - const selCol = el('select.input', { 'aria-label': 'Time column' }); - if (timeCols.length > 1) selCol.append(el('option', { value: 'all', text: 'all time columns', selected: this.histCol === 'all' })); - for (const [c, i] of timeCols) selCol.append(el('option', { value: String(i), text: c.name, selected: String(i) === this.histCol })); - selCol.addEventListener('change', () => { this.histCol = selCol.value; this.table.setRange(null); this.loadHist(); }); - const selBy = el('select.input', { 'aria-label': 'Stack by' }, el('option', { value: '', text: 'no stacking' })); - for (const [c, i] of textCols) selBy.append(el('option', { value: String(i), text: 'by ' + c.name, selected: String(i) === this.histBy })); - selBy.addEventListener('change', () => { this.histBy = selBy.value; this.loadHist(); }); - const r = this.table.range; - const label = el('span.rl', { text: r ? `${r.from.slice(0, 19)} → ${r.to.slice(0, 19)}` : 'drag across the chart to zoom in and filter' }); - const clearBtn = el('button.linkbtn', { type: 'button', text: 'zoom out', hidden: !r, on: { click: () => { this.table.setRange(null); this.loadHist(); } } }); - box.append(el('div.hl', {}, selCol, textCols.length ? selBy : null, label, clearBtn)); - if (h.empty) { box.append(el('div.muted', { text: 'No timestamps in this column.', style: { padding: '10px 0', fontSize: '11px' } })); return; } - const n = h.counts.length; - const stacked = h.cats && h.cats.length > 0; - if (!h.counts.some(Boolean)) { - box.append(el('div.muted', { text: `No timestamps in this range (${fmtCount(h.below)} earlier, ${fmtCount(h.above)} later).`, style: { padding: '14px 0', fontSize: '11px' } })); - return; - } - const max = Math.max(...h.counts, 1); - const span = h.max - h.min || 1; - const H = stacked ? 70 : 42; - const NS = 'http://www.w3.org/2000/svg'; - const mk = (tag, attrs) => { const e = document.createElementNS(NS, tag); for (const [k, v] of Object.entries(attrs)) e.setAttribute(k, v); return e; }; - const svg = mk('svg', { viewBox: `0 0 ${n} ${H}`, preserveAspectRatio: 'none', role: 'img', 'aria-label': `Timeline of ${this.histCol === 'all' ? 'all time columns' : cols[+this.histCol].name}: ${h.counts.reduce((a, b) => a + b, 0)} timestamps` }); - svg.style.height = H + 'px'; - const rf = r ? parseTime(r.from) : null, rt = r ? parseTime(r.to) : null; - // sqrt scale keeps small bursts visible next to big ones - const scale = c => (c ? Math.max(1.5, Math.sqrt(c / max) * (H - 2)) : 0); - for (let i = 0; i < n; i++) { - const c = h.counts[i]; - if (!c) continue; - const t0 = h.min + (i / n) * span; - const inRange = r && t0 + span / n >= rf && t0 <= rt; - const total = scale(c); - if (stacked) { - // segments proportional within the bar, bottom = most frequent category - let y = H; - const parts = h.stacks[i]; - parts.forEach((pc, k) => { - if (!pc) return; - const hh = (pc / c) * total; - y -= hh; - svg.append(mk('rect', { x: i + 0.12, width: 0.76, y, height: Math.max(0.3, hh - 0.25), class: `b s${k < h.cats.length ? k + 1 : 'o'}${r && !inRange ? ' out' : ''}` })); - }); - } else { - svg.append(mk('rect', { x: i + 0.12, width: 0.76, y: H - total, height: total, class: 'b' + (inRange ? ' in' : '') })); - } - } - const brush = mk('rect', { class: 'brush', y: 0, height: H, width: 0 }); - svg.append(brush); - const tip = el('div.htip', { hidden: true, role: 'tooltip' }); - const toX = e => { const b = svg.getBoundingClientRect(); return Math.max(0, Math.min(n, ((e.clientX - b.left) / b.width) * n)); }; - let x0 = null; - svg.addEventListener('mousedown', e => { x0 = toX(e); brush.setAttribute('x', x0); brush.setAttribute('width', 0); tip.hidden = true; }); - svg.addEventListener('mousemove', e => { - const x = toX(e); - if (x0 !== null) { brush.setAttribute('x', Math.min(x, x0)); brush.setAttribute('width', Math.abs(x - x0)); return; } - const i = Math.min(n - 1, Math.floor(x)); - const c = h.counts[i]; - if (!c) { tip.hidden = true; return; } - const t0 = h.min + (i / n) * span; - clear(tip); - tip.append(el('b', { text: `${fmtTime(t0)} – ${fmtTime(t0 + span / n).slice(11)} UTC` }), el('div', { text: `${fmtCount(c)} timestamp${c > 1 ? 's' : ''}` })); - if (stacked) { - h.stacks[i].map((pc, k) => [pc, k]).filter(([pc]) => pc).sort((a, b) => b[0] - a[0]).slice(0, 7).forEach(([pc, k]) => { - tip.append(el('div.tr', {}, el('i', { class: `sw s${k < h.cats.length ? k + 1 : 'o'}` }), el('span', { text: k < h.cats.length ? h.cats[k] : 'other' }), el('span.n', { text: fmtCount(pc) }))); - }); - } - const bb = box.getBoundingClientRect(); - tip.hidden = false; - tip.style.left = Math.min(bb.width - 240, Math.max(0, e.clientX - bb.left + 12)) + 'px'; - tip.style.top = (e.clientY - bb.top + 14) + 'px'; - }); - svg.addEventListener('mouseleave', e => { tip.hidden = true; if (x0 !== null) up(e); }); - const up = e => { - if (x0 === null) return; - const x = toX(e); - const a = Math.min(x, x0), b = Math.max(x, x0); - x0 = null; - if (b - a < 0.3) { if (this.table.range) { this.table.setRange(null); this.loadHist(); } return; } - const from = fmtTime(h.min + (a / n) * span), to = fmtTime(h.min + (b / n) * span + 1); - const rcols = this.histCol === 'all' ? timeCols.map(([, i]) => i) : [+this.histCol]; - this.table.setRange({ cols: rcols, from, to }); - label.textContent = `${from} → ${to}`; - clearBtn.hidden = false; - this.loadHist(); - }; - svg.addEventListener('mouseup', up); - const outl = (n2, side) => (n2 ? el('span.out', { title: side === 'below' ? 'timestamps before the axis (outliers such as 1601-01-01 are left out of the scale)' : 'timestamps after the axis', text: side === 'below' ? `‹ ${fmtCount(n2)} earlier` : `${fmtCount(n2)} later ›` }) : null); - box.append(svg, tip, el('div.axis', {}, el('span', {}, outl(h.below, 'below'), fmtTime(h.min) + ' UTC'), el('span', { text: fmtTime(h.min + span / 2) }), el('span', {}, fmtTime(h.max), outl(h.above, 'above')))); - if (stacked) { - const totals = new Array(h.cats.length + 1).fill(0); - for (const st of h.stacks) st.forEach((c, k) => { totals[k] += c; }); - const legend = el('div.legend', { 'aria-label': 'Legend' }); - h.cats.forEach((name, k) => { if (totals[k]) legend.append(el('span.li', {}, el('i', { class: `sw s${k + 1}` }), name, el('span.n', { text: fmtCount(totals[k]) }))); }); - if (totals[h.cats.length]) legend.append(el('span.li', {}, el('i', { class: 'sw so' }), 'other', el('span.n', { text: fmtCount(totals[h.cats.length]) }))); - box.append(legend); - } - } - - destroy() { this.off(); this.table.destroy(); } -} - -/** Disassembly text with light syntax colouring (address / mnemonic / operands). */ -export function disasmBlock(text) { - const pre = el('pre.code'); - for (const line of text.replace(/^\n/, '').split('\n')) { - const m = /^(0x[0-9a-f]+:?)(\s+)(\S+)(\s*)(.*)$/i.exec(line); - if (!m) { pre.append(line + '\n'); continue; } - const ops = el('span.o'); - for (const part of m[5].split(/(0x[0-9a-f]+)/i)) ops.append(/^0x/i.test(part) ? el('span.x', { text: part }) : part); - pre.append(el('span.a', { text: m[1] }), m[2], el('span.m', { text: m[3] }), m[4], ops, '\n'); - } - return pre; -} - -export function captureTime() { - const s = store.session; - if (!s) return null; - const f = (s.facts || []).find(([k]) => k === 'SystemTime'); - if (f) return parseTime(f[1]); - return store.captureGuess || null; -} - -export function relToCapture(t, cap) { - const d = cap - t; - if (Math.abs(d) < 1) return 'at capture time'; - const span = Math.abs(d); - const txt = span < 60 ? `${Math.round(span)} s` : span < 3600 ? `${Math.round(span / 60)} min` : span < 172800 ? `${(span / 3600).toFixed(1)} h` : `${Math.round(span / 86400)} days`; - return d > 0 ? `${txt} before capture` : `${txt} after capture`; -} - -export { expectedDuration, fmtMs, prefs, toast }; diff --git a/src/web/assets/results.js b/src/web/assets/results.js new file mode 100644 index 0000000..07a8c7c --- /dev/null +++ b/src/web/assets/results.js @@ -0,0 +1,230 @@ +// The results of one run, in place of the File Overview and Plugins columns: ": Results", +// a tab per plugin (status and rows, live), and for the chosen plugin a virtualised table with +// a filter, per-column filters and exports. Runs and Triage Hints stay on the right. + +import { store, api, on, el, clear, fmtCount, shortName, download, menu, toast } from './core.js'; +import { VirtualTable } from './table.js'; + +const $ = id => document.getElementById(id); +const ACTIVE = st => st === 'queued' || st === 'running'; +const clock = ms => { const t = Math.max(0, Math.round(ms / 1000)); return `${Math.floor(t / 60)}:${String(t % 60).padStart(2, '0')}`; }; +const EXPORTS = [['csv', 'CSV'], ['tsv', 'TSV'], ['json', 'JSON'], ['jsonl', 'JSON Lines'], ['md', 'Markdown']]; + +// q: the Filter rows text of the open run, shared by all of its plugin tabs. Each run keeps its +// own, stored with the run on the server (so a saved analysis brings it back). +// `filters` holds what was typed in this page, ahead of the server's copy arriving back. +const rv = { batch: null, tab: null, tables: new Map(), timer: null, q: '', save: null, filters: new Map() }; + +export const openBatchId = () => rv.batch; + +/** Show a run's results; `runId` picks the plugin tab (default: the first). */ +export function openResults(batchId, runId = null) { + const b = store.batches.find(x => x.id === batchId); + if (!b) return; + if (rv.batch !== batchId) { flushFilter(); closeTables(); rv.q = rv.filters.has(batchId) ? rv.filters.get(batchId) : b.filter || ''; } + rv.batch = batchId; + rv.tab = runId && b.runs.includes(runId) ? runId : rv.tab && b.runs.includes(rv.tab) ? rv.tab : b.runs[0]; + document.body.classList.add('results-open'); + $('results').hidden = false; + render(); + document.dispatchEvent(new CustomEvent('fastvol-results', { detail: { batch: batchId } })); + if (!rv.timer) rv.timer = setInterval(renderHead, 1000); +} + +export function closeResults() { + if (rv.batch === null) return; + flushFilter(); + closeTables(); + rv.batch = null; + rv.tab = null; + clearInterval(rv.timer); + rv.timer = null; + document.body.classList.remove('results-open'); + $('results').hidden = true; + document.dispatchEvent(new CustomEvent('fastvol-results', { detail: { batch: null } })); +} + +function closeTables() { + for (const t of rv.tables.values()) t.table && t.table.destroy(); + rv.tables.clear(); +} + +function batch() { return store.batches.find(x => x.id === rv.batch); } + +/** Store the open run's filter on the server, 400 ms after the last keystroke. */ +function saveFilter() { + const b = batch(); + if (!b) return; + b.filter = rv.q; + rv.filters.set(b.id, rv.q); + clearTimeout(rv.save && rv.save.timer); + const pending = { id: b.id, q: rv.q }; + pending.timer = setTimeout(() => sendFilter(pending), 400); + rv.save = pending; +} +function flushFilter() { + if (!rv.save) return; + clearTimeout(rv.save.timer); + sendFilter(rv.save); +} +function sendFilter(p) { + if (rv.save === p) rv.save = null; + api(`batches/${p.id}/filter`, { method: 'POST', body: { q: p.q } }).catch(e => toast('Could not save the filter: ' + e.message, 'bad')); +} + +function render() { + renderHead(); + renderTabs(); + renderBody(); +} + +function renderHead() { + const b = batch(); + if (!b) return; + const runs = b.runs.map(id => store.runs.get(id)).filter(Boolean); + const active = runs.filter(r => ACTIVE(r.status)).length; + const ends = runs.filter(r => r.started).map(r => r.started + r.elapsed); + const elapsed = active ? Date.now() - b.created : ends.length ? Math.max(...ends) - b.created : 0; + $('rs-title').textContent = `${b.name}: Results`; + $('rs-sum').textContent = `${runs.length - active}/${b.runs.length} · ${clock(elapsed)}`; + $('rs-sum').classList.toggle('active', active > 0); + if (!active && rv.timer) { clearInterval(rv.timer); rv.timer = null; } +} + +function badge(r) { + if (!r) return el('span.rs-badge', { text: '?' }); + if (r.status === 'done') return el('span.rs-badge', { text: fmtCount(r.rows) }); + if (r.status === 'running') return el('span.rs-badge.running', { text: r.rows ? fmtCount(r.rows) : '…' }); + if (r.status === 'queued') return el('span.rs-badge.queued', { text: 'queued' }); + return el('span', { class: 'rs-badge ' + r.status, text: r.status }); +} + +function renderTabs() { + const b = batch(); + const bar = $('rs-tabs'); + clear(bar); + for (const id of b.runs) { + const r = store.runs.get(id); + const sel = id === rv.tab; + const tab = el('button.rs-tab', { type: 'button', role: 'tab', 'aria-selected': String(sel), tabindex: sel ? 0 : -1, dataset: { run: id }, + title: r ? `${r.plugin} ${r.args.join(' ')}` : '', on: { click: () => selectTab(id) } }, + el('span', { class: 'rs-dot ' + (r ? r.status : '') }), + el('span.rs-tname', { text: r ? shortName(r.plugin) : 'run ' + id }), + r && r.args.length ? el('span.rs-targs', { text: r.args.join(' ') }) : null, + badge(r)); + bar.append(tab); + } + const cur = bar.querySelector('[aria-selected="true"]'); + if (cur) cur.scrollIntoView({ block: 'nearest', inline: 'nearest' }); +} + +function selectTab(id, focusTable = false) { + if (id === rv.tab) return; + rv.tab = id; + renderTabs(); + renderBody(); + document.dispatchEvent(new CustomEvent('fastvol-results', { detail: { batch: rv.batch, run: id } })); + const t = rv.tables.get(id); + if (focusTable && t && t.table) t.table.root.focus(); + else { const tab = $('rs-tabs').querySelector('[aria-selected="true"]'); if (tab) tab.focus(); } +} + +/** Step to the previous (-1) or next (+1) plugin tab. */ +export function stepTab(d) { + const b = batch(); + if (!b) return; + const k = b.runs.indexOf(rv.tab); + const next = b.runs[(k + d + b.runs.length) % b.runs.length]; + selectTab(next); +} + +/** The body of the chosen tab: a table once the plugin has columns, else its state. */ +function renderBody() { + const body = $('rs-body'); + const r = store.runs.get(rv.tab); + let t = rv.tables.get(rv.tab); + if (!t) { t = { node: el('div.rs-pane'), table: null }; rv.tables.set(rv.tab, t); } + body.replaceChildren(t.node); + fillPane(t, r); +} + +function fillPane(t, r) { + if (!r) { t.node.replaceChildren(el('div.wb-empty', { text: 'This plugin is no longer on the server.' })); return; } + if (r.status === 'failed' || r.status === 'cancelled') { + if (t.table) { t.table.destroy(); t.table = null; } + const e = r.error || {}; + t.node.replaceChildren(el('div.rs-state', {}, + el('div', { class: 'rs-state-t ' + r.status, text: e.title || (r.status === 'failed' ? 'The plugin failed' : 'Cancelled') }), + e.message ? el('div.rs-state-m', { text: e.message }) : null, + ...(e.hints || []).map(h => el('div.rs-state-h', { text: h })), + e.detail ? el('pre.rs-state-d', { text: e.detail }) : null)); + return; + } + if (!t.table && r.cols && r.cols.length) { + const table = new VirtualTable({ runId: r.id, plugin: r.plugin, label: `${shortName(r.plugin)} results` }); + table.q = rv.q; // the first view is built already filtered + t.table = table; + const q = el('input.wb-input.rs-q', { type: 'search', value: rv.q, placeholder: 'Filter rows', spellcheck: false, autocomplete: 'off', 'aria-label': 'Filter rows' }); + q.addEventListener('input', () => { rv.q = q.value; table.setQuery(q.value); saveFilter(); }); + q.addEventListener('keydown', e => { if (e.key === 'ArrowDown' || e.key === 'Enter') { e.preventDefault(); table.root.focus(); } }); + const colsBtn = el('button.wb-btn.ghost.sm', { type: 'button', text: 'Filters', title: 'A filter box per column: text, =exact, !not, >0x10, /regex/', on: { click: () => { table.toggleFilters(); colsBtn.classList.toggle('on', table.showFilters); } } }); + const exp = el('button.wb-btn.ghost.sm', { type: 'button', text: 'Export', title: 'Download the rows shown, with the visible columns' }); + exp.addEventListener('click', () => menu(exp, [ + ...EXPORTS.map(([f, label]) => ({ label, act: () => download(table.exportUrl(f)) })), + 'sep', + // what `fvol` prints for this plugin: -r, --filters and --hide-columns from Options + { label: 'fvol output', hint: 'as the command line', act: () => download(`/api/runs/${r.id}/vol`) }, + ])); + const count = el('span.rs-count'); + table.o.onState = () => { count.textContent = table.matched !== table.total || table.q ? `${fmtCount(table.matched)} of ${fmtCount(table.stored || table.total)} rows` : `${fmtCount(table.total)} rows`; }; + t.q = q; + t.node.replaceChildren(el('div.rs-tools', {}, q, colsBtn, el('span.rs-sp'), count, exp), table.root); + table.update(r); + return; + } + if (t.table) { + // coming back to a tab: apply the shared filter if it changed meanwhile + if (t.table.q !== rv.q) { t.q.value = rv.q; t.table.setQuery(rv.q); } + t.table.update(r); + return; + } + t.node.replaceChildren(el('div.wb-empty', {}, r.status === 'queued' + ? el('div', { text: 'Queued: waiting for a free slot (a few plugins run at a time).' }) + : [el('span.wb-spin'), 'Running…'])); +} + +export function focusResultsFilter() { + const t = rv.tables.get(rv.tab); + if (t && t.q) { t.q.focus(); t.q.select(); return true; } + return false; +} + +export function wireResults() { + $('rs-close').addEventListener('click', closeResults); + $('rs-tabs').addEventListener('keydown', e => { + if (e.key === 'ArrowRight') { e.preventDefault(); stepTab(1); } + if (e.key === 'ArrowLeft') { e.preventDefault(); stepTab(-1); } + if (e.key === 'ArrowDown' || e.key === 'Enter') { const t = rv.tables.get(rv.tab); if (t && t.table) { e.preventDefault(); t.table.root.focus(); } } + }); + on('runs', changed => { + const b = batch(); + if (!b || !changed) return; + const mine = changed.filter(r => b.runs.includes(r.id)); + if (!mine.length) return; + renderTabs(); + renderHead(); + if (!rv.timer && mine.some(r => ACTIVE(r.status))) rv.timer = setInterval(renderHead, 1000); + for (const r of mine) { + const t = rv.tables.get(r.id); + if (!t) continue; + if (r.id === rv.tab) fillPane(t, r); + else if (t.table) t.table.update(r); + } + }); + on('batches', () => { + if (rv.batch === null) return; + if (!batch()) { closeResults(); toast('That run was removed.'); return; } + renderHead(); + }); + on('session', ({ prev, cur }) => { if (prev && cur && prev.id !== cur.id) closeResults(); }); +} diff --git a/src/web/assets/rules.js b/src/web/assets/rules.js new file mode 100644 index 0000000..5ab66b1 --- /dev/null +++ b/src/web/assets/rules.js @@ -0,0 +1,107 @@ +// Triage rules: your own "worth a look" checks from a JSON file, matched in the browser against +// the process list. The format is in docs/web-ui.md (Triage rules). + +import { api, toast } from './core.js'; +import { captureTime } from './procdata.js'; + +export const FIELDS = { + name: p => p.name, + pid: p => p.pid, + ppid: p => p.ppid, + parent: p => (p.parent ? p.parent.name : null), + path: p => p.path ?? null, + cmdline: p => p.cmd ?? null, + threads: p => num(p.threads), + handles: p => num(p.handles), + session: p => num(p.session), + wow64: p => (p.wow64 === null || p.wow64 === undefined ? null : String(p.wow64).toLowerCase() === 'true'), + exited: p => p.exit !== null, + age: p => { const cap = captureTime(); return cap && p.create ? cap - p.create : null; }, +}; +const SEVERITIES = ['high', 'medium', 'low']; + +function num(v) { + if (v === null || v === undefined) return null; + const n = typeof v === 'number' ? v : Number(String(v).trim()); + return Number.isFinite(n) ? n : null; +} +function int0(s) { + const t = s.trim().toLowerCase(); + const n = /^-?0x[0-9a-f]+$/.test(t) ? parseInt(t, 16) : /^-?\d+(\.\d+)?$/.test(t) ? Number(t) : NaN; + return Number.isFinite(n) ? n : null; +} + +/** Compile one match value into a test function; throws with a readable message. */ +function matcher(field, spec) { + if (typeof spec === 'boolean') return v => v === spec; + if (typeof spec === 'number') return v => v === spec; + if (typeof spec !== 'string') throw new Error(`"${field}" must be text, a number or true/false`); + const re = /^\/(.*)\/([a-z]*)$/s.exec(spec); + if (re) { + let rx; + try { rx = new RegExp(re[1], re[2]); } catch (e) { throw new Error(`"${field}": bad regular expression: ${e.message}`); } + return v => v !== null && rx.test(String(v)); + } + const cmp = /^(>=|<=|>|<|=)\s*(.+)$/.exec(spec); + if (cmp && int0(cmp[2]) !== null) { + const n = int0(cmp[2]); + const op = { '>': (a, b) => a > b, '<': (a, b) => a < b, '>=': (a, b) => a >= b, '<=': (a, b) => a <= b, '=': (a, b) => a === b }[cmp[1]]; + return v => typeof v === 'number' && op(v, n); + } + if (spec.startsWith('=')) { const t = spec.slice(1).toLowerCase(); return v => v !== null && String(v).toLowerCase() === t; } + if (spec.startsWith('!')) { const t = spec.slice(1).toLowerCase(); return v => v === null || !String(v).toLowerCase().includes(t); } + const t = spec.toLowerCase(); + return v => v !== null && String(v).toLowerCase().includes(t); +} + +/** Parse and check a rules file. Returns { name, rules: [{ title, description, severity, test }] }. */ +export function compileRules(text, fileName) { + let j; + try { j = JSON.parse(text); } catch (e) { throw new Error(`not valid JSON: ${e.message}`); } + const list = Array.isArray(j) ? j : j && Array.isArray(j.rules) ? j.rules : null; + if (!list) throw new Error('expected {"rules": [ ... ]}'); + const rules = list.map((r, i) => { + const where = `rule ${i + 1}${r && r.title ? ` ("${r.title}")` : ''}`; + if (!r || typeof r !== 'object') throw new Error(`${where}: must be an object`); + if (typeof r.title !== 'string' || !r.title.trim()) throw new Error(`${where}: needs a "title"`); + if (!r.match || typeof r.match !== 'object' || !Object.keys(r.match).length) throw new Error(`${where}: needs a "match" with at least one field`); + const sev = r.severity === undefined ? 'medium' : r.severity; + if (!SEVERITIES.includes(sev)) throw new Error(`${where}: "severity" must be ${SEVERITIES.join(', ')}`); + const tests = Object.entries(r.match).map(([f, spec]) => { + if (!FIELDS[f]) throw new Error(`${where}: unknown field "${f}" (use ${Object.keys(FIELDS).join(', ')})`); + try { const m = matcher(f, spec); return p => m(FIELDS[f](p)); } catch (e) { throw new Error(`${where}: ${e.message}`); } + }); + return { title: r.title.trim(), description: typeof r.description === 'string' ? r.description : '', severity: sev, test: p => tests.every(t => t(p)) }; + }); + return { name: (j && typeof j.name === 'string' && j.name.trim()) || fileName, file: fileName, rules }; +} + +// the loaded rules; the server keeps the file with the saved analysis (~/.fvol/-metadata.json) +let loaded = null; + +/** The rules of the open analysis, from the server. */ +export async function loadSavedRules() { + let saved = null; + try { saved = await api('rules'); } catch (e) { saved = null; } + loaded = null; + if (saved && saved.text) { + try { loaded = compileRules(saved.text, saved.file); } catch (e) { toast(`${saved.file}: ${e.message}`, 'bad'); } + } + return loaded; +} +export function setRules(text, file) { + loaded = compileRules(text, file); // throws on a bad file: the old rules stay + api('rules', { method: 'POST', body: { file, text } }).catch(e => toast('Could not save the rules: ' + e.message, 'bad')); + return loaded; +} +export function clearRules() { + loaded = null; + api('rules', { method: 'DELETE' }).catch(e => toast('Could not remove the rules: ' + e.message, 'bad')); +} +export function currentRules() { return loaded; } + +/** Triage groups from the loaded rules, in file order. */ +export function ruleGroups(procs) { + if (!loaded) return []; + return loaded.rules.map(r => ({ key: 'rule:' + r.title, title: r.title, sub: r.description, hot: r.severity !== 'low', rule: true, severity: r.severity, list: procs.filter(r.test) })); +} diff --git a/src/web/assets/table.js b/src/web/assets/table.js index d3c1127..0fd5c11 100644 --- a/src/web/assets/table.js +++ b/src/web/assets/table.js @@ -5,6 +5,7 @@ import { api, fetchRows, el, clear, copy, debounce, prefs, cellText, menu } from './core.js'; const PAGE = 256; +const LEVEL = 14; // px per tree level (indent guides) const MAX_PX = 15_000_000; // stay well below browser element-height limits const NUMERIC = new Set(['Int', 'Float', 'Bin']); let uid = 0; @@ -99,6 +100,9 @@ export class VirtualTable { this.hidden = new Set(cols.map((c, i) => (hid.includes(c.name) ? i : -1)).filter(i => i >= 0)); if (this.hidden.size === cols.length) this.hidden.clear(); this.savedWidths = (saved && saved.widths) || {}; + const names = cols.map(c => c.name); + const known = ((saved && saved.order) || []).map(n => names.indexOf(n)).filter(i => i >= 0); + this.order = [...new Set([...known, ...cols.map((_, i) => i)])]; this.widths = cols.map(c => this.savedWidths[c.name] || this.guessWidth(c, [])); this.autosized = false; this.cur.col = this.visible()[0] || 0; @@ -191,13 +195,31 @@ export class VirtualTable { return null; } + /** Tree guides of row `vi` at `depth`, one character per level 1..depth: "v" a line passing + * through (an ancestor has more children below), " " nothing, and for the row's own level + * "t" (├, more siblings follow) or "e" (└, the last child). Found by looking ahead through the + * loaded rows: a level continues when a later row returns to it before anything shallower. */ + guides(vi, depth) { + const out = new Array(depth).fill('v'); + let top = depth; // deepest level not decided yet + for (let k = vi + 1; top > 0 && k < this.total && k < vi + 4096; k++) { + const r = this.rowAt(k); + if (!r) break; // not loaded: assume the lines continue + const d = r[1] >> 2; + while (top >= 1 && top >= d) { out[top - 1] = top === d ? 'v' : ' '; top--; } + } + if (vi + 1 >= this.total) for (let l = top; l >= 1; l--) out[l - 1] = ' '; + out[depth - 1] = out[depth - 1] === 'v' ? 't' : 'e'; + return out.join(''); + } + /** Row data at view index `i` (array [idx, flags, ...cells]) or undefined if not loaded. */ rowAt(i) { const p = this.pages.get(Math.floor(i / PAGE)); return p ? p[i % PAGE] : undefined; } - visible() { return this.cols.map((_, i) => i).filter(i => !this.hidden.has(i)); } + visible() { return (this.order || this.cols.map((_, i) => i)).filter(i => !this.hidden.has(i)); } // ------------------------------------------------------------------ layout charW() { @@ -224,12 +246,22 @@ export class VirtualTable { } chars = Math.max(c.name.length + 3, Math.min(m + 1, c.type === 'Str' ? 64 : 40), 4); } - return Math.round(chars * cw + 18); + let extra = 0; + if (rows.length && i === 0) { + let d = 0; + for (const r of rows) d = Math.max(d, r[1] >> 2); + if (d) extra = d * LEVEL + 4; + } + return Math.round(chars * cw + 18 + extra); } autosize(rows) { this.autosized = true; - this.widths = this.cols.map((c, i) => this.savedWidths[c.name] || this.guessWidth(c, rows, i)); + const first = 0; // the tree column + // a remembered width never hides the tree: its column is at least as wide as the nesting needs + this.widths = this.cols.map((c, i) => i === first && rows.some(r => r[1] >> 2) + ? Math.max(this.savedWidths[c.name] || 0, this.guessWidth(c, rows, i)) + : this.savedWidths[c.name] || this.guessWidth(c, rows, i)); this.applyWidths(); } @@ -242,7 +274,7 @@ export class VirtualTable { const widths = {}; this.cols.forEach((c, i) => { if (this.userSized && this.userSized.has(i)) widths[c.name] = this.widths[i]; }); const prev = prefs.get('cols:' + this.o.plugin, {}) || {}; - prefs.set('cols:' + this.o.plugin, { widths: { ...(prev.widths || {}), ...widths }, hidden: [...this.hidden].map(i => this.cols[i].name) }); + prefs.set('cols:' + this.o.plugin, { widths: { ...(prev.widths || {}), ...widths }, hidden: [...this.hidden].map(i => this.cols[i].name), order: this.order.map(i => this.cols[i].name) }); } buildHead() { @@ -268,7 +300,8 @@ export class VirtualTable { grip.addEventListener('dblclick', e => { e.stopPropagation(); this.fitColumn(i); }); grip.addEventListener('click', e => e.stopPropagation()); cell.append(grip); - cell.addEventListener('click', e => this.toggleSort(i, e.shiftKey)); + cell.addEventListener('mousedown', e => this.startMove(e, i, cell)); + cell.addEventListener('click', e => { if (this.moved) { this.moved = false; return; } this.toggleSort(i, e.shiftKey); }); cell.addEventListener('contextmenu', e => { e.preventDefault(); this.columnMenu(cell, i); }); hrow.append(cell); } @@ -376,15 +409,79 @@ export class VirtualTable { addEventListener('mouseup', up); } + /** Fit a column to its widest value among the loaded rows (and its header), measured with + * the fonts actually used; the tree column adds its indentation. */ fitColumn(i) { - const rows = []; - for (let k = this.firstRow || 0; k < (this.firstRow || 0) + 200; k++) { const r = this.rowAt(k); if (r) rows.push(r); } - this.widths[i] = this.guessWidth(this.cols[i], rows, i); + const c = this.cols[i]; + const ctx = (VirtualTable._fit ||= document.createElement('canvas').getContext('2d')); + const cellFont = getComputedStyle(this.root).font; + const hcell = this.head.querySelector(`.vt-hcell[data-col="${i}"]`); + ctx.font = hcell ? getComputedStyle(hcell).font : cellFont; + let w = ctx.measureText(c.name).width + (hcell ? 16 + (typeLabel(c.type) ? ctx.measureText(typeLabel(c.type)).width + 12 : 0) + (hcell.querySelector('.so') ? 18 : 0) : 16); + ctx.font = cellFont; + let depth = 0; + const start = Math.max(0, (this.firstRow || 0) - PAGE); + for (let k = start; k < Math.min(this.total, start + 3 * PAGE); k++) { + const r = this.rowAt(k); + if (!r) continue; + const v = r[i + 2]; + const text = v === null ? '-' : v === 0 ? 'N/A' : String(v).split('\n')[0]; + w = Math.max(w, ctx.measureText(text).width + 18); + if (i === 0) depth = Math.max(depth, r[1] >> 2); + } + this.widths[i] = Math.round(Math.min(900, Math.max(40, w + (depth ? depth * LEVEL + 4 : 0)))); (this.userSized ||= new Set()).add(i); this.applyWidths(); this.saveCols(); } + /** Drag a header sideways to move its column; a green line marks where it will land. */ + startMove(e, i, cell) { + if (e.button !== 0 || e.target.classList.contains('grip')) return; + const x0 = e.clientX; + let marker = null, target = null; + const cells = () => [...this.head.querySelectorAll('.vt-hrow .vt-hcell')]; + const move = ev => { + if (!marker && Math.abs(ev.clientX - x0) < 6) return; + if (!marker) { + marker = el('div.vt-drop'); + this.head.append(marker); + cell.classList.add('moving'); + document.body.classList.add('col-moving'); + } + // the gap nearest the pointer: before cell k, or after the last one + const cs = cells(); + const hr = this.head.getBoundingClientRect(); + let k = cs.length; + for (let j = 0; j < cs.length; j++) { const r = cs[j].getBoundingClientRect(); if (ev.clientX < r.left + r.width / 2) { k = j; break; } } + target = k; + const edge = k < cs.length ? cs[k].getBoundingClientRect().left : cs[cs.length - 1].getBoundingClientRect().right; + marker.style.left = (edge - hr.left - 1) + 'px'; + }; + const up = () => { + removeEventListener('mousemove', move); + removeEventListener('mouseup', up); + if (!marker) return; + marker.remove(); + cell.classList.remove('moving'); + document.body.classList.remove('col-moving'); + this.moved = true; // swallow the click that follows, so the drop does not also sort + setTimeout(() => { this.moved = false; }, 0); + const vis = this.visible(); + const before = target < vis.length ? vis[target] : null; + if (before === i) return; + const order = this.order.filter(x => x !== i); + const at = before === null ? order.length : order.indexOf(before); + order.splice(at, 0, i); + if (order.join() === this.order.join()) return; + this.order = order; + this.buildHead(); + this.saveCols(); + }; + addEventListener('mousemove', move); + addEventListener('mouseup', up); + } + async copyColumn(i) { const out = []; const n = Math.min(this.total, 20000); @@ -471,7 +568,7 @@ export class VirtualTable { for (let j = 0; j < vis.length; j++) { const ci = vis[j]; const cell = rowEl._cells[j]; - this.fillCell(cell, ci, row[ci + 2], j === 0 ? depth : -1); + this.fillCell(cell, ci, row[ci + 2], ci === 0 ? depth : -1, ci === 0 && depth > 0 ? this.guides(vi, depth) : ''); if (isCur && ci === this.cur.col) { cell.classList.add('cc'); active = cell; } } } @@ -480,22 +577,32 @@ export class VirtualTable { this.renderEmpty(); } - fillCell(cell, ci, v, depth) { + fillCell(cell, ci, v, depth, guides = '') { const c = this.cols[ci]; const key = v === null ? '\u0000n' : v === 0 ? '\u0000a' : v; - if (cell._v === key && cell._ci === ci && cell._d === depth) { + if (cell._v === key && cell._ci === ci && cell._d === depth && cell._g === guides) { return; } - cell._v = key; cell._ci = ci; cell._d = depth; + cell._v = key; cell._ci = ci; cell._d = depth; cell._g = guides; let cls = 'vt-cell'; - if (depth >= 0) { cls += ' t0'; cell.style.setProperty('--d', depth); if (depth > 0) cls += ' tree'; } + const tree = depth >= 0; + if (tree) { cls += ' t0'; cell.style.paddingLeft = depth > 0 ? `${8 + depth * LEVEL + 4}px` : ''; } + else cell.style.paddingLeft = ''; + // the tree column is left-aligned so a value sits right after its connector + const finish = () => { + if (!guides) return; + const g = el('span.tg', { 'aria-hidden': 'true' }); + for (const ch of guides) g.append(el('i', { class: ch === 'v' ? 'v' : ch === 't' ? 't' : ch === 'e' ? 'e' : '' })); + cell.prepend(g); + }; if (v === null || v === 0) { cell.className = cls + ' ab'; cell.textContent = v === null ? '-' : 'N/A'; + finish(); return; } const t = c.type; - if (NUMERIC.has(t)) cls += ' num'; + if (NUMERIC.has(t) && !tree) cls += ' num'; if (t === 'Hex') cls += ' hex link'; if (t === 'Int' && /^(PID|PPID|Pid|PPid|Process ID)$/.test(c.name) && this.o.onPid) cls += ' pidlink'; cell.className = cls; @@ -505,14 +612,17 @@ export class VirtualTable { const firstLine = lines.find(l => l.trim()) || ''; clear(cell); cell.append(firstLine, el('span.ml', { text: `${lines.length} lines` })); + finish(); return; } if (t === 'DateTime' && v.length > 19) { clear(cell); cell.append(v.slice(0, 19), el('span.dim', { text: v.slice(19) })); + finish(); return; } cell.textContent = v; + finish(); } renderEmpty() { diff --git a/src/web/assets/ui.css b/src/web/assets/ui.css new file mode 100644 index 0000000..dbeaa96 --- /dev/null +++ b/src/web/assets/ui.css @@ -0,0 +1,642 @@ +/* fastvol web UI — "workbench": the new design system. + Graphite surfaces, the logo's green as the one accent, a sans-serif for the interface and + monospace only for data (PIDs, addresses, hex). No external resources. + Tokens are named apart from app.css so both can coexist while the views are rewritten. */ + +:root { + /* the platform's own fonts, as native tools use them: Segoe UI / Consolas on Windows, + SF / Menlo on macOS, the desktop's font (Noto Sans / Noto Sans Mono on KDE) on Linux */ + --font-ui: system-ui, "Segoe UI", -apple-system, BlinkMacSystemFont, "Noto Sans", Cantarell, Ubuntu, "DejaVu Sans", sans-serif; + --font-mono: ui-monospace, Consolas, Menlo, "SF Mono", monospace, monospace; + + --bg-0: #101214; /* app background */ + --bg-1: #16191c; /* panels */ + --bg-2: #1d2125; /* raised: inputs, tiles */ + --bg-3: #252a2f; /* hover */ + --bd: #2a2f35; /* hairlines */ + --bd-2: #3a4148; /* input borders, strong lines */ + --fg: #e7e9ec; /* primary text */ + --fg-2: #aab1b9; /* secondary text */ + --fg-3: #7a828b; /* hints, meta */ + --acc: #46e67a; /* the logo's green */ + --acc-hover: #6bef96; + --acc-ink: #06210f; /* text on the accent */ + --acc-fg: #5cea8a; /* accent used as text/icons */ + --acc-soft: rgba(70, 230, 122, .10); + --acc-line: rgba(70, 230, 122, .45); + --bad: #ff6b6b; + --warn: #f0b429; + --radius: 8px; + --radius-s: 5px; + --shadow-lg: 0 24px 80px rgba(0, 0, 0, .55), 0 2px 10px rgba(0, 0, 0, .35); +} + +:root[data-theme="light"] { + --bg-0: #f4f5f7; + --bg-1: #ffffff; + --bg-2: #f7f8fa; + --bg-3: #eceef1; + --bd: #e3e6ea; + --bd-2: #cfd4da; + --fg: #16191c; + --fg-2: #4d555e; + --fg-3: #7b838c; + --acc: #1fa34f; + --acc-hover: #178a41; + --acc-ink: #ffffff; + --acc-fg: #15803d; + --acc-soft: rgba(31, 163, 79, .09); + --acc-line: rgba(31, 163, 79, .45); + --bad: #d92d2d; + --shadow-lg: 0 24px 70px rgba(20, 30, 40, .18), 0 2px 8px rgba(20, 30, 40, .08); +} + +/* ------------------------------------------------------------------ quick start */ + +.qs { + position: fixed; inset: 0; z-index: 200; + display: grid; place-items: center; padding: 24px; + background: var(--bg-0); + font-family: var(--font-ui); font-size: 14px; line-height: 1.45; color: var(--fg); +} +.qs *, .qs *::before, .qs *::after { box-sizing: border-box; } +.qs[hidden] { display: none; } + +.qs-win { + width: min(1040px, 100%); height: min(640px, 100%); + display: grid; grid-template-columns: 340px 1fr; + background: var(--bg-1); border: 1px solid var(--bd); border-radius: 12px; + box-shadow: var(--shadow-lg); overflow: hidden; +} + +/* left: brand + choices */ +.qs-side { display: flex; flex-direction: column; padding: 28px 22px 20px; border-right: 1px solid var(--bd); min-height: 0; } +.qs-brand { padding: 0 6px 22px; } +.qs-brand svg { display: block; width: 215px; height: 40px; color: var(--fg); } +.qs-ver { margin-top: 12px; font-size: 12px; color: var(--fg-3); } +.qs-h { margin: 6px 6px 8px; font-size: 12px; font-weight: 600; color: var(--fg-3); } + +.qs-choices { display: flex; flex-direction: column; gap: 4px; } +.qs-choice { + display: grid; grid-template-columns: 34px 1fr auto; align-items: center; gap: 12px; + width: 100%; padding: 10px 10px; text-align: left; + font: inherit; color: var(--fg); background: transparent; + border: 1px solid transparent; border-radius: var(--radius); cursor: pointer; +} +.qs-choice:hover { background: var(--bg-2); } +.qs .qs-choice:focus { outline: none; } +.qs .qs-choice:focus-visible { outline: 2px solid var(--acc-line); outline-offset: 1px; } +.qs-choice[aria-pressed="true"] { background: var(--acc-soft); border-color: var(--acc-line); } +.qs-ico { + display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-s); + background: var(--bg-2); border: 1px solid var(--bd); color: var(--fg-2); +} +.qs-choice[aria-pressed="true"] .qs-ico { color: var(--acc-fg); border-color: var(--acc-line); } +.qs-ico svg { width: 17px; height: 17px; } +.qs-ct { font-weight: 600; font-size: 14px; } +.qs-cd { font-size: 12.5px; color: var(--fg-3); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.qs-key { font: 11px var(--font-mono); color: var(--fg-3); border: 1px solid var(--bd); border-radius: 4px; padding: 1px 5px; } + +.qs-foot { margin-top: auto; padding: 0 6px; font-size: 12px; color: var(--fg-3); display: flex; gap: 14px; align-items: center; } + +/* right: the panel for the selected choice */ +.qs-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 26px 28px 22px; } +.qs-title { margin: 0; font-size: 20px; font-weight: 600; } +.qs-sub { margin: 4px 0 18px; color: var(--fg-2); font-size: 13.5px; } + +.qs .qs-input { + width: 100%; height: 36px; padding: 0 12px; + font: 13px var(--font-mono); color: var(--fg); + background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); +} +.qs .qs-input::placeholder { color: var(--fg-3); } +.qs .qs-input:focus { outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft); } + +.qs-crumbs { display: flex; flex-wrap: wrap; gap: 2px; align-items: center; margin: 12px 0 8px; font-size: 13px; color: var(--fg-3); } +.qs-crumbs button { font: inherit; color: var(--fg-2); background: none; border: 0; padding: 2px 5px; border-radius: 4px; cursor: pointer; } +.qs-crumbs button:hover { color: var(--fg); background: var(--bg-3); } +.qs-crumbs button:last-child { color: var(--fg); font-weight: 600; } + +.qs-files { flex: 1; min-height: 0; overflow: auto; border: 1px solid var(--bd); border-radius: var(--radius); background: var(--bg-0); } +.qs-file { + display: grid; grid-template-columns: 22px 1fr auto auto; gap: 10px; align-items: center; + width: 100%; padding: 7px 12px; text-align: left; + font: inherit; font-size: 13.5px; color: var(--fg); background: none; + border: 0; border-bottom: 1px solid var(--bd); cursor: pointer; +} +.qs-file:last-child { border-bottom: 0; } +.qs-file:hover { background: var(--bg-2); } +.qs-file:focus-visible { outline: none; background: var(--bg-3); } +.qs-file[aria-selected="true"] { background: var(--acc-soft); box-shadow: inset 3px 0 0 var(--acc); } +.qs-file .fi { color: var(--fg-3); display: grid; place-items: center; } +.qs-file .fi svg { width: 16px; height: 16px; } +.qs-file .fn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.qs-file.dir .fn { color: var(--fg); } +.qs-file.other .fn { color: var(--fg-2); } +.qs-file .fs { font: 12px var(--font-mono); color: var(--fg-3); } +.qs-tag { font-size: 11px; font-weight: 600; color: var(--acc-fg); background: var(--acc-soft); border: 1px solid var(--acc-line); border-radius: 99px; padding: 0 7px; } +.qs-empty { padding: 28px 16px; text-align: center; color: var(--fg-3); font-size: 13px; } + +.qs-actions { display: flex; align-items: center; gap: 10px; margin-top: 16px; } +.qs-err { flex: 1; color: var(--bad); font-size: 13px; } +.qs-picked { flex: 1; min-width: 0; font: 12.5px var(--font-mono); color: var(--fg-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +.qs-btn { + height: 36px; padding: 0 16px; font: 600 13.5px var(--font-ui); + color: var(--fg); background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); cursor: pointer; +} +.qs-btn:hover { background: var(--bg-3); } +.qs-btn.primary { color: var(--acc-ink); background: var(--acc); border-color: var(--acc); } +.qs-btn.primary:hover { background: var(--acc-hover); border-color: var(--acc-hover); } +.qs-btn.outline { color: var(--acc-fg); background: transparent; border-color: var(--acc); } +.qs-btn.outline:hover { background: var(--acc-soft); border-color: var(--acc-hover); } +.qs-btn:disabled { opacity: .45; cursor: default; } +.qs-btn:focus-visible { outline: 2px solid var(--acc-line); outline-offset: 2px; } + +.qs-pathrow { display: flex; gap: 8px; } +.qs-pathrow .qs-input { flex: 1; min-width: 0; } +.qs-btn { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; } +.qs-btn .btn-ico { width: 16px; height: 16px; } +.qs-btn[hidden] { display: none; } + +.qs-current { width: 100%; display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; padding: 16px 18px; text-align: left; background: var(--bg-2); border: 1px solid var(--bd); border-radius: var(--radius); font-size: 13px; } +.qs-current dt { color: var(--fg-3); } +.qs-current dd { margin: 0; font-family: var(--font-mono); color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +@media (max-width: 760px) { + .qs { padding: 0; } + .qs-win { grid-template-columns: 1fr; grid-template-rows: auto 1fr; height: 100%; border-radius: 0; } + .qs-side { border-right: 0; border-bottom: 1px solid var(--bd); } + .qs-foot { display: none; } +} + +/* ------------------------------------------------------------------ base */ + +*, *::before, *::after { box-sizing: border-box; } +html, body { height: 100%; margin: 0; } +body { + display: flex; flex-direction: column; overflow: hidden; + background: var(--bg-0); color: var(--fg); + font: 13px/1.4 var(--font-ui); +} +button { font: inherit; } +[hidden] { display: none !important; } +:focus-visible { outline: 2px solid var(--acc-line); outline-offset: 1px; } +::selection { background: var(--acc-soft); } + +/* ------------------------------------------------------------------ top bar */ + +.wb-top { + flex: none; display: flex; align-items: center; gap: 18px; + height: 48px; padding: 0 16px; + background: var(--bg-1); border-bottom: 1px solid var(--bd); +} +.wb-brand { display: flex; align-items: center; } +.wb-brand svg { display: block; width: 107px; height: 20px; color: var(--fg); } +.wb-ev { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 12px; padding-left: 18px; border-left: 1px solid var(--bd); } +.wb-ev-name { font-weight: 600; white-space: nowrap; } +.wb-ev-meta { font-size: 12.5px; color: var(--fg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.wb-top-actions { display: flex; align-items: center; gap: 8px; } +.wb-btn { + height: 30px; padding: 0 12px; font-size: 13px; font-weight: 600; + color: var(--fg); background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); cursor: pointer; +} +.wb-btn:hover { background: var(--bg-3); } +.wb-btn.ghost { background: transparent; color: var(--fg-2); border-color: var(--bd); } +.wb-btn.ghost:hover { color: var(--fg); background: var(--bg-2); } +.wb-icon { display: grid; place-items: center; width: 30px; height: 30px; color: var(--fg-2); background: none; border: 1px solid transparent; border-radius: var(--radius-s); cursor: pointer; } +.wb-icon:hover { color: var(--fg); background: var(--bg-2); } + +/* ------------------------------------------------------------------ three columns */ + +/* sizes come from the splitters (layout.js): --c1 overview width, --c3 right column width, + --r1 Runs height; each has a minimum so no panel can be squeezed away */ +.wb { + flex: 1; min-height: 0; outline: none; + display: grid; background: var(--bg-0); + grid-template-columns: minmax(220px, var(--c1, 28%)) 5px minmax(360px, 1fr) 5px minmax(260px, var(--c3, 24%)); + grid-template-rows: minmax(90px, var(--r1, 1fr)) 5px minmax(90px, 1fr); + grid-template-areas: "ov s1 pl s2 rn" "ov s1 pl s2 s3" "ov s1 pl s2 tr"; +} +.wb-split { position: relative; z-index: 5; background: var(--bg-0); touch-action: none; outline: none; } +.wb-split::after { content: ""; position: absolute; background: var(--bd); } +.wb-split.v { cursor: col-resize; } +.wb-split.v::after { left: 2px; top: 0; bottom: 0; width: 1px; } +.wb-split.h { cursor: row-resize; } +.wb-split.h::after { top: 2px; left: 0; right: 0; height: 1px; } +.wb-split:hover::after, .wb-split.drag::after, .wb-split:focus-visible::after { background: var(--acc); } +.wb-split.v:hover::after, .wb-split.v.drag::after, .wb-split.v:focus-visible::after { left: 1px; width: 3px; } +.wb-split.h:hover::after, .wb-split.h.drag::after, .wb-split.h:focus-visible::after { top: 1px; height: 3px; } +#s1 { grid-area: s1; } +#s2 { grid-area: s2; } +#s3 { grid-area: s3; } +body.resizing, body.resizing * { user-select: none !important; } +body.resizing.v, body.resizing.v * { cursor: col-resize !important; } +body.resizing.h, body.resizing.h * { cursor: row-resize !important; } +.wb-overview { grid-area: ov; } +.wb-plugins { grid-area: pl; } +.wb-runs { grid-area: rn; } +.wb-triage { grid-area: tr; } + +.wb-panel { display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--bg-1); } +.wb-ph { flex: none; display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 14px; border-bottom: 1px solid var(--bd); } +.wb-ph h2 { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--fg); } +.wb-count { font: 11.5px var(--font-mono); color: var(--fg-3); } +.wb-pb { flex: 1; min-height: 0; overflow: auto; } + +.wb-empty { padding: 28px 18px; text-align: center; color: var(--fg-3); font-size: 13px; } +.wb-empty-sub { margin-top: 4px; font-size: 12.5px; } +.wb-spin { display: inline-block; width: 12px; height: 12px; margin-right: 8px; vertical-align: -1px; border: 2px solid var(--bd-2); border-top-color: var(--acc); border-radius: 50%; animation: wb-spin .8s linear infinite; } +@keyframes wb-spin { to { transform: rotate(360deg); } } + +/* ------------------------------------------------------------------ file overview: a terminal */ + +:root { + --t-bg: #0a0c0d; --t-fg: #c9d1c9; --t-key: #6f8a76; --t-dim: #5d6b62; --t-prompt: #46e67a; + --t-hi: #eef5ee; --t-addr: #7cc4ff; --t-ok: #46e67a; --t-bad: #ff6b6b; +} +:root[data-theme="light"] { + --t-bg: #eceef0; --t-fg: #23282d; --t-key: #5f6b64; --t-dim: #7d8791; --t-prompt: #15803d; + --t-hi: #0e1113; --t-addr: #1d5fb4; --t-ok: #15803d; --t-bad: #c42b2b; +} +.wb-overview { background: var(--t-bg); } +.wb-overview .wb-ph { background: var(--bg-1); } +.term { + padding: 12px 14px 18px; + font: 12px/1.55 var(--font-mono); + color: var(--t-fg); background: var(--t-bg); +} +.term .tl { display: flex; white-space: pre-wrap; overflow-wrap: anywhere; min-height: 1.6em; } +.term .tk { flex: none; color: var(--t-key); white-space: pre; margin-right: 1ch; } +.term .tv { flex: 1; min-width: 0; } +.term .tv.hi { color: var(--t-hi); font-weight: 700; } +.term .tv.addr { color: var(--t-addr); } +.term .tv.ok { color: var(--t-ok); } +.term .tv.bad, .term .bad { color: var(--t-bad); } +.term .tp { color: var(--t-hi); } +.term .tpr { color: var(--t-prompt); white-space: pre; } +.term .tc, .term .tdim { color: var(--t-dim); } +@keyframes wb-blink { 50% { opacity: 0; } } + +/* ------------------------------------------------------------------ plugins */ + +.wb-plugins .wb-pb { display: flex; flex-direction: column; overflow: hidden; } +.pl-tools { flex: none; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding: 12px 14px; border-bottom: 1px solid var(--bd); } +.wb-input { + flex: 1 1 220px; height: 32px; padding: 0 11px; + font: 13.5px var(--font-ui); color: var(--fg); + background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); +} +.wb-input::placeholder { color: var(--fg-3); } +.wb-input:focus { outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft); } +.wb-seg { display: flex; padding: 2px; gap: 2px; background: var(--bg-2); border: 1px solid var(--bd); border-radius: var(--radius-s); } +.wb-seg button { height: 26px; padding: 0 9px; font-size: 12.5px; color: var(--fg-2); background: none; border: 0; border-radius: 4px; cursor: pointer; } +.wb-seg button span { margin-left: 6px; font: 11px var(--font-mono); color: var(--fg-3); } +.wb-seg button:hover { color: var(--fg); } +.wb-seg button[aria-selected="true"] { color: var(--fg); background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--bd-2); } +.wb-seg button[aria-selected="true"] span { color: var(--acc-fg); } + +.pl-list { flex: 1; min-height: 0; overflow: auto; } +.pl-row { + display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; gap: 12px; align-items: center; + padding: 8px 14px; border-bottom: 1px solid var(--bd); cursor: pointer; user-select: none; +} +.pl-row:hover { background: var(--bg-2); } +.pl-row:focus-visible { outline: none; background: var(--bg-3); } +.pl-row.on { background: var(--acc-soft); box-shadow: inset 3px 0 0 var(--acc); } +.pl-text { min-width: 0; } +.pl-main { display: flex; align-items: baseline; gap: 10px; min-width: 0; } +.pl-name { font-weight: 600; white-space: nowrap; } +.pl-full { font: 11.5px var(--font-mono); color: var(--fg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.pl-desc { font-size: 12.5px; color: var(--fg-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.pl-opts { font-size: 11.5px; color: var(--fg-3); white-space: nowrap; } +.pl-row.on .pl-opts { color: var(--acc-fg); } + +.wb-check { width: 15px; height: 15px; margin: 0; accent-color: var(--acc); cursor: pointer; } + +/* the options of a ticked plugin, unfolded under its row */ +.pl-options { display: flex; flex-direction: column; gap: 2px; padding: 6px 14px 10px 42px; background: var(--acc-soft); border-bottom: 1px solid var(--bd); box-shadow: inset 3px 0 0 var(--acc); } +.po-row { display: grid; align-items: center; gap: 4px 10px; padding: 4px 0; font-size: 12.5px; } +.po-flag { grid-template-columns: 16px auto minmax(0, 1fr); cursor: pointer; } +.po-value { grid-template-columns: minmax(130px, auto) minmax(140px, 260px) minmax(0, 1fr); } +.po-flagname, .po-flagname code { font: 12px var(--font-mono); color: var(--fg); white-space: nowrap; } +.po-req { margin-left: 6px; font: 11px var(--font-ui); color: var(--warn); } +.po-desc { color: var(--fg-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.wb-input.po-input { flex: none; height: 28px; font: 12px var(--font-mono); } +.wb-select { height: 28px; padding: 0 8px; font: 12.5px var(--font-ui); color: var(--fg); background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); } +.wb-select:focus { outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft); } + +.wb-btn.primary { display: inline-flex; align-items: center; gap: 7px; padding: 0 14px; color: var(--acc-ink); background: var(--acc); border-color: var(--acc); } +.wb-btn.primary:hover { background: var(--acc-hover); border-color: var(--acc-hover); } +.wb-btn.outline { color: var(--acc-fg); background: transparent; border-color: var(--acc); } +.wb-btn.outline:hover { background: var(--acc-soft); border-color: var(--acc-hover); } +.wb-btn:disabled { opacity: .5; cursor: default; } +.rb-play { width: 0; height: 0; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent currentColor; } + +/* the Plugins header: Presets at 1/4, Select at 1/2, Save Preset at 3/4, Run at the end */ +.pl-head { position: relative; } +.pl-head .wb-tabs { display: contents; } +.pl-head .at-25, .pl-head .at-50, .pl-head .at-75 { position: absolute; top: 50%; transform: translate(-50%, -50%); } +.pl-head .at-25 { left: 25%; } +.pl-head .at-50 { left: 50%; } +.pl-head .at-75 { left: 75%; } +.pl-head .pl-run { margin-left: auto; } +.pl-head .wb-btn { height: 28px; } +.wb-tabs button { height: 40px; padding: 0 10px; font-size: 13px; color: var(--fg-3); background: none; border: 0; border-bottom: 2px solid transparent; cursor: pointer; } +.pl-head .wb-tabs button { transform: translate(-50%, -50%); } +.wb-tabs button:hover { color: var(--fg); } +.wb-tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--acc); } + +/* ------------------------------------------------------------------ runs */ + +.rn-list { list-style: none; margin: 0; padding: 0; } +.rn-batch { border-bottom: 1px solid var(--bd); } +.rn-head { + display: grid; grid-template-columns: 12px minmax(0, 1fr) auto auto auto; gap: 10px; align-items: center; + padding: 8px 12px 8px 10px; cursor: pointer; user-select: none; +} +.rn-head:hover { background: var(--bg-2); } +.rn-head:focus-visible { outline: none; background: var(--bg-3); } +.rn-caret { width: 0; height: 0; border-style: solid; border-width: 4px 0 4px 6px; border-color: transparent transparent transparent var(--fg-3); transition: transform .12s ease; justify-self: center; } +.rn-batch.open .rn-caret { transform: rotate(90deg); } +.rn-bname { min-width: 0; padding: 0; font: 600 13.5px var(--font-ui); color: var(--fg); text-align: left; background: none; border: 0; cursor: text; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.rn-bname:hover { text-decoration: underline; text-decoration-color: var(--bd-2); text-underline-offset: 3px; } +.rn-rename { min-width: 0; height: 24px; padding: 0 6px; font: 600 13px var(--font-ui); color: var(--fg); background: var(--bg-0); border: 1px solid var(--acc); border-radius: 4px; outline: none; } +.rn-prog { display: inline-flex; align-items: center; gap: 6px; font: 12px var(--font-mono); color: var(--fg-2); } +.rn-time { font: 12px var(--font-mono); color: var(--fg-3); min-width: 34px; text-align: right; } +.rn-state { width: 8px; height: 8px; border-radius: 50%; background: var(--fg-3); } +.rn-state.done { background: var(--acc); } +.rn-state.running { background: var(--warn); animation: wb-blink 1.2s steps(1) infinite; } +.rn-state.failed { background: var(--bad); } +.rn-batch.failed .rn-prog { color: var(--bad); } + +.rn-act { visibility: hidden; height: 22px; padding: 0 7px; font-size: 12px; color: var(--fg-2); background: var(--bg-1); border: 1px solid var(--bd-2); border-radius: 4px; cursor: pointer; } +.rn-act:hover { color: var(--fg); border-color: var(--fg-3); } +.rn-head:hover .rn-act, .rn-head:focus-within .rn-act, .rn-entry:hover .rn-act, .rn-act:focus-visible { visibility: visible; } + +.rn-entries { list-style: none; margin: 0; padding: 2px 0 8px; } +.rn-entry { display: grid; grid-template-columns: 8px minmax(0, 1fr) auto auto; gap: 10px; align-items: center; padding: 4px 12px 4px 32px; font-size: 13px; } +.rn-entry:hover { background: var(--bg-2); } +.rn-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--fg-3); } +.rn-dot.done { background: var(--acc); } +.rn-dot.running { background: var(--warn); animation: wb-blink 1.2s steps(1) infinite; } +.rn-dot.queued { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-3); } +.rn-dot.failed, .rn-dot.cancelled { background: var(--bad); } +.rn-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.rn-args { font: 11.5px var(--font-mono); color: var(--fg-3); } +.rn-meta { font: 11.5px var(--font-mono); color: var(--fg-3); white-space: nowrap; } +.rn-meta.failed { color: var(--bad); } +.rn-meta.running { color: var(--warn); } +@media (prefers-reduced-motion: reduce) { .rn-state.running, .rn-dot.running { animation: none; } } + +/* ------------------------------------------------------------------ triage */ + +.tr-item { display: grid; grid-template-columns: 34px 1fr; gap: 10px; padding: 11px 14px; border-bottom: 1px solid var(--bd); } +.tr-n { font: 700 20px/1.1 var(--font-mono); color: var(--fg-2); text-align: right; } +.tr-item.hot .tr-n { color: var(--warn); } +.tr-item.zero .tr-n { color: var(--fg-3); } +.tr-t { font-weight: 600; font-size: 13.5px; } +.tr-s { font-size: 12.5px; color: var(--fg-3); } +.tr-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; } +.tr-chip { font: 11.5px var(--font-mono); color: var(--fg-2); background: var(--bg-2); border: 1px solid var(--bd); border-radius: 99px; padding: 1px 8px; } +.tr-chip.more { color: var(--fg-3); } +.tr-sec { padding: 8px 14px 6px; font-size: 12px; font-weight: 600; color: var(--fg-3); background: var(--bg-0); border-bottom: 1px solid var(--bd); } +.tr-sev { margin-left: 8px; font-size: 11px; font-weight: 600; vertical-align: 1px; padding: 0 6px; border-radius: 3px; border: 1px solid var(--bd-2); color: var(--fg-3); } +.tr-sev.high { color: var(--bad); border-color: var(--bad); } +.tr-sev.medium { color: var(--warn); border-color: var(--warn); } + +/* Triage Hints header: Load rules… / the loaded rules file */ +.tr-rules { margin-left: auto; display: flex; align-items: center; } +.wb-btn.sm { height: 26px; padding: 0 10px; font-size: 12.5px; } +.tr-loaded { display: inline-flex; align-items: center; height: 26px; border: 1px solid var(--acc); border-radius: var(--radius-s); overflow: hidden; } +.tr-file { max-width: 180px; height: 100%; padding: 0 9px; font-size: 12.5px; font-weight: 600; color: var(--acc-fg); background: none; border: 0; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tr-file:hover, .tr-x:hover { background: var(--acc-soft); } +.tr-x { height: 100%; padding: 0 8px; font-size: 15px; line-height: 1; color: var(--fg-3); background: none; border: 0; border-left: 1px solid var(--acc-line); cursor: pointer; } + +/* ------------------------------------------------------------------ toasts, connection, lock */ + +.wb-toasts { position: fixed; right: 16px; bottom: 16px; z-index: 300; display: flex; flex-direction: column; gap: 8px; } +.wb-toasts .toast { padding: 9px 14px; font-size: 13px; color: var(--fg); background: var(--bg-2); border: 1px solid var(--bd-2); border-radius: var(--radius-s); box-shadow: var(--shadow-lg); } +.wb-toasts .toast.bad { border-color: var(--bad); } +.wb-conn { position: fixed; left: 50%; top: 56px; transform: translateX(-50%); z-index: 300; padding: 8px 14px; font-size: 13px; color: var(--fg); background: var(--bg-2); border: 1px solid var(--warn); border-radius: var(--radius-s); } +.qs-lock { width: min(460px, 100%); padding: 28px; background: var(--bg-1); border: 1px solid var(--bd); border-radius: 12px; box-shadow: var(--shadow-lg); } + +.wb-ovbtn { display: none; } +@media (max-width: 1279px) { + .wb { grid-template-columns: minmax(360px, 1fr) 5px minmax(260px, var(--c3, 32%)); grid-template-areas: "pl s2 rn" "pl s2 s3" "pl s2 tr"; } + .wb-overview, #s1 { display: none; } + .wb-ovbtn { display: inline-block; } + .wb-ovbtn[aria-pressed="true"] { color: var(--acc-fg); border-color: var(--acc); } + body.ov-open .wb-overview { + display: flex; position: fixed; z-index: 150; left: 0; top: 48px; bottom: 0; width: min(440px, 92vw); + border-right: 1px solid var(--bd-2); box-shadow: var(--shadow-lg); + } +} +@media (max-width: 700px) { + .pl-head .at-25, .pl-head .at-50, .pl-head .at-75 { position: static; transform: none; } + .pl-head .wb-tabs button { transform: none; } + body { overflow: auto; } + .wb { display: flex; flex-direction: column; } + .wb-split { display: none; } + .wb-panel { min-height: 320px; } + .wb-ev-meta { display: none; } +} + +/* ------------------------------------------------------------------ presets */ + +.ps-list { flex: 1; min-height: 0; overflow: auto; } +.ps-sec { display: flex; align-items: baseline; gap: 10px; padding: 10px 14px 6px; font-size: 12px; font-weight: 600; color: var(--fg-2); background: var(--bg-0); border-bottom: 1px solid var(--bd); } +.ps-sec-note { font: 11.5px var(--font-mono); font-weight: 400; color: var(--fg-3); } +.ps-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: start; padding: 10px 14px; border-bottom: 1px solid var(--bd); cursor: pointer; } +.ps-row:hover { background: var(--bg-2); } +.ps-row:focus-visible { outline: none; background: var(--bg-3); box-shadow: inset 3px 0 0 var(--acc); } +.ps-head { display: flex; align-items: baseline; gap: 10px; } +.ps-name { font-weight: 600; } +.ps-os { font-size: 11.5px; color: var(--fg-3); } +.ps-n { font-size: 11.5px; color: var(--acc-fg); } +.ps-plugins { margin-top: 4px; font: 11.5px var(--font-mono); color: var(--fg-3); } +.ps-bad { padding: 4px 0; font-size: 12px; color: var(--warn); } +.ps-list > .ps-bad { padding: 6px 14px; } +.ps-actions { display: flex; gap: 6px; } + +/* ------------------------------------------------------------------ dialog */ + +.wb-scrim { position: fixed; inset: 0; z-index: 250; background: rgba(0, 0, 0, .45); } +.wb-dialog { + position: fixed; z-index: 251; left: 50%; top: 14vh; transform: translateX(-50%); + width: min(520px, calc(100vw - 32px)); max-height: 72vh; overflow: auto; + display: flex; flex-direction: column; gap: 14px; padding: 20px 22px; + background: var(--bg-1); border: 1px solid var(--bd-2); border-radius: 10px; box-shadow: var(--shadow-lg); +} +.wb-dialog h2 { margin: 0; font-size: 16px; font-weight: 600; } +.dl-field { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--fg-2); } +.dl-field .wb-input { flex: none; height: 34px; } +.dl-items { margin: 0; padding: 6px 10px; list-style: none; max-height: 190px; overflow: auto; background: var(--bg-0); border: 1px solid var(--bd); border-radius: var(--radius-s); } +.dl-items li { display: flex; gap: 10px; align-items: baseline; padding: 3px 0; font-size: 13px; color: var(--fg); } +.dl-items code { font: 11.5px var(--font-mono); color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.dl-p { font-weight: 600; white-space: nowrap; } +.dl-err { min-height: 18px; font-size: 13px; color: var(--bad); } +.dl-err:empty { display: none; } +.dl-link { font: inherit; font-weight: 600; color: var(--acc-fg); background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline; } +.dl-actions { display: flex; justify-content: flex-end; gap: 8px; } + +/* ------------------------------------------------------------------ results (replaces File Overview + Plugins) */ + +.wb-results { grid-area: rs; } +body.results-open .wb { grid-template-areas: "rs rs rs s2 rn" "rs rs rs s2 s3" "rs rs rs s2 tr"; } +body.results-open .wb-overview, body.results-open .wb-plugins, body.results-open #s1 { display: none; } +body.results-open .wb-ovbtn { display: none; } +@media (max-width: 1279px) { body.results-open .wb { grid-template-areas: "rs s2 rn" "rs s2 s3" "rs s2 tr"; } } +@media (max-width: 700px) { body.results-open .wb-results { min-height: 70vh; } } + +.rs-head h2 { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.rs-sum { font: 12px var(--font-mono); color: var(--fg-3); white-space: nowrap; } +.rs-sum.active { color: var(--warn); } +.rs-close { margin-left: auto; } + +.rs-tabs { flex: none; display: flex; overflow-x: auto; scrollbar-width: thin; border-bottom: 1px solid var(--bd); background: var(--bg-0); } +.rs-tab { + flex: none; display: inline-flex; align-items: center; gap: 7px; height: 36px; padding: 0 12px; + font-size: 13px; color: var(--fg-2); background: none; border: 0; border-right: 1px solid var(--bd); border-bottom: 2px solid transparent; cursor: pointer; white-space: nowrap; +} +.rs-tab:hover { color: var(--fg); background: var(--bg-2); } +.rs-tab[aria-selected="true"] { color: var(--fg); background: var(--bg-1); border-bottom-color: var(--acc); } +.rs-tab:focus-visible { outline: none; background: var(--bg-3); } +.rs-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--fg-3); } +.rs-dot.done { background: var(--acc); } +.rs-dot.running { background: var(--warn); animation: wb-blink 1.2s steps(1) infinite; } +.rs-dot.queued { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-3); } +.rs-dot.failed, .rs-dot.cancelled { background: var(--bad); } +.rs-tname { font-weight: 600; } +.rs-targs { font: 11px var(--font-mono); color: var(--fg-3); max-width: 140px; overflow: hidden; text-overflow: ellipsis; } +.rs-badge { font: 11px var(--font-mono); color: var(--fg-3); } +.rs-badge.running { color: var(--warn); } +.rs-badge.failed, .rs-badge.cancelled { color: var(--bad); } + +.rs-body { flex: 1; min-height: 0; display: flex; flex-direction: column; } +.rs-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; } +.rs-tools { flex: none; display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--bd); } +.rs-tools .rs-q { flex: 0 1 320px; height: 28px; } +.rs-tools .wb-btn.on { color: var(--acc-fg); border-color: var(--acc); } +.rs-sp { flex: 1; } +.rs-count { font: 12px var(--font-mono); color: var(--fg-3); white-space: nowrap; } +.rs-state { max-width: 640px; margin: 40px auto; padding: 0 20px; display: flex; flex-direction: column; gap: 8px; } +.rs-state-t { font-weight: 600; font-size: 15px; } +.rs-state-t.failed { color: var(--bad); } +.rs-state-m { color: var(--fg); } +.rs-state-h { color: var(--fg-2); font-size: 13px; } +.rs-state-d { margin: 6px 0 0; padding: 10px; max-height: 240px; overflow: auto; font: 12px var(--font-mono); color: var(--fg-2); background: var(--bg-0); border: 1px solid var(--bd); border-radius: var(--radius-s); white-space: pre-wrap; } + +/* the virtualised table (table.js) */ +.vt { --row: 24px; position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; outline: none; font: 12px var(--font-mono); } +.vt:focus-visible { box-shadow: inset 0 0 0 1px var(--acc-line); } +.vt-scroll { flex: 1 1 auto; overflow: auto; position: relative; contain: strict; } +.vt-head { position: sticky; top: 0; z-index: 2; background: var(--bg-1); border-bottom: 1px solid var(--bd-2); min-width: 100%; width: max-content; } +.vt-hrow, .vt-row { display: grid; grid-template-columns: var(--vt-cols); min-width: 100%; width: max-content; } +/* one visible line: when the name and the type label don't both fit, the label wraps onto a + second, clipped line and disappears; only then does the name shorten with an ellipsis */ +.vt-hcell { + position: relative; display: flex; flex-wrap: wrap; align-items: center; align-content: flex-start; column-gap: 6px; + height: 30px; padding: 0 12px 0 8px; + font: 600 12px/30px var(--font-ui); color: var(--fg-2); border-right: 1px solid var(--bd); cursor: pointer; user-select: none; white-space: nowrap; overflow: hidden; +} +.vt-hcell:hover { color: var(--fg); background: var(--bg-2); } +.vt-hcell .hn { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; } +.vt-hcell .ht { flex: none; margin-left: auto; font: 400 11px var(--font-mono); color: var(--fg-3); } +.vt-hcell .so { flex: none; font-size: 10px; color: var(--acc-fg); } +.vt-hcell.filtered .hn { color: var(--acc-fg); } +/* the resize handle sits inside the cell's right edge (the cell clips anything outside it) */ +.vt-hcell .grip { position: absolute; right: 0; top: 0; bottom: 0; width: 9px; cursor: col-resize; z-index: 1; } +.vt-hcell .grip::after { content: ""; position: absolute; right: 0; top: 6px; bottom: 6px; width: 2px; border-radius: 1px; } +.vt-hcell:hover .grip::after { background: var(--bd-2); } +.vt-hcell.moving { opacity: .45; } +.vt-drop { position: absolute; top: 0; bottom: 0; width: 3px; background: var(--acc); z-index: 3; pointer-events: none; } +body.col-moving, body.col-moving * { cursor: grabbing !important; user-select: none !important; } +.vt-hcell .grip:hover::after, .vt-hcell .grip.drag::after { background: var(--acc); } +.vt-frow { display: grid; grid-template-columns: var(--vt-cols); border-top: 1px solid var(--bd); background: var(--bg-2); } +.vt-frow input { width: 100%; min-width: 0; height: 26px; padding: 0 8px; font: 12px var(--font-mono); color: var(--fg); background: transparent; border: 0; border-right: 1px solid var(--bd); border-radius: 0; } +.vt-frow input::placeholder { color: var(--fg-3); } +.vt-frow input:focus { outline: none; background: var(--bg-0); box-shadow: inset 0 0 0 1px var(--acc); } +.vt-frow input.invalid { box-shadow: inset 0 0 0 1px var(--bad); } +.vt-spacer { position: relative; } +.vt-rows { position: absolute; left: 0; top: 0; min-width: 100%; will-change: transform; } +.vt-row { height: var(--row); cursor: default; } +.vt-row:nth-child(even) { background: rgba(127, 127, 127, .035); } +.vt-row:hover { background: var(--bg-2); } +.vt-row.cur { background: var(--acc-soft); } +.vt-row.ctx .vt-cell { opacity: .45; } +.vt-row.uniq { background: rgba(240, 180, 41, .08); box-shadow: inset 2px 0 0 var(--warn); } +.vt-row.loading .vt-cell::after { content: ""; display: block; height: 8px; width: 60%; margin-top: 8px; background: var(--bd); border-radius: 2px; } +.vt-cell { height: var(--row); line-height: var(--row); padding: 0 8px; white-space: pre; overflow: hidden; text-overflow: ellipsis; border-right: 1px solid transparent; font-variant-numeric: tabular-nums; color: var(--fg); } +.vt-row.cur .vt-cell.cc { box-shadow: inset 0 0 0 1px var(--acc); } +.vt-cell.num { text-align: right; } +.vt-cell.hex { color: #7cc4ff; } +:root[data-theme="light"] .vt-cell.hex { color: #1d5fb4; } +.vt-cell.ab { color: var(--fg-3); } +/* tree column: indent guides drawn with CSS so they join up between rows (table.js guides()) */ +.vt { --tree: #56606a; } +:root[data-theme="light"] .vt { --tree: #a3abb4; } +.vt-cell.t0 { position: relative; } +.vt-cell .tg { position: absolute; left: 8px; top: 0; bottom: 0; display: flex; pointer-events: none; } +.vt-cell .tg i { position: relative; flex: none; width: 14px; height: 100%; } +.vt-cell .tg i.v::before, .vt-cell .tg i.t::before { content: ""; position: absolute; left: 6px; top: 0; bottom: 0; border-left: 1px solid var(--tree); } +.vt-cell .tg i.e::before { content: ""; position: absolute; left: 6px; top: 0; height: 50%; border-left: 1px solid var(--tree); } +.vt-cell .tg i.t::after, .vt-cell .tg i.e::after { content: ""; position: absolute; left: 6px; width: 10px; top: 50%; border-top: 1px solid var(--tree); } +.vt-cell .dim { color: var(--fg-3); } +.vt-cell .ml { display: inline-block; margin-left: 6px; padding: 0 5px; line-height: 15px; border-radius: 3px; background: var(--bg-3); color: var(--fg-2); font-size: 11px; } +.vt-empty { position: absolute; left: 0; right: 0; top: 70px; padding: 0 20px; text-align: center; font: 13px var(--font-ui); color: var(--fg-3); pointer-events: none; } +.vt-foot { flex: none; display: flex; gap: 14px; align-items: center; height: 24px; padding: 0 12px; border-top: 1px solid var(--bd); background: var(--bg-1); font: 11.5px var(--font-ui); color: var(--fg-3); white-space: nowrap; overflow: hidden; } +.vt-foot .sp { flex: 1; } +.vt.busy .vt-rows { opacity: .55; transition: opacity .15s; } + +/* pop-up menus (core.js menu) */ +.menu { position: fixed; z-index: 400; min-width: 170px; padding: 4px; background: var(--bg-1); border: 1px solid var(--bd-2); border-radius: 7px; box-shadow: var(--shadow-lg); font: 13px var(--font-ui); } +.menu .mi { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 10px; color: var(--fg); background: none; border: 0; border-radius: 4px; text-align: left; cursor: pointer; font: inherit; } +.menu .mi:hover, .menu .mi:focus-visible { background: var(--bg-3); outline: none; } +.menu .mi small { margin-left: auto; color: var(--fg-3); } +.menu .sep { height: 1px; margin: 4px 2px; background: var(--bd); } +.menu .mh { padding: 6px 10px 3px; font-size: 12px; font-weight: 600; color: var(--fg-3); } +.menu label.mi { cursor: pointer; } +.menu input[type="checkbox"] { margin: 0; accent-color: var(--acc); } + +/* runs panel: the run whose results are shown */ +.rn-batch.shown > .rn-head { box-shadow: inset 3px 0 0 var(--acc); background: var(--acc-soft); } +.rn-entry { cursor: pointer; } +.rn-entry.pick:hover { background: var(--bg-3); } + +/* ------------------------------------------------------------------ options dialog */ + +.wb-dialog.op-dialog { width: min(860px, calc(100vw - 32px)); max-height: 84vh; top: 7vh; padding: 0; gap: 0; overflow: hidden; } +.op-head { display: flex; align-items: baseline; gap: 12px; padding: 18px 22px 12px; border-bottom: 1px solid var(--bd); } +.op-sub { font-size: 12.5px; color: var(--fg-3); } +.op-body { flex: 1; min-height: 0; overflow: auto; padding: 4px 22px 12px; } +.op-group { padding: 14px 0 4px; } +.op-group h3 { margin: 0; font-size: 13.5px; font-weight: 600; } +.op-group p { margin: 2px 0 0; font-size: 12px; color: var(--fg-3); } +.op-row { display: grid; grid-template-columns: 16px minmax(0, 1fr) minmax(180px, 280px); gap: 12px; align-items: center; padding: 7px 8px; border-radius: var(--radius-s); } +.op-row:hover { background: var(--bg-2); } +.op-row.on { background: var(--acc-soft); } +.op-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; cursor: pointer; } +.op-text code { font: 12.5px var(--font-mono); color: var(--fg); } +.op-note { font-size: 12.5px; color: var(--fg-2); } +.op-row .wb-input, .op-row .wb-select { width: 100%; height: 30px; font: 12px var(--font-mono); } +.op-row:not(.on) .wb-input, .op-row:not(.on) .wb-select { opacity: .55; } +.op-row textarea.op-lines { height: auto; min-height: 30px; padding: 6px 10px; resize: vertical; } +.op-row .op-num { width: 80px; } +.op-dialog .dl-err { padding: 0 22px; } +.op-dialog .dl-actions { padding: 12px 22px 16px; border-top: 1px solid var(--bd); } +@media (max-width: 640px) { .op-row { grid-template-columns: 16px minmax(0, 1fr); } .op-row > :last-child { grid-column: 2; } } + +/* Quick Start: saved analyses */ +.qs-prev .fn { display: flex; flex-direction: column; line-height: 1.3; } +.qs-pn { font-weight: 600; } +.qs-pp { font: 11.5px var(--font-mono); color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; } +.qs-pm { font-size: 12px; color: var(--fg-2); white-space: nowrap; } +.qs-file.qs-prev { grid-template-columns: 22px 1fr auto auto auto; } +.qs-file.qs-prev.off { cursor: default; } +.qs-file.qs-prev.off > :not(.qs-del) { opacity: .6; } +.qs-file.qs-prev.off:hover { background: none; } +.qs-del { height: 26px; padding: 0 9px; font: 12.5px var(--font-ui); color: var(--fg-2); background: var(--bg-1); border: 1px solid var(--bd-2); border-radius: 4px; cursor: pointer; visibility: hidden; } +.qs-prev:hover .qs-del, .qs-prev:focus-within .qs-del, .qs-prev.off .qs-del { visibility: visible; } +.qs-del:hover { color: var(--bad); border-color: var(--bad); } +.qs-tag.warn { color: var(--warn); background: transparent; border-color: var(--warn); } diff --git a/src/web/assets/views.js b/src/web/assets/views.js deleted file mode 100644 index ecd7b55..0000000 --- a/src/web/assets/views.js +++ /dev/null @@ -1,656 +0,0 @@ -// Workspace: tabs, the overview (landing), plugin result tabs, compare view, run history and -// the dialogs (open image, shortcuts). - -import { store, api, on, emit, el, clear, copy, menu, modal, runPlugin, whenDone, sessionRuns, shortName, pluginOs, fmtCount, fmtMs, fmtBytes, fmtAgo, parseTime, fmtTime, prefs, toast, rememberDuration, expectedDuration, finished, debounce, int0, download } from './core.js'; -import { QUICK, blurb } from './catalog.js'; -import { ResultPanel, captureTime } from './result.js'; -import { ProcessTab, errCard, selectPid, procByPid, firstPlugin } from './procs.js'; -import { HexTab } from './hex.js'; -import { openPalette } from './palette.js'; - -// ------------------------------------------------------------------ tabs -const tabs = []; // {key, view, btn} -let active = null; - -export function activeView() { return active && active.view; } - -function tabFor(key) { return tabs.find(t => t.key === key); } - -export function openTab(key, make, { focus = true, background = false } = {}) { - let t = tabFor(key); - if (!t) { - const view = make(); - const btn = el('button.tab', { role: 'tab', type: 'button', 'aria-selected': 'false', 'aria-controls': 'pane-' + key, id: 'tab-' + key }); - t = { key, view, btn }; - view.pane.id = 'pane-' + key; - view.pane.setAttribute('role', 'tabpanel'); - view.pane.setAttribute('aria-labelledby', 'tab-' + key); - view.pane.hidden = true; - btn.addEventListener('click', e => { if (e.target.closest('.x')) closeTab(key); else activate(key); }); - btn.addEventListener('auxclick', e => { if (e.button === 1 && key !== 'overview') closeTab(key); }); - document.getElementById('panes').append(view.pane); - document.getElementById('tabs').append(btn); - tabs.push(t); - renderTabBtn(t); - saveTabs(); - } - if (!background) activate(key, focus); - return t.view; -} - -function renderTabBtn(t) { - const v = t.view; - const b = t.btn; - clear(b); - const status = v.status ? v.status() : null; - if (status === 'running' || status === 'queued') b.append(el('span.dot.running')); - else if (status === 'failed') b.append(el('span.dot.failed')); - b.append(el('span.tt', { text: v.title })); - if (v.subtitle) b.append(el('span.tk', { text: v.subtitle })); - if (t.key !== 'overview') b.append(el('span.x', { 'aria-label': 'Close tab', title: 'Close (Alt+W)', text: '×' })); - b.title = v.title + (v.subtitle ? ' — ' + v.subtitle : ''); -} - -export function refreshTabs() { for (const t of tabs) renderTabBtn(t); } - -export function activate(key, focus = true) { - const t = tabFor(key); - if (!t) return; - for (const x of tabs) { - const on = x === t; - x.btn.setAttribute('aria-selected', String(on)); - x.btn.tabIndex = on ? 0 : -1; - x.view.pane.hidden = !on; - } - active = t; - t.btn.scrollIntoView({ block: 'nearest', inline: 'nearest' }); - if (t.view.onShow) t.view.onShow(); - if (focus && t.view.focus) setTimeout(() => t.view.focus(), 0); - highlightRunList(); - saveTabs(); -} - -export function closeTab(key) { - const i = tabs.findIndex(t => t.key === key); - if (i < 0 || key === 'overview') return; - const t = tabs[i]; - if (t.view.destroy) t.view.destroy(); - t.view.pane.remove(); - t.btn.remove(); - tabs.splice(i, 1); - if (active === t) activate(tabs[Math.min(i, tabs.length - 1)].key); - saveTabs(); -} - -export function cycleTab(d) { - if (!active) return; - const i = tabs.indexOf(active); - activate(tabs[(i + d + tabs.length) % tabs.length].key); -} -export function nthTab(n) { if (tabs[n]) activate(tabs[n].key); } - -function saveTabs() { - if (!store.session || !store.session.image) return; - prefs.set('tabs:' + store.session.image, { keys: tabs.map(t => t.key).filter(k => /^(run|proc):/.test(k)), active: active && active.key }); -} - -export function restoreTabs() { - if (!store.session || !store.session.image) return; - const s = prefs.get('tabs:' + store.session.image, null); - if (!s) return; - for (const k of s.keys) { - const [kind, id] = k.split(':'); - if (kind === 'run' && store.runs.has(+id) && store.runs.get(+id).session === store.session.id) openRun(+id, { background: true }); - if (kind === 'proc') openProcess(+id, { background: true }); - } - if (s.active && tabFor(s.active)) activate(s.active, false); -} - -export function closeSessionTabs() { - for (const t of [...tabs]) if (t.key !== 'overview') closeTab(t.key); -} - -// ------------------------------------------------------------------ navigation -export function openRun(id, opts = {}) { - return openTab('run:' + id, () => new RunTab(id), opts); -} -export function openProcess(pid, opts = {}) { - selectPid(pid, !opts.background); - return openTab('proc:' + pid, () => new ProcessTab(pid), opts); -} -export function openHex(layer, addr) { - const v = new HexTab({ layer, addr }); - return openTab(v.key, () => v); -} - -on('nav', ev => { - if (ev.kind === 'run') openRun(ev.id); - else if (ev.kind === 'proc') openProcess(ev.pid); - else if (ev.kind === 'hex') openHex(ev.layer, ev.addr); - else if (ev.kind === 'overview') activate('overview'); - else if (ev.kind === 'compare') openCompare(ev.a, ev.b); -}); -on('tabs-changed', () => refreshTabs()); -on('palette', ev => { - if (ev.pidFor) { - // plugins with a pid option for this OS, prefilled - openPalette({ query: '', pidFor: ev.pidFor }); - } else openPalette(ev); -}); - -// ------------------------------------------------------------------ run tab -class RunTab { - constructor(id) { - this.id = id; - this.run = store.runs.get(id); - this.pane = el('div.pane'); - this.head = el('div.rv-head'); - this.errBox = el('div'); - this.filesBox = el('div.files', { hidden: true }); - this.progress = el('div.progress', { hidden: true }, el('i')); - this.panel = new ResultPanel({ runId: id, onUpdate: r => this.update(r) }); - this.pane.append(this.head, this.progress, this.errBox, this.filesBox, this.panel.node); - this.update(this.run); - this.tick = setInterval(() => { if (this.run && this.run.status === 'running') this.renderHead(); }, 250); - } - get title() { return this.run ? shortName(this.run.plugin) : 'run ' + this.id; } - get subtitle() { return this.run && this.run.args.length ? this.run.args.join(' ') : '#' + this.id; } - status() { return this.run && this.run.status; } - - update(r) { - if (!r) return; - const prev = this.run; - this.run = r; - if (r.status === 'done' && prev && prev.status !== 'done' && r.elapsed) rememberDuration(r.plugin, r.elapsed); - this.renderHead(); - clear(this.errBox); - if (r.error && (r.status === 'failed' || (r.status === 'cancelled' && r.error.kind !== 'cancelled'))) this.errBox.append(errCard(r.error)); - if (r.evicted) this.errBox.append(errCard({ kind: 'cancelled', title: 'This result was dropped from memory', message: 'Newer results needed the memory (--max-memory). Nothing was lost on disk: run it again to see it (it only takes as long as the plugin).', hints: [], detail: '' })); - if (r.truncated) this.errBox.append(errCard({ kind: 'cancelled', title: `Showing the first ${fmtCount(r.stored)} of ${fmtCount(r.rows)} rows`, message: 'This result is larger than the memory fvol serve sets aside for results (--max-memory). The remaining rows were counted but not kept.', hints: ['Narrow the run with the plugin\'s options (for example --pid), or', 'export the complete output straight to disk with Export → “fvol -r csv” (it re-runs the plugin and streams everything).'], detail: '' })); - const running = r.status === 'running' || r.status === 'queued'; - this.progress.hidden = !running; - this.filesBox.hidden = !r.files || !r.files.length; - if (r.files && r.files.length) { - clear(this.filesBox); - this.filesBox.append(el('span.label', { text: `${r.files.length} file${r.files.length > 1 ? 's' : ''} written` })); - for (const f of r.files.slice(0, 12)) this.filesBox.append(el('button.linkbtn', { type: 'button', title: `${fmtBytes(f.size)} — download`, text: f.name, on: { click: () => download(`/api/runs/${r.id}/files/${encodeURIComponent(f.name)}`) } })); - if (r.files.length > 12) this.filesBox.append(el('span.muted', { text: `+${r.files.length - 12} more` })); - if (r.files.length > 1) this.filesBox.append(el('button.linkbtn', { type: 'button', text: 'download all (.zip)', on: { click: () => download(`/api/runs/${r.id}/files.zip`) } })); - } - refreshTabs(); - } - - renderHead() { - const r = this.run; - clear(this.head); - const os = pluginOs(r.plugin); - const title = el('div.rv-title', {}, - el('h2', {}, el('span.ns', { text: os === 'generic' ? '' : os + '.' }), shortName(r.plugin)), - r.args.length ? el('span.args', { text: r.args.join(' ') }) : null, - el('span', { class: 'stamp ' + r.status, text: r.status === 'done' ? 'done' : r.status })); - const exp = expectedDuration(r.plugin); - let meta = `${fmtCount(r.rows)} rows`; - if (r.status === 'running') { - meta += ` · ${fmtMs(r.elapsed)}`; - if (r.elapsed > 800 && r.rows) meta += ` · ${fmtCount(Math.round(r.rows / (r.elapsed / 1000)))}/s`; - if (exp && exp > 1500) meta += ` · usually ~${fmtMs(exp)}`; - const bar = this.progress; - if (exp && exp > 1500) { bar.classList.add('eta'); bar.firstChild.style.right = Math.max(2, 100 - Math.min(98, (r.elapsed / exp) * 100)) + '%'; } - } else if (r.status === 'queued') meta = 'waiting for a free worker…'; - else meta += ` · ${fmtMs(r.elapsed)}`; - if (r.truncated) meta += ' · table size cap reached: the rest was counted, not kept'; - const acts = el('div.rv-actions'); - if (r.status === 'running' || r.status === 'queued') { - acts.append(el('button.btn.danger', { type: 'button', title: 'Cancel (the plugin stops at its next result)', on: { click: () => api(`runs/${r.id}/cancel`, { method: 'POST' }).catch(e => toast(e.message, 'bad')) } }, 'Cancel')); - } else { - acts.append(el('button.btn', { type: 'button', title: 'Run again with the same options', on: { click: () => this.rerun() } }, '↻ Re-run')); - } - acts.append( - el('button.btn.ghost', { type: 'button', title: 'Edit options and run again', on: { click: () => openPalette({ plugin: r.plugin, query: shortName(r.plugin), args: argsToPrefill(r), focusForm: true }) } }, 'Options…'), - el('button.btn.ghost', { type: 'button', title: 'Compare with another run', on: { click: () => openCompare(r.id, null) } }, 'Compare')); - const b = blurb(r.plugin); - this.head.append(title, el('span.rv-meta', { text: meta, title: b || '' }), acts); - } - - async rerun() { - try { - const run = await runPlugin(this.run.plugin, argsToPrefill(this.run), { origin: 'user' }); - openRun(run.id); - } catch (e) { toast(e.message, 'bad'); } - } - - focus() { this.panel.table.root.focus({ preventScroll: true }); } - focusFilter() { this.panel.focusFilter(); } - destroy() { clearInterval(this.tick); this.panel.destroy(); } -} - -/** Reconstruct the option values of a run from its argv. */ -function argsToPrefill(r) { - const p = store.pluginMap.get(r.plugin); - if (!p) return {}; - const out = {}; - const argv = r.args; - for (let i = 0; i < argv.length; i++) { - const req = p.reqs.find(x => x.flag === argv[i]); - if (!req) continue; - if (req.kind === 'bool') { out[req.name] = true; continue; } - const vals = []; - while (i + 1 < argv.length && !p.reqs.some(x => x.flag === argv[i + 1])) vals.push(argv[++i]); - out[req.name] = req.kind.startsWith('list') ? vals : vals[0]; - } - return out; -} - -// ------------------------------------------------------------------ overview -export class Overview { - constructor() { - this.pane = el('div.pane.scrollpane'); - this.root = el('div.ov'); - this.pane.append(this.root); - on('session', () => this.render()); - on('runs', debounce(() => this.renderDynamic(), 120)); - on('procs', () => this.renderDynamic()); - this.render(); - } - get title() { return 'Overview'; } - get subtitle() { return ''; } - - render() { - clear(this.root); - const s = store.session; - if (!s) return; - if (!s.image) { this.root.append(openImageCard(true)); return; } - this.evCard = el('section.card.evcard.full', { 'aria-label': 'Evidence' }); - this.root.append(this.evCard); - this.renderEvidence(); - this.triage = el('section.card', { 'aria-label': 'Triage' }); - this.quick = el('section.card', { 'aria-label': 'Quick actions' }); - this.recent = el('section.card.full', { 'aria-label': 'Recent runs' }); - this.root.append(this.quick, this.triage, this.recent); - this.renderDynamic(); - } - - renderEvidence() { - const s = store.session; - const c = this.evCard; - clear(c); - const b = el('div.card-b'); - const osName = { windows: 'Windows', linux: 'Linux', mac: 'macOS' }[s.os] || ''; - b.append(el('div.ev-title', {}, el('h1', { text: s.name }), osName ? el('span.oslogo', { text: `${osName}${s.arch ? ' · ' + (s.arch === 'intel64' ? 'x64' : 'x86') : ''}` }) : null), - el('div.ev-path', { text: `${s.image} · ${fmtBytes(s.size)}` })); - if (s.state === 'warming') { - b.append(el('div.warming', {}, el('span.spinner'), `${s.phase || 'Preparing'}…`)); - } else if (s.state === 'failed') { - const hints = []; - if (s.banners && s.banners.length) { - for (const x of s.banners) hints.push('Kernel banner in the image: ' + x); - hints.push('Generate a symbol table for exactly this kernel with dwarf2json (from the vmlinux with debug info, or the macOS Kernel Debug Kit), put it in a directory, then use “Open another image…” with that symbols directory.'); - } else hints.push(...(s.notes || [])); - b.append(errCard({ title: s.banners && s.banners.length ? 'Symbols needed for this kernel' : 'This image could not be analysed', message: s.error, hints, detail: (s.notes || []).join('\n') })); - } - const facts = el('div.facts'); - const fact = (k, v, big = false, small = '') => { if (v === undefined || v === null || v === '') return; facts.append(el('div.fact', {}, el('div.k', { text: k }), el('div.v', { class: 'v' + (big ? ' big' : '') }, String(v), small ? el('small', { text: ' ' + small }) : null))); }; - const F = Object.fromEntries(s.facts || []); - const cap = captureTime(); - if (cap) fact('Captured', fmtTime(cap), false, 'UTC'); - if (s.os === 'windows') { - const mm = F['Major/Minor']; - fact('Windows build', mm ? mm.split('.').pop() : F.NtMajorVersion, false, F.NtProductType ? F.NtProductType.replace('NtProduct', '') : ''); - fact('CPUs', F.KeNumberProcessors); - fact('Kernel base', F['Kernel Base'] || F['Kernel base']); - fact('DTB', F.DTB); - fact('System root', F.NtSystemRoot); - fact('Kernel PDB', F.Kernel); - } else if (F.Banner) { - const m = /version (\S+)/i.exec(F.Banner) || /Darwin Kernel Version (\S+?):/.exec(F.Banner); - fact('Kernel', m ? m[1] : F.Banner); - fact('KASLR shift', F['KASLR shift']); - fact('DTB', F.DTB); - fact('Layer', F.Layer); - } - const procs = store.procs; - if (procs) { - const running = procs.filter(p => p.exit === null).length; - fact('Processes', fmtCount(procs.length), true, procs.length - running ? `${procs.length - running} exited` : ''); - } - if (s.layers && s.layers.length) fact('Layers', s.layers.join(' → ')); - if (s.warm_ms) fact('Ready in', fmtMs(s.warm_ms)); - b.append(facts); - if (F.Banner) b.append(el('div.fact.banner', {}, el('div.k', { text: 'Banner' }), el('div.v', { text: F.Banner }))); - const changeBtn = el('button.btn.ghost', { type: 'button', on: { click: () => openImageDialog() } }, 'Open another image…'); - const allFacts = el('button.btn.ghost', { type: 'button', on: { click: () => factsDialog() } }, 'All OS details'); - c.append(el('div.card-h', {}, el('h3', { text: 'Evidence' }), el('div.rv-actions', {}, allFacts, changeBtn)), b); - } - - renderDynamic() { - const s = store.session; - if (!s || !s.image || !this.quick) return; - this.renderEvidence(); - // quick actions - clear(this.quick); - const tiles = el('div.tiles'); - const runs = sessionRuns(); - const bannerOs = s.banners && s.banners.length ? (s.banners[0].startsWith('Darwin') ? 'mac' : 'linux') : null; - (QUICK[s.os || bannerOs] || QUICK.windows).forEach(([label, cands], k) => { - const name = firstPlugin(cands); - if (!name) return; - const last = runs.find(r => r.plugin === name && r.args.length === 0); - const st = last ? (last.status === 'done' ? `✓ ${fmtCount(last.rows)}` : last.status) : ''; - tiles.append(el('button.tile', { type: 'button', title: blurb(name), on: { click: () => this.quickRun(name) } }, - el('span.tn', { text: label }), el('span.ts', { class: 'ts ' + (last ? last.status : ''), text: st }), - el('span.tp', { text: shortName(name) }), el('span.td', { text: blurb(name).split('. ')[0] }))); - }); - if (!tiles.childNodes.length) tiles.append(el('p.muted', { text: 'No quick actions for this OS in this build yet — press Ctrl+K to browse all plugins.' })); - this.quick.append(el('div.card-h', {}, el('h3', { text: 'Start here' }), el('button.btn.ghost', { type: 'button', on: { click: () => openPalette() } }, 'All plugins', el('kbd', { text: 'Ctrl K' }))), el('div.card-b', {}, tiles)); - // triage - clear(this.triage); - const tri = el('div.triage'); - const procs = store.procs || []; - const flagged = procs.filter(p => p.flags.some(f => !f.startsWith('started'))); - const recent = procs.filter(p => p.flags.some(f => f.startsWith('started'))); - const exited = procs.filter(p => p.exit !== null); - // smss.exe and userinit.exe exit by design, so their children are expected orphans - const orphans = procs.filter(p => !p.parent && p.ppid !== 0 && s.os === 'windows' && !/^(System|smss\.exe|Registry|MemCompression|csrss\.exe|wininit\.exe|winlogon\.exe|explorer\.exe)$/i.test(p.name)); - const item = (n, title, sub, list, hot) => { - const chips = el('div.chips', {}, ...list.slice(0, 14).map(p => el('button.chip', { type: 'button', title: p.flags.join('\n'), on: { click: () => emit('nav', { kind: 'proc', pid: p.pid }) } }, `${p.name} ${p.pid}`))); - if (list.length > 14) chips.append(el('span.chip', { text: `+${list.length - 14}` })); - tri.append(el('div.tri', { class: 'tri' + (hot && n ? ' hot' : '') }, el('div.n', { text: String(n) }), el('div.t', {}, title, el('small', { text: sub }), list.length ? chips : null))); - }; - if (s.state === 'failed' || s.state === 'idle') tri.append(el('div.tri', {}, el('div.n', { text: '–' }), el('div.t', {}, 'No process list', el('small', { text: 'The kernel of this image was not identified, so there is nothing to triage yet.' })))); - else if (!store.procs) tri.append(el('div.tri', {}, el('div.n', {}, el('span.spinner')), el('div.t', { text: s.state === 'warming' ? 'Preparing the image…' : 'Reading the process list…' }))); - else { - item(flagged.length, 'Processes worth a look', s.os === 'windows' ? 'Unexpected parents, duplicated singletons, shells spawned by services.' : 'Heuristic flags.', flagged, true); - item(recent.length, 'Started shortly before capture', 'New processes are where an intrusion is most likely to be visible.', recent, true); - if (s.os === 'windows') item(orphans.length, 'Parent not in the process list', 'Normal for some (parent exited), odd for others.', orphans, false); - item(exited.length, 'Exited but still listed', 'Terminated processes whose objects are still in memory.', exited, false); - } - this.triage.append(el('div.card-h', {}, el('h3', { text: 'Triage hints' }), el('span.muted', { text: 'heuristics, not verdicts', style: { fontSize: '10px' } })), tri); - // recent runs - clear(this.recent); - const list = el('ol.runlist.recent'); - for (const r of runs.filter(r => r.origin === 'user').slice(0, 10)) list.append(runItem(r)); - if (!list.childNodes.length) list.append(el('li', { style: { cursor: 'default' } }, el('span'), el('span.muted', { text: 'Nothing run yet. Pick a tile, a process on the left, or press Ctrl+K.' }))); - this.recent.append(el('div.card-h', {}, el('h3', { text: 'Your recent runs' })), el('div', { style: { padding: '6px 0' } }, list)); - } - - async quickRun(name) { - try { - const run = await runPlugin(name, {}, { reuse: true, origin: 'user' }); - openRun(run.id); - } catch (e) { toast(e.message, 'bad'); } - } - - focus() { const t = this.root.querySelector('.tile, button'); if (t) t.focus({ preventScroll: true }); } -} - -function factsDialog() { - const s = store.session; - const box = el('div.dialog', { 'aria-label': 'OS details' }); - const kv = el('div', { style: { padding: '8px 0 14px' } }); - for (const [k, v] of s.facts || []) kv.append(el('div.kv', {}, el('div.k', { text: k }), el('div.v', { text: v }))); - const m = modal(box); - box.append(el('div.card-h', {}, el('h3', { text: 'Operating system details' }), el('button.iconbtn', { type: 'button', 'aria-label': 'Close', text: '×', on: { click: () => m.close() } })), kv); - box.querySelector('button').focus(); -} - -// ------------------------------------------------------------------ open image -function openImageCard(first) { - const s = store.session; - const card = el('section.card.full', { 'aria-label': 'Open a memory image' }); - const path = el('input.input', { type: 'text', value: (s && s.image) || '', placeholder: '/cases/host1/memory.raw', spellcheck: false, autocomplete: 'off', 'aria-label': 'Path of the memory image' }); - const syms = el('input.input', { type: 'text', value: s ? s.symbol_dirs.join(';') : '', placeholder: 'optional: symbol directories, ; separated', spellcheck: false, autocomplete: 'off', 'aria-label': 'Symbol directories' }); - const list = el('div.fslist', { role: 'listbox', 'aria-label': 'Files' }); - const err = el('div.err', { style: { color: 'var(--bad)', fontSize: '12px' }, role: 'alert' }); - const go = el('button.btn.primary', { type: 'button', on: { click: () => submit() } }, 'Open image'); - async function browse() { - try { - const r = await api('fs?path=' + encodeURIComponent(path.value || '.')); - clear(list); - const up = r.dir.replace(/\/[^/]+\/?$/, '') || '/'; - list.append(el('button', { type: 'button', on: { click: () => { path.value = up + '/'; browse(); } } }, el('span', { text: '↰' }), el('span', { text: '..' }), el('span.sz'))); - for (const e of r.entries) { - const full = (r.dir.endsWith('/') ? r.dir : r.dir + '/') + e.name; - if (path.value && !full.startsWith(path.value) && !path.value.endsWith('/') && !r.dir.startsWith(path.value)) { - const prefix = path.value.slice(path.value.lastIndexOf('/') + 1); - if (!e.name.startsWith(prefix)) continue; - } - list.append(el('button', { type: 'button', on: { click: () => { path.value = full + (e.dir ? '/' : ''); if (e.dir) browse(); else path.focus(); } } }, - el('span', { text: e.dir ? '▸' : '·' }), el('span', { text: e.name + (e.dir ? '/' : '') }), el('span.sz', { text: e.dir ? '' : fmtBytes(e.size) }))); - } - } catch (e) { clear(list); list.append(el('div.muted', { text: e.message, style: { padding: '6px 8px', fontSize: '12px' } })); } - } - async function submit() { - err.textContent = ''; - go.disabled = true; - try { - const body = { file: path.value.trim() }; - if (syms.value.trim()) body.symbol_dirs = syms.value.split(';').map(x => x.trim()).filter(Boolean); - await api('session', { method: 'POST', body }); - toast('Opening ' + body.file); - document.dispatchEvent(new CustomEvent('fastvol-close-dialog')); - } catch (e) { err.textContent = e.message; } - go.disabled = false; - } - path.addEventListener('input', debounce(browse, 150)); - path.addEventListener('keydown', e => { if (e.key === 'Enter') submit(); }); - const body = el('div.card-b.openbox', {}, - first ? el('img.mascot', { src: '/assets/mark.svg', alt: '' }) : null, - first ? el('p.prose', { text: 'No memory image is loaded. Enter the path of one (raw, LiME, ELF core such as a QEMU or VirtualBox core dump, Windows crash dump, VMware .vmem, QEMU savevm, AVML…). It is only read, never modified.', style: { margin: 0 } }) : el('p.prose', { text: 'Switching images keeps earlier runs in the history, but they belong to the old image.', style: { margin: 0 } }), - el('div.row', {}, path, go), syms, list, err); - card.append(el('div.card-h', {}, el('h3', { text: 'Open a memory image' })), body); - setTimeout(() => { browse(); path.focus(); }, 0); - return card; -} - -export function openImageDialog() { - const box = el('div.dialog', { 'aria-label': 'Open a memory image' }); - box.append(openImageCard(false)); - const m = modal(box); - const close = () => { m.close(); document.removeEventListener('fastvol-close-dialog', close); }; - document.addEventListener('fastvol-close-dialog', close); -} - -// ------------------------------------------------------------------ run history (rail) -function runItem(r) { - const li = el('li', { tabindex: 0, dataset: { id: r.id }, title: `${r.plugin} ${r.args.join(' ')}\n${r.status} · ${fmtCount(r.rows)} rows · ${fmtMs(r.elapsed)} · ${fmtAgo(r.created)}${r.origin !== 'user' ? '\n(opened by ' + r.origin + ')' : ''}` }, - el('span.rs', { class: 'rs ' + r.status }), - el('span.rn', {}, shortName(r.plugin), ' ', el('span.ra', { text: r.args.join(' ') }), r.origin !== 'user' ? el('span.origin', { text: ' ' + r.origin }) : null), - el('span.rm', { text: r.status === 'done' ? fmtCount(r.rows) : r.status === 'running' ? fmtMs(r.elapsed) : r.status })); - li.addEventListener('click', () => openRun(r.id)); - li.addEventListener('keydown', e => { if (e.key === 'Enter') openRun(r.id); if (e.key === 'Delete') deleteRun(r.id); }); - li.addEventListener('contextmenu', e => { - e.preventDefault(); - menu(li, [ - { label: 'Open', act: () => openRun(r.id) }, - { label: 'Compare with…', act: () => openCompare(r.id, null) }, - { label: finished(r) ? 'Remove from history' : 'Cancel', act: () => (finished(r) ? deleteRun(r.id) : api(`runs/${r.id}/cancel`, { method: 'POST' })) }, - ]); - }); - return li; -} - -async function deleteRun(id) { - closeTab('run:' + id); - await api(`runs/${id}`, { method: 'DELETE' }).catch(() => {}); -} - -export function renderRunList() { - const list = document.getElementById('runlist'); - const runs = sessionRuns(); - const showAll = prefs.get('showPivotRuns', false); - const shown = runs.filter(r => showAll || r.origin === 'user' || r.status === 'running'); - document.getElementById('run-count').textContent = runs.length ? `${shown.length}${shown.length !== runs.length ? '/' + runs.length : ''}` : ''; - list.replaceChildren(...shown.map(runItem)); - if (!shown.length) list.append(el('li', { style: { cursor: 'default' } }, el('span'), el('span.muted', { text: runs.length ? 'Only background runs so far.' : 'No runs yet.' }))); - if (runs.length !== shown.length || showAll) list.append(el('li', { style: { cursor: 'default' } }, el('span'), el('button.linkbtn', { type: 'button', text: showAll ? 'hide background runs' : `show ${runs.length - shown.length} background runs`, on: { click: () => { prefs.set('showPivotRuns', !showAll); renderRunList(); } } }))); - highlightRunList(); - // top-bar activity - const act = document.getElementById('activity'); - const running = runs.filter(r => r.status === 'running' || r.status === 'queued'); - clear(act); - if (running.length) act.append(el('span.pulse'), el('span.txt', { text: `${running.length} running` })); -} - -function highlightRunList() { - const id = active && active.key.startsWith('run:') ? active.key.slice(4) : null; - for (const li of document.querySelectorAll('#runlist li')) li.classList.toggle('active', li.dataset.id === id); -} - -// ------------------------------------------------------------------ compare -let cmpSeq = 0; -export function openCompare(a, b) { - const v = new CompareTab(a, b); - return openTab('cmp' + (++cmpSeq), () => v); -} - -class CompareTab { - constructor(a, b) { - this.pane = el('div.pane'); - this.a = a; this.b = b; - this.mode = 'all'; - this.bar = el('div.cmp-bar'); - this.grid = el('div.cmp-grid'); - this.pane.append(el('div.cmp', {}, this.bar, this.grid)); - this.renderBar(); - this.build(); - } - get title() { return 'compare'; } - get subtitle() { const ra = store.runs.get(this.a), rb = store.runs.get(this.b); return ra && rb ? `${shortName(ra.plugin)} ⇆ ${shortName(rb.plugin)}` : ''; } - - runOptions(sel, cur) { - clear(sel); - sel.append(el('option', { value: '', text: '— pick a run —' })); - for (const r of sessionRuns().filter(r => r.status === 'done' && r.cols.length)) sel.append(el('option', { value: r.id, text: `#${r.id} ${shortName(r.plugin)} ${r.args.join(' ')} (${fmtCount(r.rows)})`, selected: r.id === cur })); - } - - renderBar() { - clear(this.bar); - const sa = el('select.input', { 'aria-label': 'Left run' }); - const sb = el('select.input', { 'aria-label': 'Right run' }); - this.runOptions(sa, this.a); - this.runOptions(sb, this.b); - sa.addEventListener('change', () => { this.a = +sa.value || null; this.keys = null; this.build(); refreshTabs(); }); - sb.addEventListener('change', () => { this.b = +sb.value || null; this.keys = null; this.build(); refreshTabs(); }); - const mode = el('select.input', { 'aria-label': 'Rows to show' }, - el('option', { value: 'all', text: 'all rows, differences highlighted' }), - el('option', { value: 'only', text: 'only rows missing on the other side' }), - el('option', { value: 'common', text: 'only rows present on both sides' })); - mode.value = this.mode; - mode.addEventListener('change', () => { this.mode = mode.value; this.build(); }); - this.keysBtn = el('button.btn.ghost', { type: 'button', on: { click: () => this.keysMenu() } }, 'Match on…'); - this.bar.append(sa, el('span.muted', { text: '⇆' }), sb, mode, this.keysBtn); - } - - common() { - const ra = store.runs.get(this.a), rb = store.runs.get(this.b); - if (!ra || !rb) return []; - return ra.cols.map((c, i) => [c.name, i, rb.cols.findIndex(d => d.name === c.name)]).filter(x => x[2] >= 0); - } - - defaultKeys() { - const common = this.common(); - const pref = ['PID', 'ImageFileName', 'Name', 'COMM', 'Process', 'Path', 'Base', 'Offset', 'Offset(V)']; - const keys = common.filter(([n]) => pref.includes(n) && !(n.startsWith('Offset') && common.some(([m]) => m === 'PID'))); - return (keys.length ? keys : common.filter(([n]) => !/time|count|threads|handles/i.test(n)).slice(0, 3)).map(([n]) => n); - } - - keysMenu() { - const common = this.common(); - const items = [{ header: 'Rows match when these columns are equal' }]; - for (const [n] of common) { - const cb = el('input', { type: 'checkbox', checked: this.keys.includes(n) }); - cb.addEventListener('change', () => { this.keys = cb.checked ? [...this.keys, n] : this.keys.filter(k => k !== n); if (this.keys.length) this.build(); }); - items.push({ node: el('label.mi', {}, cb, n) }); - } - if (!common.length) items.push({ header: 'The two runs have no column in common.' }); - menu(this.keysBtn, items); - } - - build() { - if (this.pa) { this.pa.destroy(); this.pb.destroy(); this.pa = this.pb = null; } - clear(this.grid); - const ra = store.runs.get(this.a), rb = store.runs.get(this.b); - if (!ra || !rb) { - this.grid.append(el('div.empty-state', { style: { gridColumn: '1 / -1' } }, el('h2', { text: 'Compare two results' }), 'Pick two finished runs above — e.g. pslist and psscan to find hidden processes, or the same plugin before and after changing options. Rows missing on the other side are highlighted.')); - return; - } - this.keys ??= this.defaultKeys(); - const common = this.common().filter(([n]) => this.keys.includes(n)); - this.keysBtn.textContent = `Match on: ${this.keys.join(', ') || 'nothing'}`; - if (!common.length) { this.grid.append(el('div.empty-state', { style: { gridColumn: '1 / -1' }, text: 'Choose at least one column that both runs have (Match on…).' })); return; } - const side = (run, other, mine, theirs) => { - const p = new ResultPanel({ runId: run.id, cmp: { run: other.id, keys: mine, other_keys: theirs, mode: this.mode }, label: shortName(run.plugin) }); - const h = el('div.cmp-h', {}, el('b', { text: '#' + run.id }), `${shortName(run.plugin)} ${run.args.join(' ')}`, el('span.muted', { text: `${fmtCount(run.rows)} rows` })); - const s = el('div.cmp-side', {}, h, p.node); - this.grid.append(s); - return p; - }; - this.pa = side(ra, rb, common.map(c => c[1]), common.map(c => c[2])); - this.pb = side(rb, ra, common.map(c => c[2]), common.map(c => c[1])); - } - - focus() { if (this.pa) this.pa.table.root.focus({ preventScroll: true }); } - focusFilter() { if (this.pa) this.pa.focusFilter(); } - destroy() { if (this.pa) { this.pa.destroy(); this.pb.destroy(); } } -} - -// ------------------------------------------------------------------ shortcuts dialog -export function helpDialog() { - const box = el('div.dialog', { 'aria-label': 'Keyboard shortcuts' }); - const keys = el('div.keys'); - const sec = t => keys.append(el('h5', { text: t })); - const k = (ks, what) => keys.append(el('div.kk', {}, ...ks.map(x => el('kbd', { text: x }))), el('div', { text: what })); - sec('Anywhere'); - k(['Ctrl', 'K'], 'Run a plugin (search all plugins)'); - k(['/'], 'Filter the current table'); - k(['T'], 'Filter the process tree'); - k(['O'], 'Overview'); - k(['M'], 'Memory viewer at an address'); - k(['Alt', '1…9'], 'Go to tab N'); - k(['[', ']'], 'Previous / next tab'); - k(['Alt', 'W'], 'Close the tab'); - k(['Shift', 'T'], 'Light / dark theme'); - k(['?'], 'This help'); - sec('Tables'); - k(['↑↓', 'PgUp', 'PgDn'], 'Move; Ctrl+Home/End: first/last row'); - k(['←→'], 'Move between columns'); - k(['Enter'], 'Row details'); - k(['C'], 'Copy cell (Shift+C: row as TSV)'); - k(['S'], 'Sort by the column (again: reverse; Shift: add)'); - k(['F'], 'Per-column filters: text, =exact, !not, >0x10, <=5, /regex/, - (empty)'); - k(['H'], 'Open the address under the cursor in the memory viewer'); - k(['P'], 'Open the row\'s process'); - sec('Process tree'); - k(['↑↓←→'], 'Move / collapse / expand'); - k(['Enter'], 'Open the process view'); - k(['*'], 'Expand everything'); - k(['a…z'], 'Jump to a process by name'); - sec('Memory viewer'); - k(['G'], 'Go to address'); - k(['Enter'], 'Follow the pointer under the cursor'); - k(['Backspace'], 'Back'); - k(['D'], 'Disassemble from the cursor'); - k(['Shift', '←→'], 'Select a range; C copies it as hex'); - const m = modal(box); - box.append(el('div.card-h', {}, el('h3', { text: 'Keyboard shortcuts' }), el('button.iconbtn', { type: 'button', 'aria-label': 'Close', text: '×', on: { click: () => m.close() } })), keys); - box.querySelector('button').focus(); -} - -export function memoryPrompt() { - const box = el('div.dialog', { 'aria-label': 'Open memory' }); - const inp = el('input.input', { type: 'text', placeholder: '0xfffff80000000000', 'aria-label': 'Address', style: { width: '100%' } }); - const lay = el('select.input', { 'aria-label': 'Address space' }, el('option', { value: 'kernel', text: 'Kernel virtual' }), el('option', { value: 'phys', text: 'Physical' }), - ...(store.procs || []).filter(p => p.exit === null).map(p => el('option', { value: 'pid:' + p.pid, text: `Process ${p.pid} ${p.name}` }))); - const m = modal(box); - const go = () => { - let v = inp.value.trim(); - if (/^[0-9a-f]+$/i.test(v) && !/^\d+$/.test(v)) v = '0x' + v; - const n = int0(v); - if (n === null || n < 0n) { inp.classList.add('invalid'); return; } - m.close(); - openHex(lay.value, '0x' + n.toString(16)); - }; - inp.addEventListener('keydown', e => { if (e.key === 'Enter') go(); }); - box.append(el('div.card-h', {}, el('h3', { text: 'Open memory at an address' })), el('div.card-b', { style: { display: 'grid', gap: '8px' } }, lay, inp, el('div', {}, el('button.btn.primary', { type: 'button', on: { click: go } }, 'Open')))); - inp.focus(); -} diff --git a/src/web/assets/workspace.js b/src/web/assets/workspace.js new file mode 100644 index 0000000..235935a --- /dev/null +++ b/src/web/assets/workspace.js @@ -0,0 +1,521 @@ +// The workspace: four panels. File overview (left, terminal style), plugins (middle), runs (top +// right) and triage hints (bottom right). Each panel re-renders itself from the store. + +import { store, api, on, el, clear, fmtBytes, fmtCount, fmtMs, fmtTime, pluginOs, shortName, sessionBatches, prefs, toast } from './core.js'; +import { blurb } from './catalog.js'; +import { captureTime, triageGroups } from './procdata.js'; +import { openResults, openBatchId } from './results.js'; +import { builtinPresets, userPresets, loadUserPresets, savePreset, deletePreset } from './presets.js'; +import { loadSavedRules, setRules, clearRules, currentRules, ruleGroups } from './rules.js'; + +const $ = id => document.getElementById(id); + +// ------------------------------------------------------------------ top bar +export function renderTopbar() { + const s = store.session; + const name = $('wb-ev-name'), meta = $('wb-ev-meta'); + if (!s || !s.image) { name.textContent = 'no image'; meta.textContent = ''; document.title = 'fastvol'; return; } + name.textContent = s.name; + name.title = s.image; + const parts = [fmtBytes(s.size)]; + const os = osLabel(s); + if (os) parts.push(os); + const cap = captureTime(); + if (cap) parts.push('captured ' + fmtTime(cap) + ' UTC'); + if (s.state === 'warming') parts.push((s.phase || 'preparing') + '…'); + if (s.state === 'failed') parts.push('not recognised'); + meta.textContent = parts.join(' · '); + document.title = `${s.name} - fastvol`; +} + +function osLabel(s) { + const F = Object.fromEntries(s.facts || []); + const arch = s.arch === 'intel64' ? 'x64' : s.arch ? 'x86' : ''; + if (s.os === 'windows') { const b = (F['Major/Minor'] || '').split('.').pop(); return ['Windows', b && 'build ' + b, arch].filter(Boolean).join(' '); } + if (s.os === 'linux') return ['Linux', ((F.Banner || '').match(/Linux version (\S+)/) || [])[1], arch].filter(Boolean).join(' '); + if (s.os === 'mac') return ['macOS', ((F.Banner || '').match(/Darwin Kernel Version (\S+?):/) || [])[1], arch].filter(Boolean).join(' '); + return ''; +} + +// ------------------------------------------------------------------ file overview (terminal) +/** `key ....... value` lines, key and value on the same line. All sections share one value + * column (as wide as the longest key shown), so `fvol info` and `fvol windows.info` line up; + * long values wrap under their own start. */ +const present = rows => rows.filter(r => r && r[1] !== undefined && r[1] !== null && r[1] !== ''); +function section(rows, w) { + return rows.map(([k, v, cls]) => el('div.tl', {}, + el('span.tk', { text: k + ' ' + '.'.repeat(w - k.length - 1) }), + el('span.tv', { class: 'tv ' + (cls || ''), text: String(v) }))); +} + +// facts too long for the shared column and of no use for triage +const HIDDEN_FACTS = new Set(['PE MajorOperatingSystemVersion', 'PE MinorOperatingSystemVersion', 'PE TimeDateStamp']); + +const prompt = cmd => el('div.tl.tp', {}, el('span.tpr', { text: 'fastvol$ ' }), el('span', { text: cmd })); +const comment = t => el('div.tl.tc', { text: '# ' + t }); +const blank = () => el('div.tl', { text: ' ' }); +const isAddr = v => /^0x[0-9a-f]+$/i.test(v); + +export function renderOverview() { + const box = $('overview'); + const s = store.session; + clear(box); + box.append(prompt('fvol info')); + if (!s || !s.image) { + box.append(el('div.tl.tdim', { text: 'no memory image loaded.' }), el('div.tl.tdim', { text: 'open one from Quick Start.' })); + return; + } + const cap = captureTime(); + const procs = store.procs; + const info = present([ + ['image', s.name, 'hi'], + ['path', s.image], + ['size', `${fmtBytes(s.size)} (${fmtCount(s.size)} bytes)`], + ['state', s.state === 'ready' ? `ready${s.warm_ms != null ? ' in ' + fmtMs(s.warm_ms) : ''}` : s.state === 'warming' ? (s.phase || 'preparing') + '…' : s.state, s.state === 'failed' ? 'bad' : s.state === 'ready' ? 'ok' : ''], + ['os', osLabel(s)], + ['captured', cap ? fmtTime(cap) + ' UTC' : ''], + ['processes', procs ? `${fmtCount(procs.length)} (${procs.filter(p => p.exit !== null).length} exited)` : s.state === 'ready' ? (store.procError ? 'unavailable' : 'reading…') : ''], + ['symbols', s.symbol_dirs.length ? s.symbol_dirs.join('; ') : 'default search path'], + ['offline', s.offline ? 'yes' : 'no'], + ['output', s.output_dir], + ]); + const facts = present((s.facts || []).filter(([k]) => !HIDDEN_FACTS.has(k)).map(([k, v]) => [k, v, isAddr(v) ? 'addr' : ''])); + const w = Math.max(...info.concat(facts).map(([k]) => k.length)) + 3; + box.append(...section(info, w)); + if (s.state === 'failed') { + box.append(blank(), comment('error'), el('div.tl.bad', { text: s.error || 'The image could not be analysed.' })); + for (const b of s.banners || []) box.append(el('div.tl.tdim', { text: 'banner: ' + b })); + for (const n of s.notes || []) box.append(el('div.tl.tdim', { text: n })); + } + if (facts.length) { + box.append(blank(), prompt(s.os === 'windows' ? 'fvol windows.info' : 'fvol banners')); + box.append(...section(facts, w)); + } +} + +// ------------------------------------------------------------------ plugins +// Two views under the Plugins header: Presets, and Select (every plugin with a checkbox; a ticked +// plugin unfolds its options). Once anything is ticked, a Run bar slides up at the bottom. + +const OS_TABS = [['all', 'All'], ['windows', 'Windows'], ['linux', 'Linux'], ['mac', 'macOS'], ['generic', 'Other']]; +const pl = { view: 'select', q: '', os: null, sel: new Map(), fromPreset: null }; // sel: plugin name -> { option name: value } + +const optReqs = p => p.reqs.filter(r => r.flag); +const required = r => !r.optional && (r.default === null || r.default === undefined); +const PLACEHOLDER = { int: 'number, e.g. 1234 or 0x4d2', list_int: 'numbers, e.g. 4 628 1136', str: 'text', list_str: 'values, space separated', uri: 'path or file:// URL' }; + +export function renderPlugins() { + const box = $('plugins'); + const s = store.session; + if (pl.os === null) pl.os = prefs.get('plOs', null) || (s && s.os) || 'all'; + $('pl-tab-presets').setAttribute('aria-selected', String(pl.view === 'presets')); + $('pl-tab-select').setAttribute('aria-selected', String(pl.view === 'select')); + updateActions(); + clear(box); + if (pl.view === 'presets') { renderPresets(box); return; } + const search = el('input.wb-input', { type: 'search', value: pl.q, placeholder: 'Search plugins', spellcheck: false, autocomplete: 'off', 'aria-label': 'Search plugins' }); + const tabs = el('div.wb-seg', { role: 'tablist', 'aria-label': 'Operating system' }); + for (const [id, label] of OS_TABS) { + const n = id === 'all' ? store.plugins.length : store.plugins.filter(p => pluginOs(p.name) === id).length; + tabs.append(el('button', { type: 'button', role: 'tab', 'aria-selected': String(pl.os === id), on: { click: () => { pl.os = id; prefs.set('plOs', id); renderPlugins(); } } }, label, el('span', { text: String(n) }))); + } + const list = el('div.pl-list', { role: 'list' }); + const fill = () => { + clear(list); + const q = pl.q.trim().toLowerCase(); + const shown = store.plugins.filter(p => (pl.os === 'all' || pluginOs(p.name) === pl.os) && + (!q || p.name.toLowerCase().includes(q) || (blurb(p.name) || p.description || '').toLowerCase().includes(q))); + for (const p of shown) list.append(pluginRow(p)); + if (!shown.length) list.append(el('div.wb-empty', { text: 'No plugin matches “' + pl.q + '”.' })); + }; + search.addEventListener('input', () => { pl.q = search.value; fill(); }); + box.append(el('div.pl-tools', {}, search, tabs), list); + fill(); +} + +function pluginRow(p) { + const reqs = optReqs(p); + const on = pl.sel.has(p.name); + const cb = el('input.wb-check', { type: 'checkbox', checked: on, 'aria-label': 'Select ' + p.name, tabindex: -1 }); + const head = el('div.pl-row', { role: 'listitem', tabindex: 0, title: p.name, 'aria-checked': String(on), class: 'pl-row' + (on ? ' on' : '') }, + cb, + el('div.pl-text', {}, + el('div.pl-main', {}, el('span.pl-name', { text: shortName(p.name) }), el('span.pl-full', { text: p.name })), + el('div.pl-desc', { text: blurb(p.name) || p.description || '' })), + reqs.length ? el('span.pl-opts', { text: reqs.length === 1 ? '1 option' : `${reqs.length} options` }) : el('span')); + const wrap = el('div.pl-item', {}, head); + const toggle = () => { + if (pl.sel.has(p.name)) pl.sel.delete(p.name); else pl.sel.set(p.name, {}); + wrap.replaceWith(pluginRow(p)); + updateActions(); + const again = document.querySelector(`.pl-row[title="${CSS.escape(p.name)}"]`); + if (again) again.focus({ preventScroll: true }); + }; + head.addEventListener('click', e => { if (e.target !== cb) e.preventDefault(); toggle(); }); + head.addEventListener('keydown', e => { + if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); toggle(); } + if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { + e.preventDefault(); + const rows = [...document.querySelectorAll('.pl-row')]; + const k = rows.indexOf(head) + (e.key === 'ArrowDown' ? 1 : -1); + if (rows[k]) rows[k].focus(); + } + }); + if (on && reqs.length) wrap.append(optionsBlock(p, reqs)); + return wrap; +} + +/** The options of a ticked plugin: checkboxes for flags, small inputs for values. */ +function optionsBlock(p, reqs) { + const vals = pl.sel.get(p.name); + const box = el('div.pl-options', { role: 'group', 'aria-label': 'Options of ' + p.name }); + for (const r of reqs) { + const id = `opt-${p.name}-${r.name}`.replace(/[^\w-]/g, '_'); + const desc = el('span.po-desc', { text: r.description || '' }); + if (r.kind === 'bool') { + const cb = el('input.wb-check', { id, type: 'checkbox', checked: !!vals[r.name], on: { change: () => { if (cb.checked) vals[r.name] = true; else delete vals[r.name]; } } }); + box.append(el('label.po-row.po-flag', { for: id }, cb, el('code.po-flagname', { text: r.flag }), desc)); + continue; + } + let input; + if (r.kind === 'choice') { + input = el('select.wb-select', { id }, el('option', { value: '', text: r.default ? `default (${r.default})` : '-' }), ...(r.choices || []).map(c => el('option', { value: c, text: c }))); + input.value = vals[r.name] || ''; + input.addEventListener('change', () => { if (input.value) vals[r.name] = input.value; else delete vals[r.name]; }); + } else { + input = el('input.wb-input.po-input', { id, type: 'text', value: vals[r.name] || '', spellcheck: false, autocomplete: 'off', + placeholder: r.default !== null && r.default !== undefined && !(Array.isArray(r.default) && !r.default.length) ? `default ${r.default}` : PLACEHOLDER[r.kind] || '' }); + input.addEventListener('input', () => { if (input.value.trim()) vals[r.name] = input.value.trim(); else delete vals[r.name]; }); + } + box.append(el('div.po-row.po-value', {}, + el('label.po-flagname', { for: id }, el('code', { text: r.flag }), required(r) ? el('span.po-req', { text: 'required' }) : null), + input, desc)); + } + return box; +} + +// ------------------------------------------------------------------ presets + +/** The Presets view: built-in sets for the image's OS, then the user's own from ~/.fvol/presets. */ +function renderPresets(box) { + const s = store.session; + const os = s && s.os; + const list = el('div.ps-list'); + const builtin = builtinPresets(os); + list.append(el('div.ps-sec', {}, el('span', { text: 'Built-in' }), el('span.ps-sec-note', { text: os ? `for ${osName(os)} images` : 'all systems' }))); + for (const p of builtin) list.append(presetRow(p)); + if (!builtin.length) list.append(el('div.wb-empty', { text: 'No built-in presets for this system.' })); + list.append(el('div.ps-sec', {}, el('span', { text: 'Yours' }), el('span.ps-sec-note', { text: userPresets.dir ? userPresets.dir.replace(/^\/home\/[^/]+/, '~') : '~/.fvol/presets' }))); + if (!userPresets.loaded) { + list.append(el('div.wb-empty', {}, el('span.wb-spin'), 'Reading your presets…')); + loadUserPresets().then(() => { if (pl.view === 'presets') renderPlugins(); }); + } else if (userPresets.error) { + list.append(el('div.wb-empty', { text: 'Could not read your presets: ' + userPresets.error })); + } else { + for (const p of userPresets.list) list.append(presetRow(p)); + if (!userPresets.list.length) list.append(el('div.wb-empty', {}, el('div', { text: 'No saved presets yet.' }), el('div.wb-empty-sub', { text: 'Tick plugins under Select, then press Save Preset.' }))); + for (const e of userPresets.errors) list.append(el('div.ps-bad', { text: `${e.file}: ${e.error}` })); + } + box.append(list); +} + +const osName = os => ({ windows: 'Windows', linux: 'Linux', mac: 'macOS', generic: 'any', any: 'any system', mixed: 'mixed' }[os] || os || 'any'); + +function presetRow(p) { + const missing = p.plugins.filter(e => !store.pluginMap.has(e.plugin)).length; + const names = p.plugins.map(e => shortName(e.plugin) + (e.args && Object.keys(e.args).length ? ' (' + Object.keys(e.args).map(k => '--' + k.replace(/_/g, '-')).join(' ') + ')' : '')); + const actions = el('div.ps-actions'); + if (!p.builtin) { + actions.append(el('button.wb-btn.ghost.sm', { type: 'button', text: 'Delete', title: `Delete ${p.id}.json`, on: { click: async e => { + e.stopPropagation(); + if (!confirm(`Delete the preset “${p.name}”? This removes ~/.fvol/presets/${p.id}.json.`)) return; + try { await deletePreset(p.id); toast(`Deleted “${p.name}”`); } catch (x) { toast(x.message, 'bad'); } + await loadUserPresets(); + renderPlugins(); + } } })); + } + const row = el('div.ps-row', { role: 'button', tabindex: 0, title: 'Select these plugins' }, + el('div.ps-text', {}, + el('div.ps-head', {}, el('span.ps-name', { text: p.name }), el('span.ps-os', { text: osName(p.os) }), + el('span.ps-n', { text: p.plugins.length === 1 ? '1 plugin' : `${p.plugins.length} plugins` })), + el('div.ps-plugins', { text: names.join(', ') }), + missing ? el('div.ps-bad', { text: `${missing} plugin(s) not in this build will be skipped.` }) : null), + actions); + const use = () => { + pl.sel.clear(); + for (const e of p.plugins) { + if (!store.pluginMap.has(e.plugin)) continue; + const vals = {}; + for (const [k, v] of Object.entries(e.args || {})) vals[k] = Array.isArray(v) ? v.join(' ') : v; + pl.sel.set(e.plugin, vals); + } + pl.fromPreset = p.name; + pl.view = 'select'; + renderPlugins(); + toast(`Selected ${pl.sel.size} plugin${pl.sel.size === 1 ? '' : 's'} from “${p.name}”`); + }; + row.addEventListener('click', use); + row.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); use(); } }); + return row; +} + +/** Save Preset: a name, and exactly what will be saved. */ +function savePresetDialog() { + if (!pl.sel.size || document.querySelector('.wb-dialog')) return; + const oses = new Set([...pl.sel.keys()].map(pluginOs)); + const os = oses.size === 1 ? [...oses][0] : 'mixed'; + const name = el('input.wb-input', { type: 'text', maxlength: 80, placeholder: 'e.g. Ransomware sweep', spellcheck: false, autocomplete: 'off', 'aria-label': 'Preset name' }); + const errBox = el('div.dl-err', { role: 'alert' }); + const saveBtn = el('button.wb-btn.primary', { type: 'button', text: 'Save' }); + const cancel = el('button.wb-btn.ghost', { type: 'button', text: 'Cancel' }); + const items = el('ul.dl-items'); + for (const [plugin, args] of pl.sel) { + const opts = Object.entries(args).map(([k, v]) => '--' + k.replace(/_/g, '-') + (v === true ? '' : ' ' + v)).join(' '); + items.append(el('li', {}, el('span.dl-p', { text: shortName(plugin) }), opts ? el('code', { text: opts }) : null)); + } + const scrim = el('div.wb-scrim'); + const box = el('div.wb-dialog', { role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'dl-h' }, + el('h2#dl-h', { text: 'Save Preset' }), + el('label.dl-field', {}, el('span', { text: 'Name' }), name), + el('div.dl-field', {}, el('span', { text: `${pl.sel.size} plugin${pl.sel.size === 1 ? '' : 's'} · ${osName(os)}` }), items), + errBox, + el('div.dl-actions', {}, cancel, saveBtn)); + const close = () => { scrim.remove(); box.remove(); removeEventListener('keydown', onKey, true); }; + const onKey = e => { if (e.key === 'Escape') { e.preventDefault(); close(); } if (e.key === 'Enter' && e.target.tagName === 'INPUT') { e.preventDefault(); save(false); } }; + async function save(overwrite) { + errBox.replaceChildren(); + if (!name.value.trim()) { errBox.textContent = 'Give the preset a name.'; name.focus(); return; } + saveBtn.disabled = true; + try { + const p = await savePreset({ name: name.value.trim(), os, selection: pl.sel, overwrite }); + close(); + toast(`Saved “${p.name}” to ~/.fvol/presets/${p.id}.json`); + await loadUserPresets(); + if (pl.view === 'presets') renderPlugins(); + } catch (e) { + if (e.status === 409) errBox.append(e.message + '. ', el('button.dl-link', { type: 'button', text: 'Replace it', on: { click: () => save(true) } })); + else errBox.textContent = e.message; + } + saveBtn.disabled = false; + } + saveBtn.addEventListener('click', () => save(false)); + cancel.addEventListener('click', close); + scrim.addEventListener('click', close); + addEventListener('keydown', onKey, true); + document.body.append(scrim, box); + name.focus(); +} + +/** Save Preset and Run in the Plugins header: shown once a plugin is ticked. */ +function updateActions() { + const n = pl.sel.size; + $('pl-save').hidden = n === 0; + $('pl-run').hidden = n === 0; + $('pl-run-label').textContent = n > 1 ? `Run ${n}` : 'Run'; + $('pl-run').title = [...pl.sel.keys()].join('\n'); +} + +/** Run: every ticked plugin, with its options, starts together as one run. */ +async function startSelected() { + const btn = $('pl-run'); + btn.disabled = true; + try { + const entries = [...pl.sel].map(([plugin, args]) => ({ plugin, args })); + const b = await api('batches', { method: 'POST', body: { name: pl.fromPreset || undefined, entries } }); + if (!store.batches.some(x => x.id === b.id)) store.batches.push(b); + runsUi.open.add(b.id); + pl.sel.clear(); + pl.fromPreset = null; + renderPlugins(); + renderRuns(); + openResults(b.id); + } catch (e) { toast(e.message, 'bad'); } // nothing started: fix the option and press Run again + btn.disabled = false; +} + +// ------------------------------------------------------------------ runs +// Each run is a batch of plugin executions started together. A run expands to its plugins, +// each with its status, rows and time. The name can be changed by clicking it. + +const runsUi = { open: new Set(), renaming: null, timer: null }; + +const ACTIVE = st => st === 'queued' || st === 'running'; +const clock = ms => { const t = Math.max(0, Math.round(ms / 1000)); return t < 3600 ? `${Math.floor(t / 60)}:${String(t % 60).padStart(2, '0')}` : `${Math.floor(t / 3600)}:${String(Math.floor(t / 60) % 60).padStart(2, '0')}:${String(t % 60).padStart(2, '0')}`; }; + +function batchState(b) { + const runs = b.runs.map(id => store.runs.get(id)).filter(Boolean); + const count = st => runs.filter(r => r.status === st).length; + const active = runs.filter(r => ACTIVE(r.status)).length; + const failed = count('failed'), cancelled = count('cancelled'), done = count('done'); + const status = active ? 'running' : failed ? 'failed' : cancelled && !done ? 'cancelled' : 'done'; + const ends = runs.filter(r => r.started).map(r => r.started + r.elapsed); + const elapsed = active ? Date.now() - b.created : ends.length ? Math.max(...ends) - b.created : 0; + return { runs, active, failed, finished: runs.length - active, total: b.runs.length, status, elapsed }; +} + +export function renderRuns() { + const box = $('runs'); + const batches = sessionBatches(); + $('rn-count').textContent = batches.length ? String(batches.length) : ''; + const focused = document.activeElement && box.contains(document.activeElement) ? document.activeElement.dataset.key : null; + clear(box); + if (!batches.length) { + box.append(el('div.wb-empty', {}, el('div', { text: 'No runs yet.' }), el('div.wb-empty-sub', { text: 'Tick plugins in the middle and press Run.' }))); + } else { + const list = el('ol.rn-list'); + for (const b of batches) list.append(batchItem(b)); + box.append(list); + } + if (focused) { const f = box.querySelector(`[data-key="${focused}"]`); if (f) f.focus({ preventScroll: true }); } + // tick the clocks while anything runs + const anyActive = batches.some(b => batchState(b).active); + if (anyActive && !runsUi.timer) runsUi.timer = setInterval(() => { if (!runsUi.renaming) renderRuns(); }, 1000); + if (!anyActive && runsUi.timer) { clearInterval(runsUi.timer); runsUi.timer = null; } +} + +function batchItem(b) { + const st = batchState(b); + const open = runsUi.open.has(b.id); + const li = el('li.rn-batch', { class: 'rn-batch ' + st.status + (open ? ' open' : '') + (openBatchId() === b.id ? ' shown' : '') }); + const toggle = () => { if (open) runsUi.open.delete(b.id); else runsUi.open.add(b.id); renderRuns(); }; + // a click on the block: expand and show the results, or collapse when already expanded + const show = () => { if (open) { runsUi.open.delete(b.id); renderRuns(); return; } runsUi.open.add(b.id); openResults(b.id); renderRuns(); }; + let name; + if (runsUi.renaming === b.id) { + name = el('input.rn-rename', { type: 'text', value: b.name, maxlength: 80, 'aria-label': 'Run name', spellcheck: false }); + const finish = async save => { + if (runsUi.renaming !== b.id) return; + runsUi.renaming = null; + const v = name.value.trim(); + if (save && v && v !== b.name) { + try { const nb = await api(`batches/${b.id}/name`, { method: 'POST', body: { name: v } }); b.name = nb.name; } catch (e) { toast(e.message, 'bad'); } + } + renderRuns(); + }; + name.addEventListener('keydown', e => { e.stopPropagation(); if (e.key === 'Enter') finish(true); if (e.key === 'Escape') finish(false); }); + name.addEventListener('blur', () => finish(true)); + name.addEventListener('click', e => e.stopPropagation()); + setTimeout(() => { name.focus(); name.select(); }, 0); + } else { + name = el('button.rn-bname', { type: 'button', text: b.name, title: 'Rename', on: { click: e => { e.stopPropagation(); runsUi.renaming = b.id; renderRuns(); } } }); + } + const action = st.active + ? el('button.rn-act', { type: 'button', text: 'Cancel', title: 'Cancel the plugins still queued or running', on: { click: async e => { e.stopPropagation(); try { await api(`batches/${b.id}/cancel`, { method: 'POST' }); } catch (x) { toast(x.message, 'bad'); } } } }) + : el('button.rn-act', { type: 'button', text: 'Remove', title: 'Remove this run and its results', on: { click: async e => { + e.stopPropagation(); + if (!confirm(`Remove “${b.name}” and its results?`)) return; + try { await api(`batches/${b.id}`, { method: 'DELETE' }); store.batches = store.batches.filter(x => x.id !== b.id); renderRuns(); } catch (x) { toast(x.message, 'bad'); } + } } }); + const head = el('div.rn-head', { tabindex: 0, role: 'button', 'aria-expanded': String(open), dataset: { key: 'b' + b.id } }, + el('span.rn-caret', { 'aria-hidden': 'true', title: open ? 'Collapse' : 'Expand', on: { click: e => { e.stopPropagation(); toggle(); } } }), + name, + el('span.rn-prog', { title: `${st.finished} of ${st.total} plugins finished${st.failed ? `, ${st.failed} failed` : ''}` }, + el('span', { class: 'rn-state ' + st.status, 'aria-hidden': 'true' }), `${st.finished}/${st.total}`), + el('span.rn-time', { text: clock(st.elapsed) }), + action); + head.addEventListener('click', show); + head.addEventListener('keydown', e => { if (e.key === 'Enter') { e.preventDefault(); show(); } if (e.key === ' ' || e.key === 'ArrowRight' || e.key === 'ArrowLeft') { e.preventDefault(); toggle(); } if (e.key === 'F2') { runsUi.renaming = b.id; renderRuns(); } }); + li.append(head); + if (open) { + const ul = el('ul.rn-entries'); + for (const id of b.runs) { + const r = store.runs.get(id); + if (!r) continue; + const meta = r.status === 'done' ? `${fmtCount(r.rows)} rows` : r.status === 'running' ? `running ${clock(r.started ? Date.now() - r.started : 0)}` : r.status === 'queued' ? 'queued' : r.status; + const row = el('li.rn-entry', { title: `${r.plugin} ${r.args.join(' ')}` + (r.error && r.error.message ? '\n' + r.error.message : '') }, + el('span', { class: 'rn-dot ' + r.status }), + el('span.rn-name', {}, shortName(r.plugin), r.args.length ? el('span.rn-args', { text: ' ' + r.args.join(' ') }) : null), + el('span', { class: 'rn-meta ' + r.status, text: meta }), + ACTIVE(r.status) ? el('button.rn-act', { type: 'button', text: 'Cancel', title: 'Cancel this plugin', on: { click: async e => { e.stopPropagation(); try { await api(`runs/${r.id}/cancel`, { method: 'POST' }); } catch (x) { toast(x.message, 'bad'); } } } }) : el('span')); + row.addEventListener('click', () => { openResults(b.id, r.id); renderRuns(); }); + if (openBatchId() === b.id) row.classList.add('pick'); + ul.append(row); + } + li.append(ul); + } + return li; +} + +// ------------------------------------------------------------------ triage hints + +/** The header control: "Load rules…", or the loaded file with a way to replace or remove it. */ +function renderRulesControl() { + const box = $('tr-rules'); + clear(box); + const file = el('input', { type: 'file', accept: '.json,application/json', hidden: true }); + file.addEventListener('change', async () => { + const f = file.files && file.files[0]; + if (!f) return; + if (f.size > 1 << 20) { toast(`${f.name}: a rules file can be at most 1 MiB`, 'bad'); return; } + try { + const r = setRules(await f.text(), f.name); + toast(`Loaded ${r.rules.length} rule${r.rules.length === 1 ? '' : 's'} from ${f.name}`); + } catch (e) { toast(`${f.name}: ${e.message}`, 'bad'); } + renderRulesControl(); + renderTriage(); + }); + const pick = () => file.click(); + const r = currentRules(); + if (!r) { + box.append(file, el('button.wb-btn.outline.sm', { type: 'button', text: 'Load Rules…', title: 'Add your own triage rules from a JSON file', on: { click: pick } })); + return; + } + box.append(file, el('span.tr-loaded', {}, + el('button.tr-file', { type: 'button', title: `${r.file}: ${r.rules.length} rules\nClick to load another file`, text: r.name, on: { click: pick } }), + el('button.tr-x', { type: 'button', 'aria-label': 'Remove these rules', title: 'Remove these rules', text: '×', on: { click: () => { clearRules(); renderRulesControl(); renderTriage(); } } }))); +} + +function triageItem(g) { + const n = g.list.length; + const chips = el('div.tr-chips'); + for (const p of g.list.slice(0, 12)) chips.append(el('span.tr-chip', { title: p.flags.join('\n') || p.name, text: `${p.name} ${p.pid}` })); + if (n > 12) chips.append(el('span.tr-chip.more', { text: `+${n - 12}` })); + return el('div.tr-item', { class: 'tr-item' + (g.hot && n ? ' hot' : '') + (n ? '' : ' zero') }, + el('div.tr-n', { text: String(n) }), + el('div.tr-body', {}, + el('div.tr-t', {}, g.title, g.rule ? el('span', { class: 'tr-sev ' + g.severity, text: g.severity }) : null), + g.sub ? el('div.tr-s', { text: g.sub }) : null, n ? chips : null)); +} + +export function renderTriage() { + const box = $('triage'); + const s = store.session; + clear(box); + if (!s || !s.image) { box.append(el('div.wb-empty', { text: 'Open a memory image to see hints.' })); return; } + if (s.state === 'failed') { box.append(el('div.wb-empty', { text: 'The kernel was not identified, so there is nothing to triage.' })); return; } + if (store.procError) { box.append(el('div.wb-empty', { text: 'No process list: ' + store.procError })); return; } + if (!store.procs) { box.append(el('div.wb-empty', {}, el('span.wb-spin'), s.state === 'warming' ? 'Preparing the image…' : 'Reading the process list…')); return; } + const r = currentRules(); + if (r) { + box.append(el('div.tr-sec', { text: r.name })); + for (const g of ruleGroups(store.procs)) box.append(triageItem(g)); + box.append(el('div.tr-sec', { text: 'Built-in' })); + } + for (const g of triageGroups()) box.append(triageItem(g)); +} + +export function renderAll() { + renderRulesControl(); + refreshRules(); + renderTopbar(); + renderOverview(); + renderPlugins(); + renderRuns(); + renderTriage(); +} + +/** The open analysis's rules (they change when another dump is opened). */ +function refreshRules() { loadSavedRules().then(() => { renderRulesControl(); renderTriage(); }); } + +export function wire() { + $('pl-tab-presets').addEventListener('click', () => { pl.view = 'presets'; renderPlugins(); }); + $('pl-tab-select').addEventListener('click', () => { pl.view = 'select'; renderPlugins(); }); + $('pl-run').addEventListener('click', startSelected); + $('pl-save').addEventListener('click', savePresetDialog); + let sid = store.session && store.session.id; + on('session', () => { renderTopbar(); renderOverview(); renderTriage(); renderRuns(); if (store.session.id !== sid) { sid = store.session.id; refreshRules(); } }); + on('procs', () => { renderTopbar(); renderOverview(); renderTriage(); }); + on('runs', () => { if (!runsUi.renaming) renderRuns(); }); + on('batches', () => { if (!runsUi.renaming) renderRuns(); }); + document.addEventListener('fastvol-results', () => renderRuns()); +} diff --git a/src/web/mod.rs b/src/web/mod.rs index 8ce1d0b..50e9419 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -11,11 +11,15 @@ //! call; Host headers are validated (DNS rebinding); no CORS; cross-site requests refused; //! strict request limits; downloads only from a run's own output directory. +pub mod analysis; pub mod api; pub mod assets; pub mod http; pub mod jsonw; pub mod mem; +pub mod options; +pub mod picker; +pub mod presets; pub mod runs; pub mod security; pub mod server; @@ -49,30 +53,48 @@ pub struct App { pub tickets: security::Tickets, pub export_seq: AtomicU64, pub started: Instant, + /// the global fvol options (the Options dialog), saved with the analysis + pub options: Mutex, + /// options given on the `fvol serve` command line: they win over a saved analysis's + cli_options: options::Options, + /// the output folder `fvol serve -o` was given (used unless the options name another) + default_out: PathBuf, + /// the loaded triage rules file (name, content), saved with the analysis + pub rules: Mutex>, + /// the saved analysis of the open dump (`~/.fvol/-metadata.json`) + pub analysis: Mutex>, } impl App { - pub fn new(token: String, port: u16, hosts: security::HostPolicy, opts: SessionOpts, max_parallel: usize, budget: u64) -> Result, String> { + pub fn new(token: String, port: u16, hosts: security::HostPolicy, opts: SessionOpts, max_parallel: usize, budget: u64, cli_options: options::Options) -> Result, String> { let plugins = crate::plugins::all(); let hub = Arc::new(Hub::default()); - let session = Arc::new(Session::new(1, &opts).map_err(|e| e.to_string())?); + let image = opts.image.clone(); + let idle = SessionOpts { image: None, ..opts.clone() }; + let session = Arc::new(Session::new(1, &idle).map_err(|e| e.to_string())?); let app = Arc::new(App { token, port, hosts, plugins_json: api::plugins_json(&plugins), plugins, - session: RwLock::new(session.clone()), + session: RwLock::new(session), + default_out: opts.out_root.clone(), base_opts: Mutex::new(opts), runs: Arc::new(Runs::new(hub.clone(), max_parallel, budget)), hub, - next_session: AtomicU64::new(2), + next_session: AtomicU64::new(1), auth_failures: AtomicU64::new(0), tickets: security::Tickets::default(), export_seq: AtomicU64::new(1), started: Instant::now(), + options: Mutex::new(cli_options.clone()), + cli_options, + rules: Mutex::new(None), + analysis: Mutex::new(None), }); - app.start_warm_up(session); + app.open_image(image, false)?; + analysis::start_saver(app.clone()); Ok(app) } @@ -85,16 +107,111 @@ impl App { let _ = std::thread::Builder::new().name("warm-up".into()).stack_size(64 << 20).spawn(move || s.warm_up(&me.hub, &me.plugins)); } - /// Switch to another image (explicit user action). - pub fn open(self: &Arc, o: SessionOpts) -> Result, String> { - let id = self.next_session.fetch_add(1, Ordering::Relaxed); + /// Open an image (or none). A dump with a saved analysis gets its options, rules and runs + /// back. `same_session`: reopen the open dump with changed options, keeping its runs. + pub fn open_image(self: &Arc, image: Option, same_session: bool) -> Result, String> { + let cwd = std::env::current_dir().unwrap_or_else(|_| "/".into()); + let mut meta = None; + let mut fresh = None; + if !same_session { + // the background saver runs about once a second: save the dump being left now, so a + // change made just before switching is not lost + analysis::save(self); + fresh = image.as_deref().and_then(analysis::Analysis::new); + meta = fresh.as_ref().and_then(|a| analysis::load(&a.id)); + if let Some(m) = &meta { + if let Some(o) = m.get("options").and_then(|o| options::Options::from_json(o, &cwd).ok()) { + *self.options.lock().unwrap_or_else(|e| e.into_inner()) = self.with_cli(o); + } + *self.rules.lock().unwrap_or_else(|e| e.into_inner()) = m.get("rules").and_then(|r| Some((r.get("file")?.as_str()?.to_string(), r.get("text")?.as_str()?.to_string()))); + } + } + let opts = self.options.lock().unwrap_or_else(|e| e.into_inner()).clone(); + let mut o = self.base_opts.lock().unwrap_or_else(|e| e.into_inner()).clone(); + o.image = image; + opts.apply_opening(&mut o, &self.default_out); + let id = if same_session { self.session().id } else { self.next_session.fetch_add(1, Ordering::Relaxed) }; let s = Arc::new(Session::new(id, &o).map_err(|e| e.to_string())?); - *self.base_opts.lock().unwrap_or_else(|e| e.into_inner()) = o; + // --clear-cache acts once, at this open + if opts.clear_cache { + self.options.lock().unwrap_or_else(|e| e.into_inner()).clear_cache = false; + } + *self.base_opts.lock().unwrap_or_else(|e| e.into_inner()) = SessionOpts { clear_cache: false, ..o }; *self.session.write().unwrap_or_else(|e| e.into_inner()) = s.clone(); + self.apply_run_options(&opts); + if !same_session { + *self.analysis.lock().unwrap_or_else(|e| e.into_inner()) = fresh; + if let Some(m) = &meta { + analysis::restore(self, &s, m); + } + } self.hub.bump(); self.start_warm_up(s.clone()); Ok(s) } + + /// Switch to another image (explicit user action). + pub fn open(self: &Arc, image: PathBuf) -> Result, String> { + self.open_image(Some(image), false) + } + + /// Delete a saved analysis. For the dump that is open, its runs and results go too and it + /// starts over (its options stay in use, so its analysis is saved again, empty). + pub fn delete_analysis(&self, id: &str) -> Result<(), String> { + // the saver waits on this lock: nothing is written back halfway + let mut guard = self.analysis.lock().unwrap_or_else(|e| e.into_inner()); + if let Some(a) = guard.as_mut().filter(|a| a.id == id) { + let session = self.session().id; + for b in self.runs.batches().into_iter().filter(|b| b.session == session) { + self.runs.remove_batch(b.id); + } + a.saved_rows.clear(); + a.last.clear(); + a.created_ms = runs::now_ms(); + } + analysis::delete_in(&presets::fvol_dir(), id) + } + + /// Options from the Options dialog. Returns whether the image was reopened (an option that + /// decides how it is opened changed). + pub fn set_options(self: &Arc, new: options::Options) -> Result { + let old = std::mem::replace(&mut *self.options.lock().unwrap_or_else(|e| e.into_inner()), new.clone()); + let session = self.session(); + let reopen = old.opening_differs(&new) && session.image.is_some(); + if reopen { + self.open_image(session.image.clone(), true)?; + } else { + self.apply_run_options(&new); + self.hub.bump(); + } + Ok(reopen) + } + + /// Options given on the command line win over saved ones. + fn with_cli(&self, mut o: options::Options) -> options::Options { + let c = &self.cli_options; + if !c.symbol_dirs.is_empty() { + o.symbol_dirs = c.symbol_dirs.clone(); + } + if c.offline { + o.offline = true; + o.remote_isf_url = None; + } + if c.remote_isf_url.is_some() { + o.remote_isf_url = c.remote_isf_url.clone(); + o.offline = false; + } + if c.cache_path.is_some() { + o.cache_path = c.cache_path.clone(); + } + o + } + + fn apply_run_options(self: &Arc, o: &options::Options) { + self.runs.set_parallel(o.parallel(self.runs.max_parallel)); + *self.runs.log.lock().unwrap_or_else(|e| e.into_inner()) = o.log.clone(); + *self.runs.config_name.lock().unwrap_or_else(|e| e.into_inner()) = o.config_file_name(); + } } pub(crate) const USAGE: &str = "usage: fvol serve [-h] [-f FILE] [--host HOST] [--port PORT] [-s SYMBOL_DIRS] [-o OUTPUT_DIR] @@ -283,9 +400,10 @@ pub fn main(args: &[String]) -> i32 { None => cwd.join("vol-serve-output"), }; let symbol_dirs: Vec = symbol_dirs.iter().map(|d| crate::cli::abspath(d, &cwd.to_string_lossy())).collect(); - let opts = SessionOpts { image: image.clone(), symbol_dirs, out_root: out_root.clone(), offline, remote_isf_url: remote, cache_path: cache }; + let opts = SessionOpts { image: image.clone(), symbol_dirs, out_root: out_root.clone(), offline, remote_isf_url: remote, cache_path: cache, ..Default::default() }; let hosts = security::HostPolicy { port, wildcard: ip.is_unspecified(), bind: if ip.is_unspecified() { None } else { Some(ip) }, names: allow }; - let app = match App::new(token.clone(), port, hosts, opts, parallel, budget) { + let cli_options = options::Options { symbol_dirs: opts.symbol_dirs.clone(), offline: opts.offline, remote_isf_url: opts.remote_isf_url.clone(), cache_path: opts.cache_path.clone(), ..Default::default() }; + let app = match App::new(token.clone(), port, hosts, opts, parallel, budget, cli_options) { Ok(a) => a, Err(e) => { eprintln!("fvol serve: {e}"); diff --git a/src/web/options.rs b/src/web/options.rs new file mode 100644 index 0000000..62ec016 --- /dev/null +++ b/src/web/options.rs @@ -0,0 +1,330 @@ +//! The global `fvol` options of the Options dialog, saved with the analysis. Each does what it +//! does on the command line, applied at the matching step: opening the image, starting a run, +//! or the `fvol` output export (the table is in docs/web-ui.md, Options). + +use super::jsonw::W; +use crate::cli::json::{self, Json}; +use crate::plugins::Plugin; +use std::path::Path; + +pub const PARALLELISM: [&str; 3] = ["processes", "threads", "off"]; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct Options { + pub config: Option, + pub parallelism: Option, + pub extend: Vec, + pub plugin_dirs: Option, + pub symbol_dirs: Vec, + pub verbosity: u8, + pub log: Option, + pub output_dir: Option, + pub quiet: bool, + pub write_config: bool, + pub save_config: Option, + pub clear_cache: bool, + pub cache_path: Option, + pub offline: bool, + pub remote_isf_url: Option, + pub filters: Vec, + pub hide_columns: Vec, + pub renderer: Option, + pub single_location: Option, + pub stackers: Option>, + pub single_swap_locations: Vec, +} + +fn text(j: &Json, k: &str) -> Option { + j.get(k).and_then(|v| v.as_str()).map(|s| s.trim().to_string()).filter(|s| !s.is_empty()) +} +fn list(j: &Json, k: &str) -> Result, String> { + match j.get(k) { + None | Some(Json::Null) => Ok(Vec::new()), + Some(Json::Arr(a)) => a.iter().map(|x| x.as_str().map(|s| s.to_string()).ok_or_else(|| format!("\"{k}\" must be a list of text"))).collect::, _>>().map(|v| v.into_iter().map(|s| s.trim().to_string()).filter(|s| !s.is_empty()).collect()), + Some(Json::Str(s)) => Ok(s.split(';').map(|x| x.trim().to_string()).filter(|x| !x.is_empty()).collect()), + Some(_) => Err(format!("\"{k}\" must be a list of text")), + } +} +fn flag(j: &Json, k: &str) -> bool { + matches!(j.get(k), Some(Json::Bool(true))) +} + +impl Options { + /// Read options (the dialog's, or a saved analysis's); checks what the CLI checks. + pub fn from_json(j: &Json, cwd: &Path) -> Result { + let abs = |p: String| cwd.join(p).to_string_lossy().into_owned(); + let o = Options { + config: text(j, "config").map(abs), + parallelism: text(j, "parallelism"), + extend: list(j, "extend")?, + plugin_dirs: text(j, "plugin_dirs"), + symbol_dirs: list(j, "symbol_dirs")?.into_iter().map(abs).collect(), + verbosity: match j.get("verbosity") { + Some(Json::Int(i)) => (*i).clamp(0, 5) as u8, + _ => 0, + }, + log: text(j, "log").map(abs), + output_dir: text(j, "output_dir").map(abs), + quiet: flag(j, "quiet"), + write_config: flag(j, "write_config"), + save_config: text(j, "save_config"), + clear_cache: flag(j, "clear_cache"), + cache_path: text(j, "cache_path").map(abs), + offline: flag(j, "offline"), + remote_isf_url: text(j, "remote_isf_url"), + filters: list(j, "filters")?, + hide_columns: list(j, "hide_columns")?, + renderer: text(j, "renderer"), + single_location: text(j, "single_location"), + stackers: match j.get("stackers") { + None | Some(Json::Null) => None, + _ => Some(list(j, "stackers")?), + }, + single_swap_locations: list(j, "single_swap_locations")?, + }; + o.check()?; + Ok(o) + } + + fn check(&self) -> Result<(), String> { + if self.offline && self.remote_isf_url.is_some() { + return Err("--offline and --remote-isf-url cannot be used together".into()); + } + if let Some(p) = &self.parallelism + && !PARALLELISM.contains(&p.as_str()) + { + return Err(format!("--parallelism: choose from {}", PARALLELISM.join(", "))); + } + if let Some(r) = &self.renderer + && !crate::renderers::text::RENDERER_NAMES.contains(&r.as_str()) + { + return Err(format!("--renderer: choose from {}", crate::renderers::text::RENDERER_NAMES.join(", "))); + } + if let Some(c) = &self.config { + read_config(c)?; + } + for e in &self.extend { + parse_extend(e)?; + } + if let Some(d) = &self.output_dir + && !Path::new(d).is_dir() + { + return Err(format!("--output-dir: {d} is not a directory")); + } + if let Some(d) = &self.cache_path + && !Path::new(d).is_dir() + { + return Err(format!("--cache-path: {d} is not a directory")); + } + if let Some(l) = &self.log { + // the server appends to it: only a log file, never a link or another kind of file + if !l.to_ascii_lowercase().ends_with(".log") { + return Err("--log: the file name must end in .log".into()); + } + if !Path::new(l).parent().is_some_and(|p| p.is_dir()) { + return Err(format!("--log: the folder of {l} does not exist")); + } + if std::fs::symlink_metadata(l).is_ok_and(|m| !m.is_file()) { + return Err(format!("--log: {l} is not a regular file")); + } + } + if let Some(s) = &self.save_config + && (s.contains('/') || s.starts_with('.')) + { + return Err("--save-config: a file name (it is written into each run's output folder)".into()); + } + Ok(()) + } + + pub fn write(&self, w: &mut W) { + let opt = |w: &mut W, k: &str, v: &Option| { + match v { + Some(s) => w.ks(k, s), + None => w.key(k).null(), + }; + }; + let strs = |w: &mut W, k: &str, v: &[String]| { + w.key(k).arr(); + for s in v { + w.s(s); + } + w.end_arr(); + }; + w.obj(); + opt(w, "config", &self.config); + opt(w, "parallelism", &self.parallelism); + strs(w, "extend", &self.extend); + opt(w, "plugin_dirs", &self.plugin_dirs); + strs(w, "symbol_dirs", &self.symbol_dirs); + w.ku("verbosity", self.verbosity as u64); + opt(w, "log", &self.log); + opt(w, "output_dir", &self.output_dir); + w.kb("quiet", self.quiet).kb("write_config", self.write_config); + opt(w, "save_config", &self.save_config); + w.kb("clear_cache", self.clear_cache); + opt(w, "cache_path", &self.cache_path); + w.kb("offline", self.offline); + opt(w, "remote_isf_url", &self.remote_isf_url); + strs(w, "filters", &self.filters); + strs(w, "hide_columns", &self.hide_columns); + opt(w, "renderer", &self.renderer); + opt(w, "single_location", &self.single_location); + match &self.stackers { + Some(s) => strs(w, "stackers", s), + None => { + w.key("stackers").null(); + } + } + strs(w, "single_swap_locations", &self.single_swap_locations); + w.end_obj(); + } + + /// Fill the options that decide how the image is opened (a change reopens it). The + /// output folder falls back to `default_out` (the one `fvol serve -o` was given). + pub fn apply_opening(&self, o: &mut super::session::SessionOpts, default_out: &Path) { + let (loc, stackers, swaps) = self.automagic(); + o.symbol_dirs = self.symbol_dirs.clone(); + o.offline = self.offline; + o.remote_isf_url = self.remote_isf_url.clone(); + o.cache_path = self.cache_path.clone(); + o.clear_cache = self.clear_cache; + o.single_location = loc; + o.stackers = stackers; + o.swap_locations = swaps; + o.verbosity = self.verbosity; + o.out_root = self.output_dir.as_ref().map(Into::into).unwrap_or_else(|| default_out.to_path_buf()); + } + + /// Whether going from `self` to `new` changes how the image is opened. + pub fn opening_differs(&self, new: &Options) -> bool { + let key = |o: &Options| (o.symbol_dirs.clone(), o.offline, o.remote_isf_url.clone(), o.cache_path.clone(), o.clear_cache, o.automagic(), o.verbosity, o.output_dir.clone()); + key(self) != key(new) + } + + /// Location, stackers and swap files: the options, overridden by `-e automagic.*` keys (as + /// the CLI applies `-e` after the options). + pub fn automagic(&self) -> (Option, Option>, Vec) { + let (mut loc, mut stackers, mut swaps) = (self.single_location.clone(), self.stackers.clone(), self.single_swap_locations.clone()); + for e in &self.extend { + let Ok((address, value)) = parse_extend(e) else { continue }; + let strs = |v: &Json| v.as_arr().iter().filter_map(|x| x.as_str().map(|s| s.to_string())).collect::>(); + match address.as_str() { + "automagic.LayerStacker.single_location" => loc = value.as_str().map(|s| s.to_string()), + "automagic.LayerStacker.stackers" => stackers = Some(strs(&value)), + "automagic.WinSwapLayers.single_swap_locations" => swaps = strs(&value), + _ => {} + } + } + (loc, stackers, swaps) + } + + /// The run's options with the values `-c` and `-e plugins..

- - The web UI's overview of a Windows 11 image: evidence details, a process tree with lifelines, suggested first plugins and triage hints. + + The web UI's workspace for a Windows image: the file overview printed line by line, the plugin list with three malware plugins ticked and their options open, two runs with the per-plugin row counts, and triage hints.

-Plugin palette, million-row tables, process tree, hex viewer, run comparison, exports. Localhost -only, token-protected. [docs/web-ui.md](docs/web-ui.md) +

+ + + The results of a Windows Triage run: a tab per plugin with its row count, and the netscan table with its connections and listening sockets. + +

+ +Pick plugins or a preset, run them together, and read the results a tab per plugin: million-row +tables, one filter across all plugins, process trees, exports, every `fvol` option and your own +triage rules. Everything is saved in `~/.fvol` and comes back when the dump is reopened. +Localhost only, token-protected. [docs/web-ui.md](docs/web-ui.md) ## Supported images @@ -159,8 +168,7 @@ originals. [docs/architecture.md](docs/architecture.md#performance-techniques) ## License -Volatility Software License 1.0, as a port of Volatility 3 ([LICENSE.txt](LICENSE.txt)). The web UI -embeds JetBrains Mono (SIL OFL 1.1). +Volatility Software License 1.0, as a port of Volatility 3 ([LICENSE.txt](LICENSE.txt)). fastvol is built on the work of the Volatility Foundation and the volatility3 contributors. It is an independent project, not affiliated with or endorsed by the Volatility Foundation. diff --git a/docs/assets/screenshots/web-ui-memory.png b/docs/assets/screenshots/web-ui-memory.png deleted file mode 100644 index 4438118a9204ba3e52763266cf1b327e994f5cc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185759 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 OJ2F=kq%tJ#Joq15>HY!$ diff --git a/docs/assets/screenshots/web-ui-overview-dark.png b/docs/assets/screenshots/web-ui-overview-dark.png deleted file mode 100644 index 6aab556a64e5028d2638295b6cb79ca9a63f5f8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155742 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 X>oWK`bp$5h6*xI*WvO}zld%5)@GF}k diff --git a/docs/assets/screenshots/web-ui-overview-light.png b/docs/assets/screenshots/web-ui-overview-light.png deleted file mode 100644 index 650be29f397bdbed4c816ba2c0529288e04638bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162303 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

E%9<61sYyvp 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 j#pnSOzRkN-bspmGWDAvpg1 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 ^S>L>{Q^^*F%i8pK%s7lz#{ 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