Get provider auto-update working, cleanly for ProtonVPN #157

Merged
mysticalsoap merged 2 commits from auto-update-scheduler into trunk 2026-08-24 17:33:56 -04:00
Owner

Problem

The 5-day provider auto-update has been dead since the fork: the gui's update_check hangs off a check_update signal nothing emits (#142). And even if it fired, a ProtonVPN update re-feeds the stored auth file into the import — which since #146 holds the fetched OpenVPN pair, which cannot pass SRP — so it would die on the misleading "perhaps the credentials you entered are wrong" popup, with 2FA accounts unservable in any case (#147).

Fix

  • #142 — the scheduler moves into the service, which already owns the import threads, the *_last timestamps and config.json, and keeps working with no gui running: a QTimer checks 5 minutes after start (gated on the network being up) and every 6 hours, importing any provider ≥5 days stale. The sender-derived homedir the server list is delivered to is remembered in homedirs.json; providers without one are skipped. The dead gui trigger chain (check_update signals, check_for_update, update_check + queue) is removed.
  • #147 — every successful ProtonVPN import persists the proton-core session (__getstate__ dict, root-owned 0600 next to the certs) and no longer logs out on success (logout would revoke the stored tokens). A scheduled update resumes it via refresh() and never attempts SRP — no password, no TOTP needed. A dead refresh token drops the stored session and fails with an honest sign-in-required message; a transient network failure leaves the session alone and reports as a network error.

Verification

  • pytest green locally (357 passed), plus the CI ruff/compileall gates.
  • New coverage: TestAutoUpdateCheck (8 cases: due/fresh/off/no-network/no-homedir/no-auth-file/already-running/never-imported) and TestProtonSession (6 cases: persist+perms, renewal resume without SRP, missing/dead/transient-failure sessions, failed download leaves nothing).
  • Live verification still pending: packaging/arch/build-branch-and-install.sh, then backdate ProtonVPN_last in /usr/share/aqomui/config.json and restart the service to watch a real renewal run.

Closes #142, closes #147.

🤖 Generated with Claude Code

## Problem The 5-day provider auto-update has been dead since the fork: the gui's `update_check` hangs off a `check_update` signal nothing emits (#142). And even if it fired, a ProtonVPN update re-feeds the stored auth file into the import — which since #146 holds the fetched OpenVPN pair, which cannot pass SRP — so it would die on the misleading "perhaps the credentials you entered are wrong" popup, with 2FA accounts unservable in any case (#147). ## Fix - **#142** — the scheduler moves into the service, which already owns the import threads, the `*_last` timestamps and config.json, and keeps working with no gui running: a QTimer checks 5 minutes after start (gated on the network being up) and every 6 hours, importing any provider ≥5 days stale. The sender-derived homedir the server list is delivered to is remembered in `homedirs.json`; providers without one are skipped. The dead gui trigger chain (`check_update` signals, `check_for_update`, `update_check` + queue) is removed. - **#147** — every successful ProtonVPN import persists the proton-core session (`__getstate__` dict, root-owned 0600 next to the certs) and no longer logs out on success (logout would revoke the stored tokens). A scheduled update resumes it via `refresh()` and never attempts SRP — no password, no TOTP needed. A dead refresh token drops the stored session and fails with an honest sign-in-required message; a transient network failure leaves the session alone and reports as a network error. ## Verification - `pytest` green locally (357 passed), plus the CI ruff/compileall gates. - New coverage: `TestAutoUpdateCheck` (8 cases: due/fresh/off/no-network/no-homedir/no-auth-file/already-running/never-imported) and `TestProtonSession` (6 cases: persist+perms, renewal resume without SRP, missing/dead/transient-failure sessions, failed download leaves nothing). - Live verification still pending: `packaging/arch/build-branch-and-install.sh`, then backdate `ProtonVPN_last` in `/usr/share/aqomui/config.json` and restart the service to watch a real renewal run. Closes #142, closes #147. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The gui's update_check was connected to a check_update signal nothing
emits -- upstream triggered it from PingThread.finished, and that wiring
was lost in the fork, so the 5-day auto-update never ran (#142).

Rather than re-porting the gui trigger, the scheduler moves into the
service, which already owns the import threads, the *_last timestamps
and config.json, and keeps updating with no gui running. The one piece
only the gui knew -- the sender-derived homedir the imported server list
is delivered to -- is now remembered in homedirs.json across restarts;
a provider with no recorded homedir is skipped, never guessed at.

Checks run 5 minutes after start (waiting out boot-time network setup,
and gated on the network being up) and every 6 hours after that; the
threshold stays at 5 days. Closes #142.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: resume ProtonVPN updates from a persisted session, not SRP
All checks were successful
ci / test (pull_request) Successful in 29s
ci / test (push) Successful in 31s
01f6f94720
Since the auth file deliberately holds the OpenVPN pair fetched from
/vpn, a scheduled update feeding it back into the import could never
pass SRP and died on the misleading credentials popup; 2FA accounts
were unservable even with account credentials stored (#147).

Every successful import now persists the proton-core session (its
__getstate__ dict, root-owned 0600 next to the certs), and the success
path no longer logs out -- that would revoke the tokens just stored. A
scheduled update, marked by the credentials=unknown convention as
renewal on the thread, resumes that session with refresh() and never
attempts SRP: a refreshed session needs no password and no fresh TOTP.
A dead refresh token removes the stored session and fails as an honest
sign-in-required message; a transient network failure leaves it in
place and reports as a network error. Closes #147.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Live verification done (2026-08-24): after a manual re-import seeded the session (CAPTCHA solve, as expected for the first sign-in), a backdated ProtonVPN_last + service restart produced a scheduled renewal at the 5-minute mark — straight from "Last ProtonVPN update: 14 days ago - updating" to the server download with no SRP/CAPTCHA/2FA, 750 servers imported, session file re-saved root-owned 0600.

The iptables WARNINGs visible during the run predate this branch: the per-import DNS-exception failed-deletes are #158 (dangling "-D" with no "-I" anywhere), and the cgroup batches are the bypass rebuild's usual delete-before-insert noise.

🤖 Generated with Claude Code

Live verification done (2026-08-24): after a manual re-import seeded the session (CAPTCHA solve, as expected for the first sign-in), a backdated `ProtonVPN_last` + service restart produced a scheduled renewal at the 5-minute mark — straight from "Last ProtonVPN update: 14 days ago - updating" to the server download with no SRP/CAPTCHA/2FA, 750 servers imported, session file re-saved root-owned 0600. The iptables WARNINGs visible during the run predate this branch: the per-import DNS-exception failed-deletes are #158 (dangling "-D" with no "-I" anywhere), and the cgroup batches are the bypass rebuild's usual delete-before-insert noise. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mysticalsoap deleted branch auto-update-scheduler 2026-08-24 17:33:56 -04:00
Sign in to join this conversation.
No description provided.