Download the PHP package innis/nostr-blossom without Composer

On this page you can find all versions of the php package innis/nostr-blossom. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package nostr-blossom

Nostr Blossom Package

CI

A PHP library implementing the Blossom (Blob Storage on Nostr) protocol — the BUD specifications — built with Clean Architecture principles, on top of innis/nostr-core.

Overview

Blossom is a small, sharply-scoped protocol: content-addressed blobs (SHA-256), kind-24242 authorisation events, and a handful of HTTP endpoints. This package provides the protocol layer only — the spec primitives and use cases — so a server, a client, or a CLI can build on Blossom without inheriting any particular storage backend, HTTP runtime, or framework.

Requirements

Installation

Quick Start

This is the protocol layer: a host implements the ports (storage, index, inspector, clock, …) and wires them into the BUD use cases. Every use case returns either its result value or a typed BlossomFailure, so a host maps a failure to its HTTP status without parsing messages — $error->category()->httpStatus().

For a complete, runnable walkthrough — in-memory ports wired into an authorised upload and a public read — see examples/blob_lifecycle.php (php examples/blob_lifecycle.php).

Handle an upload (BUD-02)

Serve a blob (BUD-01, public by hash)

Architecture

This package follows Clean Architecture with strict layer separation:

A host provides Infrastructure adapters for the ports plus a Presentation layer (HTTP routing, blob delivery); none of that lives here.

Value objects expose state through getX()/toX() accessors, never public properties (see ADR-0001).

Design rationale

The decisions that read like smells at the call site are recorded as immutable, numbered ADRs under ADR-0000.

Host responsibilities

Because this package is the protocol layer only, a few security- and trust-sensitive concerns are deliberately the host's to enforce in its port adapters. They are not omissions — they cannot be decided without the runtime (network, filesystem, framework) the package refuses to depend on.

Supported BUDs

BUD Description Support
BUD-01 Server requirements & GET/HAS One GetBlobUseCase resolves a blob to its descriptor and stored path; a host serves GET with the body and HEAD without it. Reads are public by hash by default, or gated to authenticated signers / tenants by a GetAccessPolicy, or to tenant-owned blobs by the TenantOwnedBlossomPolicy decorator
BUD-02 Upload Content-addressed upload; reads stay public by hash. (Upstream has since moved the delete and list endpoints into BUD-12 — see below)
BUD-04 Mirror Mirror-from-HttpUrl use case via the RemoteBlobFetcherInterface
BUD-05 Media optimisation Optimise-on-upload use case via the MediaOptimiserInterface, plus a CheckMediaUseCase for the HEAD /media pre-flight: it runs the optimiser-support, size, and x-tag guards on the client's declared X-Content-Length/X-Content-Type/X-SHA-256 (DeclaredBlob), judging the declared type by MediaOptimiserInterface::supports() rather than the storage allow-list — the same admission rule the PUT /media applies
BUD-06 Upload requirements Max size and allowed types exposed on UploadConstraints for a host to advertise, plus a CheckUploadUseCase for the HEAD /upload pre-flight: it runs the size, MIME, and x-tag guards on the client's declared X-Content-Length/X-Content-Type/X-SHA-256 (DeclaredBlob) through the same admission path the PUT uses, so the pre-flight and the PUT judge the declared values identically (the PUT can still reject when the detected content disagrees with the declaration)
BUD-08 Nostr File Metadata Tags nip94 tags on the descriptor, derived from the MediaMetadata a host's inspector supplies
BUD-09 Blob report Kind-1984 report validation and persistence via ReportBlobUseCase, which takes a raw event body (no kind-24242 Authorization header), checks the event names a blob, and verifies the event's own signature directly — it does not use BlossomAuthValidator or a BlossomPolicyInterface (ADR-0010)
BUD-11 Endpoint authorization Kind-24242 Authorization event parsing and validation in BlossomAuthValidator: kind, verb, created_at reasonableness (ADR-0015)
BUD-12 Delete & list Per-tenant-isolated delete (via BlobRemover, which removes the stored bytes only when no tenant still indexes the hash — see ADR-0011) and paginated list (since/until)

Authorisation

Authentication and authorisation are two separate seams, sequenced by the use case so the cheap check always gates the expensive one.

Authentication — BlossomAuthValidator. Blossom authorisation events are Nostr kind 24242 events carrying a t (verb), an expiration, and optionally x (blob hash) and server (domain) tags. The validator is pure authentication and knows nothing about tenants — it takes a ServerIdentity only to know its own domain for the server-tag scoping check. It splits into two calls:

Authorisation — one BlossomPolicyInterface. A single contract answers "may this actor perform this action on this blob" for every verb: allowUpload, allowMedia, allowList, allowDelete, and allowGet(?PublicKey, BlobHash) (see ADR-0009 for why one interface rather than a port per verb). The ready-made TenantBlossomPolicy admits only the configured tenants (a non-empty TenantPubkeys allow-list) for the write verbs, and its read behaviour is chosen by a GetAccessPolicy enum passed at construction — Public (reads are public by hash, the default and the BUD-01 norm), Authenticated (any valid signer), or Tenant (tenants only). Restricting a tenant to only the blobs it owns is the fourth rule, and because it is the one that needs a BlobIndexInterface, it is a separate decorator rather than an enum case: TenantOwnedBlossomPolicy wraps a Tenant-mode policy and adds the per-blob ownership check, so the index is a required constructor argument that cannot be omitted —

The split between the enum and the decorator is recorded in ADR-0008. A host that wants a different rule implements the one interface; there is no second authorisation abstraction to learn.

Ordering — every cheap check gates the expensive one. Every authenticated use case runs parse() → policy admission → any other request-bound checks (x-tag binding or scoping, declared-value guards) → verify() → act, so a request that fails any of those cheap checks never costs the server a secp256k1 operation. (The ingest paths' binding against the staged bytes' hash necessarily follows verification — that hash exists only once the bytes do.) Both validator calls return a union, so the type system makes a caller narrow before touching the event. The security trade-off admission-first accepts (a tenant-probe oracle on already-public pubkeys) is recorded in ADR-0014. Public reads still short-circuit before any parse or verification.

Binding a request to a specific blob is a separate step: requireAuthorisedBlob() returns a BlossomFailure unless the validated event carries a matching x tag (and null when it does), so a caller chains it after verify() like any other check. Every write path enforces this binding: BlobIngestor rejects an upload, mirror, or optimise whose auth event has no x tag matching the hash being stored (AuthorisationFailure::blobNotAuthorised), and DeleteBlobUseCase requires the same x tag for the hash being deleted. When ADR-0015).

BlossomVerb covers all five authenticated actions — upload, media, delete, list, and get. The get verb is only consulted when a host has configured a non-public GetAccessPolicy. Under the default public reads, GetBlobUseCase serves the blob without ever consulting the validator — an Authorization header, valid or not, is ignored rather than allowed to turn a public read into a 401; a header is parsed and verified only when the policy actually gates the read.

Error handling

The use cases split failures into two channels, so a host can map them to the right HTTP status without inspecting messages:

The reasoning behind these two channels — failures as returned values rather than exceptions, the absence of a BlossomException base, returning upstream/internal failures, the category-to-status mapping, and the four trust-boundary validation strategies — is recorded in ADR-0007.

Media metadata (BUD-08)

The three write paths — upload, mirror, and optimise — all funnel through one write pipeline: a BlobValidator verifies the blob (readable, within size, authorised, and — for whatever finally gets stored — an allowed type judged by detected content rather than the declared header) and yields a StorableBlob, which the BlobIngestor coordinator persists. The allow-list gates the stored bytes: on the optimise path the input is admitted by MediaOptimiserInterface::supports() and only the optimiser's output is checked against the allowed types, so a server can accept a format it will not store and normalise it into one it will. A host's BlobInspectorInterface returns an IncomingBlob; when that inspector also decodes the image it can attach a MediaMetadata (pixel dimensions and a blurhash). When present, the BlobDescriptorFactory folds those into the descriptor's NIP-94 nip94 tags, so the uploading client can lift ready-made dim/blurhash straight into its kind-1063 or imeta without re-processing the file. On the optimise path the descriptor also carries the pre-optimisation hash as ox. Hosts that store bytes without decoding them — and where no optimisation happened — leave MediaMetadata off, and the descriptor omits nip94. The write pipeline's shape (the BlobValidator / BlobDescriptorFactory / BlobIngestor split, the optimiser passed per-call, and the coordinator's ownership of the temp file) is recorded in ADR-0004.

Testing

License

MIT License. See LICENSE file for details.


All versions of nostr-blossom with dependencies

PHP Build Version
Package Version
Requires php Version ^8.4
innis/nostr-core Version ^0.8.3
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package innis/nostr-blossom contains the following files

Loading the files please wait ...