async function payloadToResponse()

in typescript/src/promotional-offers/appleFetchOfferDetails.ts [20:86]


async function payloadToResponse(
  payload: HttpRequestPayload,
): Promise<Response> {
  // https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/generating_a_signature_for_promotional_offers
  // appBundleId         : (from ssm parameter store)
  // keyIdentifier       : (from ssm parameter store)
  // productIdentifier   : (from request payload)
  // offerIdentifier     : (from request payload)
  // applicationUsername : (from request payload as username)
  // nonce               : (server generated)
  // timestamp           : (server generated)

  // Notes:
  //
  //   1. The appBundleId is stored in parameter store because it's different in
  //      CODE and PROD, but should be fairly stable.
  //
  //   2. The private key can be regenerated by one of the apps developers.
  //
  //   3. At the moment we are using the same key for CODE and PROD, but the code is written
  //      to allow for them to be different.
  //
  //   4. If one day a key needs to be replaced, then both the key and its keyIdentifier will
  //      have to be updated in AWS.

  const appBundleId = await getConfigValue<string>(
    'promotional-offers-appBundleId',
  );
  const keyIdentifier = await getConfigValue<string>(
    'promotional-offers-keyIdentifier',
  );
  const productIdentifier = payload.productIdentifier;
  const offerIdentifier = payload.offerIdentifier;
  const applicationUsername = payload.username.toLowerCase();
  const nonce = crypto.randomUUID().toLowerCase();
  const timestamp = Date.now();

  const separator = '\u2063';
  const str1 =
    appBundleId +
    separator +
    keyIdentifier +
    separator +
    productIdentifier +
    separator +
    offerIdentifier +
    separator +
    applicationUsername +
    separator +
    nonce +
    separator +
    timestamp;

  const data = Buffer.from(str1, 'utf8');
  const privateKey1 = await getConfigValue<string>(
    'promotional-offers-encryption-private-key',
  );
  const privateKey2 = crypto.createPrivateKey({ key: privateKey1 });
  const signature = crypto.sign('SHA256', data, privateKey2);

  return {
    nonce: nonce,
    timestamp: timestamp,
    keyIdentifier: keyIdentifier,
    signature: signature.toString('base64'),
  };
}