Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
atproto — AT协议参考实现的一个分支,包含性能优化的AppView、基于Rust的firehose索引器、Redis缓存,以及面向大规模自托管社交网络的社区功能。 | Kitploit
工具/GitHubGitHub/blacksky-algorithms/atproto
云基础设施安全配置审计秘密检测身份与访问管理 (IAM)身份验证错误配置API 安全数据库安全日志分析
GitHubblacksky-algorithms/atproto

atproto

AT协议参考实现的一个分支,包含性能优化的AppView、基于Rust的firehose索引器、Redis缓存,以及面向大规模自托管社交网络的社区功能。

9436天前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
查看仓库

Blacksky AppView

这是Blacksky社区对AT协议参考实现(由Bluesky Social PBC开发)的一个分支。它驱动着位于 api.blacksky.community 的 AppView。

我们发布此代码是为了透明,并让其他社区也能从中受益。本仓库不接受贡献、issue 或 PR。 如果你需要规范的 atproto 实现,请使用 bluesky-social/atproto。

不同之处

所有变更都在 packages/bsky(AppView 逻辑)、services/bsky(运行时配置)以及一个自定义迁移文件中。其余部分均与上游保持一致。

为何不使用内置的 Firehose Consumer?

上游数据平面包含一个 TypeScript 编写的 firehose consumer(subscription.ts),用于直接索引事件。我们将其替换为 rsky-wintermute,一个 Rust 编写的索引器,原因如下:

  • 大规模性能:TypeScript consumer 按顺序处理事件。在网络规模下(约 1,000 事件/秒,总计 185 亿条记录),以约 90 条记录/秒的速度进行完整回填需要 6.5 年。Wintermute 目标为 10,000+ 记录/秒,并支持并行队列处理。
  • 回填架构:Wintermute 将实时索引与回填分离为独立的队列(firehose_live、firehose_backfill、repo_backfill、labels)。实时事件永远不会被回填任务阻塞。
  • 运维工具:Wintermute 包含用于直接索引特定账号、PLC 目录批量导入、标签流重放、blob 引用修复和队列管理的工具——这些在从头启动 AppView 时都是必需的。

本仓库中的数据平面和 AppView 仍然按原样运行。它们读取 wintermute 写入的 PostgreSQL 数据库。我们只是没有启动内置的 firehose 订阅。

性能与运维修复

这些修复对任何需要大规模自托管 AppView 的人都非常有用。

LATERAL JOIN 查询优化(packages/bsky/src/data-plane/server/routes/feeds.ts)

  • 使用 PostgreSQL LATERAL JOIN 重写了 getTimeline 和 getListFeed,强制每个用户使用索引,避免全表扫描。对于关注数千个账号的用户来说,性能提升显著。

Redis 缓存层(packages/bsky/src/data-plane/server/cache/)

  • 用户资料(60s TTL)、记录(5m)、交互计数(30s)、帖子元数据(5m)
  • 减少生产流量下的数据库负载
  • 已知问题:actor 缓存存在 protobuf 时间戳序列化 bug,Timestamp 对象在经过 Redis 的 JSON 往返后丢失了 .toDate() 方法,导致缓存命中时资料补全不完整。我们目前运行时不启用 Redis 缓存。修复方法是在缓存写入时将时间戳序列化为 ISO 字符串,并在读取时重建。

服务器端强制通知偏好(packages/bsky/src/api/app/bsky/notification/listNotifications.ts)

  • 当客户端未指定 reasons 时,服务器应用用户保存的通知偏好。没有这个设置,偏好仅在客户端生效,实际上不起作用。

认证验证器陈旧签名密钥修复(packages/bsky/src/auth-verifier.ts)

  • 在 JWT 验证重试(forceRefresh)时,绕过数据平面内存中的身份缓存,直接从 PLC 目录解析 DID 文档。修复了账号迁移后签名密钥轮换但缓存仍保留旧密钥导致的认证失败问题。

JSON 清理(packages/bsky/src/data-plane/server/routes/records.ts)

  • 在 JSON 解析前,从存储的记录中剥离空字节(\u0000)和控制字符。这些字符在 RFC 8259 中是合法的,但会被 Node.js 的 JSON.parse() 拒绝,导致数据平面中 rowToRecord 解析静默失败,最终表现为帖子缺失。

社区帖子(Blacksky 特有)

用于私有社区帖子的基础设施,这些帖子存储在 AppView 而非各个 PDS 上。这是 Blacksky 的工作方式,但也可以作为其他社区的参考。

  • 自定义词汇表命名空间 community.blacksky.feed.*,包含提交、获取、删除、时间线和帖子视图的端点
  • 独立的 community_post 表(迁移文件:20260202T120000000Z-add-community-post.ts)
  • 在数据平面和 API 层实施了成员资格限制
  • 与 getPostThreadV2 集成,支持标准/社区帖子的混合线程
  • 需要独立的成员资格数据库(BLACKSKY_MEMBERSHIP_DB_URL)

架构

root@kitploit:~
Bluesky 中继 (bsky.network)
     |
     v
rsky-wintermute -----> PostgreSQL 17 <----- Palomar
  (Rust 索引器)            |                (Go 搜索)
  - firehose consumer      |                     |
  - backfiller             |                     v
  - label indexer          |               OpenSearch
  - direct indexer         |
                            v
                    bsky-dataplane (gRPC :2585) <--- Redis (可选)
                            |
                            v
                    bsky-appview (HTTP :2584)
                            |
                            v
                    反向代理 (Caddy/nginx)

组件概览

rsky-wintermute 详解

Wintermute 是一个单体 Rust 服务,包含四个并行处理路径:

  • Ingester:通过 WebSocket 连接到 bsky.network firehose,将事件写入 Fjall(嵌入式键值存储)队列
  • Indexer:从队列读取数据,解析记录,使用 ON CONFLICT 写入 PostgreSQL(幂等性)
  • Backfiller:从 PDS 获取完整的仓库 CAR 文件,将记录解包后放入回填队列
  • Label indexer:订阅 labeler WebSocket 流,处理标签创建/撤销事件

rsky 仓库中还包含以下 CLI 工具:

  • queue_backfill —— 通过 CSV、PDS 发现或直接 DID 列表将要回填的 DID 加入队列
  • direct_index —— 绕过队列直接获取并索引特定仓库(适用于修复单个账号)
  • label_sync —— 从游标 0 开始重放标签流,以捕获遗漏的撤销事件
  • plc_import —— 从 PLC 目录批量导入 handle/DID 映射
  • palomar-sync —— 将粉丝数和 PageRank 同步到 OpenSearch

rsky-video

为那些 PDS 不支持 Bluesky 的 video.bsky.app 的用户提供的视频上传服务。使用自己的 DID(did:web:video.blacksky.community)通过服务认证 JWT 向用户 PDS 进行身份验证。流程如下:

  1. 客户端从 PDS 获取服务认证令牌(目标受众:视频服务 DID)
  2. 客户端将视频字节上传到 rsky-video
  3. rsky-video 生成一个 CID,将 blob 上传到用户的 PDS
  4. 视频转发至 Bunny Stream CDN 进行转码
  5. 转码完成后,客户端创建引用该 blob 的帖子——PDS 验证 blob 是否存在

标签处理

审核标签来自 labeler 服务(例如 Bluesky 的 Ozone),通过 WebSocket 订阅获取。Wintermute 的 ingester 在专用的 label_live 队列中处理标签(低流量,与主 firehose 分开)。label_sync 工具可以重放 labeler 的完整流,以捕获遗漏的撤销事件(标签移除),而无需重新插入标签。

部署设置

前置条件

  • Node.js 18+ 和 pnpm(用于构建数据平面和 AppView)
  • PostgreSQL 17 并包含 bsky 模式
  • Redis(可选,用于缓存——见已知问题)
  • rsky-wintermute 消费 firehose 并填充数据库
  • OpenSearch(如果运行 Palomar 搜索)

数据库

bsky 模式由数据平面的迁移脚本创建。首次运行时,数据平面会自动应用所有迁移。唯一一个 Blacksky 特有的迁移是 20260202T120000000Z-add-community-post.ts(社区帖子表)。如果不需要社区帖子,可以将其移除。

rsky-wintermute 也写入同一个模式。其所有 INSERT 语句都使用 ON CONFLICT,因此按任何顺序运行 wintermute 和数据平面迁移都是安全的。

构建

root@kitploit:~
pnpm install
pnpm build

运行数据平面

root@kitploit:~
node services/bsky/dataplane.js

运行 AppView

root@kitploit:~
node services/bsky/api.js

大规模运维

回填时间线

即使使用 wintermute 的并行处理,全网络回填(全部约 4200 万用户、约 185 亿条记录)也需要数周时间。预期如下:

  • 实时索引:从第一天起即可实时保持更新(约 1,000 事件/秒)
  • 完全回填:在 10,000 记录/秒的速度下,需 2-4 周,具体取决于 PDS 响应速度和网络状况
  • 部分回填:对于用户子集(例如仅社区成员),需要数小时到数天

在回填期间,AppView 可以正常工作,但尚未回填的用户数据将显示不完整。实时事件无论回填进度如何都会立即索引。

我们在此过程中解决的问题

以下是我们启动全网络 AppView 时遇到的问题。如果你正在做同样的事情,很可能也会遇到其中一些:

COPY 文本格式 JSON 损坏:PostgreSQL 的 COPY 文本协议将反斜杠视为转义字符。如果批量加载器没有转义 JSON 字符串中的反斜杠,\" 会变成 ",导致记录被静默损坏。record.json 列的类型是 text(不是 jsonb),因此 PostgreSQL 不会检测到这个问题。我们发现约 66,000 条记录被损坏,不得不通过从公共 API 重新获取来修复。

JSON 中的空字节:部分 AT 协议记录包含 \u0000(空字节),这在 RFC 8259 中是合法的 JSON,但 Node.js 的 JSON.parse() 会拒绝。数据平面对于这些记录会静默返回 null。在写入数据库之前应剥离空字节。

时间戳格式敏感性:数据平面期望时间戳具有毫秒精度和 Z 后缀(2026-01-12T19:45:23.307Z)。纳秒精度或时区偏移格式(+00:00)会导致微妙的排序和比较问题。

通知表膨胀:如果没有对 (did, recordUri, reason) 设置唯一约束,通知表会无限增长,出现重复记录。我们的通知表增长到了 13 亿行(663 GB)才被发现。在 INSERT 中添加 ON CONFLICT DO NOTHING 仅在唯一索引已存在时有效,而创建索引需要先对现有数据进行去重。

帖子嵌入表:如果索引器不处理,post_embed_image 和 post_embed_video 表默认不会被填充。没有这些表,getAuthorFeed 上的媒体过滤器会返回空结果。需要单独回填这些表。

标签撤销顺序:标签撤销(移除)事件通过来源、URI 和值来引用原始标签。如果撤销事件在原始标签之前到达(在回填时很常见),它们会被静默丢弃。label_sync 工具可以重放完整流来捕获这些事件。

Fjall 队列中毒:Fjall 嵌入式数据库(用于 wintermute 的队列)在崩溃后可能进入“中毒”状态,阻塞所有队列操作。修复方法是删除队列数据库目录并重启——wintermute 会从中继的游标处开始追赶(中继保留约 72 小时的历史数据)。

TLS 提供者初始化:Rust 的 rustls 需要在任何 TLS 连接之前显式安装加密提供者。如果没有在启动时调用 rustls::crypto::aws_lc_rs::default_provider().install_default(),第一次 WebSocket 连接到 firehose 就会 panic。

账号迁移后的签名密钥轮换:当用户在不同 PDS 之间迁移时,他们的签名密钥会改变。数据平面会缓存身份数据,staleTTL 为 1 小时。在此期间,迁移用户的 JWT 验证会失败。修复方法是在验证重试时绕过缓存,直接从 PLC 目录解析。

资源需求

基于运行全网络 AppView(全部约 4200 万用户、约 185 亿条记录)的经验。

存储细分(近似值,全网络):

表组大小

对于运行部分 AppView(仅索引社区成员)的小型社区,资源需求大致与索引账号数量成线性关系。

与上游同步

root@kitploit:~
git remote add upstream https://github.com/bluesky-social/atproto.git
git fetch upstream
git merge upstream/main

冲突通常发生在 packages/bsky/src/data-plane/server/routes/ 和 packages/bsky/src/api/ 中。解决方式是在保留上游更改的同时保留我们的添加项。

许可证

与上游相同:采用 MIT 和 Apache 2.0 双许可证。详见 LICENSE-MIT.txt 和 LICENSE-APACHE.txt。

下载工具
组件来源用途
rsky-wintermuteblacksky-algorithms/rskyRust firehose 索引器:消费事件、回填仓库、将记录索引到 PostgreSQL
rsky-relayblacksky-algorithms/rskyAT 协议中继,用于接收来自 labeler 服务的审核标签
rsky-videoblacksky-algorithms/rsky视频上传服务:通过 Bunny Stream CDN 转码,将 blob 引用上传到用户 PDS
bsky-dataplane本仓库 (services/bsky)基于 PostgreSQL 的 gRPC 数据层
bsky-appview本仓库 (services/bsky)为 app.bsky.* XRPC 端点提供的 HTTP API 服务器
Palomarblacksky-algorithms/indigo全文搜索:将用户资料和帖子索引到 OpenSearch,并支持粉丝数加权
palomar-syncblacksky-algorithms/rsky将粉丝数和 PageRank 分数从 PostgreSQL 同步到 OpenSearch
变量必需描述
DB_PRIMARY_URL是PostgreSQL 连接字符串,需附加 ?options=-csearch_path%3Dbsky
DB_REPLICA_URL否只读副本连接字符串
BSKY_DATAPLANE_PORT否gRPC 端口(默认 2585)
BSKY_REDIS_HOST否Redis 主机:端口,用于缓存(当前建议保持禁用)
BLACKSKY_MEMBERSHIP_DB_URL否社区成员资格独立数据库(Blacksky 特有)
变量必需描述
BSKY_APPVIEW_PORT否HTTP 端口(默认 2584)
BSKY_DATAPLANE_URLS是数据平面 gRPC URL,逗号分隔
BSKY_DID是AppView 的 DID(例如 did:web:api.example.com)
BSKY_MOD_SERVICE_DID是Ozone 审核服务 DID
BSKY_ADMIN_PASSWORDS是管理员密码,逗号分隔(用于基本认证)
资源最低配置推荐配置
CPU16 核48+ 核
RAM64 GB256 GB
存储10 TB NVMe28+ TB NVMe(RAID)
PostgreSQL专用服务器,同一机器或低延迟建议同一机器
网络持续 100 Mbps1 Gbps+
帖子 + 记录~3.5 TB
点赞~2 TB
关注~500 GB
通知~600 GB
索引~4 TB
OpenSearch(Palomar)~500 GB