nirc-rs/README.md

329 lines
12 KiB
Markdown
Executable File

# nirc-rs
a multi-protocol terminal chat client written in Rust.
nirc-rs is a TUI (terminal user interface) chat client that places you in control of your data and communications. Inspired by [naim](https://github.com/naim-devel/naim), it consolidates eight chat protocols into a single terminal interface — no web browsers, no Electron, no JavaScript.
**Version:** 0.9.0
**License:** GPL-3.0-or-later
**Author:** Jeremy Anderson - dcos.net
**Repository:** https://git.dcos.net/dcosnet/nirc-rs
---
## Features
### Protocols
| Protocol | Status | Transport | Notes |
|----------|--------|-----------|-------|
| **IRC** | ✅ Tested & Working | TLS (6697) / plaintext | SASL PLAIN, CTCP, ISUPPORT, operator commands |
| **ADC/DC++** | ✅ Tested & Working | TLS / plaintext | Hub search, file transfers, varnish guard pipeline |
| **Matrix** | 🔧 Implemented, Untested | HTTPS (matrix-sdk 0.18) | Megolm E2EE, SQLite crypto store, room sync |
| **Discord** | 🔧 Implemented, Untested | WebSocket (wss) | Gateway events, REST API |
| **Stout** | 🔧 Implemented, Untested | WebSocket (wss) | Revolt-compatible fork |
| **Spacebar** | 🔧 Implemented, Untested | WebSocket (wss) | Revolt fork |
| **Nerimity** | 🔧 Implemented, Untested | WebSocket (wss) | Custom platform |
| **BitChat** | 🔧 Implemented, Untested | libp2p (TCP) | P2P, mDNS discovery, gossipsub |
### UI
- **Tab-based interface** — channels, queries, and server statuses each get their own tab
- **Window list** (F4 toggle) — side panel showing all open windows with protocol badges and unread indicators
- **F1 dropdown menu** — QBasic 4.5 / aptitude-style menu bar for discoverable access to all commands
- **Transfer ticker** — footer bar showing active transfer progress (speed, ETA, percentage)
- **HTML markup rendering** — messages containing HTML are rendered appropriately
- **Theming** — four built-in themes (default, solarized, gruvbox, dracula) with per-color overrides
- **Timestamps** — color-coded by protocol (IRC=yellow, Matrix=magenta, ADC=blue, BitChat=green)
- **Status bar** — connection info, local IP, window count, unread count
- **Bracket paste support** — pasted text is inserted at cursor position
- **Scrollback** — per-tab message history (configurable, default 5000 lines)
### Security
- **TLS everywhere** — rustls with webpki-roots (no system OpenSSL dependency)
- **SASL authentication** — PLAIN mechanism for IRC (EXTERNAL with client certs on roadmap)
- **Encrypted identity vault** — AES-256-GCM with Argon2id key derivation (64 MiB memory, 3 iterations), keys zeroed from RAM on lock
- **ADC guard pipeline** — varnish-style security: rate limits, IP validation, SSRF prevention, path traversal blocking
- **Zeroize** — sensitive key material uses the `zeroize` crate to securely clear memory
### File Transfers
- **yamux-multiplexed streams** — multiple transfers over a single TCP connection
- **SHA-256 verification** — computed in-flight during transfer, not post-hoc
- **Resume support** — offset-based, writes to `.partial` then atomically renames on completion
- **256 KiB I/O buffers** — minimizes syscalls, maximizes throughput
- **2 GiB size cap** — prevents resource exhaustion
- **Cancellation** — via `tokio::CancellationToken`
- **Transfer ticker** — real-time speed and ETA in the footer
### Extensibility
- **Plugin system** — dynamically loaded `.so` shared libraries via `libloading`
- **Variables & aliases** — user-defined variables (`/set`), command aliases (`/alias`)
- **Custom keybindings** — map any key to a slash-command in `config.toml`
- **Per-channel logging** — naim-compatible format, 10 MiB rotation with 3 copies
---
## Installation
### From source (recommended)
```sh
# Prerequisites: Rust 1.75+ (via rustup), a C compiler
git clone https://git.dcos.net/dcosnet/nirc-rs.git
cd nirc-rs
cargo build --release
cp target/release/nirc-rs ~/.local/bin/
```
### Via cargo install
```sh
cargo install nirc-rs
```
### System packages
Arch Linux (AUR), Debian/Ubuntu `.deb`, RPM `.spec`, and Nix flake are available in the `packaging/` directory. See `packaging/` for details.
---
## Quick Start
Run `nirc-rs` with no arguments. It creates `~/.nirc/config.toml` with sensible defaults and opens the TUI:
```sh
nirc-rs
```
Connect to an IRC server:
```
/connect irc irc.libera.chat:6697
/join #rust
```
That's it — you're chatting. See [QUICKSTART.md](QUICKSTART.md) for a more detailed walkthrough.
---
## Key Bindings
| Key | Action |
|-----|--------|
| `Enter` | Send message or command |
| `Backspace` | Delete character before cursor (UTF-8 safe) |
| `Delete` | Delete character after cursor |
| `Left` / `Right` | Move cursor in input line |
| `Home` / `End` | Previous / next window |
| `Insert` | Scroll chat to bottom (unlock auto-scroll) |
| `Ctrl-N` | Jump to next window with unread messages |
| `Ctrl-B` | Jump back to previously active window |
| `Ctrl-P` | Previous buffer |
| `Ctrl-A` | Next active buffer |
| `Ctrl-Z` | Cycle highlight (rotate through highlight words) |
| `Ctrl-W` | Delete word before cursor |
| `Ctrl-K` | Delete from cursor to end of line |
| `Ctrl-A` / `Ctrl-E` | Cursor to start / end of line |
| `Ctrl-U` | Clear entire input line |
| `Ctrl-L` | Force terminal redraw |
| `Ctrl-C` | Quit nirc-rs |
| `Tab` | Tab-complete (nick/command), or cycle to next window if input is empty |
| `F1` | Toggle dropdown menu bar |
| `F4` | Cycle window list visibility (Auto → Visible → Hidden) |
| `PgUp` / `PgDn` | Scroll chat history (PgUp locks view; new messages won't auto-scroll until you PgDn back) |
| `Up` / `Down` | Navigate command history |
---
## Configuration Reference
Configuration lives at `~/.nirc/config.toml` (auto-created on first run). A full example:
```toml
[global]
nickname = "yournick"
realname = "Your Name"
log_level = "info" # error | warn | info | debug | trace
auto_connect = ["libera"] # server names to connect on startup
# ─── Servers ────────────────────────────────────────────────────────────
[[servers]]
name = "libera"
protocol = "irc" # irc | matrix | adc | discord | stout | spacebar | nerimity | bitchat
address = "irc.libera.chat:6697"
tls = true
auto_join = ["#rust", "#nirc"]
auto_reconnect = true
[servers.extra]
sasl_mechanism = "plain" # plain | external (external not yet implemented)
sasl_username = "your-account"
sasl_password = "your-password"
[[servers]]
name = "adc-hub"
protocol = "adc"
address = "hub.example.com:2780"
tls = false
auto_join = []
# ─── Appearance ─────────────────────────────────────────────────────────
[appearance]
theme = "default" # default | solarized | gruvbox | dracula
show_timestamps = true
clock_24h = true
max_scrollback = 5000
[appearance.custom_colors]
# Override individual theme colors:
# accent = "#FF79C6"
# error_fg = "#FF5555"
# bg = "#1E1E2E"
# ─── Notifications ──────────────────────────────────────────────────────
[notifications]
desktop_enabled = true
bell_enabled = true
debounce_ms = 2000
extra_highlight_words = ["urgent", "ops"]
# ─── File Transfers ─────────────────────────────────────────────────────
[transfers]
download_dir = "~/downloads" # defaults to system downloads dir
buffer_size = 262144 # 256 KiB in bytes
max_concurrent = 3
auto_accept_from = [] # nicks that auto-accept files from
# ─── Custom Keybindings ─────────────────────────────────────────────────
[keybindings]
# "F5" = "/connect irc libera"
# "Ctrl-G" = "/jump"
```
### Matrix Server Configuration
```toml
[[servers]]
name = "matrix"
protocol = "matrix"
address = "https://matrix.org"
auto_join = ["#nirc:matrix.org"]
[servers.extra]
user_id = "@alice:matrix.org"
password = "hunter2"
device_id = "NIRC-DEVICE-1"
device_name = "nirc-rs"
# access_token = "syt_abc..." # for session resume without password
```
### BitChat P2P Configuration
```toml
[[servers]]
name = "bitchat"
protocol = "bitchat"
address = "/ip4/0.0.0.0/tcp/9394"
[servers.extra]
bootstrap = "/ip4/1.2.3.4/tcp/9394/p2p/QmSomePeerId"
```
---
## Protocol Details
### IRC (Tested & Working)
Full IRCv3 support with:
- **TLS** via rustls (port 6697, auto-detected)
- **SASL PLAIN** authentication
- **CTCP** — auto-responds to `VERSION` requests
- **ISUPPORT** — server capability negotiation
- **Operator commands** — `/oper`, `/kill`, `/kline`, `/unkline`, `/wallops`
- **Channel ops** — `/op`, `/deop`, `/kick`, `/invite`, `/mode`
- **User commands** — `/whois`, `/who`, `/names`, `/topic`, `/away`, `/me`, `/notice`
- **Raw IRC** — `/raw` or `/quote` to send arbitrary IRC lines
- **UTF-8 safe** backspace and cursor movement
### ADC/DC++ (Tested & Working)
- **Hub connection** — HSUP, HSID, INF handshake sequence
- **Hub search** — SCH command for searching hub file listings
- **File transfers** — yamux-multiplexed, SHA-256 verified, resumable
- **Security pipeline** — rate limiting, IP validation (reject private/link-local IPs), SSRF prevention, path traversal blocking
- **BINF** — user info broadcast with I4/U4 support for incoming C-C connections
---
## Other Protocols
The following protocols are **fully implemented** in the codebase but have **not been tested against live servers yet**. They are on the TODO list for upcoming releases:
- **Matrix** — E2EE via megolm, SQLite-backed crypto store, dedicated OS thread for non-Send crypto types, full room/member/event handling
- **Discord** — Gateway WebSocket, REST API integration
- **Stout** — Revolt-compatible fork via REST + WebSocket
- **Spacebar** — Revolt fork via REST + WebSocket
- **Nerimity** — Custom platform via REST + WebSocket
- **BitChat** — P2P via libp2p (TCP, mDNS discovery, gossipsub, noise protocol, request-response)
---
## Plugin System
nirc-rs supports dynamically loaded plugins via `.so` shared libraries (Linux/macOS). Plugins implement the `Plugin` trait and are loaded at runtime via `libloading`.
```rust
// src/plugins/mod.rs defines the trait:
pub trait Plugin {
fn name(&self) -> &str;
fn on_message(&self, msg: &ChatMessage) -> Option<ChatMessage>;
fn on_command(&self, cmd: &str, args: &[&str]) -> Option<String>;
}
```
Place compiled `.so` files in `~/.nirc/plugins/` and they will be loaded automatically.
---
## File Transfers
File transfers are yamux-multiplexed over existing connections:
- **Send:** `/sendfile nick /path/to/file` or `/xfer <protocol> <nick> [filepath]`
- **Receive:** `/acceptfile <transfer-id> ~/downloads/`
- **Monitor:** `/transfers` to list active transfers; footer ticker shows real-time progress
- **Resume:** interrupted transfers resume from the last byte written (offset-based, `.partial` files)
- **Verify:** SHA-256 hash verified in-flight during transfer
- **Size limit:** 2 GiB maximum per file
Wire protocol: 4-byte magic (`NAIM`), 2-byte version, flags, 8-byte file size, 8-byte resume offset, filename, optional 64-byte SHA-256 — all little-endian.
---
## Contributing
Contributions are welcome. The project uses Rust edition 2021 and requires Rust 1.75+.
```sh
git clone https://git.dcos.net/dcosnet/nirc-rs.git
cd nirc-rs
cargo test # run all tests
cargo build --release # production build
```
For bug reports, feature requests, or protocol testing, visit https://git.dcos.net/dcosnet/nirc-rs.
---
## License
nirc-rs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
See [LICENSE](LICENSE) for the full text.
Copyright (C) 2026 dcos.net