UNPKG

@test-org122/hypernet-core

Version:

Hypernet Core. Represents the SDK for running the Hypernet Protocol.

210 lines 9.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MerchantConnectorRepository = void 0; const objects_1 = require("@interfaces/objects"); const errors_1 = require("@interfaces/objects/errors"); const neverthrow_1 = require("neverthrow"); const utils_1 = require("@test-org122/utils"); class MerchantConnectorRepository { constructor(blockchainProvider, ajaxUtils, configProvider, contextProvider, vectorUtils, localStorageUtils, merchantConnectorProxyFactory, blockchainUtils) { this.blockchainProvider = blockchainProvider; this.ajaxUtils = ajaxUtils; this.configProvider = configProvider; this.contextProvider = contextProvider; this.vectorUtils = vectorUtils; this.localStorageUtils = localStorageUtils; this.merchantConnectorProxyFactory = merchantConnectorProxyFactory; this.blockchainUtils = blockchainUtils; this.activatedMerchants = new Map(); this.domain = { name: "Hypernet Protocol", version: "1", }; this.types = { AuthorizedMerchant: [ { name: "authorizedMerchantUrl", type: "string" }, { name: "merchantValidatedSignature", type: "string" }, ], }; } getMerchantPublicKeys(merchantUrls) { // TODO: right now, the merchant will publish a URL with their public key; eventually, they should be held in a smart contract // For merchants that are already authorized, we can just go to their connector for the // public key. const publicKeyRequests = new Array(); for (const merchantUrl of merchantUrls) { const merchantProxy = this.activatedMerchants.get(merchantUrl); if (merchantProxy != null) { publicKeyRequests.push(merchantProxy.getPublicKey().map((publicKey) => { return { merchantUrl, publicKey }; })); } else { // Need to get it from the source const url = new URL(merchantUrl.toString()); url.pathname = "publicKey"; publicKeyRequests.push(this.ajaxUtils.get(url).map((publicKey) => { return { merchantUrl, publicKey }; })); } } return utils_1.ResultUtils.combine(publicKeyRequests).map((vals) => { const returnMap = new Map(); for (const val of vals) { returnMap.set(val.merchantUrl.toString(), val.publicKey); } return returnMap; }); } addAuthorizedMerchant(merchantUrl) { let proxy; let context; // First, we will create the proxy return this.contextProvider .getContext() .andThen((myContext) => { context = myContext; return this.merchantConnectorProxyFactory.factoryProxy(merchantUrl); }) .andThen((myProxy) => { proxy = myProxy; // With the proxy activated, we can get the validated merchant signature return utils_1.ResultUtils.combine([proxy.getValidatedSignature(), this.blockchainProvider.getSigner()]); }) .andThen((vals) => { const [merchantSignature, signer] = vals; // merchantSignature has been validated by the iframe, so this is already confirmed. // Now we need to get an authorization signature const value = { authorizedMerchantUrl: merchantUrl, merchantValidatedSignature: merchantSignature, }; const signerPromise = signer._signTypedData(this.domain, this.types, value); return neverthrow_1.ResultAsync.fromPromise(signerPromise, (e) => e); }) .andThen((authorizationSignature) => { const authorizedMerchants = this._getAuthorizedMerchants(); authorizedMerchants.set(merchantUrl, authorizationSignature); this._setAuthorizedMerchants(authorizedMerchants); // Activate the merchant connector return proxy.activateConnector(); }) .map(() => { // Only if the merchant is successfully activated do we stick it in the list. this.activatedMerchants.set(merchantUrl, proxy); }) .mapErr((e) => { // If we encounter a problem, destroy the proxy so we can start afresh. if (proxy != null) { proxy.destroy(); } // Notify the world if (context != null) { context.onAuthorizedMerchantActivationFailed.next(merchantUrl); } return e; }); } /** * Returns a map of merchant URLs with their authorization signatures. */ getAuthorizedMerchants() { const authorizedMerchants = this._getAuthorizedMerchants(); return neverthrow_1.okAsync(authorizedMerchants); } resolveChallenge(merchantUrl, paymentId, transferId) { const proxy = this.activatedMerchants.get(merchantUrl); if (proxy == null) { return neverthrow_1.errAsync(new errors_1.MerchantValidationError(`No existing merchant connector for ${merchantUrl}`)); } return proxy .resolveChallenge(paymentId) .andThen((result) => { const { mediatorSignature, amount } = result; return this.vectorUtils.resolveInsuranceTransfer(transferId, paymentId, mediatorSignature, objects_1.BigNumber.from(amount)); }) .map(() => { }); } _setAuthorizedMerchants(authorizedMerchantMap) { const authorizedMerchantEntries = new Array(); for (const keyval of authorizedMerchantMap) { authorizedMerchantEntries.push({ merchantUrl: keyval[0], authorizationSignature: keyval[1] }); } this.localStorageUtils.setItem("AuthorizedMerchants", JSON.stringify(authorizedMerchantEntries)); } _getAuthorizedMerchants() { let authorizedMerchantStr = this.localStorageUtils.getItem("AuthorizedMerchants"); if (authorizedMerchantStr == null) { authorizedMerchantStr = "[]"; } const authorizedMerchantEntries = JSON.parse(authorizedMerchantStr); const authorizedMerchants = new Map(); for (const authorizedMerchantEntry of authorizedMerchantEntries) { authorizedMerchants.set(authorizedMerchantEntry.merchantUrl, authorizedMerchantEntry.authorizationSignature); } return authorizedMerchants; } activateAuthorizedMerchants() { return utils_1.ResultUtils.combine([ this.contextProvider.getInitializedContext(), this.getAuthorizedMerchants(), this.blockchainProvider.getSigner(), ]).andThen((vals) => { const [context, authorizedMerchants, signer] = vals; const activationResults = new Array(); for (const keyval of authorizedMerchants) { activationResults.push(this._activateAuthorizedMerchant(context.account, keyval[0], // URL keyval[1], context, signer)); } return utils_1.ResultUtils.combine(activationResults).map(() => { }); }); } _activateAuthorizedMerchant(accountAddress, merchantUrl, authorizationSignature, context, signer) { let proxy; return this.merchantConnectorProxyFactory .factoryProxy(merchantUrl) .andThen((myProxy) => { proxy = myProxy; // We need to get the validated signature, so we can see if it was authorized return proxy.getValidatedSignature(); }) .andThen((validatedSignature) => { const value = { authorizedMerchantUrl: merchantUrl, merchantValidatedSignature: validatedSignature, }; const validationAddress = this.blockchainUtils.verifyTypedData(this.domain, this.types, value, authorizationSignature); if (validationAddress !== accountAddress) { // Notify the user that one of their authorized merchants has changed their code context.onAuthorizedMerchantUpdated.next(merchantUrl); // Get a new signature // validatedSignature means the code is signed by the provider, so we just need // to sign this new version. const signerPromise = signer._signTypedData(this.domain, this.types, value); return neverthrow_1.ResultAsync.fromPromise(signerPromise, (e) => e).map((newAuthorizationSignature) => { const authorizedMerchants = this._getAuthorizedMerchants(); authorizedMerchants.set(merchantUrl.toString(), newAuthorizationSignature); this._setAuthorizedMerchants(authorizedMerchants); }); } return neverthrow_1.okAsync(undefined); }) .andThen(() => { return proxy.activateConnector(); }) .map(() => { this.activatedMerchants.set(merchantUrl, proxy); }) .mapErr((e) => { // The connector could not be authenticated, so just get rid of it. if (proxy != null) { proxy.destroy(); } // Notify the world context.onAuthorizedMerchantActivationFailed.next(merchantUrl); return e; }); } } exports.MerchantConnectorRepository = MerchantConnectorRepository; //# sourceMappingURL=MerchantConnectorRepository.js.map