Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert cached subscription status & reinstate stub #1324

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 11 additions & 64 deletions typescript/src/subscription-status/googleSubStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import {
import {APIGatewayProxyEvent, APIGatewayProxyResult} from "aws-lambda";
import {fetchGoogleSubscription} from "../services/google-play";
import {optionalMsToDate} from "../utils/dates";
import {ReadSubscription} from "../models/subscription";
import {dynamoMapper} from "../utils/aws";
import {createHash} from 'crypto'
import {Option} from "../utils/option";

type SubscriptionStatus = {
interface SubscriptionStatusResponse {
"subscriptionHasLapsed": boolean
"subscriptionExpiryDate": Date
}
Expand All @@ -35,68 +33,17 @@ function googlePackageName(headers: HttpRequestHeaders): string {

export async function handler(request: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {

const purchaseToken = getPurchaseToken(request.headers);
const subscriptionId = getSubscriptionId(request.pathParameters);
const packageName = googlePackageName(request.headers);
const today = new Date()
const subscriptionExpiryDate = new Date(today.setMonth(today.getMonth() + 1))

if (purchaseToken && subscriptionId) {
const purchaseTokenHash = createHash('sha256').update(purchaseToken).digest('hex')
console.log(`Searching for valid ${subscriptionId} subscription for Android app with package name: ${packageName}, for purchaseToken hash: ${purchaseTokenHash}`)
try {
const subscriptionStatus =
await getSubscriptionStatusFromDynamo(purchaseToken, purchaseTokenHash) ??
await getSubscriptionStatusFromGoogle(subscriptionId, purchaseToken, packageName, purchaseTokenHash)

if (subscriptionStatus !== null) {
return { statusCode: 200, body: JSON.stringify(subscriptionStatus) }
} else {
console.log(`No subscription found found for purchaseToken hash: ${purchaseTokenHash}`)
return HTTPResponses.NOT_FOUND;
}
} catch (error: any) {
console.log(`Serving an Internal Server Error due to: ${error.toString().split('/tokens/')[0]}`)
return HTTPResponses.INTERNAL_ERROR
}
} else {
return HTTPResponses.INVALID_REQUEST
const responseBody: SubscriptionStatusResponse = {
"subscriptionHasLapsed": false,
"subscriptionExpiryDate": subscriptionExpiryDate
}
}


async function getSubscriptionStatusFromGoogle(subscriptionId: string, purchaseToken: string, packageName: string, purchaseTokenHash: string): Promise<SubscriptionStatus | null> {
console.log(`Fetching subscription from Google for purchaseToken hash: ${purchaseTokenHash}`)
const subscription = await fetchGoogleSubscription(subscriptionId, purchaseToken, packageName)
const subscriptionExpiryDate = optionalMsToDate(subscription?.expiryTimeMillis)
const googleSubscriptionStatus = subscriptionExpiryDate ? subscriptionStatus(subscriptionExpiryDate) : null
console.log(`Google SubscriptionStatus for purchaseToken hash: ${purchaseTokenHash}: ${JSON.stringify(googleSubscriptionStatus)}`)
return googleSubscriptionStatus
}

async function getSubscriptionStatusFromDynamo(purchaseToken: string, purchaseTokenHash: string): Promise<SubscriptionStatus | null> {
try {
console.log(`Fetching subscription from Dynamo for purchaseToken hash: ${purchaseTokenHash}`)
let itemToQuery = new ReadSubscription()
itemToQuery.setSubscriptionId(purchaseToken)
const subscription = await dynamoMapper.get(itemToQuery)
const subscriptionExpiryDate = new Date(subscription.endTimestamp)
const dynamoSubscriptionStatus = subscriptionStatus(subscriptionExpiryDate)
console.log(`Dynamo SubscriptionStatus for purchaseToken hash: ${purchaseTokenHash}: ${JSON.stringify(dynamoSubscriptionStatus)}`)
return dynamoSubscriptionStatus
} catch (error: any) {
if (error.name === 'ItemNotFoundException') {
console.log(`No subscription found in Dynamo with purchaseToken hash: ${purchaseTokenHash}`)
} else {
console.log(`The following Dynamo error occurred when attempting to retrieve a subscription with purchaseToken hash: ${purchaseTokenHash}: ${error}`)
}
// All exceptions are swallowed here as we fall-back on the Google API for all failure modes (including cache misses)
return null
}
}
console.log("Returning a stub 200 response")

function subscriptionStatus(expiryDate: Date): SubscriptionStatus {
const now = new Date(Date.now())
return {
"subscriptionHasLapsed": now > expiryDate,
"subscriptionExpiryDate": expiryDate
}
// We are returning a stubbed response as a temporary workaround to a rate limit issue that
// is currently causing a production incident for our Android subscribers.
return { statusCode: 200, body: JSON.stringify(responseBody) }
}
Loading