Skip to content

Port upstream owner deletions and admin console to fiatjaf.com/nostr - #4

Merged
deymosh merged 6 commits into
stagingfrom
feature/upstream-deletions-admin-console
Sep 30, 2026
Merged

deymosh merged 6 commits into
stagingfrom
feature/upstream-deletions-admin-console

Conversation

@deymosh

@deymosh deymosh commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

Brings upstream haven barrydeen#133 (owner deletions) and barrydeen#135 (admin console, notes browser, dashboard, ban list) onto our fiatjaf.com/nostr monorepo lineage, together with the library bump they needed.

  • chore(deps) bump fiatjaf.com/nostr to 2026-09-28 (blossom moved nipb0 → nipb7).
  • feat(deletions) the relay owner can delete any event on any of the four relays, and deleted events cannot come back through a re-publish or an import.
  • feat(admin) NIP-86 management API on every relay URI, the /admin console, per-relay notes browser, analytics dashboard with persisted history, blossom media management, and the kind 10084 ban list.
  • docs LMDB is the only engine (BadgerDB went away with the monorepo); README, .env.example and backup docs said otherwise.
  • fix(proxy) SOCKS5 transport uses DialContext (staticcheck failed on the deprecated Dial).
  • chore consistent file names: blossom_migration.go, events_scan*.go.

Adapted, not copied

Upstream still runs on go-nostr/khatru/eventstore, so several of its workarounds don't apply here and were dropped:

  • the lmdb CountEvents infinite-loop workaround: counts call db.CountEvents directly
  • the khatru "#e"/"#a" deletion filter bug does not exist in the monorepo; MustNotBeDeleted and the import checks stay because imports bypass the relay pipeline
  • the copied getExtension helper: replaced by the now-exported nipb7/blossom.GetExtension
  • blobIndexMaxLimit and the "quarter of MaxLimit" paging traps: the monorepo takes an explicit query limit

What it takes advantage of in the monorepo:

  • policies compose into the single OnEvent/OnRequest/RejectConnection hooks, and metrics wrap them
  • OverwriteRelayInformation applies console renames to NIP-11 without races
  • AllowDeleting carries the owner-deletion rule
  • blob deletes query the x tag index directly instead of walking every index entry

The NIP-86 dispatcher stays in haven rather than in khatru's RelayManagementAPI. nip86.DecodeRequest rejects unknown methods before the Generic hook runs, so the console's own methods could not be served. khatru also still answers auth failures with HTTP 200 and skips the kind and method tag checks. The new API supersedes our earlier ManagementAPI hooks (ban, allow, stats, icon).

Fixed on the way:

  • the per-relay event rate limiter was rebuilt on every event, so it never limited anything
  • tests now load testdata/test.env via testing.Testing(); upstream's file-ordering trick runs after config is loaded under go test

Testing

  • go vet, gofmt and golangci-lint: 0 issues
  • go test ./... passes with no local .env
  • upstream's test suite is ported, with the cursor-walk tests forced onto small pages, plus a new test for the tag-index blob delete

🤖 Generated with Claude Code

deymosh and others added 6 commits September 29, 2026 17:37
Pulls in three months of upstream library work, notably:

- blossom moved from nipb0/ to nipb7/ (pure rename, identical API) -
  the only code change needed for the bump
- websocket WriteWait deadlines: writes to stuck peers now time out
  instead of blocking a handler forever
- nil-subscription guards in the listener path
- NostrAddressesInTheText no longer flags npubs that are part of a URL
- eventstore/mmm stats cursor key fixed (8+2+4, not 8+4+4) and stops
  early once the cursor leaves the author's prefix
- new OverwriteSupportedMethods relay hook and assignmethod/
  unassignmethod NIP-86 methods

The lmdb CountEvents infinite-loop that upstream haven barrydeen#135 had to work
around does not exist in this lineage - the monorepo lmdb backend
already advances its cursor on every counting path.

go build and go vet are clean.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Port of upstream barrydeen#133 (Barry Deen), adapted from
nbd-wtf/go-nostr + fiatjaf/khatru to the fiatjaf.com/nostr monorepo.

The owner (OWNER_NPUB) can now delete any event stored on the relay
endpoint the request is sent to; authors keep deleting their own events
and everybody else is unaffected:

- OwnerCanDeleteAnyEvent is wired into AllowDeleting - the monorepo
  khatru hook that replaces the old OverwriteDeletionOutcome - on all
  four relays
- the tombstone is stored: the owner's kind 5 passes the chat-relay
  kind policy, the inbox whitelist-tag policy and the blanket AUTH
  requirement in MustNotBeBlacklistedToPost (the event already carries
  the owner's signature)
- deleted events don't come back: MustNotBeDeleted rejects a re-publish
  and the three import paths skip deleted events. The old khatru "#e"/"#a"
  filter bug this guarded against does not exist in the monorepo's
  handleDeleteRequest, but the import paths write to the databases
  directly and still need the check

Only delete requests signed by an event's author or by the owner count
as deletions, so nobody can tombstone an event the relay hasn't seen
yet and block it from ever being stored.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Port of upstream haven barrydeen#135 onto the fiatjaf.com/nostr monorepo.

Adds the NIP-86 management API on each of the four relay URIs, the /admin
console that drives it, a read-only notes browser per relay, an analytics
dashboard with persisted hourly history, blossom media management and the
kind 10084 ban list. State lives in management.json and metrics.json.

The NIP-86 dispatcher stays in haven rather than in khatru's
RelayManagementAPI: nip86.DecodeRequest rejects unknown methods before the
Generic hook runs, so the console's own methods could not be served, and
khatru still answers auth failures with HTTP 200, skips the kind and
method tag checks and reads the body unbounded. This replaces the earlier
ManagementAPI hooks, whose ban, allow, stats and icon methods it covers.

Adapted to the monorepo rather than copied:
- policies compose into the single OnEvent/OnRequest/RejectConnection
  functions, and metrics wrap those hooks instead of appending to slices
- the lmdb CountEvents infinite-loop workaround is gone; counts call
  db.CountEvents directly
- events are walked through the iter.Seq QueryEvents with an explicit page
  size, deleted by id, and looked up with a full-id check because the
  store indexes only the first eight bytes
- blob URLs use nipb7/blossom.GetExtension instead of a copied helper
- deleteBlobs queries the x tag index directly instead of walking every
  index entry
- the per-relay event rate limiter is built once per relay; built inside
  the hook it was a fresh bucket per event and never limited anything

Tests load their settings from testdata/test.env (chosen by
testing.Testing() in loadConfig), because config is loaded during package
variable initialisation, before any test file can seed the environment.

Co-Authored-By: Claude Code <noreply@anthropic.com>
BadgerDB support went away with the move to fiatjaf.com/nostr, whose
eventstore has no badger backend: newDBBackend opens LMDB whatever
DB_ENGINE says. The README, .env.example and backup docs still called
BadgerDB the default, which sent new installs looking for a setting that
does nothing. They now name LMDB as the only engine and point BadgerDB
users at backup and restore to move their notes across.

Co-Authored-By: Claude Code <noreply@anthropic.com>
http.Transport.Dial is deprecated and golangci-lint's staticcheck fails
on it. The x/net SOCKS5 dialer implements proxy.ContextDialer, so the
transport now uses DialContext and a dial is cancelled along with the
request that started it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
blossomMigration.go was the only camelCase file name in the package; it
is now blossom_migration.go, next to blossom.go. The event store walker
and its tests move from eventscan*.go to events_scan*.go so the notes
browser's files sort together with events.go. .env.example gains the
trailing newline it was missing. No code changes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@deymosh
deymosh merged commit ba03ecb into staging Sep 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant