4.2.2 Direct Use of JavaScript Software Development Kit

1.1.1 Direct Use of JavaScript Software Development Kit

1.1.1.1 Overview

This option suits POS systems that can consume JavaScript libraries. Predominantly, this includes web-based POS systems or the ones developed using NodeJS.

Figure 4 illustrates an overview of browser-based integration using the Secure Receipt Wallet JavaScript SDK.

Figure 5 illustrates an overview of node-based integration using the Secure Receipt Wallet JavaScript SDK.

Figure 4. Integration with the Secure Receipt Wallet platform using the browser-based JavaScript SDK
Figure 5. Integration with the Secure Receipt Wallet platform using the node-based JavaScript SDK

1.1.1.2 Merits

The merits of using the JavaScript SDK include the followings:

1. Cross-platform compatibility: All POS systems running under web browsers on any technology stack or framework can utilize the Secure Receipt Wallet JavaScript SDK to add smart receipt generation capabilities to them. For those POS systems developed based on NodeJS, the SDK can be used in a similar fashion as a server-side component. This includes running local servers using Node with web services exposed for local consumption (which has been proposed as a different integration option).

2. Open-Source Nature: Like many other JavaScript libraries, the NPM packages are all open source. How the end-to-end encryption works and how keys are persisted can all be viewed and verified from the code for peace of mind and assurance of implementation-to-design conformance.

1.1.1.3 Demerits

The demerits of using the Secure Receipt Wallet JavaScript SDK includes the followings:

1. CryptoAPI and IndexDB dependency for the browser SDK: Due to security reasons and in order to improve the security of persisting cryptographic keys in browsers, the SDK uses the subtle CryptoAPIs to perform cryptographic operations and generate non-extractable CryptoKey objects that are persisted in non-extractable format in IndexDB, as per the CryptoAPI specifications. This dependency limits the browser support to mostly modern and contemporary browsers with recent versions.

1.1.1.4 Integration Steps

1.1.1.4.1 Getting the POS Station Registered in Secure Receipt Wallet Issuer’s Portal

1.1.1.4.1.1 Require the necessary libraries

var { SecureWebCryptoBackedStorageProvider } = require('secure-webcrypto-backed-storage-js');
var { IssuerReceiptRecord, ReceiptItem, IssuerProtocolContextFactory, ConvertJSDateToNETTicks } = require('securereceiptwallet-securereceiptprotocol-javascript');
var { ReceiptIssuersInfoRefreshManager, ReceiptIssuerInfoManager, ReceiptSender, QRNotifierForAReceiptTransferRequest, SecureReceiptWalletPOSConfigurationCreator, POSConfigurationManager , SecureReceiptWalletAPICredentials, SecureReceiptWalletRegistrationPerformer, OneTimePreKeyStoreBySettings } = require('securereceiptwallet-javascript-pos-sdk');

1.1.1.4.1.2 Generate Local Keys and Configuration

var secureReceiptWalletPOSConfigurationCreator = new SecureReceiptWalletPOSConfigurationCreator();
config = secureReceiptWalletPOSConfigurationCreator.GeneratePOSConfigurationForMachine();

1.1.1.4.1.3 Demonstrate the Public Keys to the User

document.getElementById("UIElement_POSMachineID").value = config.POSMachineID;
document.getElementById("UIElement_POSMachinePublicKey").value = `${config.POSMachinePublicIdentityKey}${config.POSMachinePublicIdentityKeyForSigning}`;
document.getElementById("UIElement_KeyIndex").value = config.POSMachinePublicKeyIndex;
document.getElementById("UIElement_SignedPublicKey").value = config.POSMachineSignedPublicKeyPair_PublicKey;
document.getElementById("UIElement_SignedPublicKeySignature").value = config.POSMachineSignedPublicKeyPair_Signature;

1.1.1.4.1.4 Get the User to Enter the Public Keys in the Issuer’s Portal

ShowTipsToUser();
// do other stuff as needed….
window.open("https://issuers.securereceiptwallet.com.au/RegisterPosMachine");

1.1.1.4.1.5 Get the User to Enter “Issuer’s ID1” and “Issuer’s ID2” and “Key Index” Generated by The Portal

config.ReceiptWalletRetailerID = document.getElementById("UIElement_ReceiptWalletRetailerID").value;
config.RetailerCognitoID = document.getElementById("UIElement_RetailerCognitoID").value;

1.1.1.4.1.6 Verify the Details and Save the Configuration

try {
var regPerfomer = new SecureReceiptWalletRegistrationPerformer();
var receiptIssuerDetails = await regPerfomer.VerifyConfigWithBackendAndSaveLocallyAsync(fixedConfig, APIKey);
// the return object includes receipt issuer's details
} catch (error) {
// demonstrate error to the user
}

1.1.1.4.2 Generating and Delivering Smart Receipts

// load current configuration if any
var loadedConfig = await PosConfigManager.GetPOSConfigurationAsync();
if (loadedConfig) // do all the below!
{
var secureReceiptWalletAPICredentials = new SecureReceiptWalletAPICredentials(loadedConfig, APIKey, secureStorageProvider);
// ensure that this POS station has the right list of issuer's portal users and their public keys: remember everything is encrypted at client side
var receiptIssuerInfoManager = new ReceiptIssuerInfoManager(secureStorageProvider);
var receiptIssuerInfoSoFar = await receiptIssuerInfoManager.GetIssuerInfoAsync();
var receiptIssuersInfoRefreshManager = new ReceiptIssuersInfoRefreshManager(
secureStorageProvider,
receiptIssuerInfoManager,
secureReceiptWalletAPICredentials
);
// get the latest public keys of issuer's portal users
var receiptIssuerInfo = await receiptIssuersInfoRefreshManager.UpdatePublicKeysIfNecessary(receiptIssuerInfoSoFar);
// this is just an example of how to create the unique id of the receipt
const uuidv1 = require('uuid/v1');
// here are some receipts to transfer
var receipt = new IssuerReceiptRecord();
receipt.SetTimeStamp(new Date());
// all datetime values are long casted to strings! this has to be the time in UTC
receipt.ReceiptCreationDate = ConvertJSDateToNETTicks(new Date()).toString();
receipt.RandomReceiptID = uuidv1().substring(0, 10);
receipt.RetailerCognitoID = loadedConfig.RetailerCognitoID;;
receipt.POSMachineID = loadedConfig.POSMachineID;
receipt.IncludesFile = false;
receipt.Description = "Description";
receipt.DetailsInBodyAfterItems = "DetailsInBodyAfterItems";
receipt.DetailsInBodyBeforeItems = "DetailsInBodyBeforeItems";
receipt.DetailsInFooter = "IssuersReceipt";
receipt.DetailsInHeader = "DetailsInHeader";
receipt.ReceiptText = "ReceiptText";
receipt.TotalAmount = 100.123;
receipt.TotalTaxAmount = 10.234;
// adding receipt items
receipt.ReceiptItems = [];
var ReceiptItem1 = new ReceiptItem();
ReceiptItem1.Description = "Description";
ReceiptItem1.UnitPrice = 10.3;
ReceiptItem1.Url = "Url/to/item/properties/page/or/purchase/page";
ReceiptItem1.Quantity = 1.5;
ReceiptItem1.Identifier = "Identifier";
receipt.ReceiptItems.push(ReceiptItem1);
var ReceiptItem2 = new ReceiptItem();
ReceiptItem2.Description = "Description2";
ReceiptItem2.UnitPrice = 11.3;
ReceiptItem2.Url = "Url/to/item/properties/page/or/purchase/page";
ReceiptItem2.Quantity = 2.5;
ReceiptItem2.Identifier = "Identifier2";
receipt.ReceiptItems.push(ReceiptItem2);
//adding receipt payment details, if applicable
//receipt.CreditCardPayments=[];
//receipt.CreditCardPayments.push( NewCreditCardPaymentObject);
//receipt.EftposPayments=[];
//receipt.EftposPayments.push(NewEftposPaymentObject)
//receipt.CashPayment= CashPaymentObject;
// code to send the receipt!
var issuerProtocolContextFactory = IssuerProtocolContextFactory.GetInstance();
// CRITICAL:
// in NODE: QRFolderPath is the path in which the QR codes are saved.
// in Browser: this should be the SELECTOR of the image element on which the QR code is displayed!
var notifier = new QRNotifierForAReceiptTransferRequest(QRFolderPath);
// set the even handlers!
notifier.on('OnReceiptTransferRequestReadyToBeDisplayed', function (eventArgs) {
// take the steps to show the generated QR code to the user here....
console.log(`OnReceiptTransferRequestReadyToBeDisplayed event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});
notifier.on('OnReceiptTransferRequestAcknowledgedByUser', function (eventArgs) {
// take steps to hide the shown QR code here. The user has done the scan already....
console.log(`OnReceiptTransferRequestAcknowledgedByUser event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});
notifier.on('OnReceiptTransferFinished', function (eventArgs) {
// take steps to show to the POS operator that the transfer has been completed....
console.log(`OnReceiptTransferFinished event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});
// One-time pre-key store is needed
var OneTimePreKeyStore = new OneTimePreKeyStoreBySettings(PosConfigManager);
// receipt sender object
var receiptSender = new ReceiptSender(
issuerProtocolContextFactory,
secureReceiptWalletAPICredentials,
loadedConfig,
notifier,
receiptIssuerInfo,
OneTimePreKeyStore
);
// sending the receipt...
await receiptSender.SendReceiptAsync(receipt);
//end region UsingSDK
}
else {
// show error or take user through the configuration process
}

1.1.1.4.3 Demonstrate the Results

notifier.on('OnReceiptTransferRequestReadyToBeDisplayed', function (eventArgs) {
// take the steps to show the generated QR code to the user here....
console.log(`OnReceiptTransferRequestReadyToBeDisplayed event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});
notifier.on('OnReceiptTransferRequestAcknowledgedByUser', function (eventArgs) {
// take steps to hide the shown QR code here. The user has done the scan already....
console.log(`OnReceiptTransferRequestAcknowledgedByUser event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});
notifier.on('OnReceiptTransferFinished', function (eventArgs) {
// take steps to show to the POS operator that the transfer has been completed....
console.log(`OnReceiptTransferFinished event handler has been called with eventArgs=${JSON.stringify(eventArgs)}`);
});