NIP-96
> HTTP File Storage Integration
ファイルをクライアントからアップロードする仕組みを定めるNIP
同様の仕組みとしてhzrd149氏による
Blossomが考案されています。
対応状況
翻訳
HTTPファイルストレージ連携
はじめに
このNIPは、nostrネットワークと組み合わせて使うことが意図されているHTTPファイルストレージサーバ向けのREST APIを定義する。nostrのユーザはAPIを使うことでファイルをアップロードして、後でURLを使ってnostrのテキスト投稿から参照することができる。
シンプルさのため、そしてサーバがnostrリレーについて何も知らなくてもよいように、この仕様はデータの保存やリクエスト、取得のためにWebSocketを介する通常のnostrイベントを使用しない。
サーバの対応
nostrユーザからアクセスしてもらいたいファイルストレージサーバは、 api_url
を含む /.well-known/nostr/nip96.json
のHTTPSルートを利用可能にすることでオプトインすべきである。
_.json{
// 必須
// ファイルのアップロードと削除はこのURLで提供される。
// また、"downoad_url"がから文字列の場合にはダウンロードにも使われる。
"api_url": "https://your-file-server.example/custom-api-path",
// 任意
// もし空の場合はダウンロードは api_url で提供される。
"download_url": "https://a-cdn.example/a-path",
// 任意
// 注意: このフィールドはHTTPサーバ側で設定することは意図されていない。
// Nostrリレーが自身の /.well-known-nostr/nip96.json を
// 単に他人のHTTPファイルストレージサーバの /.well-known-nostr/nip96.json
// にリダイレクトしたい場合に使うこと。
// この場合、"api_url"フィールドは空文字列でなければならない。
// 訳注: 「移譲先のURL」の意味
"delegated_to_url": "https://your-file-server.example",
// 任意
"supported_nips": [60],
// 任意
// 訳注: 利用規約(Term of Service)のURL
"tos_url": "https://your-file-server.example/terms-of-service",
// 任意
"content_types": ["image/jpeg", "video/webm", "audio/*"],
// 任意
"plans": {
// プランのキーとしては "free"が唯一標準化されている。
// サーバが無料のストレージを提供しているかどうかを知るために
// クライアントは"free"が存在するかどうかを確かめても良い。
"free": {
"name": "Free Tier",
// デフォルトは true
// すべてのプランはNIP-98によるアップロードをサポートしなければならない(MUST)
// ただし、一部のプランではNIP-98を使わないアップロードを許可してもよい。
"is_nip98_required": true,
"url": "https://...", // 存在する場合はプランのランディングページ
"max_byte_size": 10485760,
// 期間(日数)0 は期限なしを意味する
// [7, 0] は7日から無期限の間で変わりうることを意味する
// [0, 0] は無期限を意味する
// 早い方の期限はアクセスが少ないことや他の要因等が原因になるだろう
"file_expiration": [14, 90],
"media_transformations": {
"image": [
'resizing'
]
}
}
}
}
リレーヒント
注意: この節は、HTTPサーバで利用されることを意図していない。
Nostrリレーは他のHTTPファイルストレージサーバにリダイレクトしてもよい(MAY)。
そのためには /.well-known/nostr/nip96.json
を持つサーバホスト自体のURLを指し示す "delegated_to_url"
を持つ /.well-known/nostr/nip96.json
を追加する。この場合、"api_url"フィールドは空文字列でなくてはならず、他のすべてのフィールドは存在してはならない。
もしnostrリレーがHTTPファイルストレージサーバでもあるならば、"api_url"フィールドをかわりに使わなくてはならない。
対応するファイルストレージサーバのリスト
認証
もし指示された場合には、
clients
(クライアント)は
NIP-98 Authorization
ヘッダ(
任意で payload
タグにBase64でエンコードされたファイルのSHA-256ハッシュ値(256bit)をセットする。リクエストボディ全体のハッシュではない)を追加しなければならない。
アップロード
POST $api_url
( multipart/form-data
として)
認証が必要
フォームのフィールドの一覧:
file
: 必須 アップロードするファイル
caption
: 推奨 大雑把な説明
expiration
: UNIXタイムスタンプ(秒)。永久に保存すべきであれば空文字列。サーバがこれを遵守することは必須でない。
size
: ファイルのサイズ(バイト)。これは単にファイルサイズがサーバの定める上限を超過していたときに、サーバが早期に拒否するために使用できる値である。
alt
: 推奨 視覚障害を持つユーザのための厳密な説明
media_type
: "avatar" または "banner"。(訳注: kind:0の)アバターまたはバナーとして使われることをサーバに伝える。値を設定しない場合は、サーバは通常の(特別な対応を行わない)アップロードと解釈するだろう。
content_type
: MIMEタイプ("image/jpeg"のように)。これは単にMIMEタイプが非対応の場合にサーバが早期に拒否するために使用できる値である。
no_transform
: "true"を設定すると、サーバにファイルを変換せず、ファイルを元のまま提供するよう依頼する。しかし、拒否される可能性もある。
レスポンスコード
200 OK
: アップロードしたファイルは既に存在しているが、成功(既に存在するハッシュ値)
201 Created
: ファイルのアップロードに成功(新しいハッシュ値)
202 Accepted
: アップロードしたファイルは処理を待機している。遅延処理の節を参照。
413 Payload Too Large
: ファイルサイズが上限を超過
400 Bad Request
: フォームデータが不正か、非対応
403 Forbidden
: ユーザはアップロードを許可されていないか、アップロードしたファイルのハッシュ値がAuthorizationヘッダのpayloadタグとマッチしなかった
402 Payment Required
: サーバが支払いを要求した場合。この処理フローは未定義である。
アップロードへの応答は、次のJSONオブジェクトに従う。
_.json{
// 成功時は "success"、そうでなければ "error"
status: "success",
// フリーテキスト。成功、失敗、通知メッセージ
message: "Upload successful.",
// 任意。遅延処理の節を参照。
processing_url: "...",
// これには、NIP-94のイベント形式を使用するが、 "id" や "pubkey"、
// "created_at"、 "tag" といったフィールドを埋める**必要はない**。
//
// これは、ダウンロードURL("url")、
// サーバで変換を行う前の **元** のファイルのハッシュ値("ox")、
// 任意でサーバが提供したいファイルのすべてのメタデータを持つ。
//
// アップロード失敗時、nip94_eventフィールドは設定されない。
nip94_event: {
// 必須のタグ: "url" と "ox"
tags: [
// /.well-known/nostr/nip96.json の "download_url" フィールド
// (もしくは "download_url" が未設定か、空の場合は "api_url" フィールド)
// と元のファイルのハッシュ値を組み合わせたものであってよい。
//
// 注意: `ox` の後に .png ファイル拡張子を追加している。
// (任意だが、Nostrクライアントが正規表現を使用してファイル形式を検知する
// 助けとなるだろうから、拡張子を追加することを非常に強く推奨する。
//
// ファイルをダウンロードするためのURLはどんなものであってもよい。
// (/.well-known/nostr/nip96.json の "download_url" プレフィックスを使用しても、使用しなくてもよい)
// (例えば、ロードバランスを行う目的で)
["url", "https://your-file-server.example/custom-api-path/719171db19525d9d08dd69cb716a18158a249b7b3b3ec4bbdec5698dca104b7b.png"],
// 変換を行う前の **元** のファイルの SHA-256 ハッシュ値。
// たとえこれが元のファイルを表していたとしても、サーバはこれを保存しなければならない(MUST)。
// ユーザーはこの値を使って変換されたファイルをダウンロード・削除しようとするかもしれないからである。
["ox", "719171db19525d9d08dd69cb716a18158a249b7b3b3ec4bbdec5698dca104b7b"],
// 任意。サーバの変換後の保存されたファイルのハッシュ値。
// サーバはこれを保管してもよいが、しなくても構わない。
["x", "543244319525d9d08dd69cb716a18158a249b7b3b3ec4bbde5435543acb34443"],
// 任意。クライアントがダウンロード前に容易にファイル形式を知ることを助けるために推奨される。
["m", "image/png"]
// 任意。クライアントがダウンロード前に、十分なスペースをUI上に確保することを助けるために推奨される。
["dim", "800x600"]
// ... 他の任意の NIP-94 タグ
],
content: ""
},
// ... 他のカスタムフィールド(このNIPまたはNIP-94のタグに追加することをご検討ください)
}
遅延処理
TODO
ファイルの圧縮
ダウンロード
メディアの変換
削除
ファイルの列挙
サーバの選択
注意: HTTPファイルストレージサーバの開発者はこのセクションをスキップしてもよい(クライアント開発者向けの内容のため)
ファイルサーバ設定イベントは kind:10096
の置換可能イベントで、ユーザがアップロードに使いたい1個以上のサーバを選ぶために使われる。サーバは server
タグで列挙する。
_.json{
// ...
"kind": 10096,
"content": "",
"tags": [
["server", "https://file.server.one"],
["server", "https://file.server.two"]
]
}