# โฌก Haven โ€” User Guide Welcome to **Haven**, your private chat server. This guide covers everything you need to get Haven running and invite your friends. --- ## ๐Ÿ“‹ What You Need - **Windows 10 or 11** (macOS / Linux can run it manually) - **Node.js** version 18 or newer โ†’ [Download here](https://nodejs.org/) - About **50 MB** of disk space - **OR** just [Docker](https://docs.docker.com/get-docker/) โ€” no Node.js needed --- ## ๐Ÿณ Docker Setup (Alternative) If you'd rather run Haven in a container (great for NAS boxes, servers, or if you just like Docker): ### Quick Start **Option A โ€” Pre-built image** (fastest): ```bash docker pull ghcr.io/ancsemi/haven:latest docker run -d -p 3000:3000 -v haven_data:/data ghcr.io/ancsemi/haven:latest ``` **Option B โ€” Build from source**: ```bash git clone https://github.com/ancsemi/Haven.git cd Haven docker compose up -d ``` That's it. Haven will be running at `https://localhost:3000`. ### What Happens Automatically - Self-signed SSL certs are generated on first launch (needed for voice chat) - Database, config, and uploads are stored in a Docker volume (`haven_data`) - The container runs as a non-root user for security - Restarts automatically if it crashes ### Customizing Edit `docker-compose.yml` to change the port, server name, or other settings. The environment variables are commented out with examples โ€” just uncomment what you need. ### Using a Local Folder Instead of a Volume If you want your data in a specific folder (common on Synology / NAS): ```yaml volumes: - /path/to/your/haven-data:/data ``` Replace the `haven_data:/data` line in `docker-compose.yml`. ### Updating **Option A โ€” Pre-built image** (default, recommended): ```bash docker compose pull docker compose up -d --force-recreate ``` **Option B โ€” Built from source** (only if you uncommented `build: .`): ```bash git pull docker compose build --no-cache docker compose up -d ``` Your data is safe โ€” it lives in the volume, not the container. ### Checking Your Version Open this URL in your browser (replace with your domain/IP if needed): ``` https://localhost:3000/api/version ``` Or from inside the container: ```bash docker compose exec haven cat /app/package.json | grep '"version"' ``` ### Linux Prerequisites If you're on Linux (Ubuntu, Mint, Debian, etc.), make sure you have Docker's official packages installed โ€” the default `docker.io` package from some distros may be missing Compose V2. **1. Install Docker Engine + Compose plugin:** ```bash sudo apt update sudo apt install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$UBUNTU_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin ``` **2. Add your user to the `docker` group** (so you don't need `sudo` for every command): ```bash sudo usermod -aG docker $USER newgrp docker ``` After that, `docker compose up -d` should work without errors. --- ## ๐Ÿš€ Getting Started ### Step 1 โ€” First Launch Double-click **`Start Haven.bat`** That's it. The batch file will: 1. Check that Node.js is installed 2. Install dependencies (first time only) 3. Generate SSL certificates (first time only) 4. Start the server 5. Open your browser to the login page ### Step 2 โ€” Create Your Admin Account 1. On the login page, click **Register** 2. Create an account with the admin username (default: `admin` โ€” check your data directory's `.env` file) 3. This account can create and delete channels ### Step 3 โ€” Create a Channel 1. In the sidebar, use the **Create Channel** box (admin only) 2. Give it a name like "General" or "Gaming" 3. Haven generates a unique **channel code** (8 characters) 4. Share this code with your friends โ€” it's the only way in ### Step 4 โ€” Invite Friends Send your friends: 1. Your server address: `https://YOUR_IP:3000` 2. The channel code They'll register their own account, then enter the code to join your channel. --- ## ๐Ÿ“‚ Channels & Sub-Channels ### How Channels Work Every conversation in Haven happens inside a **channel**. Channels are like rooms โ€” each has a unique 8-character code (e.g. `a3f8b2c1`). To get into a channel, you either create it or enter its code. ### Creating Sub-Channels Right-click (or click โ‹ฏ) on any channel to create a **sub-channel** beneath it. Sub-channels appear indented under their parent with a `โ†ณ` icon. They have their own code and their own message history. **When you create a sub-channel:** - All current parent channel members are **automatically added** to it - The sub-channel gets its own unique invite code - Max one level deep (no sub-sub-channels) **When someone joins a parent channel later:** - They're **automatically added** to all non-private sub-channels of that parent - They do NOT get access to private sub-channels (see below) ### Private Sub-Channels ๐Ÿ”’ When creating a sub-channel, check the **๐Ÿ”’ Private** checkbox. Private sub-channels: - Only add the **creator** as initial member (not all parent members) - Show a **๐Ÿ”’** icon instead of `โ†ณ` in the sidebar - Appear in *italic* text with reduced opacity - Can only be joined by entering the sub-channel's code directly - Are invisible to non-members (they won't see it in their channel list) Use private sub-channels for admin-only discussions, sensitive topics, or small breakout groups within a larger channel. --- ## ๏ฟฝ Importing from Discord Haven can import your entire Discord server's message history โ€” directly from the app. No external tools required. ### Method 1: Direct Connect (Recommended) 1. Open **Settings** (โš™๏ธ in the sidebar) โ†’ scroll to **Import Discord History** 2. Click the **๐Ÿ”— Connect to Discord** tab 3. Get your Discord token: - Open Discord in your browser (or desktop app with dev tools enabled) - Press **F12** โ†’ go to the **Application** tab - In the left sidebar: **Local Storage** โ†’ **https://discord.com** - Find the key called **`token`** and copy its value (without quotes) 4. Paste the token and click **Connect** 5. Pick a server from the grid, then select which channels and threads to import 6. Click **Fetch Messages** โ€” Haven downloads everything 7. In the preview, rename channels if you want, then click **Import** **What gets imported:** messages, replies, embeds, attachments, reactions, pins, forum tags, and original Discord avatars. **Channel types supported:** text, announcement, forum, media, plus active and archived threads. ### Method 2: File Upload If you prefer, export your Discord data with [DiscordChatExporter](https://github.com/Tyrrrz/DiscordChatExporter) (JSON format), then: 1. Open **Settings** โ†’ **Import Discord History** 2. Click the **๐Ÿ“ Upload File** tab 3. Drag/drop or browse for the `.json` or `.zip` file 4. Preview, rename channels, and import ### Important Notes - Imported messages appear as the original Discord usernames, but they're all stored under the admin account. They're clearly marked as imported from Discord. - The import is **history only** โ€” Discord roles, permissions, bots, and webhooks are not imported. - Your Discord token is never stored by Haven. It's used only during the import session and discarded. --- ## ๏ฟฝ๐Ÿ”‘ Join Code Settings (Admin) Each channel's invite code can be configured by admins. Click the **โš™๏ธ gear icon** next to the channel code in the header. ### Code Visibility | Setting | Behavior | |---------|----------| | **Public** | All members can see the channel code | | **Private** | Only admins see the code; others see `โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข` | ### Code Mode | Setting | Behavior | |---------|----------| | **Static** | Code never changes | | **Dynamic** | Code automatically rotates based on a trigger | ### Rotation Triggers (Dynamic mode only) | Trigger | Behavior | |---------|----------| | **Time-based** | Code rotates every X minutes | | **Join-based** | Code rotates after X new members join | You can also click **Rotate Now** to manually change the code immediately. > ๐Ÿ’ก Dynamic codes are great for public communities where you want to limit code sharing. Old codes stop working after rotation. --- ## ๐Ÿ–ผ๏ธ Avatars ### Uploading a Profile Picture 1. Click the **โš™๏ธ Settings** button in the sidebar 2. In the **Avatar** section, click **Upload** 3. Choose an image (max 2 MB; JPEG, PNG, GIF, or WebP) 4. Pick a shape: โšช Circle, โฌœ Square, โฌก Hexagon, or โ—‡ Diamond 5. Click **Save** Your avatar and shape are visible to everyone in messages and the member list. Each user's shape is stored independently. ### Removing Your Avatar Click **Clear** to remove your avatar and revert to the default initial-letter avatar. --- ## ๐ŸŽจ Themes & Effects ### Themes Haven includes 20+ visual themes. Click the **๐ŸŽจ** button at the bottom of the sidebar to open the theme picker. Themes change colors, fonts, and overall aesthetic. Your choice is saved per browser. ### Effect Overlays Effects are stackable visual layers on top of any theme. Choose from the effect selector in the theme popup: | Effect | Description | |--------|-------------| | **โŸณ Auto** | Matches your current theme's default effect | | **๐Ÿšซ None** | No overlays | | **๐Ÿ“บ CRT** | Retro scanlines + vignette + flicker | | **โ…ฏ Matrix** | Green digital rain cascade | | **โ„ Snowfall** | Falling snowflakes | | **๐Ÿ”ฅ Campfire** | Ember particles + warm glow | | **๐Ÿ’ Golden Grace** | Elden Ring-style golden particles | | **๐Ÿฉธ Blood Vignette** | Dark pulsing edges | | **โ˜ข๏ธ Phosphor** | Fallout-style green vignette | | **โš”๏ธ Water Flow** | Gentle blue sidebar animation | | **๐ŸงŠ Frost** | Ice shimmer + icicle borders | | **โšก Glitch** | Cyberpunk text scramble (see below) | | **โšœ Candlelight** | Warm sidebar glow | | **๐ŸŒŠ Ocean Depth** | Deep blue vignette | | **โœ๏ธ / โ›ช / ๐Ÿ•Š๏ธ** | Sacred themed overlays | ### Cyberpunk Text Scramble โšก When the Glitch effect is active, text around the UI randomly "scrambles" โ€” cycling through random characters before resolving back to the original text. This affects: - The **HAVEN** logo - Channel names in the sidebar - Section labels - Your username - The channel header - User names in the member list A **Glitch Frequency** slider appears in the theme popup when this effect is active. Slide left for rare, subtle glitches โ€” or right for constant chaos. --- ## ๐ŸŒ Setting Up Remote Access (Friends Over the Internet) If your friends are **not** on your local WiFi, you need to set up port forwarding so they can reach your PC from the internet. ### Find Your Public IP Visit [whatismyip.com](https://whatismyip.com) โ€” the number shown (like `203.0.113.50`) is what your friends will use. ### Port Forwarding on Your Router Every router is different, but the general steps are: 1. **Log into your router** โ€” usually `http://192.168.1.1` or `http://10.0.0.1` in your browser 2. Find **Port Forwarding** (sometimes called NAT, Virtual Servers, or Applications) 3. Create a new rule: | Field | Value | |-------|-------| | Port | `3000` | | Protocol | TCP | | Internal IP | Your PC's local IP (e.g. `10.0.0.60`) | 4. Save and apply > **How to find your local IP:** Open Command Prompt and type `ipconfig`. Look for the "IPv4 Address" under your Ethernet or WiFi adapter. ### Windows Firewall The server needs permission to accept incoming connections: 1. Open **Start Menu** โ†’ search **"Windows Defender Firewall"** 2. Click **"Advanced settings"** on the left 3. Click **"Inbound Rules"** โ†’ **"New Rule..."** 4. Select **Port** โ†’ **TCP** โ†’ enter `3000` 5. Allow the connection โ†’ apply to all profiles 6. Name it something like "Haven Chat" Or run this in PowerShell (as Administrator): ```powershell New-NetFirewallRule -DisplayName "Haven_Chat" -Direction Inbound -LocalPort 3000 -Protocol TCP -Action Allow ``` ### Tell Your Friends Send them this URL: ``` https://YOUR_PUBLIC_IP:3000 ``` > โš ๏ธ **Certificate Warning:** Your friends' browsers will show a security warning because Haven uses a self-signed certificate. This is normal and expected. Tell them to click **"Advanced"** โ†’ **"Proceed to site"**. The connection is still encrypted. --- ## ๏ฟฝ Cloudflare Tunnel (No Port Forwarding) If you don't want to mess with port forwarding or expose your home IP, you can use a **Cloudflare Tunnel** to securely share your Haven server over the internet. Cloudflare gives your server a public URL and handles all the networking โ€” no router config needed. ### Step 1 โ€” Install Cloudflared **Windows (via winget):** ```powershell winget install cloudflare.cloudflared ``` **macOS (via Homebrew):** ```bash brew install cloudflared ``` **Linux:** ```bash curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared chmod +x /usr/local/bin/cloudflared ``` Verify it installed: ```bash cloudflared --version ``` ### Step 2 โ€” Enable the Tunnel in Haven 1. Start Haven normally (`Start Haven.bat`) 2. Log in as admin 3. Open **โš™๏ธ Settings** โ†’ scroll to the **Tunnel** section 4. Select **Cloudflare** as the tunnel provider 5. Flip the toggle **on** 6. Haven will start cloudflared and display your public URL (e.g. `https://abc-def-123.trycloudflare.com`) ### Step 3 โ€” Share the URL Copy the tunnel URL and send it to your friends. That's it โ€” no port forwarding, no firewall rules, no IP address sharing. The URL changes each time you restart the tunnel, so you'll need to re-share it. ### How It Works - Haven runs **cloudflared** as a child process that creates an encrypted tunnel to Cloudflare's network - Cloudflare assigns a random public URL and proxies traffic through the tunnel to your local server - Your home IP is **never exposed** to visitors โ€” they only see Cloudflare's IP - Since Haven runs HTTPS with a self-signed cert, the tunnel connects to `https://localhost:3000` with TLS verification disabled (the Cloudflareโ†’You leg is already encrypted by the tunnel itself) ### Tunnel vs. Port Forwarding | | Port Forwarding | Cloudflare Tunnel | |---|---|---| | **Router config** | Required | None | | **Exposes home IP** | Yes | No | | **Firewall rules** | Required | None | | **Stable URL** | Your IP (may change) | Random URL (changes on restart) | | **Push notifications** | โœ… (if HTTPS) | โœ… | | **Voice chat** | โœ… | โœ… | > ๐Ÿ’ก **Tip:** For a permanent URL, you can set up a free Cloudflare account and use a named tunnel with your own domain. See [Cloudflare's tunnel docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) for details. ### Troubleshooting Tunnels | Problem | Solution | |---------|----------| | "cloudflared not found" | Restart your terminal after installing, or add it to your PATH manually | | Tunnel shows "502 Bad Gateway" | Make sure Haven is running before enabling the tunnel | | URL changes every restart | Normal for quick tunnels. Use a named tunnel + custom domain for permanence | | "Connection refused" in tunnel logs | Haven isn't running on port 3000, or it's running HTTP instead of HTTPS | --- ## ๐Ÿ” Reverse Proxy (Caddy, nginx, Traefik) If you already have a domain and want Haven to live behind a proper reverse proxy (so you get a real Let's Encrypt cert, no browser warnings, and the same `https://chat.example.com` URL every time), set `FORCE_HTTP=true` and let the proxy terminate TLS for you. ### Quick Recipe (Caddy) 1. **Stop Haven** if it's running. 2. Add the following line to your `.env` file (create one next to `package.json` if it doesn't exist): ```env FORCE_HTTP=true ``` This tells Haven to skip its built-in self-signed cert generation and listen on plain HTTP on port 3000. Caddy will handle the HTTPS leg. 3. **Install Caddy** ([caddyserver.com/download](https://caddyserver.com/download)) and create a `Caddyfile`: ```caddy chat.example.com { reverse_proxy localhost:3000 } ``` Replace `chat.example.com` with your real domain. Caddy will auto-fetch a Let's Encrypt cert on first run. Make sure ports **80 and 443** are open / forwarded to the Caddy host. 4. **Start Caddy**, then **start Haven** (`Start Haven.bat` or `npm start`). 5. Open `https://chat.example.com` in a browser. You should see Haven with a clean padlock and no cert warnings. ### Using a Tunnel + Caddy If you don't want to port-forward 80/443, point a tunnel (Cloudflare Tunnel, Tailscale Funnel, ngrok, etc.) at the Caddy host. The flow becomes: ``` Browser โ†’ Tunnel (HTTPS) โ†’ Caddy (HTTPS) โ†’ Haven (HTTP, FORCE_HTTP=true) ``` Caddy still terminates TLS for the LAN leg, and the tunnel terminates a second TLS layer for the public leg. That's the setup minecraft_bread used successfully (see the support thread for the full step-by-step). ### nginx Snippet ```nginx server { listen 443 ssl http2; server_name chat.example.com; ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 86400; } } ``` The `Upgrade` / `Connection` headers are required for Socket.io WebSocket traffic; without them voice chat and live messages will silently break. ### Common Gotchas | Problem | Fix | |---------|-----| | Browser shows Haven's self-signed cert warning instead of the Let's Encrypt one | You forgot `FORCE_HTTP=true`. Haven is still serving its own HTTPS on 3000 and Caddy is just proxying that. Add the line, restart Haven. | | Voice chat / live updates don't work behind nginx | Add the `Upgrade` and `Connection "upgrade"` headers shown above. Caddy handles WebSockets automatically. | | Mixed-content errors in browser console | Make sure the proxy forwards `X-Forwarded-Proto $scheme` so Haven knows it's serving over HTTPS. | | "502 Bad Gateway" from Caddy | Haven isn't running, or it's still bound to HTTPS on 3000. Double-check `FORCE_HTTP=true` is in `.env` and you restarted Haven after adding it. | > ๐Ÿ’ก A full Docker Compose example with Traefik + coturn lives in [`docs/examples/haven-traefik-coturn/`](docs/examples/haven-traefik-coturn/) if you'd rather run the whole stack containerised. --- ## ๐Ÿ”ง Router-Specific Tips ### Xfinity / Comcast (XB7 Gateway) 1. Open the **Xfinity app** on your phone 2. Go to **WiFi** โ†’ scroll down โ†’ **Advanced settings** โ†’ **Port forwarding** 3. Select your PC from the device list 4. Add port `3000` (TCP/UDP) and apply 5. **Important:** Go to **Home** โ†’ disable **xFi Advanced Security** โ€” it silently blocks all inbound connections 6. Verify the **reserved IP** in port forwarding matches your PC's actual IP (`ipconfig` to check) ### Common Issues | Problem | Solution | |---------|----------| | **"SSL_ERROR_RX_RECORD_TOO_LONG"** | Browser is using `https://` but server is running HTTP. Change URL to `http://localhost:3000`, or install OpenSSL and restart (see Troubleshooting below) | | Friends get "took too long to respond" | Port forwarding not set up, or firewall blocking | | Friends get "connection refused" | Server isn't running โ€” launch `Start Haven.bat` | | Can't connect with `https://` | Make sure you're using port 3000, not 443 | | Voice chat doesn't work | Must use `https://` โ€” voice requires a secure connection | | "Certificate error" in browser | Normal โ€” click Advanced โ†’ Proceed | --- ## ๐ŸŽจ Themes Haven comes with 6 themes. Switch between them using the theme buttons at the bottom of the left sidebar: | Button | Theme | Style | |--------|-------|-------| | โฌก | **Haven** | Deep blue/purple (default) | | ๐ŸŽฎ | **Discord** | Dark gray with blue accents | | โ…ฏ | **Matrix** | Black and green, scanline overlay | | โ—ˆ | **Tron** | Black with neon cyan glow | | โŒ | **HALO** | Military green with Mjolnir vibes | | โšœ | **LoTR** | Parchment gold and deep brown | | ๐ŸŒ† | **Cyberpunk** | Neon pink and electric yellow | | โ„ | **Nord** | Arctic blue and frost | | ๐Ÿง› | **Dracula** | Deep purple and blood red | | โš” | **Bloodborne** | Gothic crimson and ash | | โฌš | **Ice** | Pale blue and white | | ๐ŸŒŠ | **Abyss** | Deep ocean darkness | Your theme choice is saved per browser. --- ## ๐ŸŽค Voice Chat 1. Join a text channel first 2. Click **๐ŸŽค Join Voice** in the channel header 3. Allow microphone access when your browser asks 4. Click **๐Ÿ”‡ Mute** to toggle your mic 5. Click **๐Ÿ“ž Leave** to disconnect from voice Voice chat is **peer-to-peer** โ€” audio goes directly between you and other users, not through the server. > Voice requires HTTPS. If you're running locally, use `https://localhost:3000`. For remote connections, use `https://YOUR_IP:3000`. ### TURN Server (Voice Over the Internet) By default, voice/screen sharing uses STUN servers, which work when both users are on the same network or behind simple NATs. For connections across different networks (especially mobile data / 5G), you need a **TURN server** to relay traffic. **Quick setup with coturn (free, open-source):** ```bash # Ubuntu/Debian sudo apt install coturn # /etc/turnserver.conf: listening-port=3478 tls-listening-port=5349 realm=your-domain.com use-auth-secret static-auth-secret=YOUR_RANDOM_SECRET_HERE ``` Then add to your Haven `.env`: ```env TURN_URL=turn:your-server.com:3478 TURN_SECRET=YOUR_RANDOM_SECRET_HERE ``` Restart Haven, and voice/screen sharing will work across any network. > **Docker users:** Add `TURN_URL` and `TURN_SECRET` as environment variables in your `docker-compose.yml`. See the commented example in the default compose file. > **Oracle Cloud / cloud VMs:** Make sure ports 3478 (UDP+TCP) and 49152โ€“65535 (UDP) are open in your security group / firewall rules. These are needed for TURN relay traffic. --- ## ๐Ÿ”” Push Notifications Push notifications let you receive alerts when someone messages a channel you're in, even when the Haven tab is in the background or closed. ### Requirements - **HTTPS is required.** Push notifications use Service Workers, which only work over `https://` or `localhost`. If you're accessing Haven via a LAN IP like `http://192.168.1.x:3000`, push will **not** work. - A modern browser (Chrome, Edge, Firefox, or Safari 16+) - Haven must be running with SSL certificates (the default if OpenSSL is installed) ### How to Enable 1. Open Haven in your browser via `https://` (e.g., `https://localhost:3000` or `https://your-domain:3000`) 2. Click the **โš™๏ธ Settings** button (bottom of the right sidebar) 3. Scroll to **Push Notifications** and flip the toggle **on** 4. Your browser will ask for notification permission โ€” click **Allow** 5. The status should change to **Enabled** ### Setting Up on Your Devices **Desktop (Windows / macOS / Linux):** - Works in Chrome, Edge, and Firefox out of the box - Make sure you access Haven via `https://` (not `http://`) - If you see "Service worker failed" or "Requires HTTPS", you're on an insecure connection **Mobile (Android):** - Open Haven in **Chrome** or **Edge** via `https://` - Enable push in Settings (same steps as above) - Notifications appear even when Chrome is closed **Mobile (iOS / iPadOS):** - Requires **Safari 16.4+** (iOS 16.4 or later) - First, **Add to Home Screen**: tap Share โ†’ "Add to Home Screen" - Open Haven from the home screen icon (it runs as a web app) - Enable push in Settings โ€” Safari will ask for permission ### Troubleshooting Push | Problem | Solution | |---------|----------| | "Service worker failed" | You're not on HTTPS. Use `https://localhost:3000` or set up SSL certs (see Troubleshooting below) | | "Requires HTTPS" | Access Haven via `https://` instead of `http://` | | "Permission denied" | You blocked notifications. Reset in browser settings: Settings โ†’ Site Settings โ†’ Notifications โ†’ find Haven โ†’ Allow | | Toggle is grayed out | Your browser doesn't support push, or you're in incognito/private mode | | Notifications not appearing | Check your OS notification settings โ€” Haven notifications may be muted at the system level | | Only works on localhost | For LAN/remote access, you need valid SSL. Haven auto-generates self-signed certs if OpenSSL is installed | --- ## โš™๏ธ Configuration All settings are in the `.env` file in your **data directory**: | OS | Data Directory | |----|---------------| | Windows | `%APPDATA%\Haven\` | | Linux / macOS | `~/.haven/` | | Setting | What it does | |---------|-------------| | `PORT` | Server port (default: 3000) | | `ADMIN_USERNAME` | Which username gets admin powers | | `JWT_SECRET` | Auto-generated security key โ€” don't share this | | `HAVEN_DATA_DIR` | Override where data is stored | > `.env` is created automatically on first launch. If you change it, restart the server. --- ## ๐Ÿ’ก Tips - **Bookmark the URL** โ€” so you don't have to type the IP every time - **Keep the bat window open** โ€” closing it stops the server - **Your data is stored separately** โ€” all messages, config, and uploads are in your data directory (`%APPDATA%\Haven` on Windows, `~/.haven` on Linux/macOS), not in the Haven code folder - **Back up your data directory** โ€” copy it somewhere safe to preserve your chat history - **Channel codes are secrets** โ€” treat them like passwords. Anyone with the code can join. --- ## ๐Ÿ” End-to-End Encryption (E2E) All direct messages in Haven are **end-to-end encrypted**. The server never has access to the plaintext of your DMs or the keys needed to decrypt them. ### How It Works - When you first log in, your browser generates an **ECDH P-256 key pair**. - The private key is encrypted (wrapped) with a key **derived from your password** using PBKDF2, and the encrypted blob is stored on the server for cross-device sync. - The server **never sees** your password-derived wrapping key โ€” it's computed in your browser and never transmitted. - When you message someone, both users' public keys are combined via ECDH + HKDF to produce a shared AES-256-GCM encryption key. Messages are encrypted before leaving your browser. ### When Keys Are Preserved (Old Messages Readable) | Scenario | Why it works | |---|---| | Close the tab and reopen it | IndexedDB still has your keys โ€” no password needed | | Refresh the page | Same โ€” IndexedDB survives refreshes | | JWT auto-login (return visit) | IndexedDB has the keys cached | | Log in on a new device/browser | You type your password โ†’ wrapping key is derived โ†’ server backup is downloaded and unwrapped | | Clear cookies (but NOT site data) | IndexedDB is site data, not cookies โ€” keys survive | | Change your password | Private key is re-wrapped with the new password and re-uploaded โ€” the ECDH key pair itself doesn't change | ### When Keys Are Lost (Old Messages Permanently Unreadable) | Scenario | Why keys are lost | |---|---| | Clear all browser/site data when that's your only device | IndexedDB is wiped โ€” on re-login the server backup may still unwrap if password hasn't changed | | Clear browser data **after** changing your password | Server backup was wrapped with the old password โ€” new password can't unwrap it โ†’ new keys generated | | Manually reset encryption keys (๐Ÿ”„ button in DM header) | Intentional wipe โ€” new key pair, old messages unreadable | | Admin deletes your account or resets the database | Server backup gone โ€” if IndexedDB is also empty, fresh keys are generated | **Short version:** Same password + at least one of (IndexedDB **or** server backup) = keys survive. Lost both = old messages gone forever. ### Can Anyone Intercept Messages? | Attack vector | Can they read messages? | Why | |---|---|---| | Server admin reading the database | **No** | Encrypted private key is wrapped with a key derived from YOUR password โ€” admin has the blob but not the key | | Someone with physical server access | **No** | Same reason โ€” the blob is useless without your password | | Man-in-the-middle on the network | **No** | Messages are encrypted client-side before transmission | | Stolen JWT token | **No** | JWT authenticates you, but E2E keys live in your browser's IndexedDB โ€” attacker can't unwrap the server backup without your password | | Someone who knows your password + has your JWT | **Yes** | Equivalent to using your login โ€” they can derive the wrapping key and decrypt everything | | Modified server JavaScript | **Yes** | If the admin pushes tampered JS that exfiltrates keys, all bets are off โ€” this is true of every web-based E2E system | ### Resetting Encryption Keys In any DM conversation, click the **๐Ÿ”„** button in the channel header to reset your encryption keys. This: - Generates a brand new key pair - Makes **all** previous encrypted messages **permanently unreadable** for both parties - Posts a timestamped notice in the chat so both users know when/why old messages became unreadable - Requires you to type **RESET** to confirm (there is no undo) ### Verifying Encryption Click the **๐Ÿ”** button in the DM header to view your **safety number** โ€” a 60-digit code derived from both users' public keys. Compare it with your conversation partner through a separate channel (phone, in person, etc.). If they match, no one is intercepting your conversation. --- ## ๐Ÿค– Bot & Webhook Developer Guide Haven has a built-in bot API powered by webhooks. Bots can send messages, delete messages, play soundboard sounds, and register custom slash commands. ### Creating a Bot 1. Go to **Settings โ†’ Server Admin Settings โ†’ Bots** (or open a channel's settings and look for the webhook/bot option) 2. Create a new webhook โ€” give it a name, optionally set an avatar URL and a callback URL 3. Copy the **Webhook Token** (64-character hex string) โ€” this is your bot's API key ### Sending Messages ``` POST https://your-server.com/api/webhooks/ Content-Type: application/json { "content": "Hello from my bot!", "username": "MyBot", "avatar_url": "https://example.com/avatar.png" } ``` - `content` (required) โ€” message text, max 4000 characters - `username` (optional) โ€” override the bot's display name for this message - `avatar_url` (optional) โ€” override the bot's avatar for this message Response: `{ "success": true, "message_id": 123 }` ### Deleting Messages ``` DELETE https://your-server.com/api/webhooks//messages/ ``` Bots can delete any message in their assigned channel. Returns `{ "success": true }`. ### Playing Soundboard Sounds ``` POST https://your-server.com/api/webhooks//sounds Content-Type: application/json { "sound": "AOL - You've Got Mail" } ``` Plays the named sound for all users currently viewing the bot's channel. Use `GET /api/sounds` (with a Bearer token) to list available sound names. ### Registering Slash Commands Bots with a `callback_url` can register custom slash commands that users can invoke from chat: **Register:** ``` POST https://your-server.com/api/webhooks//commands Content-Type: application/json { "command": "leaderboard", "description": "Show the current leaderboard" } ``` **List:** ``` GET https://your-server.com/api/webhooks//commands ``` **Unregister:** ``` DELETE https://your-server.com/api/webhooks//commands/leaderboard ``` When a user types `/leaderboard`, Haven sends a POST to your bot's callback URL with the command details, signed with HMAC so you can verify authenticity. ### Rate Limits All webhook endpoints are rate-limited to **30 requests per minute** per IP. ### Callback Payloads If your webhook has a `callback_url` and `callback_secret` configured, Haven will POST command invocations to your URL. The payload includes an HMAC signature in the `X-Haven-Signature` header that you should verify using your callback secret. --- ## ๐Ÿ†˜ Troubleshooting **"SSL_ERROR_RX_RECORD_TOO_LONG" or "ERR_SSL_PROTOCOL_ERROR" in browser** โ†’ Your browser is trying to connect via `https://` but the server is actually running in HTTP mode. This happens when SSL certificates weren't generated (usually because OpenSSL isn't installed). **Quick fix:** Change the URL in your browser from `https://localhost:3000` to `http://localhost:3000`. **Permanent fix:** Install OpenSSL so Haven can generate certificates: 1. Download from [slproweb.com/products/Win32OpenSSL.html](https://slproweb.com/products/Win32OpenSSL.html) (the "Light" version is fine) 2. During install, choose **"Copy OpenSSL DLLs to the Windows system directory"** 3. **Restart your PC** (so OpenSSL is added to PATH) 4. Delete the `certs` folder in your data directory (`%APPDATA%\Haven\certs`) 5. Re-launch `Start Haven.bat` โ€” it will regenerate certificates and start in HTTPS mode **How to tell if you're running HTTP or HTTPS:** Check the server's startup banner in the terminal. If it says `http://localhost:3000` โ€” you're on HTTP. If it says `https://localhost:3000` โ€” you're on HTTPS. The protocol in the URL you use must match. **"Node.js is not installed"** โ†’ Download and install from [nodejs.org](https://nodejs.org/). Restart your PC after installing. **Server starts but browser shows blank page** โ†’ Try clearing your browser cache, or open in an incognito/private window. **Friends can connect locally but not remotely** โ†’ Port forwarding isn't configured correctly. Double-check the port, protocol, and internal IP. **"Error: EADDRINUSE"** โ†’ Another program is using port 3000. Close it, or change the port in `.env`. **Voice chat echoes** โ†’ Use headphones to prevent your speakers from feeding into your microphone. ---

โฌก Haven โ€” Your server. Your rules.