KadrSync

Документация · v2.4

Установка и настройка KadrSync

Руководство описывает регистрацию и выбор тарифа, подключение мобильного приложения по одноразовому токену, развёртывание выделенного узла хранения для клиентов тарифа «Бизнес» и протокол поблочной загрузки, который используют все приложения KadrSync.

Как устроен KadrSync

Сервис состоит из трёх компонентов:

  • Облако KadrSync — управляемое хранилище, которое принимает зашифрованные блоки, проверяет их целостность и реплицирует в три зоны. Для тарифа «Бизнес» вместо облака может использоваться выделенный узел на инфраструктуре клиента.
  • Приложения — для iOS, Android, Windows, macOS и Linux. Выполняют шифрование, разбиение на блоки и дельта-синхронизацию.
  • Личный кабинет — app.kadrsync.space: управление подпиской, устройствами, участниками семейного или корпоративного тарифа. Доступа к содержимому файлов не имеет.

Серверы KadrSync никогда не получают ключи шифрования. Даже при полном доступе к хранилищу и базе данных виден только шифротекст, размеры блоков и служебные метки времени.

Аккаунт и тариф

  1. 1

    Зарегистрируйтесь на app.kadrsync.space/signup или в мобильном приложении. Новый аккаунт сразу получает 5 ГБ на бесплатном тарифе «Базовый».

  2. 2

    Придумайте парольную фразу шифрования. Она отличается от пароля входа и никогда не передаётся на сервер: из неё на устройстве формируется мастер-ключ.

  3. 3

    Чтобы увеличить объём, откройте Личный кабинет → Подписка и выберите тариф. «Личный» и «Семейный» доступны с 14-дневным пробным периодом. Сравнить тарифы.

ТарифХранилищеУстройстваИстория версий
Базовый5 ГБ27 дней
Личный200 ГБбез ограничений30 дней
Семейный2 ТБ на 6 участниковбез ограничений90 дней
Бизнес1 ТБ на пользователябез ограничений1 год

Связывание мобильного приложения по токену

Новое устройство подключается к аккаунту с помощью одноразового токена связывания. Токен действует 10 минут, используется только один раз и не даёт доступа к ключам шифрования — они передаются отдельно, напрямую между вашими устройствами.

  1. 1

    На уже подключённом устройстве или в личном кабинете откройте Настройки → Устройства → Добавить устройство. Будет показан QR-код и токен вида KSP-7QX4-M2RD-91HF.

  2. 2

    Установите приложение KadrSync на телефон, нажмите «Войти по токену» и отсканируйте QR-код либо введите токен вручную. Клиенты тарифа «Бизнес» с выделенным узлом дополнительно указывают его адрес.

  3. 3

    Сверьте шестизначный код безопасности на обоих экранах. Совпадение кодов подтверждает, что обмен ключами X25519 прошёл без посредника.

  4. 4

    Выберите альбомы для резервного копирования и условия загрузки (только Wi-Fi, только при зарядке). Первичная синхронизация начнётся в фоне.

Под капотом приложение обменивает токен связывания на сессионный маркер устройства:

HTTP
POST /v1/devices/pair HTTP/1.1
Host: api.kadrsync.space
Content-Type: application/json

{
  "pairing_token": "KSP-7QX4-M2RD-91HF",
  "device_name": "Pixel 8",
  "platform": "android",
  "device_public_key": "x25519:Hk3v9Q1mZ0p6cR4bT8wY2uN7aJ5eL1sD0fG3hK6xV9o="
}

HTTP/1.1 201 Created
{
  "device_id": "dev_01JA8M4Z7K2Q9W3E5R6T",
  "session_token": "ks_sess_…",
  "expires_in": 2592000,
  "plan": "family",
  "quota_bytes": 2199023255552,
  "chunk_size": 4194304
}

Ключ восстановления

При создании аккаунта приложение генерирует ключ восстановления из 24 слов (BIP-39). Это единственный способ расшифровать данные, если вы забыли парольную фразу и потеряли все устройства.

Служба поддержки KadrSync может восстановить доступ к аккаунту и подписке, но не к содержимому файлов. Утрата ключа восстановления и всех связанных устройств означает безвозвратную потерю данных.

Тариф «Бизнес»

Развёртывание выделенного узла хранения

Клиенты тарифа «Бизнес» могут хранить зашифрованные блоки на собственной инфраструктуре: в своём дата-центре, на NAS или в частном облаке. Узел работает по лицензионному ключу, который выдаётся в личном кабинете в разделе Организация → Выделенный узел. Учёт пользователей, подписка и личный кабинет остаются в облаке KadrSync.

РесурсМинимумРекомендуется
Процессор2 ядра x86_64 / ARM644 ядра
Оперативная память2 ГиБ8 ГиБ
ДискОбъём данных × 1,05SSD для БД, RAID для блоков
ПОDocker 24+, Compose v2Docker 27+, домен и TLS-сертификат
СетьИсходящий HTTPS к api.kadrsync.space для проверки лицензии и учёта квот
  1. 1

    Подготовьте каталог и загрузите манифест

    Создайте рабочий каталог и получите файлы конфигурации. Ссылка на загрузку доступна в личном кабинете после активации тарифа.

    bash
    sudo mkdir -p /opt/kadrsync && cd /opt/kadrsync
    curl -fsSL -H "Authorization: Bearer $KADRSYNC_LICENSE_KEY" \
      https://dl.kadrsync.space/node/latest/bundle.tar.gz | tar xz
  2. 2

    Укажите лицензию и параметры узла

    Отредактируйте файл .env: задайте лицензионный ключ, публичный адрес узла и сгенерируйте секрет для подписи сессионных маркеров.

    .env
    # Лицензионный ключ из личного кабинета (Организация → Выделенный узел)
    KADRSYNC_LICENSE_KEY=
    # Публичный адрес, по которому приложения обращаются к узлу
    KADRSYNC_PUBLIC_URL=https://storage.company.ru
    # Каталог для зашифрованных блоков
    KADRSYNC_BLOB_PATH=/srv/kadrsync/blobs
    # Секрет для подписи сессионных маркеров: openssl rand -hex 32
    KADRSYNC_SESSION_SECRET=
    POSTGRES_PASSWORD=
  3. 3

    Запустите узел и привяжите его к организации

    После запуска узел проверит лицензию и появится в личном кабинете со статусом «Активен». Новые устройства сотрудников будут автоматически направлены на него.

    bash
    docker compose up -d
    docker compose exec node kadrsync-node license status
    # organization: org_01JA7…  plan: business  seats: 25  status: active
  4. 4

    Настройте TLS и обратный прокси

    Приложения отказываются подключаться к узлу без HTTPS. Пример конфигурации Caddy с автоматическим выпуском сертификата:

    Caddyfile
    storage.company.ru {
        request_body {
            max_size 8MB
        }
        reverse_proxy node:8080
    }

REST API: аутентификация

Все запросы выполняются по HTTPS к https://api.kadrsync.space/v1 (или к адресу выделенного узла) и содержат сессионный маркер устройства в заголовке Authorization. Ответ на запрос /me содержит текущий тариф и использованный объём.

bash
curl -s https://api.kadrsync.space/v1/me \
  -H "Authorization: Bearer $KADRSYNC_SESSION_TOKEN"
Ответ
{
  "account_id": "acc_01JA7ZK3M0Q8R5T2V6W",
  "plan": "family",
  "subscription_status": "active",
  "renews_at": "2026-11-15T00:00:00Z",
  "quota_bytes": 2199023255552,
  "used_bytes": 230535987200
}

REST API: поблочная загрузка

Загрузка файла выполняется в три этапа: создание сессии загрузки с манифестом блоков, передача отсутствующих блоков и фиксация объекта. Сервер проверяет хеш BLAKE3 каждого блока после приёма; блок с несовпадающим хешем отклоняется и должен быть отправлен повторно. Квота тарифа проверяется при создании сессии.

POST /uploads

Манифест блоков, ответ — список недостающих индексов.

PUT /uploads/{id}/chunks/{n}

Передача зашифрованного блока с проверкой хеша.

POST /uploads/{id}/commit

Атомарная фиксация версии объекта.

Шаг 1. Создание сессии загрузки

Приложение заранее разбивает зашифрованный файл на блоки по chunk_size байт и вычисляет хеш каждого блока. В ответе сервер сообщает, какие блоки уже есть в хранилище (дедупликация) и какие нужно передать.

HTTP
POST /v1/uploads HTTP/1.1
Host: api.kadrsync.space
Authorization: Bearer ks_sess_…
Content-Type: application/json

{
  "library_id": "lib_camera_roll",
  "encrypted_name": "b64:Q2l4Rk9nV0R0c3VtV1N…",
  "wrapped_file_key": "b64:4h7JpX0v2Lk9bN1q…",
  "size": 19084391,
  "chunk_size": 4194304,
  "chunks": [
    { "index": 0, "size": 4194320, "hash": "blake3:9c1e5a…44ab" },
    { "index": 1, "size": 4194320, "hash": "blake3:02fd71…b7e0" },
    { "index": 2, "size": 4194320, "hash": "blake3:7a33c0…1d58" },
    { "index": 3, "size": 4194320, "hash": "blake3:e81a2f…0c93" },
    { "index": 4, "size": 2307191, "hash": "blake3:51b4d8…f6d2" }
  ]
}

HTTP/1.1 201 Created
{
  "upload_id": "upl_01JA8Q3VXN0F4C7B2M",
  "missing_chunks": [0, 1, 3, 4],
  "quota_remaining_bytes": 1968487268352,
  "expires_at": "2026-10-16T18:42:31Z"
}

Размер каждого блока на 16 байт больше исходного — это тег аутентификации Poly1305. Последний блок может быть короче chunk_size. Блоки, найденные при дедупликации, в квоте повторно не учитываются.

Шаг 2. Передача блоков

Каждый недостающий блок передаётся отдельным запросом. Заголовок X-Chunk-Hash обязателен: сервер вычисляет хеш принятых байтов и сравнивает его со значением из заголовка и манифеста.

bash
curl -X PUT "https://api.kadrsync.space/v1/uploads/upl_01JA8Q3VXN0F4C7B2M/chunks/0" \
  -H "Authorization: Bearer $KADRSYNC_SESSION_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  -H "X-Chunk-Hash: blake3:9c1e5a…44ab" \
  --data-binary @chunk_0000.enc
Ответ
HTTP/1.1 200 OK
{
  "index": 0,
  "status": "verified",
  "received_bytes": 4194320,
  "remaining_chunks": [1, 3, 4]
}

Пример реализации на TypeScript, которую используют десктопные приложения:

upload.ts
const CHUNK_SIZE = 4 * 1024 * 1024;

export async function uploadFile(api: KadrSyncApi, file: EncryptedFile) {
  // 1. Разбиваем шифротекст на блоки и считаем BLAKE3 для каждого
  const chunks = await splitIntoChunks(file.ciphertext, CHUNK_SIZE);
  const manifest = chunks.map((c, index) => ({ index, size: c.byteLength, hash: blake3Hex(c) }));

  // 2. Сервер возвращает только те блоки, которых у него нет
  const { upload_id, missing_chunks } = await api.post('/uploads', { ...file.meta, chunk_size: CHUNK_SIZE, chunks: manifest });

  // 3. Передаём недостающие блоки с повторами при ошибке валидации
  for (const index of missing_chunks) {
    await retry(() => api.put(`/uploads/${upload_id}/chunks/${index}`, chunks[index], {
      'X-Chunk-Hash': manifest[index].hash,
    }), { attempts: 5, retryOn: [409, 422, 503] });
  }

  // 4. Фиксируем версию объекта
  return api.post(`/uploads/${upload_id}/commit`, { root_hash: merkleRoot(manifest) });
}

Шаг 3. Фиксация объекта

После приёма всех блоков приложение передаёт корень дерева Меркла по хешам блоков. Сервер пересчитывает его и, при совпадении, атомарно публикует новую версию объекта для остальных устройств.

HTTP
POST /v1/uploads/upl_01JA8Q3VXN0F4C7B2M/commit HTTP/1.1
Host: api.kadrsync.space
Authorization: Bearer ks_sess_…
Content-Type: application/json

{ "root_hash": "blake3:f0a9c2…8e17" }

HTTP/1.1 200 OK
{
  "object_id": "obj_01JA8QB6TQ1H3Z5K9P",
  "version": 3,
  "cursor": "gal_7f2208"
}

Коды ошибок

КодИдентификаторОписание и действие приложения
401session_expiredСессионный маркер истёк или отозван. Требуется повторное связывание устройства.
402subscription_inactiveПодписка не оплачена или истекла. Загрузка приостановлена, чтение доступно. Пользователь направляется в раздел «Подписка».
409chunk_already_receivedБлок уже принят ранее. Перейдите к следующему блоку.
413chunk_too_largeРазмер блока превышает chunk_size + 16 байт.
422chunk_hash_mismatchХеш принятых данных не совпал с манифестом. Блок отброшен, повторите передачу.
422root_hash_mismatchКорень дерева Меркла не совпал при фиксации. Создайте новую сессию загрузки.
507quota_exceededИсчерпан объём хранилища по тарифу. Приложение предлагает перейти на тариф с большим объёмом.

Не нашли ответ?

Напишите в поддержку: support@kadrsync.space. Подписчики «Семейного» и «Бизнес» тарифов получают ответ в приоритетном порядке.

Выбрать тариф