Заложить репозиторий: философия, архитектура, модель угроз, ADR
Документы фиксируют принятые проектные решения Bare: клиент без фреймворков и сборки, Go-сервер одним бинарём, E2EE на WebCrypto, сервер-реле без истории, локальная история с экспортом/импортом, Web Push + VAPID. Кода нет — сначала документы. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SW4ZXtKn5NjX8NH3Lhm2ND
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# бинарь
|
||||
/bare
|
||||
|
||||
# локальная база
|
||||
*.db
|
||||
*.db-*
|
||||
@@ -0,0 +1,19 @@
|
||||
# Правила работы с репозиторием Bare
|
||||
|
||||
Перед любой работой прочитай `docs/philosophy.md` и `docs/architecture.md`. Всё в них — принятые решения, а не предложения.
|
||||
|
||||
## Жёсткие ограничения
|
||||
|
||||
- Клиент: HTML, CSS, vanilla JS, нативные браузерные API. Никаких фреймворков, npm-зависимостей и сборки — ES-модули как есть.
|
||||
- Сервер: Go, стандартная библиотека. Допущены ровно три внешних пакета: webpush-go, драйвер SQLite, argon2. Ничего сверх — без обсуждения.
|
||||
- Криптография на клиенте: только WebCrypto.
|
||||
|
||||
## Процесс
|
||||
|
||||
- Новые фичи и зависимости по умолчанию отклоняются. Порядок: обсуждение → ADR → код.
|
||||
- Любое изменение архитектуры — через новый ADR в `docs/decisions/` (формат: контекст / решение / следствия).
|
||||
- Простота важнее функций. Сомневаешься — не добавляй.
|
||||
|
||||
## Документация
|
||||
|
||||
Язык — русский. Стиль — сжатый и декларативный: короткие утвердительные абзацы, без маркетинговой воды и канцелярита.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Bare contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Bare
|
||||
|
||||
Максимально простой веб-чат. Web-native PWA на ванильных технологиях: HTML, CSS, vanilla JS — и Go-сервер одним бинарём. Ноль npm-зависимостей, никакой сборки.
|
||||
|
||||
Bare — маленький независимый инструмент, а не конкурент Discord, Slack или Telegram. Название буквальное: голый, без лишнего, ничего не спрятано за слоями абстракций.
|
||||
|
||||
Сервер — реле, а не архив: он передаёт зашифрованные сообщения и забывает их. История живёт только на устройстве. E2EE по умолчанию — оператор видит только шифротекст. Забыл пароль — значит забыл: восстановления нет, потому что пароль — материал ключа.
|
||||
|
||||
## Документация
|
||||
|
||||
- [Философия](docs/philosophy.md) — манифест
|
||||
- [Архитектура](docs/architecture.md) — обзор системы
|
||||
- [Модель угроз](docs/threat-model.md) — от чего защищаемся и от чего нет
|
||||
- [Решения](docs/decisions/) — ADR по ключевым решениям
|
||||
- [Открытые вопросы](docs/open-questions.md)
|
||||
|
||||
## Статус
|
||||
|
||||
Проектирование. Кода ещё нет — сначала документы.
|
||||
|
||||
## Лицензия
|
||||
|
||||
[MIT](LICENSE)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Архитектура
|
||||
|
||||
Bare — это PWA-клиент на ванильных веб-технологиях и Go-сервер одним бинарём. Между ними — голый HTTPS: приём сообщений через SSE, отправка обычным `fetch POST`. Чат поверх голого HTTP.
|
||||
|
||||
## Стек
|
||||
|
||||
Клиент: HTML + CSS + vanilla JS, ES-модули без сборки, один service worker, manifest.json. PWA. Ноль npm-зависимостей.
|
||||
|
||||
Сервер: Go, стандартная библиотека плюс ровно три внешних пакета — webpush-go, драйвер SQLite, argon2. База — SQLite. HTTPS обязателен: без него не работают service worker и пуши.
|
||||
|
||||
## Аккаунты
|
||||
|
||||
Регистрация — ник и пароль. Ник уникален и является идентификатором пользователя. Без email, телефона, OAuth и интеграций. Восстановления пароля нет.
|
||||
|
||||
Серверная аутентификация: Argon2id, сессия в httpOnly cookie.
|
||||
|
||||
## E2EE
|
||||
|
||||
Вся клиентская криптография — WebCrypto, без крипто-библиотек.
|
||||
|
||||
Идентичность пользователя — ECDH-пара (P-256). Приватный ключ шифруется ключом, выведенным из пароля (PBKDF2), и хранится на сервере как блоб — сервер видит только шифротекст. Отсюда два следствия. Сброс пароля невозможен by design. Мультидевайс-вход прост: новый девайс вводит пароль, скачивает блоб, расшифровывает ключ.
|
||||
|
||||
Чаты 1:1: ECDH shared secret → AES-GCM.
|
||||
|
||||
Комнаты: у комнаты симметричный ключ, он раздаётся участникам зашифрованным на их публичные ключи. При изменении состава — rekey. Новый участник не видит сообщений до своего вступления — их и не существует нигде, кроме устройств участников.
|
||||
|
||||
Forward secrecy — осознанный non-goal v1.
|
||||
|
||||
## Хранение
|
||||
|
||||
Сервер хранит только три вещи: аккаунты (ник, argon2-хеш, зашифрованный ключевой блоб), метаданные комнат и контактов, транзитную очередь зашифрованных недоставленных сообщений. Очередь per-device: доставлено и подтверждено ACK — удалено с сервера; не забрано за 30 дней — удалено.
|
||||
|
||||
Клиент хранит историю в IndexedDB. messageId — ULID/UUIDv7: хронологическая сортировка и идемпотентный merge. Составной индекс (chatId, messageId). Пагинация курсором по ~50 сообщений, виртуализация списка в DOM.
|
||||
|
||||
При старте клиент запрашивает `navigator.storage.persist()` и показывает занятое место через `storage.estimate()`.
|
||||
|
||||
## Экспорт и импорт истории
|
||||
|
||||
Экспорт: вся локальная история сериализуется, шифруется отдельной парольной фразой (запрашивается в момент экспорта) и сохраняется одним файлом `.bare`. Импорт: файл плюс фраза, merge в IndexedDB по messageId, идемпотентно — повторный импорт и склейка истории с двух устройств не создают дублей.
|
||||
|
||||
Это единственный механизм переноса истории между устройствами. Осознанно.
|
||||
|
||||
## Пуши
|
||||
|
||||
Web Push + VAPID. Одна пара ключей, никаких регистраций и оплат у вендоров, никакого Firebase SDK.
|
||||
|
||||
Пуш — сигнал, не транспорт: содержимое всегда догоняется через очередь при открытии. Текст пуша generic («имя: новое сообщение») — сервер не знает плейнтекста. Declarative Web Push не используем: несовместим с E2EE.
|
||||
|
||||
iOS: пуши работают только у PWA, установленного на экран «Домой», поэтому онбординг-баннер установки — обязательная часть продукта. Разрешение на уведомления запрашивается после осмысленного действия (первое отправленное сообщение), не при входе.
|
||||
|
||||
Сервер обрабатывает 404/410 от push-сервисов и чистит мёртвые подписки.
|
||||
|
||||
## Scope v1
|
||||
|
||||
Чаты 1:1 и комнаты. Только текст и эмодзи (эмодзи — юникод, отдельной фичи нет). Экспорт/импорт истории. Пуши на всех платформах. Всё остальное — за пределами v1.
|
||||
@@ -0,0 +1,16 @@
|
||||
# ADR-001: Клиент на ванильных веб-технологиях, без сборки
|
||||
|
||||
## Контекст
|
||||
|
||||
Bare обещает аудируемость: любой должен иметь возможность проверить глазами, что делает код, который исполняет его браузер. Фреймворки, npm-зависимости и сборка превращают исходники в артефакт, который никто не читает.
|
||||
|
||||
## Решение
|
||||
|
||||
Клиент — HTML, CSS и vanilla JS на нативных браузерных API. ES-модули отдаются как есть, без транспиляции и бандлинга. Ноль npm-зависимостей. Один service worker и manifest.json — полноценный PWA.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Код в продакшене байт в байт совпадает с кодом в репозитории.
|
||||
- Нет supply-chain-рисков npm и нет тулчейна, который надо поддерживать.
|
||||
- Состояние, рендеринг и роутинг пишем руками — отказ от удобств фреймворков осознанный.
|
||||
- Поддерживаем только современные браузеры с ES-модулями и WebCrypto.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-002: Сервер на Go, один бинарь
|
||||
|
||||
## Контекст
|
||||
|
||||
Серверу Bare нужно немного: HTTP, SSE, SQLite, хеширование паролей, Web Push. Простота развёртывания и аудита важнее богатства экосистемы.
|
||||
|
||||
## Решение
|
||||
|
||||
Сервер пишется на Go со стандартной библиотекой. Допущены ровно три внешних пакета: webpush-go, драйвер SQLite, argon2. Результат сборки — один бинарь.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Развёртывание: скопировать бинарь, запустить. Без рантаймов и обязательных контейнеров.
|
||||
- Любая новая зависимость требует обсуждения и нового ADR.
|
||||
- Часть вещей (роутинг, миграции) пишем руками поверх stdlib.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-003: SQLite как единственная база
|
||||
|
||||
## Контекст
|
||||
|
||||
Сервер хранит мало: аккаунты, метаданные комнат и контактов, транзитную очередь. Отдельный сервер БД — лишняя движущаяся часть, противоречащая идее одного бинаря.
|
||||
|
||||
## Решение
|
||||
|
||||
Вся серверная persistence — SQLite, один файл рядом с бинарём.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Бэкап — копия одного файла.
|
||||
- Нет сетевой БД — нет её настройки, аутентификации и отказов.
|
||||
- Вертикальный потолок масштабирования принимаем осознанно: Bare — маленький инструмент, не платформа.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-004: Realtime через SSE и fetch POST
|
||||
|
||||
## Контекст
|
||||
|
||||
Чату нужна доставка сообщений в реальном времени. WebSocket — отдельный протокол со своим жизненным циклом, капризами прокси и кастомным фреймингом. Хочется остаться в рамках голого HTTP.
|
||||
|
||||
## Решение
|
||||
|
||||
Приём сообщений — Server-Sent Events. Отправка — обычный `fetch POST`. Чат поверх голого HTTP.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Никакого кастомного протокола: всё видно в DevTools как обычные HTTP-запросы, реконнект SSE встроен в браузер.
|
||||
- Работает везде, где работает HTTPS, без апгрейда соединения.
|
||||
- Двунаправленного канала нет — он и не нужен: у отправки и приёма разные пути.
|
||||
@@ -0,0 +1,16 @@
|
||||
# ADR-005: Аккаунт — ник и пароль
|
||||
|
||||
## Контекст
|
||||
|
||||
Email, телефон и OAuth тянут за собой внешние сервисы, интеграции и утечку идентичности. Bare — независимый инструмент без внешних завязок.
|
||||
|
||||
## Решение
|
||||
|
||||
Регистрация — ник и пароль. Ник уникален и является идентификатором пользователя. Без email, телефона, OAuth и восстановления пароля. Серверная аутентификация: Argon2id, сессия в httpOnly cookie.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Ноль внешних сервисов в цикле регистрации и входа.
|
||||
- Сервер не знает о пользователе ничего, кроме ника.
|
||||
- Восстановления доступа нет — пароль ещё и материал ключа (ADR-006).
|
||||
- Открытость регистрации (инвайты или нет) — открытый вопрос.
|
||||
@@ -0,0 +1,16 @@
|
||||
# ADR-006: E2EE на WebCrypto, ключ за паролем
|
||||
|
||||
## Контекст
|
||||
|
||||
Оператор не должен уметь читать сообщения. Крипто-библиотеки на клиенте противоречат нулю зависимостей и аудируемости — вся криптография должна быть нативной.
|
||||
|
||||
## Решение
|
||||
|
||||
Только WebCrypto. Идентичность пользователя — ECDH-пара P-256. Приватный ключ шифруется ключом, выведенным из пароля (PBKDF2 — единственный KDF в WebCrypto), и хранится на сервере как блоб. Чаты 1:1: ECDH shared secret → AES-GCM.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Сервер видит только шифротекст — и блоба, и сообщений.
|
||||
- Сброс пароля невозможен by design: пароль — материал ключа. Забыл — значит забыл.
|
||||
- Мультидевайс-вход: новый девайс вводит пароль, скачивает блоб, расшифровывает ключ.
|
||||
- Стойкость блоба к оффлайн-перебору равна стойкости пароля.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-007: Симметричный ключ комнаты и rekey
|
||||
|
||||
## Контекст
|
||||
|
||||
Сообщение в комнате должны читать все участники, но не сервер. Шифровать каждое сообщение отдельно каждому участнику — квадратичный объём работы и трафика.
|
||||
|
||||
## Решение
|
||||
|
||||
У комнаты один симметричный ключ. Он раздаётся участникам зашифрованным на их публичные ключи. При любом изменении состава — rekey: новый ключ, новая раздача.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Новый участник не видит сообщений до своего вступления — их и не существует нигде, кроме устройств участников.
|
||||
- Вышедший участник не читает сообщения после rekey.
|
||||
- Rekey выполняют клиенты; серверу ключи недоступны.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-008: Сервер — реле с per-device очередью
|
||||
|
||||
## Контекст
|
||||
|
||||
Сервер никогда не является местом, где живёт история (философия, п. 2). Но получатель бывает офлайн — сообщение надо где-то подержать до доставки.
|
||||
|
||||
## Решение
|
||||
|
||||
Сервер хранит транзитную очередь зашифрованных недоставленных сообщений, per-device. Доставлено и подтверждено ACK — удалено с сервера. Не забрано за 30 дней — удалено. Кроме очереди сервер хранит только аккаунты и метаданные комнат и контактов.
|
||||
|
||||
## Следствия
|
||||
|
||||
- На сервере нет истории — компрометация сервера не раскрывает переписку.
|
||||
- Устройство, молчавшее больше 30 дней, теряет недоставленные сообщения. Осознанно.
|
||||
- Нужна идентификация устройства для очередей — открытый вопрос.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-009: История — только на устройстве, в IndexedDB
|
||||
|
||||
## Контекст
|
||||
|
||||
История, живущая на сервере, делает сервер архивом и целью атак. У Bare история — собственность устройства.
|
||||
|
||||
## Решение
|
||||
|
||||
Клиент хранит историю в IndexedDB. messageId — ULID/UUIDv7: хронологическая сортировка и идемпотентный merge. Составной индекс (chatId, messageId). Пагинация курсором по ~50 сообщений, виртуализация списка в DOM. При старте — `navigator.storage.persist()`; занятое место показывается через `storage.estimate()`.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Зашёл с другого устройства — там только новые сообщения.
|
||||
- Потеря устройства без экспорта — потеря истории.
|
||||
- Браузер может вычистить storage; `persist()` снижает риск, но не исключает его.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-010: Перенос истории — только ручной экспорт/импорт
|
||||
|
||||
## Контекст
|
||||
|
||||
История живёт на устройстве (ADR-009), но людям нужны перенос на новое устройство и склейка истории с нескольких. Облачная синхронизация сделала бы сервер архивом — non-goal.
|
||||
|
||||
## Решение
|
||||
|
||||
Экспорт: вся локальная история сериализуется, шифруется отдельной парольной фразой (запрашивается в момент экспорта) и сохраняется одним файлом `.bare`. Импорт: файл плюс фраза, идемпотентный merge в IndexedDB по messageId. Это единственный механизм переноса истории между устройствами.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Повторный импорт и склейка истории с двух устройств не создают дублей.
|
||||
- Файл `.bare` самодостаточен и не зависит от пароля аккаунта.
|
||||
- Перенос — явное действие пользователя. Автоматики не будет. Осознанно.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-011: Web Push + VAPID, пуш — сигнал
|
||||
|
||||
## Контекст
|
||||
|
||||
Без уведомлений чат бесполезен. Firebase SDK и вендорские кабинеты — зависимость и завязка, несовместимые с философией.
|
||||
|
||||
## Решение
|
||||
|
||||
Web Push + VAPID: одна пара ключей, никаких регистраций и оплат у вендоров, никакого Firebase SDK. Пуш — сигнал, не транспорт: содержимое догоняется через очередь при открытии. Текст пуша generic («имя: новое сообщение»). Declarative Web Push не используем — несовместим с E2EE. Сервер обрабатывает 404/410 от push-сервисов и чистит мёртвые подписки.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Сервер не знает плейнтекста — и в пуше его нет.
|
||||
- Доставка идёт через инфраструктуру вендоров браузеров (FCM/APNs/Mozilla) — свойство стандарта, не наша зависимость.
|
||||
- iOS: пуши только у PWA на экране «Домой», поэтому онбординг-баннер установки — обязательная часть продукта. Разрешение запрашиваем после первого отправленного сообщения, не при входе.
|
||||
@@ -0,0 +1,15 @@
|
||||
# ADR-012: Forward secrecy — non-goal v1
|
||||
|
||||
## Контекст
|
||||
|
||||
FS требует ratcheting в духе Signal Protocol: состояние на каждую пару устройств, синхронизация, сложность, несовместимая с клиентом из нескольких читаемых файлов.
|
||||
|
||||
## Решение
|
||||
|
||||
В v1 forward secrecy нет. 1:1 — статический ECDH shared secret, комнаты — симметричный ключ до rekey.
|
||||
|
||||
## Следствия
|
||||
|
||||
- Компрометация приватного ключа раскрывает ранее записанные шифротексты.
|
||||
- Модель угроз говорит об этом прямо (`docs/threat-model.md`).
|
||||
- Возврат к FS позже возможен — отдельным ADR.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Открытые вопросы
|
||||
|
||||
Решения по этим пунктам ещё не приняты. Каждое принятое решение уходит в ADR и вычёркивается отсюда.
|
||||
|
||||
- Регистрация: открытая или по инвайтам?
|
||||
- Механика добавления контакта и приглашения в комнату: по нику? по ссылке?
|
||||
- Лимиты: длина сообщения, rate limiting, антиспам.
|
||||
- Смена пароля (= перешифровка ключевого блоба): в v1 или позже?
|
||||
- Идентификация устройства для per-device очередей.
|
||||
- Язык интерфейса (ru/en); нужна ли i18n.
|
||||
- Визуальная айдентика: отдельный бриф будет добавлен в `docs/identity/`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Философия
|
||||
|
||||
Bare — максимально простой веб-чат. Utility, а не платформа. Название буквальное: голый, без лишнего, ничего не спрятано за слоями абстракций.
|
||||
|
||||
## Принципы
|
||||
|
||||
### 1. Bare = голый web
|
||||
|
||||
HTML, CSS, vanilla JS, нативные браузерные API. Ноль npm-зависимостей на клиенте. Никакой сборки — ES-модули как есть.
|
||||
|
||||
### 2. Сервер — реле, а не архив
|
||||
|
||||
Сервер никогда не является местом, где живёт история. Он передаёт и забывает.
|
||||
|
||||
### 3. История живёт только на устройстве
|
||||
|
||||
Зашёл с другого места — там только новые сообщения. Перенос истории — явный ручной экспорт/импорт.
|
||||
|
||||
### 4. Забыл пароль — значит забыл
|
||||
|
||||
Восстановления нет, и это не политика, а криптография: пароль — материал ключа.
|
||||
|
||||
### 5. Оператор не может читать сообщения
|
||||
|
||||
E2EE по умолчанию. У админа с полным доступом к серверу — только шифротекст.
|
||||
|
||||
### 6. Аудируемость через простоту
|
||||
|
||||
Клиент — несколько читаемых файлов без сборки. Любой может проверить глазами, что код делает.
|
||||
|
||||
### 7. Простота важнее функций
|
||||
|
||||
Каждая фича должна оправдать своё существование. По умолчанию — нет.
|
||||
|
||||
## Non-goals
|
||||
|
||||
Это не «пока не успели», а осознанные решения не делать:
|
||||
|
||||
- Облачная синхронизация истории между устройствами.
|
||||
- «Удалить у всех» после доставки.
|
||||
- Серверный поиск — поиск только локальный.
|
||||
- Файлы, медиа, голос, реакции, треды (v1).
|
||||
- Forward secrecy (v1).
|
||||
- Федерация.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Модель угроз
|
||||
|
||||
Честная. Здесь написано не только что Bare защищает, но и чего он защитить не может.
|
||||
|
||||
## Что защищаем
|
||||
|
||||
Содержимое сообщений. Оно шифруется на устройстве отправителя и расшифровывается на устройствах получателей. Сервер, канал и оператор видят только шифротекст.
|
||||
|
||||
## От кого защищаем
|
||||
|
||||
**Пассивный оператор сервера.** Админ с полным доступом к базе и диску видит: ники, argon2-хеши, зашифрованные ключевые блобы, метаданные комнат и контактов, транзитную очередь шифротекстов. Плейнтекста у него нет.
|
||||
|
||||
**Сетевой наблюдатель.** HTTPS обязателен. Наблюдатель видит факт и объём трафика к серверу, не содержимое.
|
||||
|
||||
**Кража базы или бэкапа.** В базе нет ничего сверх того, что видит оператор: те же шифротексты и метаданные.
|
||||
|
||||
**Push-инфраструктура.** Пуш не несёт содержимого: сервер не знает плейнтекста, поэтому его нет и в пуше.
|
||||
|
||||
## От кого не защищаем
|
||||
|
||||
**Активно-злонамеренный оператор.** Оператор, способный подменить клиентский код, может украсть ключи и плейнтекст. Это фундаментальный предел web-E2EE: клиент каждый раз загружается с сервера. Смягчение — открытый код и клиент из нескольких читаемых файлов без сборки: подмену можно заметить глазами. Гарантии нет.
|
||||
|
||||
**Метаданные.** Кто, с кем, когда и сообщениями какого размера обменивается — серверу видно. Скрытие метаданных — не задача Bare.
|
||||
|
||||
**Компрометация устройства.** История лежит на устройстве в открытом виде (IndexedDB). Доступ к устройству — доступ к истории. Защита устройства — зона ответственности пользователя и ОС.
|
||||
|
||||
**Слабый пароль.** Пароль — материал ключа. Ключевой блоб хранится на сервере, и его стойкость к оффлайн-перебору равна стойкости пароля. Слабый пароль ослабляет и вход, и шифрование.
|
||||
|
||||
**Собеседник.** E2EE не защищает от участника чата: получатель может сохранить, переслать, сфотографировать. «Удалить у всех» после доставки не существует.
|
||||
|
||||
## Осознанные пределы v1
|
||||
|
||||
**Forward secrecy отсутствует.** Компрометация приватного ключа пользователя раскрывает ранее записанные атакующим шифротексты его чатов 1:1. Осознанный non-goal v1.
|
||||
|
||||
**Push-транспорт идёт через инфраструктуру вендоров браузеров** (FCM, APNs, Mozilla). Это свойство стандарта Web Push, а не наша зависимость. Вендоры видят факт и время доставки пуша.
|
||||
Reference in New Issue
Block a user