From f77a9570e973dda7247c653754e62d5a9a895658 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Thu, 2 Apr 2026 20:55:00 +0200 Subject: Per-OS CA install instructions (mitmuxd -install-ca) Trusting the CA was previously "import ca.pem into whatever's making the requests" with no further help. -install-ca generates the CA if needed and prints copy-pasteable, OS-specific steps, then exits without starting the proxy. Deliberately instructions-only, never auto-executing anything: Linux trust-store tooling varies enough across distros (trust vs update-ca-trust vs update-ca-certificates) that guessing wrong and running the wrong command unattended is worse than asking, and installing a root CA is a system-wide trust change affecting every TLS connection on the machine, not just mitmux's own traffic - running the printed command themselves keeps the user in control of that. internal/ca/install.go: InstallInstructions(goos, caPath) dispatches by OS. Linux detects trust (p11-kit - Arch, also on Fedora) / update-ca-trust (RHEL/Fedora/CentOS) / update-ca-certificates (Debian/Ubuntu/Gentoo) via PATH lookup and prints whichever is actually present, plus separate certutil/NSS instructions for Firefox/Chrome's own certificate store (which doesn't always follow the system trust store on Linux). macOS (security add-trusted-cert) and Windows (certutil -addstore / Import-Certificate) are implemented from each platform's standard documented tooling but not verified live - no macOS/Windows machine was available to test against, unlike Linux. commandExists is a package var (not a direct exec.LookPath call) so tests can fake which tools are "present" and exercise every detection branch deterministically, independent of what's actually installed on whatever machine runs `go test`. Verified live: built mitmuxd, ran -install-ca against a throwaway CA dir on this (Arch Linux) machine - correctly detected `trust` and `certutil` on PATH and printed accurate commands, confirmed the CA files were actually generated, confirmed no proxy/daemon process was left running (exits immediately after printing), and confirmed running it a second time reuses the existing CA (identical file hash) rather than regenerating. go build/vet/gofmt/test/mod tidy all clean. --- cmd/mitmuxd/main.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/mitmuxd/main.go b/cmd/mitmuxd/main.go index 9db31e5..9c77516 100644 --- a/cmd/mitmuxd/main.go +++ b/cmd/mitmuxd/main.go @@ -7,11 +7,13 @@ package main import ( "context" "flag" + "fmt" "log" "net" "os" "os/signal" "path/filepath" + "runtime" "syscall" "time" @@ -26,6 +28,7 @@ func main() { caDir := flag.String("ca-dir", "", "directory for CA cert/key and history db (default: XDG config dir)") dbPath := flag.String("db", "", "path to history database (default: /history.db)") socketPath := flag.String("socket", "", "control socket path (default: $XDG_RUNTIME_DIR/mitmux.sock, else /mitmux.sock)") + installCA := flag.Bool("install-ca", false, "generate the CA if needed, print OS-specific trust-store install steps, and exit (doesn't start the proxy)") flag.Parse() dir := *caDir @@ -41,7 +44,14 @@ func main() { if err != nil { log.Fatalf("load CA: %v", err) } - log.Printf("CA ready: %s (install %s/ca.pem in your client's trust store to avoid TLS warnings)", root.Cert.Subject.CommonName, dir) + + if *installCA { + fmt.Printf("CA certificate: %s\n\n", ca.CertPath(dir)) + fmt.Print(ca.InstallInstructions(runtime.GOOS, ca.CertPath(dir))) + return + } + + log.Printf("CA ready: %s (install %s/ca.pem in your client's trust store to avoid TLS warnings, or run 'mitmuxd -install-ca' for OS-specific steps)", root.Cert.Subject.CommonName, dir) dbFile := *dbPath if dbFile == "" { -- cgit v1.2.3