Files
gists/config/visidata/README.md
tobias 250999b0c6 visidata: add replayable IOC showcase and usage docs
Provide a sample dataset and cmdlog that exercise typed IOC enrichment while keeping heavy lookups scoped for practical throttled runs, and document how to run it.
2026-02-21 23:20:42 +01:00

6.1 KiB
Raw Blame History

VisiData Config + Plugins

This folder contains a VisiData config.py (symlinked from visidatarc) plus a small set of local plugins under plugins/.

Install

The installer links (or copies) the config and plugins into VisiDatas per-user directory.

./install.sh --link        # default, symlinks into place
./install.sh --copy        # copies into place
./install.sh --deps        # installs optional Python deps into $VD_DIR/plugins-deps

On VisiData 3.3, $VD_DIR defaults to:

  • macOS: ~/Library/Preferences/visidata
  • Linux: ${XDG_CONFIG_HOME:-~/.config}/visidata

Plugins

Plugins are installed into $VD_DIR/plugins/ and imported via the top-level plugins package.

Showcase Demo

This repo includes a self-contained sample dataset + command log to demonstrate the local IOC/IP features:

  • showcase_ioc.tsv (sample IOC rows)
  • showcase_ioc.vdj (replay file)

Run it interactively from this repo root:

vd --visidata-dir "$PWD" --config "$PWD/visidatarc" --play showcase_ioc.vdj

What it showcases:

  • custom types: IP, Domain, URL, Hash
  • IP membership expressions: src_ip * network
  • URL parsing fields: url.host, url.parts.path, url.domain
  • hash classification: file_hash.kind
  • IP lookups: src_ip.ipinfo.*, src_ip.asn.*, src_ip.geo.*, src_ip.country()
  • provider visibility: src_ip.geo.source, src_ip.asn.source, domain.dns.source
  • domain/network intel: domain.dns.*, domain.rdap.*
  • hash intel: file_hash.mb.* (MalwareBazaar)
  • VirusTotal lookups: src_ip.vt.*, file_hash.vt.*, domain.vt.*, url.vt.*
  • local plugin command: tke-hidecol

Lookup notes:

  • VT columns require options.tke_vt_api_key (or VT_API_KEY / VIRUSTOTAL_API_KEY / ~/.virustotal_api_key).
  • IPInfo/ASN/Geo columns use free providers and may be rate-limited; options.tke_ipinfo_token improves reliability.
  • To keep replays practical with strict throttling, some heavy lookup columns are intentionally limited to a subset of rows.

plugins/hidecol.py

Adds a command to hide columns that are empty or constant across all rows.

  • Command: tke-hidecol
  • Menu: Column -> Hide -> empty/superfluous columns

plugins/iptype.py

Adds a custom IP datatype that supports:

  • IPv4 + IPv6 addresses
  • CIDR networks (e.g. 192.168.7.0/24)
  • Correct sorting (numeric, by version)
  • Membership test operator: ip * net (and net * ip)
  • Normalized lookup/enrichment properties, accessible as attributes in expressions

Type + Command

  • Type converter: ip(...)
  • Type name: IP
  • Command: type-ip (sets cursorCol.type=ip)

Operations

Membership test:

  • ipcol * "192.168.7.0/24" -> True/False
  • "192.168.7.0/24" * ipcol -> True/False

Attributes (on IP typed cells)

Lookup objects expose both normalized fields and raw response data:

  • ipcol.ipinfo.country
  • ipcol.ipinfo.data.<any_json_field>
  • ipcol.asn.asn, ipcol.asn.name, ipcol.asn.country
  • ipcol.asn.data.<any_json_field>
  • ipcol.vt.verdict (e.g. "3/94"), ipcol.vt.malicious, ipcol.vt.total, ipcol.vt.category (alias: ipcol.vt.type)
  • ipcol.vt.data.<any_json_field>
  • ipcol.geo.* (best-available geo: prefers MaxMind mmdb, else free HTTP providers)
  • ipcol.maxmind.* (offline-only MaxMind lookup; empty if no mmdb)

Caching

All lookup providers cache results in a local sqlite+pickle DB (default ~/.visidata_cache.db).

Lookup Providers + Keys

Options (set in config.py / visidatarc):

  • options.tke_cache_db_path="~/.visidata_cache.db"
  • options.tke_lookup_cache_ttl=86400
  • options.tke_lookup_error_ttl=300
  • options.tke_lookup_timeout=10
  • options.tke_ipinfo_token="..." (optional; ipinfo can work without it)
  • options.tke_ipapi_key="..." (optional)
  • options.tke_vt_api_key="..." (required for VT lookups unless using ~/.virustotal_api_key)
  • options.tke_maxmind_mmdb_path="/path/to/GeoLite2-City.mmdb" (optional)

Env var equivalents:

  • IPINFO_TOKEN, IPAPI_KEY
  • VT_API_KEY or VIRUSTOTAL_API_KEY (also supports ~/.virustotal_api_key)
  • MAXMIND_MMDB_PATH or GEOIP_MMDB_PATH

MaxMind (offline “free” GeoLite2) support:

  • Place a GeoLite2-City.mmdb / GeoLite2-Country.mmdb file in $VD_DIR/, or set options.tke_maxmind_mmdb_path.

plugins/iplib.py

Pure-Python library used by iptype.py for:

  • Normalized info classes (IPInfo, ASNInfo, VTInfo, GeoInfo)
  • JSONNode wrapper (.data.<field>) for safe attribute-style access into raw dict/list JSON
  • Parsing/normalization helpers for each providers response shape

This file intentionally does not import VisiData so it can be validated outside the VisiData runtime.

Config: visidatarc

This repos visidatarc is intended to be installed as VisiDatas config.py:

  • $VD_DIR/config.py (VisiData 3.3 default)
  • and also ~/.visidatarc as a legacy fallback

It currently contains:

  • display/date format options
  • a sqlite+pickle caching decorator and a set of general-purpose helpers (aggregators, timestamp parsing, “dirty” JSON parsing, etc)

Are the visidatarc functions superseded?

Partially:

  • The IP-centric lookups and normalized attribute access are now primarily handled by plugins/iptype.py on typed values (e.g. ipcol.geo.country_code).
  • Many other helpers in visidatarc (aggregators like avgdiff, parsing/time conversion helpers, etc.) are still independent and useful.

Keeping old + new side-by-side (without duplicating code)

Yes. The cleanest pattern in VisiData is:

  1. Put shared logic into a module under plugins/ (so its on sys.path via $VD_DIR).
  2. In visidatarc, import and expose thin wrappers (or just import the module and use module.func(...) in expressions).

Concretely:

  • plugins/iplib.py already holds parsing/normalization shared by the IP type.
  • If you have legacy functions in visidatarc that overlap with the new IP lookups, refactor those functions into a shared module (e.g. plugins/lookups.py) and have both visidatarc and plugins/iptype.py call into it.

This keeps backward-compatible names available while ensuring caching/auth/provider behavior is implemented in one place.