UNPKG

test-keyguard-client

Version:

Nimiq Keyguard client library dev test

200 lines (193 loc) 9.79 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@nimiq/rpc')) : typeof define === 'function' && define.amd ? define(['exports', '@nimiq/rpc'], factory) : (factory((global.KeyguardClient = {}),global.rpc)); }(this, (function (exports,rpc) { 'use strict'; var BehaviorType; (function (BehaviorType) { BehaviorType[BehaviorType["REDIRECT"] = 0] = "REDIRECT"; BehaviorType[BehaviorType["IFRAME"] = 1] = "IFRAME"; })(BehaviorType || (BehaviorType = {})); class RequestBehavior { static getAllowedOrigin(endpoint) { const url = new URL(endpoint); return url.origin; } constructor(type) { this._type = type; } async request(endpoint, command, args) { throw new Error('Not implemented'); } get type() { return this._type; } } class RedirectRequestBehavior extends RequestBehavior { static getRequestUrl(endpoint, command) { return `${endpoint}/request/${command}/`; } constructor(targetUrl, localState) { super(BehaviorType.REDIRECT); const location = window.location; this._targetUrl = targetUrl || `${location.protocol}//${location.hostname}:${location.port}${location.pathname}`; this._localState = localState || {}; // Reject local state with reserved property. if (typeof this._localState.__command !== 'undefined') { throw new Error('Invalid localState: Property \'__command\' is reserved'); } } async request(endpoint, command, args) { const url = RedirectRequestBehavior.getRequestUrl(endpoint, command); const origin = RequestBehavior.getAllowedOrigin(endpoint); const client = new rpc.RedirectRpcClient(url, origin); await client.init(); const state = Object.assign({ __command: command }, this._localState); client.callAndSaveLocalState(this._targetUrl, state, 'request', ...args); } } class IFrameRequestBehavior extends RequestBehavior { constructor() { super(BehaviorType.IFRAME); this._iframe = null; this._client = null; } async request(endpoint, command, args) { if (this._iframe && this._iframe.src !== `${endpoint}${IFrameRequestBehavior.IFRAME_PATH_SUFFIX}`) { throw new Error('Accounts Manager iframe is already opened with another endpoint'); } const origin = RequestBehavior.getAllowedOrigin(endpoint); if (!this._iframe) { this._iframe = await this.createIFrame(endpoint); } if (!this._iframe.contentWindow) { throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`); } if (!this._client) { this._client = new rpc.PostMessageRpcClient(this._iframe.contentWindow, origin); await this._client.init(); } return await this._client.call(command, ...args); } async createIFrame(endpoint) { return new Promise((resolve, reject) => { const $iframe = document.createElement('iframe'); $iframe.name = 'NimiqKeyguardIFrame'; $iframe.style.display = 'none'; document.body.appendChild($iframe); $iframe.src = `${endpoint}${IFrameRequestBehavior.IFRAME_PATH_SUFFIX}`; $iframe.onload = () => resolve($iframe); $iframe.onerror = reject; }); } } IFrameRequestBehavior.IFRAME_PATH_SUFFIX = '/request/iframe/'; (function (KeyguardCommand) { KeyguardCommand["CREATE"] = "create"; KeyguardCommand["REMOVE"] = "remove-key"; KeyguardCommand["IMPORT"] = "import"; KeyguardCommand["EXPORT_WORDS"] = "export-words"; KeyguardCommand["EXPORT_FILE"] = "export-file"; KeyguardCommand["EXPORT"] = "export"; KeyguardCommand["CHANGE_PASSPHRASE"] = "change-passphrase"; KeyguardCommand["SIGN_TRANSACTION"] = "sign-transaction"; KeyguardCommand["SIGN_MESSAGE"] = "sign-message"; KeyguardCommand["DERIVE_ADDRESS"] = "derive-address"; // Iframe requests KeyguardCommand["LIST"] = "list"; KeyguardCommand["MIGRATE_ACCOUNTS_TO_KEYS"] = "migrateAccountsToKeys"; KeyguardCommand["DERIVE_ADDRESSES"] = "deriveAddresses"; KeyguardCommand["RELEASE_KEY"] = "releaseKey"; })(exports.KeyguardCommand || (exports.KeyguardCommand = {})); class KeyguardClient { constructor(endpoint = KeyguardClient.DEFAULT_ENDPOINT, defaultBehavior, defaultIframeBehavior) { this._endpoint = endpoint; this._defaultBehavior = defaultBehavior || new RedirectRequestBehavior(); this._defaultIframeBehavior = defaultIframeBehavior || new IFrameRequestBehavior(); // Listen for response this._redirectClient = new rpc.RedirectRpcClient('', RequestBehavior.getAllowedOrigin(this._endpoint)); this._redirectClient.onResponse('request', this._onResolve.bind(this), this._onReject.bind(this)); this._observable = new Nimiq.Observable(); } init() { return this._redirectClient.init(); } on(command, resolve, reject) { this._observable.on(`${command}-resolve`, resolve); this._observable.on(`${command}-reject`, reject); } /* TOP-LEVEL REQUESTS */ create(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.CREATE, [request]); } remove(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.REMOVE, [request]); } import(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.IMPORT, [request]); } async exportWords(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.EXPORT_WORDS, [request]); } async exportFile(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.EXPORT_FILE, [request]); } async export(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.EXPORT, [request]); } async changePassphrase(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.CHANGE_PASSPHRASE, [request]); } async signTransaction(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.SIGN_TRANSACTION, [request]); } async signMessage(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.SIGN_MESSAGE, [request]); } async deriveAddress(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.DERIVE_ADDRESS, [request]); } /* IFRAME REQUESTS */ async list(listFromLegacyStore, requestBehavior = this._defaultIframeBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.LIST, [listFromLegacyStore]); } async migrateAccountsToKeys(requestBehavior = this._defaultIframeBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.MIGRATE_ACCOUNTS_TO_KEYS, []); } async deriveAddresses(keyId, paths, requestBehavior = this._defaultIframeBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.DERIVE_ADDRESSES, [keyId, paths]); } async releaseKey(keyId, requestBehavior = this._defaultIframeBehavior) { return this._request(requestBehavior, exports.KeyguardCommand.RELEASE_KEY, [keyId]); } /* PRIVATE METHODS */ _request(behavior, command, args) { return behavior.request(this._endpoint, command, args); } _onReject(error, id, state) { const command = state.__command; if (!command) { throw new Error('Invalid state after RPC request'); } delete state.__command; this._observable.fire(`${command}-reject`, error, state); } _onResolve(result, id, state) { const command = state.__command; if (!command) { throw new Error('Invalid state after RPC request'); } delete state.__command; this._observable.fire(`${command}-resolve`, result, state); } } KeyguardClient.DEFAULT_ENDPOINT = window.location.origin === 'https://accounts.nimiq.com' ? 'https://keyguard-next.nimiq.com' : window.location.origin === 'https://accounts.nimiq-testnet.com' ? 'https://keyguard-next.nimiq-testnet.com' : 'http://localhost:8000/src'; exports.KeyguardClient = KeyguardClient; exports.RequestBehavior = RequestBehavior; exports.RedirectRequestBehavior = RedirectRequestBehavior; exports.IFrameRequestBehavior = IFrameRequestBehavior; Object.defineProperty(exports, '__esModule', { value: true }); })));