mirror of
https://github.com/hzrd149/blossom.git
synced 2025-12-09 07:08:50 +00:00
Compare commits
46 Commits
1d855e1633
...
multi-part
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edb095118a | ||
|
|
60e9f287fe | ||
|
|
782d382ca7 | ||
|
|
6105ea6a6f | ||
|
|
a3546a5bc3 | ||
|
|
9d8b3cb677 | ||
|
|
b29ada0e11 | ||
|
|
9832ac4582 | ||
|
|
d5225114af | ||
|
|
55781b0125 | ||
|
|
eaa37c348d | ||
|
|
52abe4467a | ||
|
|
8487a70a22 | ||
|
|
9e468f8749 | ||
|
|
72d5c1690a | ||
|
|
287b32b531 | ||
|
|
4e6e322aa3 | ||
|
|
fa676debf3 | ||
|
|
e5462c3e1a | ||
|
|
7a9111f54d | ||
|
|
29cbfbf504 | ||
|
|
995f715c96 | ||
|
|
550d8693e0 | ||
|
|
b50a5374b3 | ||
|
|
c195efdf30 | ||
|
|
8b5d740aa4 | ||
|
|
db49443b1f | ||
|
|
a91360634f | ||
|
|
c99b4898f5 | ||
|
|
1a44035b7d | ||
|
|
ec40af6b95 | ||
|
|
13fa0f485d | ||
|
|
34a50d09f5 | ||
|
|
36a741a87b | ||
|
|
c5d90aa74d | ||
|
|
2d7e013b47 | ||
|
|
854218f573 | ||
|
|
bafed19c7f | ||
|
|
37f6255e4e | ||
|
|
afa1290a6a | ||
|
|
b7e4e96ed5 | ||
|
|
ee1fca7ef5 | ||
|
|
c746be27e3 | ||
|
|
81bd6f856f | ||
|
|
85f5b57245 | ||
|
|
73461b47b2 |
10
README.md
10
README.md
@@ -12,7 +12,7 @@ Blobs are packs of binary data addressed by their sha256 hash
|
|||||||
|
|
||||||
## How does it work?
|
## How does it work?
|
||||||
|
|
||||||
Blossom Servers expose four endpoints for managing blobs
|
Blossom Servers expose a few endpoints for managing blobs
|
||||||
|
|
||||||
- `GET /<sha256>` (optional file `.ext`) [BUD-01](./buds/01.md#get-sha256---get-blob)
|
- `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)
|
- `HEAD /<sha256>` (optional file `.ext`) [BUD-01](./buds/01.md#head-sha256---has-blob)
|
||||||
@@ -27,6 +27,10 @@ Blossom Servers expose four endpoints for managing blobs
|
|||||||
- `Authentication`: Signed [nostr event](./buds/02.md#delete-authorization-required)
|
- `Authentication`: Signed [nostr event](./buds/02.md#delete-authorization-required)
|
||||||
- `PUT /mirror` [BUD-04](./buds/04.md#put-mirror---mirror-blob)
|
- `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/02.md#upload-authorization-required)
|
||||||
|
- `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)
|
||||||
|
- `PUT /report` [BUD-09](./buds/09.md)
|
||||||
|
|
||||||
## Protocol specification (BUDs)
|
## Protocol specification (BUDs)
|
||||||
|
|
||||||
@@ -40,9 +44,10 @@ See the [BUDs](./buds) folder and specifically [BUD-01](./buds/01.md) and [BUD-0
|
|||||||
- [BUD-02: Blob upload and management](./buds/02.md)
|
- [BUD-02: Blob upload and management](./buds/02.md)
|
||||||
- [BUD-03: User Server List](./buds/03.md)
|
- [BUD-03: User Server List](./buds/03.md)
|
||||||
- [BUD-04: Mirroring blobs](./buds/04.md)
|
- [BUD-04: Mirroring blobs](./buds/04.md)
|
||||||
|
- [BUD-05: Media optimization](./buds/05.md)
|
||||||
- [BUD-06: Upload requirements](./buds/06.md)
|
- [BUD-06: Upload requirements](./buds/06.md)
|
||||||
- [BUD-08: Nostr File Metadata Tags](./buds/08.md)
|
- [BUD-08: Nostr File Metadata Tags](./buds/08.md)
|
||||||
- [BUD-10: Chunked blobs](./buds/10.md)
|
- [BUD-09: Blob Report](./buds/09.md)
|
||||||
|
|
||||||
## Event kinds
|
## Event kinds
|
||||||
|
|
||||||
@@ -50,7 +55,6 @@ See the [BUDs](./buds) folder and specifically [BUD-01](./buds/01.md) and [BUD-0
|
|||||||
| ------- | ------------------- | ------------------ |
|
| ------- | ------------------- | ------------------ |
|
||||||
| `24242` | Authorization event | [01](./buds/01.md) |
|
| `24242` | Authorization event | [01](./buds/01.md) |
|
||||||
| `10063` | User Server List | [03](./buds/03.md) |
|
| `10063` | User Server List | [03](./buds/03.md) |
|
||||||
| `2001` | Merkle tree | [10](./buds/10.md) |
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
42
buds/01.md
42
buds/01.md
@@ -16,6 +16,10 @@ DELETE` headers.
|
|||||||
|
|
||||||
The header `Access-Control-Max-Age: 86400` MAY be set to cache the results of a preflight request for 24 hours.
|
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.
|
||||||
|
|
||||||
## Authorization events
|
## Authorization events
|
||||||
|
|
||||||
Authorization events are used to identify the users to the server
|
Authorization events are used to identify the users to the server
|
||||||
@@ -32,7 +36,7 @@ Authorization events MAY have multiple `x` tags for endpoints that require a sha
|
|||||||
|
|
||||||
Example event:
|
Example event:
|
||||||
|
|
||||||
```json
|
```jsonc
|
||||||
{
|
{
|
||||||
"id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb",
|
"id": "bb653c815da18c089f3124b41c4b5ec072a40b87ca0f50bbbc6ecde9aca442eb",
|
||||||
"pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e",
|
"pubkey": "b53185b9f27962ebdf76b8a9b0a84cd8b27f9f3d4abd59f715788a3bf9e7f75e",
|
||||||
@@ -41,7 +45,7 @@ Example event:
|
|||||||
"created_at": 1708773959,
|
"created_at": 1708773959,
|
||||||
"tags": [
|
"tags": [
|
||||||
["t", "upload"],
|
["t", "upload"],
|
||||||
// Authorization events MAY have multiple "x" tags
|
// Authorization events MAY have multiple "x" tags.
|
||||||
["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"],
|
["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"],
|
||||||
["expiration", "1708858680"]
|
["expiration", "1708858680"]
|
||||||
],
|
],
|
||||||
@@ -67,42 +71,22 @@ Authorization: Nostr eyJpZCI6IjhlY2JkY2RkNTMyOTIwMDEwNTUyNGExNDI4NzkxMzg4MWIzOWQ
|
|||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
All endpoints MUST be served from the root path (eg. `https://cdn.example.com/upload`, etc). This allows clients to talk to servers interchangeably when uploading or retrieving blobs
|
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
|
||||||
|
|
||||||
## Error Responses
|
|
||||||
|
|
||||||
For HTTP `4xx` and `5xx` status codes servers MUST repond with `Content-Type: application/json` and a JSON object containing `message`
|
|
||||||
|
|
||||||
The `message` field MUST be human readable and should explain the reason for the error. Optionally servers may include other fields for the client with more information about the error
|
|
||||||
|
|
||||||
Example Error response:
|
|
||||||
|
|
||||||
```
|
|
||||||
HTTP/2 401
|
|
||||||
content-type: application/json; charset=utf-8
|
|
||||||
content-length: 32
|
|
||||||
access-control-allow-origin: *
|
|
||||||
access-control-expose-headers: *
|
|
||||||
access-control-allow-headers: authorization,*
|
|
||||||
access-control-allow-methods: get, put, delete
|
|
||||||
|
|
||||||
{"message":"Missing Auth event"}
|
|
||||||
```
|
|
||||||
|
|
||||||
## GET /sha256 - Get Blob
|
## GET /sha256 - Get Blob
|
||||||
|
|
||||||
The `GET /<sha256>` endpoint MUST return the contents of the blob with the `Content-Type` header set to the appropriate MIME type
|
The `GET /<sha256>` endpoint MUST return the contents of the blob with the `Content-Type` header set to the appropriate MIME-type
|
||||||
|
|
||||||
The endpoint MUST accept an optional file extension in the URL. ie. `.pdf`, `.png`, etc
|
The endpoint MUST accept an optional file extension in the URL. ie. `.pdf`, `.png`, etc
|
||||||
|
|
||||||
If the endpoints returns a 301 or 302 redirect it MUST redirect to a URL containing the same sha256 hash as requested blob.
|
If the endpoints returns a 301 or 302 redirect it MUST redirect to a URL containing the same sha256 hash as the requested blob.
|
||||||
This ensures that if a user was to copy or reuse the redirect URL it would still contain the original sha256 hash
|
This ensures that if a user was to copy or reuse the redirect URL it would still contain the original sha256 hash
|
||||||
|
|
||||||
### Get Authorization (optional)
|
### Get Authorization (optional)
|
||||||
|
|
||||||
The server may optionally require authorization when retrieving blobs from the `GET /<sha256>` endpoint
|
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 perform additional checks on the authorization event
|
||||||
|
|
||||||
1. A `t` tag MUST be present and set to `get`
|
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 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
|
||||||
@@ -150,3 +134,9 @@ Example event for retrieving multiple blobs from single server:
|
|||||||
The `HEAD /<sha256>` endpoint MUST respond with either a `200` or `404` status code
|
The `HEAD /<sha256>` endpoint MUST respond with either a `200` or `404` status code
|
||||||
|
|
||||||
The endpoint MUST accept an optional file extension in the URL similar to the `GET /<sha256>` endpoint. ie. `.pdf`, `.png`, etc
|
The endpoint MUST accept an optional file extension in the URL similar to the `GET /<sha256>` endpoint. ie. `.pdf`, `.png`, etc
|
||||||
|
|
||||||
|
## Range requests
|
||||||
|
|
||||||
|
To better support mobile devices, video files, or low bandwidth connections. servers should support range requests ([RFC 7233 section 3](https://www.rfc-editor.org/rfc/rfc7233#section-3)) on the `GET /<sha256>` endpoint and signal support using the `accept-ranges: bytes` and `content-length` headers on the `HEAD /<sha256>` endpoint
|
||||||
|
|
||||||
|
See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) for more details
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ Defines the `/upload`, `/list` and `DELETE /<sha256>` endpoints
|
|||||||
|
|
||||||
A blob descriptor is a JSON object containing `url`, `sha256`, `size`, `type`, and `uploaded` fields
|
A blob descriptor is a JSON object containing `url`, `sha256`, `size`, `type`, and `uploaded` fields
|
||||||
|
|
||||||
- `url` A publicly accessible URL to the [BUD-01](./01.md#get-sha256---get-blob) `GET /<sha256>` endpoint (optionally with a file extension)
|
- `url` A publicly accessible URL to the [BUD-01](./01.md#get-sha256---get-blob) `GET /<sha256>` endpoint with a file extension
|
||||||
- `sha256` The sha256 hash of the blob
|
- `sha256` The sha256 hash of the blob
|
||||||
- `size` The size of the blob in bytes
|
- `size` The size of the blob in bytes
|
||||||
- `type` (optional) The MIME type of the blob
|
- `type` (optional) The MIME type of the blob
|
||||||
- `uploaded` The unix timestamp of when the blob was uploaded to the server
|
- `uploaded` The unix timestamp of when the blob was uploaded to the server
|
||||||
|
|
||||||
|
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:
|
Example:
|
||||||
@@ -47,7 +49,7 @@ Servers MAY reject an upload for any reason and should respond with the appropri
|
|||||||
Servers MAY accept an authorization event when uploading blobs and should perform additional checks
|
Servers MAY accept an authorization event when uploading blobs and should perform additional checks
|
||||||
|
|
||||||
1. The `t` tag MUST be set to `upload`
|
1. The `t` tag MUST be set to `upload`
|
||||||
2. MUST contain at least one `x` tag matching the sha256 hash of the blob being uploaded
|
2. MUST contain at least one `x` tag matching the sha256 hash of the body of the request
|
||||||
|
|
||||||
Example Authorization event:
|
Example Authorization event:
|
||||||
|
|
||||||
|
|||||||
@@ -12,18 +12,18 @@ A server may expose a `PUT /mirror` endpoint to allow users to copy a blob from
|
|||||||
|
|
||||||
Clients MUST pass the URL of the remote blob as a stringified JSON object in the request body
|
Clients MUST pass the URL of the remote blob as a stringified JSON object in the request body
|
||||||
|
|
||||||
```json
|
```jsonc
|
||||||
// request body
|
// request body...
|
||||||
{
|
{
|
||||||
"url": "https://cdn.satellite.earth/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf"
|
"url": "https://cdn.satellite.earth/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Clients MUST set the `Authorization` header to an upload authorization event defined in [BUD-02](./02.md#upload-authorization-required)
|
Clients MAY set the `Authorization` header to an upload authorization event defined in [BUD-02](./02.md#upload-authorization-required). 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
|
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 MUST NOT be interpreted as the user requesting a bulk mirror.**
|
**Multiple `x` tags in the authorization event MUST NOT be interpreted as the user requesting a bulk mirror.**
|
||||||
|
|
||||||
The endpoint MUST return a [Blob Descriptor](#blob-descriptor) if the mirroring was successful or an error object if it was not
|
The endpoint MUST return a [Blob Descriptor](#blob-descriptor) if the mirroring was successful or an error object if it was not
|
||||||
|
|
||||||
|
|||||||
48
buds/05.md
Normal file
48
buds/05.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# BUD-05
|
||||||
|
|
||||||
|
## Media optimization endpoints
|
||||||
|
|
||||||
|
`draft` `optional`
|
||||||
|
|
||||||
|
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 server should preform any optimizations or conversions it deems necessary in order to make the media more suitable for distribution
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### 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 preform the following 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
|
||||||
|
|
||||||
|
## HEAD /media
|
||||||
|
|
||||||
|
Servers MUST respond to `HEAD` requests on the `/media` endpoint in a similar way to the `HEAD /upload` endpoint defined in [BUD-06](./06.md)
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
This endpoint is intentionally limited to optimizing a single blob with the goal of making it easier to distribute
|
||||||
|
|
||||||
|
How the blob is optimized is the sole respirability 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.
|
||||||
|
|
||||||
|
## Client Implementation
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
17
buds/06.md
17
buds/06.md
@@ -8,14 +8,13 @@ Defines how clients can verify if the upload can be completed before sending the
|
|||||||
|
|
||||||
## HEAD /upload - Upload requirements
|
## 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-Upload-Message` 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 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.
|
||||||
|
|
||||||
### Headers
|
### Headers
|
||||||
|
|
||||||
- `X-SHA-256`: A string that represents the blob's SHA-256 hash.
|
- `X-SHA-256`: A string that represents the blob's SHA-256 hash.
|
||||||
- `X-Content-Length`: An integer that represents the blob size in bytes.
|
- `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`.
|
- `X-Content-Type`: A string that specifies the blob's MIME type, like `application/pdf` or `image/png`.
|
||||||
- `X-Upload-Message`: A human readable message that explains the reason why the upload cannot proceed.
|
|
||||||
|
|
||||||
### Upload Authorization
|
### Upload Authorization
|
||||||
|
|
||||||
@@ -39,36 +38,36 @@ Example response from the server if the upload can be done:
|
|||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
```
|
```
|
||||||
|
|
||||||
If the upload cannot proceed, the server `MUST` return an appropriate `4xx` HTTP status code and a custom header `X-Upload-Message` with a human readable error message.
|
If the upload cannot proceed, the server `MUST` return an appropriate `4xx` HTTP status code and a custom header `X-Reason` with a human readable error message.
|
||||||
|
|
||||||
Some examples of error messages:
|
Some examples of error messages:
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 400 Bad Request
|
HTTP/1.1 400 Bad Request
|
||||||
X-Upload-Message: Invalid X-SHA-256 header format. Expected a string.
|
X-Reason: Invalid X-SHA-256 header format. Expected a string.
|
||||||
```
|
```
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
X-Upload-Message: Authorization required for uploading video files.
|
X-Reason: Authorization required for uploading video files.
|
||||||
```
|
```
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 403 Forbidden
|
HTTP/1.1 403 Forbidden
|
||||||
X-Upload-Message: SHA-256 hash banned.
|
X-Reason: SHA-256 hash banned.
|
||||||
```
|
```
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 411 Length Required
|
HTTP/1.1 411 Length Required
|
||||||
X-Upload-Message: Missing X-Content-Length header.
|
X-Reason: Missing X-Content-Length header.
|
||||||
```
|
```
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 413 Content Too Large
|
HTTP/1.1 413 Content Too Large
|
||||||
X-Upload-Message: File too large. Max allowed size is 100MB.
|
X-Reason: File too large. Max allowed size is 100MB.
|
||||||
```
|
```
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 415 Unsupported Media Type
|
HTTP/1.1 415 Unsupported Media Type
|
||||||
X-Upload-Message: Unsupported file type.
|
X-Reason: Unsupported file type.
|
||||||
```
|
```
|
||||||
|
|||||||
24
buds/08.md
24
buds/08.md
@@ -1,16 +1,18 @@
|
|||||||
# Nostr File Metadata Tags
|
# BUD-08
|
||||||
|
|
||||||
|
## Nostr File Metadata Tags
|
||||||
|
|
||||||
`draft` `optional`
|
`draft` `optional`
|
||||||
|
|
||||||
Describes how a server could return nostr [NIP-94 File Metadata](https://github.com/nostr-protocol/nips/blob/master/94.md) tags from the `/upload` and `/mirror` endpoints
|
Describes how a server could return nostr [NIP-94 File Metadata](https://github.com/nostr-protocol/nips/blob/master/94.md) tags from the `/upload` and `/mirror` endpoints
|
||||||
|
|
||||||
## Returning tags
|
### Returning tags
|
||||||
|
|
||||||
As described in [BUD-02](./02.md#blob-descriptor) servers MAY add any additional fields to a blob descriptor
|
As described in [BUD-02](./02.md#blob-descriptor) servers MAY add any additional fields to a blob descriptor
|
||||||
|
|
||||||
Servers MAY return an additional `nip94` field in the [blob descriptor](./02.md#blob-descriptor) from the `/upload` or `/mirror` endpoints
|
Servers MAY return an additional `nip94` field in the [blob descriptor](./02.md#blob-descriptor) from the `/upload` or `/mirror` endpoints
|
||||||
|
|
||||||
The `nip94` field should contain a JSON object with the keys being the tag names defined in [NIP-94](https://github.com/nostr-protocol/nips/blob/master/94.md)
|
The `nip94` field should contain a JSON array with KV pairs as defined in [NIP-94](https://github.com/nostr-protocol/nips/blob/master/94.md)
|
||||||
|
|
||||||
An example response would look like:
|
An example response would look like:
|
||||||
|
|
||||||
@@ -21,13 +23,13 @@ An example response would look like:
|
|||||||
"size": 184292,
|
"size": 184292,
|
||||||
"type": "application/pdf",
|
"type": "application/pdf",
|
||||||
"uploaded": 1725909682,
|
"uploaded": 1725909682,
|
||||||
"nip94": {
|
"nip94": [
|
||||||
"url": "https://cdn.example.com/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf",
|
["url", "https://cdn.example.com/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf"],
|
||||||
"m": "application/pdf",
|
["m", "application/pdf"],
|
||||||
"x": "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553",
|
["x", "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"],
|
||||||
"size": 184292,
|
["size", "184292"],
|
||||||
"magnet": "magnet:?xt=urn:btih:9804c5286a3fb07b2244c968b39bc3cc814313bc&dn=bitcoin.pdf",
|
["magnet", "magnet:?xt=urn:btih:9804c5286a3fb07b2244c968b39bc3cc814313bc&dn=bitcoin.pdf"],
|
||||||
"i": "9804c5286a3fb07b2244c968b39bc3cc814313bc"
|
["i", "9804c5286a3fb07b2244c968b39bc3cc814313bc"]
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
41
buds/09.md
Normal file
41
buds/09.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# BUD-09
|
||||||
|
|
||||||
|
## Blob Report
|
||||||
|
|
||||||
|
`draft` `optional`
|
||||||
|
|
||||||
|
This bud defines a new endpoint for clients and users to report blobs to servers.
|
||||||
|
|
||||||
|
|
||||||
|
### PUT /report - reporting a blob
|
||||||
|
|
||||||
|
The request body MUST be a signed [NIP-56](https://github.com/nostr-protocol/nips/blob/master/56.md) report event with one or more `x` tags containing the hashes of the blobs being reported.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"kind": 1984,
|
||||||
|
"tags": [
|
||||||
|
["x", "<blob-sha256>", "<type-based-on-nip-56>"],
|
||||||
|
["x", "<another-blob-sha256>", "<type-based-on-nip-56>"]
|
||||||
|
],
|
||||||
|
"content": "<human readable report details>",
|
||||||
|
// other fields...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The clients can include `e` or `p` tags to point to the event or the profile that contains this media if they want to make this report event useful for relays as well.
|
||||||
|
|
||||||
|
Server MUST respond to a report request with a success code or a code in the 4xx/5xx range if there was any error.
|
||||||
|
|
||||||
|
### Client behavior
|
||||||
|
|
||||||
|
The clients can show a blob report button on posts or in blob details. Or its RECOMMENDED to merge this with normal nostr report and send it to both relays and blossom server. other clients can receive it from relays and hide or blur reported blob from trusted friends.
|
||||||
|
|
||||||
|
### Server behavior
|
||||||
|
|
||||||
|
The servers MAY keep the reports somewhere for operators to check and take action on them. they MAY use a list of trusted people or moderators to directly take action on blob without operator request.
|
||||||
|
|
||||||
|
Servers MAY consider removed blobs sha256 as blocked to prevent rewrite.
|
||||||
|
Servers SHOULD advertise a route or landing page to provide their rules and term of service which affects the report process.
|
||||||
177
buds/10.md
177
buds/10.md
@@ -1,115 +1,96 @@
|
|||||||
# BUD-10
|
# BUD-10
|
||||||
|
|
||||||
## Chunked blobs
|
## Multi-part uploads
|
||||||
|
|
||||||
`draft` `optional`
|
`draft` `optional`
|
||||||
|
|
||||||
Breaking large blobs into smaller chunks for distribution
|
This bud defines a new `PATCH` method for the `/upload` endpoint to allow clients to upload blobs in multiple parts.
|
||||||
|
|
||||||
### Chunking
|
### Signaling support for multi-part uploads
|
||||||
|
|
||||||
The client MAY break large blobs into any number or size of chunks. although its recommended to use the size `1Mb` or `4Mb` for small and large chunks
|
The server SHOULD respond to an `OPTIONS /upload` request with a `204` "No Content" response according to [RFC-9110](https://httpwg.org/specs/rfc9110.html#rfc.section.9.3.7) including the [`Allow`](https://httpwg.org/specs/rfc9110.html#field.allow) header with `PATCH`
|
||||||
|
|
||||||
Clients MUST NOT pad the remaining chunk, If clients need privacy they should use random chunk sizes and optionally encrypt the large blob
|
### Upload requirements
|
||||||
|
|
||||||
Clients MUST create a merkle tree using the chunk hashes as the leaf nodes
|
The server SHOULD implement [BUD-06](06.md) "Upload requirements" to allow clients to check if a blob can be uploaded before uploading any chunks.
|
||||||
|
|
||||||
### Publishing
|
### Chunking strategy
|
||||||
|
|
||||||
Clients should publish a `2001` kind event after chunking the file in order to store the list of chunks
|
The client MAY split the blob into as many chunks as needed and MAY include overlap in the chunks if needed.
|
||||||
|
|
||||||
The events MUST contain an ordered list of `chunk` tags with the sha256 hashes of the chunks
|
The server MUST concatenate the chunks based on the `Upload-Offset` and `Content-Length` headers to reconstruct the final blob to ensure any overlap is accounted for.
|
||||||
|
|
||||||
The `content` field MUST be a human readable description of the chunked file
|
### Uploading chunks
|
||||||
|
|
||||||
|
Clients MUST send the following headers in each `PATCH /upload` request:
|
||||||
|
|
||||||
|
- `X-SHA-256`: The sha256 hash of the final blob. this should be considered the "ID" of the multi-part upload.
|
||||||
|
- `Upload-Type`: The mine type of the final blob. should be set like `Content-Type` defined in [RFC-9110](https://httpwg.org/specs/rfc9110.html#field.content-type)
|
||||||
|
- `Upload-Length`: The total length of the blob. should be set like `Content-Length` defined in [RFC-9110](https://httpwg.org/specs/rfc9110.html#field.content-length)
|
||||||
|
- `Content-Length`: The length of the chunk in bytes.
|
||||||
|
- `Upload-Offset`: The offset of the chunk in the blob.
|
||||||
|
- `Content-Type`: The type of the chunk. MUST be set to `application/octet-stream`
|
||||||
|
|
||||||
|
The server MUST respond with a `204` "No Content" response if the chunk was accepted or a `4xx` status code if it was not.
|
||||||
|
|
||||||
|
### Uploading the final chunk
|
||||||
|
|
||||||
|
Once the server has received enough chunks to cover the `Upload-Length` of the blob the server MUST respond with a `2xx` status code following [BUD-02](02.md) or a `4xx` status code if the blob hash does not match the `X-SHA-256` header
|
||||||
|
|
||||||
|
### Authorization
|
||||||
|
|
||||||
|
The server MAY require authorization for uploads by checking the `Authorization` header similar to the [`PUT /upload`](./02.md#upload-authorization-required) endpoint
|
||||||
|
|
||||||
|
The server SHOULD validate that the authorization event contains the following tags:
|
||||||
|
|
||||||
|
- A `t` tag set to `upload`
|
||||||
|
- One `x` tag for each chunk with the sha256 hash of the chunk
|
||||||
|
- A final `x` tag with the sha256 hash of the final blob
|
||||||
|
|
||||||
|
### Resuming uploads
|
||||||
|
|
||||||
|
The client SHOULD keep track of a chunks it has uploaded in order to resume uploads after a failure.
|
||||||
|
|
||||||
|
### Example upload flow
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Client splits the blob into 4 chunks
|
||||||
|
split -b 46073 bitcoin.pdf chunk_
|
||||||
|
|
||||||
|
# Client uploads the first chunk
|
||||||
|
curl -X PATCH http://cdn.example.com/upload \
|
||||||
|
-H "X-SHA-256: b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553" \
|
||||||
|
-H "Upload-Type: application/pdf" \
|
||||||
|
-H "Upload-Length: 184292" \
|
||||||
|
-H "Upload-Offset: 0" \
|
||||||
|
-H "Content-Length: 46073" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary "@chunk_aa"
|
||||||
|
|
||||||
|
# Server accepts the chunk and responds with a 204
|
||||||
|
HTTP/1.1 204 No Content
|
||||||
|
|
||||||
|
# CLient uploads remaining chunks (2-4)
|
||||||
|
curl -X PATCH http://cdn.example.com/upload
|
||||||
|
# ..
|
||||||
|
--data-binary "@chunk_ab"
|
||||||
|
curl -X PATCH http://cdn.example.com/upload
|
||||||
|
# ...
|
||||||
|
--data-binary "@chunk_ac"
|
||||||
|
curl -X PATCH http://cdn.example.com/upload
|
||||||
|
# ...
|
||||||
|
--data-binary "@chunk_ad"
|
||||||
|
|
||||||
|
# Server responds with 200 OK
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/pdf
|
||||||
|
Content-Length: 184292
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
{
|
||||||
"tags": [
|
"url": "https://cdn.example.com/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf",
|
||||||
[ "chunk", "7e668b56a58c7891e0cf263ea3f093b75eebade23d663a45aa9920f347b3d671"],
|
"sha256": "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553",
|
||||||
[ "chunk", "9b9c44a91396f19fd8700986eb0586dff2dcccf96c75bc2caefef302bcd78da1"],
|
"uploaded": 1725105921,
|
||||||
[ "chunk", "7a281548f1223664b855b10b08e59e84389ccabeb742517f6cd75eda2724a798"],
|
"type": "application/pdf",
|
||||||
[ "chunk", "fadeccee86b123088bbc452df10e8fbc99d4c2f22a70ef7a35605ec8e439c345"],
|
"length": 184292
|
||||||
[ "chunk", "5d62398419e6d136771541f3d2215e0ce31b1be45e99dbc64b43a4b734b447ca"],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The event MUST have an `x` tag with the sha256 hash of the ordered concatenated hashes of each chunk
|
|
||||||
|
|
||||||
Example using `xxd` and `sha256sum`:
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
hashes=(
|
|
||||||
"7e668b56a58c7891e0cf263ea3f093b75eebade23d663a45aa9920f347b3d671"
|
|
||||||
"9b9c44a91396f19fd8700986eb0586dff2dcccf96c75bc2caefef302bcd78da1"
|
|
||||||
"7a281548f1223664b855b10b08e59e84389ccabeb742517f6cd75eda2724a798"
|
|
||||||
"fadeccee86b123088bbc452df10e8fbc99d4c2f22a70ef7a35605ec8e439c345"
|
|
||||||
"5d62398419e6d136771541f3d2215e0ce31b1be45e99dbc64b43a4b734b447ca"
|
|
||||||
)
|
|
||||||
|
|
||||||
concatenated=""
|
|
||||||
for hex in "${hex_array[@]}"; do
|
|
||||||
concatenated="${concatenated}${hex}"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Chunks:"
|
|
||||||
printf '%s\n' "${hex_array[@]}"
|
|
||||||
|
|
||||||
echo -e "\nConcatenated:"
|
|
||||||
echo "$concatenated"
|
|
||||||
|
|
||||||
echo -e "\nRoot hash:"
|
|
||||||
echo "$concatenated" | xxd -r -p | sha256sum
|
|
||||||
```
|
|
||||||
|
|
||||||
The final `chunk` tags and `x` tag should look something like this
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tags": [
|
|
||||||
[ "chunk", "7e668b56a58c7891e0cf263ea3f093b75eebade23d663a45aa9920f347b3d671"],
|
|
||||||
[ "chunk", "9b9c44a91396f19fd8700986eb0586dff2dcccf96c75bc2caefef302bcd78da1"],
|
|
||||||
[ "chunk", "7a281548f1223664b855b10b08e59e84389ccabeb742517f6cd75eda2724a798"],
|
|
||||||
[ "chunk", "fadeccee86b123088bbc452df10e8fbc99d4c2f22a70ef7a35605ec8e439c345"],
|
|
||||||
[ "chunk", "5d62398419e6d136771541f3d2215e0ce31b1be45e99dbc64b43a4b734b447ca"],
|
|
||||||
[ "x", "2d839865ac17d8bb10168490a88107637619f79dac21275fcec1705162581f39" ],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Metadata
|
|
||||||
|
|
||||||
The `2001` event MAY include additional metadata tags to help other clients know the filename, mime type or servers to download from
|
|
||||||
|
|
||||||
Metadata tags:
|
|
||||||
- `name` Filename
|
|
||||||
- `mime` Mime type of file
|
|
||||||
- `size` Total size in bytes of the file
|
|
||||||
- `server` (multiple) Recommended servers to download chunks from
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
Example `2001` event
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "fd2f4da046851170576e7a09009e63f752dc469c61a24faca514b2cedfe641aa",
|
|
||||||
"pubkey": "5328e6c743a50271745e16476590ba7ea3dc591c65f3a5e2b03430814c1dabc0",
|
|
||||||
"created_at": 1731405194,
|
|
||||||
"kind": 2001,
|
|
||||||
"content": "Here is the original version",
|
|
||||||
"tags": [
|
|
||||||
[ "chunk", "7e668b56a58c7891e0cf263ea3f093b75eebade23d663a45aa9920f347b3d671"],
|
|
||||||
[ "chunk", "9b9c44a91396f19fd8700986eb0586dff2dcccf96c75bc2caefef302bcd78da1"],
|
|
||||||
[ "chunk", "7a281548f1223664b855b10b08e59e84389ccabeb742517f6cd75eda2724a798"],
|
|
||||||
[ "chunk", "fadeccee86b123088bbc452df10e8fbc99d4c2f22a70ef7a35605ec8e439c345"],
|
|
||||||
[ "chunk", "5d62398419e6d136771541f3d2215e0ce31b1be45e99dbc64b43a4b734b447ca"],
|
|
||||||
[ "x", "2d839865ac17d8bb10168490a88107637619f79dac21275fcec1705162581f39" ],
|
|
||||||
[ "name", "example.mp4" ],
|
|
||||||
[ "mime", "video/mp4" ],
|
|
||||||
[ "size", "4823449" ],
|
|
||||||
[ "server", "https://cdn.example.com" ],
|
|
||||||
[ "server", "https://nostr.download" ]
|
|
||||||
],
|
|
||||||
"sig": "cd589a4ea702185c69d1fec93a7704265071b674c5708a1da04d08bcba873f5277bc0abb379cbb014852fafa2ac951ed49abbdba60028a4f02ef4e31ff2599cb"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user