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 и функциями сообщества для самостоятельного хостинга социальных сетей в масштабе.

Репозиторий
9431 день назадПроверено 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), который индексирует события напрямую. Мы заменили его на rsky-wintermute — индексатор на Rust, по нескольким причинам:

  • Производительность при масштабировании: Потребитель на 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-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

Запуск AppView

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

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

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

Полная обратная загрузка всей сети (все ~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 млрд записей).

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

Для небольшого сообщества, работающего с частичным 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/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
ПеременнаяОбязательноОписание
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ДаURL gRPC dataplane через запятую
BSKY_DIDДаDID AppView (например, did:web:api.example.com)
BSKY_MOD_SERVICE_DIDДаDID модерационного сервиса Ozone
BSKY_ADMIN_PASSWORDSДаПароли администраторов через запятую для базовой аутентификации
РесурсМинимумРекомендуется
CPU16 ядер48+ ядер
RAM64 ГБ256 ГБ
Накопитель10 ТБ NVMe28+ ТБ NVMe (RAID)
PostgreSQLВыделенный, на той же машине или с низкой задержкойРекомендуется та же машина
СетьСтабильные 100 Мбит/с1+ Гбит/с
Группа таблицРазмер
Посты + записи~3,5 ТБ
Лайки~2 ТБ
Подписки~500 ГБ
Уведомления~600 ГБ
Индексы~4 ТБ
OpenSearch (Palomar)~500 ГБ