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

implement requested client-side validation for amazon purchases #1392

Merged
merged 2 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions docs/docs/api_reference/methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ _*deprecated_ ~~`buySubscription(sku: string)`~~<ul><li>sku: subscription ID/sku
`finishTransaction(purchase: InAppPurchase/ProductPurchase, isConsumable?: boolean, developerPayloadAndroid?: string)`<ul><li>purchase: purchase object</li><li>isConsumable?: specify whether the product is a consumable</li><li>developerPayloadAndroid: developerPayload</li></ul> | `Promise<void>` | This method works for both platforms and is recommended since version 4.1.0 or later. Equal to `finishTransactionIOS` + `consumePurchaseAndroid` and `acknowledgePurchaseAndroid`.
_*deprecated_ ~~`buySubscription(sku: string, prevSku?: string, mode?: number)`~~<ul><li>sku: subscription ID/sku</li><li>prevSku: old subscription ID/sku (optional)</li><li>mode: proration mode (optional)</li></ul> | `Promise<Purchase>` | **Android only** Create (buy) a subscription to a sku. For upgrading/downgrading subscription on Android pass the second parameter with current subscription ID, on iOS this is handled automatically by store. You can also optionally pass in a proration mode integer for upgrading/downgrading subscriptions on Android
`validateReceiptAndroid(bundleId: string, productId: string, productToken: string, accessToken: string)` <ul><li>bundleId: the packageName</li><li>productId: productId</li><li>productToken: productToken</li><li>accessToken: accessToken</li><li>isSubscription: isSubscription</li></ul> | `Object\|boolean` | **Android only** Validate receipt.
`validateReceiptAmazon(developerSecret: string, userId: string, receiptId: string, useSandbox : boolean)` <ul><li>developerSecret: from the Amazon developer console</li><li>userId: who purchased the item</li><li>receiptId: long obfuscated string returned when purchasing the item</li><li>useSandbox: Defaults to true, use sandbox environment or production.</li></ul> | `Object\|boolean` | **Amazon only** Validate receipt.
_*deprecated_ ~~`setInstallSourceAndroid()`~~ | `void` | **Android only** It was used to select the Android Module (Amazon or Google Play) This is now handled by the variant selected when running the app. This method will be removed as there's no use for it anymore
39 changes: 38 additions & 1 deletion src/iap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Android from './types/android';
import * as Amazon from './types/amazon';
import * as Apple from './types/apple';

import {
Expand Down Expand Up @@ -696,7 +697,9 @@ export const validateReceiptIos = async (
};

/**
* Validate receipt for Android.
* Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including
* your access token in the binary you ship to users is potentially dangerous.
* Use server side validation instead for your production builds
* @param {string} packageName package name of your app.
* @param {string} productId product id for your in app product.
* @param {string} productToken token for your purchase.
Expand Down Expand Up @@ -733,6 +736,40 @@ export const validateReceiptAndroid = async (
return response.json();
};

/**
* Validate receipt for Amazon. NOTE: This method is here for debugging purposes only. Including
* your developer secret in the binary you ship to users is potentially dangerous.
* Use server side validation instead for your production builds
* @param {string} developerSecret: from the Amazon developer console.
* @param {string} userId who purchased the item.
* @param {string} receiptId long obfuscated string returned when purchasing the item
* @param {boolean} useSandbox Defaults to true, use sandbox environment or production.
* @returns {Promise<object>}
*/
export const validateReceiptAmazon = async (
developerSecret: string,
userId: string,
receiptId: string,
useSandbox: boolean = true,
): Promise<Amazon.ReceiptType> => {
const sandoboxUrl = useSandbox ? 'sandbox/' : '';
const url = `https://appstore-sdk.amazon.com/${sandoboxUrl}version/1.0/verifyReceiptId/developer/${developerSecret}/user/${userId}/receiptId/${receiptId}`;

const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});

if (!response.ok)
throw Object.assign(new Error(response.statusText), {
statusCode: response.status,
});

return response.json();
};

/**
* Add IAP purchase event in ios.
* @returns {callback(e: InAppPurchase | ProductPurchase)}
Expand Down
23 changes: 23 additions & 0 deletions src/types/amazon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* From: https://developer.amazon.com/es/docs/in-app-purchasing/iap-rvs-examples.html
*/
export type ReceiptType = {
autoRenewing: boolean;
betaProduct: boolean;
cancelDate: number | null;
cancelReason: string;
deferredDate: number | null;
deferredSku: number | null;
freeTrialEndDate: number;
gracePeriodEndDate: number;
parentProductId: string;
productId: string;
productType: string;
purchaseDate: number;
quantity: number;
receiptId: string;
renewalDate: number;
term: string;
termSku: string;
testTransaction: boolean;
} & Record<string, unknown>;