Open24

Nostr というのが流行っているらしい

雪猫雪猫
雪猫雪猫

NIP-11 Relay Information Document

https://{domain}Accept: application/nostr+json ヘッダー付きでアクセスされたら JSON を返す。

NIP-15 End of Stored Events Notice

データ取得をリクエストされて全部送り終わったら EOSE を送る。

雪猫雪猫

EVENT

[
  "EVENT",
  "<subscription_id>",
  {<REQ で要求されたオブジェクト>}
]

OK

[
  "OK",
  "<id>",
  true,
  ''
]

NOTICE

[
  "NOTICE",
  "<message>"
]
雪猫雪猫

国内限定リレー

IP 制限がかかっています。

ホワイトリストリレー

使用したい場合は管理者へ問い合わせてください。

国産リレー

運用する際の課題

  • スパム対策
  • スケール
  • コスト
雪猫雪猫

リレーの制限

対象

  • kind
  • pubkey
    • フォロー
    • フォロワー
    • 独自リスト
  • 課金
    • 読み書き
    • データの保持期間
  • IP アドレス
    • リクエスト全体(インフラレイヤー)
    • 読み書きで個別に設定(アプリケーションレイヤー)
  • 投稿内容 (content, tags)
    • 正規表現
    • ハッシュタグ
  • 個人
    • pubkey が自分
    • p タグが自分宛

形式

  • ホワイトリスト
  • ブラックリスト

実装

  • NIP-42
  • 設定ファイル
雪猫雪猫

クライアント

使用

Client Web PWA iOS Android Note
Iris
Snort × × リレーの情報が見れる
Damus × × × 使いやすい
Amethyst × × ×

ライブラリ

https://github.com/nbd-wtf/nostr-tools

参考

https://zenn.dev/ihasq/articles/26c6e28891c522
https://kappaseijin.hatenablog.com/entry/2023/02/10/212745

雪猫雪猫

NIP-05 Mapping Nostr keys to DNS-based internet identifiers

https://zenn.dev/snowcait/articles/e2361b3827d517

NIP-11 Relay Information Document

JavaScript
await fetch(`https://${domain}`, {
  method: 'GET',
  headers: {
    'Accept': 'application/nostr+json',
  },
});

NIP-07 window.nostr capability for web browsers

https://github.com/fiatjaf/nos2x

Alby は Nostr 単体では使えない。

NIP-15 End of Stored Events Notice

データ取得をリクエストして EOSE が来たら完了。
リレーがサポートしているかは NIP-11 の supported_nips を確認。

雪猫雪猫

EVENT

id, pubkey, created_at, sig は生成するので省略。

投稿

[
  "EVENT",
  {
    "kind": 1,
    "tags": [],
    "content": "<投稿内容>",
  }
]

REQ

自分に関する情報

タイムラインを取得する際に limit フィルターを使用すると安定しないので非推奨。
代わりに since + until で期間ごとに取得することを推奨。

[
  "REQ",
  "<subscription_id>",
  {"authors":["<pubkey-hex>"]}
]

CLOSE

[
  "CLOSE",
  "<subscription_id>"
]
雪猫雪猫

リレーリスト

Client kind: 10002 kind: 3
(deprecated)
Snort ⭕️ ⭕️
Iris ⭕️
Damus ⭕️
Amethyst ⭕️
kind: 10002
[
    "EVENT",
    "<subscription_id>",
    {
        "id": "<id>",
        "pubkey": "<pubkey>",
        "created_at": 1234567890,
        "kind": 10002,
        "tags": [
            [
                "r",
                "wss://eden.nostr.land"
            ],
            [
                "r",
                "wss://relay.damus.io"
            ],
            [
                "r",
                "wss://relay.snort.social"
            ],
            [
                "r",
                "wss://relay.current.fyi"
            ],
            [
                "r",
                "wss://relay-jp.nostr.wirednet.jp"
            ],
            [
                "r",
                "wss://nostr.holybea.com"
            ],
            [
                "r",
                "wss://nostr-relay.nokotaro.com"
            ],
            [
                "r",
                "wss://nos.lol/"
            ]
        ],
        "content": "",
        "sig": "<sig>"
    }
]
kind: 3
[
    "EVENT",
    "<subscription_id>",
    {
        "content": "{\"wss://eden.nostr.land\":{\"read\":true,\"write\":true},\"wss://relay.damus.io\":{\"read\":true,\"write\":true},\"wss://relay.snort.social\":{\"read\":true,\"write\":true},\"wss://relay.current.fyi\":{\"read\":true,\"write\":true},\"wss://relay-jp.nostr.wirednet.jp\":{\"read\":true,\"write\":true},\"wss://nostr.holybea.com\":{\"read\":true,\"write\":true},\"wss://nostr-relay.nokotaro.com\":{\"read\":true,\"write\":true}}",
        "created_at": 1234567890,
        "id": "<id>",
        "kind": 3,
        "pubkey": "<pubkey>",
        "sig": "<sig>",
        "tags": [
            [
                "p",
                "<pubkey>"
            ]
        ]
    }
]
雪猫雪猫

kind 0

  • 複数のデータを保持しているリレーがあるので最新を採用
雪猫雪猫

kind 6

リポスト。

Iris
{
    "id": "3e568e5fcb2e294b32efa9064a9297725de3e80cf5b645b382ada9748ee6856a",
    "pubkey": "83d52b4363d2d1bc5a098de7be67c120bfb7c0cee8efefd8eb6e42372af24689",
    "created_at": 1677391085,
    "kind": 6,
    "tags": [
        [
            "e",
            "c8843678966ae8d092830485111dc932a6c29e0e48343d87a98ac965b7f6c773",
            "",
            "mention"
        ],
        [
            "p",
            "a22a2372ed6e77d2391d4392be07547b9e8ba38394cae680219781d5061a8c67"
        ]
    ],
    "content": "",
    "sig": "f14fd6d0081b93766105de7d97b93d3d6519466b5ff476d72595f007f41de638ed4a7b4d087b53d945f73982d4a9a33d4495c72fbf868d8a5792aa718ef37389"
}
Snort
[
    "EVENT",
    "23201",
    {
        "id": "0c26843832b742bfa56ce88d860884d402b1e0a45739a55bcafb643c2c8a38e5",
        "pubkey": "83d52b4363d2d1bc5a098de7be67c120bfb7c0cee8efefd8eb6e42372af24689",
        "created_at": 1677390964,
        "kind": 6,
        "tags": [
            [
                "e",
                "c2e054959646f1eb4109cefc34dbb0100f6af1c7d3012a5b9a86f1c8af3ccab0"
            ],
            [
                "p",
                "d1d1747115d16751a97c239f46ec1703292c3b7e9988b9ebdd4ec4705b15ed44"
            ]
        ],
        "content": "{\"id\":\"c2e054959646f1eb4109cefc34dbb0100f6af1c7d3012a5b9a86f1c8af3ccab0\",\"pubkey\":\"d1d1747115d16751a97c239f46ec1703292c3b7e9988b9ebdd4ec4705b15ed44\",\"created_at\":1677390434,\"kind\":1,\"tags\":[],\"content\":\"NIP-58訳したった\\nhttps://scrapbox.io/nostr/NIP-58\",\"sig\":\"93516654ddae95be81209b90fba3523681a665500f91b4a4d6b39bc7c1ae05d14c46057ad2d709e235ec137170502fc0d64d700a672cd2ed41c1b0abb8140c2b\",\"relays\":[\"wss://nostr.holybea.com\"]}",
        "sig": "e10b205653efeaecd718487142d1cdfcc1b345c56c1e8808016cfe1f761bb01519c89ff93bab5016ea88245f086e9e77e3113534627c3e984ba9056bbf82fcf1"
    }
]
Damus
[
  "EVENT",
  "23201",
  {
    "id": "23c9aea1ac314eb2c23313fbc0704625d18578769075a7557f2ad494c2d90b12",
    "pubkey": "83d52b4363d2d1bc5a098de7be67c120bfb7c0cee8efefd8eb6e42372af24689",
    "created_at": 1677392543,
    "kind": 6,
    "tags":
      [
        [
          "e",
          "c30b34c922a4a9257f05816dd74ce8be06267d91deb3fea3d810d0d96c6d755c",
          "",
          "root",
        ],
        [
          "p",
          "4d39c23b3b03bf99494df5f3a149c7908ae1bc7416807fdd6b34a31886eaae25",
        ],
      ],
    "content": '{"pubkey":"4d39c23b3b03bf99494df5f3a149c7908ae1bc7416807fdd6b34a31886eaae25","content":"blastrはREST API (今の所POSTのみ) 付きのリレーだよ〜","id":"c30b34c922a4a9257f05816dd74ce8be06267d91deb3fea3d810d0d96c6d755c","created_at":1677392472,"sig":"816b67f363638ae53ca5954b6801a9fadc9f122513fc47be914b2f245c13506133cf25cd7e7a517b13a195647360f3d72489e78d6cf7ee33bf47f09565f9e279","kind":1,"tags":[]}',
    "sig": "68c5b35e8f4bd299700a02e23000cb0f70ff93fdaec556473aca3977b74e4aa8dd8297ac21753ffa6f16eff1a25772aaf7efc28a00cf89c75648b9e2f65008d6",
  },
]
雪猫雪猫

パブリックチャットクライアント

名前
作者
プラットフォーム ログイン その他
機能
備考
Amethyst
Vitor
Android TL, DM -
Coracle
hodlbod
Web
(PC, Mobile)
不要 TL, DM ログインしてないと日本人部屋が見えない
NostrChat
Talha
Web
(PC, Mobile)
必要 DM 要リレー編集
部屋検索は ID のみ
GARNET
murakmii
Web (PC) 不要 - 更新停止?
FreeFrom
MAAS㈱
iOS, Android
Web
0xchat
water783
iOS, Android
Nostri.chat
pablof7z
ぱぶ茶(仮)
Don
Web (PC) 不要 - WIP
nostter
雪猫
Web
(PC, Mobile)
不要 TL ホーム TL に流れてくる

ピン留め保存先

名前 プラットフォーム 保存先
Amethyst Android kind 3(NIP 違反)
Coracle Web
NostrChat Web
GARNET Web localStorage
ぱぶ茶(仮) Web
nostter Web kind 10001
雪猫雪猫

主要クライアントの NIP 準拠状況

Amethyst

  • ❌kind 1 をマークダウンとして描画
  • ❌リレーリストを kind 3 に保存
  • ❌チャンネルのピン留めを kind 3 に保存
  • ❌スパム報告時にいいねにあたる kind 7 を送信

Damus

  • ❌リレーリストを kind 3 に保存
  • ❌ e tag の扱いがおかしい

Plebstr

Snort

  • ❌kind 1 をマークダウンとして描画
  • 🔺ミュートを kind 30001 に保存
    • NIP-51 の先行実装のまま

Iris

Coracle

  • 🔺無言引用をリポストの代わりにしている
    • 一時期 NIP からリポストの仕様が消えていてそう扱うのも案の 1 つになっていた

Rabbit

nostter

  • 🔺kind 6 の content が空
    • 旧仕様。kind 5 と矛盾するので NIP を戻すべき
雪猫雪猫

NIPs

⭕️ : 必須
🔺 : 任意
- : 不要

NIP Relay Client
NIP-01 ⭕️ ⭕️
NIP-02 🔺 🔺
NIP-03
NIP-04 🔺 🔺
NIP-05 - 🔺
NIP-06
NIP-07 - 🔺
NIP-08 🔺 🔺
NIP-09 🔺 🔺
NIP-10 🔺 🔺
NIP-11 🔺 🔺
NIP-12
NIP-13
NIP-14
NIP-15 🔺 🔺
NIP-16 🔺 🔺
NIP-19 - 🔺
NIP Relay Client
NIP-20
NIP-21 - 🔺
NIP-22 🔺 🔺
NIP-23
NIP-25
NIP-26
NIP-28
NIP-33
NIP-36
NIP-40
NIP-42
NIP-50
NIP-56
NIP-57
NIP-65
雪猫雪猫

リレーから返ってくるエラー

["NOTICE","ERROR: bad req: std::get: wrong index for variant"]

送信した JSON のフォーマットがおかしい。

["NOTICE","ERROR: bad req: uneven size input to from_hex"]

npub1 形式ではなく hex で送る必要がある。

["NOTICE","ERROR: bad req: filter item too small"]

ids などに渡す文字列が不正。(ids: [""] など)

["NOTICE","ERROR: bad req: total filter items too large"]
["NOTICE","invalid: \"[2].authors\" must contain less than or equal to 1000 items"]

フィルターの各項目の配列を 1,000 未満にする。

雪猫雪猫

NIP-57 Lightning Zaps

流れ

TODO: invoice 生成について記載

  1. Zap に必要な情報を含んだ kind 9734 イベントを自分の pubkey で作成
  2. kind 9734 はリレーに送らずウォレットのサーバーへ送信
  3. ウォレットのサーバーが支払いを処理してレシートを発行
  4. レシート情報と元データ(kind 9734)を含んだ kind 9735 イベントをウォレットの pubkey で作成
  5. 元データに含まれるリレーへ kind 9735 を送信
  6. kind 9735 には #p(, #e) が付いているので相手に通知がいく&過去の Zap 情報も取得できる

具体的なフロー

  1. nip57.makeZapRequest でイベントを生成(未署名)
  2. 署名
  3. nip57.getZapEndpoint で kind 0 から LN URL を取得
  4. LN URL へリクエストを送る
  5. レスポンスの pr が invoice
  6. invoice を QR コードに変換して表示

WIP

参考資料

https://scrapbox.io/nostr/NIP-57

雪猫雪猫

アウトボックスモデル

NIP-65
旧ゴシップモデル

課題

  • デバイス毎にリレー構成を変更できない
  • フォロイーの write リレー全部を購読するとパフォーマンスが悪化する(全部は購読しなくていいことになっているが適切に選ぶのは困難)
  • 有料リレーしか購読していないユーザーのリレーへ書き込めない
雪猫雪猫

初心者のハードル

理解するのがやや難しい概念など。

  • 秘密鍵
  • リレー
  • クライアントの名前がバラバラなので同じ SNS として認識しづらい
  • クライアント毎に挙動が異なる場合がある
雪猫雪猫

クライアントのパフォーマンス改善ポイント

  • EOSE を待たずに随時反映する
    • 事前にソートするのは諦めて後から挿入する
    • ただし created_at が正しい保証はないので EOSE 以降の投稿は常に最新として扱う
  • pubkey や tags の情報は非同期で取得して後から反映する
    • リレーの Rate Limit に引っかからないように REQ をバッファする
    • UI スレッドをブロックしないように注意
  • キャッシュを適切に行う(バグの温床になりやすく諸刃の剣なので注意)
    • 自分の Replaceable Events, Parameterized Replaceable Events
    • フォロイーの kind 0
    • フォロワーかどうか判定したければフォロワーの kind 3
    • NIP-65 対応をするならフォロイー(+メンション等を送る可能性のある人)の kind 10002
    • 過度にキャッシュしないこと(ディスク容量、更新処理の複雑化)
雪猫雪猫

NIP-19

special relay(s) author
(event.pubkey)
kind
(event.kind)
npub pubkey - - -
nsec seckey - - -
note id - - -
nprofile pubkey - -
nevent id
nrelay relay URL - - -
naddr identifier (d tag)