File server Blossom

Hosting multimediale sul proprio hostname: upload indirizzati per contenuto, storage locale o compatibile S3 e autenticazione kind-24242 per il tuo relay Nostr.

Panoramica

nostrfy può fungere da server blob Blossom: i client caricano file indirizzati tramite il loro hash SHA-256, e il relay li restituisce. Come l’API REST, vive su un hostname dedicato sulla stessa porta.

Configurazione

toml
[blossom]
host = "media.example.com"          # obbligatorio — abilita la funzione
storage = "local"                   # "local" o "s3"
local_path = "./data/images"        # radice dello storage locale
max_upload_bytes = 20971520         # 20 MiB
min_free_bytes = 33554432           # rifiuta gli upload quando il disco ha poco spazio libero
restrict_uploads = false            # solo le pubkey nella allowlist possono caricare

# Per S3 / Cloudflare R2:
s3_endpoint = "https://<account>.r2.cloudflarestorage.com"
s3_region = "auto"
s3_bucket = "nostr-media"
s3_access_key = "..."
s3_secret_key = "..."

Indirizza media.example.com alla stessa porta nel tuo reverse proxy, poi riavvia. GET / su quell’host risponde con il documento informativo del server Blossom. Con storage = "s3" l’endpoint deve essere HTTPS a meno che l’host sia loopback (p. es. un MinIO locale per i test).

Layout dello storage

Entrambi i backend usano la gerarchia <npub1...>, indicizzata dallo SHA-256 del file:

  • local — file sotto <local_path>/<npub1...>/<sha256>
  • s3 / R2 — oggetti <npub1...>/<sha256> nel bucket configurato

I byte dei blob non toccano mai il database del relay — LMDB contiene solo la mappatura sha256 → proprietario e la allowlist degli upload.

Endpoint

MetodoPercorsoAuthDescrizione
GET/—Informazioni sul server Blossom
GET / HEAD/<sha256>[.ext]—Recupero / verifica di un blob (intervalli di byte, 206)
PUT/uploadkind 24242 (t=upload, x=sha256, expiration)Caricamento di un blob — 201 nuovo, 200 già esistente
HEAD/uploadkind 24242 (t=upload, x=sha256, expiration)Controllo preliminare BUD-06 — l’upload verrebbe accettato?
PUT/mediakind 24242 (t=media, x=sha256, expiration)Upload multimediale BUD-05 (memorizzato così com’è)
HEAD/mediakind 24242 (t=media, x=sha256, expiration)Controllo preliminare BUD-05 — l’upload verrebbe accettato?
GET/list/<pubkey>kind 24242 (t=list, expiration)Blob caricati dalla pubkey richiedente (cursore + limit)
DELETE/<sha256>kind 24242 (t=delete, x=sha256, expiration)Eliminazione di un blob (solo chi l’ha caricato)

Note di sicurezza

  • I byte caricati dagli utenti sono serviti con X-Content-Type-Options: nosniff.
  • HTML/SVG/XML/JavaScript ricevono inoltre Content-Disposition: attachment e una CSP sandbox, così l’origine multimediale non può essere usata per XSS persistente.
  • I token sono accettati sia nella forma base64url della specifica (senza padding) sia nella forma standard con padding (BUD-11).
  • L’header X-SHA-256 è verificato rispetto ai byte reali — una mancata corrispondenza restituisce 409.
  • I file sono serviti con ETag, Cache-Control: immutable e il content type memorizzato.
  • Una pubkey bannata con NIP-86 banpubkey è rifiutata su ogni endpoint.

Esempio

sh
# Info sul server
curl https://media.example.com/

# Upload (evento di autenticazione dal tuo client Blossom, ad es. tramite nak o l'helper blossom di nostr-tools)
curl -X PUT -H "Authorization: Nostr <auth>" -H "Content-Type: image/png" --data-binary @photo.png https://media.example.com/upload

# Recupero
curl https://media.example.com/<sha256>

# Elenca i tuoi upload (evento di autenticazione con t=list; la pubkey nel percorso deve essere la tua)
curl -H "Authorization: Nostr <auth>" https://media.example.com/list/<pubkey-hex>

# Elimina (evento di autenticazione con t=delete e x=<sha256>)
curl -X DELETE -H "Authorization: Nostr <auth>" https://media.example.com/<sha256>

Limitare gli upload

Imposta restrict_uploads = true nella sezione [blossom]:

toml
[blossom]
host = "media.example.com"
restrict_uploads = true

La allowlist vive nel database del relay (LMDB), gestita con comandi dedicati — nessun riavvio necessario, il demone ricarica automaticamente:

sh
nostrfy blossom allow npub1...          # autorizza una pubkey (npub1... o hex)
nostrfy blossom deny npub1...           # revoca una pubkey
nostrfy blossom list                    # mostra la lista e restrict_uploads

Gli upload da pubkey non in lista sono rifiutati con 403.

Backup e migrazione

Esegui il backup sia dello storage blob configurato sia di database.path per preservare l’inventario completo e lo stato di autorizzazione. La mappatura sha256 → proprietario è persistita in LMDB, quindi i riavvii sono istantanei e non servono indici in memoria né scansioni all’avvio — le ricerche leggono la mappatura direttamente dal database. Una migrazione automatica una tantum ricostruisce la mappatura dai blob legacy al primo avvio dopo un aggiornamento; un marcatore salta i riavvii successivi.