srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/PLUGINS.md
diff options
context:
space:
mode:
Diffstat (limited to 'PLUGINS.md')
-rw-r--r--PLUGINS.md117
1 files changed, 117 insertions, 0 deletions
diff --git a/PLUGINS.md b/PLUGINS.md
new file mode 100644
index 0000000..bb46461
--- /dev/null
+++ b/PLUGINS.md
@@ -0,0 +1,117 @@
+# mitmux plugins
+
+A plugin is any external process, in any language, that connects to
+`mitmuxd`'s control socket and speaks the same JSON protocol the `mitmux`
+TUI itself uses - there's no separate "plugin API," no interpreter
+embedded in mitmuxd, and no in-process extension mechanism to trust.
+This is deliberate: it keeps the daemon simple, lets a plugin be written
+in whatever language actually suits the job (a JWT plugin doing crypto
+work might want Python's `jwcrypto`; a fast passive scanner might want
+Go), and means a plugin can be developed and tested against the exact
+same socket the TUI is already using, with `mitmux` itself open in
+another terminal watching what happens in real time.
+
+## Connecting
+
+The socket path is the same one `mitmux -socket` and `mitmuxd -socket`
+use - `$XDG_RUNTIME_DIR/mitmux.sock` by default, else
+`<config-dir>/mitmux.sock` (see the README's Platforms section for the
+per-OS config directory). A plugin needs **two connections**, for two
+different jobs:
+
+1. A **subscribe connection** - long-lived, one-way, the daemon pushes
+ newly-captured entries to it as they happen. Send one `{"type":
+ "subscribe"}` request, then just keep reading `Response` objects off
+ the connection; no more requests are ever sent on it.
+2. A **request/response connection** - send one JSON request object,
+ read back exactly one JSON response object, repeat. This is how a
+ plugin looks up entries, resends requests, and tags things - anything
+ that isn't the live feed.
+
+Both are the same wire format: JSON values written directly to the
+socket, no length prefix or newline delimiter required (Go's
+`encoding/json` reads a stream and extracts one balanced JSON value at a
+time; if your language's JSON library needs an explicit framing, treat
+each object as ending where its braces balance - using a proper
+streaming/incremental JSON parser, not naive line-splitting, is the
+reliable way to consume this).
+
+## Requests a plugin actually needs
+
+The full protocol (`internal/ipc/ipc.go`'s `Request`/`Response` structs)
+also covers everything the TUI itself does - search, export, rules,
+scope, client certs, Intruder attacks, and so on. A plugin only needs a
+handful of these:
+
+- **`subscribe`** - see above. No fields. Response stream: each object
+ has `"type": "new"` and a `"new"` field (a `store.Summary`) for one
+ freshly-captured entry. **Slow consumers silently drop entries** - the
+ daemon never blocks proxying to wait for a plugin to keep up. If your
+ plugin needs to guarantee it never misses one, don't rely on the live
+ feed alone; periodically reconcile against `list`/`search` too.
+- **`get`** - `{"type": "get", "id": <entry id>}`. Returns the full
+ entry (raw request/response bytes, exact/truncated flags, existing
+ tags) as `"detail"`.
+- **`repeat`** - `{"type": "repeat", "scheme": "https", "host":
+ "example.com", "raw": <base64 raw bytes>}`. Sends `raw` to
+ `scheme://host` exactly as given - no normalization, no header
+ injection, no auto-fixed `Content-Length` - and records the exchange
+ to history with `source: "repeater"`. This is what an Autorize- or
+ Param-Miner-style plugin uses to send its own probe requests.
+- **`list`** / **`search`** - read existing history, same filters the
+ TUI's own `/` search uses (`status:`, `source:`, `flagged:`, `tag:`,
+ free text). Useful for a plugin that reconciles past traffic on
+ startup rather than only watching what happens from here on.
+- **`tag_entry`** - the actual plugin-integration primitive:
+
+ ```json
+ {
+ "type": "tag_entry",
+ "id": 42,
+ "tag_plugin": "jwt-decoder",
+ "tag": "jwt",
+ "tag_data": "{\"header\":{...},\"payload\":{...}}"
+ }
+ ```
+
+ `id` is the history entry being marked. `tag_plugin` is a
+ human-readable name your plugin picks for itself - purely
+ informational, not an identity or auth mechanism, since anything that
+ can reach the socket can claim any name (the socket itself is the
+ trust boundary - see Security below). `tag` is the short marker shown
+ as a badge in the TUI's history list and searchable via `tag:jwt`.
+ `tag_data` is an opaque string - conventionally JSON, since the TUI's
+ tag-detail view syntax-highlights it automatically if it parses as
+ JSON (same highlighter the pretty-printed response body view uses),
+ falling back to plain text otherwise - that a human reviewing the
+ entry later can open and read. Response: `{"type": "tag_entry",
+ "tag_id": <new tag's id>}`, or `{"type": "error", "error": "..."}`.
+
+A tagged entry shows its tags as a comma-joined badge in the TUI's
+history table (a new `Tags` column) and sortable via `o`/`O` like any
+other column; from the detail view, `T` opens the full tag list, `enter`
+on one shows its data.
+
+## What's not here yet
+
+Everything above covers a plugin that **observes and marks** traffic -
+enough for a JWT decoder, an authorization-bypass checker (replay with
+a different session token, diff the response, tag it if it looks like
+an IDOR), a hidden-parameter prober, or a known-vulnerable-JS-library
+scanner. It does not yet cover a plugin **acting interactively** on
+demand from the TUI - e.g. JWT Editor's "re-sign this token with a
+different key, right now, from the panel" - which needs a live
+round-trip to a specific still-connected plugin process, not just
+stored data. That's a deliberately separate, second protocol addition,
+not yet built; see `PLAN.md`'s plugin section for where it's headed.
+
+## Security
+
+The control socket has no authentication of its own beyond whatever the
+OS's Unix domain socket file permissions grant - the same trust
+boundary the `mitmux` TUI itself already operates inside. A plugin
+connected to it has the same level of access the TUI has: it can read
+every captured request and response (which may contain credentials,
+session tokens, anything else that crossed the proxy), resend traffic,
+and tag entries. Only run plugins you trust, the same way you'd only
+run any other local tool with access to your intercepted traffic.