4.2.1 Direct Use of.NET Software Development Kit

1.1.1.1 Overview

This option suits POS systems that can consume .NET libraries. Predominantly, this includes POS systems developed using Microsoft technology stack based on the .NET framework.

Figure 3 illustrates an overview of this integration model.

Figure 3. Integration with the Secure Receipt Wallet platform using .NET SDKs

1.1.1.2 Merits

The merits of using the .NET SDKs include the followings:

1. Cross-platform compatibility: Having been built upon the .NET Standard stack, the SDK is cross compatible to operate in all platforms (for macOS and Linux, as well as Android, iOS and Windows). Depending on the platform, different schemes have been used to make use of the keychain storage (if available) to secure the local storage of cryptographic keys on the platform, which may result in different dependencies.

1.1.1.3 Demerits

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

1. .NET stack dependency: Whilst a common stack for systems development, there may be a limited number of POS systems developed based upon the .Net framework to utilize the .NET SDK.

2. TLS 1.2 and .NET 4.5 dependency: The SDK heavily uses the async programming paradigm itself and can be compiled to target .NET 4.5 which opens up space for compatibility and use on Windows XP and Windows 2003 Server, however, all our back-end APIs use TLS 1.2 as the minimum and due to the limitations of Windows XP and 2003 Server around TLS 1.2, the framework is currently available for Windows Vista and above. Understandably, there is a wide range of POS systems still operating on Windows XP (and its embedded version). Accordingly, Secure Receipt Wallet is exploring options to make the SDK (and Secure Receipt Wallet CloudConnect Agent) available on Window XP and Windows Server 2003.

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 Reference the right nuget packages and namespaces

using SecureReceiptTransferProtocol.Protobuffs.SchemaTypes;
using SecureReceiptWallet.Ed25519Block.Models;
using SecureReceiptWallet.SecureReceiptProtocol.Models.Issuer;
using SecureReceiptWallet.SecureReceiptProtocol.ProtocolStateMachine.States.IssuerStates;
using SecureReceiptWalletPOSSDK.Configuration;
using SecureReceiptWalletPOSSDK.DataProtection;
using SecureReceiptWalletPOSSDK.DP;
using SecureReceiptWalletPOSSDK.Identity;
using SecureReceiptWalletPOSSDK.Models;
using SecureReceiptWalletPOSSDK.ReceiptSender;
using SecureReceiptWalletPOSSDK.ReceiptSenderBiz;
using SecureReceiptWalletPOSSDK.Registration;

1.1.1.4.1.2 Generate Local Keys and Configuration

// create configuration for the POS station
SecureReceiptWalletPOSConfigurationCreator configCreator = new SecureReceiptWalletPOSConfigurationCreator();
SecureReceiptWalletPOSConfiguration config = configCreator.GeneratePOSConfigurationForMachine();

1.1.1.4.1.3 Demonstrate the Public Keys to the User

UIElement_POSMachineID.Text = config.POSMachineID;
UIElement_POSMachinePublicKey.Text = $"{config.POSMachinePublicIdentityKey}{config.POSMachinePublicIdentityKeyForSigning}";
UIElement_KeyIndex.Value = config.POSMachinePublicKeyIndex;
UIElement_SignedPublicKey.Text = config.POSMachineSignedPublicKeyPair_PublicKey;
UIElement_SignedPublicKeySignature.Text = 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….
OpenBrowser(“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= UIElement_ReceiptWalletRetailerID.Text;
config.RetailerCognitoID = UIElement_RetailerCognitoID.Text ;

1.1.1.4.1.6 Verify the Details and Save the Configuration

// verify with the back-end and persist securely
try
{
SecureReceiptWalletRegistrationPerformer regPerfomer = new SecureReceiptWalletRegistrationPerformer();
await regPerfomer.VerifyConfigWithBackendAndSaveLocallyAsync(config, " Your API Key from Developer's Portal @ https://developers.securereceiptwallet.com.au");
...
}
catch (Exception ex)
{
// display relevant information to user about failure
}

1.1.1.4.2 Generating and Delivering Smart Receipts

// building secure storage providers and config managers
AsyncWindowsSecureStorageProvider secureStorageProvider = new AsyncWindowsSecureStorageProvider("your configuration item ID");
POSConfigurationManager PosConfigManager = new POSConfigurationManager(secureStorageProvider);
SecureReceiptWalletPOSConfiguration config = await PosConfigManager.GetPOSConfigurationAsync();
if (config != null)
{
// for authentication, only a subset of configuration is used...
POSAuthenticationParameters authParams = new POSAuthenticationParameters
{
POSMachineID = config.POSMachineID,
POSMachinePrivateIdentityKeyForSigning = new Ed25519PrivateKey(config.POSMachinePrivateIdentityKeyForSigning),
POSMachinePublicKeyIndex = config.POSMachinePublicKeyIndex,
ReceiptWalletRetailerID = config.ReceiptWalletRetailerID,
RetailerCognitoID = config.RetailerCognitoID
};
// building API call credentials
var secureReceiptWalletAPICredentials = new SecureReceiptWalletAPICredentials(authParams, "Your API Key from Developer's Portal @ https://developers.securereceiptwallet.com.au", secureStorageProvider);
// ensuring that if issuer's details or users' public keys have been changed, the local copies are updated.
var receiptIssuerInfoManager = new ReceiptIssuerInfoManager(secureStorageProvider);
// this is the issuer info from local cache
var receiptIssuerInfoSoFar = await receiptIssuerInfoManager.GetIssuerInfoAsync();
// making sure we updatet the local cache if details have changed....
var receiptIssuersInfoRefreshManager = new ReceiptIssuersInfoRefreshManager(
secureStorageProvider,
receiptIssuerInfoManager,
secureReceiptWalletAPICredentials
);
// if a new issuer's portal user has been added or they have changed their private key, we MUST reflect that!
var receiptIssuerInfo = await receiptIssuersInfoRefreshManager.UpdatePublicKeysIfNecessaryAsync(receiptIssuerInfoSoFar);
#region UsingSDK
// compile the receipt object
IssuerReceiptRecord receipt = new IssuerReceiptRecord();
// critical details for the receipt! the creation moment should be in UTC, in ticks, and in string format!
receipt.ReceiptCreationDate = DateTime.Now.ToUniversalTime().Ticks.ToString();
receipt.RandomReceiptID = "a truely random identifier least 10 characters long";
receipt.SetTimeStamp(DateTime.Now);
// set other properties of the receipt object
receipt.DetailsInFooter = "this will appear in the footer";
receipt.DetailsInHeader = "this will appear in the header";
receipt.ReceiptText = "teextual version of the receipt, for non-smart digital only receipts, which will not require independent receipt items....";
receipt.TotalAmount = 100.123;
receipt.TotalTaxAmount = 10.234;
receipt.ReceiptItems = new List<ReceiptItem>();
receipt.ReceiptItems.Add(new ReceiptItem()
{
Description = "Description",
UnitPrice = 10.3,
Url = "Url/to/item/properties/or/purchase/page",
Quantity = 1.5,
Identifier = "Identifier"
});
receipt.ReceiptItems.Add(new ReceiptItem()
{
Description = "Description2",
UnitPrice = 11.3,
Url = "Url/to/item/properties/or/purchase/page",
Quantity = 2.5,
Identifier = "Identifier2"
});
// set payment objects, if applicable
receipt.EftposPayments = new List<EftposPayment>();
// next step if applicable:
//receipt.EftposPayments.Add(new EftposPayment { });
receipt.CreditCardPayments = new List<CreditCardPayment>();
// next step if applicable:
//receipt.CreditCardPayments.Add(new CreditCardPayment { });
// any cash payment?
receipt.CashPayment = new CashPayment { Currency="USD",Purchase=100.123, TotalPaid=105, AmountReturned= 4.877 };
// code to send the receipt!
IssuerProtocolContextFactory issuerProtocolContextFactory = IssuerProtocolContextFactory.GetInstance();
QRNotifierForAReceiptTransferRequest notifier = new QRNotifierForAReceiptTransferRequest();
// set the even handlers!
notifier.OnReceiptTransferRequestReadyToBeDisplayed += Notifier_OnReceiptTransferRequestReadyToBeDisplayed;
notifier.OnReceiptTransferRequestAcknowledgedByUser += Notifier_OnReceiptTransferRequestAcknowledgedByUser; ;
notifier.OnReceiptTransferFinished += async (object sender, ReceiptTransferCompletedEventArgs e) => { await Notifier_OnReceiptTransferFinished(sender, e); };
// OneTimePreKeys store! This will generate new keys if necessary
OneTimePreKeyStoreBySettings OneTimePreKeyStore = new OneTimePreKeyStoreBySettings(PosConfigManager);
// the recceipt sender will deal with everything needed
ReceiptSender receiptSender = new ReceiptSender(
issuerProtocolContextFactory,
secureReceiptWalletAPICredentials,
config,
notifier,
receiptIssuerInfo,
OneTimePreKeyStore
);
// at last, sending the receipt....
await receiptSender.SendReceiptAsync(receipt);
#endregion UsingSDK
}
else // cofig object was null!
{
// show error to user and potentially, get them to go through the registration process if needed…
}

1.1.1.4.3 Display the results

Use the event handlers to display the results to the user.

private void Notifier_OnReceiptTransferRequestReadyToBeDisplayed(object sender, QRReceiptTransferRequestReadyEventArgs e)
{
string QRCode = e.QRCode;
Bitmap QRImage = e.QRImage;
ReceiptTransferRequest receiptTransferRequest = e.ReceiptTransferRequest;
//this event handler is called when the QR code has been created and is ready to be displayed to the user.
}
private void Notifier_OnReceiptTransferRequestAcknowledgedByUser(object sender, QRReceiptTransferRequestAcknowledgedByUserEventArgs e)
{
//this event handler is called when the user scans the QR code. You can stop displaying the QR code to the user at this point.
}
private async Task Notifier_OnReceiptTransferFinished(object sender, ReceiptTransferCompletedEventArgs e)
{
//this event handler is called when the receipt transfer is finished.
}