Files
wt cf25e28c28
Rust verification / test (push) Successful in 4m10s
initial commit
2026-10-28 15:59:54 +07:00

103 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2FAuth на Rust — 0.3.0
Целевая версия: **2FAuth 8.0.3**, коммит `3516c776a1fcbd83d234efc007e3a49807d6ed91`.
Это развиваемая реализация совместимости, **пока не подтверждённая как полная замена PHP**. Рабочий сервер пользователя не изменялся. Все сравнения выполняются на отдельных синтетических базах, включая копию БД, созданной настоящими Laravel-миграциями.
## Что реализовано
- HOTP, TOTP и Steam; SHA-1/256/512 и MD5; атомарный HOTP-счётчик; URI и экспорт.
- Шифрование Laravel AES-CBC, `APP_KEY`, предыдущие ключи; транзакционное включение/выключение шифрования данных и иконок.
- Аккаунты, группы, порядок и назначения отдельно для каждого пользователя; общие аккаунты, всеобщие ссылки доступа, передача владельца с подтверждением пароля; запрет выдачи секретов получателям.
- Регистрация, вход, CSRF, профиль, смена/восстановление пароля, ограничения регистрации, последний администратор, управление пользователями.
- Passport 13: настоящие RSA JWT, создание/отзыв PAT, существующие PHP bearer-токены и зашифрованные браузерные `laravel_token`. Действующая PHP-cookie может быть преобразована в Rust-сессию при загрузке интерфейса.
- OAuth: authorization code с PKCE, client credentials, Device Code Flow, ротация refresh-токенов и запрет повторного обмена; формат шифрования Defuse PHP совместим с эталоном.
- Перенос Laravel-сессий из файлов и SQLite: JSON/PHP-сериализация, SESSION_ENCRYPT, проверка cookie/CSRF, remember-me и отзыв при выходе.
- WebAuthn: регистрация, вход, список/переименование/удаление устройств, восстановление; импорт существующих зашифрованных PEM-ключей Laragear P-256/RSA/Ed25519. Проверки используют подписанные данные аутентификатора.
- GitHub/OpenID SSO, PKCE, одноразовый state, проверка OIDC JWT при настройке issuer; reverse-proxy-вход только от доверенного сетевого адреса.
- Импорт 2FAuth, Aegis, 2FAS, Bitwarden, текстовых URI и Google Authenticator; вложенные иконки; QR; официальные и локальные наборы иконок.
- Настройки, предпочтения, журналы входа/OTP, уведомления, SMTP/STARTTLS/TLS/sendmail/log; исходный собранный Vue-интерфейс и размещение в подкаталоге.
Подробные доказательства и ограничения: [compatibility/CURRENT.md](compatibility/CURRENT.md), [compatibility/VERIFICATION.md](compatibility/VERIFICATION.md). Старые разделы аудита в `compatibility/README.md` относятся к исходной версии 0.1.0.
## Готовый бинарный файл
В архиве есть `bin/twofauth-rs` для Linux x86_64 GNU. Он проверен в этой среде; для запуска нужны glibc 2.39 или новее и libgcc_s. Контрольная сумма приведена в `bin/BUILD.txt`. Если система старее или имеет другую архитектуру, соберите проект из исходников либо через Docker.
Запускайте бинарный файл из каталога `rust-server`; соседний каталог `public` определяется автоматически. Для новой установки сначала задайте и сохраните `APP_KEY`, затем используйте команды ниже, заменив `./target/release/twofauth-rs` на `./bin/twofauth-rs`. Для имеющейся установки ключи должны остаться прежними.
## Сборка и отдельная тестовая установка
Нужны современный stable Rust, C-компилятор, make и Perl: OpenSSL собирается из исходников для WebAuthn. Сборка Docker в этой среде не запускалась.
```sh
cargo build --locked --release
mkdir -p data
./target/release/twofauth-rs init
RUST_COOKIE_SECURE=false ./target/release/twofauth-rs serve
```
Откройте `http://127.0.0.1:8080`. На пустой БД доступна регистрация; первый пользователь становится администратором. Отключать Secure-cookie следует только для локального HTTP. Для HTTPS оставьте значение по умолчанию.
Можно создать отдельного тестового пользователя через файл пароля:
```sh
./target/release/twofauth-rs create-user --name Test --email test@example.invalid --password-file /path/password.txt
```
`init` отказывается создавать схему поверх существующих пользователей. `create-user` создаёт обычного пользователя. Файл пароля должен быть доступен только владельцу; для этой CLI-команды требуется 12–72 байта.
## Проверка копии существующей SQLite
Сначала сделайте согласованную копию БД и каталога `storage` средствами SQLite/вашего резервного копирования. Не копируйте только основной файл SQLite при незавершённом WAL.
Настройте окружение на **копию**:
```sh
export DB_CONNECTION=sqlite
export DB_DATABASE=/absolute/path/to/copied/database.sqlite
export APP_URL=https://test.example.invalid
export STORAGE_PATH=/absolute/path/to/copied/storage
export PASSPORT_KEY_PATH=/absolute/path/to/copied/storage
# APP_KEY и APP_PREVIOUS_KEYS должны сохранять исходные значения.
./target/release/twofauth-rs prepare-sqlite
./target/release/twofauth-rs serve
```
`prepare-sqlite` проверяет используемые поля таблиц и добавляет только служебные таблицы Rust. Он не выполняет Laravel-миграции и не меняет историю миграций. Если эти служебные таблицы отсутствуют при запуске, `serve` также проверит схему и создаст их. Исходная БД должна уже быть обновлена до целевого PHP-коммита. Поддержка PostgreSQL/MySQL/SQL Server в этой реализации **ещё отсутствует**.
Сохраняйте исходные ключи Passport `oauth-private.key`/`oauth-public.key`, `APP_KEY`, предыдущие ключи и содержимое хранилища. Не генерируйте новые ключи вместо существующих. Для encrypted WebAuthn-ключей `APP_KEY` нужен даже при выключенном шифровании OTP.
## Конфигурация
`DATABASE_URL=sqlite:///absolute/file.sqlite` имеет приоритет над `DB_DATABASE`. По умолчанию используется `sqlite://data/2fauth.sqlite`. Адрес прослушивания: `LISTEN_ADDR`, по умолчанию `127.0.0.1:8080`.
Применяются исходные `APP_URL`, `APP_NAME`, `APP_KEY`, `APP_PREVIOUS_KEYS`, настройки SMTP `MAIL_*`, параметры `GITHUB_*`, `OPENID_*`, `WEBAUTHN_*`, `AUTH_GUARD`/`AUTHENTICATION_GUARD`, `AUTH_PROXY_HEADER_FOR_*`, `TRUSTED_PROXIES`, предпочтения `USERPREF_DEFAULT__*`/`USERPREF_LOCKED__*`.
Дополнительно:
| Параметр | Назначение |
|---|---|
| `STORAGE_PATH` | Каталог Laravel storage; по умолчанию `storage` |
| `PASSPORT_KEY_PATH` | Каталог ключей Passport; по умолчанию `storage` |
| `RUST_PUBLIC_DIR` | Каталог собранного интерфейса; по умолчанию `public` рядом с исходниками |
| `RUST_COOKIE_SECURE` | `false` только для локального HTTP; по умолчанию Secure |
| `APP_SUBDIRECTORY` | Например `/tools/2fa`; `APP_URL` должен содержать тот же путь |
| `SESSION_DRIVER`, `SESSION_TABLE`, `SESSION_COOKIE`, `SESSION_ENCRYPT` | Чтение исходных Laravel-сессий: `file` или `database`; сохраняйте исходные параметры и `STORAGE_PATH` |
| `PASSPORT_JSON_API_ROUTES` | `true` включает исправленные маршруты управления OAuth-клиентами и токенами; по умолчанию выключено, как в закреплённом PHP-эталоне |
| `RUST_OAUTH_CONSENT_ENABLED` | `true` включает исправленный экран согласия OAuth; это явное расширение относительно дефектного маршрута эталона |
| `OPENID_ISSUER` | Включает discovery и проверку подписанного ID token; без него сохранён upstream-flow с явными URL |
| `OPENID_DISCOVERY_URL`, `OPENID_JWKS_URL` | Необязательные переопределения OIDC endpoints |
В Docker каталог `/data` должен быть доступен UID 10001. В образе `STORAGE_PATH` и `PASSPORT_KEY_PATH` указывают на `/data/storage`. Команды и проверки для разработчиков приведены в английском README.
## Что ещё препятствует полной замене
Другие СУБД; остальные Laravel session-хранилища (Redis, cookie и другие); все варианты конфигурации и переводы ошибок; полное сравнение всех маршрутов и middleware; браузерная проверка всех экранов и реальных SSO/WebAuthn-провайдеров. Некоторые диагностические ответы сознательно описывают Rust, а не PHP. QR-код может иметь другое SVG-представление при том же URI. Отдельные ограничения удалённых иконок и почтовых драйверов описаны в `compatibility/CURRENT.md`.
Прохождение ограниченного набора тестов не означает полной совместимости. Боевой PHP-сервер пока не следует выключать на основании этого архива.
## Особенности закреплённого OAuth-эталона
В исходном PHP-файле AppServiceProvider флаг регистрации JSON-маршрутов Passport устанавливается после загрузки пакета. Поэтому `/oauth/clients` и `/oauth/tokens` по умолчанию возвращают SPA для GET и 405 для изменений. Стандартный GET `/oauth/authorize` также неработоспособен: отсутствует реализация AuthorizationViewResponse. По умолчанию сохранено наблюдаемое поведение. Два явных параметра выше включают рабочее управление и согласие для authorization code; экран подтверждения Device Flow в этой версии сохраняет исходную ошибку привязки представления. Эти расширения не считаются точным воспроизведением дефектов эталона.