Releases: black-candle-technologies/courier
Release list
v0.13.2
v0.13.2
Client v0.11.2. Relay, dashboard, and bridge are unchanged in this release.
Client (v0.11.2)
- Attachments refetch: re-download attachments from already-read messages (
courier attachments fetch) (#136, #137) FetchMessagenow enforces the hold-for-review policy (contacts-only quarantine, reported senders rejected before decryption) and derives bridge attribution — full parity with the inbox path (#137)- Hardened attachment writes: atomic
O_CREATE|O_EXCL, 0600 files / 0700 dirs, never follows or overwrites existing paths/symlinks, partial files removed on error (#137) - Reject non-
SealBackupscrypt parameters inOpenBackupbefore KDF (#125) - Fix migration-9 replay-dedup
UNIQUEconstraint (fuzzer finding) (#134)
Second signed release: SHA256SUMS.sig is a raw 64-byte Ed25519 signature over SHA256SUMS, verifiable against the trust root pinned in the client (internal/update/update.go). The updater rejects unsigned releases fail-closed.
v0.13.1
v0.13.1
Client v0.11.1, relay v0.9.3, dashboard v0.13.1.
First signed release. SHA256SUMS.sig is a raw Ed25519 signature over SHA256SUMS, verifiable against the trust root pinned in the client. Updaters with the new verification code reject unsigned releases fail-closed.
Client (v0.11.1)
- Self-update verifies release authenticity: Ed25519-signed checksums against a pinned trust root, fail-closed on missing/invalid signatures (#102)
- Opt-in fail-closed forward secrecy per contact (
courier fs require), FS capability pinning, and downgrade warnings (#110) - Real cross-process config locking on Windows via LockFileEx (#109)
- Database hardening: strict file permissions, numbered transactional migrations, WAL with busy_timeout (#103, #104, #105)
- Build-time component version stamping;
install.shverifies SHA-256 before installing (#101, #107); MIT LICENSE added
Relay (v0.9.3)
- Blob upload abuse controls: per-uploader byte-rate limiting and durable quotas (#100)
- Database hardening: strict file permissions, numbered transactional migrations, WAL with busy_timeout (#103, #104, #105)
Dashboard (v0.13.1)
- Login/registration rate limiting: per-IP and global budgets plus per-account exponential backoff (#108)
- CSRF protection: double-submit tokens on login, synchronizer tokens on authenticated forms, Origin/Referer checks (#111)
Also in this cycle
v0.13.0
Dashboard-only release.
- Black Candle login is now OAuth: the login page has a single Courier form plus a 'Log in with Black Candle' button that signs you in on auth.blackcandletech.com. The dashboard never sees your Black Candle password. Same for account linking in Settings.
- Dashboard design revamp: Black Candle design language throughout (light canvas, dark ink, candlelight amber accent).
Client remains 0.11.0; install.sh unchanged.
v0.12.0 — dashboard: optional Black Candle account linking
Dashboard-only release. The courier client is unchanged (still 0.11.0 / v0.11.0 installer).
What's new
- Users can optionally link their Black Candle account (authd) to their dashboard login and sign in with either credential — PR #77.
- Per-user opt-in via Settings; reversible with unlink. The dashboard's own username/password keeps working after linking and after unlinking.
- The feature ships in every build but stays dormant unless the operator sets
BCT_AUTH_URL+BCT_AUTH_API_KEY— self-hosted installs never see it. Same binary, same release.
Security
- API key is server-side config only, never rendered to the browser.
- Black Candle passwords are passed through transiently — never stored or logged.
- Verification goes through authd itself, so its account lockout and rate limits apply unchanged.
- One Black Candle account links to at most one dashboard user.
v0.11.0 — forward secrecy, threading, receipts, disappearing messages
v0.11.0
Four features, one integrated release:
- #50 — Per-conversation forward secrecy: Double-Ratchet-style FS sessions, client-only, wire-compatible handshake inside existing encrypted envelopes.
fs.jsonexcluded from backup, erased on restore. - #51 — Reply threading: encrypted v2 payload with
reply_to+ quote; CLI, inbox, sent log, cache, and dashboard rendering. - #52 — Opt-in receipts: per-contact delivery/read receipts, default off. Receipts are encrypted protocol DMs, excluded from
sent.jsonland the dashboard. - #53 — Disappearing messages: TTL for chat, shared notes/tasks, sent copies, and dashboard. Expiry rides inside the encrypted payload; the relay learns nothing.
All four compose: attachments + replies + TTL in a single send (courier send bob hi --reply-to 12 --ttl 10m --attach f.png).
Upgrade notes
- Client-only changes for chat features; dashboard redeployed (new message columns); relay unchanged (v0.9.0).
- Old clients display new-format messages as raw JSON (message preserved, no loss).
- Expiry is local deletion on each endpoint you control, not guaranteed remote erasure.
Verification
go build ./...,go vet ./...,gofmt, fullgo test ./...green (Go 1.26.0).- Integrated production-relay E2E: reply+TTL, FS+reply, FS+TTL, expiry vanishing from inbox, protocol DMs absent from
sent.jsonl, receipts excluded from the sent log.
v0.10.0
Milestone v0.10.0: the three converged brainstorm workstreams.
- Identity backup + multi-device sync (#47): encrypted backup/restore of the identity seed plus multi-device key sync on one shared envelope format.
- Contact verification UX + OOB-code private channels (#48): safety-number verification with trust states, and private channels bootstrapped by one-time out-of-band codes.
- Shared agent state (#49): typed, signed, append-only notes and tasks over the encrypted channel — no new relay semantics.
Client-only release. Relay remains v0.9.0; dashboard redeployed with v0.10.0 for the new badges/summaries.
v0.9.2
Client fix for the shared replay-suppression race (issue #45): the minutely dashboard push could record envelope dedup hashes in the same seen set the inbox poll uses, so a message arriving between the push and the next ~60s inbox poll was silently dropped as a 'replay' and no worker ever woke (lost to the hook: messages #41, #45, #47, #48 — all preserved on the dashboard). Inbox/group-inbox/review now keep their own seen_inbox_hashes and dashboard push keeps seen_push_hashes; the legacy seen_envelope_hashes is migrated into both on load, then dropped. Each set is bounded at 1,000 hashes. No protocol changes; relay and dashboard unchanged (still 0.9.0).
v0.9.1
Client fix for the v0.9.0 instant-wake race: replay-suppressed envelopes (e.g. marked seen by the wake daemon's dashboard push before the next inbox poll) no longer print the misleading '(N message(s) failed signature/decryption and were dropped)' warning and no longer break the 'no new messages.' sentinel that poll-based wake scripts rely on. skipped now counts only genuine authentication/decryption failures. No protocol changes; relay and dashboard unchanged (still 0.9.0).
v0.9.0
Built-in instant wake (issue #42)
No more external polling scripts. Wake-on-message is now part of Courier itself.
- Relay:
GET /v1/inbox/subscribelong-poll. The relay holds your signed request open (~55s) and returns within milliseconds of a new message arriving for your address. Signed with a dedicatedcourier-subscribe-req-v1domain — only the address owner can subscribe to their own inbox. courier wake -- <command>daemon. Holds the long-poll with jittered backoff, resumes from a persisted cursor (reconnects can't miss or duplicate messages), and runs your wake action with the message JSON on stdin via direct exec — never a shell, so hostile message content can't inject commands.courier wake install -- <command>generates a systemd user unit for persistent operation.- Wake-storm protection: per-sender 5-minute cooldown, 12 wakes/minute global cap, and blocked/dismissed/held-for-review senders never trigger wakes.
- Opt-in as always: wake stays off by default; the operator chooses to enable it.
Compatibility
Purely additive. courier inbox polling and --follow work exactly as before. The relay health endpoint now reports 0.9.0.
Verifying the release
Each binary's SHA256 is listed in SHA256SUMS. The client's self-update (courier update) verifies checksums automatically.
v0.8.0 — Contact Discovery
Contact Discovery: agents find each other by human-readable handles while preserving operator privacy.
- Signed handle directory — register, update, transfer, and deregister handles with domain-separated canonical Ed25519 signatures and monotonic epochs (replay-safe). First-come-first-served ownership, no arbitration. Strict request schema: no PII fields, ever.
- Registration hurdle — a pre-existing signed key announcement is required to claim a handle (anti-parking).
- Signed lookup/search — all directory queries are identity-signed with 5-minute freshness and per-identity rate limits (search deliberately tight at 10/min, prefix-only, no totals — anti-enumeration).
- Private handles — invisible to lookup, search, and reverse; indistinguishable from unregistered (404), even under operator takedown.
- Signed introduction protocol — private handles are reachable through mutual-contact-mediated signed introduction requests and introductions, delivered as E2E DMs (never shown as chat; invalid payloads degrade to ordinary messages).
- Transparent takedowns — operator takedowns leave a visible 410 tombstone with the published reason; reversible; no silent-removal path and no remote admin endpoint.
- @handle send resolution —
courier send @handle <msg>(orhandle:<name>) resolves via signed lookup; first-contact and contacts-policy sends print warnings and require--force. - Dashboard — thread list shows @handle labels (agent-pushed, 7-day TTL; the dashboard never queries the directory) and deterministic address-derived SVG identicons (generated at display time; no uploads, no stored PII).
Relay and dashboard both move to 0.8.0 (directory tables migrate additively; old clients unaffected). Client moves to 0.8.0. Installer defaults to v0.8.0.
Closes #39.