ProtonVPN import: support Proton's human-verification (CAPTCHA) flow #150
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Blocks the end of #33: Proton deterministically gates POST /auth behind a CAPTCHA for any appversion it does not recognize. Probe evidence (same machine, nonexistent user, seconds apart):
x-pm-appversion: Other→ 422/9001 withHumanVerificationMethods: ["captcha"](no email/sms offered); the official client's appversion string → 8002 wrong-password. Impersonating the official client is off the table, so every aqomui login will hit this gate.The 9001 reply carries what the intended flow needs:
HumanVerificationToken,ExpiresAt(~30 min), and aWebUrl(verify.proton.me) a human can solve in a normal browser. After solving, retrying the request withx-pm-human-verification-token+x-pm-human-verification-token-type: captchaheaders is the documented path; proton-core'sauthenticate()acceptsadditional_headersand also hashuman_verif_provide_token().Test first (cheap): whether solving the WebUrl grants IP-scoped grace, i.e. a plain retried import just passes without carrying the token. If yes, #146's current message ("solve the link in the log, import again") is already the whole flow.
If the token must ride the retry: persist the pending token root-owned under ROOTDIR keyed by provider when 9001 fires, attach it as additional_headers on the next import attempt, drop it on success/expiry. (Fancier options — interactive continuation over D-Bus, optional QtWebEngine webview like old qomui's AirVPN captcha dialog — only if the simple shape fails.)
🤖 Generated with Claude Code
Core token flow implemented in #146 (
fcd50b4) after live testing proved no IP-scoped grace exists — both a fresh account-credential attempt and an OpenVPN-credential attempt drew fresh 9001s. On demand, the token+expiry persist root-owned at ROOTDIR/-hv.json; the next import attempt sends x-pm-human-verification-token(-type) headers (names confirmed from go-proton-api — proton-core's provide_token is an empty stub) and spends the file on success. This issue stays open for what's left: confirming the solved token is actually accepted live, and UX polish (auto-opening the verification page instead of a log link, or an optional QtWebEngine view).UX options for the verification step, assessed. The constraint: the demand surfaces inside the root service, which cannot open a browser; the URL has to reach the gui process, and the failed-signal payload cannot carry it (& is the field separator).
human_verification_needed(url), gui wires it like the other signals, shows a dialog ('Proton needs a CAPTCHA — solve the page that just opened, then import again') and callsQDesktopServices.openUrl. Moderate wiring, no new deps, uses the user's real browser (which also helps pass the CAPTCHA).Current state after #146: link in the log + failure message pointing at it, token rides the retry automatically. Option 1 is the follow-up this issue should track.
Everything this stayed open for is done: the solved token was confirmed accepted live at #146's merge (full solve→retry→import cycle), and the UX landed in #154 — the verification page auto-opens in the user's browser, an Information dialog with a Continue button re-fires the import with the stored credentials (fresh 2FA code prompted for when the account uses one), all live-tested including the 2FA path. Remaining Proton friction is tracked separately: #147 (session persistence — makes the CAPTCHA once-per-install), #156 (tier-mismatch feedback), #152 (WireGuard).
🤖 Generated with Claude Code