diff --git a/README.md b/README.md index 5c91d9f..0f24a3a 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,19 @@

WhatSetup • + IRC • + DeployCommandsConfigLicense

+

+ Website • + Public Servers • + Documentation +

+

.NET 10 SignalR @@ -40,21 +48,25 @@ Each server is fully independent — no central authority, no account federation ```mermaid graph TD subgraph Server["Server"] + ChatSvc["ChatService"] Hub["SignalR ChatHub"] + IRC["IRC Gateway :6667"] Auth["JWT Auth"] DB["SQLite DB (EF Core)"] Files["File Storage"] end - subgraph Client["Client"] + subgraph Clients["Clients"] TUI["Terminal GUI (TUI)"] - Theme["Theme Engine"] - API["API Client (auto-refresh)"] + IRCClient["IRC Client (irssi, WeeChat, ...)"] end - API -- "WebSocket" --> Hub - API -- "REST" --> Auth - Hub --> DB + TUI -- "WebSocket" --> Hub + TUI -- "REST" --> Auth + IRCClient -- "TCP" --> IRC + Hub --> ChatSvc + IRC --> ChatSvc + ChatSvc --> DB Auth --> DB Files --> DB ``` @@ -65,6 +77,7 @@ graph TD - **Self-hostable** — your server, your rules, your data - **Real-time messaging** via SignalR WebSockets +- **IRC gateway** — native IRC clients connect alongside TUI users, full cross-protocol messaging - **JWT auth** with short-lived access tokens and 30-day refresh tokens - **Channels** — create, set topics, delete (no 47-step permission wizard required) - **File & image uploads** with actual validation (magic bytes, not just trusting the extension) @@ -122,6 +135,66 @@ Connect, register, chat. That's the whole onboarding flow. dotnet build src/EchoHub.slnx ``` +## IRC Gateway + +EchoHub includes a built-in IRC protocol gateway. Any standard IRC client can connect to the same server and chat alongside TUI users — messages flow both ways in real time. + +### Enable It + +In the server's `appsettings.json`: + +```json +{ + "Irc": { + "Enabled": true, + "Port": 6667, + "ServerName": "echohub", + "Motd": "Welcome to EchoHub IRC Gateway!" + } +} +``` + +### Connect + +```bash +# irssi +irssi -c your-server.com -p 6667 -w -n + +# WeeChat +/server add echohub your-server.com/6667 -password= -nicks= +/connect echohub +``` + +IRC users must have an existing EchoHub account (no registration via IRC). Auth works via `PASS`/`NICK`/`USER` or SASL PLAIN. + +### What Works + +| Feature | How it maps to IRC | +| ------- | ------------------ | +| Text messages | Standard `PRIVMSG` (long messages split at ~400 byte chunks) | +| Images | `[Image: filename]` + download URL + ASCII art line-by-line | +| File uploads | `[File: filename] /api/files/{id}` | +| Channels | `JOIN`, `PART`, `NAMES`, `TOPIC`, `LIST` | +| Presence | `AWAY`, `WHO`, `WHOIS` | +| Status | Maps to IRC away/here | + +### TLS + +If running behind **nginx** (recommended), let nginx handle TLS -- see [Deployment with nginx](#deployment-with-nginx) below. + +For direct TLS without a reverse proxy, the IRC gateway can terminate TLS itself: + +```json +{ + "Irc": { + "TlsEnabled": true, + "TlsPort": 6697, + "TlsCertPath": "/path/to/cert.pfx", + "TlsCertPassword": "your-password" + } +} +``` + ## Client Commands | Command | Description | @@ -172,35 +245,107 @@ dotnet build src/EchoHub.slnx | `Jwt:Secret` | *(auto-generated)* | JWT signing key | | `Server:Name` | `My EchoHub Server` | Server display name | | `Server:Description` | `A self-hosted EchoHub chat server` | Server description | +| `Server:PublicServer` | `false` | List on the [public directory](https://echohub.voidcube.cloud/servers) | +| `Server:PublicHost` | *(empty)* | Public hostname for directory listing | +| `Irc:Enabled` | `false` | Enable the IRC gateway | +| `Irc:Port` | `6667` | IRC listen port | +| `Irc:TlsEnabled` | `false` | Enable TLS for IRC | +| `Irc:TlsPort` | `6697` | IRC TLS port | +| `Irc:ServerName` | `echohub` | IRC server name in protocol messages | +| `Irc:Motd` | `Welcome to EchoHub IRC Gateway!` | Message of the day | | `Cors:AllowedOrigins` | *(all origins)* | CORS whitelist | -Logging uses Serilog — console + daily rolling files with 14-day retention. Configure it in the `Serilog` section of appsettings. +Logging uses Serilog — console + daily rolling files with 14-day retention. Configure in the `Serilog` section. + +## Deployment with nginx + +Most production deployments run behind nginx. Here's a config that handles both the HTTP/WebSocket server and the IRC gateway: + +```nginx +# HTTP + WebSocket (EchoHub Server API + SignalR) +server { + listen 443 ssl; + server_name echohub.example.com; + + ssl_certificate /etc/letsencrypt/live/echohub.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/echohub.example.com/privkey.pem; + + location / { + proxy_pass http://127.0.0.1:5000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Required for SignalR WebSocket + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } + + # Increase max upload size for file sharing + client_max_body_size 10m; +} + +# HTTP → HTTPS redirect +server { + listen 80; + server_name echohub.example.com; + return 301 https://$host$request_uri; +} + +# IRC TLS (port 6697 → plain IRC on 6667) +stream { + upstream irc_backend { + server 127.0.0.1:6667; + } + + server { + listen 6697 ssl; + proxy_pass irc_backend; + + ssl_certificate /etc/letsencrypt/live/echohub.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/echohub.example.com/privkey.pem; + } +} +``` + +With this setup, keep the EchoHub IRC gateway's `TlsEnabled` set to `false` — nginx terminates TLS. See the full example at [`examples/nginx.conf`](examples/nginx.conf). ## Project Structure ```text src/ -├── EchoHub.Core/ # Shared models, DTOs, contracts, validation -│ ├── Constants/ # ValidationConstants, HubConstants -│ ├── Contracts/ # IEchoHubClient (SignalR interface) -│ ├── DTOs/ # Record DTOs -│ └── Models/ # Entity models +├── EchoHub.Core/ # Shared models, DTOs, contracts, validation +│ ├── Constants/ # ValidationConstants, HubConstants +│ ├── Contracts/ # IChatService, IChatBroadcaster, IEchoHubClient +│ ├── DTOs/ # Record DTOs +│ └── Models/ # Entity models │ -├── EchoHub.Server/ # ASP.NET Core server -│ ├── Auth/ # JWT token service -│ ├── Controllers/ # REST API endpoints -│ ├── Data/ # EF Core DbContext + migrations -│ ├── Hubs/ # SignalR ChatHub -│ ├── Services/ # Presence, file storage, image processing -│ └── Setup/ # First-run setup, DB initialization +├── EchoHub.Server/ # ASP.NET Core server +│ ├── Auth/ # JWT token service +│ ├── Controllers/ # REST API endpoints +│ ├── Data/ # EF Core DbContext + migrations +│ ├── Hubs/ # SignalR ChatHub +│ ├── Services/ # ChatService, presence, file storage, image processing +│ └── Setup/ # First-run setup, DB initialization │ -├── EchoHub.Client/ # Terminal.Gui TUI client -│ ├── Config/ # Client configuration -│ ├── Services/ # API client, SignalR connection -│ ├── Themes/ # 6 built-in themes -│ └── UI/ # MainWindow, dialogs, chat renderer +├── EchoHub.Server.Irc/ # IRC protocol gateway +│ ├── IrcGatewayService # TCP listener (BackgroundService) +│ ├── IrcCommandHandler # IRC command dispatch (JOIN, PRIVMSG, etc.) +│ ├── IrcBroadcaster # Fans chat events to IRC connections +│ └── IrcMessageFormatter # MessageDto → IRC PRIVMSG lines │ -└── EchoHub.slnx # Solution file +├── EchoHub.Client/ # Terminal.Gui TUI client +│ ├── Config/ # Client configuration +│ ├── Services/ # API client, SignalR connection +│ ├── Themes/ # 13 built-in themes +│ └── UI/ # MainWindow, dialogs, chat renderer +│ +└── EchoHub.slnx # Solution file ``` ## License diff --git a/docs/api/core-articles/index.md b/docs/api/core-articles/index.md index 852da7d..d8545b1 100644 --- a/docs/api/core-articles/index.md +++ b/docs/api/core-articles/index.md @@ -5,5 +5,5 @@ Articles related to the EchoHub.Core shared library. ## Topics - Data models and DTOs -- SignalR contract interface +- Contract interfaces (IChatService, IChatBroadcaster, IEchoHubClient) - Validation constants and shared rules diff --git a/docs/api/index.md b/docs/api/index.md index 3978198..b62904c 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -10,8 +10,12 @@ Terminal.Gui v2 TUI application -- UI components, services, themes, and configur ### Core -Shared library -- DTOs, models, constants, and the SignalR client contract. +Shared library -- DTOs, models, constants, and contracts (`IChatService`, `IChatBroadcaster`, `IEchoHubClient`). ### Server -ASP.NET Core server -- controllers, hubs, authentication, and data access. +ASP.NET Core server -- controllers, hubs, ChatService, SignalRBroadcaster, authentication, and data access. + +### Server.Irc + +IRC protocol gateway -- TCP listener, command handler, IrcBroadcaster, and message formatter. diff --git a/docs/api/server-articles/index.md b/docs/api/server-articles/index.md index cafad01..6cafdf8 100644 --- a/docs/api/server-articles/index.md +++ b/docs/api/server-articles/index.md @@ -6,6 +6,8 @@ Articles related to the EchoHub server built with ASP.NET Core. - Authentication and JWT tokens - SignalR hub and real-time messaging +- IRC gateway and protocol bridging +- ChatService and broadcaster pattern - File upload and validation - Rate limiting configuration - Database schema and migrations diff --git a/docs/api/toc.yml b/docs/api/toc.yml index 78334db..79092df 100644 --- a/docs/api/toc.yml +++ b/docs/api/toc.yml @@ -16,3 +16,7 @@ href: ../_api_meta/server/toc.yml - name: Articles href: server-articles/ +- name: Server.Irc + items: + - name: API Reference + href: ../_api_meta/server-irc/toc.yml diff --git a/docs/articles/architecture.md b/docs/articles/architecture.md index 9b67ffd..bc59652 100644 --- a/docs/articles/architecture.md +++ b/docs/articles/architecture.md @@ -4,6 +4,16 @@ EchoHub follows a decentralized model where each server is fully independent. There is no central authority or account federation. Users create one account per server. +The server exposes two protocol interfaces to the same chat backend: + +```text +IRC Client ──► TCP :6667 ──► IrcGateway ──┐ + ├──► ChatService ──► DB + PresenceTracker +TUI Client ──► WebSocket ──► ChatHub ─────┘ +``` + +Both protocols call into a shared `IChatService` for business logic. Events fan out to all registered `IChatBroadcaster` implementations (SignalR and IRC). + ## Components ### EchoHub.Core @@ -12,7 +22,7 @@ Shared library containing: - **Models**: `User`, `Channel`, `Message`, `RefreshToken` - **DTOs**: Record types for API requests/responses -- **Contracts**: `IEchoHubClient` -- the strongly-typed SignalR client interface +- **Contracts**: `IChatService` (protocol-agnostic chat operations), `IChatBroadcaster` (event fan-out interface), `IEchoHubClient` (SignalR client interface) - **Constants**: `ValidationConstants` (shared regex patterns), `HubConstants` ### EchoHub.Server @@ -20,10 +30,21 @@ Shared library containing: ASP.NET Core web application: - **Controllers**: REST API endpoints for auth, channels, users, files, server info -- **Hubs**: SignalR `ChatHub` for real-time messaging +- **Hubs**: SignalR `ChatHub` -- thin adapter delegating to `IChatService` - **Auth**: JWT token service (15-min access tokens, 30-day refresh tokens) - **Data**: EF Core with SQLite -- **Services**: Presence tracking, file storage, image-to-ASCII conversion +- **Services**: `ChatService` (core business logic), `SignalRBroadcaster`, presence tracking, file storage, image-to-ASCII conversion + +### EchoHub.Server.Irc + +IRC protocol gateway (separate project for clean separation of concerns): + +- **IrcGatewayService**: `BackgroundService` with TCP listener on configured port(s), optional TLS +- **IrcCommandHandler**: Per-client IRC command dispatch -- handles `CAP`/`SASL`, `NICK`/`USER`/`PASS`, `JOIN`/`PART`/`PRIVMSG`/`QUIT`, `NAMES`/`TOPIC`/`WHO`/`WHOIS`/`AWAY`/`LIST`/`MODE`/`MOTD` +- **IrcBroadcaster**: `IChatBroadcaster` implementation that formats chat events as IRC protocol lines, with echo suppression (IRC convention) +- **IrcMessageFormatter**: Converts `MessageDto` to IRC `PRIVMSG` lines -- splits long text at word boundaries (~400 byte chunks), sends images as ASCII art line-by-line + +IRC users authenticate with existing EchoHub accounts via `PASS`/`NICK`/`USER` or SASL PLAIN (BCrypt verification against the database). ### EchoHub.Client @@ -31,11 +52,22 @@ Terminal.Gui v2 TUI application: - **UI**: Main window, dialogs, chat renderer with ANSI color support - **Services**: API client with automatic token refresh, SignalR connection wrapper -- **Themes**: 6 built-in color themes +- **Themes**: 13 built-in color themes - **Config**: Client configuration management ## Communication -- REST API for authentication, profile management, channel CRUD, file uploads -- SignalR WebSocket for real-time messaging and presence updates +- **REST API** for authentication, profile management, channel CRUD, file uploads +- **SignalR WebSocket** for real-time messaging and presence updates (TUI client) +- **IRC TCP** for real-time messaging via standard IRC protocol (IRC clients) - JWT tokens passed via query string for SignalR authentication +- IRC authentication via PASS/SASL PLAIN against BCrypt password hashes + +## Broadcaster Pattern + +The `IChatBroadcaster` interface allows multiple protocols to receive chat events: + +- **SignalRBroadcaster**: Wraps `IHubContext`, filters out IRC connections +- **IrcBroadcaster**: Iterates live IRC connections in a channel, formats events as IRC protocol lines + +Both are registered in DI and called by `ChatService` when events occur. This means a message sent from an IRC client appears in the TUI client, and vice versa. diff --git a/docs/articles/getting-started.md b/docs/articles/getting-started.md index 9f31bf1..2d45cad 100644 --- a/docs/articles/getting-started.md +++ b/docs/articles/getting-started.md @@ -4,6 +4,8 @@ - [.NET 10 SDK](https://dotnet.microsoft.com/download) +Or grab a self-contained binary from [Releases](https://github.com/HueByte/EchoHub/releases) -- no runtime needed. + ## Run the Server ```bash @@ -24,6 +26,37 @@ dotnet run --project src/EchoHub.Client Connect to a server, register an account, and start chatting. +## Connect via IRC + +Enable the IRC gateway in the server's `appsettings.json`: + +```json +{ + "Irc": { + "Enabled": true, + "Port": 6667 + } +} +``` + +Then connect with any standard IRC client: + +```bash +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. + +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. + +## Configuration + +Server configuration is in `appsettings.json` (auto-generated on first run). See the [example config](https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Server/appsettings.example.json) for all available options. + +To list your server on the [public directory](https://echohub.voidcube.cloud/servers), set `Server:PublicServer` to `true` and `Server:PublicHost` to your server's public address. + ## Build from Source ```bash diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 90c9628..f34555b 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -4,5 +4,6 @@ Release history for EchoHub. ## Releases +- [v0.2.0](v0.2.0.md) - IRC Gateway - [v0.1.1](v0.1.1.md) - Directory Connection Self-Healing - [v0.1.0](v0.1.0.md) - Initial Release diff --git a/docs/changelog/toc.yml b/docs/changelog/toc.yml index 32cbada..b3b5122 100644 --- a/docs/changelog/toc.yml +++ b/docs/changelog/toc.yml @@ -1,5 +1,7 @@ - name: Overview href: index.md +- name: v0.2.0 + href: v0.2.0.md - name: v0.1.1 href: v0.1.1.md - name: v0.1.0 diff --git a/docs/changelog/v0.2.0.md b/docs/changelog/v0.2.0.md new file mode 100644 index 0000000..1e9b7cd --- /dev/null +++ b/docs/changelog/v0.2.0.md @@ -0,0 +1,21 @@ +# v0.2.0 - IRC Gateway + +## Features + +- **IRC protocol gateway** -- native IRC clients (irssi, WeeChat, HexChat, etc.) can connect to EchoHub servers +- **Cross-protocol messaging** -- messages flow bidirectionally between IRC and TUI clients in real time +- **SASL PLAIN authentication** -- IRC clients can authenticate via SASL or traditional PASS/NICK/USER +- **Full IRC command support** -- JOIN, PART, PRIVMSG, QUIT, NAMES, TOPIC, WHO, WHOIS, AWAY, LIST, MODE, MOTD +- **TLS support** -- optional encrypted IRC connections on port 6697 +- **Image-to-IRC formatting** -- images appear as ASCII art line-by-line with download URLs +- **Message splitting** -- long messages automatically split at word boundaries (~400 byte chunks) +- **Configurable MOTD** -- server message of the day for IRC clients + +## Architecture Changes + +- Extracted shared business logic from `ChatHub` into protocol-agnostic `IChatService` +- Introduced `IChatBroadcaster` pattern for multi-protocol event fan-out +- `ChatHub` refactored to thin adapter delegating to `IChatService` +- `ChannelsController` updated to use `IChatService` for broadcasts +- New `EchoHub.Server.Irc` project for clean separation of concerns +- `IChatService` and `IChatBroadcaster` interfaces live in `EchoHub.Core/Contracts` diff --git a/docs/docfx.json b/docs/docfx.json index 7e28fca..52df4c8 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -30,6 +30,16 @@ ], "dest": "_api_meta/client", "filter": "filterConfig.yml" + }, + { + "src": [ + { + "src": "../src/EchoHub.Server.Irc/bin/Release/net10.0", + "files": ["EchoHub.Server.Irc.dll"] + } + ], + "dest": "_api_meta/server-irc", + "filter": "filterConfig.yml" } ], "build": { @@ -55,6 +65,12 @@ "dest": "api/client", "files": ["*.yml"], "exclude": ["toc.yml"] + }, + { + "src": "_api_meta/server-irc", + "dest": "api/server-irc", + "files": ["*.yml"], + "exclude": ["toc.yml"] } ], "resource": [ diff --git a/docs/index.md b/docs/index.md index 6c8b7cd..cf75e8f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,11 +4,13 @@ _layout: landing # EchoHub Documentation -Welcome to the EchoHub documentation. EchoHub is a decentralized, IRC-like chat application built with .NET 10 and SignalR. +Welcome to the EchoHub documentation. EchoHub is a decentralized, IRC-style chat platform. Self-hosted, terminal-first, with a built-in IRC gateway so native IRC clients can connect alongside the TUI client. + +**Website:** [echohub.voidcube.cloud](https://echohub.voidcube.cloud/) | **Public Servers:** [Server Directory](https://echohub.voidcube.cloud/servers) ## Quick Links - [Getting Started](articles/getting-started.md) - Set up and run EchoHub -- [Architecture](articles/architecture.md) - Understand the system design +- [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/examples/nginx.conf b/examples/nginx.conf new file mode 100644 index 0000000..ca07536 --- /dev/null +++ b/examples/nginx.conf @@ -0,0 +1,94 @@ +# EchoHub nginx configuration example +# +# This config handles: +# - HTTPS reverse proxy for the HTTP API + SignalR WebSocket +# - TLS termination for IRC on port 6697 +# - HTTP → HTTPS redirect +# +# Prerequisites: +# - EchoHub Server running on 127.0.0.1:5000 +# - IRC gateway enabled on port 6667 (Irc:Enabled = true, Irc:TlsEnabled = false) +# - TLS certificate (e.g. from Let's Encrypt) +# +# Usage: +# 1. Copy this file to /etc/nginx/sites-available/echohub +# 2. Replace "echohub.example.com" with your domain +# 3. Update certificate paths +# 4. ln -s /etc/nginx/sites-available/echohub /etc/nginx/sites-enabled/ +# 5. nginx -t && systemctl reload nginx +# +# Note: The "stream" block for IRC TLS must go in the main nginx.conf +# (outside the http block), not in sites-available. See the bottom of +# this file for the stream config. + +# --- Place this in /etc/nginx/sites-available/echohub --- + +# HTTP → HTTPS redirect +server { + listen 80; + listen [::]:80; + server_name echohub.example.com; + + return 301 https://$host$request_uri; +} + +# HTTPS — API + SignalR WebSocket +server { + listen 443 ssl; + listen [::]:443 ssl; + server_name echohub.example.com; + + ssl_certificate /etc/letsencrypt/live/echohub.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/echohub.example.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + # File upload limit (match EchoHub's MaxFileSizeBytes) + client_max_body_size 10m; + + location / { + proxy_pass http://127.0.0.1:5000; + proxy_http_version 1.1; + + # Standard proxy headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Required for SignalR WebSocket upgrade + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + + # Long timeout for WebSocket connections + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + + # Disable buffering for real-time + proxy_buffering off; + } +} + +# --- Place this in /etc/nginx/nginx.conf (outside the http block) --- + +# IRC TLS termination (port 6697 → plain IRC on 6667) +# The stream module handles raw TCP, not HTTP. +# +# stream { +# upstream irc_backend { +# server 127.0.0.1:6667; +# } +# +# server { +# listen 6697 ssl; +# listen [::]:6697 ssl; +# proxy_pass irc_backend; +# +# ssl_certificate /etc/letsencrypt/live/echohub.example.com/fullchain.pem; +# ssl_certificate_key /etc/letsencrypt/live/echohub.example.com/privkey.pem; +# ssl_protocols TLSv1.2 TLSv1.3; +# +# # Timeout for idle IRC connections (24 hours) +# proxy_timeout 86400s; +# } +# }