@test-org122/hypernet-core
Version:
Hypernet Core. Represents the SDK for running the Hypernet Protocol.
210 lines • 9.73 kB
JavaScript
"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