Pro backend 0.2 + libsession 1.7 compatibility updates#2144
Open
jagerman wants to merge 15 commits into
Open
Conversation
Temporary save point — mid-refactor, intentionally not compiling. Will be rebased/rewritten once libsession pins the response-parser structs (FINAL PIN 1f308535 moves response parsing into libsession; the kotlinx response schemas below get deleted in favour of consuming libsession structs). Durable (keep): - Proof/ProProofInfo: gen_index_hash -> revocationTag, expiry ms -> seconds; protobuf accessor setRevocationTag; user-profile get/setProAccessExpiry. - Revocation reshape: InstantAsSecondsSerializer; ProDatabase schema (revocation_tag/effective_ts/retain_until_ts, isRevoked >= effective_ts, retain_for aging) + lokiV61 migration; RevocationListPollingWorker caller. - AddProPaymentApi request build: provider slug + Google token|order_id payment_id. Superseded (to delete when libsession response structs land): - GetProDetailsApi ProDetails/Item kotlinx schema, GetProRevocationsApi schema, ProProof response serializer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Save point (app does NOT compile yet — consumers/display still reference the now-deleted response schemas). - ProApi base: endpoint + buildJsonBody + kotlinx responseDeserializer -> buildProRequest(): ProRequest (endpoint+body from libsession) and parseResponse(json): Res (typed struct from libsession); check res.header. - GetProDetailsApi -> GetProDetailsResponse (parsePaymentDetailsResponse). - GenerateProProofApi / AddProPaymentApi -> ProProofResponse. - GetProRevocationApi -> GetProRevocationsResponse. Still TODO next: delete orphaned ProDetails/ProRevocations kotlinx schemas; migrate ProDataMapper/ProDatabase/ProStatusManager/FetchProDetailsWorker/ RevocationListPollingWorker to the glue structs; provider display (names from Crowdin, URLs from libsession provider_urls); .data now ProProofResponse.proof. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e source) provideProBackendConfig() now sources the backend URL + Ed25519 signing pubkey from the glue (BackendRequests.proBackendUrl() / proBackendPubKeyHex(), backed by session::pro_backend::URL / PUBKEY) instead of the BuildConfig.PRO_BACKEND_DEV copy — so a future URL/pubkey change happens only in libsession. x25519 is still derived on the fly in ProBackendConfig. (The now-unused PRO_BACKEND_DEV buildConfigField in app/build.gradle.kts can be removed separately.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ded) The glue's ProRequest now carries contentType; relay it as the Content-Type header instead of hardcoding "application/json", so the wire format stays a libsession<-> backend contract the app never assumes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
libsession no longer supplies provider display names (device/store/platform/ account) — they're client-owned i18n now. Hand-add the English values to values/strings.xml so R.string.proProvider* compiles for the app-side pro provider-metadata migration. TODO (Jason): these MUST be added upstream on Crowdin (project 618696) + approved + synced BEFORE the next translations regen, or the sync deletes them. Marker: TODO(crowdin) comment in strings.xml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tract Drop the ErrorStatus generic + convertErrorStatus(Int) mechanism: the header is now a closed status enum + open error_code slug + diagnostic error. ProApi is single-type-param; a Failure carries a typed ProApiError(status, errorCode, error) with isRetryable (backend Error, or unknown_payment). Added ProErrorCode slug constants (§5.1). All *Api subclasses drop the ErrorStatus arg; deleted AddPaymentErrorStatus (int enum), GetProProofStatus, and the orphaned GetProRevocations @serializable schema. addProPayment: already-redeemed special-case deleted (ok now always carries a proof — a re-claim succeeds), success saves data.proof, failures retry when retryable else raise PaymentServerException. Get-details consumers (ProDataMapper/workers/DB) still reference the old ProDetails shape — migrated in the next commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New app-side PaymentProviderMetadata (replaces the removed libsession type): display names from local proProvider* strings, URLs from the glue's providerUrls(slug). - ProDataMapper.toProStatus now maps GetProDetailsResponse: userStatus slug (never/active/expired via ProUserStatus; no account-level revoked), plan slug -> ProSubscriptionDuration, provider slug -> metadata, Instant/Duration fields. - ProStatus.providerData now uses the app-side PaymentProviderMetadata. Plumbing (workers/DB/repository/ProStatusManager call sites, delete orphaned ProDetails) + error_code->Crowdin follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the get-details plumbing off the deleted wire-vestige ProDetails onto the clean @serializable glue struct: - ProDatabase caches GetProDetailsResponse (tolerates a stale/incompatible blob by dropping it -> refetch); repository LoadState + workers use it. - FetchProDetailsWorker / ProProofGenerationWorker: userStatus slug (ProUserStatus) instead of the int DETAILS_STATUS_*; ok-responses carry a proof (requireNotNull). - ProStatusManager: toProStatus(now, context); debug mock states + non-originating UI build PaymentProviderMetadata via providerMetadata(slug, context). - Delete the orphaned ProDetails / ServerProDetailsStatus / DETAILS_STATUS_*. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e messages
Resolve provider display names from pro_provider_<slug>_<suffix> (with unknown/slug
fallback); build the {pro_stores} purchasable-store list from BackendRequests.visiblePlatforms()
(google_play first, gated on the store translation existing); map error_code slugs to localized
pro_error_<slug> strings. Removes the hardcoded DEFAULT_*_STORE constants and PLATFORM_STORE2_KEY.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…table schema The pro_revocations CREATE TABLE still declared the old gen_index_hash/expiry_ms columns while all queries used revocation_tag/effective_ts/retain_until_ts — inserts would have hit missing columns. Fixed the schema to match. No migration (Session Pro has not shipped). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
My earlier fix edited ProDatabase.createTable (the lokiV57 migration step) to the new revocation_tag/effective_ts/retain_until_ts schema. That is the wrong place to change: createTable is replayed as the lokiV57 upgrade step for installs coming from older versions, so it must keep the shape it originally shipped with. The actual schema change is already handled correctly by reshapeRevocationsForSeconds (lokiV61), which DROPs and recreates the table with the seconds schema and runs for every upgrading and fresh install. Restore createTable to the original gen_index_hash/expiry_ms shape so the migration history is honest; reshape supersedes it. No functional change (reshape is terminal and always runs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FetchProDetailsWorker cleared the pro config whenever userStatus != ACTIVE, which also fires for any unknown/future status slug. removeProConfig() writes the SYNCED user profile, so an older client that doesn't recognise a new status would erase a still-valid proof and propagate the deletion to all the user's devices. Only clear on the authoritative terminal statuses (EXPIRED/NEVER); leave the proof untouched on an unrecognised status. Its own expiry governs entitlement, and the backend won't refresh (or will revoke) a genuinely-lapsed account. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion-foundation#15) Move the app onto the split-out get_pro_status endpoint (the light "am I Pro?" call); the paginated get_payment_details history endpoint is library-only and is not wired (no android UI uses payment history). - api/GetProDetailsApi -> GetProStatusApi: buildGetProStatusRequest (drops the count=10 param, get_pro_status has no count) + parseProStatusResponse. - ProDataMapper: GetProStatusResponse; the single latestPayment replaces items.firstOrNull()/items[0]. Unknown-status handling is unchanged (proof is only cleared on EXPIRED/NEVER, never on an unknown status). - FetchProDetailsWorker -> FetchProStatusWorker, ProDetailsRepository -> ProStatusRepository, plus ProProofGenerationWorker / ProStatusManager / ProDatabase / settings view-models: full *ProDetails* -> *ProStatus* terminology purge (types, functions, workers, DB accessors). - ProDatabase: the persisted pro-status cache key is renamed pro_details -> pro_status. This orphans any previously cached blob; it is re-fetched on next poll and the feature is pre-release + gated by forcePostPro(), so this is benign. Pairs with the libsession-util-android glue commit that re-pins libsession to 3f8aace0 and reshapes GetProStatusResponse. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render every plan period generically from libsession's parsed (count, unit)
instead of fixed month buckets, and carry (count, unit) throughout instead of a
re-parsed slug:
- ProStatus.Active.duration is a ProPlanPeriod(count, unit); ProDataMapper builds
it from the glue's structured (planCount, planUnit) — no slug regex.
- SKU catalog (ProSubscriptionDuration) holds (count, unit) per opaque store slug.
The annual SKU is (1, YEAR) to match the backend's "1y" code (ProPlan.TwelveMonth),
never canonicalized, so current-plan matching works.
- Choose-plan cards are one generic pair of strings — "{plan_length} - {monthly_price}
/ month" and "{price} billed every {plan_length}" — replacing the six fixed
proPrice*/proBilled* keys; {plan_length} comes from the ICU formatter.
- DateUtils: MONTH/YEAR added to the plan-length formatter; helper to resolve a
not-yet-synced Crowdin key with an English fallback.
New Crowdin keys (to add upstream): proPlanLifetime, proPlanPricePerMonth,
proPlanBilledEvery. Retire: proPrice{One,Three,Twelve}Month(s),
proBilled{Monthly,Quarterly,Annually}.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Derive the per-month discount baseline from the highest per-month price among the available plans (the shortest-duration plan) instead of assuming the 1-month SKU exists. If the monthly plan is ever dropped from the catalog, the discounts still anchor correctly. The baseline plan itself gets 0% and no badge via discountBadge() (already generic — no hardcoded period). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopts the Pro backend response contract and reworks all client-owned Pro display strings to be data-driven off the provider slug, so new payment providers need only translations (no code changes). Relies on the updated
libsession-util-androidglue.This is required for Android compatibility with session-foundation/session-pro-backend#2 and session-foundation/libsession-util#95.
Changes
ProApiconsumes the newstatusenum +errorCode+ singleerror; dropped the oldErrorStatus/errors[]handling and thealready_redeemedspecial-case (a re-claim now returnsok+ a proof).GetProDetailsResponseglue struct (workers,ProDatabase, repository, display mapping).providerMetadata()resolvespro_provider_<slug>_<suffix>(withpro_provider_unknown_*→ raw-slug fallback); removes the hardcoded Google/AppleisApplebranching.{pro_stores}store list: built at runtime fromBackendRequests.visiblePlatforms()(own platform first, gated on the store translation existing) and substituted into the "purchase via …" messages; replaces the old two-store{platform_store}/{platform_store_other}enumeration. Deletes the deadDEFAULT_*_STOREconstants andPLATFORM_STORE2_KEY.error_codeto a localizedpro_error_<slug>string (falling back to the backend diagnostic); non-retryable add-payment failures now surface the specific reason.Dependencies
pro_provider_*,pro_error_*,{pro_stores}messages) land via the shared-scripts Crowdin sync; not committed here.