Open10

Nostr リレー開発

雪猫雪猫

要件

  • WebSocket が動くサーバー
  • NIP の実装 (wss)
    • NIP
    • クライアントから送られてくるメッセージとリレーが返すメッセージ
      • EVENT
        • OK
        • NOTICE
      • REQ
        • フィルターのパース、SQL 化
        • EVENT
        • EOSE
        • CLOSED
        • NOTICE
      • CLOSE
        • NOTICE
      • AUTH
        • AUTH
        • OK
        • CLOSED
  • 認証
    • NIP-42
      • pubkey ホワイトリスト
        • p タグに含まれる場合も許可
  • レートリミット
  • スパム対策
    • タグが大量に含まれる場合は弾く
      • kind 3, NIP-51 が弾かれてしまうのでなし
  • NIP-11 の実装 (https, application/nostr+json)
  • フロントエンド (https)
    • トップページ
    • 利用規約
    • ステータスページ
    • ダッシュボード(管理画面)
      • スパム報告一覧
      • BAN
        • データ削除
        • ブロック
        • pubkey
        • IP アドレス
  • テスト
  • あるといいかも?
    • Webhook
    • プッシュ通知
雪猫雪猫

規約

利用規約

このサービスはいかなる種類の保証もなく現状のまま提供されます。
管理者は一切の責任を負いません。
利用規約は、将来予告なしにいつでも変更される可能性があります。
BOT は kind 0 に bot: true を設定してください。設定されていない場合はブロックされることがあります。

管理者の判断で削除およびブロックされることがあります。
例:

  • 違法なコンテンツ
  • スパム行為
  • その他

プライバシーポリシー

送信されたデータおよび送信元の IP アドレスを保存します。
送信されたデータはすべて公開されます。(暗号化されている場合は暗号化後のデータのみ)
IP アドレスは公開されませんが必要に応じて警察などへ提供される場合があります。

参考

https://github.com/cameri/nostream/blob/b6133a18fde1bba396bc04419adc39f186ea8eb0/resources/terms.html
https://nostr.wine/terms

雪猫雪猫

ルーティング

  • example.com
    • /: トップページ
      • リレーの説明
      • 登録
        • 利用規約、プライバシーポリシー
      • ユーザー数などの情報
    • / + Accept: application/nostr+json: NIP-11
    • / (wss): WebSocket
    • /register: ユーザー登録
  • status.example.com
    • /: ステータス
  • portal.example.com
    • /: 管理画面
雪猫雪猫

データベース設計

要件

REQ フィルターは可変のため事前に TL を構築することができない。
DB 全体からデータを効率よく取得する必要がある。

メタデータ

  • IP アドレス
  • 受信日時
  • 登録情報

選定

Durable Objects SQL Storage, D1, KV, TimescaleDB, その他から選択。
D1 + KV にするのが良さそう。後々他の選択肢も選べるようになるとベター。

Durable Objects は GUI がないのでデータ見るときに大変そう。

設計

D1 にすべてを保存すると容量(上限 10GB)的に厳しいのとおそらく肥大化したときにパフォーマンスが出ない。
イベントは KV (上限なし)に保存しつつ REQ に必要なデータだけ D1 に保存するのが良さそう。

id, pubkey などの SHA256 データは CHAR(64) ではなく BINARY(32) で保存した方がよさそう。

events

KV

  • id => event

D1

[events]

  • id BLOB (32 bytes)
  • pubkey BLOB (32 bytes)
  • kind INTEGER
  • tags TEXT
  • created_at INTEGER

[tags をテーブル分ける場合]

  • id BLOB
  • name TEXT
  • value TEXT
  • created_at INTEGER
SELECT id FROM tags WHERE name = ? AND value = ?;
SELECT * FROM events WHERE pubkey = ?
    AND id IN (SELECT id FROM tags WHERE name = ? AND value = ?) -- #t
    AND id IN (SELECT id FROM tags WHERE name = ? AND value = ?) -- #p
SELECT * FROM events WHERE pubkey = ?
    INNER JOIN tags ON events.id = tags.id AND name = ? AND value = ? -- #t
    INNER JOIN tags ON events.id = tags.id AND name = ? AND value = ? -- #p

connections

KV or D1

  • connection_id TEXT (challenge を使える?)
  • ip_address
  • pubkey

registrations

KV or D1

  • pubkey