chromium/components/test/data/payments/get_challenge.js

/*
 * Copyright 2020 The Chromium Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

const kPaymentMethodIdentifier = 'secure-payment-confirmation';

/**
 * Returns the total amount from the clientDataJSON field of the given
 * PaymentResponse.
 * @param {PaymentResponse} response - A response from a secure payment
 * confirmation app.
 * @return {string} - Either the total amount or the string "undefined".
 */
function getTotalFromPaymentResponse(response) {
  try {
    if (!response || !response.details || !response.details.response ||
        !response.details.response.clientDataJSON) {
      return 'undefined';
    }
    const clientDataJSON = String.fromCharCode(...new Uint8Array(
        response.details.response.clientDataJSON));
    const clientData = JSON.parse(clientDataJSON);
    if (!clientData || !clientData.payment || !clientData.payment.total) {
      return 'undefined';
    }
    return clientData.payment.total.value;
  } catch (e) {
    return e.message;
  }
}

/**
 * Returns the total amount from the clientDataJSON field that was set by a
 * secure payment confirmation app.
 * @param {string} credentialId - The base64 encoded identifier of the
 * credential to use for payment.
 * @param {string} totalAmount - The total amount to be charged.
 * @return {Promise<string>} - Either the total amount or an error string.
 */
async function getTotalAmountFromClientData(credentialId, totalAmount) {
  try {
    const request = createPaymentRequest(credentialId, totalAmount, false, '');
    const response = await request.show();
    await response.complete();
    return getTotalFromPaymentResponse(response);
  } catch (e) {
    return e.message;
  }
}

/**
 * Returns the total amount from the clientDataJSON field that was set by a
 * secure payment confirmation app with a modified amount.
 * @param {string} credentialId - The base64 encoded identifier of the
 * credential to use for payment.
 * @param {string} modifiedTotal - The total amount to be charged in the
 * modifier.
 * @return {Promise<string>} - Either the total amount or an error string.
 */
async function getTotalAmountFromClientDataWithModifier(
    credentialId, modifiedTotal) {
  try {
    const request = createPaymentRequest(
        credentialId, '0', true, modifiedTotal);
    const response = await request.show();
    await response.complete();
    return getTotalFromPaymentResponse(response);
  } catch (e) {
    return e.message;
  }
}

/**
 * Returns the total amount from the clientDataJSON field that was set by a
 * secure payment confirmation app. Passes a promise into PaymentRequest.show()
 * that resolves with the finalized price after 0.5 seconds.
 * @param {string} credentialId - The base64 encoded identifier of the
 * credential to use for payment.
 * @param {string} finalizedTotal - The finalized amount to be charged.
 * @return {Promise<string>} - Either the total amount or an error string.
 */
async function getTotalAmountFromClientDataWithShowPromise(
    credentialId, finalizedTotal) {
  try {
    const request = createPaymentRequest(
        credentialId, '0', false, '');
    const response = await request.show(new Promise((resolve) => {
      window.setTimeout(() => {
        resolve(createDetails(finalizedTotal, false, ''));
      }, 500); // 0.5 seconds.
    }));
    await response.complete();
    return getTotalFromPaymentResponse(response);
  } catch (e) {
    return e.message;
  }
}

/**
 * Returns the total amount from the clientDataJSON field that was set by the
 * secure payment confirmation app. Passes a promise into PaymentRequest.show()
 * that resolves with the finalized and modified price after 0.5 seconds.
 * @param {string} credentialId - The base64 encoded identifier of the
 * credential to use for payment.
 * @param {string} finalizedModifierAmount - The finalized amount to be charged.
 * @return {Promise<string>} - Either the total amount or an error string.
 */
async function getTotalAmountFromClientDataWithModifierAndShowPromise(
    credentialId, finalizedModifierAmount) {
  try {
    const request = createPaymentRequest(credentialId, '0', false, '');
    const response = await request.show(new Promise((resolve) => {
      window.setTimeout(() => {
        resolve(createDetails('0', true, finalizedModifierAmount));
      }, 500); // 0.5 seconds.
    }));
    await response.complete();
    return getTotalFromPaymentResponse(response);
  } catch (e) {
    return e.message;
  }
}

/**
 * Creates a PaymentRequest object for secure payment confirmation method.
 * @param {string} credentialId - The base64 encoded identifier of the
 * credential to use for payment.
 * @param {string} totalAmount - The total amount to be charged.
 * @param {bool} withModifier - Whether modifier should be added.
 * @param {string} modifierAmount - The modifier amount, optional.
 * @return {PaymentRequest} - A PaymentRequest object.
 */
function createPaymentRequest(
    credentialId, totalAmount, withModifier, modifierAmount) {
  const challenge = new TextEncoder().encode('hello world');
  return new PaymentRequest(
      [{
        supportedMethods: kPaymentMethodIdentifier,
        data: {
          action: 'authenticate',
          credentialIds:
              [Uint8Array.from(atob(credentialId), (b) => b.charCodeAt(0))],
          timeout: 6000,
          payeeOrigin: 'https://example-payee-origin.test',
          challenge,
          instrument: {
            icon: window.location.origin + '/icon.png',
            displayName: 'My card',
          },
          rpId: 'a.com',
        },
      }],
      createDetails(totalAmount, withModifier, modifierAmount));
}

/**
 * Creates the payment details to be the second parameter of PaymentRequest
 * constructor.
 * @param {string} totalAmount - The total amount.
 * @param {bool} withModifier - Whether modifier should be added.
 * @param {string} modifierAmount - The modifier amount, optional.
 * @return {PaymentDetails} - The payment details with the given total amount.
 */
function createDetails(totalAmount, withModifier, modifierAmount) {
  let result = {
    total: {label: 'TEST', amount: {currency: 'USD', value: totalAmount}},
  };
  if (withModifier) {
    result.modifiers = [{
      supportedMethods: kPaymentMethodIdentifier,
      total: {
        label: 'MODIFIER TEST',
        amount: {currency: 'USD', value: modifierAmount}},
    }];
  }
  return result;
}