Skip to content

Improve TLS-rejection diagnosis and visibility - #261

Merged
taylorcox75 merged 1 commit into
release/v3.8.45from
bugfix/#256-tls-rejection-visibility
Sep 21, 2026
Merged

taylorcox75 merged 1 commit into
release/v3.8.45from
bugfix/#256-tls-rejection-visibility

Conversation

@taylorcox75

Copy link
Copy Markdown
Owner

Summary

Related to #256. The reporter's underlying connection failure is not fixed here — that's still waiting on repro details the owner requested on the issue (does the toggle still show ON, is the failure instant or ~10s, a connectivity-log screenshot). What ships now is the diagnosis/visibility half described in the plan's "What you CAN ship now" section, so a rejected certificate stops being indistinguishable from a dead server:

  • utils/error.ts — new isTlsRejection(error) recognizes iOS rejecting a server's TLS certificate from the free-text description React Native's XHR bridge puts on error.request.response (the native NSError's localizedDescription — RN forwards only that string, not the NSURLErrorDomain code). Matches language-neutral SSL/TLS terms plus "certificate" translated into all six locales this app ships, since that description text is localized to the device's language.
  • services/api/client.ts — the network-error branch (ECONNABORTED/ERR_NETWORK) now checks isTlsRejection first and throws a new, distinct message ("Certificate rejected. Enable...") with a clogWarn('TLS', ...), instead of folding it into the existing 'Connection timeout...' string that callers substring-match. The new message is deliberately kept out of RECONNECTABLE_MESSAGES — a rejected cert isn't something a re-login fixes, so it shouldn't trigger a reconnect loop.
  • modules/insecure-cert-allowlist/index.ts — new isInsecureCertAllowlistAvailable(). OTA JS updates ship independently of the native binary, so a device can get this module's JS wrapper without its native half (a binary predating #... whichever PR added it). Previously the toggle just silently no-op'd with zero signal. services/server-manager.ts's syncInsecureCertAllowlist now warns via clogWarn('CERT', ...) when a server wants the flag but it's unavailable, and app/server/add.tsx/app/server/[id].tsx show a hint under the toggle ("Requires the latest App Store version") in that case.
  • components/SuperDebugPanel.tsx — both REACH probes (Feature 1 "Ping Host" and Step 1 of the full diagnostic run) switch from fetch() to a raw XMLHttpRequest. The certificate-specific guidance text existed but was unreachable: RN's whatwg-fetch polyfill collapses every network-level failure, including a rejected cert, into a bare TypeError('Network request failed'), so the generic branch always won. The raw XHR preserves the response-body detail isTlsRejection needs, same as the app's real HTTP client already relies on.
  • AGENTS.md — File Index updates for the above, plus a new §10 Gotcha: a native-module-backed feature can be delivered via OTA to a binary that lacks the native module, and the JS wrapper no-ops silently rather than erroring — check availability explicitly.

Scope note: per the plan, this branch does not touch app/(tabs)/(torrents)/index.tsx, context/TorrentContext.tsx, or context/TransferContext.tsx (owned by other tasks in this milestone) beyond the two files (services/api/client.ts, services/server-manager.ts) it was explicitly blocked-then-unblocked on Task A (#254, already merged) to edit.

Test plan

  • npx tsc --noEmit → exit 0
  • npm test → 79 suites / 1160 tests, all passing (includes new isTlsRejection unit tests in tests/utils/error.test.ts and new network-error-branch tests in tests/services/client.test.ts, covering an English description, a non-English description, and a plain ERR_NETWORK that must not be misclassified)
  • npm run lint → 0 errors, 37 warnings (documented baseline)
  • npm run format → applied
  • Not run in a simulator — no device/simulator available in this environment. The UI-visible changes (the toggle hint in server add/edit, and the SuperDebugPanel REACH probe behavior) could not be visually verified; the owner should confirm them in Xcode.

🤖 Generated with Claude Code

A rejected self-signed certificate was indistinguishable from a dead
server, so nobody could tell what was wrong. This does not fix the
reporter's underlying connection failure (still awaiting repro details
on the issue) — it ships the diagnosis/visibility half:

- utils/error.ts: isTlsRejection(error) recognizes iOS rejecting a
  server's TLS certificate from the free-text description RN's XHR
  bridge exposes on error.request.response, matched across all six
  locales since that text is localized to the device language.
- services/api/client.ts: the network-error branch throws a distinct
  "Certificate rejected..." message (with a clogWarn('TLS', ...)) when
  isTlsRejection matches, instead of the generic connection-timeout
  message, without touching the existing substring-matched strings.
- modules/insecure-cert-allowlist: exports
  isInsecureCertAllowlistAvailable() so a server wanting the allowlist
  flag on a binary that predates the native module (an OTA JS update
  shipped without it) is surfaced instead of silently no-op-ing —
  services/server-manager.ts warns via clogWarn('CERT', ...), and the
  server add/edit screens show a hint under the toggle.
- components/SuperDebugPanel.tsx: both REACH probes switch from
  fetch() to a raw XMLHttpRequest so the certificate-specific guidance
  (previously unreachable, since whatwg-fetch collapses every network
  failure into a bare "Network request failed") can actually fire.
- AGENTS.md: File Index updates plus a new §10 Gotcha entry about an
  OTA-shipped feature silently lacking its native half.
@taylorcox75
taylorcox75 merged commit 71f05bb into release/v3.8.45 Sep 21, 2026
1 check failed
@taylorcox75
taylorcox75 deleted the bugfix/#256-tls-rejection-visibility branch September 21, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant