jwallet-web-keystore
Advanced tools
Comparing version
@@ -16,7 +16,7 @@ 'use strict'; | ||
if (encryptionType === 'nacl.secretbox') { | ||
return encryptNaclSecretbox(otherProps); | ||
if (encryptionType !== 'nacl.secretbox') { | ||
throw new Error('Encryption type ' + encryptionType + ' is not supported'); | ||
} | ||
throw new Error('Encryption type ' + encryptionType + ' is not supported'); | ||
return encryptNaclSecretbox(otherProps); | ||
} | ||
@@ -34,2 +34,6 @@ | ||
if (encryptedData == null) { | ||
throw new Error('Password is invalid'); | ||
} | ||
return encodeEncryptedData(encryptedData, nonce, 'nacl.secretbox'); | ||
@@ -73,7 +77,7 @@ } | ||
if (encryptionType === 'nacl.secretbox') { | ||
return decryptNaclSecretbox(props); | ||
if (encryptionType !== 'nacl.secretbox') { | ||
throw new Error('Decryption type ' + encryptionType + ' is not supported'); | ||
} | ||
throw new Error('Decryption type ' + encryptionType + ' is not supported'); | ||
return decryptNaclSecretbox(props); | ||
} | ||
@@ -93,3 +97,3 @@ | ||
if (decryptedData == null) { | ||
throw new Error('Decryption failed'); | ||
throw new Error('Password is invalid'); | ||
} | ||
@@ -96,0 +100,0 @@ |
@@ -11,2 +11,3 @@ 'use strict'; | ||
var R = require('ramda'); | ||
var uuidv4 = require('uuid/v4'); | ||
@@ -16,19 +17,13 @@ var bitcore = require('bitcore-lib'); | ||
var _require = require('lodash'), | ||
find = _require.find, | ||
findIndex = _require.findIndex; | ||
var utils = require('./utils'); | ||
var encryption = require('./encryption'); | ||
var _testPassword = require('./password'); | ||
var _testPassword2 = require('./password'); | ||
var _require2 = require('./mnemonic'), | ||
_generateMnemonic = _require2.generateMnemonic, | ||
_isMnemonicValid = _require2.isMnemonicValid, | ||
_isBip32XPublicKeyValid = _require2.isBip32XPublicKeyValid; | ||
var _require = require('./mnemonic'), | ||
_generateMnemonic = _require.generateMnemonic, | ||
_isMnemonicValid = _require.isMnemonicValid, | ||
_isBip32XPublicKeyValid = _require.isBip32XPublicKeyValid; | ||
var packageData = require('../package.json'); | ||
var ADDRESSES_PER_ITERATION_LIMIT = 5; | ||
var Keystore = function () { | ||
@@ -40,3 +35,3 @@ function Keystore() { | ||
this.accounts = []; | ||
this.wallets = []; | ||
this.defaultDerivationPath = props.defaultDerivationPath || "m/44'/60'/0'/0"; | ||
@@ -49,6 +44,5 @@ this.defaultEncryptionType = props.defaultEncryptionType || 'nacl.secretbox'; | ||
this.passwordConfig = props.passwordConfig || {}; | ||
this.addressesFromMnemonicPerIteration = 5; | ||
this.mnemonicType = 'mnemonic'; | ||
this.addressType = 'address'; | ||
this.checkPasswordData = null; | ||
this.salt = utils.generateSalt(this.saltByteCount); | ||
this.version = packageData.version; | ||
@@ -58,108 +52,101 @@ } | ||
_createClass(Keystore, [{ | ||
key: 'getAccounts', | ||
value: function getAccounts() { | ||
return this.accounts; | ||
key: 'getWallets', | ||
value: function getWallets() { | ||
return R.clone(this.wallets); | ||
} | ||
}, { | ||
key: 'getAccount', | ||
value: function getAccount(findProps) { | ||
if (!(findProps && findProps.id)) { | ||
throw new Error('Account ID not provided'); | ||
key: 'getWallet', | ||
value: function getWallet(walletId) { | ||
if (!walletId) { | ||
throw new Error('Wallet ID not provided'); | ||
} | ||
return this._getAccount(findProps); | ||
} | ||
}, { | ||
key: 'removeAccount', | ||
value: function removeAccount(accountId) { | ||
var accountIndex = this._getAccountIndex(accountId); | ||
var wallet = R.find(R.propEq('id', walletId))(this.wallets); | ||
if (accountIndex === -1) { | ||
return false; | ||
if (!wallet) { | ||
throw new Error('Wallet with id ' + walletId + ' not found'); | ||
} | ||
this.accounts.splice(accountIndex, 1); | ||
return R.clone(wallet); | ||
} | ||
}, { | ||
key: 'removeWallet', | ||
value: function removeWallet(walletId) { | ||
var wallet = this.getWallet(walletId); | ||
if (!this.accounts.length) { | ||
this._removePasswordDataToCheck(); | ||
} | ||
var isNotWalletId = function isNotWalletId(_ref) { | ||
var id = _ref.id; | ||
return id !== walletId; | ||
}; | ||
this.wallets = R.filter(isNotWalletId)(this.wallets); | ||
return true; | ||
return wallet; | ||
} | ||
}, { | ||
key: 'removeAccounts', | ||
value: function removeAccounts(password) { | ||
if (password) { | ||
this._checkPassword(password); | ||
} | ||
this.accounts = []; | ||
this._removePasswordDataToCheck(); | ||
key: 'removeWallets', | ||
value: function removeWallets() { | ||
this.wallets = []; | ||
} | ||
}, { | ||
key: 'createAccount', | ||
value: function createAccount(props) { | ||
key: 'createWallet', | ||
value: function createWallet(props) { | ||
var type = props.type, | ||
isReadOnly = props.isReadOnly, | ||
password = props.password, | ||
accountName = props.accountName, | ||
otherProps = _objectWithoutProperties(props, ['type', 'isReadOnly', 'password', 'accountName']); | ||
name = props.name, | ||
otherProps = _objectWithoutProperties(props, ['type', 'isReadOnly', 'password', 'name']); | ||
this._checkAccountUniqueness({ accountName: accountName }, 'name'); | ||
this._testPassword(password); | ||
var extendedAccountInfo = this._getExtendedAccountInfo(accountName); | ||
var accountData = _extends({}, otherProps, extendedAccountInfo, { password: password }); | ||
var extendedInfo = this._getExtendedWalletInfo(name); | ||
var walletData = _extends({}, otherProps, extendedInfo, { password: password }); | ||
this._checkPassword(password); | ||
this._checkWalletUniqueness(walletData.name, 'name'); | ||
var createAccountHandler = void 0; | ||
if (type === this.mnemonicType) { | ||
createAccountHandler = isReadOnly ? this._createReadOnlyMnemonicAccount : this._createMnemonicAccount; | ||
if (isReadOnly) { | ||
this._createReadOnlyMnemonicWallet(walletData); | ||
} else { | ||
this._createMnemonicWallet(walletData); | ||
} | ||
} else if (type === this.addressType) { | ||
createAccountHandler = isReadOnly ? this._createReadOnlyAddressAccount : this._createAddressAccount; | ||
if (isReadOnly) { | ||
this._createReadOnlyAddressWallet(walletData); | ||
} else { | ||
this._createAddressWallet(walletData); | ||
} | ||
} else { | ||
throw new Error('Type of account not provided or incorrect'); | ||
throw new Error('Type of wallet not provided or invalid'); | ||
} | ||
createAccountHandler.call(this, accountData); | ||
return accountData.id; | ||
return walletData.id; | ||
} | ||
}, { | ||
key: 'setAccountName', | ||
value: function setAccountName(accountId, accountName) { | ||
var account = this.getAccount({ id: accountId }); | ||
key: 'setWalletName', | ||
value: function setWalletName(walletId, name) { | ||
var wallet = this.getWallet(walletId); | ||
this._checkAccountExist(account); | ||
if (account.accountName === accountName) { | ||
return account; | ||
if (!name) { | ||
throw new Error('New wallet name should not be empty'); | ||
} else if (wallet.name === name) { | ||
throw new Error('New wallet name should not be equal with the old one'); | ||
} | ||
this._checkAccountUniqueness({ accountName: accountName }, 'name'); | ||
this._checkWalletUniqueness(name, 'name'); | ||
if (!(accountName && accountName.length)) { | ||
throw new Error('New account name should be not empty'); | ||
} | ||
return this._setAccount(account, { accountName: accountName }); | ||
return this._updateWallet(walletId, { name: name }); | ||
} | ||
}, { | ||
key: 'getPrivateKey', | ||
value: function getPrivateKey(password, accountId) { | ||
var addressIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; | ||
value: function getPrivateKey(password, walletId) { | ||
var _getWallet = this.getWallet(walletId), | ||
isReadOnly = _getWallet.isReadOnly, | ||
type = _getWallet.type, | ||
salt = _getWallet.salt, | ||
encrypted = _getWallet.encrypted; | ||
var account = this.getAccount({ id: accountId }); | ||
this._isNotReadOnly(isReadOnly); | ||
this._checkAccountExist(account); | ||
this._checkReadOnly(account); | ||
this._checkPassword(password); | ||
var privateKey = type === this.mnemonicType ? this._getPrivateKeyFromMnemonic(password, walletId) : this._decryptPrivateKey(encrypted.privateKey, password, salt); | ||
var type = account.type, | ||
encrypted = account.encrypted; | ||
var privateKey = type === 'address' ? this._decryptData(encrypted.privateKey, password, true) : this._getPrivateKeyFromMnemonic(password, account, addressIndex); | ||
return utils.add0x(privateKey); | ||
@@ -169,19 +156,24 @@ } | ||
key: 'setAddressIndex', | ||
value: function setAddressIndex(accountId) { | ||
value: function setAddressIndex(walletId) { | ||
var addressIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
var account = this.getAccount({ id: accountId, type: this.mnemonicType }); | ||
var _getWallet2 = this.getWallet(walletId), | ||
type = _getWallet2.type; | ||
this._checkAccountExist(account); | ||
this._isMnemonicType(type); | ||
return this._setAccount(account, { addressIndex: addressIndex }); | ||
return this._updateWallet(walletId, { addressIndex: addressIndex }); | ||
} | ||
}, { | ||
key: 'setDerivationPath', | ||
value: function setDerivationPath(password, accountId, newDerivationPath) { | ||
var account = this.getAccount({ id: accountId, type: this.mnemonicType }); | ||
value: function setDerivationPath(password, walletId, newDerivationPath) { | ||
var _getWallet3 = this.getWallet(walletId), | ||
isReadOnly = _getWallet3.isReadOnly, | ||
type = _getWallet3.type, | ||
salt = _getWallet3.salt, | ||
encrypted = _getWallet3.encrypted, | ||
derivationPath = _getWallet3.derivationPath; | ||
this._checkAccountExist(account); | ||
this._checkReadOnly(account); | ||
this._checkPassword(password); | ||
this._isMnemonicType(type); | ||
this._isNotReadOnly(isReadOnly); | ||
@@ -192,15 +184,11 @@ if (!this.constructor.isDerivationPathValid(newDerivationPath)) { | ||
var encrypted = account.encrypted, | ||
derivationPath = account.derivationPath; | ||
if (newDerivationPath === derivationPath) { | ||
if (R.equals(R.toLower(newDerivationPath), R.toLower(derivationPath))) { | ||
throw new Error('Can not set the same derivation path'); | ||
} | ||
var xpub = this._getXPubFromMnemonic(password, encrypted.mnemonic, newDerivationPath); | ||
var xpub = this._getXPubFromMnemonic(password, salt, encrypted.mnemonic, newDerivationPath); | ||
this._checkAccountUniqueness({ bip32XPublicKey: xpub }, 'xpub'); | ||
this._checkWalletUniqueness(xpub, 'bip32XPublicKey'); | ||
return this._setAccount(account, { | ||
return this._updateWallet(walletId, { | ||
derivationPath: newDerivationPath, | ||
@@ -212,33 +200,38 @@ bip32XPublicKey: xpub | ||
key: 'getAddressesFromMnemonic', | ||
value: function getAddressesFromMnemonic(accountId) { | ||
value: function getAddressesFromMnemonic(walletId) { | ||
var iteration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ADDRESSES_PER_ITERATION_LIMIT; | ||
var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.addressesFromMnemonicPerIteration; | ||
var account = this.getAccount({ id: accountId, type: this.mnemonicType }); | ||
var _getWallet4 = this.getWallet(walletId), | ||
type = _getWallet4.type, | ||
bip32XPublicKey = _getWallet4.bip32XPublicKey; | ||
this._checkAccountExist(account); | ||
this._isMnemonicType(type); | ||
return this._generateAddresses(account.bip32XPublicKey, iteration, limit); | ||
return this._generateAddresses(bip32XPublicKey, iteration, limit); | ||
} | ||
}, { | ||
key: 'getAddressFromMnemonic', | ||
value: function getAddressFromMnemonic(accountId) { | ||
var addressIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
key: 'getAddress', | ||
value: function getAddress(walletId) { | ||
var _getWallet5 = this.getWallet(walletId), | ||
type = _getWallet5.type, | ||
address = _getWallet5.address, | ||
addressIndex = _getWallet5.addressIndex, | ||
bip32XPublicKey = _getWallet5.bip32XPublicKey; | ||
var account = this.getAccount({ id: accountId, type: this.mnemonicType }); | ||
this._checkAccountExist(account); | ||
return this._generateAddresses(account.bip32XPublicKey, addressIndex, 1).shift(); | ||
return type === this.mnemonicType ? R.head(this._generateAddresses(bip32XPublicKey, addressIndex, 1)) : address; | ||
} | ||
}, { | ||
key: 'getMnemonic', | ||
value: function getMnemonic(password, accountId) { | ||
var account = this.getAccount({ id: accountId, type: this.mnemonicType }); | ||
value: function getMnemonic(password, walletId) { | ||
var _getWallet6 = this.getWallet(walletId), | ||
isReadOnly = _getWallet6.isReadOnly, | ||
type = _getWallet6.type, | ||
salt = _getWallet6.salt, | ||
encrypted = _getWallet6.encrypted; | ||
this._checkAccountExist(account); | ||
this._checkReadOnly(account); | ||
this._checkPassword(password); | ||
this._isMnemonicType(type); | ||
this._isNotReadOnly(isReadOnly); | ||
var paddedMnemonic = this._decryptData(account.encrypted.mnemonic, password); | ||
var paddedMnemonic = this._decryptData(encrypted.mnemonic, password, salt); | ||
@@ -248,2 +241,36 @@ return paddedMnemonic.trim(); | ||
}, { | ||
key: 'getDecryptedWallet', | ||
value: function getDecryptedWallet(password, walletId) { | ||
var _getWallet7 = this.getWallet(walletId), | ||
id = _getWallet7.id, | ||
isReadOnly = _getWallet7.isReadOnly, | ||
type = _getWallet7.type, | ||
name = _getWallet7.name, | ||
address = _getWallet7.address, | ||
salt = _getWallet7.salt, | ||
encrypted = _getWallet7.encrypted; | ||
var walletData = { | ||
id: id, | ||
name: name, | ||
type: type, | ||
readOnly: isReadOnly ? 'yes' : 'no' | ||
}; | ||
if (isReadOnly) { | ||
return walletData; | ||
} | ||
if (type === this.mnemonicType) { | ||
return R.assoc('mnemonic', this._decryptData(encrypted.mnemonic, password, salt))(walletData); | ||
} | ||
return R.compose(R.assoc('address', address), R.assoc('privateKey', this._decryptPrivateKey(encrypted.privateKey, password, salt)))(walletData); | ||
} | ||
}, { | ||
key: 'setPassword', | ||
value: function setPassword(password, newPassword, walletId) { | ||
this._reEncryptData(password, newPassword, walletId); | ||
} | ||
}, { | ||
key: 'serialize', | ||
@@ -256,59 +283,19 @@ value: function serialize() { | ||
value: function deserialize(backupData) { | ||
var data = void 0; | ||
try { | ||
var data = JSON.parse(backupData); | ||
this._restoreBackupData(data); | ||
try { | ||
data = JSON.parse(backupData); | ||
return data; | ||
} catch (err) { | ||
throw new Error('Failed to parse backup data'); | ||
} | ||
this._restoreBackupData(data); | ||
return data; | ||
} | ||
}, { | ||
key: 'getDecryptedAccounts', | ||
value: function getDecryptedAccounts(password) { | ||
var _this = this; | ||
this._checkPassword(password); | ||
return this.accounts.map(function (account) { | ||
var isReadOnly = account.isReadOnly, | ||
type = account.type, | ||
accountName = account.accountName, | ||
address = account.address, | ||
encrypted = account.encrypted; | ||
var privateKey = encrypted.privateKey, | ||
mnemonic = encrypted.mnemonic; | ||
var decryptedPrivateKey = privateKey ? _this._decryptData(privateKey, password) : null; | ||
var decryptedMnemonic = mnemonic ? _this._decryptData(mnemonic, password) : null; | ||
return { | ||
accountName: accountName, | ||
type: type, | ||
readOnly: isReadOnly ? 'yes' : 'no', | ||
address: address || 'n/a', | ||
privateKey: decryptedPrivateKey || 'n/a', | ||
mnemonic: decryptedMnemonic ? decryptedMnemonic.trim() : 'n/a' | ||
}; | ||
}); | ||
} | ||
}, { | ||
key: 'setPassword', | ||
value: function setPassword(password, newPassword) { | ||
this._checkPassword(password); | ||
this._setPasswordDataToCheck(newPassword); | ||
this._reEncryptData(password, newPassword); | ||
} | ||
}, { | ||
key: '_createMnemonicAccount', | ||
value: function _createMnemonicAccount(props) { | ||
key: '_createMnemonicWallet', | ||
value: function _createMnemonicWallet(props) { | ||
var id = props.id, | ||
password = props.password, | ||
accountName = props.accountName; | ||
name = props.name; | ||
var mnemonic = props.mnemonic.toLowerCase(); | ||
var mnemonic = R.toLower(props.mnemonic); | ||
var derivationPath = props.derivationPath || this.defaultDerivationPath; | ||
@@ -322,27 +309,35 @@ | ||
var salt = utils.generateSalt(this.saltByteCount); | ||
var paddedMnemonic = utils.leftPadString(mnemonic, ' ', this.paddedMnemonicLength); | ||
var encryptedMnemonic = this._encryptData(paddedMnemonic, password); | ||
var bip32XPublicKey = this._getXPubFromMnemonic(password, encryptedMnemonic, derivationPath); | ||
var encryptedMnemonic = this._encryptData(paddedMnemonic, password, salt); | ||
var xpub = this._getXPubFromMnemonic(password, salt, encryptedMnemonic, derivationPath); | ||
this._checkAccountUniqueness({ bip32XPublicKey: bip32XPublicKey }, 'xpub'); | ||
this._checkWalletUniqueness(xpub, 'bip32XPublicKey'); | ||
this.accounts.push({ | ||
type: this.mnemonicType, | ||
this._appendWallet({ | ||
id: id, | ||
accountName: accountName, | ||
name: name, | ||
salt: salt, | ||
derivationPath: derivationPath, | ||
bip32XPublicKey: bip32XPublicKey, | ||
addressIndex: 0, | ||
isReadOnly: false, | ||
addressIndex: 0, | ||
userType: 'mnemonic', | ||
bip32XPublicKey: xpub, | ||
type: this.mnemonicType, | ||
encrypted: { | ||
privateKey: null, | ||
mnemonic: encryptedMnemonic | ||
} | ||
}, | ||
/** | ||
* Another wallet data, necessary for consistency of types | ||
*/ | ||
address: null | ||
}); | ||
} | ||
}, { | ||
key: '_createReadOnlyMnemonicAccount', | ||
value: function _createReadOnlyMnemonicAccount(props) { | ||
key: '_createReadOnlyMnemonicWallet', | ||
value: function _createReadOnlyMnemonicWallet(props) { | ||
var id = props.id, | ||
bip32XPublicKey = props.bip32XPublicKey, | ||
accountName = props.accountName; | ||
name = props.name; | ||
@@ -354,89 +349,119 @@ | ||
this._checkAccountUniqueness({ bip32XPublicKey: bip32XPublicKey }, 'xpub'); | ||
this._checkWalletUniqueness(bip32XPublicKey, 'bip32XPublicKey'); | ||
this.accounts.push({ | ||
type: this.mnemonicType, | ||
this._appendWallet({ | ||
id: id, | ||
accountName: accountName, | ||
name: name, | ||
bip32XPublicKey: bip32XPublicKey, | ||
addressIndex: 0, | ||
isReadOnly: true, | ||
addressIndex: 0, | ||
encrypted: {} | ||
userType: 'bip32Xpub', | ||
type: this.mnemonicType, | ||
/** | ||
* Another wallet data, necessary for consistency of types | ||
*/ | ||
salt: null, | ||
address: null, | ||
encrypted: null, | ||
derivationPath: null | ||
}); | ||
} | ||
}, { | ||
key: '_createAddressAccount', | ||
value: function _createAddressAccount(props) { | ||
key: '_createAddressWallet', | ||
value: function _createAddressWallet(props) { | ||
var id = props.id, | ||
password = props.password, | ||
accountName = props.accountName, | ||
name = props.name, | ||
privateKey = props.privateKey; | ||
if (!utils.isValidPrivateKey(privateKey)) { | ||
if (!utils.isPrivateKeyValid(privateKey)) { | ||
throw new Error('Private Key is invalid'); | ||
} | ||
var salt = utils.generateSalt(this.saltByteCount); | ||
var address = utils.getAddressFromPrivateKey(privateKey); | ||
var addressLowerCase = address.toLowerCase(); | ||
this._checkAccountUniqueness({ addressLowerCase: addressLowerCase }, 'address'); | ||
this._checkWalletUniqueness(address, 'address'); | ||
this.accounts.push({ | ||
type: this.addressType, | ||
this._appendWallet({ | ||
id: id, | ||
name: name, | ||
salt: salt, | ||
address: address, | ||
addressLowerCase: addressLowerCase, | ||
accountName: accountName, | ||
isReadOnly: false, | ||
userType: 'privateKey', | ||
type: this.addressType, | ||
encrypted: { | ||
privateKey: this._encryptData(privateKey, password, true) | ||
} | ||
mnemonic: null, | ||
privateKey: this._encryptPrivateKey(privateKey, password, salt) | ||
}, | ||
/** | ||
* Another wallet data, necessary for consistency of types | ||
*/ | ||
addressIndex: null, | ||
derivationPath: null, | ||
bip32XPublicKey: null | ||
}); | ||
} | ||
}, { | ||
key: '_createReadOnlyAddressAccount', | ||
value: function _createReadOnlyAddressAccount(props) { | ||
key: '_createReadOnlyAddressWallet', | ||
value: function _createReadOnlyAddressWallet(props) { | ||
var id = props.id, | ||
accountName = props.accountName, | ||
name = props.name, | ||
address = props.address; | ||
if (!utils.isValidAddress(address)) { | ||
if (!utils.isAddressValid(address)) { | ||
throw new Error('Address is invalid'); | ||
} | ||
var addressLowerCase = address.toLowerCase(); | ||
this._checkAccountUniqueness({ addressLowerCase: addressLowerCase }, 'address'); | ||
this._checkWalletUniqueness(address, 'address'); | ||
this.accounts.push({ | ||
type: this.addressType, | ||
this._appendWallet({ | ||
id: id, | ||
name: name, | ||
address: address, | ||
addressLowerCase: addressLowerCase, | ||
accountName: accountName, | ||
isReadOnly: true, | ||
encrypted: {} | ||
userType: 'address', | ||
type: this.addressType, | ||
/** | ||
* Another wallet data, necessary for consistency of types | ||
*/ | ||
salt: null, | ||
encrypted: null, | ||
addressIndex: null, | ||
derivationPath: null, | ||
bip32XPublicKey: null | ||
}); | ||
} | ||
}, { | ||
key: '_getExtendedAccountInfo', | ||
value: function _getExtendedAccountInfo(accountName) { | ||
key: '_appendWallet', | ||
value: function _appendWallet(wallet) { | ||
this.wallets = R.append(wallet)(this.wallets); | ||
} | ||
}, { | ||
key: '_getExtendedWalletInfo', | ||
value: function _getExtendedWalletInfo(name) { | ||
var id = uuidv4(); | ||
return { id: uuidv4(), accountName: accountName || id }; | ||
return { id: id, name: name || id }; | ||
} | ||
}, { | ||
key: '_deriveKeyFromPassword', | ||
value: function _deriveKeyFromPassword(password) { | ||
var scryptParams = this.scryptParams, | ||
derivedKeyLength = this.derivedKeyLength, | ||
salt = this.salt; | ||
value: function _deriveKeyFromPassword(password, salt) { | ||
if (!password) { | ||
throw new Error('Password is empty'); | ||
} | ||
return utils.deriveKeyFromPassword(password, scryptParams, derivedKeyLength, salt); | ||
return utils.deriveKeyFromPassword(password, this.scryptParams, this.derivedKeyLength, salt); | ||
} | ||
}, { | ||
key: '_encryptPrivateKey', | ||
value: function _encryptPrivateKey(dataToEncrypt, password, salt) { | ||
return this._encryptData(dataToEncrypt, password, salt, true); | ||
} | ||
}, { | ||
key: '_encryptData', | ||
value: function _encryptData(dataToEncrypt, password) { | ||
var isPrivateKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
value: function _encryptData(dataToEncrypt, password, salt) { | ||
var isPrivateKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
@@ -447,9 +472,14 @@ return encryption.encryptData({ | ||
encryptionType: this.defaultEncryptionType, | ||
derivedKey: this._deriveKeyFromPassword(password) | ||
derivedKey: this._deriveKeyFromPassword(password, salt) | ||
}); | ||
} | ||
}, { | ||
key: '_decryptPrivateKey', | ||
value: function _decryptPrivateKey(dataToDecrypt, password, salt) { | ||
return this._decryptData(dataToDecrypt, password, salt, true); | ||
} | ||
}, { | ||
key: '_decryptData', | ||
value: function _decryptData(dataToDecrypt, password) { | ||
var isPrivateKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
value: function _decryptData(dataToDecrypt, password, salt) { | ||
var isPrivateKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
@@ -459,3 +489,3 @@ return encryption.decryptData({ | ||
data: dataToDecrypt, | ||
derivedKey: this._deriveKeyFromPassword(password) | ||
derivedKey: this._deriveKeyFromPassword(password, salt) | ||
}); | ||
@@ -465,7 +495,10 @@ } | ||
key: '_getPrivateKeyFromMnemonic', | ||
value: function _getPrivateKeyFromMnemonic(password, account, addressIndex) { | ||
var encrypted = account.encrypted, | ||
derivationPath = account.derivationPath; | ||
value: function _getPrivateKeyFromMnemonic(password, walletId) { | ||
var _getWallet8 = this.getWallet(walletId), | ||
encrypted = _getWallet8.encrypted, | ||
derivationPath = _getWallet8.derivationPath, | ||
addressIndex = _getWallet8.addressIndex, | ||
salt = _getWallet8.salt; | ||
var hdRoot = this._getPrivateHdRoot(password, encrypted.mnemonic, derivationPath); | ||
var hdRoot = this._getPrivateHdRoot(password, salt, encrypted.mnemonic, derivationPath); | ||
var generatedKey = this._generateKey(hdRoot, addressIndex); | ||
@@ -478,18 +511,20 @@ | ||
value: function _generateAddresses(bip32XPublicKey, iteration, limit) { | ||
var _this = this; | ||
var keyIndexStart = iteration * limit; | ||
var keyIndexEnd = keyIndexStart + limit; | ||
var addresses = []; | ||
var hdRoot = this._getPublicHdRoot(bip32XPublicKey); | ||
var range = R.range(keyIndexStart, keyIndexEnd); | ||
for (var index = keyIndexStart; index < keyIndexEnd; index += 1) { | ||
var generatedKey = this._generateKey(hdRoot, index); | ||
var publicKey = generatedKey.publicKey.toString(); | ||
var address = utils.getAddressFromPublicKey(publicKey); | ||
return R.map(function (index) { | ||
return _this._generateAddress(hdRoot, index); | ||
})(range); | ||
} | ||
}, { | ||
key: '_generateAddress', | ||
value: function _generateAddress(hdRoot, index) { | ||
var generatedKey = this._generateKey(hdRoot, index); | ||
var publicKey = generatedKey.publicKey.toString(); | ||
addresses.push(address); | ||
} | ||
return addresses; | ||
return utils.getAddressFromPublicKey(publicKey); | ||
} | ||
@@ -516,4 +551,4 @@ }, { | ||
key: '_getPrivateHdRoot', | ||
value: function _getPrivateHdRoot(password, encryptedMnemonic, derivationPath) { | ||
var mnemonic = this._decryptData(encryptedMnemonic, password); | ||
value: function _getPrivateHdRoot(password, salt, encryptedMnemonic, derivationPath) { | ||
var mnemonic = this._decryptData(encryptedMnemonic, password, salt); | ||
var hdPath = this._getHdPath(mnemonic, derivationPath); | ||
@@ -525,4 +560,4 @@ | ||
key: '_getXPubFromMnemonic', | ||
value: function _getXPubFromMnemonic(password, encryptedMnemonic, derivationPath) { | ||
var hdRoot = this._getPrivateHdRoot(password, encryptedMnemonic, derivationPath); | ||
value: function _getXPubFromMnemonic(password, salt, encryptedMnemonic, derivationPath) { | ||
var hdRoot = this._getPrivateHdRoot(password, salt, encryptedMnemonic, derivationPath); | ||
@@ -532,49 +567,16 @@ return hdRoot.hdPublicKey.toString(); | ||
}, { | ||
key: '_setAccount', | ||
value: function _setAccount(account, props) { | ||
var accountIndex = this._getAccountIndex(account.id); | ||
key: '_updateWallet', | ||
value: function _updateWallet(walletId, newData) { | ||
var wallet = this.getWallet(walletId); | ||
var newWallet = _extends({}, wallet, newData); | ||
if (accountIndex === -1) { | ||
throw new Error('Account not found'); | ||
} | ||
this.removeWallet(walletId); | ||
this._appendWallet(newWallet); | ||
var newAccount = _extends({}, account, props); | ||
this.accounts.splice(accountIndex, 1, newAccount); | ||
return newAccount; | ||
return newWallet; | ||
} | ||
}, { | ||
key: '_getAccount', | ||
value: function _getAccount(findProps) { | ||
return find(this.accounts, findProps); | ||
} | ||
}, { | ||
key: '_getAccountIndex', | ||
value: function _getAccountIndex(accountId) { | ||
return findIndex(this.accounts, { id: accountId }); | ||
} | ||
}, { | ||
key: '_getBackupData', | ||
value: function _getBackupData() { | ||
var accounts = this.accounts, | ||
defaultDerivationPath = this.defaultDerivationPath, | ||
defaultEncryptionType = this.defaultEncryptionType, | ||
scryptParams = this.scryptParams, | ||
derivedKeyLength = this.derivedKeyLength, | ||
checkPasswordData = this.checkPasswordData, | ||
salt = this.salt, | ||
version = this.version; | ||
return { | ||
accounts: accounts, | ||
defaultDerivationPath: defaultDerivationPath, | ||
defaultEncryptionType: defaultEncryptionType, | ||
scryptParams: scryptParams, | ||
derivedKeyLength: derivedKeyLength, | ||
checkPasswordData: checkPasswordData, | ||
salt: salt, | ||
version: version | ||
}; | ||
return R.pick(['wallets', 'defaultDerivationPath', 'defaultEncryptionType', 'scryptParams', 'derivedKeyLength', 'version'])(this); | ||
} | ||
@@ -585,12 +587,10 @@ }, { | ||
if (backupData.version <= packageData.version) { | ||
var accounts = backupData.accounts, | ||
var wallets = backupData.wallets, | ||
defaultDerivationPath = backupData.defaultDerivationPath, | ||
defaultEncryptionType = backupData.defaultEncryptionType, | ||
scryptParams = backupData.scryptParams, | ||
derivedKeyLength = backupData.derivedKeyLength, | ||
checkPasswordData = backupData.checkPasswordData, | ||
salt = backupData.salt; | ||
derivedKeyLength = backupData.derivedKeyLength; | ||
this.accounts = accounts || []; | ||
this.wallets = wallets || []; | ||
this.defaultDerivationPath = defaultDerivationPath || this.defaultDerivationPath; | ||
@@ -600,4 +600,2 @@ this.defaultEncryptionType = defaultEncryptionType || this.defaultEncryptionType; | ||
this.derivedKeyLength = derivedKeyLength || this.derivedKeyLength; | ||
this.checkPasswordData = checkPasswordData || this.checkPasswordData; | ||
this.salt = salt || this.salt; | ||
this.version = packageData.version; | ||
@@ -607,98 +605,67 @@ } | ||
}, { | ||
key: '_checkAccountExist', | ||
value: function _checkAccountExist(account) { | ||
if (!account) { | ||
throw new Error('Account not found'); | ||
key: '_isNotReadOnly', | ||
value: function _isNotReadOnly(isReadOnly) { | ||
if (isReadOnly) { | ||
throw new Error('Wallet is read only'); | ||
} | ||
} | ||
}, { | ||
key: '_checkReadOnly', | ||
value: function _checkReadOnly(account) { | ||
if (account.isReadOnly) { | ||
throw new Error('Account is read only'); | ||
key: '_isMnemonicType', | ||
value: function _isMnemonicType(type) { | ||
if (type !== this.mnemonicType) { | ||
throw new Error('Wallet type is not mnemonic'); | ||
} | ||
} | ||
}, { | ||
key: '_checkPassword', | ||
value: function _checkPassword(password) { | ||
if (!(password && password.length)) { | ||
throw new Error('Password is empty'); | ||
} | ||
key: '_checkWalletUniqueness', | ||
value: function _checkWalletUniqueness(uniqueProperty, propertyName) { | ||
var isFound = function isFound(wallet) { | ||
var property = wallet[propertyName]; | ||
if (!this.checkPasswordData) { | ||
this._setPasswordDataToCheck(password); | ||
return property ? R.equals(R.toLower(property), R.toLower(uniqueProperty)) : false; | ||
}; | ||
return; | ||
} | ||
var foundWallet = R.compose(R.head, R.filter(isFound))(this.wallets); | ||
var errMessage = 'Password is incorrect'; | ||
try { | ||
var decryptedData = this._decryptData(this.checkPasswordData, password); | ||
if (!(decryptedData && decryptedData.length)) { | ||
throw new Error(errMessage); | ||
} | ||
} catch (e) { | ||
throw new Error(errMessage); | ||
if (foundWallet) { | ||
throw new Error('Wallet with this ' + propertyName + ' already exists'); | ||
} | ||
} | ||
}, { | ||
key: '_checkAccountUniqueness', | ||
value: function _checkAccountUniqueness(uniqueProperty, propertyName) { | ||
var isAccountExist = !!this._getAccount(uniqueProperty); | ||
key: '_testPassword', | ||
value: function _testPassword(password) { | ||
var testPasswordResult = _testPassword2(password, this.passwordConfig); | ||
if (isAccountExist) { | ||
throw new Error('Account with this ' + propertyName + ' already exists'); | ||
} | ||
} | ||
}, { | ||
key: '_setPasswordDataToCheck', | ||
value: function _setPasswordDataToCheck(password) { | ||
var testPasswordResult = _testPassword(password, this.passwordConfig); | ||
if (testPasswordResult.failedTests.length) { | ||
throw new Error(testPasswordResult.errors[0]); | ||
} | ||
var checkPasswordData = utils.generateSalt(this.saltByteCount); | ||
this.checkPasswordData = this._encryptData(checkPasswordData, password); | ||
} | ||
}, { | ||
key: '_removePasswordDataToCheck', | ||
value: function _removePasswordDataToCheck() { | ||
this.checkPasswordData = null; | ||
} | ||
}, { | ||
key: '_reEncryptData', | ||
value: function _reEncryptData(password, newPassword) { | ||
var _this2 = this; | ||
value: function _reEncryptData(password, newPassword, walletId) { | ||
var _getWallet9 = this.getWallet(walletId), | ||
isReadOnly = _getWallet9.isReadOnly, | ||
type = _getWallet9.type, | ||
salt = _getWallet9.salt, | ||
encrypted = _getWallet9.encrypted; | ||
this.accounts.forEach(function (account) { | ||
var isReadOnly = account.isReadOnly, | ||
encrypted = account.encrypted; | ||
if (isReadOnly) { | ||
return; | ||
} | ||
if (type === this.mnemonicType) { | ||
var decryptedMnemonic = this._decryptData(encrypted.mnemonic, password, salt); | ||
var mnemonic = this._encryptData(decryptedMnemonic, newPassword, salt); | ||
if (isReadOnly) { | ||
return; | ||
} | ||
this._updateWallet(walletId, { | ||
encrypted: R.assoc('mnemonic', mnemonic)(encrypted) | ||
}); | ||
} else { | ||
var decryptedPrivateKey = this._decryptPrivateKey(encrypted.privateKey, password, salt); | ||
var privateKey = this._encryptPrivateKey(decryptedPrivateKey, newPassword, salt); | ||
var newEncrypted = {}; | ||
Object.keys(encrypted).forEach(function (key) { | ||
var encryptedItem = encrypted[key]; | ||
var isPrivateKey = key === 'privateKey'; | ||
if (encryptedItem) { | ||
var decryptedItem = _this2._decryptData(encryptedItem, password, isPrivateKey); | ||
newEncrypted[key] = _this2._encryptData(decryptedItem, newPassword); | ||
} else { | ||
newEncrypted[key] = encryptedItem; | ||
} | ||
this._updateWallet(walletId, { | ||
encrypted: R.assoc('privateKey', privateKey)(encrypted) | ||
}); | ||
_this2._setAccount(account, { encrypted: newEncrypted }); | ||
}); | ||
} | ||
} | ||
@@ -723,10 +690,10 @@ }], [{ | ||
}, { | ||
key: 'isValidAddress', | ||
value: function isValidAddress(address) { | ||
return utils.isValidAddress(address); | ||
key: 'isAddressValid', | ||
value: function isAddressValid(address) { | ||
return utils.isAddressValid(address); | ||
} | ||
}, { | ||
key: 'isValidPrivateKey', | ||
value: function isValidPrivateKey(privateKey) { | ||
return utils.isValidPrivateKey(privateKey); | ||
key: 'isPrivateKeyValid', | ||
value: function isPrivateKeyValid(privateKey) { | ||
return utils.isPrivateKeyValid(privateKey); | ||
} | ||
@@ -741,3 +708,3 @@ }, { | ||
value: function testPassword(password, passwordConfig) { | ||
return _testPassword(password, passwordConfig); | ||
return _testPassword2(password, passwordConfig); | ||
} | ||
@@ -744,0 +711,0 @@ }]); |
@@ -12,4 +12,4 @@ 'use strict'; | ||
function isValidAddress(address) { | ||
return isNormalizedAddress(address) || isValidChecksumAddress(address); | ||
function isAddressValid(address) { | ||
return isNormalizedAddress(address) || isChecksumAddressValid(address); | ||
} | ||
@@ -22,3 +22,3 @@ | ||
function isValidChecksumAddress(address) { | ||
function isChecksumAddressValid(address) { | ||
return (/^0x[0-9a-fA-F]{40}$/i.test(address) && getChecksum(address) === address | ||
@@ -39,3 +39,3 @@ ); | ||
function isValidPrivateKey(privateKey) { | ||
function isPrivateKeyValid(privateKey) { | ||
return (/^0x[0-9a-fA-F]{64}$/i.test(privateKey) | ||
@@ -66,3 +66,3 @@ ); | ||
return add0x(address); | ||
return getChecksum(address); | ||
} | ||
@@ -108,4 +108,4 @@ | ||
module.exports = { | ||
isValidAddress: isValidAddress, | ||
isValidPrivateKey: isValidPrivateKey, | ||
isAddressValid: isAddressValid, | ||
isPrivateKeyValid: isPrivateKeyValid, | ||
getAddressFromPublicKey: getAddressFromPublicKey, | ||
@@ -112,0 +112,0 @@ getAddressFromPrivateKey: getAddressFromPrivateKey, |
{ | ||
"name": "jwallet-web-keystore", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "Library for ethereum blockchain accounts management", | ||
@@ -11,3 +11,5 @@ "main": "index.js", | ||
"compile": "npm run clean && ./node_modules/.bin/babel ./src --out-dir ./lib", | ||
"build": "npm run lint && npm run compile && npm test" | ||
"build": "npm run lint && npm run compile && npm test", | ||
"precommit": "./node_modules/.bin/lint-staged", | ||
"prepush": "npm run build" | ||
}, | ||
@@ -33,2 +35,7 @@ "repository": { | ||
"account", | ||
"seed", | ||
"seed-phrase", | ||
"bip32", | ||
"bip32xpublickey", | ||
"extended-public-key", | ||
"ethereum", | ||
@@ -50,3 +57,3 @@ "address", | ||
"elliptic": "6.4.0", | ||
"lodash": "4.17.4", | ||
"ramda": "0.25.0", | ||
"scrypt.js": "0.2.0", | ||
@@ -66,2 +73,4 @@ "tweetnacl": "1.0.0", | ||
"eslint-plugin-import": "2.7.0", | ||
"husky": "0.14.3", | ||
"lint-staged": "6.1.1", | ||
"mocha": "3.5.3", | ||
@@ -68,0 +77,0 @@ "should": "13.1.0", |
231
README.md
# jwallet-web-keystore | ||
Library for ethereum blockchain accounts management. | ||
Library for ethereum blockchain wallets management. | ||
@@ -14,5 +14,5 @@ <p align="center"> | ||
Keystore can hold `read only` / `full access` accounts of two types: | ||
* Address / PrivateKey | ||
* Mnemonic | ||
Keystore can hold `read only` / `full access` wallets of two types: | ||
* `privateKey` / `address` | ||
* `mnemonic` / `bip32XPublicKey` | ||
@@ -41,20 +41,22 @@ Also Keystore API provides several [utility methods](#static-methods) for working with mnemonics / hashes / passwords. | ||
### Account properties | ||
### Wallet properties | ||
| Property | Type | Description | | ||
| -------------------- | ------- | ----------------------------------------------------------------- | | ||
| id | String | Unique ID of account | | ||
| type | String | Type of account (`mnemonic` / `address`) | | ||
| accountName | String | Account name | | ||
| derivationPath | String | Derivation path for generating of addresses from mnemonic | | ||
| isReadOnly | Boolean | Read-only flag of account | | ||
| address | String | Address of account | | ||
| addressIndex | Number | Current index of address of `mnemonic` account | | ||
| bip32XPublicKey | String | BIP32 Extended Public Key | | ||
| encrypted | Object | Container of encrypted data | | ||
| encrypted.privateKey | Object | Encrypted private key | | ||
| encrypted.mnemonic | Object | Encrypted mnemonic | | ||
| Property | Type | Description | | ||
| -------------------- | ------- | --------------------------------------------------------- | | ||
| id | String | Unique ID of wallet | | ||
| type | String | Type of wallet (`mnemonic` / `address`) | | ||
| name | String | Wallet name | | ||
| salt | String | Salt for enforcing of password | | ||
| address | String | Address of wallet | | ||
| userType | String | User-friendly type of wallet | | ||
| isReadOnly | Boolean | Read-only flag of wallet | | ||
| addressIndex | Number | Current index of address of `mnemonic` wallet | | ||
| derivationPath | String | Derivation path for generating of addresses from mnemonic | | ||
| bip32XPublicKey | String | BIP32 Extended Public Key | | ||
| encrypted | Object | Container of encrypted data | | ||
| encrypted.privateKey | Object | Encrypted private key | | ||
| encrypted.mnemonic | Object | Encrypted mnemonic | | ||
**Notes:** | ||
* `isReadOnly` - flag means that account can be used only for balance / transactions checking | ||
* `isReadOnly` - flag means that wallet can be used only for balance / transactions checking | ||
* `bip32XPublicKey` - `xpub...` key that used for deriving of public keys (addresses) | ||
@@ -64,3 +66,3 @@ | ||
See [mocha tests](https://github.com/jibrelnetwork/keystore/tree/master/test) for examples of usage. | ||
See [mocha tests](https://github.com/jibrelnetwork/jwallet-web-keystore/tree/master/test) for examples of usage. | ||
@@ -76,3 +78,3 @@ ### new Keystore(props) | ||
| props | Object | {} | Constructor properties | | ||
| props.defaultDerivationPath | String | "m/44'/60'/0'/0" | Default derivation path for new `Mnemonic` accounts | | ||
| props.defaultDerivationPath | String | "m/44'/60'/0'/0" | Default derivation path for new `Mnemonic` wallets | | ||
| props.defaultEncryptionType | String | 'nacl.secretbox' | Default encryption type. Currently `nacl.secretbox` is only one supported | | ||
@@ -97,7 +99,7 @@ | props.paddedMnemonicLength | Number | 120 | Mnemonic will be padded left with this size before encryption | | ||
#### getAccounts() | ||
#### getWallets() | ||
##### Returns | ||
Accounts list presented in keystore. | ||
Wallets list presented in keystore. | ||
@@ -107,16 +109,14 @@ ##### Example | ||
```javascript | ||
const accounts = keystore.getAccounts() | ||
const wallets = keystore.getWallets() | ||
``` | ||
#### getAccount(props) | ||
#### getWallet(walletId) | ||
##### Parameters | ||
account properties object ([Account properties](#account-properties)). | ||
Wallet ID. | ||
**Note: all properties are optional except of `id`.** | ||
##### Returns | ||
Accounts list presented in keystore. | ||
Wallet found by its ID. | ||
@@ -126,14 +126,22 @@ ##### Example | ||
```javascript | ||
const accounts = keystore.getAccounts() | ||
const wallet = keystore.getWallet('JHJ23jG^*DGHj667s') | ||
``` | ||
#### createAccount(props) | ||
#### createWallet(props) | ||
##### Parameters | ||
account properties with except of `id` & `encrypted` ([Account properties](#account-properties)) | ||
wallet properties([Wallet properties](#wallet-properties)): | ||
* `type` | ||
* `name` | ||
* `address` | ||
* `mnemonic` | ||
* `isReadOnly` | ||
* `privateKey` | ||
* `derivationPath` | ||
* `bip32XPublicKey` | ||
##### Returns | ||
Unique ID of created account | ||
Unique ID of created wallet | ||
@@ -143,21 +151,22 @@ ##### Example | ||
```javascript | ||
const accountId = keystore.createAccount({ | ||
const walletId = keystore.createWallet({ | ||
type: 'address', | ||
name: 'My wallet', | ||
isReadonly: false, | ||
password: 'JHJ23jG^*DGHj667s', | ||
type: 'address', | ||
privateKey: '0x8a02a99cc7a801da6996a2dacc406ffa5190dc9c8a02a99cc7a801da6996a2da', | ||
accountName: 'My account', | ||
}) | ||
``` | ||
#### removeAccount(accountId) | ||
#### removeWallet(walletId) | ||
##### Parameters | ||
| Param | Type | Description | | ||
| --------- | ------ | -------------------- | | ||
| accountId | String | Unique ID of account | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| walletId | String | Unique ID of wallet | | ||
##### Returns | ||
`true` if removed, otherwise `false`. | ||
Removed wallet data. | ||
@@ -167,33 +176,25 @@ ##### Example | ||
```javascript | ||
const result = keystore.removeAccount('110ec58a-a0f2-4ac4-8393-c977d813b8d1') // true | ||
const removedWallet = keystore.removeWallet('110ec58a-a0f2-4ac4-8393-c977d813b8d1') // data | ||
``` | ||
#### removeAccounts([password]) | ||
#### removeWallets() | ||
##### Parameters | ||
| Param | Type | Description | | ||
| --------- | ------ | -------------------------------------------- | | ||
| password | String | Keystore password. The parameter is optional | | ||
##### Example | ||
```javascript | ||
keystore.removeAccounts('JHJ23jG^*DGHj667s') // all keystore accounts were removed | ||
keystore.removeAccounts('123') // failed, password is invalid | ||
keystore.removeAccounts() // ok, accounts were removed | ||
keystore.removeWallets() // ok, wallets were removed | ||
``` | ||
#### setAccountName(accountId, newName) | ||
#### setWalletName(walletId, newName) | ||
##### Parameters | ||
| Param | Type | Description | | ||
| --------- | ------ | -------------------- | | ||
| accountId | String | Unique ID of account | | ||
| newName | String | New account name | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| walletId | String | Unique ID of wallet | | ||
| newName | String | New wallet name | | ||
##### Returns | ||
Updated account. | ||
Updated wallet. | ||
@@ -203,14 +204,13 @@ ##### Example | ||
```javascript | ||
const updatedAccount = keystore.setAccountName('110ec58a-a0f2-4ac4-8393-c977d813b8d1', 'New account name') | ||
const updatedWallet = keystore.setWalletName('110ec58a-a0f2-4ac4-8393-c977d813b8d1', 'New wallet name') | ||
``` | ||
#### getPrivateKey(password, accountId, addressIndex) | ||
#### getPrivateKey(password, walletId) | ||
##### Parameters | ||
| Param | Type | Description | | ||
| ------------ | ------ | -------------------------------------------------------------------- | | ||
| password | String | Keystore password | | ||
| accountId | String | Unique ID of account | | ||
| addressIndex | Number | Index of address (private key) to derive from `mnemonic` (default 0) | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| password | String | Wallet password | | ||
| walletId | String | Unique ID of wallet | | ||
@@ -227,19 +227,19 @@ ##### Returns | ||
#### setDerivationPath(password, accountId, newDerivationPath) | ||
#### setDerivationPath(password, walletId, newDerivationPath) | ||
**Note: used only for `mnemonic` accounts.** | ||
**Note: used only for `mnemonic` wallets.** | ||
##### Parameters | ||
| Param | Type | Description | | ||
| ----------------- | ------ | -------------------- | | ||
| password | String | Keystore password | | ||
| accountId | String | Unique ID of account | | ||
| newDerivationPath | String | New derivation path | | ||
| Param | Type | Description | | ||
| ----------------- | ------ | ------------------- | | ||
| password | String | Wallet password | | ||
| walletId | String | Unique ID of wallet | | ||
| newDerivationPath | String | New derivation path | | ||
**Note: default derivation path that will be assigned to all new created accounts can be managed by `defaultDerivationPath` constructor parameter.** | ||
**Note: default derivation path that will be assigned to all new created wallets can be managed by `defaultDerivationPath` constructor parameter.** | ||
##### Returns | ||
Updated account. | ||
Updated wallet. | ||
@@ -249,15 +249,15 @@ ##### Example | ||
```javascript | ||
const updatedAccount = keystore.setDerivationPath('JHJ23jG^*DGHj667s', '110ec58a-a0f2-4ac4-8393-c977d813b8d1', "m/44'/61'/0'/0") | ||
const updatedWallet = keystore.setDerivationPath('JHJ23jG^*DGHj667s', '110ec58a-a0f2-4ac4-8393-c977d813b8d1', "m/44'/61'/0'/0") | ||
``` | ||
#### getMnemonic(password, accountId) | ||
#### getMnemonic(password, walletId) | ||
**Note: used only for `mnemonic` accounts.** | ||
**Note: used only for `mnemonic` wallets.** | ||
##### Parameters | ||
| Param | Type | Description | | ||
| --------- | ------ | -------------------- | | ||
| password | String | Keystore password | | ||
| accountId | String | Unique ID of account | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| password | String | Wallet password | | ||
| walletId | String | Unique ID of wallet | | ||
@@ -274,5 +274,5 @@ ##### Returns | ||
#### getAddressesFromMnemonic(accountId, iteration, limit) | ||
#### getAddressesFromMnemonic(walletId, iteration, limit) | ||
**Note: used only for `mnemonic` accounts.** | ||
**Note: used only for `mnemonic` wallets.** | ||
@@ -283,3 +283,3 @@ ##### Parameters | ||
| --------- | ------ | ------------------------------------------------------------------------ | | ||
| accountId | String | Unique ID of account | | ||
| walletId | String | Unique ID of wallet | | ||
| iteration | Number | Iteration index (aka page for pagination) to generate bunch of addresses | | ||
@@ -298,16 +298,13 @@ | limit | Number | Count of addresses to generate from mnemonic per one page / iteration | | ||
#### getAddressFromMnemonic(accountId, addressIndex) | ||
#### getAddress(walletId, addressIndex) | ||
**Note: used only for `mnemonic` accounts.** | ||
##### Parameters | ||
| Param | Type | Description | | ||
| ------------ | ------ | -------------------------------------------------------------- | | ||
| accountId | String | Unique ID of account | | ||
| addressIndex | String | Index of address to derive from `mnemonic` / `bip32XPublicKey` | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| walletId | String | Unique ID of wallet | | ||
##### Returns | ||
Derived by index address. | ||
Current address of wallet. | ||
@@ -317,8 +314,8 @@ ##### Example | ||
```javascript | ||
const address = keystore.getAddressFromMnemonic('110ec58a-a0f2-4ac4-8393-c977d813b8d1', 5) | ||
const address = keystore.getAddress('110ec58a-a0f2-4ac4-8393-c977d813b8d1') | ||
``` | ||
#### setAddressIndex(accountId, addressIndex) | ||
#### setAddressIndex(walletId, addressIndex) | ||
**Note: used only for `mnemonic` accounts.** | ||
**Note: used only for `mnemonic` wallets.** | ||
@@ -329,3 +326,3 @@ ##### Parameters | ||
| ------------ | ------ | -------------------------------------------------------------- | | ||
| accountId | String | Unique ID of account | | ||
| walletId | String | Unique ID of wallet | | ||
| addressIndex | String | Index of address to derive from `mnemonic` / `bip32XPublicKey` | | ||
@@ -335,3 +332,3 @@ | ||
Updated account. | ||
Updated wallet. | ||
@@ -341,3 +338,3 @@ ##### Example | ||
```javascript | ||
const updatedAccount = keystore.setAddress('110ec58a-a0f2-4ac4-8393-c977d813b8d1', 5) | ||
const updatedWallet = keystore.setAddress('110ec58a-a0f2-4ac4-8393-c977d813b8d1', 5) | ||
``` | ||
@@ -372,17 +369,18 @@ | ||
```javascript | ||
const backupData = '{"accounts":[{"type":"mnemonic","id":"2e820ddb-a9ce-43e1-b7ec-dbed59eec7e9",...' | ||
const backupData = '{"wallets":[{"type":"mnemonic","id":"2e820ddb-a9ce-43e1-b7ec-dbed59eec7e9",...' | ||
const keystoreDeserializedData = keystore.deserialize(backupData) | ||
``` | ||
#### getDecryptedAccounts(password) | ||
#### getDecryptedWallet(password, walletId) | ||
##### Parameters | ||
| Param | Type | Description | | ||
| -------- | ------ | ----------------- | | ||
| password | String | Keystore password | | ||
| Param | Type | Description | | ||
| -------- | ------ | ------------------- | | ||
| password | String | Wallet password | | ||
| walletId | String | Unique ID of wallet | | ||
#### Returns | ||
Accounts with decrypted data. | ||
Wallet with decrypted data. | ||
@@ -392,13 +390,14 @@ ##### Example | ||
```javascript | ||
const decryptedAccounts = keystore.getDecryptedAccounts('JHJ23jG^*DGHj667s') | ||
const decryptedWallet = keystore.getDecryptedWallets('JHJ23jG^*DGHj667s', '110ec58a-a0f2-4ac4-8393-c977d813b8d1') | ||
``` | ||
#### setPassword(password, newPassword) | ||
#### setPassword(password, newPassword, walletId) | ||
##### Parameters | ||
| Param | Type | Description | | ||
| ------------ | ------ | ------------------------ | | ||
| password | String | Keystore password | | ||
| newPassword | String | New keystore password | | ||
| Param | Type | Description | | ||
| ----------- | ------ | --------------------- | | ||
| password | String | Wallet password | | ||
| newPassword | String | New keystore password | | ||
| walletId | String | Unique ID of wallet | | ||
@@ -408,3 +407,3 @@ ##### Example | ||
```javascript | ||
keystore.setPassword('JHJ23jG^*DGHj667s', 'Tw5E^g7djfd(29j') | ||
keystore.setPassword('JHJ23jG^*DGHj667s', 'Tw5E^g7djfd(29j', '110ec58a-a0f2-4ac4-8393-c977d813b8d1') | ||
``` | ||
@@ -466,3 +465,3 @@ | ||
#### isValidAddress(address) | ||
#### isAddressValid(address) | ||
@@ -480,6 +479,6 @@ | Param | Type | Description | | ||
```javascript | ||
const isValid = Keystore.isValidAddress('0x8a02a99ee7a801da6996a2dacc406ffa5190dc9c') | ||
const isValid = Keystore.isAddressValid('0x8a02a99ee7a801da6996a2dacc406ffa5190dc9c') | ||
``` | ||
#### isValidPrivateKey(privateKey) | ||
#### isPrivateKeyValid(privateKey) | ||
@@ -498,3 +497,3 @@ | Param | Type | Description | | ||
const pk = '0xa7fcb4efc392d2c8983cbfe64063f994f85120e60843407af95907d905d0dc9f' | ||
const isValid = Keystore.isValidPrivateKey(pk) | ||
const isValid = Keystore.isPrivateKeyValid(pk) | ||
``` | ||
@@ -522,3 +521,3 @@ | ||
| ------------------------ | ------ | ------- | -------------------------- | | ||
| password | String | | Keystore password | | ||
| password | String | | Wallet password | | ||
| passwordConfig | Object | {} | Password options container | | ||
@@ -525,0 +524,0 @@ | passwordConfig.minLength | Number | 10 | Min length for password | |
@@ -10,7 +10,7 @@ const should = require('should') | ||
const bip32XPublicKey = 'xpub6DZVENYSZsMW1D48vLG924qPaxz83TZc43tK7zMbCdFcv1La9pqe6pBiuxdzDNjufXRW42CfJEK8indRdhfDoWvYfZDZS1xjkZrQB5iYtHy' | ||
const accountName = 'mnemonic read only account' | ||
const accountIdLength = 36 | ||
const name = 'mnemonic read only wallet' | ||
const walletIdLength = 36 | ||
const currentKeystoreVersion = packageData.version | ||
let accountId | ||
let walletId | ||
let serializedKeystoreData | ||
@@ -21,6 +21,6 @@ | ||
it('createAccount() should create example account', function(done) { | ||
accountId = keystore.createAccount({ | ||
it('createWallet() should create example wallet', function(done) { | ||
walletId = keystore.createWallet({ | ||
name, | ||
password, | ||
accountName, | ||
bip32XPublicKey, | ||
@@ -31,4 +31,4 @@ type: 'mnemonic', | ||
accountId.should.be.a.String() | ||
accountId.length.should.be.equal(accountIdLength) | ||
walletId.should.be.a.String() | ||
walletId.length.should.be.equal(walletIdLength) | ||
@@ -51,5 +51,5 @@ done() | ||
deserializedKeystoreData.should.be.an.Object() | ||
deserializedKeystoreData.accounts.should.be.an.Array() | ||
deserializedKeystoreData.accounts[0].should.be.an.Object() | ||
deserializedKeystoreData.accounts[0].id.should.be.equal(accountId) | ||
deserializedKeystoreData.wallets.should.be.an.Array() | ||
deserializedKeystoreData.wallets[0].should.be.an.Object() | ||
deserializedKeystoreData.wallets[0].id.should.be.equal(walletId) | ||
deserializedKeystoreData.version.should.be.equal(currentKeystoreVersion) | ||
@@ -56,0 +56,0 @@ |
const should = require('should') | ||
const Keystore = require('../index') | ||
const validMnemonic = 'come average primary sunny profit eager toy pulp struggle hazard tourist round' | ||
const validMnemonic = 'come average primary sunny profit eager toy pulp struggle hazard tourist ' + | ||
'round' | ||
const invalidMnemonic = `${validMnemonic} some other words` | ||
@@ -37,4 +39,8 @@ | ||
const mnemonicWithEntropy = Keystore.generateMnemonic(mnemonicEntropy) | ||
const mnemonicWithBufferLength = Keystore.generateMnemonic(mnemonicEntropy, mnemonicBufferLength) | ||
const mnemonicWithBufferLength = Keystore.generateMnemonic( | ||
mnemonicEntropy, | ||
mnemonicBufferLength, | ||
) | ||
const words = mnemonic.toString().split(' ') | ||
@@ -87,8 +93,8 @@ const wordsWithEntropy = mnemonicWithEntropy.toString().split(' ') | ||
describe('isValidAddress', function() { | ||
describe('isAddressValid', function() { | ||
it('should return true when address is correct', function(done) { | ||
const isAddressValid1 = Keystore.isValidAddress(validAddress) | ||
const isAddressValid2 = Keystore.isValidAddress(invalidChecksumAddress) | ||
const isAddressValid3 = Keystore.isValidAddress(invalidAddress1) | ||
const isAddressValid4 = Keystore.isValidAddress(invalidAddress2) | ||
const isAddressValid1 = Keystore.isAddressValid(validAddress) | ||
const isAddressValid2 = Keystore.isAddressValid(invalidChecksumAddress) | ||
const isAddressValid3 = Keystore.isAddressValid(invalidAddress1) | ||
const isAddressValid4 = Keystore.isAddressValid(invalidAddress2) | ||
@@ -111,7 +117,7 @@ isAddressValid1.should.be.a.Boolean() | ||
describe('isValidPrivateKey', function() { | ||
describe('isPrivateKeyValid', function() { | ||
it('should return true when private key is correct', function(done) { | ||
const isPrivateKeyValid1 = Keystore.isValidPrivateKey(validPrivateKey) | ||
const isPrivateKeyValid2 = Keystore.isValidPrivateKey(invalidPrivateKey1) | ||
const isPrivateKeyValid3 = Keystore.isValidPrivateKey(invalidPrivateKey2) | ||
const isPrivateKeyValid1 = Keystore.isPrivateKeyValid(validPrivateKey) | ||
const isPrivateKeyValid2 = Keystore.isPrivateKeyValid(invalidPrivateKey1) | ||
const isPrivateKeyValid3 = Keystore.isPrivateKeyValid(invalidPrivateKey2) | ||
@@ -150,4 +156,8 @@ isPrivateKeyValid1.should.be.a.Boolean() | ||
const testInvalidPasswordResult = Keystore.testPassword(invalidPassword) | ||
const testPasswordResultWithCustomConfig = Keystore.testPassword(validPassword, customPasswordConfig) | ||
const testPasswordResultWithCustomConfig = Keystore.testPassword( | ||
validPassword, | ||
customPasswordConfig, | ||
) | ||
testValidPasswordResult.should.be.an.Object() | ||
@@ -154,0 +164,0 @@ testValidPasswordResult.failedTests.should.be.an.Array() |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
21
5%1662
0.67%81788
-2.02%13
18.18%514
-0.19%1
Infinity%+ Added
+ Added
- Removed
- Removed