329 lines
12 KiB
Markdown
Executable File
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 |