diff --git a/lib/keystore.js b/lib/keystore.js index a8a813f6..d36d29f1 100644 --- a/lib/keystore.js +++ b/lib/keystore.js @@ -427,6 +427,114 @@ KeyStore.prototype.getAddresses = function (hdPathString) { }; +KeyStore.prototype.getAddressWithEncKey = function (address, hdPathString) { + address = strip0x(address); + + return { + address: address, + encPrivKey: this.ksData[hdPathString].encPrivKeys[address] + } +} + +KeyStore.prototype.getAddressWithEncKeys = function (hdPathString) { + if (hdPathString === undefined) { + hdPathString = this.defaultHdPathString; + } + + this._checkHdPathPurpose(hdPathString, 'sign'); + + let addresses = this.ksData[hdPathString].addresses; + + return addresses.map(function(addr) { + return this.getAddressWithEncKey(addr, hdPathString); + }.bind(this)); +} + +/** + * Serialize a address + * + * Schema: + * { + * "address": "
", + * "encPrivKey": { + * "key": "", + * "nounce": "" + * } + * } + */ +KeyStore.prototype.dumpAddress = function (address, hdPathString) { + + if (hdPathString === undefined) { + hdPathString = this.defaultHdPathString; + } + + this._checkHdPathPurpose(hdPathString, 'sign'); + + address = strip0x(address); + this._checkAddressExists(address, hdPathString); + + var jsonAddr = this.getAddressWithEncKey(address, hdPathString) + + return JSON.stringify(jsonAddr); +} + +KeyStore.prototype.loadAddress = function (serAddr, hdPathString) { + + var jsonAddr = JSON.parse(serAddr); + var addr = jsonAddr.address; + + if (hdPathString === undefined) { + hdPathString = this.defaultHdPathString; + } + + this._validateAddressSerSchema(jsonAddr); + this._checkHdPathPurpose(hdPathString, 'sign'); + + try { + // already exists + this._checkAddressExists(addr, hdPathString); + console.warn('Address ' + addr + ' already exists in keystore at ' + hdPathString); + + return ; + + } catch(err) { + // load new address + this.ksData[hdPathString].encPrivKeys[addr] = jsonAddr.encPrivKey; + this.ksData[hdPathString].addresses.push(addr); + } +} + +KeyStore.prototype._validateAddressSerSchema = function (jsonAddr) { + if (typeof jsonAddr === 'string') { + jsonAddr = JSON.parse(jsonAddr); + } + + if (!jsonAddr.address) { + throw new Error('"address" is missing from the address serialization'); + } + + if (!jsonAddr.encPrivKey) { + throw new Error('"key" is missing from the address serialization'); + } + + return true; +} + +KeyStore.prototype._checkHdPathPurpose = function (hdPathString, purpose) { + if (this.ksData[hdPathString].info.purpose !== purpose) { + throw new Error('Addresses not defined when purpose is not "' + purpose + '"'); + } +} + +KeyStore.prototype._checkAddressExists = function (address, hdPathString) { + address = strip0x(address); + if (this.ksData[hdPathString].encPrivKeys[address] == undefined) { + throw new Error('Address not found in KeyStore'); + } + + return true; +} + KeyStore.prototype.getSeed = function (pwDerivedKey) { if(!this.isDerivedKeyCorrect(pwDerivedKey)) { @@ -458,6 +566,15 @@ KeyStore.prototype.exportPrivateKey = function (address, pwDerivedKey, hdPathStr return privKey; }; +KeyStore.prototype.resetAddress = function(hdPathString) { + if (hdPathString === undefined) { + hdPathString = this.defaultHdPathString; + } + + this.ksData[hdPathString].encPrivKeys = []; + this.ksData[hdPathString].addresses = []; +}; + KeyStore.prototype.generateNewAddress = function(pwDerivedKey, n, hdPathString) { if(!this.isDerivedKeyCorrect(pwDerivedKey)) { diff --git a/test/keystore.js b/test/keystore.js index 4163460b..cfe96be4 100644 --- a/test/keystore.js +++ b/test/keystore.js @@ -280,6 +280,62 @@ describe("Keystore", function() { }); + describe("dumpAddress", function() { + + it("returns a valid dump", function() { + var validKS = fixtures.valid[0]; + let pwDerivedKey = Uint8Array.from(validKS.pwDerivedKey); + + var ks = new keyStore(validKS.mnSeed, pwDerivedKey) + ks.generateNewAddress(pwDerivedKey, 5); + + var addr = ks.getAddresses(); + addr = addr[0]; + + var ser = ks.dumpAddress(addr); + var jsonAddr = JSON.parse(ser); + expect(jsonAddr.address).to.eql(addr); + expect(jsonAddr.encPrivKey).to.eql(ks.ksData[ks.defaultHdPathString].encPrivKeys[addr]); + }); + + it('check if the address exists', function() { + var validKS = fixtures.valid[0]; + var pwDerivedKey = Uint8Array.from(validKS.pwDerivedKey); + + var ks = new keyStore(validKS.mnSeed, pwDerivedKey) + + expect(function() { + ks.dumpAddress('0x0'); + }).to.throw(); + }); + }); + + describe('loadAddress', function() { + it('loads the addresss dump', function(done) { + var validKS = fixtures.valid[0]; + var pwDerivedKey = Uint8Array.from(validKS.pwDerivedKey); + + var ks = new keyStore(validKS.mnSeed, pwDerivedKey) + + var ser = JSON.stringify({ + address: '12345', + encPrivKey: { + key: '12345=privKey', + nonce: '12345=nonce' + } + }); + + ks.loadAddress(ser); + + ks.hasAddress('12345', function(err, has) { + expect(err).to.be.null; + expect(has).to.be.true; + done(); + }); + + }); + }); + describe("Seed functions", function() { it('returns the unencrypted seed', function(done) { var ks = new keyStore(fixtures.valid[0].mnSeed, Uint8Array.from(fixtures.valid[0].pwDerivedKey))