import { acknowledgeGooglePlaySubscription, googlePlayAccountId, GooglePlayVerificationError, normalizeGooglePlaySubscription, verifyGooglePlaySubscriptionPayload, } from './google-play.ts' function assert(condition: boolean, message: string): asserts condition { if (!condition) throw new Error(message) } const futureExpiry = '2030-01-01T00:00:00Z' const pastExpiry = '2020-01-01T00:00:00Z' function standardBase64(bytes: Uint8Array): string { let binary = '' for (const byte of bytes) binary += String.fromCharCode(byte) return btoa(binary) } Deno.test('active Google Play subscription grants the mapped tier', () => { const normalized = normalizeGooglePlaySubscription({ startTime: '2029-12-01T00:00:00Z', subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE', acknowledgementState: 'ACKNOWLEDGEMENT_STATE_PENDING', linkedPurchaseToken: 'old-linked-purchase-token', lineItems: [{ productId: 'd3ro_voice_pro_monthly', expiryTime: futureExpiry, latestSuccessfulOrderId: 'GPA.1234-5678-9012-34567', autoRenewingPlan: { autoRenewEnabled: true }, }], }, 'd3ro_voice_pro_monthly', Date.parse('2029-12-15T00:00:00Z')) assert(normalized.tier === 'pro', 'product must map to pro') assert(normalized.entitled, 'active future subscription must be entitled') assert(normalized.purchaseState === 'purchased', 'active subscription must be purchased') assert(normalized.autoRenewing, 'auto renewal must be preserved') assert(!normalized.acknowledged, 'pending acknowledgement must be preserved') assert(normalized.linkedPurchaseToken === 'old-linked-purchase-token', 'linked token must be preserved') assert(normalized.storeTransactionId === 'GPA.1234-5678-9012-34567', 'line-item order id must be preserved') }) Deno.test('out-of-app re-subscription requires a verified prior account binding', async () => { const userId = '11111111-2222-3333-4444-555555555555' const accountId = await googlePlayAccountId(userId) const base = { subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE', lineItems: [{ productId: 'd3ro_voice_pro_monthly', expiryTime: futureExpiry }], } const byExpiredAccount = await verifyGooglePlaySubscriptionPayload( userId, 'd3ro_voice_pro_monthly', { ...base, outOfAppPurchaseContext: { expiredExternalAccountIdentifiers: { obfuscatedExternalAccountId: accountId }, }, }, ) assert(byExpiredAccount.entitled, 'expired account id should bind the re-subscription') const byExpiredToken = await verifyGooglePlaySubscriptionPayload( userId, 'd3ro_voice_pro_monthly', { ...base, outOfAppPurchaseContext: { expiredPurchaseToken: 'known-expired-token' }, }, (token) => Promise.resolve(token === 'known-expired-token'), ) assert(byExpiredToken.entitled, 'server-owned expired token should bind the re-subscription') let rejected = false try { await verifyGooglePlaySubscriptionPayload( userId, 'd3ro_voice_pro_monthly', { ...base, outOfAppPurchaseContext: { expiredPurchaseToken: 'unknown-token' } }, () => Promise.resolve(false), ) } catch (error) { rejected = error instanceof GooglePlayVerificationError && error.code === 'purchase_account_mismatch' } assert(rejected, 'unowned out-of-app purchase must fail closed') }) Deno.test('canceled subscription keeps access only until its verified expiry', () => { const beforeExpiry = normalizeGooglePlaySubscription({ subscriptionState: 'SUBSCRIPTION_STATE_CANCELED', lineItems: [{ productId: 'd3ro_voice_pro_plus_monthly', expiryTime: futureExpiry }], }, 'd3ro_voice_pro_plus_monthly', Date.parse('2029-12-15T00:00:00Z')) assert(beforeExpiry.purchaseState === 'cancelled', 'state must be cancelled') assert(beforeExpiry.entitled, 'canceled subscription retains prepaid access') const afterExpiry = normalizeGooglePlaySubscription({ subscriptionState: 'SUBSCRIPTION_STATE_CANCELED', lineItems: [{ productId: 'd3ro_voice_pro_plus_monthly', expiryTime: pastExpiry }], }, 'd3ro_voice_pro_plus_monthly', Date.parse('2029-12-15T00:00:00Z')) assert(!afterExpiry.entitled, 'expired canceled subscription must not grant access') }) Deno.test('unknown and mismatched products fail closed', () => { for (const productId of ['unknown_product', 'd3ro_voice_pro_monthly']) { let error: unknown try { normalizeGooglePlaySubscription({ subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE', lineItems: [{ productId: 'different_product', expiryTime: futureExpiry }], }, productId) } catch (candidate) { error = candidate } assert(error instanceof GooglePlayVerificationError, 'invalid product must fail explicitly') } }) Deno.test('obfuscated account id is deterministic and contains no raw UUID', async () => { const userId = '11111111-2222-3333-4444-555555555555' const accountId = await googlePlayAccountId(userId) assert(accountId.length === 64, 'account hash must be SHA-256 hex') assert(!accountId.includes(userId), 'raw user id must not be exposed to the store') assert(accountId === await googlePlayAccountId(userId), 'account hash must be stable') }) Deno.test('Google Play subscription is acknowledged by the server API', async () => { const keyPair = await crypto.subtle.generateKey({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: Uint8Array.from([1, 0, 1]), hash: 'SHA-256', }, true, ['sign', 'verify']) const privateKey = new Uint8Array(await crypto.subtle.exportKey('pkcs8', keyPair.privateKey)) const privateKeyBase64 = standardBase64(privateKey).match(/.{1,64}/g)?.join('\n') ?? '' const serviceAccount = { client_email: 'play-verifier@example.iam.gserviceaccount.com', private_key: `-----BEGIN PRIVATE KEY-----\n${privateKeyBase64}\n-----END PRIVATE KEY-----\n`, token_uri: 'https://oauth2.googleapis.com/token', } Deno.env.set('GOOGLE_PLAY_SERVICE_ACCOUNT_JSON', JSON.stringify(serviceAccount)) Deno.env.set('GOOGLE_PLAY_PACKAGE_NAME', 'com.d3ro.voice') const requestedUrls: string[] = [] const fakeFetch: typeof fetch = (input, init) => { const url = String(input) requestedUrls.push(url) if (url === 'https://oauth2.googleapis.com/token') { return Promise.resolve(new Response(JSON.stringify({ access_token: 'fixture-access-token', expires_in: 3600 }), { status: 200, headers: { 'Content-Type': 'application/json' }, })) } const requestInit = init as { method?: string; headers?: unknown } | undefined assert(requestInit?.method === 'POST', 'acknowledgement must use POST') assert(requestInit.headers !== undefined, 'acknowledgement must be authenticated') return Promise.resolve(new Response(null, { status: 204 })) } try { await acknowledgeGooglePlaySubscription( 'd3ro_voice_pro_monthly', 'fixture-purchase-token', fakeFetch, ) } finally { Deno.env.delete('GOOGLE_PLAY_SERVICE_ACCOUNT_JSON') Deno.env.delete('GOOGLE_PLAY_PACKAGE_NAME') } assert(requestedUrls.length === 2, 'OAuth and acknowledge endpoints must both be called') assert( requestedUrls[1].endsWith('/purchases/subscriptions/d3ro_voice_pro_monthly/tokens/fixture-purchase-token:acknowledge'), 'acknowledge endpoint must bind package, product and purchase token', ) })