Files
Toot-Worker/readme.md
T
2026-05-14 09:59:58 +08:00

6.6 KiB

Toot Worker

一个运行在 Cloudflare Workers 上的单用户联邦宇宙发布软件,使用:

  • Workers: HTTP API、ActivityPub 路由、Mastodon API 兼容层
  • D1: 用户、OAuth 应用、嘟文、媒体索引、关注、收藏、转发、通知、提及、话题标签、远端 actor 缓存
  • R2: 媒体文件
  • KV: OAuth access token 会话

当前目标:让常见 Mastodon App 完成实例发现、创建 OAuth App、登录、上传媒体、发布嘟文、读取公开/家庭时间线、收藏/转发/回复、查看通知、搜索、关注/取关远端账号,同时支持单用户实例与 Fediverse 双向联邦。

本地运行

npm install
npm run db:local
npm run dev

默认管理员账号来自 wrangler.jsonc:

  • 用户名:admin
  • 密码:change-me-before-deploy

部署前必须改掉 ADMIN_PASSWORD,更推荐用 Cloudflare secret 管理密码:

wrangler secret put ADMIN_PASSWORD

PUBLIC_BASE_URL 必须在首次正式部署前改成你的稳定实例域名,例如:

"PUBLIC_BASE_URL": "https://social.example.com"

这个值会进入:

  • Actor ID
  • Object ID
  • WebFinger 返回值
  • 媒体和头像 URL

一旦开始对外联邦后,不要再改域名,否则远端会把你视为另一个实例身份。

Cloudflare 资源

wrangler d1 create toot_db
wrangler r2 bucket create toot-media
wrangler kv namespace create KV

把返回的 ID 填回 wrangler.jsonc,然后应用迁移并部署:

npm run db:remote
npm run deploy

已实现接口

Mastodon API 兼容

实例 / 应用 / 鉴权:

  • GET /api/v1/instanceGET /api/v2/instance
  • POST /api/v1/appsGET /api/v1/apps/verify_credentials
  • GET /oauth/authorizePOST /oauth/authorize
  • POST /oauth/tokenPOST /oauth/revoke

账号:

  • GET /api/v1/accounts/verify_credentials
  • PATCH /api/v1/accounts/update_credentials(自动联邦 Update Person)
  • GET /api/v1/accounts/relationships
  • GET /api/v1/accounts/:id
  • GET /api/v1/accounts/:id/statuses
  • POST /api/v1/accounts/:id/followPOST /api/v1/accounts/:id/unfollow(向远端发送 Follow / Undo)
  • GET /api/v1/follow_requestsPOST /api/v1/follow_requests/:id/authorize/reject(stub,默认全自动接受)

嘟文:

  • POST /api/v1/statuses(支持 media_idsspoiler_textsensitivein_reply_to_idvisibilitylanguage,自动解析 @user/@user@host 提及和 #hashtag,投递 Create 给 followers 与 mention)
  • GET /api/v1/statuses/:idDELETE /api/v1/statuses/:id(联邦 Delete 出站)
  • GET /api/v1/statuses/:id/context
  • POST /api/v1/statuses/:id/favourite/unfavourite(联邦 Like / Undo Like)
  • POST /api/v1/statuses/:id/reblog/unreblog(联邦 Announce / Undo Announce)
  • POST /api/v1/statuses/:id/bookmark/unbookmark/pin/unpin(本地 stub)

时间线 / 通知 / 媒体 / 搜索 / 其它:

  • GET /api/v1/timelines/publicGET /api/v1/timelines/home(分页支持 max_id / since_id / min_id,响应携带 Link 头)
  • GET /api/v1/notificationsPOST /api/v1/notifications/clearPOST /api/v1/notifications/:id/dismiss
  • POST /api/v1/mediaPOST /api/v2/mediaPUT /api/v1/media/:id
  • GET /api/v2/searchGET /api/v1/search(本地账号 / 嘟文 / 话题标签 + 跨站 WebFinger 解析 acct: 查询)
  • GET /api/v1/custom_emojisGET /api/v1/filtersGET /api/v1/trends/tagsGET /api/v1/markers(stub)
  • POST /api/v1/push/subscription(返回 422,目前不支持推送)

ActivityPub / 发现

  • GET /.well-known/webfinger?resource=acct:user@example.com
  • GET /.well-known/nodeinfoGET /.well-known/host-meta
  • GET /nodeinfo/2.0
  • GET /users/:username(含 endpoints.sharedInboxiconimagepublicKey)
  • GET /users/:username/followers/following
  • GET /users/:username/outbox(支持 ?page=true 翻页)
  • POST /users/:username/inboxPOST /inbox(共享 inbox)
  • GET /objects/:id(嘟文已删除时返回 Tombstone,HTTP 410)

入站 inbox 处理类型:Follow / Undo(Follow) / Accept(Follow) / Reject(Follow) / Like / Undo(Like) / Announce / Undo(Announce) / Delete(Note) / Delete(Person) / Update(Person) / Create(Note)(只用于触发提及通知)。Create 用于触发提及通知和回复通知。

安全

  • 密码哈希使用 PBKDF2-SHA256 / 100000 iterations,带每用户随机 16 字节 salt,旧版 salt.hash 哈希也能继续验证(便于无缝升级)。
  • HTTP Signature(rsa-sha256)出站:签名 (request-target)hostdatedigest,自动计算 SHA-256 digest。
  • HTTP Signature 入站验证:
    • 强制要求 Date 头,允许 ±12 小时时钟偏移
    • POST 必须带 Digest,且与 body 哈希一致
    • 通过签名头里的 keyId 取得远端 actor 公钥(并在 actor_cache 表中缓存),拒绝 body.actor 与 actor cache 不一致的请求
    • 验证 host 头匹配请求 URL
  • 远端 actor 公钥与 inbox 写入 actor_cache,默认 24 小时 TTL,远端 Delete(Person) 会清理缓存与所有相关关注 / 收藏 / 转发 / 通知。
  • 重放保护:已处理过的 activity.id 会写入 remote_activities,重复投递被静默丢弃(返回 202)。

数据库结构

迁移文件:

  • migrations/0001_initial.sql — 基础表(users / oauth_apps / oauth_codes / statuses / media / follows / remote_activities)
  • migrations/0002_features.sql — 通知 / 收藏 / 转发 / 提及 / 话题标签 / actor 缓存 / 出站关注 / 删除墓碑 / 嘟文扩展字段(summary / sensitive / language)

重要限制

这是一个单用户可运行实现,不是完整 Mastodon 服务端:

  • 只支持单管理员账号自动初始化,不开放注册
  • 通知 / 收藏 / 转发都已实现,但内容审核、屏蔽、过滤、列表、自定义表情、推送通知仍是 stub
  • 没有处理远端嘟文缓存(收到 Create(Note) 不会存,仅触发提及通知)。意味着客户端的 home timeline 仍只能看到本地嘟文
  • 私信(direct visibility)的检索没有按收信人过滤,目前所有客户端都能在公开时间线之外读到自己的嘟文,不应当作私信使用
  • 没有实现轮询(poll)、列表(list)、推送(push)、未来嘟文(scheduled)等

参考