Skip to content

About

Hotline Protocol Server

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

   __         _     __               
  / /_  ___  (_)___/ /______  ______ 
 / __ \/ _ \/ / __  / ___/ / / / __ \
/ / / /  __/ / /_/ / /  / /_/ / / / /
\/ /_/\___/_/\__,_/_/   \__,_/_/ /_/ 

Swift 6.2 macOS | Linux License: GPL v2

HeidrunServer

A Swift 6, pure-SwiftNIO Hotline-protocol server. Pairs with the Heidrun macOS client (or any classic Hotline 1.x client). Runs on macOS and Linux from the same source.

Features

  • Hotline 1.x protocol: chat, plain + threaded news, private messages + private chats, kick, broadcast
  • Persistent accounts (SQLite via GRDB) with PBKDF2-SHA256 password hashing
  • Admin transactions: createLogin / deleteLogin / openLogin / modifyLogin
  • File system: list, info, download, upload, delete, create folder, rename, move, alias
  • HTXF transfer side-channel (port + 1) with data-fork resume
  • Optional TLS sibling listener pair (encrypts control + transfer end-to-end)
  • Tracker UDP registration (Mobius-compatible, 5-min beacon)
  • Server banner (transID 212) — JPEG / GIF / BMP / PICT / URL
  • Per-file metadata (HFS type/creator + comments) persisted alongside accounts
  • Idle-away supervisor — auto-flips the away flag after configurable inactivity
  • Server-side chat commands — /version, /who, /topic, /broadcast, /kick, /usershistory, /away, /me, …
  • Structured logging via swift-log, graceful shutdown on SIGINT / SIGTERM

Quick start

Docker

make help        # list all targets
make up          # docker compose up -d --build (alias: make prod)
make logs        # follow the container log
make down

Defaults: control port 5500, HTXF transfer 5501, admin admin / CHANGE_ME_BEFORE_FIRST_RUN (see docker-compose.yml to set a real password before the first run).

Nothing inside a running container updates itself. make refresh rebuilds the image without the layer cache so the runtime picks up Ubuntu's current security fixes; run it from a weekly cron — see docs/OPERATIONS.md.

Local (development)

swift run HeidrunServer

Binds 127.0.0.1:5500 + 127.0.0.1:5501. Default admin is admin / admin against a fresh database — change it immediately for any real deployment.

Configuration

Two layered sources: env vars > TOML file > built-in defaults.

The annotated source of truth for the config surface is heidrun-server.example.toml. The high-traffic env vars:

Var Default What it does
HEIDRUN_CONFIG (unset) Path to a TOML config file
HEIDRUN_PORT 5500 Control port. Transfer port is always port + 1
HEIDRUN_SERVER_NAME Heidrun Display name in the user list
HEIDRUN_AGREEMENT (unset) Banner text pushed after login (transID 109)
HEIDRUN_CHAT_SUBJECT (empty) Initial public chat topic
HEIDRUN_DB_PATH (in-memory) SQLite file for accounts + file metadata
HEIDRUN_AUDIT_LOG_ENABLED on Master switch for the audit log (presence/transfers/auth/admin → a separate audit_events SQLite file, read via /audit). 0/false/no/off disables all recording. Replaces HEIDRUN_USER_HISTORY
HEIDRUN_AUDIT_DB_PATH (<db>.audit.sqlite) Audit SQLite file; unset derives a sibling of HEIDRUN_DB_PATH (in-memory if that's also unset)
HEIDRUN_AUDIT_RETENTION_DAYS 90 Days of audit history to keep (prune-on-write)
HEIDRUN_LOG_IP_ADDRESSES off 1/true/yes/on stores each client's raw IP in audit rows. Off by default — raw IPs are GDPR personal data
HEIDRUN_USER_HISTORY on Deprecated alias of HEIDRUN_AUDIT_LOG_ENABLED; still honoured
HEIDRUN_SEND_USER_ACCESS off 1/true/yes/on pushes the HXD-style User Access bitmap (TX 354) after login so third-party clients light up admin UI. Off by default — it blanks the roster on Heidrun clients older than protocol rc18
HEIDRUN_FILES_ROOT (tempdir) Directory the file ops operate on
HEIDRUN_NEWS_PATH (in-memory) JSON snapshot file for news state
HEIDRUN_ADMIN_LOGIN / HEIDRUN_ADMIN_PASSWORD admin / admin Bootstrap admin (only seeded on a fresh DB)
HEIDRUN_TRACKERS (empty) Comma-separated host[:port][:password] list of trackers
HEIDRUN_TLS_PORT / _CERTIFICATE / _PRIVATE_KEY (unset) Enables the TLS sibling pair on tls_port / tls_port + 1
HEIDRUN_BANNER_PATH / HEIDRUN_BANNER_KIND (unset) / jpeg Image file delivered via downloadBanner (transID 212)
HEIDRUN_LOG_LEVEL info swift-log level: trace / debug / info / … / critical

Operator depth (TLS / Let's Encrypt deploy hooks, ufw-docker, bootstrap admin permission upgrade, tracker debugging, full env reference) lives in docs/OPERATIONS.md. To run the full-featured heidrun-admin CLI natively on the host against a bind-mounted deployment, see docs/native-host-admin.md.

Slash commands

Users can issue server commands by typing them into the public chat input. Slash-prefixed lines are intercepted server-side; only the sender sees the response.

Command What it does
/version Version, build id, Swift compiler, platform, ports, uptime, user count
/uptime One-liner: *** uptime: 4d 11h 23m
/who / /users Roster dump with nicknames + socket IDs
/whoami Self-info: nickname, socket, login, IP, client version, TLS yes/no, admin yes/no, away yes/no, raw privilege bitmask
/away Toggle the away flag; broadcasts userChanged
/me <action> IRC-style action chat
/broadcast <msg> Server-wide popup (transID 355). Admin-only (.canBroadcast)
/topic [text] Read or set the public chat topic. Set is admin-only
/kick <socketID> Disconnect a target. Admin-only (.disconnectUsers)
/news clear flat|threaded|all Wipe news on the live server. Admin-only (.deleteNewsBundles)
/usershistory [hours] / /history User join/leave history for the last 1–24h (default 1h). Admin-only (.disconnectUsers)
/audit [--type …] [--user …] [--since Nh|Nd] [--limit N] Query the audit log (presence/transfers/auth/admin); /audit help for usage. Aliases /transfers, /authlog, /adminlog. Admin-only (.disconnectUsers)
/invisible / /visible Hide / re-show in peer rosters. Admin-only
/help List every command with one-line description

Single / prefix only — //foo and a bare / fall through as normal chat. Case-insensitive on the command head.

Tested deployment images

Image Status
swift:6.3.3-noble (Ubuntu 24.04) Builds + runs — the builder the shipped Dockerfile uses; runtime is plain ubuntu:noble with the Swift stdlib linked statically
swift:6.2-jammy (Ubuntu 22.04) Builds + runs
swift:6.2-noble (Ubuntu 24.04) Builds + runs
swift:6.0-jammy Too old — swift-log 1.12+ requires Swift 6.2

Architecture

HeidrunServer (lifecycle actor) binds the listener pair and owns the shared stores. Each accepted connection becomes a ClientSession actor that decodes Hotline packets via HeidrunCore and dispatches them across ClientSession+*.swift extensions (Admin, Files, PlainNews, ThreadedNews, PrivateChats, PrivateMessages, Banner, Misc). Replies are built with static PacketEncoder builders.

Wire types and codecs live in the shared SPM package franckjej/heidrun-protocol. Edits to the wire format happen there, not here.

For protocol details (encoding quirks, transaction IDs, HTXF framing, 1904-epoch timestamps) see AGENTS.md or the heidrun-protocol README.

License

GPL-2.0. Full text in LICENSE.

Dual licensing

Copyright © Daubit & Francke GmbH. The copyright holder reserves all rights to license this code under other terms — commercial, proprietary, BSD/MIT-style, or any other arrangement — for its own products and for third parties on request. The GPL-2.0 grant above governs public/community use; it does not bind the copyright holder's re-use of the same code under different terms.

For a non-GPL licence: jens.francke@daubit-francke.de.

Third-party

Built on Apple's Apache 2.0 Swift packages: swift-nio, swift-nio-ssl, swift-log, swift-crypto. Persistence via GRDB.swift (MIT). TOML parsing via TOMLKit (MIT).

Heritage

Heidrun is a Swift 6 reimplementation of the 2002 Hotline Mac client by Göran Granström, whose original plug-in modules were GPL-2.0. This server is a new ground-up implementation but shares the protocol heritage and the same licensing posture.

About

Hotline Protocol Server

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages