Commit graph

207 commits

Author SHA1 Message Date
xtclovver
219518c53f fix(checker): не считать kernel-route таблицы local утечкой VPN (#78)
Some checks failed
CI / build (push) Has been cancelled
evaluateHostRoutes выдавал ложное срабатывание "Host route ... (VPN
server IP leak)" на адресе собственного транспортного интерфейса.

netlinkRouteDump делает RTM_GETROUTE с NLM_F_DUMP без указания таблицы,
поэтому в дамп попадают записи таблицы local (table 255), которые ядро
автоматически создаёт для каждого настроенного адреса интерфейса:

  local 12.233.114.164 dev ccmni1 table local proto kernel scope host
      src 12.233.114.164

Такая запись имеет prefixLen=32, type=local, scope=host, dst==prefsrc.
Если адрес интерфейса попадает в публично-маршрутизируемый диапазон
(например 12.0.0.0/8 у сотовых модемов ccmni MediaTek), все условия
фильтра проходили и checker рапортовал утечку.

Добавлен isKernelManagedLocalRoute: исключает type local/broadcast/
anycast/multicast, scope host и dst==prefsrc. Настоящая утечка VPN —
unicast-маршрут к чужому публичному IP (dst!=prefsrc) в main/policy
таблицах — детектируется как прежде.
2026-06-12 14:43:29 +03:00
xtclovver
52b4550427
chore(quality): SonarCloud triage — safe fixes + UI tile bugfix (#77)
Some checks are pending
CI / build (push) Waiting to run
* fix(ui): wire IP-consensus result into its category tile

The IpConsensusReady handler only marked the stage completed and never
called updateTileFromIpConsensus(), unlike every sibling updateTileFrom*
branch. As a result the IP-consensus tile (CATEGORY_IPS) never reflected
detected/review/clean signals. Call the already-written updater with the
event payload.

* chore(quality): low-risk SonarCloud code-smell cleanups

Behavior-preserving fixes for SonarCloud findings, verified by build +
unit tests. No detector signal, threshold, port, or verdict logic changed.

Kotlin:
- extract duplicated string literals to consts (S1192): "*.*.*.*",
  "SHA-512", "meduza.io", "<none>", sing-box core type
- if-throw -> require()/check() for validation (S6532): Ed25519 decode,
  GeoIp HTTP status
- empty catch blocks documented (S108); collapsible if merged (S1066)
- isExpanded() -> val property (S6512) with call-site update
- drop unused lambda parameter (S1172)

C++ (native_signs_probe.cpp, native_curl_probe.cpp):
- read-only netlink/diag pointers made pointer-to-const (S5350)
- split multi-variable declarations (S1659)
- sizeof/sizeof -> std::size for JNI method table (S7127)
- ipv6 prefix loop converted to range-for (S5566)
- progress-callback state pointer made const (S5350)

Riskier findings (cognitive complexity, too-many-params, deep nesting,
flag-guarded null ops that the Kotlin compiler cannot smart-cast) were
left in place. Genuine false positives (C++20/23 suggestions under a
C++17 toolchain, JNI function-pointer decay, intentional reinterpret_cast
in syscall code, sentinel IPs) were marked False Positive / Accepted in
SonarCloud rather than changed.
2026-06-12 02:24:56 +03:00
xtclovver
7fa507c60c
chore(release): v2.9.0 changelog, README sync, version bump (#76)
Подготовка релиза v2.9.0 (versionCode 20900).

- Добавлены fastlane changelog 20900.txt для en-US/ru-RU/fa/zh-CN,
  охватывающие коммиты #73/#74/#75 (6 детекторов VPN/прокси,
  детектор эмулятора/изоляции, профили маркетплейса, Ed25519-подпись
  каталога, фиксы).
- README (все 4 локали) синхронизированы с новыми детекторами:
  дерево архитектуры, паттерны интерфейсов (4.2), BypassChecker
  (Clash API + SOCKS5-auth, 6.4), NativeSignsChecker (TUN/TAP по типу,
  host-route /32, эмулятор, изоляция, 12.1-12.4), тип VPN-транспорта (3.1).
- build.gradle.kts: versionCode 20802 -> 20900, versionName 2.8.2 -> 2.9.0.
2026-06-12 00:56:49 +03:00
xtclovver
3e1a9cf6e6
feat(checker): детектирование эмулятора и изоляции песочницы (#75)
Some checks are pending
CI / build (push) Waiting to run
Приложение определяет, что запущено в эмуляторе или изолированном/
клонированном контексте (вторичный пользователь, рабочий профиль,
dual-app), и поднимает NEEDS_REVIEW. Сетевые детекторы слепы к VPN,
скрытому в другом контексте, поэтому собственная изолированная/
эмулированная среда сама по себе является поводом для ревью.

Что добавлено:
- Native JNI-проба nativeDetectEmulator (QEMU/goldfish/Genymotion/
  BlueStacks) в native_signs_probe.cpp + регистрация в kMethods.
- Bridge NativeSignsBridge.detectEmulator с тест-override.
- Парсер NativeEmulatorFinding в NativeInterfaceProbe.
- Блоки evaluateEmulator (native HIGH + Build-эвристика MEDIUM) и
  evaluateIsolation (вторичный пользователь / клон / рабочий профиль)
  в NativeSignsChecker, вшитые в check().
- Источники NATIVE_EMULATOR и SANDBOX_ISOLATION в EvidenceSource,
  заведены только в NATIVE_REVIEW_SOURCES VerdictEngine (R6): вклад
  строго NEEDS_REVIEW, никогда DETECTED.
- Локализация 5 строк (en/ru/fa/zh-rCN).
- Тесты: парсер, оба эвалуатора, два кейса R6 в VerdictEngineTest.

Контроль качества (адверсариальная проверка): убрана ложноположительная
эвристика MANUFACTURER=="unknown" (легитимные AOSP/бюджетные устройства),
удалён мёртвый path-фоллбэк в clone-детекции (userId уже выводится из
того же пути тем же regex через extractUserId).

Проверено: ./gradlew :app:testDebugUnitTest :app:lintDebug
:app:assembleDebug — BUILD SUCCESSFUL, native-либы для arm64-v8a/
armeabi-v7a/x86_64, без MissingTranslation.
2026-06-12 00:26:30 +03:00
xtclovver
653a9f6413
feat(detect): six competitor-derived VPN/proxy detectors (#74)
* feat(detect): extend VPN interface name patterns (utun/xfrm/zt/tailscale/svpn/gre/l2tp/he-ipv6)

* fix(detect): route xfrm through IPsec disambiguation, narrow l2tp pattern

* feat(detect): classify VPN transport subtype (PLATFORM/LEGACY/IKEV2) via reflection

* chore: fastline add icon and screenshots

* fix: Marketplace fix display error

* feat(detect): host-route /32 heuristic for VPN server IP leak via physical interface

* fix(detect): reuse UrlSanitizer.isPublicAddress for host-route filter, propagate needsReview

* feat(detect): SOCKS5 weak-auth brute and UDP ASSOCIATE bypass probes (loopback, opt-in)

* test(detect): cover proxy auth-probe gate, loopback guard, and join mock acceptors

* feat(detect): Clash/mihomo/sing-box REST API scanner with VPN server IP leak detection

* perf(detect): share single OkHttpClient across Clash API probes

* feat(detect): detect TUN/TAP interfaces by ARPHRD_TUNTAP type (65534) from sysfs

* refactor(detect): name ARPHRD_TUNTAP constant instead of magic 65534

* fix(detect): correct VpnTransportInfo type mapping to AOSP constants (SERVICE/PLATFORM/LEGACY/OEM)
2026-06-12 00:01:35 +03:00
xtclovver
dfb46b716c
Рефакторинг: дедупликация и декомпозиция god-классов с сохранением поведения + фикс багов/защиты у профилей (#73)
* fix: Security upgrade & bug fixes for profiles

* fix: bugs, security and warnings

* chore: README update

* test: expand vpn/ characterization coverage

Add VpnAppClassifierTest (marker priority, case sensitivity, go version
extraction) and extend VpnAppCatalogTest with catalog integrity
invariants, VpnDumpsysParserTest with parser corpus cases,
VpnApkInspectorTest with split-apk/path-edge cases,
VpnAppMetadataScannerTest with null-package/permission/format cases.
Tests pin current behavior before refactoring; no production changes.

* test: fix data race in CdnPullingCheckerTest label collection

fetchEndpoint stubs are invoked from parallel coroutines, but the tests
collected labels into a plain ArrayList, causing intermittent
ArrayIndexOutOfBoundsException. Use CopyOnWriteArrayList.

* refactor: single source of truth for interface name patterns

NetworkInterfaceNameNormalizer no longer redeclares its own base-pattern
list; it now uses NetworkInterfacePatterns.STACKED_BASE_INTERFACES, a
deliberate strict subset of STANDARD_INTERFACES (seth/dummy excluded to
keep v4- de-stacking behavior byte-identical). Pinned the divergence and
classification behavior in NetworkInterfaceNameNormalizerTest.

* refactor: extract strict IP-literal validators into probe/IpLiterals

Move the strict charset+InetAddress validators verbatim out of
CdnPullingClient; the client keeps one-line delegates so all call sites
and tests stay untouched. PublicIpClient.looksLikeIp is deliberately NOT
unified: its loose heuristic is required for mail.ru HTML extraction
(now documented). Add IpLiteralsTest pinning edge cases including the
JDK quirk where IPv4-mapped IPv6 literals parse as Inet4Address.

* refactor: deduplicate checker/ plumbing

- Share a single SignalOutcome data class instead of identical nested
  copies in DirectSignsChecker and IndirectSignsChecker.
- GeoIpChecker: extract fetchBuiltinProvider, the common
  fetch/validate/error skeleton of the five builtin providers; each
  provider keeps its own URL construction and field-path cascades.
- BypassChecker: extract startProxyScanAsync/startXrayScanAsync so
  check() is orchestration only; progress-callback wiring unchanged.

No thresholds, signals, finding order or result structures changed.
IndirectSigns/LocationSignals/CallTransport check() bodies were already
step-decomposed and are deliberately left as is.

* refactor: collapse VpnCheckRunner await/publish blocks into publishOnReady

Replace 11 identical await -> throwIfCancelled -> publish wrapper blocks
with a generic publishOnReady helper using CheckUpdate constructor
references. Same supervisorScope receiver, same null contract, same
publish order; BypassProgress, IpConsensusReady and VerdictReady paths
untouched.

* test: golden snapshots and section-parity net for export formatters

Pin the byte-exact output of all three CheckResult formatters (Markdown,
JSON, debug diagnostics) for the rich fixture, privacy mode on and off,
with UTC/Locale.US pinned and a fixed timestamp. Actual outputs are
dumped to build/export-golden-actual/ for easy regeneration after an
intentional format change. The parity test additionally asserts every
populated section appears in every formatter, guarding the three
independent traversals against silent drift.

No shared traversal/visitor is introduced on purpose: the formatters
diverge deliberately (separators, masking policy, flag emission), so
unification would change export bytes.

* test: add markdown golden files missed by the global *.md gitignore

Allow-list app/src/test/resources/export/golden/*.md so golden
regeneration keeps working.

* test: pin custom-check editor read/write semantics before decomposition

Round-trip test (non-default config in every section survives open-save
unchanged), defaults test (untouched new profile saves the exact literal
defaults from saveAndExit), and official-fork test (saving a profile
whose official flag survived the storage trust chain produces a new id,
an edited-suffix name, cleared marketplaceInfo and sourceProfileId).

* refactor: decompose custom-check editor into per-section binders

SettingsCustomCheckEditorFragment (1593 -> 422 lines) now delegates each
checker section to a SectionBinder in customcheck/ui/editor/: bind()
loads the profile slice into the body views, collect() reconstructs it
with the exact legacy defaults, summary() renders the collapsed line.
Shared plumbing extracted alongside: EndpointPills (pill rows),
InlineEndpointSection (add/edit wiring for the three
InlineEndpointEditorController-backed sections), EditorSectionBinders
(visual order). Reachability domains moved into their binder; the
generic custom-domain list, section accordion state, dependency
enforcement and the save/fork flow stay in the fragment.

Read/write semantics are pinned by SettingsCustomCheckEditorRoundTripTest
(previous commit) and were not changed. Dead makeDialogContainer/
makeDialogEdit helpers dropped.

* refactor: replace MainActivity tile id-mappers with a static tile table

ui/main/CategoryTiles declares the twelve category tiles (id, header
title/icon resources, per-tile view ids) in accordion order; MainActivity
category constants now alias the table ids and setupCategoryAccordion/
createTileHolder consume TileSpec directly. Removes the eight mechanical
when-mappers (~130 lines). Tile behavior, the tiles field and TileHolder
member names are unchanged (MainActivityUiRenderingTest reflection net
passes unmodified).

* refactor: extract scan-report export flow into MainExportController

ui/main/MainExportController owns the format/action dialogs, the two
CreateDocument launchers, clipboard copy and document writing, moved
verbatim from MainActivity. The controller is constructed as an activity
field initializer, preserving the pre-STARTED launcher registration
timing; the export snapshot and the debug-clipboard toggle stay in the
activity and are supplied via lambdas.

* fix: NoSuchElementException race in ScanCancellationSignal.cancel

callbacks.entries.toList() takes the size==1 fast path through first(),
which throws NoSuchElementException when a checker unregisters its
callback concurrently. Snapshot through the concurrent map iterator
instead; invocation-after-clear ordering and the register() double-check
contract are unchanged. Surfaced as an intermittent failure of
VpnCheckRunnerTest cancelled-execution test.

* refactor: deduplicate MainActivity loading-stage view mapping

showLoadingCardForStage and markLoadingStagesCancelled repeated the same
stage -> card/icon/status/findings/info-section bundle twice; both now
share a single categoryViewsForStage table. bindCardStoppedState mirrors
bindCardLoadingState, removing the four copies of the stopped-state
icon/status block. Per-stage behavior is unchanged.

Deliberate deviation from the original phase plan: a separate
LoadingStageCoordinator class would have needed ~10 injected callbacks
for the same effect; in-place deduplication wins on risk and size.

* fix: preserve {ip}-placeholder GeoIP provider URLs across profile round trip

UrlSanitizer.sanitizeHttpsUrl runs the URL through java.net.URI, which
throws on the illegal { } chars, so any custom GeoIP provider whose URL
embeds the documented {ip} placeholder was silently dropped on every
profile save/load. Add sanitizeGeoIpProviderUrl, which validates a copy
with {ip} replaced by a public IP literal (8.8.8.8) and returns the
original string when it passes. Wire deserializeGeoIp to it.

The {ip} substitution only exists in GeoIpChecker.fetchCustomProvider;
IpComparison/CdnPulling send URLs verbatim, so they keep the generic
sanitizer. canonicalHash semantics unchanged.

* fix: localize IP-channels markdown export header

CheckResultMarkdownExportFormatter hardcoded the Russian '## IP каналы' section header, leaking Russian into en/fa/zh exports. Use the existing R.string.ip_channels_title resource via the Context the formatter already receives. Goldens regenerated (US locale -> 'IP channels').

* fix: localize remaining Russian literals in Markdown export formatter

Replace hardcoded RU strings in CheckResultMarkdownExportFormatter with
context.getString lookups so en/fa/zh exports no longer leak Russian:
- IP-channels table column headers (Channel/Country/Sources)
- "Flags:" prefix
- operator-whitelist section (title, Detected yes/no, control suffix,
  Duration label/ms unit, available/unavailable)

Add export_* string resources to all four locales (en/ru/fa/zh-rCN) and
drop the object-level AVAILABLE/UNAVAILABLE consts. Regenerate export
golden snapshots (now render under Locale.US in English) and update the
operator-whitelist unit-test assertions accordingly.

* refactor: extract main render environment and FindingViewFactory

* refactor: extract CategoryCardRenderer from MainActivity

* refactor: extract IP-comparison and CDN-pulling renderers

* refactor: extract call-transport, bypass, IP-channels and reachability renderers

* refactor: extract VerdictRenderer and finish MainActivity render decomposition
2026-06-11 19:50:36 +03:00
xtclovver
7142ea1c6c fix: bugs
Some checks failed
CI / build (push) Has been cancelled
2026-05-25 20:14:54 +03:00
xtclovver
f6e9df2a35 feat: Strengthening profile security 2026-05-25 19:18:49 +03:00
xtclovver
595e4335f6 feat: add marketplace and profiles 2026-05-25 19:04:15 +03:00
xtclovver
74d256a28d refactor: restructure packages and dedup utilities
Some checks failed
CI / build (push) Has been cancelled
2026-05-19 18:53:44 +03:00
xtclovver
a830c52b8e chore: remove dead code 2026-05-19 18:53:31 +03:00
xtclovver
8aaa6b5f43 chore: warnings fix 2026-05-19 17:48:26 +03:00
AR34
2325f1d59b
Add Telegram & Fix Warings (#68) 2026-05-19 17:16:41 +03:00
xtclovver
63e9b97a36 feat: детекция белых списков оператора и per-app TUN-зонд (#61)
Some checks failed
CI / build (push) Has been cancelled
2026-05-15 03:14:32 +03:00
xtclovver
7b101d20e8 fix: errors catch fot RTT
Some checks are pending
CI / build (push) Waiting to run
2026-05-13 20:24:02 +03:00
xtclovver
ff6cb6b534 fiz: баги 2026-05-11 20:54:33 +03:00
xtclovver
e9b7bb6667 fix&feat: Error показывается в UI корректно и ложно не вызывает "Нужна проверка" (#66) 2026-05-11 16:47:02 +03:00
xtclovver
dd33d2f03f fix: Исправлено ложноположительное срабатывание при роуминге иностранной SIM в России (issue #63)
Some checks failed
CI / build (push) Has been cancelled
2026-05-08 16:32:49 +03:00
xtclovver
562b13e729 feat: больше информации в экспорте данных 2026-05-08 15:36:13 +03:00
xtclovver
04179db9a7 fix: обновить версию до 2.7.0
Some checks are pending
CI / build (push) Waiting to run
2026-05-08 02:56:13 +03:00
xtclovver
7006854473 feat: Расширение провайдеров для GeoIP проверки 2026-05-08 02:52:40 +03:00
xtclovver
a9f5dacff1 feat: add to underlying check yandex endpoint (#61) 2026-05-08 02:09:50 +03:00
xtclovver
88c32fee81 fix: Verdict Engine более логично отдаёт решение 2026-05-08 01:53:26 +03:00
xtclovver
350eabb9d6 fix: Location Services now works as intended 2026-05-08 01:05:13 +03:00
xtclovver
e7d76f9b4b feat: Выбор между классической и новой иконкой приложения 2026-05-07 23:02:54 +03:00
xtclovver
e16a78fd5e feat: StatsService check 2026-05-07 23:01:37 +03:00
xtclovver
4a9ed45762 feat: редизайн иконки
Some checks are pending
CI / build (push) Waiting to run
2026-05-07 03:38:54 +03:00
xtclovver
e2d2d1fb11 feat: SNITCH проверка (β) (#49) 2026-05-07 01:21:35 +03:00
xtclovver
859f3ca515 fix: Дополнить список доменов в предупреждении 2026-05-07 00:23:46 +03:00
xtclovver
d49d391469 fix: обновить версию до 2.6.11 2026-05-06 21:28:37 +03:00
xtclovver
3c5343391f fix: disable dependenciesInfo for F-Droid reproducible build 2026-05-06 21:28:28 +03:00
xtclovver
2385802479 fix: обновить версию до 2.6.10 2026-05-06 21:10:17 +03:00
xtclovver
85845fb42e chore:remove build-id from CMakeLists 2026-05-06 21:09:48 +03:00
xtclovver
20d8255720 fix: подготовить воспроизводимый релиз 2.6.9 2026-05-06 20:02:51 +03:00
xtclovver
f69af5e6db choreL build.gradle.kts now using static build
Some checks are pending
CI / build (push) Waiting to run
2026-05-06 16:08:10 +03:00
ArThirtyFour
575322489f Fix crush 2026-05-01 15:25:39 +03:00
xtclovver
b4aeca20f9 chore: FDROID decrease greadle & AGP version 2026-05-01 02:00:33 +03:00
ArThirtyFour
3bff7276d0 Add links to Matrix 2026-04-30 20:27:21 +03:00
xtclovver
24061b0d3e fix: bugs and unit tests 2026-04-30 18:31:37 +03:00
xtclovver
fb2f7ec123 feat: настройки цветов для людей с CVD (цветовой слепотой) 2026-04-30 17:27:38 +03:00
xtclovver
195482503c feat: обнаружение авторизированных Happ прокси 2026-04-30 04:21:31 +03:00
xtclovver
e43c0f04ed feat: HUSI like scan 2026-04-30 03:59:22 +03:00
xtclovver
cb802a3123 test: покрытие detectPackagesWithVpnInName в InstalledVpnAppDetector 2026-04-27 16:59:41 +03:00
ArThirtyFour
6a1b17e7a9 теперь должен вроде не жаловаться 2026-04-23 20:50:23 +03:00
xtclovver
556457ddcd fix: VerdictEngine теперь корректно обрабатывает сценарии корпоративного VPN в РФ и т.п ситуации 2026-04-23 20:50:23 +03:00
notcvnt
3c267a3d8e fix: вернуть debug настройку обратно 2026-04-23 20:50:23 +03:00
ArThirtyFour
c05870238b Fix 2026-04-23 20:32:07 +03:00
ArThirtyFour
5140bc9dc3 Add strings 2026-04-22 21:07:28 +03:00
ArThirtyFour
04c1a16622 Fix kakish 2026-04-22 20:56:37 +03:00
ArThirtyFour
bb5b2896b6 Add Delect add with "VPN" in Title 2026-04-22 20:23:34 +03:00