Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,52 @@ RELAY_URL=ws://localhost:3000
# (use `just web` for Vite HMR instead).
# BUZZ_WEB_DIR=./web/dist

# -----------------------------------------------------------------------------
# Admin Dashboard (private moderation surface)
# -----------------------------------------------------------------------------
# Host name that serves the read-only moderation dashboard and its
# /api/admin/v1 endpoints. Leave unset to keep the admin surface absent.
# Setting it requires one of the two authentication variables below.
# BUZZ_ADMIN_HOST=admin.localhost:3000
#
# Authentication mode. Accepted values: token (default), disabled, nip98.
# Any other value is a startup error.
# BUZZ_ADMIN_AUTH=token
#
# Option A — BUZZ_ADMIN_AUTH=token (default when unset):
# Exactly 64 hex characters (32 bytes); generate with `openssl rand -hex 32`.
# `just admin` generates a throwaway one per run and prints it.
# BUZZ_ADMIN_TOKEN=<64 hex characters>
#
# Option B — BUZZ_ADMIN_AUTH=disabled (network-layer auth only):
# Set only when the admin API is already protected at the network layer
# (VPN, private ingress). The relay logs a WARN on every startup.
# BUZZ_ADMIN_TOKEN must NOT also be set.
#
# Option C — BUZZ_ADMIN_AUTH=nip98 (Nostr pubkey-based auth):
# NIP-98 HTTP Auth. Each request must carry an Authorization: Nostr header
# with a signed kind-27235 event. Authorized principals are resolved from:
# 1. RELAY_OPERATOR_PUBKEYS — comma-separated 64-char hex pubkeys (config Operators).
# 2. RELAY_OWNER_PUBKEY — implicit Operator fallback when RELAY_OPERATOR_PUBKEYS is unset.
# 3. relay_operators table — DB-managed Operator/Moderator roster.
# The dashboard requires a NIP-07 browser extension.
# Setting RELAY_OPERATOR_PUBKEYS for the admin console does NOT require
# RELAY_OPERATOR_API_ORIGIN; that origin is only for community provisioning
# (see below). When BUZZ_ADMIN_HOST is set, the relay advertises the admin
# origin in its NIP-11 document (`admin_api` field) so clients can auto-discover
# the console without manual URL entry.
# RELAY_OPERATOR_PUBKEYS=<64-char hex pubkey>[,<64-char hex pubkey>...]
#
# Directory holding the built dashboard assets (`pnpm -C admin-web build`).
# BUZZ_ADMIN_WEB_DIR=./admin-web/dist
#
# Canonical origin (http(s)://host[:port], no path) that community-provisioning
# NIP-98 requests are verified against. Required only to USE the provisioning
# endpoints (POST /operator/communities) — not for the admin console. When
# RELAY_OPERATOR_PUBKEYS is set but this is unset, the relay boots with a WARN
# and provisioning requests fail closed until it is set.
# RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000

# Shared Redis-backed admission limits. Defaults shown below; each value must
# be a positive integer.
# BUZZ_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=60
Expand Down
44 changes: 43 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
# Changelog

## Unreleased

- **Breaking:** the relay admin moderation API (`/api/admin/v1`) now requires
explicit authentication configuration when `BUZZ_ADMIN_HOST` is set. Choose
one mode via `BUZZ_ADMIN_AUTH` (unset defaults to `token`):
- **`BUZZ_ADMIN_AUTH=token` (default):** set `BUZZ_ADMIN_TOKEN` to exactly
64 hex characters (`openssl rand -hex 32`). Every request requires
`Authorization: Bearer`. The dashboard prompts for the token on first load.
- **`BUZZ_ADMIN_AUTH=disabled`:** admin API is unauthenticated. Use only when
the admin API is already protected by a VPN or private ingress. The relay
logs a `WARN` on every startup. The dashboard skips the token prompt.
- **`BUZZ_ADMIN_AUTH=nip98`:** NIP-98 HTTP Auth. Every request must carry an
`Authorization: Nostr <base64 event>` header containing a signed kind-27235
event. Authorized principals resolve from `RELAY_OPERATOR_PUBKEYS`
(comma-separated 64-char hex pubkeys for config-backed Operators),
`RELAY_OWNER_PUBKEY` (implicit Operator fallback when `RELAY_OPERATOR_PUBKEYS`
is unset), and the `relay_operators` table (DB-managed Operator/Moderator
roster). The dashboard requires a NIP-07 browser extension (nos2x or Alby);
without one it shows an installation screen. Individual operator access is
revocable without rotating a shared secret.
- Any unrecognised value for `BUZZ_ADMIN_AUTH` is a startup error
(typo-proofing). `BUZZ_ADMIN_TOKEN` set alongside `disabled` or `nip98` is
also a startup error.
- `Host`/`Origin` matching is retained in all modes as defense-in-depth.
- **Migration from the previous `BUZZ_ADMIN_INSECURE_NO_AUTH=true`:** replace
with `BUZZ_ADMIN_AUTH=disabled`. The behavior is identical.
- The relay NIP-11 relay-information document now advertises the admin API
origin in an optional `admin_api` field (`scheme://host[:port]`) whenever the
admin surface is configured (`BUZZ_ADMIN_HOST` set). The scheme follows the
same loopback rule as NIP-98 `u`-tag verification (`http` for
`localhost`/`127.x`/`[::1]`, else `https`). Clients can auto-discover the admin
console instead of requiring manual URL entry; the field is omitted entirely
when no admin surface is configured. IPv6 admin hosts must be bracketed
(`[::1]`, `[::1]:3000`); an unbracketed literal is a startup error because it
cannot form a valid URI authority.
- `RELAY_OPERATOR_API_ORIGIN` is no longer required at boot when
`RELAY_OPERATOR_PUBKEYS` is set. The allowlist is shared by the NIP-98 admin
console (which needs no origin) and the community-provisioning endpoints
(which do). Setting the pubkeys for the admin console no longer forces an
origin; the relay logs a `WARN` naming the affected feature, and the
community-provisioning endpoints (`POST /operator/communities`) fail closed
at request time until `RELAY_OPERATOR_API_ORIGIN` is set.

## v0.5.9

### Desktop and shared changes
Expand Down Expand Up @@ -52,7 +95,6 @@
- infra: bind development services to loopback ([#4871](https://github.com/block/buzz/pull/4871)) ([`65834d68d0d3441c4e628540d6d5c8b0a2e757c9`](https://github.com/block/buzz/commit/65834d68d0d3441c4e628540d6d5c8b0a2e757c9))

[Compare desktop-v0.5.7...desktop-v0.5.8](https://github.com/block/buzz/compare/desktop-v0.5.7...desktop-v0.5.8)

## v0.5.7

### Desktop and shared changes
Expand Down
6 changes: 5 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,11 @@ admin: bootstrap _ensure-migrations
pnpm -C admin-web build
export BUZZ_ADMIN_HOST="${BUZZ_ADMIN_HOST:-admin.localhost:3000}"
export BUZZ_ADMIN_WEB_DIR="${BUZZ_ADMIN_WEB_DIR:-{{justfile_directory()}}/admin-web/dist}"
# The relay refuses to start without a token, and never logs one. Mint a
# throwaway per run so no dev secret is ever committed or reused.
export BUZZ_ADMIN_TOKEN="${BUZZ_ADMIN_TOKEN:-$(openssl rand -hex 32)}"
echo "Admin dashboard: http://${BUZZ_ADMIN_HOST}/reports"
echo "Admin token (paste into dashboard prompt): ${BUZZ_ADMIN_TOKEN}"
cargo run -p buzz-relay

# Seed deterministic reports and product feedback for local admin dashboard review
Expand All @@ -429,7 +433,7 @@ admin-check: fmt-check
cargo test -p buzz-relay api::admin
cargo test -p buzz-relay router::tests
pnpm -C admin-web check
pnpm -C admin-web exec playwright test
pnpm -C admin-web test:e2e

# Start the relay server in release mode
relay-release: _ensure-migrations
Expand Down
Loading
Loading