Commit Graph
2274 Commits
Author SHA1 Message Date
Dushnilin e1247dad58 fix(install): ash-compatible install commands
- Replace sh <(wget -O - ...) with wget -O /tmp/... && sh /tmp/...
- BusyBox ash on OpenWrt does not support process substitution <(...)
2026-08-25 15:46:16 +03:00
Dushnilin c3172dd82d refactor: remove hardcoded port 4534 — dynamic port from config
- Added get_mixed_port() to core/common.uc (reads sing-box config.json)
- agent_api.uc, api.uc: use common.get_mixed_port()
- warp_generator.uc: use config port instead of hardcoded fallback
- watchdog.uc: use mixed_ports_from_config() for Clash API calls
- runtime.uc: dynamic port in conflict checks and proxy probe
2026-08-25 15:46:03 +03:00
Dushnilin 1aa69d5e03 feat(telegram): full i18n — ~230 Russian strings replaced with t() calls
- Added ~120 new i18n keys to both en and ru sections
- Replaced all remaining hardcoded Russian strings in telegram.uc
- Menu, status, connections, diagnostics, help, subscriptions, quiet hours,
  test rule, export, MAC blocking, devices, watchdog/AI, QoS, section
  management, DNS presets, exec, daily digest, update notifications,
  blocked activity, all navigation buttons
- All keys verified present via runtime check
2026-08-25 15:45:44 +03:00
Dushnilin 2c21dd93c7 fix(telegram): move get_mixed_port() before mixed_port_alive()
ucode doesn't hoist functions — get_mixed_port() must be defined
before mixed_port_alive() which calls it.
2026-08-24 21:09:27 +03:00
Dushnilin 9a3bb6054b fix(telegram): read actual mixed-port from sing-box config
- Add get_mixed_port() helper that reads config.json
- Replace all hardcoded 4534 in telegram.uc with get_mixed_port()
- mixed_port_alive() now checks the real port
- diagnose() checks the real port for proxy health
- Clash API calls use the real port
- Route failure alerts use i18n, remove hardcoded port number
- Fixes LuCI 'Check connection to Telegram' showing false negatives
  when sing-box uses a non-default mixed-port (e.g. 1602)
2026-08-24 21:06:17 +03:00
Dushnilin bd3db0789e fix(tests): update doctor test for i18n format strings 2026-08-24 20:59:56 +03:00
Dushnilin b3a425e524 feat(telegram): i18n en/ru + /lang command
- Create i18n.uc with en/ru string tables (~125 keys)
- Add t() binding at module level, set per-session via UCI telegram.language
- Replace hardcoded Russian in main menu, status, speed, ping, test,
  connections, outbounds, sections, diagnostics, restart, language
- Add /lang command: language picker with UCI persistence
- Setting schema labels translated at display time via get_schema_label()
- 175 t() calls, 245 remaining raw Russian (deep UI only)
2026-08-24 20:36:30 +03:00
Dushnilin 9d0761c14e fix(warp): расширен диапазон IP для генерации WARP
- Добавлены недостающие /24 диапазоны: 162.159.195.0/24, 162.159.204.0/24,
  188.114.96.0/24, 188.114.97.0/24 (ранее было только 4 из 8 диапазонов)
- probe_ips: 9 → 17 IP (по два представителя на каждый /24 + 8.6.112.0)
- resolve_ips/resolve_ips_probe для API-запросов: 4 → 8 IP
- engage.cloudflareclient.com DNS-резолв продолжает добавлять
  динамические IP в пул автоматически
2026-08-24 17:02:39 +03:00
Dushnilin 8f99c40f2e fix(frontend): dashboard status и latency для сервисных секций
- getZapret2Status/getZapretStatus/getSingBoxStatus/getByedpiStatus:
  добавлен allowNonZeroWithStdout — rpcd может вернуть не-zero exit при
  наличии полезного stdout (модуль-провайдер не найден, но JSON-статус
  всё равно отдан). Без этого флага callBaseMethod считал вызов
  провалившимся → serviceStatus undefined → «Неизвестный»
- customProxyLatencies: сервисные секции (SING_BOX, ZAPRET, ZAPRET2,
  BYEDPI) больше не перезаписываются кешем latency-теста. Ранее
  неудачный тест кешировал -1, перезаписывая latency:0 из секции →
  отображалось «-1ms» вместо статуса
2026-08-24 14:39:33 +03:00
Dushnilin 4b80deed5f fix(service): экспорт write_text_file и mixed-вотч по конфигу
- helpers.uc определяла write_text_file, но не экспортировала:
  биндинг в telegram-воркере был null, write_heartbeat падал каждый
  цикл — «Worker loop error: left-hand side is not a function»
  каждые ~25с, heartbeat не писался, воркер зря перезапускался
- watchdog: mixed-порт теперь читается из сгенерённого конфига
  sing-box (inbounds[].type=mixed), а не хардкод 4534. Когда mixed
  выключен (Main.mixed_proxy_enabled=0) — вотч встаёт в сторону
  вместо бесконечных «Restarting sing-box» с пересозданием nftables
  каждые ~5 минут
- проверено на живом роутере: 0 рестартов и 0 ошибок воркера после
  деплоя, E2E зелёный
2026-08-24 13:56:29 +03:00
Dushnilin 890450d619 fix(singbox): mtproxy-инбаунд вместо shadowsocks — корень «decode psk» (#23)
В ветке mtproto тип инбаунда перезатирался на shadowsocks-2022,
и ee-секрет уходил в password: SS2022 парсит его как base64-PSK —
отсюда FATAL «decode psk: illegal base64 data at input byte 60»
у всех, у кого включён MTProto-сервер.

- mtproto снова эмитит type=mtproxy (как в схеме extended 2.6.x),
  юзер — {name, secret}, а не password (регрессия fe0099a3)
- конфиг с MTProto и AWG проверен `sing-box check` на реальном
  sing-box-extended 1.13.18-extended-2.6.5 — PASS
- warp-генератор: прямой префлайт-зонд с --resolve (DNS-отравление
  больше не даёт ложное «API недоступен»), живость 4534 — локальная
  по /proc/net/tcp вместо сквозного запроса через туннель
- багрепорт маскирует ai_doctor_api_key и tuic_password
2026-08-24 11:26:28 +03:00
Dushnilin 6bbc37cfdd fix(service): необъявленные вызовы в watchdog и telegram-воркере
- watchdog: command_output_from_args использовался без биндинга —
  «Graceful degradation: check_mixed_proxy_port failed: left-hand
  side is not a function» на каждом проходе
- telegram: write_heartbeat звал write_text_file из core.helpers,
  который не импортировался — «Worker loop error» каждый цикл,
  heartbeat не писалcя, воркер зря перезапускался по стейлу
- E2E: ноль «left-hand side» в логах OpenWrt-контейнера после фикса
2026-08-24 10:53:06 +03:00
Dushnilin 7da51a62d7 fix(singbox): AWG-джанк в тегах и MTProto-секрет
- i1–i5/j1–j3: классический hex конвертируется в теги <b 0x…>;
  userspace WireGuard extended/lx молча игнорирует голый hex,
  handshake не завершался (#39 #41 #42)
- j1/j2/j3/itime эмитятся только для extended ≤2.6.0: в 2.6.1+
  поля удалены из схемы, sing-box падает на unknown fields
- j1–j3 больше не ломаются uci_bin_to_hex
- h1–h4: диапазоны «min-max» на обеих ветках
- MTProto: секрет канонизируется в ee-hex из любой формы
  (hex/base64), валидатор даёт понятную ошибку вместо
  FATAL decode psk (#23)
- XHTTP v2: парсинг и экспорт ключей подписок
- валидатор: warp/masque/openvpn/snell/mieru/sudoku — только extended
- тесты: stat→ucode (busybox), раннеры исключены из E2E,
  новые server_mtproto.sh и awg_variant_schema.sh
2026-08-24 10:13:33 +03:00
Dushnilin 5031eda81b docs(kb): верификация AmneziaWG в sing-box-extended
Факты расследования issues #39/#42: extended реализует amnezia целиком
(строгий парсер + I1-I5 obf-chain в wireguard-go форке), генерация
Tachyon совпадает со схемой; кейс kernel-vs-userspace остаётся внешним,
зафиксированы шаги диагностики.
2026-08-22 20:01:41 +03:00
Dushnilin 0241e1898f feat(doctor): честный вердикт по мёртвым WireGuard/AWG-туннелям
Жалобы вида «AWG не работает» (#39, #42) почти всегда означают: конфиг
секции применён корректно, но пир не отвечает (сервер лежит, провайдер
режет UDP до эндпоинта). Раньше доктор об этом молчал, и виноватым
выглядел Tachyon.

Новый чек 6c сканирует свежий лог ядра на ошибки outbound/wireguard
(operation timed out / handshake timeout): при свидетельствах мёртвого
туннеля - явный вердикт «проблема вне Tachyon» с подсказкой проверить
сервер и UDP-порт у провайдера. Если wireguard-трафика в логе нет вовсе,
чек не выдаёт ни одной строки - без шума для пользователей без AWG.
2026-08-22 10:46:36 +03:00
Dushnilin 44016ec95b fix(config): ложное предупреждение про AWG, сироты section_interface, дубль cron
- has_outbound_section: туннельные секции (awg/warp/vpn/openvpn/masque/
  anytls/snell/mieru/sudoku) теперь считаются исходящей конфигурацией -
  одинокая AWG-секция больше не получает вводящее в заблуждение
  «No proxy outbound sections found» (жалобы пользователей #39/#42)
- новая миграция orphan_section_interface_cleanup: удаление секции
  маршрутизации раньше оставляло после себя дочерние section_interface,
  ссылающиеся на несуществующего родителя (у пользователя - запись на
  секцию '2' при живой только '1'); сироты удаляются через новую операцию
  delete_section; функция объявлена до массива MIGRATIONS - ucode не
  поднимает объявления
- strip_unmarked_tachyon_cron_lines: старые версии писали cron-строки без
  маркер-комментария, они переживали фильтрацию по маркерам, копились при
  обновлениях и crond запускал component_updates_if_due дважды за тик;
  немаркированные строки с нашими командами теперь вычищаются при каждом
  refresh и remove
2026-08-22 10:08:05 +03:00
Dushnilin c788c86184 fix(warp): префлайт-проверка Cloudflare вместо XHR timeout
На сетях, где api.cloudflareclient.com недоступен (типичный случай из
issue #39), генератор сжигал весь временной бюджет - фронтенд умирал по
XHR timeout через 30 секунд, не показывая причины.

- префлайт: одна проба (4с connect / 6с max) напрямую и через доступный
  транспорт; если Cloudflare недостижим - мгновенная понятная ошибка
  «Cloudflare API недоступен...» вместо минутного зависания
- бюджеты ужаты до 20с на call_api и 20с на всю регистрацию, чтобы
  худший случай укладывался в XHR-таймаут LuCI
- все ошибочные выходы теперь печатают JSON-конверт и exit(0): фронтенд
  парсит data.message и показывает настоящую причину (ненулевой код
  заставлял его писать безликое Unknown error)
2026-08-22 10:07:40 +03:00
Dushnilin e446b370e3 feat(watchdog): самолечение порта 4534 и живости телеграм-воркера
- новая slow-проверка (раз в 5 мин): sing-box запущен, но mixed-порт 4534
  не слушается две проверки подряд (~10 мин) -> один авторестарт ядра;
  если не помогло - уведомление админу не чаще раза в час, без циклов
  бесконечных рестартов
- проверка живости телеграм-воркера: бот включён, pid жив, но heartbeat
  старше 15 минут (зависший long-poll/мёртвый цикл) или pid отсутствует ->
  рестарт воркера через telegram_start с ограничением раз в час
- обе проверки добавлены в perform_slow_checks через safe_call
2026-08-22 10:07:19 +03:00
Dushnilin 28c5c19645 feat(telegram): бот выживает при мёртвом прокси и сам сообщает о проблемах
Корень «бот молчит»: get_proxy_args считал достаточным условием маршрутизации
через 4534 сам факт запущенного sing-box - если mixed-inbound не поднялся,
каждый запрос вечно падал, воркер уходил в бесконечный backoff (468 ретраев
подряд у пользователя), хотя api.telegram.org был доступен напрямую.

- mixed_port_alive(): TCP-проба слушается ли 4534 (netstat) с кэшем 30с;
  маршрут через прокси выдаётся только при живом порте
- tg_request разделён на tg_request_via + fallback-цепочку: прокси не ответил -
  повтор без прокси; отключается UCI telegram.bot_direct_fallback='0'
- алерт админу однократно за эпизод после 5 неудачных опросов подряд с
  указанием причины; сбрасывается при восстановлении опроса
- heartbeat /var/run/tachyon_telegram.heartbeat после каждого успешного
  цикла - основа для вотчдог-проверки живости (следующий коммит)
- ротация tmpfs-лога воркера: потолок 512KB, хвост 100KB, проверка раз в час
- /doctor в боте рендерит человекочитаемую сводку (проблемы/исправлено/
  запланировано) вместо сырого JSON
- config_version убран из человекочитаемого вывода конфига (внутренний
  маркер миграций)
2026-08-22 10:06:56 +03:00
Dushnilin c910e6368e fix(build): po2lmo собирается через Makefile luci
Upstream openwrt/luci убрал template_lmo.c из дерева: po2lmo теперь
линкуется с src/lib/lmo и генерируемым lemon plural_formula, поэтому
прямой вызов gcc больше не работает - только in-tree Makefile.
Проверка наличия template_lmo.c заменена на сборку make po2lmo,
проверено на свежем клоне master.
2026-08-21 21:41:23 +03:00
Dushnilin f29db7d5a3 fix(build): каталог defaults перед install, устойчивый ensure_po2lmo
- build_backend_root ставил defaults/config до создания родительского
  каталога usr/lib/tachyon/defaults - релизная сборка падала на install
  (обнаружено сборкой тега 1.2.89)
- ensure_po2lmo: частичный клон feeds/luci приводил к компиляции без
  template_lmo.c; теперь при отсутствии исходников делается чистый
  переклон, а финальный fallback больше не печатает путь к несуществующему
  бинарнику - сразу явная ошибка
2026-08-21 21:34:08 +03:00
Dushnilin 4716792a95 ci(shellcheck): исключить usr/bin из проверки
tachyon/files/usr/bin/tachyon - ucode-скрипт с shebang #!/usr/bin/ucode,
shellcheck умеет проверять только sh/bash/dash/ksh и падает на нём.
Покрытие cgi-bin и hotplug остаётся.
2026-08-21 21:26:55 +03:00
Dushnilin 2b170c63eb ci(frontend): миграция workflow с yarn на npm
В репозитории лежит package-lock.json и нет yarn.lock, поэтому yarn-workflow
не кэшировал ничего (hashFiles по отсутствующему файлу) и ставил неразрешимые
деревья зависимостей заново каждый раз. Переведено на npm ci с npm-кэшем по
lockfile; проверка diff сборки ограничена выходной директорией LuCI htdocs,
которую build реально производит. Применена prettier-нормализация недавно
правленных исходников.
2026-08-21 21:05:10 +03:00
Dushnilin 41536b7988 test(shell_inventory): агентский CGI в ожидаемом списке shell-скриптов пакета
UTF-8 BOM раньше прятал shebang CGI от скана инвентаря; после удаления BOM
скрипт (корректно) определяется как shell, поэтому ожидаемый список
пополняется tachyon/files/usr/lib/cgi-bin/tachyon-agent.
2026-08-21 21:03:56 +03:00
Dushnilin d097494b23 test(infra): shellcheck не-.sh скриптов, фикс BOM, регрессионный тест RAG
- workflow shellcheck теперь покрывает агентский CGI, hotplug WAN-монитор и
  точки входа usr/bin; в CGI перед shebang стоял UTF-8 BOM, из-за которого
  Linux вообще не мог исполнить скрипт (bad interpreter) - удалён вместе со
  случайными BOM в исходниках фронтенда
- новый rag_embeddings.sh фиксирует исправленный порядок аргументов push(),
  инвалидацию кэша по отпечатку индекса, нормализацию null model_override и
  порядок объявлений - ни один из починенных багов RAG не сможет вернуться
  незаметно
- hosts_li
2026-08-21 20:58:51 +03:00
Dushnilin 0b4edc4789 test(run_all): параллельный запуск с логами по тестам и сводкой pass/fail
run_all.sh гонял набор последовательно с fail-fast: первый упавший тест
отменял всё остальное, а CI (xargs -P4) расходился с локальным порядком.
Теперь поддерживается -P N параллельность как в CI, ведётся лог по каждому
тесту, печатается сводка pass/fail и вывод упавших, принимаются фильтры имён
для запуска подмножества, а ошибки синтакс-проверки по-прежнему прерывают
всё до старта тестов.
2026-08-21 20:50:21 +03:00
Dushnilin fc18082bf6 perf(store): fast-path по ссылке, ограничение живущих всю сессию коллекций
- store.set выполнял JSON.stringify с сортировкой ключей над старым и новым
  значением каждого обновляемого ключа; ежесекундный ui-state poll дважды в
  секунду сериализовал весь payload секций даже без изменений. Дешёвая
  проверка по идентичности отсекает частый случай.
- Sets/Maps учёта задач (handled subscription/latency/component/service jobs,
  custom proxy latencies) росли всю сессию LuCI без границ; теперь они
  ограничены 500 записями через общий хелпер.
- AI-чат модалка: параллельные отправки перемешивали удаление плейсхолдера
  "печатает" и портили ветку диалога; поле ввода и кнопка блокируются на
  время запроса.
2026-08-21 20:41:32 +03:00
Dushnilin 5878e2dfd9 i18n(service-check): локализация захардкоженных русских строк
Модалка проверки доступности сервисов была полностью захардкожена русским
и невидима для po-инструментария: англоязычные пользователи получали русские
надписи. Все литералы обёрнуты в _() с английскими msgid, добавлены ru-
переводы и записи pot; пересобран main.js.
2026-08-21 20:36:51 +03:00
Dushnilin 58feaecb7a perf(monitoring): keyed-реконсиляция строк вместо полной пересборки таблицы
Каждые 500мс вся таблица соединений уничтожалась и создавалась заново даже
без изменений - на сотнях соединений это джанки, убивает выделение текста
(ради чего был написан целый обходной механизм защиты выделения) и постоянно
кормит MutationObserver на всём body потоком мутаций.

Строки теперь ключуются по id соединения: структурно неизменённые строки
получают точечную правку ячеек Time/Downloaded/Uploaded, строки со
изменившимся host/route/source/закрытием заменяются по одной, исчезнувшие
соединения удаляют свою строку. tbody с сообщением состояния ("загрузка",
"остановлен") заменяется целиком.

Заодно исправлены предсуществующие eslint-ошибки (пустые catch-блоки,
неиспользуемые переменные) - npm run lint проходит чисто.
2026-08-21 20:33:04 +03:00
Dushnilin c3d72257ee feat(ui): ошибки действий выводятся тостами, опрос отступает при скрытой вкладке
- общий хелпер notifyActionFailure: глобальная проверка, просмотр логов и
  показ конфига sing-box раньше останавливали спиннер и писали ошибку только
  в лог, оставляя пользователя гадать; теперь неудачи показывают тост с
  деталью ошибки от бэкенда (добавлены ru-переводы)
- опрос runtime UI state при скрытой вкладке отступает до одного запроса в
  30 секунд вместо ежесекундного запуска /usr/bin/tachyon get_ui_state на
  роутере круглые сутки
2026-08-21 19:28:07 +03:00
Dushnilin ca21eb2202 feat(doctor): новые проверки и журнал исходов диагностики
Пять проверок, которых раньше не было, все read-only:

- место на диске: /tmp и overlay при >=90% молча ломают запись кэша,
  загрузку подписок и коммиты конфигов
- системные часы: неверный год валит все TLS-соединения (DoH, подписки,
  LLM API) после холодной загрузки без NTP
- наличие ca-bundle: HTTPS-проверки падают с SSL-ошибками без пакета;
  код уже ссылался на него в вердиктах, но не проверял
- конфликты порта 53: другой DNS-демон на :53 конкурирует с dnsmasq и даёт
  плавающие сбои резолвинга
- возраст кэша подписки: sing-box может гонять трафик через списки узлов
  многодневной давности, хотя сам URL подписки доступен

Плюс журнал исходов (/tmp/tachyon_doctor_history.json, максимум 50 записей):
повторные сбои за 24 часа помечаются как повторяющиеся, а не как уникальный
инцидент.
2026-08-21 19:24:20 +03:00
Dushnilin 7d222fbfe1 feat(doctor): диагностика в dry-run по умолчанию, ремонты по явному запросу
Доктор мутировал систему при каждом диагностическом запуске: отключал
rebind protection dnsmasq, делал kill -9 процессу на портах 4534/9090,
стирал syslog во время OOM-аудита и подменял resolv.conf на 1.1.1.1 как
побочный эффект "проверки".

- run_doctor_checks() теперь только диагностирует в dry-run: каждая мутация
  идёт через обёртки doc_set/doc_commit/doc_run/doc_unlink, которые
  записывают планируемое действие и сообщают "WILL FIX (doctor --fix)";
  ремонты выполняются только через "tachyon doctor --fix" или repair=true
- recovery-проверки (сервис остановлен) следуют тому же правилу
- параллельные запуски доктора из LuCI, Telegram и cron сериализуются
  mkdir-локом со взятием устаревшего лока через 15 минут тишины
- трекер применённых фиксов пишется атомарно (tmp+mv)
- OOM-проверка больше не стирает logread (это форензика) и атрибутирует
  kill именно sing-box
- ai_doctor прогонял весь набор проверок дважды (внутри local_rule_doctor и
  напрямую); результаты считаются один раз и переиспользуются
- curl к LLM/Clash/подпискам получили connect + total таймауты, зависший
  эндпоинт больше не подвешивает доктора
2026-08-21 19:20:05 +03:00
Dushnilin 300ad50417 fix(security): защита CGI агента, права конфига и захват лока
- агентский CGI: /diagnose мог удалять nft-таблицы, переписывать resolv.conf
  и перезапускать sing-box с любого устройства LAN без токена; bearer-токен
  теперь передаётся через окружение вместо argv (виден в ps), тело запроса
  ограничено 64KB до чтения, wildcard Access-Control-Allow-Origin убран -
  произвольные сайты больше не могут читать состояние роутера кросс-доменно
  (включая DNS rebinding)
- agent_api: сравнение токена за константное время
- uci/migration: /etc/config/tachyon хранит Telegram bot token и ссылки на
  подписки; UCI не сохраняет 0600 при коммитах, поэтому режим ужесточается
  после каждого коммита этого конфига и после миграций
- build.yml: убран NODE_TLS_REJECT_UNAUTHORIZED=0 из шагов публикации релиза -
  проверка сертификатов не должна отключаться на раннере, заливающем релизы
- initd/state: устранено окно TOCTOU при захвате устаревшего reload-лока:
  два ожидающих могли оба выполнить rm+rmdir+mkdir и каждый считал лок своим;
  захват теперь атомарным переименованием, которое выигрывает ровно один
  претендент
2026-08-21 19:19:40 +03:00
Dushnilin 8996790f25 fix(core): хотфиксы issues #23, #32, #39, #41
- service_check: lan_interface() запрашивала несуществующий конфиг
  forkop/podkop, из-за чего все проверки сервисов смотрели в br-lan вместо
  настроенных LAN-интерфейсов - секции AWG/WireGuard всегда получали вердикт
  "не отвечает" при рабочем kernel-конфиге (#41, #32, #39)
- rag: у push() были перепутаны аргументы - коллекция эмбеддингов оставалась
  пустой для всех провайдеров OpenAI-формата; кэш эмбеддингов теперь
  инвалидируется по отпечатку индекса (mtime+size), null model_override
  обрабатывается корректно
- warp_generator: curl к Clash API без таймаута и матрица ретраев без общего
  дедлайна могли блокировать выполнение минутами и ловить XHR timeout LuCI
  (#39); добавлены -m 5 на локальные вызовы и бюджеты 40с/90с на весь цикл
- build.sh: релизные пакеты теперь содержат тот же состав файлов, что и
  сборка через OpenWrt Makefile (hotplug WAN-монитор, агентский CGI в
  /usr/lib/cgi-bin, defaults/config, профили servicecheck); конфиги с
  секретами ставятся с правами 0600; тест паритета инвентаря
- updates UI: после самообновления tachyon страница перезагружается только
  когда перезапущенный бэкенд снова отвечает на get_ui_state, вместо
  фиксированной задержки 8 секунд (#23)
2026-08-21 19:19:17 +03:00
Dushnilin 432fa31337 fix(monitoring): форматирование колонки Источник (имя + IP) и расширение колонки до 33% 2026-08-21 15:16:08 +03:00
Dushnilin ae4f7c5128 fix(monitoring): оптимизация ширины колонок таблицы (уменьшена колонка Маршрут) и актуализация каталогов локализации 2026-08-21 15:01:00 +03:00
Dushnilin b2deb9a695 i18n(ru): добавить переводы WARP прокси, проверки Telegram и кнопки проверки подключения 2026-08-21 13:34:55 +03:00
Dushnilin c5bd7ce197 fix(dashboard): отображение AmneziaWG вместо WireGuard, отображение пинга на карточках соединений и фикс генератора WARP 2026-08-21 10:37:27 +03:00
Dushnilin e4e2d19c6d fix(runtime): устранение сбоев запуска sing-box, исправление правил nftables и защита от гонок вочдога
- Восстановление кэша правил: восстановление .srs, .lst, .json файлов из постоянного каталога /etc/tachyon/rulesets/ при старте; защита от удаления кэша при остановке; добавление фоллбэка пустых ruleset в runtime.uc перед валидацией
- nftables: удаление невалидного auto-merge для интервальных составных сетов (ipv4_addr/ipv6_addr . inet_service)
- core/ip: исправление нормализации IPv6-адреса и порта для TPROXY без дублирования скобок
- dns block: исправление возвращаемого статуса nft_add_dns_block_rules_from_schedules при отсутствии правил блокировки
- watchdog & lifecycle: добавление флага блокировки /var/run/tachyon/starting для исключения сброса правил вочдогом во время старта
- ui & i18n: форматирование бейджей устройств в родительском контроле и обновление переводов
2026-08-21 08:52:23 +03:00
Dushnilin adf5c7a22f i18n: добавить русские переводы для content blocking и telegram diagnose 2026-08-21 07:50:11 +03:00
Dushnilin bd083cc5d3 feat: content blocking в родительском контроле (блокировка доменов на устройство)
Новые опции config schedule:
- blocked_domains: домены для блокировки (full:/keyword:/regex: префиксы)
- mode: block (список) | allow (whitelist — всё кроме списка)
- dns_level: блокировка на DNS-уровне (NXDOMAIN через dns-block-in)
- notify: уведомление в Telegram при попытке доступа

Механизм:
- sing-box: новый dns-block-in inbound (127.0.0.43:1053) с reject-правилами
  для заблокированных доменов; source_ip_cidr для IP-устройств;
  invert для whitelist-режима
- nftables: nat chain dns_block — REDIRECT DNS-запросов устройств на
  dns-block-in; time-based через meta hour для расписаний; MAC-устройства
  матчатся по ether saddr (DHCP-динамические IP поддерживаются)
- route rules reject для always-on расписаний (fallback при обходе DNS)
- telegram worker: проверка nft counters каждые 60s, уведомление о
  заблокированной активности

UI (parental.js):
- колонка Blocked Sites в таблице
- textarea с пресетами: соцсети, видео, игры, взрослый контент,
  мессенджеры, магазины
- mode / dns_level / notify переключатели

Валидация: домены, mode, dns_level, notify в validator.uc
Тесты: tests/content_blocking.sh (98/98 backend, 522/522 frontend)
2026-08-21 05:11:39 +03:00
Dushnilin 7084b9ba3d chore: sync localization catalogs after telegram_diagnose strings 2026-08-20 22:28:27 +03:00
Dushnilin 83e1a82e71 feat: add telegram_diagnose backend command and connection test button
Backend: telegram_diagnose returns JSON with 8 checks (token, admin_ids,
sing-box, port, DNS with FakeIP support, direct API, proxy API, send
test message). Registered in CLI dispatcher.

Frontend: Test Connection button in Telegram settings calls
telegram_diagnose and renders results with check/cross icons.

DNS check accepts sing-box FakeIP range (198.18.x.x/198.19.x.x).
2026-08-20 22:17:09 +03:00
Dushnilin 66ffb50a1a feat: add Telegram API connection test button to settings
Runs 7-step diagnostic: token check, sing-box running, port 4534
listening, DNS resolution, direct IPv4 API, proxy API, send test
message. Shows green/red indicators with actionable advice for each.
2026-08-20 21:56:12 +03:00
Dushnilin d6df03e1f2 fix: prevent double update modal after Tachyon self-update page reload
After a self-update completes and the page reloads, the state watcher
finds the old action and opens a second modal. Save the job_id to
sessionStorage before reload, and restore it into handledComponentJobs
on page load so the watcher skips it.
2026-08-20 20:00:39 +03:00
Dushnilin b53b93786a chore: sync locales after adding enable_rag and warp_proxy_section 2026-08-20 19:48:24 +03:00
Dushnilin 2a87db172b fix: add missing enable_rag and warp_proxy_section to LuCI settings form
The custom renderAdvancedSettings panel was never connected to the UI.
Added enable_rag checkbox to AI tab and warp_proxy_section dropdown
to Advanced tab in the standard LuCI settings.js form.

Also fixed warp_proxy_section load function to use map data instead of
uci.sections() which returns an array (for...in iterated indices).

Added Russian translations for new strings.
2026-08-20 19:39:39 +03:00
Dushnilin a9790f5638 fix: remove premature version check during tachyon self-update
The version-based early exit in waitComponentActionJob fired while
the state file still showed running: true and RPC was healthy. This
caused the frontend to declare install complete while the backend
was still restarting services, triggering a page reload before the
install finished.

Now version detection only fires when RPC fails (backend unreachable)
or when state is done with success=false. Normal installs always wait
for the state file to confirm completion.
2026-08-20 17:39:36 +03:00
Dushnilin 364b79ee27 fix: loop unknown inbound field stripping in sing-box config check
The graceful degradation for unknown sing-box inbound fields (e.g.
prefer_ip, tolerate_time_skewness) only retried once. When an older
sing-box version doesn't support multiple new fields, the first
unknown field gets stripped and the retry fails on the second one.

Now loops the check-strip-retry cycle until either:
- sing-box check passes
- no more unknown inbound fields are detected
- no stripping occurred (break to avoid infinite loop)

Fixes: 'Generated sing-box configuration is invalid: inbounds[8].
tolerate_time_skewness: json: unknown field' on older sing-box versions.
2026-08-20 13:57:11 +03:00
Dushnilin c6104289c7 fix: WARP generator proxy-first mode + helpful error message
call_api():
- If warp_proxy_section is set: try proxy FIRST, skip direct entirely
  (saves 32s when CF API is only reachable via tunnel)
- If no section: try direct first, then fallback to proxy (as before)
- Error hint: 'Cloudflare API may be blocked on WAN. Try setting
  warp_proxy_section in Advanced Settings to route through a tunnel.'

Addresses GitHub issue #39 requirements:
- Section/outbound selection for WARP registration: DONE
- No hardcoded Clash API IP: DONE
- Quick fail on dead WAN IPs: DONE (proxy-first mode)
- Helpful error message: DONE
2026-08-20 10:58:41 +03:00