Android грузит приложение как нативную библиотеку и входит через JNI-символ, а
не через main. Поэтому Tauri-приложение переехало из src/main.rs в src/gui.rs
внутри библиотеки, с #[cfg_attr(mobile, tauri::mobile_entry_point)], а main.rs
стал обёрткой. Модуль объявлен как #[cfg(feature = "gui")], так что свойство
«--no-default-features даёт ядро без Tauri и WebView» сохранилось — проверено
сборкой и 51 тестом headless-варианта.
Переход на rustls — вынужденный, но выгодный. native-tls на Linux и Android
тянет OpenSSL, а openssl-sys не кросскомпилируется под aarch64-linux-android:
сборка падала на нём. rustls на чистом Rust, корневые сертификаты webpki вшиты
в бинарь. Побочно: на Linux исчезла зависимость от системного libssl, а образу
Docker больше не нужен даже ca-certificates.
На этом переходе тест живой сети поймал баг, который прошёл бы в релиз: rustls
0.23 отказывается угадывать криптопровайдер и ПАНИКУЕТ на первом TLS-
рукопожатии. Компиляция чистая, все офлайновые тесты зелёные — они ходят через
локальный маршрут без TLS. То есть в сборку ушло бы приложение, не способное
подключиться ни к чему. Провайдер (ring, кросскомпилируется под Android)
устанавливается в ensure_crypto_provider, регрессию держит тест
a_crypto_provider_is_available_for_tls. Живой тест против шести боевых
дата-центров Telegram проходит.
Прочее:
- open::that заменён на tauri-plugin-opener: у крейта open нет реализации под
Android, а плагин работает на обеих платформах.
- Библиотека переименована в tglock_lib: одинаковые имена lib и bin давали
коллизию выходных файлов, которую cargo обещает сделать ошибкой.
- Программный рендер WebView не применяется на Android — там GPU есть всегда,
и переопределение только замедлило бы интерфейс.
- .gitignore: строка /gen скрывала весь сгенерированный Android-проект. Теперь
игнорируются только артефакты сборки, local.properties и keystore.
Foreground service. Прокси — поток в процессе приложения, и без сервиса система
выгрузит его через минуты после сворачивания. Сервис стартует из MainActivity,
а не по команде из ядра: JNI-мост между Rust и Kotlin осознанно не делался,
чтобы не добавлять слой, который нельзя проверить. Плата — уведомление висит,
пока открыто приложение, даже при выключенной защите.
НЕ ПРОВЕРЕНО: вся Android-часть в рантайме. Устройств не подключено,
эмулятора и системных образов в SDK нет. APK собирается, но приложение никто
ни разу не запускал: ни интерфейс, ни сервис, ни тип specialUse на Android 14+,
ни запрос разрешения на уведомления. Поэтому Android-артефакт сознательно НЕ
добавлен в release.yml — публиковать нечего, пока никто не запустил это на
живом устройстве.
Претензия про VirusTotal всплывала в обсуждениях и не была нигде объяснена.
Отмахнуться «это ложное срабатывание» нельзя: движок реагирует на реальное
поведение программы. Поэтому в README добавлен раздел, который объясняет
механизм и даёт способы проверить, не доверяя автору на слово.
Что написано:
- что увидит пользователь: SmartScreen на Windows, детекты у части движков на
VirusTotal;
- почему: неподписанный файл проверяется эвристиками строже, а поведение —
открыть локальный порт, объявить себя прокси и прописаться в настройки
Telegram — совпадает с профилем прокси-троянов. Программа делает именно это,
только по просьбе пользователя, и автоматически отличить одно от другого
движок не может;
- что подписи не будет: сертификат это ежегодный платёж, проект бесплатный.
Формулировка прямая, без «скоро подпишем»;
- три проверяемых пути: сверка sha256 с digest, который GitHub публикует на
странице релиза (с командами под три ОС), открытый лог сборки в Actions с
указанием конкретного run и коммита, сборка из исходников одной командой;
- если этого недостаточно — не запускать, и это названо нормальным решением, а
не паранойей, со ссылкой на альтернативу.
Конкретные числа детектов не приводятся: они меняются от сборки к сборке и со
временем, обещать «4 из 59» значит закладывать в документацию то, что устареет.
Соответствующие пункты обновлены в ARCHITECTURE_V2.md (Current limitations) и
в статусе ISSUE_AUDIT.md — там это было записано как открытый вопрос,
требующий покупки сертификата, теперь как принятое решение.
Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
Резервный маршрут через Worker был в коде с 2.0, но воспользоваться им никто
не мог: в ARCHITECTURE_V2.md описан только контракт эндпоинта — это
спецификация для того, кто будет писать воркер, а не руководство. Ни скрипта,
ни шагов в репозитории не было. Поэтому люди, у которых легли все обычные
маршруты, писали «не работает» вместо того, чтобы включить запасной выход.
Добавлено:
- worker/tglock-worker.js — готовый скрипт. Проверяет путь и upgrade,
подтверждает подпротокол binary (без этого клиент рвёт рукопожатие),
соединяется только с семью адресами Telegram, которые запрашивает TGLock,
и поддерживает необязательный TGLOCK_TOKEN. Без списка адресов воркер стал
бы открытым TCP-прокси для любого, кто узнает его адрес.
- docs/CLOUDFLARE_WORKER.md — когда это нужно и когда нет (таблица
«что видно в приложении → нужен ли Worker»), установка через веб-интерфейс,
проверка живости, подключение в GUI и через --worker, ограничение доступа,
контракт для своих реализаций.
- Ссылки из README: в FAQ про блокировку web.telegram.org и в блок docs.
Контракт закреплён тестами, чтобы документация не разошлась с кодом:
- worker_path вынесен в функцию, из неё же строятся боевые маршруты;
- documented_worker_contract_matches_the_requested_path сверяет формат пути;
- worker_allowlist_covers_every_address_a_route_can_ask_for падает, если в
маршрутах появится адрес, которого нет в скрипте воркера;
- connects_through_the_documented_worker_contract поднимает сервер, ведущий
себя ровно по документации, и проверяет что туннель работает в обе стороны
и что запрошен именно документированный URI.
Чего тесты не проверяют: развёрнутый воркер в самом Cloudflare. Это указано и
в самой инструкции.
Отдельно: снят флаг prerelease в release.yml. До правки /releases/latest
отдавал v2.0.0-beta.1, то есть кнопка «Скачать» в README вела на сборку без
CLI и без фикса рендера. Существующий релиз v2.0.0-beta.2 помечен как latest
вручную.
Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
Интерфейс построен на системном WebView, а тот без 3D-ускорения окно не
создаёт. Отсюда весь класс жалоб: не стартует в виртуалке, не стартует с
дефолтным драйвером Microsoft, не стартует без монитора. Диагноз в #17 дал
@de4me: в VirtualBox приложение запускается только после включения галочки
«Включить ускорение 3D».
Перед стартом Tauri TGLock теперь сам запрашивает программный рендер:
- Windows: WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS с --disable-gpu
и --disable-gpu-compositing;
- Linux: WEBKIT_DISABLE_COMPOSITING_MODE и WEBKIT_DISABLE_DMABUF_RENDERER;
- macOS: не требуется, WebKit сам уходит в программный рендер.
Для панели со статусом программный рендер не стоит ничего заметного, поэтому
он выбран значением по умолчанию, а не аварийным режимом. Уже заданные
оператором переменные не перезаписываются, TGLOCK_FORCE_GPU=1 отключает
механизм целиком.
Логика вынесена в чистую функцию software_rendering_vars и покрыта четырьмя
тестами: значение по умолчанию, отключение через TGLOCK_FORCE_GPU, уважение
чужой переменной и правильный набор ключей на каждой платформе.
Версия поднята до 2.0.0-beta.2 в Cargo.toml, package.json и tauri.conf.json:
нужен тег, чтобы в релиз попали и tglock-cli, и этот фикс.
README получил отдельный вопрос в FAQ про «окно не появляется»,
ARCHITECTURE_V2.md — обновлённый пункт в Current limitations.
Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
Аудит репозитория после #25 и #26. Расхождения между тем, что написано, и тем,
что есть:
- README обещал `tglock-cli-*` в таблице загрузок, но в релизе
v2.0.0-beta.1 такого артефакта нет: задача `cli` в release.yml сработает
только на следующем теге. Заменено на честную формулировку с командой
сборки из main.
- ui/main.ts держал начальным значением маршрута строку «Автоматический
маршрут», которую бэкенд больше не отдаёт: при коде 0 возвращается
«Маршрут ещё не выбран». Иначе до первого опроса статуса интерфейс
показывал название несуществующего маршрута.
- ARCHITECTURE_V2.md не упоминал ни разделения на библиотеку и два бинаря, ни
фичи `gui`, ни правила различения протоколов, ни политики прямого релея, ни
того, что GUI не запускается без WebView. Добавлены разделы, а последнее
внесено в Current limitations вместе с отсутствием подписи бинарей.
- ISSUE_AUDIT.md описывал состояние на 29 июля. Сам аудит оставлен как
фиксация на дату, сверху добавлен статус на 30 июля: что закрыто, что
осталось открытым и почему, и что исправлено вне списка issues.
- HABR.md — черновик статьи, а не документация, но был указан в README как
«подробный технический разбор». В нём «два файла, 350 строк, четыре
платформы», тогда как сейчас 2872 строки Rust, семь файлов и три платформы
плюс headless. Добавлена шапка с поправкой, ссылка в README переписана так,
чтобы читателя не отправляли к устаревшим числам за документацией.
Проверено: fmt, clippy в обоих вариантах сборки, 47 + 12 тестов, npm run build,
все ссылки на файлы в .md существуют.
Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>