onionwire/README.md
Sirius DevOps 82634db142
Some checks are pending
ci / test (push) Waiting to run
tui: ASCII onion chrome, themed panes, and real keyboard navigation
- Hand-written wordmark banner (<=80 cols, auto-collapses to a compact
  mark below banner width) plus onion glyph and themed screen headings
- Color-palette consts, stateful pane titles, highlighted selection row
  (accent + bg), context-sensitive footer that always keeps '? help'
- Pane focus model (roster/chat/composer) with Tab/Shift-Tab, 1/2/3,
  j/k + arrows, g/G, and a '?' help overlay; Esc closes any overlay
- New tests/tui_chrome.rs: banner widths, help overlay bindings, real
  footer helper at 80 and 120 cols, 80x24 draw smoke test
- README keybinding table updated to match

Locked helper strings (fingerprint_mismatch_banner, rotate_screen_text,
wipe_screen_text, parse_slash) unchanged; UI-only (src/tui.rs).
2026-09-10 13:01:40 -04:00

8.2 KiB
Raw Permalink Blame History

OnionWire

Lean Tor messenger: one Rust process (ratatui + Noise IK + sqlite + in-process Arti). Two people scan a QR, then chat. No hosted server. Identity is a public key; the onion is only a locator.

You do not install a tor daemon, torrc, Prosody, or XMPP. OnionWire embeds Arti and publishes its own v3 onion.

Install

Pick one: a CI-built binary (fastest), or build from source.

Requirements

Need Notes
Linux x86_64 or aarch64. TUI needs a real terminal (not a pipe).
Network First run bootstraps Tor via Arti. Offline start will fail closed.
Not needed tor package, torrc, Prosody, an XMPP account, a DHT.

Arti onion services are still experimental. If the hidden service cannot come up, OnionWire exits — it does not fall back to C-tor.

Option A — download a release binary

CI builds stripped Linux binaries on every v*.*.* tag and attaches them to GitHub Releases.

x86_64 (most PCs / VMs):

curl -fL -O https://github.com/sirius0xdev/onionwire/releases/latest/download/onionwire-x86_64-unknown-linux-gnu
curl -fL -O https://github.com/sirius0xdev/onionwire/releases/latest/download/onionwire-x86_64-unknown-linux-gnu.sha256
sha256sum -c onionwire-x86_64-unknown-linux-gnu.sha256
chmod +x onionwire-x86_64-unknown-linux-gnu
./onionwire-x86_64-unknown-linux-gnu --version

aarch64 (Raspberry Pi, ARM servers):

curl -fL -O https://github.com/sirius0xdev/onionwire/releases/latest/download/onionwire-aarch64-unknown-linux-gnu
curl -fL -O https://github.com/sirius0xdev/onionwire/releases/latest/download/onionwire-aarch64-unknown-linux-gnu.sha256
sha256sum -c onionwire-aarch64-unknown-linux-gnu.sha256
chmod +x onionwire-aarch64-unknown-linux-gnu
./onionwire-aarch64-unknown-linux-gnu --version

Install onto PATH if you want onionwire as a command (keep the asset filename until after sha256sum -c):

mkdir -p ~/.local/bin
install -m 755 onionwire-x86_64-unknown-linux-gnu ~/.local/bin/onionwire
# ensure ~/.local/bin is on PATH, then:
onionwire

The binary is dynamically linked against glibc (Ubuntu 24.04 builders). If ./onionwire dies with GLIBC_… not found, use Option B on that machine.

Checksum files are sha256sum format (<hash> onionwire-<target>). Download both files with curl -O so the names match, then sha256sum -c.

Option B — build from source

Needs Rust 1.87+ (edition = "2024"). A distro rustc is fine if rustc --version reports 1.87 or newer. Do not install tor for this app.

# rustup (if you do not already have cargo)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustc --version   # must be 1.87 or newer
git clone https://github.com/sirius0xdev/onionwire.git
cd onionwire
cargo test --locked
cargo clippy --locked -- -D warnings
cargo build --release --locked
./target/release/onionwire --version
./target/release/onionwire

Install the binary:

cargo install --path . --locked --force
# lands in ~/.cargo/bin/onionwire

Source of record also lives at https://forgejo.siriusdevops.com/sirius/onionwire (same tree). GitHub is where CI publishes downloadable artifacts.

Two instances on one machine

Each process needs its own data dir (identity + onion + sqlite):

ONIONWIRE_HOME=/tmp/ow-a ./onionwire
ONIONWIRE_HOME=/tmp/ow-b ./onionwire

Then F2 on A, F3-paste on B (and the other way around).

First run

onionwire

or cargo run --release.

On start you should see onionwire: bootstrapping Arti… on stderr. First bootstrap can take a minute. Data lives in ONIONWIRE_HOME if set, otherwise ~/.local/share/onionwire/ (onionwire.db + Arti state, mode 0700). First open creates an ed25519 identity key. That key is you.

Friends are keys

A friend is an ed25519 pubkey (UNIQUE(pubkey)). The .onion on that row is only where they are reachable right now. Re-scanning the same k updates the locator; it never creates a second person.

Keys (TUI)

Focus starts on the composer so typing works immediately. Tab cycles panes; j/k and arrows only move the focused pane (roster or chat). 1/2/3 switch focus when you are not typing in the composer. ? opens help from every screen except paste (so a payload can contain ?).

Key Action
Tab / Shift-Tab Cycle focus: roster → chat → composer
1 / 2 / 3 Focus roster / chat / composer (when not typing)
j k / Move or scroll the focused pane
g / G Jump to top / bottom of the focused pane
? Keybinding help (Esc closes)
F2 Share: terminal QR + payload
F3 Paste a friends payload
F4 Rotate onion (locator only)
Enter Run /wipe or /wipe-all from the composer
Esc Close overlay / back to Main / clear composer
Ctrl-Q Quit

F2 QR

F2 shows a terminal QR and the payload:

onionwire:v1:k=…:o=…:spk=…:sig=…

F3 pastes a payload. Unknown k asks for approval. Same k already in the roster updates onion only.

F4 rotate onion

F4 is a locator change, not a new identity. Confirm by typing ROTATE (Enter alone does nothing).

  • Your identity fingerprint stays the same.
  • A new onion is published; the old one is hard-cut (no dual-host grace).
  • Online friends get a signed loc frame.
  • Offline friends cannot find you until they rescan the new QR. There is no directory.

Fail closed

If a peers onion is down, send fails. v1 has no outbox, no retry queue, no DHT, no name server.

Wipe

Composer (bottom of the roster screen):

  • /wipe — confirm by typing WIPE. Overwrites the message log and VACUUMs. Identity key and friends stay.
  • /wipe-all — confirm by typing WIPEALL. Deletes the data dir. Next start is a new person (new identity key). Esc cancels. Nothing is wiped without confirm.

Uninstall

# binary (whichever you used)
rm -f ~/.local/bin/onionwire ~/.cargo/bin/onionwire

# optional: destroy identity, friends, and message log
# (same as /wipe-all — you become a new person next run)
rm -rf ~/.local/share/onionwire

If you set ONIONWIRE_HOME, delete that directory instead.

Seized laptop

v1 stores plaintext on disk:

  • message log (sqlite messages.plaintext)
  • your identity secret key (self.identity_sk)
  • friend public keys and current locators

Full-disk encryption plus /wipe / /wipe-all is the mitigation. There is no sqlcipher in v1.

Threat model: docs/THREAT_MODEL.md.

Releases (maintainers)

Push a version tag. GitHub Actions builds Linux binaries and publishes a GitHub Release.

# version in Cargo.toml must match the tag without the leading v
git tag v0.1.0
git push github v0.1.0     # GitHub remote — this is what triggers CI

Workflows:

  • .github/workflows/ci.ymlcargo test --locked and clippy on main / PRs (ignored Tor-live tests are not run).
  • .github/workflows/release.yml — on v*.*.* tags, cargo build --release for x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu, strip, sha256, attach to the release.

Do not run cargo publish; publish = false.

Troubleshooting

Symptom What to do
GLIBC_… not found Binary is newer than your libc. Build from source (Option B).
sha256sum: FAILED Re-download both the binary and .sha256; run the check in the same directory.
Hang on bootstrapping Arti… Need outbound network. First consensus fetch is slow. Wait a couple of minutes; if it never publishes, it fails closed — no C-tor fallback.
onionwire: unknown argument No subcommands. Flags are --version / --help only, then the TUI.
Blank / broken TUI Run in a real terminal emulator, not nohup / systemd without a TTY.
Two chats, same laptop Separate ONIONWIRE_HOME per process.
Friend cannot find you after F4 Expected if they were offline. They must F3-paste the new QR. Same k updates the row.

Not in v1

Prosody, XMPP, s2s, MAM, carbons, outbox, multi-device, DHT / name server, sqlcipher.

License

MIT