UNPKG

vexjs-keygen

Version:

General purpose library for private key storage and key management.

947 lines (799 loc) 30.6 kB
'use strict'; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** @module Keystore */ var assert = require('assert'); var _require = require('vexjs-ecc'), PrivateKey = _require.PrivateKey, Signature = _require.Signature; var ecc = require('vexjs-ecc'); var minimatch = require('minimatch'); var Keygen = require('./keygen'); var UriRules = require('./uri-rules'); var validate = require('./validate'); var globalConfig = require('./config'); var _require2 = require('./config'), localStorage = _require2.localStorage; var userStorage = require('./keypath-utils')('kstor'); module.exports = Keystore; /** Provides private key management and storage and tooling to limit exposure of private keys as much as possible. Although multiple root keys may be stored, this key store was designed with the idea that all keys for a given `accountName` are derive from a single root key (the master private key). This keystore does not query the blockchain or any external services. Removing keys here does not affect the blockchain. @arg {string} accountName - Blockchain account name that will act as the container for a key and all derived child keys. @arg {object} [config] @arg {number} [config.timeoutInMin = 10] - upon timeout, remove keys matching timeoutKeyPaths. @arg {number} [config.timeoutKeyPaths = ['owner', 'owner/**']] - by default, expire only owner and owner derived children. If the default uriRules are used this actually has nothing to delete. @arg {uriRules} [config.uriRules] - Specify which type of private key will be available on certain pages of the application. Lock it down as much as possible and later re-prompt the user if a key is needed. Default is to allow active (`active`) and all active derived keys (`active/**`) everywhere (`.*`). @arg {boolean} [keepPublicKeys = true] - Enable for better UX; show users keys they have access too without requiring them to login. Logging in brings a private key online which is not necessary to see public information. The UX should implement this behavior in a way that is clear public keys are cached before enabling this feature. @example config = { uriRules: { 'active': '.*', 'active/**': '.*' }, timeoutInMin: 10, timeoutKeyPaths: [ 'owner', 'owner/**' ], keepPublicKeys: true } */ function Keystore(accountName) { var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; assert.equal(typeof accountName === 'undefined' ? 'undefined' : _typeof(accountName), 'string', 'accountName'); assert.equal(typeof config === 'undefined' ? 'undefined' : _typeof(config), 'object', 'config'); var configDefaults = { uriRules: { 'active': '.*', 'active/**': '.*' }, timeoutInMin: 10, timeoutKeyPaths: ['owner', 'owner/**'], keepPublicKeys: true }; config = Object.assign({}, configDefaults, config); var uriRules = UriRules(config.uriRules); /** @private */ var state = {}; var expireAt = void 0, expireInterval = void 0; var unlistenHistory = void 0; // Initialize state from localStorage userStorage.query(localStorage, [accountName, 'kpath'], function (_ref, wif) { var _ref2 = _slicedToArray(_ref, 2), path = _ref2[0], pubkey = _ref2[1]; var storageKey = userStorage.createKey(accountName, 'kpath', path, pubkey); state[storageKey] = wif; }); /** Login or derive and save private keys. This may be called from a login action. Keys may be removed as during Uri navigation or when calling logout. @arg {object} params @arg {parentPrivateKey} params.parent - Master password (masterPrivateKey), active, owner, or other permission key. @arg {Array<keyPathMatcher>} [params.saveKeyMatches] - These private keys will be saved to disk. (example: `active`). @arg {accountPermissions} [params.accountPermissions] - Permissions object from Vex blockchain via get_account. This is used to validate the parent and derive additional permission keys. This allows this keystore to detect incorrect passwords early before trying to sign a transaction. See Chain API `get_account => account.permissions`. @throws {Error} 'invalid login' */ function deriveKeys(_ref3) { var parent = _ref3.parent, _ref3$saveKeyMatches = _ref3.saveKeyMatches, saveKeyMatches = _ref3$saveKeyMatches === undefined ? [] : _ref3$saveKeyMatches, accountPermissions = _ref3.accountPermissions; keepAlive(); assert(parent != null, 'parent is a master password or private key'); var keyType = validate.keyType(parent); assert(/master|wif|privateKey/.test(keyType), 'parentPrivateKey is a masterPrivateKey or private key'); if (typeof saveKeyMatches === 'string') { saveKeyMatches = [saveKeyMatches]; } saveKeyMatches.forEach(function (m) { if (minimatch('owner', m)) { throw new Error('do not save owner key to disk'); } // if(minimatch('active', m)) { // throw new Error('do not save active key to disk') // } }); assert((typeof accountPermissions === 'undefined' ? 'undefined' : _typeof(accountPermissions)) === 'object' || accountPermissions == null, 'accountPermissions is an optional object'); if (!unlistenHistory) { unlistenHistory = globalConfig.history.listen(function () { keepAlive(); // Prevent certain private keys from being available to high-risk pages. var paths = getKeyPaths().wif; var pathsToPurge = uriRules.check(currentUriPath(), paths).deny; removeKeys(pathsToPurge); }); } if (!expireInterval) { if (config.timeoutInMin != null) { var tick = function tick() { if (timeUntilExpire() === 0) { removeKeys(config.timeoutKeyPaths); clearInterval(expireInterval); expireInterval = null; } }; expireInterval = setInterval(tick, config.timeoutInMin * min); } } // cache if (!accountPermissions) { var permissions = userStorage.get(localStorage, [accountName, 'permissions']); if (permissions) { accountPermissions = JSON.parse(permissions); } } // cache pubkey (that is a slow calculation) var Keypair = function Keypair(privateKey) { return { privateKey: privateKey, pubkey: privateKey.toPublic().toString() }; }; // blockchain permission format var perm = function perm(parent, perm_name, pubkey) { return { perm_name: perm_name, parent: parent, required_auth: { keys: [{ key: pubkey }] } }; }; // Know if this is stubbed in next (don't cache later) var isPermissionStub = accountPermissions == null; var parentKeys = {}; if (keyType === 'master') { var masterPrivateKey = PrivateKey(parent.substring(2)); parentKeys.owner = Keypair(masterPrivateKey.getChildKey('owner')); parentKeys.active = Keypair(parentKeys.owner.privateKey.getChildKey('active')); if (!accountPermissions) { accountPermissions = [perm('owner', 'active', parentKeys.active.pubkey), perm('', 'owner', parentKeys.owner.pubkey)]; } } else { if (accountPermissions) { // unknown for now.. parentKeys.other = Keypair(PrivateKey(parent)); } else { parentKeys.active = Keypair(PrivateKey(parent)); accountPermissions = [perm('owner', 'active', parentKeys.active.pubkey)]; } } assert(accountPermissions, 'accountPermissions is required at this point'); var authsByPath = Keygen.authsByPath(accountPermissions); // Don't allow key re-use function uniqueKeyByRole(role) { var auth = authsByPath[role]; if (auth == null) { return; } auth.keys.forEach(function (rolePub) { var _loop = function _loop(other) { if (other === role) { return 'continue'; } authsByPath[other].keys.forEach(function (otherPub) { if (otherPub.key === rolePub.key) { throw new Error(role + ' key reused in authority: ' + other); } }); }; for (var other in authsByPath) { var _ret = _loop(other); if (_ret === 'continue') continue; } }); } uniqueKeyByRole('active'); uniqueKeyByRole('owner'); if (!isPermissionStub) { // cache userStorage.save(localStorage, [accountName, 'permissions'], JSON.stringify(accountPermissions), { immutable: false }); } var keyUpdates = [], allow = false; // check existing keys.. for (var path in authsByPath) { var auth = authsByPath[path]; var _loop2 = function _loop2(parentPath) { var parentKey = parentKeys[parentPath]; // owner, active, other if (auth.keys.find(function (k) { return k.key === parentKey.pubkey; }) != null) { keyUpdates.push({ path: path, privateKey: parentKey.privateKey }); } }; for (var parentPath in parentKeys) { _loop2(parentPath); } } if (keyUpdates.length === 0) { throw new Error('invalid login'); } // Sync keyUpdates with storage .. function saveKeyUpdates() { // sort key updates so removeKeys will only remove children var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { var _loop3 = function _loop3() { var _step$value = _step.value, path = _step$value.path, privateKey = _step$value.privateKey; var disk = saveKeyMatches.find(function (m) { return minimatch(path, m); }) != null; var update = addKey(path, privateKey, disk); if (update) { allow = true; if (update.dirty) { // blockchain key changed // remove so these will be re-derived var children = getKeys(path + '/**').map(function (k) { return k.path; }); removeKeys(children, false /*keepPublicKeys*/); } } }; for (var _iterator = keyUpdates.sort()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { _loop3(); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } saveKeyUpdates(); // Gather up all known keys then derive children var wifsByPath = {}; // After saveKeyUpdates, fetch the remaining allowed and valid private keys getKeys().filter(function (k) { return !!k.wif; }).forEach(function (k) { // getKeys => {path, pubkey, wif} wifsByPath[k.path] = k.wif; }); // Combine existing keys in the keystore with any higher permission keys // in wifsByPath that may not exist after this function call. var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = keyUpdates[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _step2$value = _step2.value, _path2 = _step2$value.path, privateKey = _step2$value.privateKey; if (!wifsByPath[_path2]) { // These more secure keys could be used to derive less secure // child keys below. wifsByPath[_path2] = privateKey.toWif(); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } keyUpdates = []; // Use all known keys in wifsByPath to derive all known children. // Why? As the user navigates any parent could get removed but the child // could still be allowed. Good thing we saved the children while we could. for (var _path in authsByPath) { if (!wifsByPath[_path]) { var keys = Keygen.deriveKeys(_path, wifsByPath); if (keys.length) { var authorizedKeys = authsByPath[_path].keys.map(function (k) { return k.key; }); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { var _loop4 = function _loop4() { var key = _step3.value; // {path, privateKey} var pubkey = key.privateKey.toPublic().toString(); var inAuth = !!authorizedKeys.find(function (k) { return k === pubkey; }); if (inAuth) { // if user did not change this key wifsByPath[key.path] = key.privateKey.toWif(); keyUpdates.push(key); } }; for (var _iterator3 = keys[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { _loop4(); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } } } // save allowed children saveKeyUpdates(); keyUpdates = []; if (!allow) { // uri rules blocked every key throw new Error('invalid login for page'); } } /** @private see: keystore.deriveKeys Save a private or public key to the store in either RAM only or RAM and disk. Typically deriveKeys is used instead. @arg {keyPath} path - active/mypermission, owner, active, .. @arg {string} key - wif, pubkey, or privateKey @arg {boolean} toDisk - save to persistent storage (localStorage) @throws {AssertionError} path error or active, owner/* toDisk save attempted @return {object} {[wif], pubkey, dirty} or null (denied by uriRules) */ function addKey(path, key) { var toDisk = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; validate.path(path); keepAlive(); var keyType = validate.keyType(key); assert(/^wif|pubkey|privateKey$/.test(keyType), 'key should be a wif, public key string, or privateKey object'); if (toDisk) { assert(path !== 'owner', 'owner key should not be stored on disk'); assert(path.indexOf('owner/') !== 0, 'owner derived keys should not be stored on disk'); // assert(path !== 'active', 'active key should not be stored on disk') } if (uriRules.deny(currentUriPath(), path).length) { // console.log('Keystore addKey denied: ', currentUriPath(), path); return null; } var wif = keyType === 'wif' ? key : keyType === 'privateKey' ? ecc.PrivateKey(key).toWif() : null; var pubkey = keyType === 'pubkey' ? ecc.PublicKey(key).toString() : keyType === 'privateKey' ? key.toPublic().toString() : ecc.privateToPublic(wif); assert(!!pubkey, 'pubkey'); var storageKey = userStorage.createKey(accountName, 'kpath', path, pubkey); var dirty = userStorage.save(state, storageKey, wif, { clobber: false }); if (toDisk) { var saved = userStorage.save(localStorage, storageKey, wif, { clobber: false }); dirty = dirty || saved; } return wif == null ? { pubkey: pubkey, dirty: dirty } : { wif: wif, pubkey: pubkey, dirty: dirty }; } /** Return paths for all available keys. Empty array is used if there are no keys. @return {object} {pubkey: Array<pubkey>, wif: Array<wif>} */ function getKeyPaths() { keepAlive(); var pubs = new Set(); var wifs = new Set(); function query(store) { userStorage.query(store, [accountName, 'kpath'], function (_ref4, wif) { var _ref5 = _slicedToArray(_ref4, 2), path = _ref5[0], pubkey = _ref5[1]; pubs.add(path); if (wif != null) { wifs.add(path); } }); } query(state); query(localStorage); return { pubkey: Array.from(pubs).sort(), wif: Array.from(wifs).sort() }; } /** Fetch or derive a public key. @arg {keyPath} @return {pubkey} or null */ function getPublicKey(path) { validate.path(path); var _getKeys = getKeys(path), _getKeys2 = _slicedToArray(_getKeys, 1), key = _getKeys2[0]; return key ? key.pubkey : null; } /** Return public keys for a path or path matcher. @arg {keyPath|keyPathMatcher} [keyPathMatcher = '**'] return all keys @return {Array<pubkey>} public keys or empty array */ function getPublicKeys() { var keyPathMatcher = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '**'; return getKeys(keyPathMatcher).map(function (key) { return key.pubkey; }); } /** Fetch or derive a private key. @arg {keyPath} path @return {wif} or null (missing or not available for location) */ function getPrivateKey(path) { validate.path(path); var _getKeys3 = getKeys(path), _getKeys4 = _slicedToArray(_getKeys3, 1), key = _getKeys4[0]; return key ? key.wif : undefined; } /** Return private keys for a path matcher or for a list of public keys. If a list of public keys is provided they will be validated ensuring they all have private keys to return. @arg {keyPathMatcher} [keyPathMatcher = '**'] default is to match all @arg {Array<pubkey>} [pubkeys = null] if specified, filter and require all @throws Error `login with your ${key.pubkey} key` @throws Error `missing public key ${key}` @return {Array<wif>} wifs or empty array */ function getPrivateKeys() { var keyPathMatcher = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '**'; var pubkeys = arguments[1]; if (!pubkeys) { return getKeys(keyPathMatcher).filter(function (key) { return key.wif != null; }).map(function (key) { return key.wif; }); } if (pubkeys instanceof Array) { pubkeys = new Set(pubkeys); } assert(pubkeys instanceof Set, 'pubkeys should be a Set or Array'); var keys = new Map(); getKeys(keyPathMatcher).filter(function (key) { return pubkeys.has(key.pubkey); }).forEach(function (key) { if (key.wif == null) { throw new Error('login with your \'' + key.path + '\' key'); } keys.set(key.pubkey, key.wif); }); pubkeys.forEach(function (key) { if (!keys.has(key)) { // Was keepPublicKeys true? throw new Error('missing public key ' + key); } }); return Array.from(keys.values()); } /** Fetch or derive a key pairs. @arg {keyPath|keyPathMatcher} keyPathMatcher @return {Array<keyPathPrivate>} {path, pubkey, deny, wif} or empty array. Based on the Uri rules and current location, the deny could be set to true and the wif will be null. */ function getKeys() { var keyPathMatcher = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '**'; keepAlive(); var keys = new Map(); // if we try to derive it below var wifsByPath = {}; var isPath = validate.isPath(keyPathMatcher); function query(store) { userStorage.query(store, [accountName, 'kpath'], function (_ref6, wif) { var _ref7 = _slicedToArray(_ref6, 2), path = _ref7[0], pubkey = _ref7[1]; if (wif == null) { wif = wifsByPath[path]; } else { wifsByPath[path] = wif; } if (minimatch(path, keyPathMatcher)) { var result = { path: path, pubkey: pubkey }; result.deny = uriRules.deny(currentUriPath(), path).length !== 0; result.wif = result.deny ? null : wif; keys.set(path, result); if (isPath) { return false; // break } } }); } query(state); if (isPath && keys.size) { // A path can match only one, found so no need to query localStorage return Array.from(keys.values()); } query(localStorage); if (!isPath) { // keyPathMatcher can not derive keys // .. the search is complete (found or not) return Array.from(keys.values()); } assert(isPath, 'keyPathMatcher should be a path at this point'); var key = null; // derive children (path) var path = keyPathMatcher; var deriveKeys = Keygen.deriveKeys(path, wifsByPath); if (deriveKeys.length) { var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = deriveKeys[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var derivedKey = _step4.value; // {path, privateKey} if (derivedKey.path === path) { // filter intermediate children var deny = uriRules.deny(currentUriPath(), path).length !== 0; key = { path: path, pubkey: derivedKey.privateKey.toPublic().toString(), wif: deny ? null : derivedKey.privateKey.toWif(), deny: deny }; break; } } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } return key ? [key] : []; } /** @private Remove a key or keys from this key store (ram and disk). Typically logout is used instead. @arg {keyPathMatcher|Array<keyPathMatcher>|Set<keyPathMatcher>} @arg {boolean} keepPublicKeys */ function removeKeys(paths) { var keepPublicKeys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.keepPublicKeys; assert(paths != null, 'paths'); if (typeof paths === 'string') { paths = [paths]; } assert(paths instanceof Array || paths instanceof Set, 'paths is a Set or Array'); var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = paths[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var path = _step5.value; validate.path(path); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } function clean(store, prefix) { for (var _key in store) { if (_key.indexOf(prefix) === 0) { if (keepPublicKeys) { store[_key] = null; } else { delete store[_key]; } } } } var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = paths[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var _path3 = _step6.value; var prefix = userStorage.createKey(accountName, 'kpath', _path3); clean(state, prefix); clean(localStorage, prefix); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } } /** @typedef {object} oneTimeSignatures @property {Array<string>} signatures - in hex @property {pubkey} oneTimePublic */ /** @arg {pubkey} otherPubkey @arg {keyPathMatcher} keyPathMatcher @return {Promise<oneTimeSignatures>} */ function signSharedSecret(otherPubkey) { var keyPathMatcher = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '**'; assert(/pubkey|PublicKey/.test(validate.keyType(otherPubkey)), 'otherPubkey'); assert.equal(typeof keyPathMatcher === 'undefined' ? 'undefined' : _typeof(keyPathMatcher), 'string', 'keyPathMatcher'); return PrivateKey.randomKey().then(function (oneTimePrivate) { var sharedSecret = oneTimePrivate.getSharedSecret(otherPubkey); var signatures = getPrivateKeys(keyPathMatcher).map(function (wif) { return ecc.sign(sharedSecret, wif); }); var oneTimePublic = ecc.privateToPublic(oneTimePrivate); return { signatures: signatures, oneTimePublic: oneTimePublic }; }); } /** Removes all saved keys on disk and clears keys in memory. Call only when the user chooses "logout." Do not call when the application exits. Forgets everything allowing the user to use a new password next time. */ function logout() { for (var _key2 in state) { delete state[_key2]; } var prefix = userStorage.createKey(accountName); for (var _key3 in localStorage) { if (_key3.indexOf(prefix) === 0) { delete localStorage[_key3]; } } clearInterval(expireInterval); expireInterval = null; if (unlistenHistory) { unlistenHistory(); unlistenHistory = null; } expireAt = null; } /** @return {number} 0 (expired) or milliseconds until expire */ function timeUntilExpire() { return expireAt === 0 ? 0 : expireAt == null ? 0 : Math.max(0, expireAt - Date.now()); } /** Keep alive (prevent expiration). Called automatically if Uri navigation happens or keys are required. It may be necessary to call this manually. */ function keepAlive() { expireAt = Date.now() + config.timeoutInMin * min; } /** Integration for 'vexjs' .. Call keyProvider with no parameters or with a specific keyPathMatcher pattern to get an array of public keys in this key store. A library like vexjs may be provided these available public keys to vexd get_required_keys for filtering and to determine which private keys are needed to sign a given transaction. Call again with the get_required_keys pubkeys array to get the required private keys returned (or an error if any are missing). @throws Error `login with your ${path} key` @throws Error `missing public key ${key}` @arg {object} param @arg {string} [param.keyPathMatcher = '**'] - param.keyPathMatcher for public keys @arg {Array<pubkey>|Set<pubkey>} [param.pubkeys] for fetching private keys @return {Array<pubkey|wif>} available pubkeys in the keystore or matching wif private keys for the provided pubkeys argument (also filtered using keyPathMatcher). @see https://github.com/vexanium/vexjs */ function keyProvider() { var _ref8 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref8$keyPathMatcher = _ref8.keyPathMatcher, keyPathMatcher = _ref8$keyPathMatcher === undefined ? '**' : _ref8$keyPathMatcher, pubkeys = _ref8.pubkeys; keepAlive(); if (pubkeys) { return getPrivateKeys(keyPathMatcher, pubkeys); } if (keyPathMatcher) { // For `login with your xxx key` below, get all keys even if a // wif is not available. return getPublicKeys(keyPathMatcher); } } return { deriveKeys: deriveKeys, addKey: addKey, getKeys: getKeys, getKeyPaths: getKeyPaths, getPublicKey: getPublicKey, getPublicKeys: getPublicKeys, getPrivateKey: getPrivateKey, getPrivateKeys: getPrivateKeys, removeKeys: removeKeys, signSharedSecret: signSharedSecret, logout: logout, timeUntilExpire: timeUntilExpire, keepAlive: keepAlive, keyProvider: keyProvider }; } /** @private */ function currentUriPath() { var location = globalConfig.history.location; return '' + location.pathname + location.search + location.hash; } /** Erase all traces of this keystore (for all users). */ Keystore.wipeAll = function () { var prefix = userStorage.createKey(); for (var _key4 in localStorage) { if (_key4.indexOf(prefix) === 0) { delete localStorage[_key4]; } } }; // used to convert milliseconds var sec = 1000, min = 60 * sec;