Skip to content

feat: nodeinfo / OSV 脆弱性ウィジェットを追加 - #48

Merged
hitalin merged 2 commits into
mainfrom
feat/widgets-nodeinfo-osv
Aug 14, 2026
Merged

hitalin merged 2 commits into
mainfrom
feat/widgets-nodeinfo-osv

Conversation

@hitalin

@hitalin hitalin commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Fediverse サーバー調査とパッケージ脆弱性照会のウィジェットを 2 つ追加します。どちらも認証不要の公開 API で、コミットは種別ごとに分けてあります。

nodeinfo (widgets/nodeinfo)

任意の Fediverse サーバーの nodeinfo を引いて、ソフトウェア・バージョン・規模・登録受付状態を表示します。既存の server-info が自サーバー固定なのに対し、こちらは相手サーバーを調べる用途です。

  • 接続先: https://<入力ホスト>/.well-known/nodeinfo → そこが指す nodeinfo 本体 (2.1 優先、無ければ 2.0)
  • なぜ 2 段: 本体パスは実装ごとに違う (Pleroma は /nodeinfo/2.1.json) ため discovery は省略できません
  • href の扱い: discovery が返す href は相手が自由に決める値なので、調査対象ホスト自身の https:// URL 以外は捨てます (別ドメインへ取りに行かせない)
  • 表示前のサニタイズ: nodeName も相手の自由入力なので $ [ ] * < > を全角へ。nodeDescription は HTML 混じりで無害化コストが高いため最初から表示しません
  • 保存のタイミング: ホストの保存は取得成功後。名前が引けないホストで Nd:http が落ちたとき、その値が次回起動でも読まれてウィジェットが復旧不能になるのを避けています

OSV 脆弱性 (widgets/osv-vulns)

OSV.dev にパッケージ名を投げて既知脆弱性を新しい順に表示します。既定は Misskey 公式 JS SDK の npm:misskey-js。既存の cve ウィジェットが NVD の直近 N 日を眺める CVE 番号起点なのに対し、こちらはパッケージ起点で引きます。

  • 接続先: POST https://api.osv.dev/v1/query (API キー不要)
  • 本文の組み立て: Json:stringify で組みます。パッケージ名を文字列連結すると本文を捏造できるため。加えて validPkg で許可文字を制限し、"\ を弾いた値だけをリンク生成にも通します
  • 表示前のサニタイズ: summary も第三者テキストなので $ [ ] * < > を全角へ
  • 性能: 並べ替えキーは 1 件 1 回だけ作ります。sort の比較関数から呼ぶと PyPI:Django (320 件) で 12 秒かかりました。桁の切り出しも 1 文字ずつのループをやめて to_num に任せ、同条件で 0.5 秒未満に収めています

共通

  • Json:parse は失敗時に throw せず error 値を返すため、obj 以外は null に潰しています。Fediverse でないホストが HTML を返しても壊れません
  • 応答サイズに上限を設け、桁違いのものはパースせず捨てます
  • 自動更新はどちらも 6 時間おき (内容がほぼ静的なため)

動作確認

AiScript 1.2.1 のハーネスで純粋関数を検証 (nodeinfo 48 ケース / OSV 48 ケース、いずれも全パス) し、Nd:http を実 fetch に差し替えた通し実行で表示を確認しました。

  • nodeinfo: misskey.io / misskey.design / mastodon.social / mstdn.jp / pleroma.soykaf.com / transfem.social (Sharkey)、および nodeinfo を持たないホスト (HTTP 404 表示)
  • OSV: npm:misskey-js (2 件) / npm:misskey-reversi (0 件) / npm:next (64 件) / PyPI:Django (320 件)

pnpm registry:buildcheck-registry-integrity.mjs は緑です。

🤖 Generated with Claude Code

hitalin and others added 2 commits August 15, 2026 03:32
任意の Fediverse サーバーの nodeinfo を引いて、ソフトウェア・バージョン・
規模・登録受付状態を表示する。既存の server-info が自サーバー固定なのに対し、
こちらは相手サーバーを調べる用途。認証不要で応答も数 KB。

- discovery (/.well-known/nodeinfo) は省略できない。本体パスは実装ごとに
  違う (Pleroma は /nodeinfo/2.1.json)。2.1 を優先し、無ければ 2.0
- discovery が返す href は相手が自由に決める値なので、調査対象ホスト自身の
  https URL 以外は捨てる。別ドメインへ取りに行かせない
- nodeName も相手の自由入力なので $ [ ] * < > を全角へサニタイズ。
  nodeDescription は HTML 混じりで無害化コストが高く、最初から表示しない
- Json:parse は失敗時に throw せず error 値を返すため obj 以外は null に潰し、
  200KB 超の応答はパースせず捨てる
- ホストの保存は取得成功後。名前が引けないホストで Nd:http が落ちたとき、
  その値が次回起動でも読まれてウィジェットが復旧不能になるのを避ける

misskey.io / misskey.design / mastodon.social / mstdn.jp /
pleroma.soykaf.com / transfem.social (Sharkey) で表示を確認。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
OSV.dev にパッケージ名を投げて既知脆弱性を新しい順に表示する。既定は
Misskey 公式 JS SDK の npm:misskey-js。既存の cve ウィジェットが NVD の
直近 N 日を眺める CVE 番号起点なのに対し、こちらはパッケージ起点で引く。

- POST /v1/query の本文は Json:stringify で組む。パッケージ名を文字列連結
  すると本文を捏造できるため。加えて validPkg で許可文字を制限し、" と \
  を弾いた値だけをリンク生成にも通す
- ecosystem の綴りは OSV 側で厳密 ("PyPI" / "crates.io" / "RubyGems") なので
  select で固定。0 件のときの応答は {} (vulns キーごと無い)
- 並べ替えキーは 1 件 1 回だけ作る。sort の比較関数から呼ぶと PyPI:Django
  (320 件) で 12 秒かかる。桁の切り出しも 1 文字ずつのループをやめて to_num
  に任せ、同条件で 0.5 秒未満に収めた
- summary は表示前に $ [ ] * < > を全角へサニタイズ
- published は同日に複数出る (npm:next) ので秒まで見て並べる

npm:misskey-js (2 件) / npm:misskey-reversi (0 件) / npm:next (64 件) /
PyPI:Django (320 件) で表示と所要時間を確認。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hitalin
hitalin merged commit 5a17137 into main Aug 14, 2026
1 check passed
@hitalin
hitalin deleted the feat/widgets-nodeinfo-osv branch August 14, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant