WebAuthn PRFでNostr秘密鍵を保護する、ローカルファーストのReact SPAです。秘密鍵をランダム生成し、PRF出力からHKDF-SHA-256で導いたAES-256-GCM鍵で暗号化します。平文秘密鍵を表示・コピー・永続化する機能はありません。
- WebAuthn PRF必須のウォレット作成・解除
- Nostrイベントのローカル署名と署名検証
- NIP-46
nostrconnect:///bunker://接続、権限管理、リレー待受 - NIP-07しか使えないサイト向けのオリジン固定ブックマークレット
- NIP-04 / NIP-44暗号化・復号の中継(権限を付与した操作は自動承認、未付与の操作は毎回承認。承認カードの「今後も許可」で恒久権限にでき、接続カードから個別に取り消せます)
- 将来のNIP-57 ZAP要求を載せられる共通承認境界
WebAuthn PRF (32 bytes)
│ HKDF-SHA-256 + random salt + domain separation
▼
non-exportable AES-256-GCM key
│ authenticated decrypt
▼
Nostr secp256k1 secret ── sign / NIP-04 / NIP-44
IndexedDBに保存するのはcredential ID、PRF入力、salt、IV、公開鍵、暗号文と接続メタデータだけです。PRF出力と平文秘密鍵は保存しません。解除後のsignerは2分の非操作、タブの非表示、別タブからのロックで破棄します。例外として、NIP-46リレー待受が有効な間は別タブのクライアントに応答するため自動ロックを保留します(署名・復号の承認は毎回必要です。手動ロックは常に有効です)。
詳細は アーキテクチャ、セキュリティとテスト、プロトコルとZAP を参照してください。
- Node.js 22.12以上
- pnpm 11.1.2
- WebAuthn PRFとuser verificationに対応する認証器・ブラウザ
- 本番ではHTTPS(ローカル開発は
http://localhost)
pnpm install
pnpm dev表示された http://localhost:5173 を開きます。WebAuthn資格情報はRP IDに結びつくため、IPアドレスではなく localhost を使ってください。
- ホームで「この端末にウォレットを作る」を押し、端末の認証を完了します。
- 表示されたnpubを確認し、「署名して検証」でリレー送信なしの署名テストを実行します。
- 「接続」でクライアントの
nostrconnect://URIを貼り、要求権限を絞って接続します。または10分有効のbunker://招待を作ります。 - 「ツール」のボタンをブックマークバーへドラッグし、NIP-07対応サイト上で実行します。開いたKeynestで接続と各要求を承認します。
- 「設定」でRP ID、暗号文の保存先、自動ロック、削除ガードを確認します。
実認証器を使う手動確認では、ブラウザDevToolsのApplication/IndexedDBに平文鍵や nsec がないことも確認してください。
pnpm format # oxfmtで整形
pnpm lint # Oxlintの型付き検査
pnpm typecheck # ルート生成 + TypeScript
pnpm test # Vitestユニット/コンポーネントテスト
pnpm build # 本番SPAビルド
pnpm ready # 上記のリリース前ゲート
pnpm qa:browser # localhost:4173上のブラウザQAブラウザQAを実行する場合は、別ターミナルで pnpm dev --port 4173 を起動し、初回のみ pnpm exec playwright install chromium を実行します。
wrangler.jsonc で dist/ を静的アセットとして配信します(SPAフォールバック付き)。
pnpm build
pnpm dlx wrangler deploy # 初回は wrangler login が必要WebAuthn資格情報はデプロイ先ホスト名(RP ID)に結び付きます。Worker名やドメインを変えると既存ウォレットは解除できなくなるため、恒久運用するホスト名を決めてから実資産に使ってください。
- PRFが取得できない環境にパスワード等の弱いフォールバックはしません。
- 配置先のRP ID変更、ブラウザデータ削除、認証器紛失後の復元機能はありません。現時点で実資産の唯一の保管先には向きません。
- SPAを閉じたりブラウザが休止したりすると、NIP-46 signerは待受できません。
- JavaScriptではコピー済みメモリの完全消去を保証できません。所有バッファは上書きしますが、保証範囲は設計資料に明記しています。
- Lightning請求・支払いは未実装です。現状のZAP対応は署名・承認境界の先行設計までです。
src/features/vault/ WebAuthn、HKDF/AES-GCM、IndexedDB、ロック
src/features/signing/ Nostr署名と入力境界
src/features/requests/ NIP-46/NIP-07/ZAP共通承認キュー
src/features/nip46/ URI、権限、RPC、リレーruntime
src/features/nip07/ bookmarkletとpopup bridge
src/routes/ TanStack RouterのSPA画面
サーバーサイドのコードはありません。