Merge pull request #13606 from mozilla/fxa-5417

fix(auth): ensure /app-store-notification endpoint returns 200s
This commit is contained in:
Bianca Danforth 2022-07-14 19:17:40 -04:00 коммит произвёл GitHub
Родитель 55b88cf01a b494747e5f
Коммит 1e8634d3d5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 39 добавлений и 8 удалений

Просмотреть файл

@ -37,7 +37,7 @@ export class AppleIapHandler {
try { try {
({ bundleId, originalTransactionId, decodedPayload } = ({ bundleId, originalTransactionId, decodedPayload } =
await this.appStore.purchaseManager.decodeNotificationPayload( await this.appStore.purchaseManager.decodeNotificationPayload(
request.payload as any (request.payload as any).signedPayload
)); ));
} catch (err) { } catch (err) {
// app-store-server-api compiles CertificateValidationError to a function, // app-store-server-api compiles CertificateValidationError to a function,
@ -157,7 +157,15 @@ export const appleIapRoutes = (): ServerRoute[] => {
options: { options: {
...SUBSCRIPTIONS_DOCS.OAUTH_SUBSCRIPTIONS_IAP_APP_STORE_NOTIFICATION_POST, ...SUBSCRIPTIONS_DOCS.OAUTH_SUBSCRIPTIONS_IAP_APP_STORE_NOTIFICATION_POST,
validate: { validate: {
payload: isA.string().required() as any, // https://developer.apple.com/documentation/appstoreservernotifications/responsebodyv2
payload: isA
.object({
signedPayload: isA.string().required(),
})
.required() as any,
},
payload: {
maxBytes: 37000, // twice the expected size
}, },
}, },
handler: (request: AuthRequest) => handler: (request: AuthRequest) =>

Просмотреть файл

@ -245,6 +245,24 @@ describe('PurchaseManager', () => {
assert.deepEqual(result, mockSubscriptionWithNotificationProps); assert.deepEqual(result, mockSubscriptionWithNotificationProps);
}); });
it('adds only notificationType to the purchase if notificationSubtype is undefined when passed in', async () => {
mockPurchaseDoc.data = sinon.fake.returns({});
mockPurchaseDoc.exists = true;
const notificationType = 'foo';
const notificationSubtype = undefined;
const mockSubscriptionWithNotificationProp = {
...mockSubscription,
latestNotificationType: notificationType,
};
const result = await purchaseManager.querySubscriptionPurchase(
mockBundleId,
mockOriginalTransactionId,
notificationType,
notificationSubtype
);
assert.deepEqual(result, mockSubscriptionWithNotificationProp);
});
it('throws unexpected library error', async () => { it('throws unexpected library error', async () => {
mockPurchaseDoc.ref.set = sinon.fake.rejects(new Error('test')); mockPurchaseDoc.ref.set = sinon.fake.rejects(new Error('test'));
try { try {

Просмотреть файл

@ -162,7 +162,9 @@ describe('AppleIapHandler', () => {
userId: 'test1234', userId: 'test1234',
}; };
mockRequest = { mockRequest = {
payload: {}, payload: {
signedPayload: 'base64 encoded string',
},
}; };
appleIap.purchaseManager = { appleIap.purchaseManager = {
decodeNotificationPayload: sinon.fake.resolves({ decodeNotificationPayload: sinon.fake.resolves({
@ -178,7 +180,10 @@ describe('AppleIapHandler', () => {
it('handles a notification that requires profile updating', async () => { it('handles a notification that requires profile updating', async () => {
const result = await appleIapHandler.processNotification(mockRequest); const result = await appleIapHandler.processNotification(mockRequest);
assert.deepEqual(result, {}); assert.deepEqual(result, {});
assert.calledOnce(appleIap.purchaseManager.decodeNotificationPayload); assert.calledOnceWithExactly(
appleIap.purchaseManager.decodeNotificationPayload,
mockRequest.payload.signedPayload
);
assert.calledOnce(appleIap.purchaseManager.getSubscriptionPurchase); assert.calledOnce(appleIap.purchaseManager.getSubscriptionPurchase);
assert.calledOnce(appleIap.purchaseManager.processNotification); assert.calledOnce(appleIap.purchaseManager.processNotification);
assert.calledOnce(mockCapabilityService.iapUpdate); assert.calledOnce(mockCapabilityService.iapUpdate);

Просмотреть файл

@ -93,10 +93,10 @@ export class PurchaseManager {
// triggered by a notification // triggered by a notification
if (triggerNotificationType !== undefined) { if (triggerNotificationType !== undefined) {
subscriptionPurchase.latestNotificationType = triggerNotificationType; subscriptionPurchase.latestNotificationType = triggerNotificationType;
// This may be `undefined`, but we assign regardless to clear any previous if (triggerNotificationSubtype !== undefined) {
// notification's subtype value. subscriptionPurchase.latestNotificationSubtype =
subscriptionPurchase.latestNotificationSubtype = triggerNotificationSubtype;
triggerNotificationSubtype; }
} }
// Convert subscriptionPurchase object to a format that to be stored in Firestore // Convert subscriptionPurchase object to a format that to be stored in Firestore