Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -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?

Expand All @@ -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

Expand All @@ -35,26 +36,26 @@ Blossom Servers expose a few endpoints for managing blobs
- `GET /<sha256>` (optional file `.ext`) [BUD-01](./buds/01.md#get-sha256---get-blob)
- `HEAD /<sha256>` (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/<pubkey>` [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 /<sha256>` [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
Expand Down
59 changes: 5 additions & 54 deletions buds/01.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 /<sha256>` 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
{
Expand All @@ -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
{
Expand All @@ -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"
}
Expand Down
28 changes: 11 additions & 17 deletions buds/02.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand All @@ -119,20 +117,16 @@ Servers MUST accept `DELETE` requests to the `/<sha256>` 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)

Servers MUST accept an authorization event when deleting blobs
### Delete Authorization

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

When multiple `x` tags are present on the authorization event the server MUST only delete the blob listed in the URL.
2. MUST contain at least one `x` tag matching the sha256 hash of the blob being deleted.

**Multiple `x` tags MUST NOT be interpreted as the user requesting a bulk delete.**
**Multiple `x` tags in the authorization token MUST NOT be interpreted as the user requesting to delete multiple blobs.**

Example Authorization event:
Example authorization token:

```json
{
Expand Down
21 changes: 12 additions & 9 deletions buds/04.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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)
8 changes: 3 additions & 5 deletions buds/05.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
2 changes: 1 addition & 1 deletion buds/06.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading