Serveur de fichiers Blossom

Hébergement média sur son propre nom d’hôte : téléversements adressés par contenu, stockage local ou compatible S3, et authentification kind-24242 pour votre relais Nostr.

Aperçu

nostrfy peut agir comme serveur de blobs Blossom : les clients téléversent des fichiers adressés par leur hachage SHA-256, et le relais les ressert. Comme l’API REST, il vit sur un nom d’hôte dédié sur le même port.

Configuration

toml
[blossom]
host = "media.example.com"          # requis — active la fonctionnalité
storage = "local"                   # "local" ou "s3"
local_path = "./data/images"        # racine du stockage local
max_upload_bytes = 20971520         # 20 MiB
min_free_bytes = 33554432           # refuse les téléversements quand l’espace disque libre est insuffisant
restrict_uploads = false            # seules les clés de la liste d’autorisation peuvent téléverser

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

Pointez media.example.com vers le même port dans votre proxy inverse, puis redémarrez. GET / sur cet hôte répond avec le document d’information du serveur Blossom. Avec storage = "s3", le point de terminaison doit être en HTTPS sauf si l’hôte est loopback (p. ex. un MinIO local pour les tests).

Organisation du stockage

Les deux backends utilisent la hiérarchie <npub1...>, indexée par le SHA-256 du fichier :

  • local — fichiers sous <local_path>/<npub1...>/<sha256>
  • s3 / R2 — objets <npub1...>/<sha256> dans le bucket configuré

Les octets des blobs ne touchent jamais la base de données du relais — LMDB ne contient que la correspondance sha256 → propriétaire et la liste d’autorisation de téléversement.

Points de terminaison

MéthodeCheminAuthDescription
GET/—Informations du serveur Blossom
GET / HEAD/<sha256>[.ext]—Récupérer / sonder un blob (plages d’octets, 206)
PUT/uploadkind 24242 (t=upload, x=sha256, expiration)Téléverser un blob — 201 nouveau, 200 existe déjà
HEAD/uploadkind 24242 (t=upload, x=sha256, expiration)Pré-vol BUD-06 — le téléversement serait-il accepté ?
PUT/mediakind 24242 (t=media, x=sha256, expiration)Téléversement média BUD-05 (stocké tel quel)
HEAD/mediakind 24242 (t=media, x=sha256, expiration)Pré-vol BUD-05 — le téléversement serait-il accepté ?
GET/list/<pubkey>kind 24242 (t=list, expiration)Blobs téléversés par la clé publique demanderesse (curseur + limit)
DELETE/<sha256>kind 24242 (t=delete, x=sha256, expiration)Supprimer un blob (téléverseur uniquement)

Notes de sécurité

  • Les octets téléversés par les utilisateurs sont servis avec X-Content-Type-Options: nosniff.
  • HTML/SVG/XML/JavaScript reçoivent en plus Content-Disposition: attachment et une CSP sandbox, de sorte que l’origine média ne peut pas servir au XSS stocké.
  • Les jetons sont acceptés sous la forme base64url de la spécification (sans padding) et sous la forme standard avec padding (BUD-11).
  • L’en-tête X-SHA-256 est vérifié par rapport aux octets réels — une discordance renvoie 409.
  • Les fichiers sont servis avec ETag, Cache-Control: immutable et le type de contenu stocké.
  • Une clé publique bannie via NIP-86 banpubkey est refusée sur chaque point de terminaison.

Exemple

sh
# Infos du serveur
curl https://media.example.com/

# Téléversement (événement d’authentification depuis votre client Blossom, par ex. via nak ou l’assistant blossom de nostr-tools)
curl -X PUT -H "Authorization: Nostr <auth>" -H "Content-Type: image/png" --data-binary @photo.png https://media.example.com/upload

# Récupération
curl https://media.example.com/<sha256>

# Listez vos propres téléversements (événement d’authentification avec t=list ; la clé du chemin doit être la vôtre)
curl -H "Authorization: Nostr <auth>" https://media.example.com/list/<pubkey-hex>

# Suppression (événement d’authentification avec t=delete et x=<sha256>)
curl -X DELETE -H "Authorization: Nostr <auth>" https://media.example.com/<sha256>

Restreindre les téléversements

Définissez restrict_uploads = true dans la section [blossom] :

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

La liste d’autorisation vit dans la base de données du relais (LMDB), gérée avec des commandes dédiées — aucun redémarrage requis, le démon recharge automatiquement :

sh
nostrfy blossom allow npub1...          # autorisez une clé (npub1... ou hex)
nostrfy blossom deny npub1...           # révoquez une clé
nostrfy blossom list                    # affichez la liste et restrict_uploads

Les téléversements des clés publiques non listées sont rejetés avec 403.

Sauvegardes et migration

Sauvegardez à la fois le stockage de blobs configuré et database.path pour préserver l’inventaire complet et l’état d’autorisation. La correspondance sha256 → propriétaire est persistée dans LMDB, donc les redémarrages sont instantanés et aucun index en mémoire ni balayage au démarrage n’est nécessaire — les recherches lisent la correspondance directement depuis la base de données. Une migration automatique unique reconstruit la correspondance à partir des blobs hérités au premier démarrage après une mise à niveau ; un marqueur ignore les redémarrages suivants.