README.md

Скрепа

Защищённый неанонимный (KYC) мессенджер со сквозным шифрованием на российских алгоритмах ГОСТ. В локальной разработке авторизация сейчас идёт через mock OAuth provider; production KYC-провайдер ещё не зафиксирован.

Архитектура

┌─────────────────────────────────────────────┐
│  Flutter UI (6 платформ)                    │
│  ┌───────────────────────────────────────┐  │
│  │  Rust Core (flutter_rust_bridge FFI)  │  │
│  │  gost-crypto + skrepa-protocol       │  │
│  └───────────────────────────────────────┘  │
└──────────────┬──────────────────────────────┘
               │ gRPC (tonic)
┌──────────────▼──────────────────────────────┐
│  Rust Server                                │
│  PostgreSQL · KYC auth provider            │
└─────────────────────────────────────────────┘

Компоненты

Компонент Путь Описание
gost-crypto gost-crypto/ Pure Rust реализация ГОСТ алгоритмов (без OpenSSL)
skrepa-protocol skrepa-protocol/ E2E протокол: X3DH, сессии, группы, хранилище
Сервер server/ gRPC сервер: маршрутизация, авторизация, хранение
Клиент (Rust ядро) client/core/ Bridge API для Flutter: криптография, локальная БД
Клиент (Flutter) client/flutter_app/ UI: чаты, контакты, группы, настройки

Криптография

Подробное описание криптографического стека, E2E-протоколов, storage encryption и multi-device вынесено в docs/crypto-architecture.md.

Для protected groups целевая архитектура и ограничения отдельно зафиксированы в docs/adr/0001-mls-gost.md.

Требования

Обязательные

  • Rust 1.75+ (curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh)
  • Flutter 3.11+ (brew install --cask flutter)
  • Docker (для testcontainers, integration compose-стендов и локальной разработки)

Опциональные (для proptest эквивалентности с OpenSSL)

  • OpenSSL 3.x с gost-engine (brew install openssl@3)
  • gost-engine (собрать из исходников)

Быстрый старт

1. Клонирование и сборка

git clone <repo-url> skrepa
cd skrepa

# Сборка Rust workspace (crypto + protocol + server)
cargo build

# Сборка клиентского Rust ядра (отдельный workspace из-за конфликта sqlite)
cd client/core && cargo build && cd ../..

2. Канонический локальный запуск

scripts/dev-web-local.sh

Это основной локальный entrypoint для разработки web-клиента и backend в одной команде. Скрипт:

  • поднимает PostgreSQL, Redis, Scylla и MinIO через docker compose;
  • собирает и запускает локальный debug skrepa-server;
  • включает mock OAuth для локальной авторизации;
  • собирает и сервит web-клиент на http://127.0.0.1:8090.

Для одноразовой сборки без watcher:

scripts/dev-web-local.sh --once

Если нужен browser launch сразу после старта:

scripts/dev-web-local.sh --open

3. Backend/infra без web

Если нужен только backend/infra для ручных проверок, cargo test или flutter test, канонический способ не поднимать сервисы руками, а обернуть команду:

scripts/with-itest-env.sh -- bash

Скрипт сам поднимет PostgreSQL, Redis, Scylla, MinIO и skrepa-server, экспортирует SKREPA_GRPC_* переменные и зачистит окружение после выхода из shell. Вместо bash можно передать любую команду, например cargo xtask test flutter-web-integration.

4. Запуск Flutter-клиента отдельно

Для web используй scripts/dev-web-local.sh из предыдущего раздела. Для desktop/mobile flutter run остаётся отдельной точкой входа, но backend уже должен быть поднят через scripts/dev-web-local.sh или scripts/with-itest-env.sh -- bash:

cd client/flutter_app
flutter pub get
flutter run  # на macOS/Windows/Linux, если backend доступен по localhost

Для Android/iOS указывайте backend явно через --dart-define, иначе mobile-клиент останется на дефолтном localhost:50051 устройства:

cd client/flutter_app

# Android Emulator -> backend на хост-машине
flutter run \
  --dart-define=SKREPA_GRPC_HOST=10.0.2.2 \
  --dart-define=SKREPA_GRPC_PORT=50051 \
  --dart-define=SKREPA_GRPC_TLS=false

# Тестовый стенд / внешний backend
flutter run \
  --dart-define=SKREPA_GRPC_HOST=skrepa.fomkin.org \
  --dart-define=SKREPA_GRPC_PORT=443 \
  --dart-define=SKREPA_GRPC_TLS=true

Тестирование

Подробный контракт по тестам, профилям, suite’ам, prerequisites, CI и низкоуровневым runner’ам вынесен в docs/testing.md.

# Показать реестр suite'ов и профилей
cargo xtask test list

# Проверить окружение и сделать быстрый прогон
cargo xtask test doctor fast
cargo xtask test fast

# Полный канонический прогон перед merge
cargo xtask test doctor full
cargo xtask test full

# Тяжёлый CI/scheduled контракт
cargo xtask test doctor exhaustive
cargo xtask test exhaustive

Для точечных suite’ов, doctor, dry-run, device runtime, CI-контракта и низкоуровневых runner’ов см. docs/testing.md.

Конфигурация сервера

Переменные окружения

Переменная Описание По умолчанию (debug)
DATABASE_URL PostgreSQL connection string postgres://localhost/skrepa
JWT_SECRET Секрет для JWT токенов (минимум 32 байта) dev-secret-...
LISTEN_ADDR Адрес прослушивания gRPC 0.0.0.0:50051
REDIS_URL Redis для Pub/Sub и состояния звонков (TLS: rediss://...) redis://127.0.0.1:6379
SCYLLA_NODES ScyllaDB ноды (через запятую) 127.0.0.1:9042
S3_ENDPOINT S3-совместимое хранилище http://127.0.0.1:9000
S3_BUCKET Имя бакета skrepa-files
S3_ACCESS_KEY S3 ключ доступа minioadmin
S3_SECRET_KEY S3 секретный ключ minioadmin
CDN_BASE_URL URL для прямой загрузки файлов http://127.0.0.1:9000/skrepa-files
MAX_FILE_SIZE Макс. размер файла (байт) 10485760 (10 МБ)
TURN_ENABLED Включить self-hosted TURN false
TURN_URL Адрес TURN-сервера turn:turn.example.com:3478
TURN_SECRET Shared secret для coturn (пусто)
TURN_TTL Время жизни TURN-credentials (сек) 86400 (24 часа)

В release-сборке DATABASE_URL, JWT_SECRET, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, CDN_BASE_URL обязательны — сервер упадёт при запуске без них.

Настройка TURN-сервера (для звонков)

Без TURN-сервера звонки работают только при прямом P2P-соединении. За symmetric NAT или строгими firewall (~15% сетей) звонки не пройдут. Для production-развёртывания TURN обязателен.

1. Установка coturn

apt install coturn
systemctl enable coturn

2. Конфигурация /etc/turnserver.conf

realm=skrepa.example.com
listening-port=3478
tls-listening-port=443

# Публичный IP сервера
external-ip=203.0.113.10

# TLS-сертификат (для TURNS через 443 — проходит через любой firewall)
cert=/etc/letsencrypt/live/turn.skrepa.example.com/fullchain.pem
pkey=/etc/letsencrypt/live/turn.skrepa.example.com/privkey.pem

# Shared secret — тот же что TURN_SECRET в Скрепе
use-auth-secret
static-auth-secret=СГЕНЕРИРУЙТЕ_НАДЁЖНЫЙ_СЕКРЕТ

# Relay-порты
min-port=49152
max-port=65535

# Запретить relay на внутренние сети
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255

log-file=/var/log/turnserver.log

3. Открыть порты на firewall

# STUN/TURN
ufw allow 3478/tcp
ufw allow 3478/udp
# TURNS (TLS)
ufw allow 443/tcp
# Relay-порты
ufw allow 49152:65535/udp

4. Запуск сервера Скрепа с TURN

TURN_ENABLED=true \
TURN_URL=turn:turn.skrepa.example.com:3478 \
TURN_SECRET=СГЕНЕРИРУЙТЕ_НАДЁЖНЫЙ_СЕКРЕТ \
TURN_TTL=86400 \
DATABASE_URL=postgres://... \
JWT_SECRET=... \
cargo run -p skrepa-server

5. Проверка

# Проверить что coturn отвечает
turnutils_uclient -T -u test -w test turn.skrepa.example.com

# В логах сервера должно быть:
# TURN credentials generated for user ...

Как работает

  1. Клиент вызывает StartCall — сервер генерирует временные TURN-credentials:
    • username = "timestamp:userId" (expires через TURN_TTL секунд)
    • credential = base64(HMAC-SHA1(TURN_SECRET, username))
  2. Сервер возвращает ICE-серверы: STUN + TURN/UDP + TURN/TCP + TURNS/443
  3. Клиент использует их для WebRTC PeerConnection
  4. coturn проверяет credentials тем же HMAC-SHA1 алгоритмом
  5. Если P2P не проходит, трафик идёт через TURN-сервер (зашифрован E2E, TURN видит только шифртекст)

Важно: TURN-credentials передаются через Redis Pub/Sub. В production Redis должен использовать TLS (rediss:// вместо redis://), чтобы credentials не передавались по сети в открытом виде. Credentials имеют ограниченный TTL (по умолчанию 24 часа).

Схема базы данных

Миграции применяются автоматически. Основные PostgreSQL таблицы:

Таблица Назначение
users Пользователи (user_id, KYC subject, identity key)
devices Привязанные устройства (device_id, revoked_at)
prekeys Одноразовые prekeys для X3DH
messages Зашифрованные сообщения (payload — opaque blob)
groups Групповые чаты
group_members Участники групп (role: admin/member)
storage_keys Зашифрованные ключи хранилища
device_links Временные токены для привязки устройств
auth_states Временные OAuth состояния внешнего auth provider
file_metadata Метаданные файлов (owner, size)

Протокол gRPC

Основные proto-определения находятся в server/proto/skrepa/v1/.

Сервис Методы Авторизация
AuthService StartAuth, CompleteAuth, RefreshToken Нет (pre-auth)
UserService Register, GetIdentityKey, PutStorageKey, GetStorageKey, InitDeviceLink, CompleteDeviceLink, ListDevices, RevokeDevice JWT
PrekeyService UploadPrekeys, GetPrekeyBundle, GetPrekeyCount JWT
MessagingService SendMessage, ReceiveMessages (stream), AckMessages, GetMessageHistory JWT
GroupService CreateGroup, AddMember, RemoveMember, GetGroup, ListGroups JWT
FileService UploadFile (stream), DownloadFile (stream) JWT
SignalingService StartCall, AnswerCall, RejectCall, EndCall, SendIceCandidate, ReceiveSignaling (stream) JWT
GroupCallService CreateRoom, JoinRoom, LeaveRoom, SendRoomIceCandidate, ReceiveRoomEvents (stream) JWT (SFU)

Протокол E2E шифрования

README больше не дублирует описание криптографических потоков. Подробности по direct sessions, sender keys, PROTECTED_MLS, storage encryption и multi-device см. в docs/crypto-architecture.md.

Безопасность

Проект прошёл 6 раундов аудита безопасности:

  • 0 CRITICAL, 0 HIGH на последних 4 раундах
  • Proof-of-possession при регистрации Identity Key
  • Device revocation проверяется на каждом запросе (включая RefreshToken и streaming)
  • Валидация всех входных данных (32-byte IDs, payload 64KB, batch limits)
  • Все ошибки БД не утекают наружу (ServerError::Db → generic “internal error”)
  • Rate limiting и cleanup — документированы как будущие улучшения

Структура файлов

skrepa/
├── Cargo.toml                          # Rust workspace
├── README.md                           # Этот файл
│
├── gost-crypto/                        # Pure Rust ГОСТ криптография
│   ├── src/
│   │   ├── pure/                       # Реализации алгоритмов
│   │   │   ├── kuznyechik.rs           # Блочный шифр
│   │   │   ├── streebog.rs             # Хеш-функция
│   │   │   ├── mgm.rs                  # AEAD режим
│   │   │   ├── gost3410.rs             # ЭЦП + VKO
│   │   │   ├── bigint.rs               # 256-бит арифметика
│   │   │   ├── ec.rs                   # Эллиптические кривые
│   │   │   ├── hmac.rs                 # HMAC-Стрибог
│   │   │   └── drbg.rs                 # ГОСТ DRBG
│   │   ├── hash.rs, cipher.rs, ...     # Публичный API
│   │   └── engine.rs, ffi.rs           # OpenSSL (только для proptest)
│   └── tests/
│       ├── equivalence.rs              # Proptest vs OpenSSL (8000+ тестов)
│       └── integration.rs              # Функциональные тесты
│
├── skrepa-protocol/                    # E2E протокол
│   ├── src/
│   │   ├── x3dh.rs                     # X3DH handshake
│   │   ├── session.rs                  # Сессии (encrypt/decrypt)
│   │   ├── group.rs                    # Sender Keys + hash-ratchet
│   │   ├── storage.rs                  # Storage Key wrap/unwrap
│   │   ├── keys.rs                     # Типы ключей
│   │   └── nonce.rs                    # Counter-based nonces
│   └── tests/protocol.rs              # Integration тесты протокола
│
├── server/                             # gRPC сервер
│   ├── proto/skrepa/v1/                # Proto definitions
│   ├── migrations/                     # SQL миграции
│   ├── src/
│   │   ├── main.rs, lib.rs             # Точка входа
│   │   ├── auth/                       # Auth provider abstraction, JWT, interceptor
│   │   ├── db/                         # PostgreSQL + Scylla access layer
│   │   ├── services/                   # gRPC services
│   │   ├── validate.rs                 # Валидация входных данных
│   │   └── push/                       # Push-уведомления (stub)
│   └── tests/e2e.rs                    # E2E тесты
│
└── client/
    ├── core/                           # Rust ядро клиента
    │   └── src/
    │       ├── api/skrepa.rs           # Bridge API для Flutter
    │       └── db/                     # SQLite schema
    │
    └── flutter_app/                    # Flutter UI (6 платформ)
        ├── lib/
        │   ├── main.dart               # Точка входа (RustLib.init + Riverpod)
        │   ├── app/                    # Router, тема
        │   ├── grpc/                   # gRPC клиенты + interceptors
        │   ├── providers/              # Riverpod (auth, messaging, groups, devices)
        │   └── screens/                # 8 экранов
        └── test/
            ├── screens/                # 10 widget тестов
            └── integration/            # 17 integration тестов (Docker + Rust)

Лицензия

TBD

Описание
Конвейеры
0 успешных
0 с ошибкой
Разработчики