Skip to content

Feature request: in-app WKWebView for manual captcha solving (localhost:8765) #29

@swift2geek

Description

@swift2geek

Body:

Summary

When the bundled vkt-client triggers manual captcha mode, it exposes a captcha proxy at http://localhost:8765. On macOS / Windows / Android the user can open this
URL in any browser and solve the captcha. On iOS this is impossible — Safari can reach localhost but the captcha session token from the NE process is not
shareable, and the user has no way to know a captcha is needed in the first place.

As a result, every TurnBridge connection attempt currently fails silently with the same pattern:

[APP] User requested connect with profile "..."
[APP] VPN status: Connecting
[APP] (12 seconds pass)
[APP] VPN status: Disconnecting
[APP] VPN status: Disconnected

…and PacketTunnel logs show:

[TP] Captcha required, opening proxy on localhost:8765
[TP] (no UI to surface this to user)
[TP] DTLS connection timeout!
[TP] FATAL: 0 connected streams

This has become a hard blocker since VK rolled out the new slider/sound captcha format — the auto-solver fails on every modern attempt, so manual captcha is the only
path forward. iOS is the only platform without a way to access it.

Proposed solution

Add an in-app captcha UI:

  1. When PacketTunnelProvider detects captcha-needed state, write a flag to the App Group shared container (or send a Darwin notification).
  2. Main app observes the flag and:
    • Shows a banner: "Captcha required — tap to solve"
    • Optionally fires a local notification if app is backgrounded
  3. On tap, present a modal sheet with WKWebView pointing at http://localhost:8765.
  4. WKWebView renders the captcha page exactly as Safari would on macOS.
  5. User solves the captcha → vkt-client receives the token → NE proceeds with TURN handshake → tunnel comes up.

Captcha needs to be re-solved roughly every 9 minutes (matches the VK credentials TTL of ~8m52s seen in [VK Auth] Using cached credentials (cache=0, expires in 8m52.852161667s)), so the same UX flow can re-trigger periodically.

Why localhost:8765 should work in WKWebView

NE and the main app run in separate processes but share the same localhost. WKWebView in the main app can reach the captcha proxy listening inside the NE without any
extra plumbing — no need for a custom URL scheme handler.

Implementation hints

  • App Group is already required for any shared state; if not configured, add one (group.com.nullcstring.turnbridge or similar) in entitlements for both targets.
  • IPC: UserDefaults(suiteName:) polling, or CFNotificationCenterGetDarwinNotifyCenter for instant signaling.
  • The captcha proxy URL contains a session token (?session_token=…) that NE should write to the shared container so the main app can construct the full URL.

Related upstream issue

The auto-captcha logic in cacggghp/vk-turn-proxy is currently broken because VK switched from checkbox to slider/sound captcha types — see
https://github.com/cacggghp/vk-turn-proxy issues. Even when that's fixed, manual captcha will likely remain a fallback path, so iOS UI for it is valuable
independently.

Environment

  • TurnBridge build from latest main
  • iOS 26.4.1 (iPhone)
  • Server: vk-turn-proxy v1.8.3 on Debian 13
  • VK call link is valid (verified — call opens in browser, captcha appears on auth)

Happy to test patches and provide more logs. Thanks for the project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions