Skip to content

More pro fixes - #2152

Merged
jagerman merged 5 commits into
session-foundation:devfrom
jagerman:fix-pro-grace-display
Aug 6, 2026
Merged

More pro fixes#2152
jagerman merged 5 commits into
session-foundation:devfrom
jagerman:fix-pro-grace-display

Conversation

@jagerman

@jagerman jagerman commented Aug 6, 2026

Copy link
Copy Markdown
Member

(on top of #2150, removing Pro gating)

  • Fixes how grace period is dealt with: the expiry is just the expiry, NOT the grace period, and is now properly based on the account expiry NOT the proof expiry. This fixes issues where warnings about expiry would come up before they should.
  • Clear config's pro expiry when we get new pro expiry data from the backend
  • Fix a bug where the "pro expired" splash screen would come up when the account renewed while the app was closed. The trigger was happening before the status had been updated, thus acting on stale data. Now the splash screen requires a status refresh before it shows up.
  • If the pro proof was still good and new due for renewal (as often happens shortly after expiry, while in the grace period) then initiating a new subscription was not forcing a status update, so you'd pay and go back to the Pro screen but it would still show you as expired. Fixed by forcing a status update immediately after making a payment. (Two commits: the first tried to trigger a new proof, but that is a no-op in this case; the second commit updates to trigger a status update).

The ACTIVE branch computed renewingAt = expiry − grace and inGracePeriod =
now ∈ [expiry−grace, expiry). But user_status stays `active` through the grace
window (the backend judges coverage against expiry + grace_period_duration), so
the renewal is due AT the paid-through `expiry`, and being past it while still
active IS the grace period. Subtracting grace put "renew due" a whole grace
period early, so in sandbox (grace ≫ the compressed test period) inGracePeriod
was perpetually true — the UI showed "renewal unsuccessful" constantly instead
of an expiry countdown.

renewingAt is now the account expiry; inGracePeriod is now >= expiry.
Handle the generate_pro_proof Failure explicitly instead of collapsing it to a
RuntimeException. On not_subscribed / revoked / subscription_expired (and no
purchase in flight) clear the cached access-expiry E and drop the now-defunct
credential (downgrade-guarded). Required so the acquire loop terminates: with
libsession's renewal target now firing on "future E but no proof", a stale
future E left after a not-entitled response would spin (remove_pro_config only
clears `s`, never `E`). Proof success still sets E from account_expiry.
The expired splash keyed off the cached get_pro_status (proDataState.type) and
ignored the fetch's refreshState, so on a cold foreground it flashed the stale
pre-renewal EXPIRED — and latched via hasSeenProExpired. Gate it on
refreshState is State.Success: only after a get_pro_status request that actually
succeeded (the round-trip completed and the backend answered — even "expired"),
never off a failed/in-flight fetch. Consistent with the iOS CTA gate.
…hows active

Minting the proof is what makes the backend validate the payment and mark the
account active, so the display-only get_pro_status behind the Pro settings
screen is stale "expired" right after a purchase. Force-refresh it on proof-gen
success so the UI flips to active on its own instead of needing a manual
"Check Pro Status".
…mption

The store takes the payment but the backend only learns of it via an async store
notification, so a single refresh right after the purchase usually reads a stale
"expired" and nothing re-fetches — the proof (if any) is still valid so the
renewal loop stays dormant, and pro_prepaid is suppressed while a proof is held
(so re-subscribing during the grace window drives no redemption poll at all).

Chase the ACCOUNT expiry instead: on onPurchaseInFlight, fire get_pro_status
immediately, then — pacing off each fetch's COMPLETION (requestRefresh enqueues
with REPLACE, so re-firing mid-flight would cancel/restart a slow onion request
forever) — wait 5s and retry until the account expiry advances past its
pre-purchase value, for up to ~2 minutes since the first request (so 30s-timeout
onion requests still get a few attempts). Stop signal is expiry-advanced, not
status==active, so extending an already-active subscription is handled too.

Deliberately does not rotate the proof early (that would leak the subscription
change via the rotating seed) — the grace proof renews on its own schedule.
@jagerman
jagerman force-pushed the fix-pro-grace-display branch from f189f62 to 93904ae Compare August 6, 2026 15:55
@jagerman
jagerman merged commit f7e0660 into session-foundation:dev Aug 6, 2026
3 of 5 checks passed
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.

2 participants