From 6fbc2e05da49625eacc1884d61071e96c182abdc Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 13 Jan 2026 19:48:31 -0800 Subject: [PATCH 1/6] M ove authorization to BUD-11 and clarify --- README.md | 15 ++++++----- buds/01.md | 59 ++++------------------------------------- buds/02.md | 28 ++++++++------------ buds/04.md | 21 ++++++++------- buds/05.md | 8 +++--- buds/06.md | 2 +- buds/11.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 117 insertions(+), 93 deletions(-) create mode 100644 buds/11.md diff --git a/README.md b/README.md index 45c35f8..a9012f2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🌸 Blossom - Blobs stored simply on mediaservers -Blossom uses [nostr](https://github.com/nostr-protocol/nostr) public / private keys for identities. Users are expected to sign authorization events to prove their identity when interacting with servers +Blossom uses [nostr](https://github.com/nostr-protocol/nostr) public / private keys for users identities. ## What is it? @@ -27,6 +27,7 @@ BUDs or **Blossom Upgrade Documents** are short documents that outline an additi - [BUD-08: Nostr File Metadata Tags](./buds/08.md) - [BUD-09: Blob Report](./buds/09.md) - [BUD-10: Blossom URI Schema](./buds/10.md) +- [BUD-11: Nostr Authorization](./buds/11.md) ## Endpoints @@ -35,26 +36,26 @@ Blossom Servers expose a few endpoints for managing blobs - `GET /` (optional file `.ext`) [BUD-01](./buds/01.md#get-sha256---get-blob) - `HEAD /` (optional file `.ext`) [BUD-01](./buds/01.md#head-sha256---has-blob) - `PUT /upload` [BUD-02](./buds/02.md#put-upload---upload-blob) - - `Authentication`: Signed [nostr event](./buds/02.md#upload-authorization-required) + - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#upload-authorization)) - Return a blob descriptor - `HEAD /upload` [BUD-06](./buds/06.md#head-upload---upload-requirements) - `GET /list/` [BUD-02](./buds/02.md#get-listpubkey---list-blobs-unrecommended) _(optional, unrecommended)_ - Returns an array of blob descriptors - - `Authentication` _(optional)_: Signed [nostr event](./buds/02.md#list-authorization-optional) + - `Authentication` _(optional)_: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#list-authorization)) - `DELETE /` [BUD-02](./buds/02.md#delete-sha256---delete-blob) - - `Authentication`: Signed [nostr event](./buds/02.md#delete-authorization-required) + - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#delete-authorization)) - `PUT /mirror` [BUD-04](./buds/04.md#put-mirror---mirror-blob) - - `Authentication`: Signed [nostr event](./buds/02.md#upload-authorization-required) + - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#upload-authorization)) - `HEAD /media` [BUD-05](./buds/05.md#head-media) - `PUT /media` [BUD-05](./buds/05.md#put-media) - - `Authentication`: Signed [nostr event](./buds/05.md#upload-authorization) + - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-05](./buds/05.md#upload-authorization)) - `PUT /report` [BUD-09](./buds/09.md) ## Event kinds | kind | description | BUD | | ------- | ------------------- | ------------------ | -| `24242` | Authorization event | [01](./buds/01.md) | +| `24242` | Authorization token | [11](./buds/11.md) | | `10063` | User Server List | [03](./buds/03.md) | ## License diff --git a/buds/01.md b/buds/01.md index 94243bf..641a367 100644 --- a/buds/01.md +++ b/buds/01.md @@ -20,55 +20,6 @@ The header `Access-Control-Max-Age: 86400` MAY be set to cache the results of a Every time a server sends an error response (HTTP status codes >=400), it may include a human-readable header `X-Reason` that can be displayed to the user. -## Authorization events - -Authorization events are used to identify the users to the server - -Authorization events must be generic and must NOT be scoped to specific servers. This allows pubkeys to sign a single event and interact the same way with multiple servers. - -Events MUST be kind `24242` and have a `t` tag with a verb of `get`, `upload`, `list`, or `delete` - -Events MUST have the `content` set to a human readable string explaining to the user what the events intended use is. For example `Upload Blob`, `Delete dog-picture.png`, `List Images`, etc - -All events MUST have a [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) `expiration` tag set to a unix timestamp at which the event should be considered expired. - -Authorization events MAY have multiple `x` tags for endpoints that require a sha256 hash. - -Example event: - -```jsonc -{ - "id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb", - "pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e", - "kind": 24242, - "content": "Upload bitcoin.pdf", - "created_at": 1708773959, - "tags": [ - ["t", "upload"], - // Authorization events MAY have multiple "x" tags. - ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], - ["expiration", "1708858680"] - ], - "sig": "d0d58c92afb3f4f1925120b99c39cffe77d93e82f488c5f8f482e8f97df75c5357175b5098c338661c37d1074b0a18ab5e75a9df08967bfb200930ec6a76562f" -} -``` - -Servers must perform the following checks in order to validate the event - -1. The `kind` must be `24242` -2. `created_at` must be in the past -3. The `expiration` tag must be set to a Unix timestamp in the future -4. The `t` tag must have a verb matching the intended action of the endpoint -5. Additional checks for specific endpoints. `/upload`, `/delete`, etc - -Using the `Authorization` HTTP header, the kind `24242` event MUST be base64 encoded and use the Authorization scheme Nostr - -Example HTTP Authorization header: - -``` -Authorization: Nostr eyJpZCI6IjhlY2JkY2RkNTMyOTIwMDEwNTUyNGExNDI4NzkxMzg4MWIzOWQxNDA5ZDhiOTBjY2RiNGI0M2Y4ZjBmYzlkMGMiLCJwdWJrZXkiOiI5ZjBjYzE3MDIzYjJjZjUwOWUwZjFkMzA1NzkzZDIwZTdjNzIyNzY5MjhmZDliZjg1NTM2ODg3YWM1NzBhMjgwIiwiY3JlYXRlZF9hdCI6MTcwODc3MTIyNywia2luZCI6MjQyNDIsInRhZ3MiOltbInQiLCJnZXQiXSxbImV4cGlyYXRpb24iLCIxNzA4ODU3NTQwIl1dLCJjb250ZW50IjoiR2V0IEJsb2JzIiwic2lnIjoiMDJmMGQyYWIyM2IwNDQ0NjI4NGIwNzFhOTVjOThjNjE2YjVlOGM3NWFmMDY2N2Y5NmNlMmIzMWM1M2UwN2I0MjFmOGVmYWRhYzZkOTBiYTc1NTFlMzA4NWJhN2M0ZjU2NzRmZWJkMTVlYjQ4NTFjZTM5MGI4MzI4MjJiNDcwZDIifQ== -``` - ## Endpoints All endpoints MUST be served from the root of the domain (eg. the `/upload` endpoint MUST be accessible from `https://cdn.example.com/upload`, etc). This allows clients to talk to servers interchangeably when uploading or retrieving blobs @@ -103,14 +54,14 @@ include a file extension in the URL that reflects the blob type (e.g. `.bin`, `. The server may optionally require authorization when retrieving blobs from the `GET /` endpoint -In this case, the server MUST perform additional checks on the authorization event +In this case, the server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then perform the following additional checks: 1. A `t` tag MUST be present and set to `get` -2. The event MUST contain either a `server` tag containing the full URL to the server or MUST contain at least one `x` tag matching the sha256 hash of the blob being retrieved +2. The authorization token MUST contain either a `server` tag (limiting the token to specific servers) or MUST contain at least one `x` tag matching the sha256 hash of the blob being retrieved (scoping the token to specific blob hashes). see [BUD-11](./11.md#tag-scoping). If the client did not send an `Authorization` header the server must respond with the appropriate HTTP status code `401` (Unauthorized) -Example event for retrieving a single blob: +Example authorization token for retrieving a single blob: ```json { @@ -128,7 +79,7 @@ Example event for retrieving a single blob: } ``` -Example event for retrieving multiple blobs from single server: +Example authorization token for retrieving multiple blobs from single server: ```json { @@ -140,7 +91,7 @@ Example event for retrieving multiple blobs from single server: "tags": [ ["t", "get"], ["expiration", "1708857340"], - ["server", "https://cdn.example.com/"] + ["server", "cdn.example.com"] ], "sig": "e402ade78e1714d40cd6bd3091bc5f4ada8e904e90301b5a2b9b5f0b6e95ce908d4f22b15e9fb86f8268a2131f8adbb3d1f0e7e7afd1ab0f4f08acb15822a999" } diff --git a/buds/02.md b/buds/02.md index c5711a5..86f21f8 100644 --- a/buds/02.md +++ b/buds/02.md @@ -53,12 +53,12 @@ servers may rely on the file extension to serve the blob correctly. ### Upload Authorization (Optional) -Servers MAY accept an authorization event when uploading blobs and SHOULD perform additional checks +Servers MAY require an authorization token when uploading blobs. The server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then perform the following additional checks: 1. The `t` tag MUST be set to `upload` -2. The authorization event MUST contain at least one `x` tag matching the sha256 hash of the body of the request +2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the body of the request. The `x` tag scopes the token to specific blob hashes (see [BUD-11](./11.md#tag-scoping)). -Example Authorization event: +Example authorization token: ```json { @@ -88,15 +88,13 @@ The endpoint MAY support `since` and `until` query parameters to filter the list Servers MAY reject a list request for any reason and MUST respond with the appropriate HTTP `4xx` status code and an error message explaining the reason for the rejection -### List Authorization (optional) +### List Authorization -The server MAY optionally require Authorization when listing blobs uploaded by the pubkey - -In this case the server MUST perform additional checks on the authorization event +The server MAY require a `list` authorization token when listing blobs uploaded by the pubkey. If a server requires authorization it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then it MUST perform the following additional checks: 1. The `t` tag MUST be set to `list` -Example Authorization event: +Example authorization token: ```json { @@ -119,20 +117,16 @@ Servers MUST accept `DELETE` requests to the `/` endpoint Servers MAY reject a delete request for any reason and SHOULD respond with the appropriate HTTP `4xx` status code and an error message explaining the reason for the rejection -### Delete Authorization (required) +### Delete Authorization -Servers MUST accept an authorization event when deleting blobs - -Servers SHOULD perform additional checks on the authorization event +Servers MAY require a `delete` authorization token when deleting blobs. If a server requires authorization it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: 1. The `t` tag MUST be set to `delete` -2. The authorization event MUST contain at least one `x` tag matching the sha256 hash of the blob being deleted +2. MUST contain at least one `x` tag matching the sha256 hash of the blob being deleted. -When multiple `x` tags are present on the authorization event the server MUST only delete the blob listed in the URL. +**Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.** -**Multiple `x` tags MUST NOT be interpreted as the user requesting a bulk delete.** - -Example Authorization event: +Example authorization token: ```json { diff --git a/buds/04.md b/buds/04.md index 67b013b..1bac797 100644 --- a/buds/04.md +++ b/buds/04.md @@ -19,12 +19,6 @@ Clients MUST pass the URL of the remote blob as a stringified JSON object in the } ``` -Clients MAY set the `Authorization` header to an upload authorization event defined in [BUD-02](./02.md#upload-authorization-optional). When using authorization, the event MUST be of type "upload". - -The `/mirror` endpoint MUST download the blob from the specified URL and verify that there is at least one `x` tag in the authorization event matching the sha256 hash of the download blob - -**Multiple `x` tags in the authorization event MUST NOT be interpreted as the user requesting to mirror multiple blobs.** - The endpoint MUST return a [Blob Descriptor](#blob-descriptor) and a `2xx` status code if the mirroring was successful or a `4xx` status code and error message if it was not. @@ -36,11 +30,20 @@ Servers MAY use the `Content-Length` header to determine the size of the blob. Servers MAY reject a mirror request for any reason and MUST respond with the appropriate HTTP `4xx` status code and an error message explaining the reason for the rejection. +### Upload Authorization + +Servers MAY require an `upload` authorization token when mirroring blobs. The server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: + +1. The `t` tag MUST be set to `upload` +2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the downloaded blob. The `x` tag scopes the token to specific blob hashes (see [BUD-11](./11.md#tag-scoping)). + +**Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to mirror multiple blobs.** + ## Example Flow -1. Client signs an `upload` authorization event and uploads blob to Server A +1. Client signs an `upload` authorization token and uploads blob to Server A 1. Server A returns a [Blob Descriptor](./02.md#blob-descriptor) with the `url` -1. Client sends the `url` to Server B `/mirror` using the original `upload` authorization event +1. Client sends the `url` to Server B `/mirror` using the original `upload` authorization token 1. Server B downloads the blob from Server A using the `url` -1. Server B verifies the downloaded blob hash matches the `x` tag in the authorization event +1. Server B verifies the downloaded blob hash matches the `x` tag in the authorization token 1. Server B returns a [Blob Descriptor](./02.md#blob-descriptor) diff --git a/buds/05.md b/buds/05.md index a7165eb..8948736 100644 --- a/buds/05.md +++ b/buds/05.md @@ -18,12 +18,10 @@ Servers MAY reject media uploads for any reason and should respond with the appr ### Upload Authorization -Servers MAY require a `media` [authorization event](./02.md#upload-authorization-required) to identify the uploader - -If a server requires a `media` authorization event it MUST perform the following checks +Servers MAY require a `media` authorization token to identify the uploader. If a server requires a `media` authorization token it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: 1. The `t` tag MUST be set to `media` -2. MUST contain at least one `x` tag matching the sha256 hash of the body of the request +2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the body of the request. ## HEAD /media @@ -45,4 +43,4 @@ Clients MAY let a user selected a "trusted processing" server for uploading imag Once a server has been selected, the client uploads the original media to the `/media` endpoint of the trusted server and get the optimized blob back -Then the client can ask the user to sign another `upload` authorization event for the new optimized blob and call the `/mirror` endpoint on other servers to distribute the blob +Then the client can ask the user to sign another `upload` authorization token for the new optimized blob and call the `/mirror` endpoint on other servers to distribute the blob diff --git a/buds/06.md b/buds/06.md index f3b9cbe..36fc259 100644 --- a/buds/06.md +++ b/buds/06.md @@ -18,7 +18,7 @@ The `HEAD /upload` endpoint MUST use the `X-SHA-256`, `X-Content-Type` and `X-Co ### Upload Authorization -The `HEAD /upload` endpoint MAY accept an `upload` authorization event using the `Authorization` header similar to what is used in the [`PUT /upload`](./02.md#upload-authorization-required) endpoint +The `HEAD /upload` endpoint MAY accept an `upload` authorization token using the `Authorization` header similar to what is used in the [`PUT /upload`](./02.md#upload-authorization) endpoint If the server requires authorization to upload it may respond with the `401` status code, or if authorization was provided and is invalid or not permitted it may respond with `403` status code diff --git a/buds/11.md b/buds/11.md new file mode 100644 index 0000000..39588f8 --- /dev/null +++ b/buds/11.md @@ -0,0 +1,77 @@ +# BUD-11 + +## Nostr Authorization + +`draft` `optional` + +Defines the authorization token format used by blossom servers to identify users. Authorization tokens are optional and servers MAY require them for various endpoints. + +## Authorization tokens + +Authorization tokens are signed nostr events proving to a server that the user (`pubkey`) has permitted an application to take an action on their behalf. + +The authorization token MUST be a nostr event of kind `24242` and have a `t` tag with a verb of `get`, `upload`, `list`, `delete`, or `media` + +Authorization tokens MUST have the `content` set to a human readable string explaining intended use. For example `Upload Blob`, `Delete old blobs`, `List Images`, etc + +All authorization tokens MUST have a [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) `expiration` tag set to a unix timestamp at which the token should be considered expired. + +## Tag scoping + +Authorization tokens MAY include `server` and `x` tags to scope the token to specific servers or blob hashes. + +- **`server` tag**: Limits the token to specific servers by domain name. If no `server` tags are present, the token is valid for all servers. Multiple `server` tags may be present to allow the token to be used on multiple servers. The value MUST be a domain name only (e.g., `cdn.example.com`), not a full URL. + +- **`x` tag**: Scopes the token to specific blob hashes (similar to how `server` scopes to servers). Multiple `x` tags may be present for endpoints that require a sha256 hash. When `x` tags are present, the token is only valid for operations on the specified blob hashes. + +Example authorization token: + +```jsonc +{ + "id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb", + "pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e", + "kind": 24242, + "content": "Upload bitcoin.pdf", + "created_at": 1708773959, + "tags": [ + ["t", "upload"], + // Authorization tokens MAY have multiple "x" tags. + ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], + ["expiration", "1708858680"] + ], + "sig": "d0d58c92afb3f4f1925120b99c39cffe77d93e82f488c5f8f482e8f97df75c5357175b5098c338661c37d1074b0a18ab5e75a9df08967bfb200930ec6a76562f" +} +``` + +## Base validation + +Servers must perform the following checks in order to validate the authorization token + +1. The `kind` must be `24242` +2. `created_at` must be in the past +3. The `expiration` tag must be set to a Unix timestamp in the future +4. The `t` tag must have a verb matching the intended action of the endpoint +5. If `server` tags are present, the server MUST verify that its domain name is present in at least one `server` tag. If no `server` tags are present, the token is valid for all servers. + +## HTTP Authorization header + +Using the `Authorization` HTTP header, the authorization token (kind `24242`) MUST be base64 encoded and use the Authorization scheme Nostr + +Example HTTP Authorization header: + +``` +Authorization: Nostr eyJpZCI6IjhlY2JkY2RkNTMyOTIwMDEwNTUyNGExNDI4NzkxMzg4MWIzOWQxNDA5ZDhiOTBjY2RiNGI0M2Y4ZjBmYzlkMGMiLCJwdWJrZXkiOiI5ZjBjYzE3MDIzYjJjZjUwOWUwZjFkMzA1NzkzZDIwZTdjNzIyNzY5MjhmZDliZjg1NTM2ODg3YWM1NzBhMjgwIiwiY3JlYXRlZF9hdCI6MTcwODc3MTIyNywia2luZCI6MjQyNDIsInRhZ3MiOltbInQiLCJnZXQiXSxbImV4cGlyYXRpb24iLCIxNzA4ODU3NTQwIl1dLCJjb250ZW50IjoiR2V0IEJsb2JzIiwic2lnIjoiMDJmMGQyYWIyM2IwNDQ0NjI4NGIwNzFhOTVjOThjNjE2YjVlOGM3NWFmMDY2N2Y5NmNlMmIzMWM1M2UwN2I0MjFmOGVmYWRhYzZkOTBiYTc1NTFlMzA4NWJhN2M0ZjU2NzRmZWJkMTVlYjQ4NTFjZTM5MGI4MzI4MjJiNDcwZDIifQ== +``` + +## Endpoint-specific requirements (example) + +Individual endpoints may extend the base validation with additional requirements. The following are examples of how endpoints use authorization tokens: + +- **`/upload`** ([BUD-02](./02.md#upload-authorization)): May requires at least one `x` tag matching the sha256 hash of the blob being uploaded +- **`DELETE /`** ([BUD-02](./02.md#delete-authorization)): May requires at least one `x` tag matching the sha256 hash of the blob being deleted +- **`PUT /media`** ([BUD-05](./05.md#upload-authorization)): May requires at least one `x` tag matching the sha256 hash of the media being uploaded +- **`GET /`** ([BUD-01](./01.md#get-authorization)): May require either a `server` tag or at least one `x` tag matching the sha256 hash of the blob being retrieved +- **`GET /list/`** ([BUD-02](./02.md#list-authorization)): May require a `server` tag limiting the token to specific servers +- **`PUT /mirror`** ([BUD-04](./04.md#put-mirror---mirror-blob)): May requires at least one `x` tag matching the sha256 hash of the blob being mirrored + +See the respective BUD documents for the exact requirements for each endpoint. All endpoints that accept authorization tokens MUST perform the base validation checks defined above before performing any endpoint-specific checks. From 5c060c5ee8344f2fa28ec77e9c2451c0526b92d5 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 24 Feb 2026 15:59:17 -0300 Subject: [PATCH 2/6] Clarify authorization token encoding in BUD-11 to specify Base64 URL-safe format without padding --- buds/11.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buds/11.md b/buds/11.md index 39588f8..3cc2392 100644 --- a/buds/11.md +++ b/buds/11.md @@ -55,7 +55,7 @@ Servers must perform the following checks in order to validate the authorization ## HTTP Authorization header -Using the `Authorization` HTTP header, the authorization token (kind `24242`) MUST be base64 encoded and use the Authorization scheme Nostr +Using the `Authorization` HTTP header, the authorization token (kind `24242`) MUST be encoded as Base64 URL-safe without padding (Base64url, as used by JWTs) and use the Authorization scheme Nostr Example HTTP Authorization header: From c273d9a1e7ba674f0590ed1de4af47825d13d634 Mon Sep 17 00:00:00 2001 From: pippellia-btc Date: Wed, 25 Feb 2026 13:09:23 +0100 Subject: [PATCH 3/6] moved endpoint specific definitions to BUD-11 so the logic is unified. --- buds/01.md | 50 +++------------------------------- buds/02.md | 69 +++-------------------------------------------- buds/04.md | 7 +---- buds/05.md | 5 +--- buds/06.md | 4 +-- buds/11.md | 79 +++++++++++++++++++++++++++++++----------------------- 6 files changed, 55 insertions(+), 159 deletions(-) diff --git a/buds/01.md b/buds/01.md index 641a367..77851fb 100644 --- a/buds/01.md +++ b/buds/01.md @@ -11,14 +11,13 @@ _All pubkeys MUST be in hex format_ Servers MUST set the `Access-Control-Allow-Origin: *` header on all responses to ensure compatibility with applications hosted on other domains. For [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests) (`OPTIONS`) requests, -servers MUST also set, at minimum, the `Access-Control-Allow-Headers: Authorization, *` and `Access-Control-Allow-Methods: GET, HEAD, PUT, -DELETE` headers. +servers MUST also set, at minimum, the `Access-Control-Allow-Headers: Authorization, *` and `Access-Control-Allow-Methods: GET, HEAD, PUT, DELETE` headers. The header `Access-Control-Max-Age: 86400` MAY be set to cache the results of a preflight request for 24 hours. ## Error responses -Every time a server sends an error response (HTTP status codes >=400), it may include a human-readable header `X-Reason` that can be displayed to the user. +Every time a server sends an error response (HTTP status codes >=400), it MAY include a human-readable header `X-Reason` that can be displayed to the user. ## Endpoints @@ -52,50 +51,7 @@ include a file extension in the URL that reflects the blob type (e.g. `.bin`, `. ### Get Authorization (optional) -The server may optionally require authorization when retrieving blobs from the `GET /` endpoint - -In this case, the server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then perform the following additional checks: - -1. A `t` tag MUST be present and set to `get` -2. The authorization token MUST contain either a `server` tag (limiting the token to specific servers) or MUST contain at least one `x` tag matching the sha256 hash of the blob being retrieved (scoping the token to specific blob hashes). see [BUD-11](./11.md#tag-scoping). - -If the client did not send an `Authorization` header the server must respond with the appropriate HTTP status code `401` (Unauthorized) - -Example authorization token for retrieving a single blob: - -```json -{ - "id": "06d4842b9d7f8bf72440471704de4efa9ef8f0348e366d097405573994f66294", - "pubkey": "ec0d11351457798907a3900fe465bfdc3b081be6efeb3d68c4d67774c0bc1f9a", - "kind": 24242, - "content": "Get bitcoin.pdf", - "created_at": 1708771927, - "tags": [ - ["t", "get"], - ["expiration", "1708857340"], - ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"] - ], - "sig": "22ecb5116ba143e4c3d6dc4b53d549aed6970ec455f6d25d145e0ad1fd7c0e26c465b2e92d5fdf699c7050fa43e6a41f087ef167208d4f06425f61548168fd7f" -} -``` - -Example authorization token for retrieving multiple blobs from single server: - -```json -{ - "id": "d9484f18533d5e36f000f902a45b15a7eecf5fbfcb046789756d57ea87115dc5", - "pubkey": "b5f07faa8d3529f03bd898a23dfb3257bab8d8f5490777c46076ff9647e205dc", - "kind": 24242, - "content": "Get blobs from example.com", - "created_at": 1708771927, - "tags": [ - ["t", "get"], - ["expiration", "1708857340"], - ["server", "cdn.example.com"] - ], - "sig": "e402ade78e1714d40cd6bd3091bc5f4ada8e904e90301b5a2b9b5f0b6e95ce908d4f22b15e9fb86f8268a2131f8adbb3d1f0e7e7afd1ab0f4f08acb15822a999" -} -``` +Servers MAY require authorization when retrieving blobs, as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ## HEAD /sha256 - Has Blob diff --git a/buds/02.md b/buds/02.md index 86f21f8..8046326 100644 --- a/buds/02.md +++ b/buds/02.md @@ -53,28 +53,7 @@ servers may rely on the file extension to serve the blob correctly. ### Upload Authorization (Optional) -Servers MAY require an authorization token when uploading blobs. The server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then perform the following additional checks: - -1. The `t` tag MUST be set to `upload` -2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the body of the request. The `x` tag scopes the token to specific blob hashes (see [BUD-11](./11.md#tag-scoping)). - -Example authorization token: - -```json -{ - "id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb", - "pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e", - "kind": 24242, - "content": "Upload bitcoin.pdf", - "created_at": 1708773959, - "tags": [ - ["t", "upload"], - ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], - ["expiration", "1708858680"] - ], - "sig": "d0d58c92afb3f4f1925120b99c39cffe77d93e82f488c5f8f482e8f97df75c5357175b5098c338661c37d1074b0a18ab5e75a9df08967bfb200930ec6a76562f" -} -``` +Servers MAY require authorization when uploading blobs, as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ## GET /list/pubkey - List Blobs (Unrecommended) @@ -90,26 +69,7 @@ Servers MAY reject a list request for any reason and MUST respond with the appro ### List Authorization -The server MAY require a `list` authorization token when listing blobs uploaded by the pubkey. If a server requires authorization it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then it MUST perform the following additional checks: - -1. The `t` tag MUST be set to `list` - -Example authorization token: - -```json -{ - "id": "cbb1cab9566355bfdf04e1f1fc1e655fe903ecc193e8a750092ee53beec2a0e8", - "pubkey": "a5fc3654296e6de3cda6ba3e8eba7224fac8b150fd035d66b4c3c1dc2888b8fc", - "kind": 24242, - "content": "List Blobs", - "created_at": 1708772350, - "tags": [ - ["t", "list"], - ["expiration", "1708858680"] - ], - "sig": "ff9c716f8de0f633738036472be553ce4b58dc71d423a0ef403f95f64ef28582ef82129b41d4d0ef64d2338eb4aeeb66dbc03f8b3a3ed405054ea8ecb14fa36c" -} -``` +Servers MAY require authorization when listing blobs. See [BUD-11](./11.md#endpoint-authorization-requirements) for the required action and implied blob hash. ## DELETE /sha256 - Delete Blob @@ -119,27 +79,4 @@ Servers MAY reject a delete request for any reason and SHOULD respond with the a ### Delete Authorization -Servers MAY require a `delete` authorization token when deleting blobs. If a server requires authorization it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: - -1. The `t` tag MUST be set to `delete` -2. MUST contain at least one `x` tag matching the sha256 hash of the blob being deleted. - -**Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.** - -Example authorization token: - -```json -{ - "id": "a92868bd8ea740706d931f5d205308eaa0e6698e5f8026a990e78ee34ce47fe8", - "pubkey": "ae0063dd2c81ec469f2291ac029a19f39268bfc40aea7ab4136d7a858c3a06de", - "kind": 24242, - "content": "Delete bitcoin.pdf", - "created_at": 1708774469, - "tags": [ - ["t", "delete"], - ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], - ["expiration", "1708858680"] - ], - "sig": "2ba9af680505583e3eb289a1624a08661a2f6fa2e5566a5ee0036333d517f965e0ffba7f5f7a57c2de37e00a2e85fd7999076468e52bdbcfad8abb76b37a94b0" -} -``` +Servers MAY require authorization when deleting blobs. **Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.** See [BUD-11](./11.md#endpoint-authorization-requirements) for the required action and implied blob hash. diff --git a/buds/04.md b/buds/04.md index 1bac797..572a9bd 100644 --- a/buds/04.md +++ b/buds/04.md @@ -32,12 +32,7 @@ Servers MAY reject a mirror request for any reason and MUST respond with the app ### Upload Authorization -Servers MAY require an `upload` authorization token when mirroring blobs. The server MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: - -1. The `t` tag MUST be set to `upload` -2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the downloaded blob. The `x` tag scopes the token to specific blob hashes (see [BUD-11](./11.md#tag-scoping)). - -**Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to mirror multiple blobs.** +Servers MAY require authorization when mirroring blobs as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ## Example Flow diff --git a/buds/05.md b/buds/05.md index 8948736..72cdabc 100644 --- a/buds/05.md +++ b/buds/05.md @@ -18,10 +18,7 @@ Servers MAY reject media uploads for any reason and should respond with the appr ### Upload Authorization -Servers MAY require a `media` authorization token to identify the uploader. If a server requires a `media` authorization token it MUST first perform the base validation checks defined in [BUD-11](./11.md#base-validation), then MUST perform the following additional checks: - -1. The `t` tag MUST be set to `media` -2. The authorization token MUST contain at least one `x` tag matching the sha256 hash of the body of the request. +Servers MAY require authorization when processing media as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ## HEAD /media diff --git a/buds/06.md b/buds/06.md index 36fc259..dfb7cc7 100644 --- a/buds/06.md +++ b/buds/06.md @@ -18,9 +18,7 @@ The `HEAD /upload` endpoint MUST use the `X-SHA-256`, `X-Content-Type` and `X-Co ### Upload Authorization -The `HEAD /upload` endpoint MAY accept an `upload` authorization token using the `Authorization` header similar to what is used in the [`PUT /upload`](./02.md#upload-authorization) endpoint - -If the server requires authorization to upload it may respond with the `401` status code, or if authorization was provided and is invalid or not permitted it may respond with `403` status code +Servers MAY require authorization for this endpoint as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ### Examples diff --git a/buds/11.md b/buds/11.md index 3cc2392..f75b06a 100644 --- a/buds/11.md +++ b/buds/11.md @@ -4,45 +4,57 @@ `draft` `optional` -Defines the authorization token format used by blossom servers to identify users. Authorization tokens are optional and servers MAY require them for various endpoints. +Defines the format of the authorization token used by Blossom servers to identify users and by users to authorize actions on those servers. Authorization tokens are optional; servers MAY require them for specific endpoints. ## Authorization tokens -Authorization tokens are signed nostr events proving to a server that the user (`pubkey`) has permitted an application to take an action on their behalf. +Authorization tokens are signed [nostr](https://github.com/nostr-protocol/nips/blob/master/01.md) events of kind `24242` proving to a server that the user (`pubkey`) has permitted an application to take an action on their behalf. -The authorization token MUST be a nostr event of kind `24242` and have a `t` tag with a verb of `get`, `upload`, `list`, `delete`, or `media` +All authorization tokens: -Authorization tokens MUST have the `content` set to a human readable string explaining intended use. For example `Upload Blob`, `Delete old blobs`, `List Images`, etc +- MUST have the `content` set to a human readable string explaining intended use to the user. For example `Upload Blob`, `Delete old blobs`, `List Images`, etc. -All authorization tokens MUST have a [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) `expiration` tag set to a unix timestamp at which the token should be considered expired. +- MUST have a [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) `expiration` tag set to a unix timestamp at which the token should be considered expired. + +- MUST have a `t` tag with a verb of `get`, `upload`, `list`, `delete`, or `media`. The value of the `t` tag MUST correspond to the action performed by the target endpoint, as defined in the section [Endpoint Authorization Requirements](#endpoint-authorization-requirements). ## Tag scoping Authorization tokens MAY include `server` and `x` tags to scope the token to specific servers or blob hashes. -- **`server` tag**: Limits the token to specific servers by domain name. If no `server` tags are present, the token is valid for all servers. Multiple `server` tags may be present to allow the token to be used on multiple servers. The value MUST be a domain name only (e.g., `cdn.example.com`), not a full URL. +- **`server` tag**: Limits the token to specific servers by domain name. If no `server` tags are present, the token is valid for all servers. Multiple `server` tags may be present to allow the token to be used on multiple servers. The value MUST be a lowercase domain name only (e.g., `cdn.example.com`), not a full URL. -- **`x` tag**: Scopes the token to specific blob hashes (similar to how `server` scopes to servers). Multiple `x` tags may be present for endpoints that require a sha256 hash. When `x` tags are present, the token is only valid for operations on the specified blob hashes. +- **`x` tag**: Scopes the token to specific lowercase hex-encoded blob hashes. Multiple `x` tags may be present for endpoints that require a sha256 hash. When `x` tags are present, the token is only valid for operations on the specified blob hashes. Example authorization token: ```jsonc { - "id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb", - "pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e", + "id": "7a1735c3852cf3f374edae4b2af2ee18e750e6dec583e19c4795d3b179af6d17", "kind": 24242, - "content": "Upload bitcoin.pdf", - "created_at": 1708773959, + "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "created_at": 1772019044, "tags": [ - ["t", "upload"], - // Authorization tokens MAY have multiple "x" tags. - ["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], - ["expiration", "1708858680"] + ["t","upload"], + ["expiration","1708858680"], + // Authorization token MAY have multiple "x" tags + ["x","b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"], ], - "sig": "d0d58c92afb3f4f1925120b99c39cffe77d93e82f488c5f8f482e8f97df75c5357175b5098c338661c37d1074b0a18ab5e75a9df08967bfb200930ec6a76562f" + "content": "", + "sig": "4b57c22b1797b109530ffe5d04cabac468b1a5942873a5141334ecbc77694fc968a1b941979ba13602fceb1dad8014ab6469c6ae9cef0b5668cc23ad1449e103" } ``` +## HTTP Authorization Header + +Using the `Authorization` HTTP header, the authorization token MUST be encoded as Base64 URL-safe without padding (Base64url, as used by JWTs) and use the Authorization scheme Nostr + +Example HTTP Authorization Header: + +``` +Authorization: Nostr ewogICJpZCI6ICI3YTE3MzVjMzg1MmNmM2YzNzRlZGFlNGIyYWYyZWUxOGU3NTBlNmRlYzU4M2UxOWM0Nzk1ZDNiMTc5YWY2ZDE3IiwKICAia2luZCI6IDI0MjQyLAogICJwdWJrZXkiOiAiNzliZTY2N2VmOWRjYmJhYzU1YTA2Mjk1Y2U4NzBiMDcwMjliZmNkYjJkY2UyOGQ5NTlmMjgxNWIxNmY4MTc5OCIsCiAgImNyZWF0ZWRfYXQiOiAxNzcyMDE5MDQ0LAogICJ0YWdzIjogWwogICAgWyJ0IiwidXBsb2FkIl0sCiAgICBbImV4cGlyYXRpb24iLCIxNzA4ODU4NjgwIl0sCiAgICAvLyBBdXRob3JpemF0aW9uIHRva2VuIE1BWSBoYXZlIG11bHRpcGxlICJ4IiB0YWdzCiAgICBbIngiLCJiMTY3NDE5MWE4OGVjNWNkZDczM2U0MjQwYTgxODAzMTA1ZGM0MTJkNmM2NzA4ZDUzYWI5NGZjMjQ4ZjRmNTUzIl0sCiAgXSwKICAiY29udGVudCI6ICIiLAogICJzaWciOiAiNGI1N2MyMmIxNzk3YjEwOTUzMGZmZTVkMDRjYWJhYzQ2OGIxYTU5NDI4NzNhNTE0MTMzNGVjYmM3NzY5NGZjOTY4YTFiOTQxOTc5YmExMzYwMmZjZWIxZGFkODAxNGFiNjQ2OWM2YWU5Y2VmMGI1NjY4Y2MyM2FkMTQ0OWUxMDMiCn0 +``` + ## Base validation Servers must perform the following checks in order to validate the authorization token @@ -51,27 +63,28 @@ Servers must perform the following checks in order to validate the authorization 2. `created_at` must be in the past 3. The `expiration` tag must be set to a Unix timestamp in the future 4. The `t` tag must have a verb matching the intended action of the endpoint -5. If `server` tags are present, the server MUST verify that its domain name is present in at least one `server` tag. If no `server` tags are present, the token is valid for all servers. +5. If `server` tags are present, the server MUST verify that its domain name is present in at least one `server` tag. -## HTTP Authorization header +## Endpoint Authorization Requirements -Using the `Authorization` HTTP header, the authorization token (kind `24242`) MUST be encoded as Base64 URL-safe without padding (Base64url, as used by JWTs) and use the Authorization scheme Nostr +The following table defines, for each endpoint, the required `t` tag action and the implied blob hash (if any). If an endpoint has an implied blob hash, the token MUST include at least one `x` tag whose value matches that hash. -Example HTTP Authorization header: +| Endpoint | Action | Implied blob hash | +| -------------------- | -------- | ------------------------------------------ | +| `GET /` | `get` | The `` in the URL | +| `HEAD /` | `get` | The `` in the URL | +| `PUT /upload` | `upload` | sha256 of the request body | +| `HEAD /upload` | `upload` | sha256 from the `X-SHA-256` request header | +| `DELETE /` | `delete` | The `` in the URL | +| `GET /list/` | `list` | — | +| `PUT /mirror` | `upload` | sha256 of the mirrored blob | +| `PUT /media` | `media` | sha256 of the request body | +| `HEAD /media` | `media` | sha256 from the `X-SHA-256` request header | -``` -Authorization: Nostr eyJpZCI6IjhlY2JkY2RkNTMyOTIwMDEwNTUyNGExNDI4NzkxMzg4MWIzOWQxNDA5ZDhiOTBjY2RiNGI0M2Y4ZjBmYzlkMGMiLCJwdWJrZXkiOiI5ZjBjYzE3MDIzYjJjZjUwOWUwZjFkMzA1NzkzZDIwZTdjNzIyNzY5MjhmZDliZjg1NTM2ODg3YWM1NzBhMjgwIiwiY3JlYXRlZF9hdCI6MTcwODc3MTIyNywia2luZCI6MjQyNDIsInRhZ3MiOltbInQiLCJnZXQiXSxbImV4cGlyYXRpb24iLCIxNzA4ODU3NTQwIl1dLCJjb250ZW50IjoiR2V0IEJsb2JzIiwic2lnIjoiMDJmMGQyYWIyM2IwNDQ0NjI4NGIwNzFhOTVjOThjNjE2YjVlOGM3NWFmMDY2N2Y5NmNlMmIzMWM1M2UwN2I0MjFmOGVmYWRhYzZkOTBiYTc1NTFlMzA4NWJhN2M0ZjU2NzRmZWJkMTVlYjQ4NTFjZTM5MGI4MzI4MjJiNDcwZDIifQ== -``` +## Security Considerations -## Endpoint-specific requirements (example) +### Unscoped Tokens -Individual endpoints may extend the base validation with additional requirements. The following are examples of how endpoints use authorization tokens: +A token that does not include a `server` tag is valid on any Blossom server that accepts it. If intercepted or leaked, such a token can be replayed against other servers for the duration of its validity (until its `expiration`). -- **`/upload`** ([BUD-02](./02.md#upload-authorization)): May requires at least one `x` tag matching the sha256 hash of the blob being uploaded -- **`DELETE /`** ([BUD-02](./02.md#delete-authorization)): May requires at least one `x` tag matching the sha256 hash of the blob being deleted -- **`PUT /media`** ([BUD-05](./05.md#upload-authorization)): May requires at least one `x` tag matching the sha256 hash of the media being uploaded -- **`GET /`** ([BUD-01](./01.md#get-authorization)): May require either a `server` tag or at least one `x` tag matching the sha256 hash of the blob being retrieved -- **`GET /list/`** ([BUD-02](./02.md#list-authorization)): May require a `server` tag limiting the token to specific servers -- **`PUT /mirror`** ([BUD-04](./04.md#put-mirror---mirror-blob)): May requires at least one `x` tag matching the sha256 hash of the blob being mirrored - -See the respective BUD documents for the exact requirements for each endpoint. All endpoints that accept authorization tokens MUST perform the base validation checks defined above before performing any endpoint-specific checks. +This risk is particularly significant for `delete` tokens. An unscoped `delete` token intercepted from one server can be reused to delete the same blob from any other server where it exists. From 2e958bf018ee0de1d961daa5ee02ea39e9602a45 Mon Sep 17 00:00:00 2001 From: pippellia-btc Date: Wed, 25 Feb 2026 15:17:06 +0100 Subject: [PATCH 4/6] specified the header "X-SHA-256" and its use in authorization in both /upload and /media. --- buds/02.md | 21 +++++++++------------ buds/05.md | 25 +++++++++++-------------- buds/06.md | 4 ++-- buds/11.md | 12 +++++++----- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/buds/02.md b/buds/02.md index 8046326..549fc35 100644 --- a/buds/02.md +++ b/buds/02.md @@ -20,7 +20,7 @@ A blob descriptor is a JSON object containing `url`, `sha256`, `size`, `type`, a Servers MUST include a file extension in the URL in the `url` field to allow clients to easily embed the URL in social posts or other content -Servers MAY include additional fields in the descriptor like `magnet`, `infohash`, or `ipfs` depending on other protocols they support +Servers MAY include additional fields in the descriptor like `magnet`, `infohash`, or `ipfs` depending on other protocols they support. Example: @@ -36,20 +36,17 @@ Example: ## PUT /upload - Upload Blob -The `PUT /upload` endpoint MUST accept binary data in the body of the request and MAY use the `Content-Type` and `Content-Length` headers to get the MIME type and size of the data +The `PUT /upload` endpoint MUST accept binary data in the request body. +The server MUST NOT modify the blob in any way and MUST compute the sha256 hash over the exact bytes received. This requirement ensures that users can re-upload blobs to other servers without discrepancies. -The endpoint MUST NOT modify the blob in any way and SHOULD return the exact same sha256 that was uploaded. This is critical to allow users to re-upload their blobs to new servers +Clients SHOULD include `Content-Type` and `Content-Length` headers specifying the MIME type and size of the data. Clients MAY provide an `X-SHA-256` header containing the lowercase hex-encoded sha256 of the request body. A server MAY use this value to enforce rejection policies or perform authorization checks prior to persisting the blob. -The endpoint MUST return a [Blob Descriptor](#blob-descriptor) if the upload was successful or an error object if it was not - -Servers MAY reject an upload for any reason and SHOULD respond with the appropriate HTTP `4xx` status code and an error message explaining the reason for the rejection +On success, the endpoint MUST respond with a `2xx` status code with a [Blob Descriptor](#blob-descriptor) in the response body. +On failure, the endpoint MUST return an appropriate `4xx` status code and an error message explaining the reason for the rejection. ### File extension normalization (Optional) -When storing blobs, servers MAY normalise the file extension to a standard format (e.g. `.pdf`, `.png`, etc.) based on -the MIME type of the blob. This can be especially useful when the `GET /` endpoint is redirected to an external -URL (see the [proxying and redirection section from BUD-01](./01.md#proxying-and-redirection-optional)), as external -servers may rely on the file extension to serve the blob correctly. +When storing blobs, servers MAY normalise the file extension to a standard format (e.g. `.pdf`, `.png`, etc.) based on the MIME type of the blob. This can be especially useful when the `GET /` endpoint is redirected to an external URL (see the [proxying and redirection section from BUD-01](./01.md#proxying-and-redirection-optional)), as external servers may rely on the file extension to serve the blob correctly. ### Upload Authorization (Optional) @@ -69,7 +66,7 @@ Servers MAY reject a list request for any reason and MUST respond with the appro ### List Authorization -Servers MAY require authorization when listing blobs. See [BUD-11](./11.md#endpoint-authorization-requirements) for the required action and implied blob hash. +Servers MAY require authorization when listing blobs as defined by [BUD-11](./11.md#endpoint-authorization-requirements). ## DELETE /sha256 - Delete Blob @@ -79,4 +76,4 @@ Servers MAY reject a delete request for any reason and SHOULD respond with the a ### Delete Authorization -Servers MAY require authorization when deleting blobs. **Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.** See [BUD-11](./11.md#endpoint-authorization-requirements) for the required action and implied blob hash. +Servers MAY require authorization when deleting blobs as defined by [BUD-11](./11.md#endpoint-authorization-requirements). **Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.** diff --git a/buds/05.md b/buds/05.md index 72cdabc..4e3647f 100644 --- a/buds/05.md +++ b/buds/05.md @@ -8,13 +8,13 @@ Defines the `PUT /media` endpoint for processing and optimizing media ## PUT /media -The `PUT /media` endpoint MUST accept binary data in the body of the request and MAY use the `Content-Type` and `Content-Length` headers to get the MIME type and size of the media +The `PUT /media` endpoint MUST accept binary data in the request body. +The server SHOULD perform any optimizations or conversions it deems necessary in order to make the media more suitable for distribution. -The server should preform any optimizations or conversions it deems necessary in order to make the media more suitable for distribution +Clients SHOULD include `Content-Type` and `Content-Length` headers specifying the MIME type and size of the data. Clients MAY provide an `X-SHA-256` header containing the lowercase hex-encoded sha256 of the request body. A server MAY use this value to enforce rejection policies or perform authorization checks prior to persisting the blob. -The endpoint MUST respond with a `2xx` status and a [blob descriptor](./02.md#blob-descriptor) of the new processed blob - -Servers MAY reject media uploads for any reason and should respond with the appropriate HTTP `4xx` status code and an error message explaining the reason for the rejection +On success, the endpoint MUST respond with a `2xx` status code with a [Blob Descriptor](#blob-descriptor) in the response body. +On failure, the endpoint MUST return an appropriate `4xx` status code and an error message explaining the reason for the rejection. ### Upload Authorization @@ -26,18 +26,15 @@ Servers MUST respond to `HEAD` requests on the `/media` endpoint in a similar wa ## Limitations -This endpoint is intentionally limited to optimizing a single blob with the goal of making it easier to distribute +The goal of this endpoint is to provide a simple "trusted" optimization endpoint clients can use to optimize media for distribution. +How the blob is optimized is the sole responsibility of the server and the client should have no say in what optimization process is used. -How the blob is optimized is the sole responsibility of the server and the client should have no say in what optimization process is used - -The goal of this endpoint is to provide a simple "trusted" optimization endpoint clients can use to optimize media for distribution - -If a longer optimization or transformation process is needed, or if the client needs to specify how a blob should be transformed. there are other tools and protocol that should be used. +If a longer optimization or transformation process is needed, or if the client needs to specify how a blob should be transformed, other protocols should be used. ## Client Implementation -Clients MAY let a user selected a "trusted processing" server for uploading images or short videos +Clients MAY let a user selected a "trusted processing" server for uploading images or short videos. -Once a server has been selected, the client uploads the original media to the `/media` endpoint of the trusted server and get the optimized blob back +Once a server has been selected, the client uploads the original media to the `/media` endpoint of the trusted server and get the optimized blob back. -Then the client can ask the user to sign another `upload` authorization token for the new optimized blob and call the `/mirror` endpoint on other servers to distribute the blob +Then the client can call the `/mirror` endpoint on other servers to distribute the blob. diff --git a/buds/06.md b/buds/06.md index dfb7cc7..691c0e9 100644 --- a/buds/06.md +++ b/buds/06.md @@ -8,11 +8,11 @@ Defines how clients can verify if the upload can be completed before sending the ## HEAD /upload - Upload requirements -The `HEAD /upload` endpoint MUST use the `X-SHA-256`, `X-Content-Type` and `X-Content-Length` headers sent by client to get the SHA-256 hash, MIME type and size of the blob that will be uploaded, returning a HTTP status code and a custom header `X-Reason` to indicate some human readable message about the upload requirements. +The `HEAD /upload` endpoint MUST use the `X-SHA-256`, `X-Content-Type` and `X-Content-Length` headers sent by client to get the sha256 hash, MIME type and size of the blob that will be uploaded, returning a HTTP status code and a custom header `X-Reason` to indicate some human readable message about the upload requirements. ### Headers -- `X-SHA-256`: A string that represents the blob's SHA-256 hash. +- `X-SHA-256`: A lowercase hex-encoded sha256 string that represents the blob's hash. - `X-Content-Length`: An integer that represents the blob size in bytes. - `X-Content-Type`: A string that specifies the blob's MIME type, like `application/pdf` or `image/png`. diff --git a/buds/11.md b/buds/11.md index f75b06a..bd98469 100644 --- a/buds/11.md +++ b/buds/11.md @@ -67,19 +67,21 @@ Servers must perform the following checks in order to validate the authorization ## Endpoint Authorization Requirements -The following table defines, for each endpoint, the required `t` tag action and the implied blob hash (if any). If an endpoint has an implied blob hash, the token MUST include at least one `x` tag whose value matches that hash. +The following table defines, for each endpoint, the required `t` tag action and the implied blob hash (if any). The token MUST include at least one `x` tag whose value matches the implied blob hash. +If an endpoint has an implied blob hash and it cannot be determined (e.g. missing `X-SHA-256` header), authorization MUST fail. + | Endpoint | Action | Implied blob hash | | -------------------- | -------- | ------------------------------------------ | | `GET /` | `get` | The `` in the URL | | `HEAD /` | `get` | The `` in the URL | -| `PUT /upload` | `upload` | sha256 of the request body | -| `HEAD /upload` | `upload` | sha256 from the `X-SHA-256` request header | +| `PUT /upload` | `upload` | `X-SHA-256` request header | +| `HEAD /upload` | `upload` | `X-SHA-256` request header | | `DELETE /` | `delete` | The `` in the URL | | `GET /list/` | `list` | — | | `PUT /mirror` | `upload` | sha256 of the mirrored blob | -| `PUT /media` | `media` | sha256 of the request body | -| `HEAD /media` | `media` | sha256 from the `X-SHA-256` request header | +| `PUT /media` | `media` | `X-SHA-256` request header | +| `HEAD /media` | `media` | `X-SHA-256` request header | ## Security Considerations From 4d2cc07a0175e694e51168969e9c22884fae8041 Mon Sep 17 00:00:00 2001 From: pippellia-btc Date: Wed, 25 Feb 2026 15:19:51 +0100 Subject: [PATCH 5/6] removed mentions to auth in README since there is now a specific BUD --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index a9012f2..23c4615 100644 --- a/README.md +++ b/README.md @@ -36,19 +36,12 @@ Blossom Servers expose a few endpoints for managing blobs - `GET /` (optional file `.ext`) [BUD-01](./buds/01.md#get-sha256---get-blob) - `HEAD /` (optional file `.ext`) [BUD-01](./buds/01.md#head-sha256---has-blob) - `PUT /upload` [BUD-02](./buds/02.md#put-upload---upload-blob) - - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#upload-authorization)) - - Return a blob descriptor - `HEAD /upload` [BUD-06](./buds/06.md#head-upload---upload-requirements) -- `GET /list/` [BUD-02](./buds/02.md#get-listpubkey---list-blobs-unrecommended) _(optional, unrecommended)_ - - Returns an array of blob descriptors - - `Authentication` _(optional)_: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#list-authorization)) +- `GET /list/` [BUD-02](./buds/02.md#get-listpubkey---list-blobs-unrecommended) _(unrecommended)_ - `DELETE /` [BUD-02](./buds/02.md#delete-sha256---delete-blob) - - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#delete-authorization)) - `PUT /mirror` [BUD-04](./buds/04.md#put-mirror---mirror-blob) - - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-02](./buds/02.md#upload-authorization)) - `HEAD /media` [BUD-05](./buds/05.md#head-media) - `PUT /media` [BUD-05](./buds/05.md#put-media) - - `Authentication`: Signed [nostr event](./buds/11.md) (see [BUD-05](./buds/05.md#upload-authorization)) - `PUT /report` [BUD-09](./buds/09.md) ## Event kinds From f82748e03b653415154c5c7ed46186e37a5fc730 Mon Sep 17 00:00:00 2001 From: pippellia-btc Date: Wed, 25 Feb 2026 15:44:17 +0100 Subject: [PATCH 6/6] unified validation logic, specified whether the "x" tag is required or optional in the bud-11 table --- buds/11.md | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/buds/11.md b/buds/11.md index bd98469..0dd60fc 100644 --- a/buds/11.md +++ b/buds/11.md @@ -55,33 +55,32 @@ Example HTTP Authorization Header: Authorization: Nostr ewogICJpZCI6ICI3YTE3MzVjMzg1MmNmM2YzNzRlZGFlNGIyYWYyZWUxOGU3NTBlNmRlYzU4M2UxOWM0Nzk1ZDNiMTc5YWY2ZDE3IiwKICAia2luZCI6IDI0MjQyLAogICJwdWJrZXkiOiAiNzliZTY2N2VmOWRjYmJhYzU1YTA2Mjk1Y2U4NzBiMDcwMjliZmNkYjJkY2UyOGQ5NTlmMjgxNWIxNmY4MTc5OCIsCiAgImNyZWF0ZWRfYXQiOiAxNzcyMDE5MDQ0LAogICJ0YWdzIjogWwogICAgWyJ0IiwidXBsb2FkIl0sCiAgICBbImV4cGlyYXRpb24iLCIxNzA4ODU4NjgwIl0sCiAgICAvLyBBdXRob3JpemF0aW9uIHRva2VuIE1BWSBoYXZlIG11bHRpcGxlICJ4IiB0YWdzCiAgICBbIngiLCJiMTY3NDE5MWE4OGVjNWNkZDczM2U0MjQwYTgxODAzMTA1ZGM0MTJkNmM2NzA4ZDUzYWI5NGZjMjQ4ZjRmNTUzIl0sCiAgXSwKICAiY29udGVudCI6ICIiLAogICJzaWciOiAiNGI1N2MyMmIxNzk3YjEwOTUzMGZmZTVkMDRjYWJhYzQ2OGIxYTU5NDI4NzNhNTE0MTMzNGVjYmM3NzY5NGZjOTY4YTFiOTQxOTc5YmExMzYwMmZjZWIxZGFkODAxNGFiNjQ2OWM2YWU5Y2VmMGI1NjY4Y2MyM2FkMTQ0OWUxMDMiCn0 ``` -## Base validation +## Validation -Servers must perform the following checks in order to validate the authorization token +To validate an authorization token, a server MUST perform the following checks: -1. The `kind` must be `24242` -2. `created_at` must be in the past -3. The `expiration` tag must be set to a Unix timestamp in the future -4. The `t` tag must have a verb matching the intended action of the endpoint -5. If `server` tags are present, the server MUST verify that its domain name is present in at least one `server` tag. +1. The event `kind` MUST be `24242`. +2. The `created_at` timestamp MUST be in the past. +3. An `expiration` tag MUST be present and set to a Unix timestamp in the future. +4. The `t` tag MUST contain a verb matching the intended action of the endpoint. +5. If one or more `server` tags are present, the server MUST verify that its domain name appears in at least one `server` tag. +6. If the endpoint requires `x` tags, the server MUST verify that at least one `x` tag matches the blob hash implied by the endpoint. ## Endpoint Authorization Requirements -The following table defines, for each endpoint, the required `t` tag action and the implied blob hash (if any). The token MUST include at least one `x` tag whose value matches the implied blob hash. -If an endpoint has an implied blob hash and it cannot be determined (e.g. missing `X-SHA-256` header), authorization MUST fail. +The table below defines, for each endpoint, the required `t` tag action, the implied blob hash (if any), and whether at least one matching `x` tag is required. - -| Endpoint | Action | Implied blob hash | -| -------------------- | -------- | ------------------------------------------ | -| `GET /` | `get` | The `` in the URL | -| `HEAD /` | `get` | The `` in the URL | -| `PUT /upload` | `upload` | `X-SHA-256` request header | -| `HEAD /upload` | `upload` | `X-SHA-256` request header | -| `DELETE /` | `delete` | The `` in the URL | -| `GET /list/` | `list` | — | -| `PUT /mirror` | `upload` | sha256 of the mirrored blob | -| `PUT /media` | `media` | `X-SHA-256` request header | -| `HEAD /media` | `media` | `X-SHA-256` request header | +| Endpoint | Required `t` | Implied Blob Hash | `x` Tag Requirement | +|----------------------|--------------|-------------------------------|---------------------| +| `GET /` | `get` | `` from the URL | optional | +| `HEAD /` | `get` | `` from the URL | optional | +| `PUT /upload` | `upload` | `X-SHA-256` request header | required | +| `HEAD /upload` | `upload` | `X-SHA-256` request header | required | +| `DELETE /` | `delete` | `` from the URL | required | +| `GET /list/` | `list` | — | not applicable | +| `PUT /mirror` | `upload` | SHA-256 of the mirrored blob | required | +| `PUT /media` | `media` | `X-SHA-256` request header | required | +| `HEAD /media` | `media` | `X-SHA-256` request header | required | ## Security Considerations