diff --git a/docs/articles/configuration.md b/docs/articles/configuration.md index ab860f4..af9605e 100644 --- a/docs/articles/configuration.md +++ b/docs/articles/configuration.md @@ -101,6 +101,23 @@ Access tokens expire after 15 minutes, refresh tokens after 30 days with rotatio | `Server:PublicHost` | *(empty)* | Public hostname for the directory listing (e.g. `chat.example.com:5000`) | | `Server:Admins` | `[]` | Array of admin usernames (e.g. `["alice", "bob"]`) | +### Uploads + +Per-attachment size limits by kind (in megabytes) and the per-message attachment cap. An +absent or partial `Uploads` section keeps the built-in defaults. See +[Messages & Attachments](messages-and-attachments.md) for how kinds are detected. + +| Key | Default | Description | +| --- | --- | --- | +| `Uploads:MaxImageSizeMB` | `10` | Max size for one image attachment | +| `Uploads:MaxAudioSizeMB` | `10` | Max size for one audio attachment | +| `Uploads:MaxFileSizeMB` | `100` | Max size for any other attachment | +| `Uploads:MaxAvatarSizeMB` | `2` | Max avatar upload size | +| `Uploads:MaxAttachmentsPerMessage` | `10` | Attachments allowed on a single message | + +The server sizes its request-body limits from these values, so raising a limit here is all +that's needed — no separate Kestrel tuning. + ### Encryption | Key | Default | Description | diff --git a/docs/articles/getting-started.md b/docs/articles/getting-started.md index feee4ee..a0cb0b4 100644 --- a/docs/articles/getting-started.md +++ b/docs/articles/getting-started.md @@ -17,7 +17,7 @@ curl -sSfL https://raw.githubusercontent.com/HueByte/EchoHub/master/scripts/inst To install a specific version or to a custom directory: ```bash -curl -sSfL .../install.sh | sh -s -- --version 0.2.11 +curl -sSfL .../install.sh | sh -s -- --version 0.2.14 curl -sSfL .../install.sh | sh -s -- --install-dir /opt/echohub ``` @@ -76,11 +76,11 @@ Then connect with any standard IRC client: irssi -c localhost -p 6667 -w -n ``` -IRC users must have an existing EchoHub account. Authentication works via `PASS`/`NICK`/`USER` or SASL PLAIN. Messages flow bidirectionally between IRC and TUI clients. +Your nick is your EchoHub username and the server password is your account password (`PASS`/`NICK`/`USER` or SASL PLAIN). Connecting with a new username registers the account. Messages flow bidirectionally between IRC and TUI clients. For TLS, set `TlsEnabled: true`, `TlsPort: 6697`, and provide a PKCS#12 certificate path. -See the [Architecture](architecture.md) page for details on how the IRC gateway integrates with the chat service. +See the [IRC Gateway guide](irc-gateway.md) for command mapping, attachment rendering, and limitations, or [Architecture](architecture.md) for how the gateway integrates with the chat service. ## Configuration diff --git a/docs/articles/irc-gateway.md b/docs/articles/irc-gateway.md new file mode 100644 index 0000000..6dfbae6 --- /dev/null +++ b/docs/articles/irc-gateway.md @@ -0,0 +1,103 @@ +# IRC Gateway + +Every EchoHub server can expose a second door: a built-in **IRC gateway** that speaks the +classic IRC protocol on port 6667. Any standard IRC client — irssi, WeeChat, HexChat, +Halloy — can join the same channels as TUI users, see the same messages, and chat with the +same accounts. Under the hood both protocols call the same chat service, so a message sent +from IRC appears instantly in the TUI and vice versa (see [Architecture](architecture.md)). + +## Enabling the gateway + +The gateway is off by default. Enable it in `appsettings.json` (or `Irc__Enabled=true` as an +environment variable): + +```json +{ + "Irc": { + "Enabled": true, + "Port": 6667, + "TlsEnabled": false, + "TlsPort": 6697, + "TlsCertPath": "", + "ServerName": "echohub", + "Motd": "Welcome to EchoHub IRC Gateway!" + } +} +``` + +The plaintext listener always starts on `Port`. The TLS listener on `TlsPort` starts only +when `TlsEnabled` is `true` **and** `TlsCertPath` points to a PKCS#12 (`.pfx`) certificate. +See the [configuration reference](configuration.md#irc-gateway) for every option. + +## Connecting & authentication + +Your IRC **nick is your EchoHub username** and your server password is your **account +password**. Two flows are supported: + +```bash +# classic PASS/NICK/USER — most clients call this the "server password" +irssi -c chat.example.com -p 6667 -w -n +``` + +or **SASL PLAIN** (advertised via `CAP LS`), where the SASL username/password are the account +credentials. + +A few things worth knowing: + +- **Connecting auto-registers.** If the username doesn't exist yet, the gateway creates the + account with that password (usernames: 3–50 chars of `a-z 0-9 _ -`; passwords: 6+ chars). + The very first account ever created on a server becomes the **Owner**. +- Because of that, a typo'd password for an *existing* account fails with + `Username is already taken` — the gateway tried to log in, couldn't, then tried to register + the name. If you see that error, re-check your password. +- Connecting without a password is rejected: `Password required. Use PASS command or SASL PLAIN.` + +## What maps to what + +| IRC | EchoHub | +| --- | --- | +| `JOIN #room` | Join a channel (history is replayed on join) | +| `JOIN #room ` | Join a password-protected (`+k`) channel | +| `PART` / `QUIT` | Leave channel / disconnect | +| `LIST` | Public channels only (password-protected ones show a `[+k]` hint) | +| `TOPIC` | Read or set the channel topic (permission-checked) | +| `NAMES` / `WHO` | Online users in the channel | +| `WHOIS` | Profile: display name, channels, idle time, away status | +| `AWAY [message]` | Sets your EchoHub status to Away / back to Online | +| `MODE #room +k ` / `-k` | Set / clear the channel password | + +Private (unlisted) channels don't appear in `LIST`, but members who know the exact name can +still `JOIN` them. Channels are not auto-created from IRC — create them from the TUI first. + +## How messages look + +- **Attachments** arrive as labeled link lines — `[Image: photo.png] https://…`, + `♪ [Audio: song.mp3] https://…`, `[File: report.pdf] https://…` — and image attachments + additionally render their **ASCII-art preview** using truecolor ANSI escapes, so a modern + terminal IRC client shows actual picture previews. +- **Link embeds** are appended as `│`-prefixed text lines. +- Long messages are split at word boundaries into IRC-safe lines (~400 bytes each); + incoming messages may be up to 2,000 characters like any EchoHub message. +- Your own messages aren't echoed back (standard IRC convention). +- Moderation actions surface natively: kicks arrive as `KICK`, bans and channel nukes as + server `NOTICE`s. + +## Limitations + +The gateway bridges what IRC can express — and deliberately refuses what it can't: + +- **No end-to-end encrypted rooms.** Joining an [encrypted room](encrypted-rooms.md) fails + with *"Cannot join channel — end-to-end encrypted, use the EchoHub client."* Bridging one + would require the server to hold the room key, breaking the zero-knowledge design. +- **No private messages.** `PRIVMSG` to a nick is rejected; EchoHub is channel-based. +- **Usernames, not display names.** Messages are attributed to the account username; + a user's display name is visible via `WHOIS`/`WHO` (realname field). +- **No client features.** Uploading attachments, profiles, themes, and reactions to status + changes are TUI-client features. Other users' status changes aren't pushed to IRC — + discover them with `WHOIS`/`WHO`. + +## How IRC users appear to TUI users + +Users connected *only* through the gateway are tagged `[irc]` in the users panel — a hint +that they can't receive encrypted content or use client-side features. Someone connected +with both an IRC client and the TUI shows untagged. diff --git a/docs/articles/messages-and-attachments.md b/docs/articles/messages-and-attachments.md new file mode 100644 index 0000000..4f47d30 --- /dev/null +++ b/docs/articles/messages-and-attachments.md @@ -0,0 +1,109 @@ +# Messages & Attachments + +An EchoHub message is **text content plus up to 10 attachments**, Discord-style. A plain chat +line is just a message with no attachments; a photo dump is one message with several files and +an optional caption. This page explains how to attach files, what happens to them on the way to +the server, and how other clients receive them. + +## Message basics + +| Limit | Value | +| --- | --- | +| Max message length | 2,000 characters | +| Max newlines per message | 30 (no blank-line runs) | +| Max attachments per message | 10 | +| Link embeds per message | first 3 URLs | + +Multiline messages are written with `Ctrl+N` for a newline; `Enter` sends. URLs in a message +get link embeds (title, description, theme color) fetched by the server. + +## Attaching files + +All of these end up in the same place — the **staging tray** — and are sent together as one +message the next time you press `Enter`, with whatever you've typed as the caption: + +- **Paste a copied file** — copy one *or several* files in your file manager and press + `Ctrl+V` in the input. All of them are staged at once. +- **Paste an image from the clipboard** — copy an image in a browser (right-click → *Copy + image*), take a screenshot (`Win+Shift+S`), or copy from an image editor, then `Ctrl+V`. + The image is attached directly as a PNG named `image.png` — no saving to disk first. + On Linux this uses `wl-paste` or `xclip`; on macOS it requires + [`pngpaste`](https://github.com/jcsalterego/pngpaste) (`brew install pngpaste`). +- **Drag & drop** — drop a file onto the terminal window; the client recognizes the dropped + path and stages the file. +- **`/send `** — stage a file by path (quote paths containing spaces). + +The input frame's title shows what's currently staged. `/clear` drops all staged attachments +without sending. Sending with an empty input is fine — the message is just the attachments. + +```text +┌ Message (2 attached: report.pdf, image.png) ──────────────┐ +│ here's the summary and a screenshot_ │ +└────────────────────────────────────────────────────────────┘ +``` + +**URL sends are different:** `/send ` sends an image URL immediately as its own +message — nothing is staged, and it isn't available in end-to-end encrypted rooms (the server +would have to fetch the image, which would defeat the encryption). + +## Attachment kinds + +The kind is detected per attachment, not per message: + +| Kind | Detected by | Renders as | Default size limit | +| --- | --- | --- | --- | +| **Image** | Magic bytes: JPEG, PNG, GIF, WebP | ASCII-art preview in chat | 10 MB | +| **Audio** | Extension: `.mp3` `.wav` `.ogg` `.flac` `.aac` `.m4a` `.wma` | Playable row (▶) | 10 MB | +| **File** | Everything else | Downloadable row | 100 MB | + +Limits are per file and server-configurable — see the `Uploads` section in the +[configuration guide](configuration.md) (`MaxImageSizeMB`, `MaxAudioSizeMB`, `MaxFileSizeMB`, +`MaxAttachmentsPerMessage`). + +## Image previews (ASCII art) + +Images are rendered in chat as half-block ASCII art. You pick the rendering size: + +| Flag | Size | Feel | +| --- | --- | --- | +| `-s` / `/size s` | 40 × 40 | compact | +| `-m` / `/size m` | 80 × 80 | default | +| `-l` / `/size l` | 120 × 120 | detailed | + +`/size` with no argument opens a picker; the choice persists as your default. A one-off +`-s|-m|-l` flag on `/send` applies to that message. + +## Receiving attachments + +Right-click a message (or press `F6` to select one with the arrow keys) for actions: + +- **Images** → save to disk +- **Audio** → play (in-client playback) +- **Files** → download + +Downloads go to your configured download folder — set it with `/downloadpath` (no argument +opens a native folder picker, or pass a path directly). + +## Attachments in encrypted rooms + +In an [end-to-end encrypted room](encrypted-rooms.md) every attachment is encrypted +client-side **before** upload: + +```mermaid +flowchart LR + F[File bytes] -->|AES-256-GCM with room key| B[Ciphertext blob] + F -->|if image: render ASCII locally| A[ASCII preview] + A -->|room-encrypt| AP["$RC1$… preview"] + B --> S[Server stores blob + name + size] + AP --> S +``` + +The server never sees the file contents or the rendered preview — it stores an opaque blob and +broadcasts it to members, who decrypt locally. File **names and sizes remain visible** to the +server so the file list stays usable; don't put secrets in a file name. Pasted clipboard +images go through exactly the same pipeline. + +## Deleting messages with attachments + +Deleting a message also removes its uploaded attachment files from the server. You can always +delete your own messages; moderators can delete others' — see [Moderation & Roles](moderation.md). diff --git a/docs/articles/moderation.md b/docs/articles/moderation.md new file mode 100644 index 0000000..13c5ee4 --- /dev/null +++ b/docs/articles/moderation.md @@ -0,0 +1,71 @@ +# Moderation & Roles + +Every EchoHub server has a four-tier role hierarchy. Moderation is **strictly hierarchical**: +acting on another user requires outranking them — equal rank is never enough — and a few +invariants protect the server owner from lockouts. + +## Roles + +| Role | Rank | Users panel glyph | How it's granted | +| --- | --- | --- | --- | +| **Owner** | 3 | ★ | The first account ever registered on the server | +| **Admin** | 2 | ♦ | Assigned by the Owner | +| **Mod** | 1 | ❀ | Assigned by an Admin or the Owner | +| **Member** | 0 | — | Everyone else | + +Assign roles with `/role `. Two rules apply: + +- You can only assign roles **strictly below your own** — an Admin can promote to Mod but + cannot create another Admin; only the Owner can. +- **Owner is not assignable and not demotable.** There is exactly one Owner (the first + account), nobody can be promoted to it, and the Owner's role can't be changed. + +## Actions + +| Command | Minimum role | Effect | +| --- | --- | --- | +| `/kick [reason]` | Mod | Disconnects the user. Not persistent — they can reconnect immediately. | +| `/ban [reason]` | Admin | Persistent: flags the account banned and disconnects it. Banned accounts are rejected at login. | +| `/unban ` | Admin | Lifts a ban. | +| `/mute [minutes]` | Mod | Blocks the user from sending messages or uploading files. Without a duration the mute is **indefinite**; with one it auto-expires (checked every ~15 seconds). | +| `/unmute ` | Mod | Lifts a mute early. | +| `/role ` | Admin | Assign a role (see rules above). | +| `/nuke` | Mod | Deletes the **entire history of the current channel**, including all attachment files on disk. Channel-wide — no per-user check. | + +Kick, ban, and mute all enforce the hierarchy: the target's role must be **strictly lower** +than yours. A Mod cannot kick another Mod; nobody can kick, ban, mute, or demote the Owner. + +## Deleting messages + +Deletion has its own, slightly different rule set: + +- **Your own messages** — always deletable, whatever your role. Right-click a message → + *Delete message*, or press `F6`, pick the message, and hit `Delete`. +- **Someone else's messages** — requires **Mod or higher** *and* strictly outranking the + author. A Mod can delete a Member's message, but not another Mod's. + +Deleting a message also purges its uploaded attachment blobs from the server's disk, and the +removal is broadcast live — the message disappears from everyone's chat immediately. + +## How actions surface + +Everyone in the channel sees moderation happen: + +- **TUI clients** show system messages — *"alice was kicked (reason)"*, *"bob was banned"*, + *"Channel history has been cleared by a moderator."* The kicked or banned user themselves + gets a dialog with the reason, then the client disconnects. +- **IRC clients** get native protocol events: kicks arrive as a real `KICK` command, bans as + a server `NOTICE`. (See the [IRC Gateway guide](irc-gateway.md).) + +Muted users aren't announced; they simply receive *"You are muted and cannot send messages."* +when they try to speak. + +## Design notes + +- All checks run server-side in the moderation API — the client commands are conveniences, + and the same rules bind IRC users and any direct API caller. +- Bans are account-level, not IP-level. A banned person can register a fresh account; pair + bans with registration hygiene on public servers. +- In [end-to-end encrypted rooms](encrypted-rooms.md) moderation still works at the metadata + level — messages can be deleted and users muted/kicked by identity — but no moderator can + *read* the content, including the Owner. diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index c9cfe08..0c8e113 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -2,6 +2,14 @@ items: - name: Getting Started href: getting-started.md + - name: TUI Guide + href: tui-guide.md + - name: Messages & Attachments + href: messages-and-attachments.md + - name: Moderation & Roles + href: moderation.md + - name: IRC Gateway + href: irc-gateway.md - name: Docker href: docker.md - name: Architecture diff --git a/docs/articles/tui-guide.md b/docs/articles/tui-guide.md new file mode 100644 index 0000000..5103425 --- /dev/null +++ b/docs/articles/tui-guide.md @@ -0,0 +1,116 @@ +# TUI Guide + +Everything you can do in the EchoHub terminal client: keyboard shortcuts, mouse actions, +slash commands, themes, and the everyday behaviors (unread markers, auto-join, scrollback) +that make it feel like a proper IRC-era client with modern comforts. + +## Layout + +```text +┌ Menu bar ──────────────────────────────────────────────────┐ +│ ┌ Channels ─┐ ┌ Messages ────────────────────┐ ┌ Users ──┐ │ +│ │ #general 3│ │ 12:01 hi │ │ ★ alice │ │ +│ │ #dev │ │ ── new messages ── │ │ ❀ bob │ │ +│ │ #random*~ │ │ 12:04 anyone around? │ │ carol │ │ +│ └───────────┘ └──────────────────────────────┘ │ d [irc] │ │ +│ ┌ Message │ Enter=send │ Tab=complete │ … ────┐ └─────────┘ │ +│ │ _ │ │ +│ └─────────────────────────────────────────────┘ │ +│ Status: Connected │ v0.2.14 │ alice │ Act: #dev │ +└─────────────────────────────────────────────────────────────┘ +``` + +Channel list markers: `*` = password-protected, `~` = private (unlisted), plus unread counts +(orange when you were @mentioned). Users panel glyphs: `★` Owner, `♦` Admin, `❀` Mod, +`[irc]` for IRC-gateway-only users; status icons `●`/`○`/`◐`/`◌` for online/offline/away/dnd. + +## Keyboard shortcuts + +### In the message input + +| Key | Action | +| --- | --- | +| `Enter` | Send the message (also sends staged attachments with the text as caption) | +| `Ctrl+N` | Insert a newline (multiline message) | +| `Tab` | Autocomplete a slash command (`/th` → `/theme`) | +| `Ctrl+V` (or `Ctrl+Y`) | Paste — copied files and images become attachments, text pastes normally ([details](messages-and-attachments.md)) | +| `Ctrl+C` / `Ctrl+X` | Copy / cut in the input | +| `Ctrl+W` | Delete the word left of the cursor | +| `Ctrl+K` | Open the search palette | +| `F6` | Move focus into the message list | + +### In the message list (after `F6`) + +| Key | Action | +| --- | --- | +| `↑` / `↓` | Select a message | +| `Enter` | Activate: play/download/save an attachment, open an `@mention`'s profile, join a `#channel`, or open the sender's profile | +| `Delete` / `Backspace` | Delete the selected message (with confirmation; [permission rules](moderation.md)) | +| `F6` | Return focus to the input | + +### Anywhere + +| Key | Action | +| --- | --- | +| `F2` | Toggle the users panel | +| `Ctrl+K` | Search palette | +| `Alt+Q` | Quit | + +## The search palette (`Ctrl+K`) + +A command-palette that searches **channels and app actions** — type to filter, `↓` to +navigate, `Enter` to jump. Actions include Connect, Disconnect, Logout, My Profile, +Set Status, Create/Delete Channel, Saved Servers, Toggle Users Panel, Check for Updates, +and Quit. `Ctrl+K` again closes it. + +## Mouse + +- **Right-click a message** for the context menu: save image / play audio / download file + (depending on the attachment), *Mention @user*, *View profile*, *Copy text*, + *Copy message ID*, *Delete message*. +- **Left-click a message** does the most useful thing for that line: attachments + play/download/save, `@mentions` and the sender open profiles, `#channel` references join + that channel. +- **Click a user** in the users panel to open their profile; **click a channel** to switch. + +## Slash commands + +Type `/help` in any channel for the full list. The highlights: + +| Command | What it does | +| --- | --- | +| `/status ` or `/status ` | Presence / status message | +| `/nick `, `/color <#hex>`, `/avatar ` | Display name, nick color, avatar | +| `/theme ` | Switch theme | +| `/send`, `/clear`, `/size`, `/downloadpath` | Attachments — see [Messages & Attachments](messages-and-attachments.md) | +| `/join [password]`, `/leave`, `/topic ` | Channel membership and topic | +| `/passwd ` | Rotate an encrypted room's passphrase | +| `/profile [user]`, `/users`, `/meta` | Profiles, online users, room info | +| `/kick`, `/ban`, `/mute`, `/role`, `/nuke`, … | [Moderation](moderation.md) | +| `/servers`, `/quit` | Saved servers, exit | + +Emoji shortcodes (`:smile:` style) are replaced live as you type. + +## Themes + +14 built-in themes: **Default, Transparent, TransparentLight, Classic, Light, Hacker, +Solarized, Dracula, Monokai, Nord, Gruvbox, Ocean, HighContrast, RosePine** — switch from +the User menu or `/theme `. The two *Transparent* themes use no background color at +all, so your terminal's own background (and any blur/acrylic) shows through. + +You can add your own: drop a theme JSON into `~/.echohub/themes/` and it appears in the list +(names that collide with a built-in are skipped). + +## Everyday behaviors + +- **Unread markers** — a `── new messages ──` rule marks where you left off in each channel, + irssi-style. Read positions are **persisted per server**, so the marker survives + reconnects and restarts. The status bar's `Act:` segment lists channels with activity + (orange when you were @mentioned), and day boundaries draw a date rule. +- **Auto-join** — connecting joins `#general` plus every channel you're a member of, so + unread counts and mentions accumulate everywhere. Channels you `/leave` stay left, and + password-protected or [encrypted rooms](encrypted-rooms.md) are never auto-prompted — + join those explicitly. `#general` is the home channel and can't be left or deleted. +- **Scrollback** — history loads 100 messages at a time; scrolling to the top of a channel + fetches the next page and keeps your position (no jump). +- **Drag & drop** — dropping a file onto the window stages it as an attachment. diff --git a/docs/auriondocs/index.html b/docs/auriondocs/index.html new file mode 100644 index 0000000..de4844e --- /dev/null +++ b/docs/auriondocs/index.html @@ -0,0 +1,20 @@ + + + + + + AurionDocs + + + +
+

AurionDocs

+

Supplementary documentation for EchoHub.

+

← Back to EchoHub documentation

+
+ + diff --git a/docs/docfx.json b/docs/docfx.json index 7608b47..ad98ecd 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -46,7 +46,7 @@ "content": [ { "files": ["**/*.{md,yml}"], - "exclude": ["_site/**", "_api_meta/**"] + "exclude": ["_site/**", "_api_meta/**", "auriondocs/**"] }, { "src": "_api_meta/core", @@ -75,7 +75,7 @@ ], "resource": [ { - "files": ["images/**"] + "files": ["images/**", "auriondocs/**"] } ], "output": "_site", diff --git a/docs/index.md b/docs/index.md index cf75e8f..43dcb88 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,6 +11,10 @@ Welcome to the EchoHub documentation. EchoHub is a decentralized, IRC-style chat ## Quick Links - [Getting Started](articles/getting-started.md) - Set up and run EchoHub +- [TUI Guide](articles/tui-guide.md) - Keyboard shortcuts, slash commands, and everyday usage +- [Messages & Attachments](articles/messages-and-attachments.md) - Attaching, pasting, and receiving files +- [Encrypted Rooms](articles/encrypted-rooms.md) - End-to-end encrypted channels +- [IRC Gateway](articles/irc-gateway.md) - Connect with any IRC client - [Architecture](articles/architecture.md) - System design and IRC gateway - [API Reference](api/index.md) - Generated C# API documentation - [Changelog](changelog/index.md) - Release history diff --git a/docs/toc.yml b/docs/toc.yml index c93ba17..fd30a1b 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -7,3 +7,5 @@ - name: API href: api/ homepage: api/index.md +- name: AurionDocs + href: auriondocs/index.html