Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
atproto — Форк эталонной реализации AT Protocol с оптимизированным по производительности AppView, индексером firehose на Rust, кэшированием Redis и функциями сообщества для самостоятельного хостинга социальных сетей в масштабе. | Kitploit
Инструменты/GitHubGitHub/blacksky-algorithms/atproto
Безопасность облачной инфраструктурыАудит конфигурацииОбнаружение СекретовУправление идентификацией и доступом (IAM)АутентификацияНеправильная КонфигурацияБезопасность APIБезопасность Баз ДанныхАнализ Журналов
GitHubblacksky-algorithms/atproto

atproto

Форк эталонной реализации AT Protocol с оптимизированным по производительности AppView, индексером firehose на Rust, кэшированием Redis и функциями сообщества для самостоятельного хостинга социальных сетей в масштабе.

Репозиторий
94367 дней назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Blacksky AppView

Это форк эталонной реализации AT Protocol от Blacksky, созданный компанией Bluesky Social PBC. Он обеспечивает работу AppView по адресу api.blacksky.community.

Мы публикуем этот код для прозрачности и чтобы другие сообщества могли воспользоваться нашей работой. Этот репозиторий не принимает вклады, issues или PR. Если вам нужна каноническая реализация atproto, используйте bluesky-social/atproto.

Что отличается

Все изменения находятся в packages/bsky (логика AppView), services/bsky (конфигурация времени выполнения) и одной пользовательской миграции. Всё остальное — из вышестоящего репозитория.

Почему не встроенный потребитель Firehose?

В вышестоящем dataplane входит потребитель firehose на TypeScript (subscription.ts), который индексирует события напрямую. Мы заменили его на — индексатор на Rust, по нескольким причинам:

rsky-wintermute
  • Производительность при масштабировании: Потребитель на TypeScript обрабатывает события последовательно. При сетевом масштабе (~1 000 событий/сек, 18,5 миллиардов записей в сумме) полная обратная загрузка (~90 записей/сек) заняла бы 6,5 лет. Wintermute нацелен на 10 000+ записей/сек с параллельной обработкой очередей.
  • Архитектура обратной загрузки: Wintermute разделяет live-индексацию и обратную загрузку в независимые очереди (firehose_live, firehose_backfill, repo_backfill, labels). События live-режима никогда не блокируются работой по обратной загрузке.
  • Эксплуатационные инструменты: Wintermute включает утилиты для прямой индексации конкретных аккаунтов, массового импорта из PLC-каталога, повторного воспроизведения потока меток, восстановления blob-ссылок и управления очередями — всё это необходимо при начальной настройке AppView с нуля.

Dataplane и AppView из этого репозитория по-прежнему работают как есть. Они читают из базы данных PostgreSQL, в которую пишет wintermute. Мы просто не запускаем встроенную подписку на firehose.

Исправления производительности и эксплуатации

Эти исправления полезны всем, кто разворачивает AppView самостоятельно.

Оптимизация запросов с LATERAL JOIN (packages/bsky/src/data-plane/server/routes/feeds.ts)

  • getTimeline и getListFeed переписаны с использованием PostgreSQL LATERAL JOIN, чтобы принудительно использовать индексы по пользователям вместо полного сканирования таблиц. Значительное улучшение для пользователей, следящих за тысячами аккаунтов.

Кэширующий слой Redis (packages/bsky/src/data-plane/server/cache/)

  • Профили акторов (TTL 60 с), записи (5 мин), счетчики взаимодействий (30 с), метаданные постов (5 мин)
  • Снижает нагрузку на базу данных при продакшн-трафике
  • Известная проблема: В кэше акторов есть ошибка сериализации protobuf-меток времени: после JSON-передачи через Redis объекты Timestamp теряют метод .toDate(), что приводит к неполной гидратации профилей при попадании в кэш. В настоящее время мы работаем с отключённым кэшированием Redis. Исправление: сериализовать метки времени как ISO-строки при записи в кэш и восстанавливать при чтении.

Серверное применение предпочтений уведомлений (packages/bsky/src/api/app/bsky/notification/listNotifications.ts)

  • Когда клиент не указывает reasons, сервер применяет сохранённые предпочтения уведомлений пользователя. Без этого предпочтения применяются только на стороне клиента и не имеют эффекта.

Исправление устаревшего ключа подписи в верификаторе аутентификации (packages/bsky/src/auth-verifier.ts)

  • При повторной попытке верификации JWT (forceRefresh) обходится кэш идентификаторов dataplane в памяти и DID-документ напрямую запрашивается из PLC-каталога. Исправляет ошибки аутентификации после миграции аккаунта, когда ключ подписи меняется, но в кэше остаётся старый.

Очистка JSON (packages/bsky/src/data-plane/server/routes/records.ts)

  • Из хранимых записей перед парсингом JSON удаляются нулевые байты (\u0000) и управляющие символы. Они допустимы по RFC 8259, но отвергаются JSON.parse() в Node.js, что приводит к незаметным сбоям rowToRecord в dataplane, которые проявляются как отсутствующие посты.

Сообщества (специфично для Blacksky)

Инфраструктура для приватных постов сообщества, которые хранятся в AppView, а не на отдельных PDS. Специфично для того, как работает Blacksky, но может служить примером для других сообществ.

  • Пользовательское пространство лексикона community.blacksky.feed.* с конечными точками для отправки, получения, удаления, ленты и просмотра тредов
  • Отдельная таблица community_post (миграция: 20260202T120000000Z-add-community-post.ts)
  • Проверка членства на уровне dataplane и API
  • Интеграция с getPostThreadV2 для смешанных тредов из стандартных и сообщественных постов
  • Требует отдельной базы данных членства (BLACKSKY_MEMBERSHIP_DB_URL)

Архитектура

root@kitploit:~
Bluesky Relay (bsky.network)
     |
     v
rsky-wintermute -----> PostgreSQL 17 <----- Palomar
  (индексатор на Rust)        |                (поиск на Go)
  - потребитель firehose      |                     |
  - обратная загрузка         |                     v
  - индексатор меток          |               OpenSearch
  - прямая индексация         |
                            v
                    bsky-dataplane (gRPC :2585) <--- Redis (опционально)
                            |
                            v
                    bsky-appview (HTTP :2584)
                            |
                            v
                    Обратный прокси (Caddy/nginx)

Обзор компонентов

КомпонентИсходный кодНазначение
rsky-wintermuteblacksky-algorithms/rskyИндексатор firehose на Rust: потребляет события, выполняет обратную загрузку репозиториев, индексирует записи в PostgreSQL
rsky-relayblacksky-algorithms/rskyРеле AT Protocol для получения меток модерации от сервисов-лейблеров
rsky-videoblacksky-algorithms/rskyСервис загрузки видео: транскодирование через Bunny Stream CDN, загрузка blob-ссылок в PDS пользователя
bsky-dataplaneЭтот репозиторий (services/bsky)Уровень данных gRPC поверх PostgreSQL
bsky-appviewЭтот репозиторий (services/bsky)HTTP-сервер API для конечных точек XRPC app.bsky.*
Palomarblacksky-algorithms/indigoПолнотекстовый поиск: индексирует профили и посты в OpenSearch с учётом количества подписчиков
palomar-syncblacksky-algorithms/rskyСинхронизирует количество подписчиков и оценки PageRank из PostgreSQL в OpenSearch

rsky-wintermute подробно

Wintermute — монолитная служба на Rust с четырьмя параллельными путями обработки:

  • Ingester: Подключается к firehose bsky.network через WebSocket, записывает события в очереди Fjall (встраиваемое key-value хранилище)
  • Indexer: Читает из очередей, разбирает записи, записывает в PostgreSQL с ON CONFLICT для идемпотентности
  • Backfiller: Загружает полные CAR-файлы репозиториев из PDS, распаковывает записи в очередь обратной загрузки
  • Label indexer: Подписывается на потоки WebSocket лейблеров, обрабатывает события создания/отмены меток

Дополнительные CLI-инструменты, включённые в репозиторий rsky:

  • queue_backfill — поставить DID в очередь обратной загрузки из CSV, из обнаружения PDS или прямого списка DID
  • direct_index — загрузить и проиндексировать конкретные репозитории, минуя очереди (полезно для исправления отдельных аккаунтов)
  • label_sync — повторно воспроизвести потоки меток с курсора 0, чтобы наверстать пропущенные отмены
  • plc_import — массовый импорт соответствий handle/DID из PLC-каталога
  • palomar-sync — синхронизировать количество подписчиков и PageRank в OpenSearch

rsky-video

Сервис загрузки видео для пользователей, чей PDS не поддерживает video.bsky.app от Bluesky. Использует собственный DID (did:web:video.blacksky.community) для аутентификации в PDS пользователя через JWT служебной аутентификации. Процесс:

  1. Клиент получает токен служебной аутентификации от PDS (аудитория: DID сервиса видео)
  2. Клиент загружает байты видео в rsky-video
  3. rsky-video генерирует CID, загружает blob в PDS пользователя
  4. Видео отправляется в Bunny Stream CDN для транскодирования
  5. По завершении клиент создаёт пост со ссылкой на blob — PDS проверяет наличие blob

Обработка меток

Метки модерации поступают от сервисов-лейблеров (например, Ozone от Bluesky) через подписку WebSocket. Ingester от Wintermute обрабатывает метки в выделенной очереди label_live (малый объём, отдельно от основного firehose). Инструмент label_sync может воспроизвести полный поток лейблера, чтобы наверстать пропущенные отмены меток (удаление меток) без повторной вставки меток.

Настройка

Предварительные требования

  • Node.js 18+ и pnpm (для сборки dataplane и appview)
  • PostgreSQL 17 со схемой bsky
  • Redis (опционально, для кэширования — см. известную проблему выше)
  • rsky-wintermute, потребляющий firehose и заполняющий базу данных
  • OpenSearch (если используется поиск Palomar)

База данных

Схема bsky создаётся миграциями dataplane. При первом запуске dataplane автоматически применит все миграции. Единственная специфичная для Blacksky миграция — 20260202T120000000Z-add-community-post.ts (таблица сообщений сообщества). Если вам не нужны сообщения сообщества, удалите её.

rsky-wintermute пишет в ту же схему. Все его INSERT используют ON CONFLICT, поэтому безопасно запускать wintermute и миграции dataplane в любом порядке.

Сборка

root@kitploit:~
pnpm install
pnpm build

Запуск Dataplane

root@kitploit:~
node services/bsky/dataplane.js
ПеременнаяОбязательноОписание
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)

Запуск AppView

root@kitploit:~
node services/bsky/api.js
ПеременнаяОбязательноОписание
BSKY_APPVIEW_PORTНетПорт HTTP (по умолчанию 2584)
BSKY_DATAPLANE_URLSДаURL gRPC dataplane через запятую
BSKY_DIDДаDID AppView (например, did:web:api.example.com)
BSKY_MOD_SERVICE_DIDДаDID модерационного сервиса Ozone
BSKY_ADMIN_PASSWORDSДаПароли администраторов через запятую для базовой аутентификации

Эксплуатация в масштабе

Время обратной загрузки

Полная обратная загрузка всей сети (все ~42 млн пользователей, ~18,5 млрд записей) занимает недели даже при параллельной обработке wintermute. Ожидайте:

  • Live-индексация: Поддерживает работу в реальном времени с первого дня (~1 000 событий/сек)
  • Полная обратная загрузка: 2–4 недели при 10 000 записей/сек в зависимости от отзывчивости PDS и состояния сети
  • Частичная обратная загрузка: От нескольких часов до нескольких дней для подмножества пользователей (например, только члены сообщества)

Во время обратной загрузки AppView работает, но будет показывать неполные данные для пользователей, которые ещё не обработаны. Live-события индексируются немедленно независимо от прогресса обратной загрузки.

Проблемы, которые мы решили на этом пути

Это проблемы, с которыми мы столкнулись при начальной настройке AppView для всей сети. Если вы делаете то же самое, вы, вероятно, столкнётесь с некоторыми из них:

Повреждение JSON в текстовом формате COPY: Текстовый протокол COPY в PostgreSQL обрабатывает обратную косую черту как escape-символ. Если ваш массовый загрузчик не экранирует обратную косую черту в JSON-строках, \" становится ", и вы получаете незаметно повреждённые записи. Столбец record.json имеет тип text (не jsonb), поэтому PostgreSQL не обнаружит этого. Мы нашли ~66 000 повреждённых записей и пришлось их восстанавливать, повторно загружая из публичного API.

Нулевые байты в JSON: Некоторые записи AT Protocol содержат \u0000 (нулевой байт), что является допустимым JSON по RFC 8259, но отвергается JSON.parse() в Node.js. Dataplane молча возвращает null для таких записей. Удаляйте нулевые байты перед записью в базу данных.

Чувствительность к формату временных меток: Dataplane ожидает временные метки с точностью до миллисекунд и суффиксом Z (2026-01-12T19:45:23.307Z). С точностью до наносекунды или в формате смещения часового пояса (+00:00) это вызывает тонкие проблемы сортировки и сравнения.

Разрастание таблицы уведомлений: Без уникального ограничения на (did, recordUri, reason) таблица уведомлений бесконечно растёт с дубликатами. Наша достигла 1,3 миллиарда строк (663 ГБ), прежде чем мы это заметили. Добавление ON CONFLICT DO NOTHING в INSERT помогает только в том случае, если уникальный индекс существует заранее, а создание индекса требует дедупликации существующих данных.

Таблицы вложений постов: Таблицы post_embed_image и post_embed_video не заполняются по умолчанию, если ваш индексатор их не обрабатывает. Без них медиа-фильтр в getAuthorFeed ничего не возвращает. Их нужно заполнять отдельно.

Порядок отмены меток: События отмены меток (удаление) ссылаются на оригинальную метку по источнику, URI и значению. Если отмена приходит раньше оригинальной метки (часто при обратной загрузке), она молча отбрасывается. Инструмент label_sync воспроизводит полный поток, чтобы отловить такие случаи.

Отравление очередей Fjall: Встроенная база данных Fjall (используется для очередей wintermute) может перейти в «отравленное» состояние после сбоев, блокируя все операции с очередями. Исправление: удалите каталог с очередями и перезапустите — wintermute наверстает упущенное с курсора реле (реле хранят около 72 часов истории).

Инициализация провайдера TLS: rustls требует явной установки криптопровайдера перед любым TLS-соединением. Без rustls::crypto::aws_lc_rs::default_provider().install_default() при запуске первое WebSocket-соединение с firehose вызывает панику.

Смена ключа подписи после миграции аккаунта: Когда пользователи переходят между PDS, их ключ подписи меняется. Dataplane кэширует данные идентификации с staleTTL в 1 час. В течение этого окна верификация JWT для мигрированных пользователей завершается ошибкой. Исправление: обходить кэш при повторной попытке верификации и напрямую запрашивать данные из PLC-каталога.

Требования к ресурсам

На основе работы AppView для всей сети (все ~42 млн пользователей, ~18,5 млрд записей).

РесурсМинимумРекомендуется
CPU16 ядер48+ ядер
RAM64 ГБ256 ГБ
Накопитель10 ТБ NVMe28+ ТБ NVMe (RAID)
PostgreSQLВыделенный, на той же машине или с низкой задержкойРекомендуется та же машина
СетьСтабильные 100 Мбит/с1+ Гбит/с

Распределение хранилища (приблизительно, для всей сети):

Группа таблицРазмер
Посты + записи~3,5 ТБ
Лайки~2 ТБ
Подписки~500 ГБ
Уведомления~600 ГБ
Индексы~4 ТБ
OpenSearch (Palomar)~500 ГБ

Для небольшого сообщества, работающего с частичным 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.

Скачать инструмент