Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nopeer.pw — P2P Encrypted Web Messenger

Zero-Server, Zero-Knowledge, Peer-to-Peer Browser Communicator

Nopeer.pw — это открытый веб-мессенджер нового поколения, работающий полностью на стороне клиента (Client-Side Only). Он предоставляет возможность обмениваться мгновенными сообщениями, передавать файлы любого размера, форматировать текст с помощью Markdown и совершать аудиовызовы без промежуточных серверов хранения данных.

В основе проекта лежит концепция Zero-Knowledge Architecture: сервер не знает, кто с кем общается, не имеет доступа к содержимому переписки и не хранит метаданные или ключи шифрования.


📋 Оглавление


1. Архитектура системы

1.1. Общие принципы

  1. Serverless Data Flow: Все данные (текст, медиа, файлы) передаются напрямую из RAM браузера Отправителя в RAM браузера Получателя.
  2. Ephemeral States: Сообщения и ключи шифрования хранятся исключительно в оперативной памяти (In-Memory). При закрытии вкладки браузера вся история сессии и сессионные ключи уничтожаются без возможности восстановления.
  3. End-to-End Encryption (E2EE): Никакая незашифрованная информация не покидает пределы браузера пользователя.

1.2. Схема компонентов

┌────────────────────────────────────────────────────────────────────────┐
│                             BROWSER A                                  │
│  ┌──────────────┐    ┌─────────────────┐    ┌───────────────────────┐  │
│  │  UI / DOM    │ ── │ Engine / Crypto │ ── │ WebRTC (RTCDataChan)  │  │
│  └──────────────┘    └─────────────────┘    └───────────────────────┘  │
└───────────────────────────────┬────────────────────────────────────────┘
                                │
             (1) Signaling      │      (2) Direct P2P Channel
             SDP / ICE Exchange │      Encrypted Data & Media
                                ▼
         ┌───────────────────────────────┐
         │ Node.js Signaling (PeerJS)    │
         │   * Zero Payload Access       │
         │   * Temporary Address Router  │
         └───────────────────────────────┘
                                ▲
                                │
┌───────────────────────────────┼────────────────────────────────────────┐
│                               │                                        │
│  ┌──────────────┐    ┌────────┴────────┐    ┌───────────────────────┐  │
│  │  UI / DOM    │ ── │ Engine / Crypto │ ── │ WebRTC (RTCDataChan)  │  │
│  └──────────────┘    └─────────────────┘    └───────────────────────┘  │
│                             BROWSER B                                  │
└────────────────────────────────────────────────────────────────────────┘

2. Подробный разбор функционала

2.1. Инициализация и менеджер сессий

  • Генерация ID: При запуске приложения модуль создаёт случайный идентификатор Peer ID.
  • Ссылка-приглашение: Формируется URL вида https://nopeer.pw/#<peer-id>. Внутренний хэш ссылки (#) не передаётся на веб-сервер при HTTP-запросе, обеспечивая дополнительную приватность.
  • QR-Код: Автоматическая генерация SVG QR-кода прямо в браузере для быстрого подключения мобильных устройств.

2.2. Текстовый чат и движок Markdown

  • Рендеринг текста: Встроенный лёгкий парсер преобразует Markdown-разметку (жирный, курсив, заголовки, списки, таблицы) в безопасный HTML.
  • XSS Sanitization: Все входящие сообщения фильтруются перед вставкой в DOM для предотвращения атак типа Cross-Site Scripting.
  • Подтверждение доставки (ACK): Реализована система квитирования пакетов:
    • Sent — пакет отправлен в сокет DataChannel.
    • Delivered — противоположный пир получил пакет и отправил обратно служебный кадр ACK.
    • Read — сообщение отрисовано и попало в область видимости окна (Focus/IntersectionObserver).

2.3. Потоковая передача файлов (Chunked Binary Transfer)

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

  1. Чтение: Файл читается блоками по 16–64 КБ с помощью FileReader API.
  2. Шифрование: Каждый блок шифруется отдельным вызовом AES-GCM с индивидуальным IV.
  3. Отправка: Бинарные кадры отправляются в RTCDataChannel.
  4. Контроль буфера: Используется свойство bufferedAmount, предотвращающее переполнение сетевого буфера WebRTC. Если буфер переполнен, отправка приостанавливается до события bufferedamountlow.
  5. Сборка: Получатель собирает зашифрованные и расшифрованные блоб-объекты, формируя финальный Blob и ссылочный объект URL.createObjectURL().

2.4. Голосовые P2P-вызовы

  • Использование navigator.mediaDevices.getUserMedia({ audio: true }).
  • Добавление аудио-треков напрямую в RTCPeerConnection.
  • Настройка кодека OPUS с адаптивным битрейтом для минимальной задержки при слабом интернет-соединении.
  • Возможность отключения микрофона (Mute) на лету без разрыва соединения.

2.5. Управление состоянием и очистка памяти

  • Кнопка экстренного уничтожения (Purge / Panic Button): Мгновенно обнуляет массивы сообщений в RAM, закрывает WebRTC-соединение, стирает криптографические ключи и перезагружает страницу.
  • Auto-Teardown: При закрытии вкладки браузер посылает предупредительный кадр DISCONNECT противоположной стороне, после чего уничтожает все локальные контексты.

3. Безопасность и сквозное шифрование (E2EE)

Проект опирается на стандартный системный модуль Web Crypto API (crypto.subtle), доступный в современных браузерах.

3.1. Используемые криптографические примитивы

Назначение Алгоритм / Протокол Параметры
Асимметричный обмен ECDH (Elliptic Curve Diffie-Hellman) Кривая P-256 (secp256r1)
Деривация ключей HKDF (HMAC-based Key Derivation) Хэш-функция SHA-256
Симметричное шифрование AES-GCM Длина ключа: 256 бит
Инициализационный вектор IV / Nonce 96 бит (12 байт), случайный для каждого кадра

3.2. Пошаговый протокол рукопожатия (Handshake)

Шаг 1 — Генерация пары ключей:

Пир А и Пир Б генерируют временные (ephemeral) ECDH ключи в браузере:

KeyPair_A = (K_pubA, K_privA)
KeyPair_B = (K_pubB, K_privB)

Шаг 2 — Обмен публичными ключами:

Публичные ключи K_pubA и K_pubB экспортируются в формат JWK или Raw и передаются друг другу через Сигнальный сервер при открытии сессии.

Шаг 3 — Вычисление Shared Secret (ECDH):

Оба пира независимо вычисляют общий секрет S:

S_A = ECDH(K_privA, K_pubB)
S_B = ECDH(K_privB, K_pubA)
=> S_A = S_B = S

Шаг 4 — Деривация мастер-ключа (HKDF):

Из общего секрета S извлекается 256-битный сессионный ключ K_session:

K_session = HKDF-Expand(HKDF-Extract(salt, S), "nopeer-v1-aes-key", 256)

Диаграмма рукопожатия:

[Client A]                                                [Client B]
   │                                                         │
   │ ── (1) Gen ECDH KeyPair A ──┐             ┌── (1) Gen ECDH KeyPair B
   │                             │             │             │
   │ ── (2) Send PubKey A ───────┼──[Signal]───┼───────────► │
   │                             │             │             │
   │ ◄───────────────────────────┼──[Signal]───┼─ Send PubKey B (2)
   │                             │             │             │
   │ ── (3) Compute Shared S ────┘             └── (3) Compute Shared S
   │ ── (4) Derive AES Key ─────────────────────── Derive AES Key (4) ──

3.3. Шифрование сообщений и чанков файлов

Каждая единица данных (текстовая строка, сервисное сообщение или файловый чанк) перед отправкой превращается в JSON-структуру и зашифровывается.

Алгоритм обработки:

  1. Создаётся случайный IV размером 12 байт: crypto.getRandomValues(new Uint8Array(12)).
  2. Объект данных переводится в бинарный вид (TextEncoder).
  3. Выполняется шифрование: Ciphertext = AES-GCM-Encrypt(K_session, IV, Plaintext).
  4. В режиме GCM автоматически встроен 128-битный Authentication Tag для контроля целостности.
  5. Формируется итоговый пакет кадра.

Структура зашифрованного пакета (Binary Payload Format):

+------------------------+----------------------------------------------+
| Field                  | Size / Format                                |
+------------------------+----------------------------------------------+
| Initialization Vector  | 12 Bytes (Fixed)                             |
| Encrypted Payload      | Variable Size (N Bytes)                      |
| GCM Authentication Tag | 16 Bytes (Appended to Encrypted Payload)     |
+------------------------+----------------------------------------------+

3.4. Матрица угроз и защита (Threat Model)

Угроза / Вектор атаки Уровень риска Метод защиты в Nopeer.pw
Компрометация Signaling сервера Средний Сервер пересылает только публичные ключи ECDH. Прослушивание сигнала не позволяет расшифровать трафик.
Утечка сообщений с сервера Высокий Сообщения не передаются на сервер и не сохраняются на диске.
Модификация трафика (MITM) Высокий Режим шифрования AES-GCM проверяет подлинность (Auth Tag). Изменённый пакет отбрасывается браузером.
Компрометация после сессии Низкий Ключи являются временными (ephemeral). После закрытия вкладки ключи удаляются из RAM (Perfect Forward Secrecy на уровне сессии).
Анализ размера файлов Низкий Файлы передаются фиксированными блоками (чанками), что усложняет сигнатурный анализ.

4. Сетевое взаимодействие и протоколы

4.1. Роль Сигнального сервера (Signaling)

Сигнальный сервер написан на Node.js с использованием фреймворка PeerJS Server. Его задача ограничена двумя функциями:

  1. Выдача уникальных ID для пользователей.
  2. Трансляция SDP (Session Description Protocol) офферов/ансверов и ICE-кандидатов между клиентами.

Как только P2P-соединение установлено, обмен через сигнальный сервер приостанавливается.

4.2. Установление связи через ICE / STUN / TURN

Для преодоления NAT и файрволов используется стандарт ICE (Interactive Connectivity Establishment):

  • STUN-серверы: Определяют публичный IP-адрес и порт клиента (используются публичные Google STUN).
  • Direct P2P: В ~80% случаев клиенты устанавливают прямое соединение (UDP/TCP).
  • TURN-серверы (Relay): Если оба пира находятся за строгим NAT (Symmetric NAT), трафик инкапсулируется и ретранслируется через TURN-сервер в зашифрованном виде. TURN-сервер не может расшифровать AES-GCM трафик.

4.3. Бинарный протокол WebRTC DataChannel

Для обмена используется RTCDataChannel со следующей конфигурацией:

const dataChannelOptions = {
  ordered: true,         // Гарантия порядка доставки
  maxRetransmits: 3000   // Настройка повторной отправки при потере пакетов
};

Типы служебных кадров (Payload Types):

Тип Описание
MSG Зашифрованное текстовое сообщение
FILE_HEADER Метаданные файла (имя, размер, тип, количество чанков)
FILE_CHUNK Зашифрованный фрагмент файла
ACK Подтверждение получения кадра
TYPING Уведомление о наборе текста
PING / PONG Проверка активности соединения (Heartbeat)

5. Структура проекта

nopeer.pw/
├── client/                     # Фронтенд-приложение (Client-Side)
│   ├── index.html              # Основной HTML-интерфейс
│   ├── css/
│   │   ├── main.css            # Главные стили и переменные оформления
│   │   └── components.css      # Стили модальных окон, чата и кнопок
│   ├── js/
│   │   ├── app.js              # Точка входа, оркестрация модулей и UI
│   │   ├── crypto.js           # Web Crypto API: ECDH, AES-GCM, HKDF
│   │   ├── peer.js             # Обертка над WebRTC / PeerJS соединением
│   │   ├── file-transfer.js    # Модуль чанкинга, контроллер буфера и файлов
│   │   └── ui-render.js        # Парсинг Markdown, очистка DOM, уведомления
│   └── assets/                 # Иконки, звуковые эффекты уведомлений
│
├── server/                     # Сигнальный сервер (Signaling Server)
│   ├── server.js               # Точка запуска Node.js / PeerJS сервера
│   ├── config.js               # Конфигурация портов и CORS
│   └── package.json            # Зависимости сервера
│
├── docs/                       # Дополнительная документация и схемы
│   └── SECURITY.md             # Детальный аудит безопасности
├── .gitignore
├── LICENSE                     # Лицензия MIT
└── README.md                   # Документация проекта

6. Развертывание и установка

6.1. Системные требования

  • Node.js: Версия 18.x или выше.
  • NPM / Yarn: Актуальная версия менеджера пакетов.
  • Браузер: Chrome 90+, Firefox 88+, Safari 14.1+, Edge 90+.
  • SSL-сертификат: Обязателен для продакшена. Web Crypto API и WebRTC блокируются браузерами в незашифрованном HTTP контексте (за исключением localhost).

6.2. Установка сигнального сервера

Клонируйте репозиторий:

git clone https://github.com/TheMk-ctrl/nopeer.pw.git
cd nopeer.pw/server

Установите зависимости:

npm install

Запустите сигнальный сервер:

# Запуск в режиме разработки
npm run dev

# Продакшен запуск
npm start

По умолчанию сервер начинает listening на порту 9000.

6.3. Настройка и запуск веб-клиента

Перейдите в директорию клиента и укажите адрес сигнального сервера в конфигурационном файле client/js/peer.js:

const SIGNALING_CONFIG = {
  host: 'your-domain.com', // или 'localhost'
  port: 9000,
  path: '/myapp',
  secure: true // true для HTTPS
};

Запустите статический веб-сервер:

cd ../client
npx serve . -p 3000

Откройте адрес https://localhost:3000 в вашем браузере.


7. Отладка и диагностика

Для контроля состояния P2P-соединений и криптографических процессов в клиент встроен режим отладки.

Включение Debug-режима

В консоли разработчика браузера (F12) выполните:

localStorage.setItem('debug', 'nopeer:*');
location.reload();

Мониторинг WebRTC в браузере

  • Chrome / Edge: chrome://webrtc-internals/ — позволяет просматривать графики битрейта, потери пакетов, состояние ICE-кандидатов и RTT.
  • Firefox: about:webrtc — детальная диагностика SDP-согласований и DataChannel.

8. Лицензия

Проект распространяется под лицензией MIT. Вы можете свободно использовать, копировать, модифицировать и разворачивать данный код как в личных, так и в коммерческих целях.

Copyright (c) Nopeer.pw

About

Открытый веб-мессенджер нового поколения, работающий полностью на стороне клиента (Client-Side Only). Он предоставляет возможность обмениваться мгновенными сообщениями, передавать файлы любого размера, форматировать текст с помощью Markdown и совершать аудиовызовы.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages