diff --git a/js/controllers/import.js b/js/controllers/import.js index 9b6de0a91..49c4d9c58 100644 --- a/js/controllers/import.js +++ b/js/controllers/import.js @@ -30,7 +30,7 @@ angular.module('copayApp.controllers').controller('ImportController', // try to import encrypted wallet with passphrase try { - w = identity.import(encryptedObj, passphrase, skipFields); + w = identity.fromEncryptedObj(encryptedObj, passphrase, skipFields); } catch (e) { errMsg = e.message; } diff --git a/js/models/Identity.js b/js/models/Identity.js index a65abbcaf..d496918ae 100644 --- a/js/models/Identity.js +++ b/js/models/Identity.js @@ -125,20 +125,6 @@ Identity.prototype.fromEncryptedObj = function(base64, passphrase, skipFields) { return this.fromObj(walletObj, skipFields); }; -/** - * @TODO: import is a reserved keyword! DONT USE IT - * @TODO: this is essentialy the same method as {@link Identity#fromEncryptedObj}! - * @desc Imports a wallet from an encrypted base64 object - * @param {string} base64 - the base64 encoded object - * @param {string} passphrase - passphrase to decrypt it - * @param {string[]} skipFields - fields to ignore when importing - * @return {Wallet} - */ -Identity.prototype.import = function(base64, passphrase, skipFields) { - var self = this; - return self.fromEncryptedObj(base64, passphrase, skipFields); -}; - Identity.prototype.migrateWallet = function(walletId, passphrase, cb) { var self = this; @@ -173,7 +159,7 @@ Identity.prototype.read = function(walletId, skipFields, cb) { err; var obj = {}; - this.storage.readWallet(walletId, function(err, ret) { + this.storage.getFirst('wallet::' + walletId, function(err, ret) { if (err) return cb(err); _.each(Wallet.PERSISTED_PROPERTIES, function(p) { @@ -513,4 +499,5 @@ Identity.prototype.joinCreateSession = function(opts, cb) { }); }; + module.exports = Identity; diff --git a/js/models/WalletStorage.js b/js/models/WalletStorage.js deleted file mode 100644 index aa26ecbfb..000000000 --- a/js/models/WalletStorage.js +++ /dev/null @@ -1,358 +0,0 @@ -'use strict'; -var preconditions = require('preconditions').singleton(); -var CryptoJS = require('node-cryptojs-aes').CryptoJS; -var bitcore = require('bitcore'); -var preconditions = require('preconditions').instance(); -var _ = require('underscore'); -var CACHE_DURATION = 1000 * 60 * 5; -var id = 0; - -function Storage(opts) { - opts = opts || {}; - - this.wListCache = {}; - this.__uniqueid = ++id; - if (opts.password) - this.setPassphrase(opts.password); - - try { - this.storage = opts.storage || localStorage; - this.sessionStorage = opts.sessionStorage || sessionStorage; - } catch (e) { - console.log('Error in storage:', e); //TODO - }; - - preconditions.checkState(this.storage, 'No storage defined'); - preconditions.checkState(this.sessionStorage, 'No sessionStorage defined'); -} - -var pps = {}; -Storage.prototype._getPassphrase = function() { - - if (!pps[this.__uniqueid]) - throw new Error('NOPASSPHRASE: No passphrase set'); - - return pps[this.__uniqueid]; -} - -Storage.prototype.setPassphrase = function(password) { - pps[this.__uniqueid] = password; -} - -Storage.prototype._encrypt = function(string) { - var encrypted = CryptoJS.AES.encrypt(string, this._getPassphrase()); - var encryptedBase64 = encrypted.toString(); - return encryptedBase64; -}; - -Storage.prototype._decrypt = function(base64) { - var decryptedStr = null; - try { - var decrypted = CryptoJS.AES.decrypt(base64, this._getPassphrase()); - if (decrypted) - decryptedStr = decrypted.toString(CryptoJS.enc.Utf8); - } catch (e) { - // Error while decrypting - return null; - } - return decryptedStr; -}; - - -Storage.prototype._read = function(k, cb) { - preconditions.checkArgument(cb); - - var self = this; - this.storage.getItem(k, function(ret) { - if (!ret) return cb(null); - var ret = self._decrypt(ret); - if (!ret) return cb(null); - - ret = ret.toString(CryptoJS.enc.Utf8); - ret = JSON.parse(ret); - return cb(ret); - }); -}; - -Storage.prototype._write = function(k, v, cb) { - preconditions.checkArgument(cb); - - v = JSON.stringify(v); - v = this._encrypt(v); - this.storage.setItem(k, v, cb); -}; - -// get value by key -Storage.prototype.getGlobal = function(k, cb) { - preconditions.checkArgument(cb); - - this.storage.getItem(k, function(item) { - cb(item == 'undefined' ? undefined : item); - }); -}; - -// set value for key -Storage.prototype.setGlobal = function(k, v, cb) { - preconditions.checkArgument(cb); - this.storage.setItem(k, typeof v === 'object' ? JSON.stringify(v) : v, cb); -}; - -// remove value for key -Storage.prototype.removeGlobal = function(k, cb) { - preconditions.checkArgument(cb); - this.storage.removeItem(k, cb); -}; - -Storage.prototype.getSessionId = function(cb) { - preconditions.checkArgument(cb); - var self = this; - - self.sessionStorage.getItem('sessionId', function(sessionId) { - if (sessionId) - return cb(sessionId); - - sessionId = bitcore.SecureRandom.getRandomBuffer(8).toString('hex'); - self.sessionStorage.setItem('sessionId', sessionId, function() { - return cb(sessionId); - }); - }); -}; - -Storage.prototype.setSessionId = function(sessionId, cb) { - this.sessionStorage.setItem('sessionId', sessionId, cb); -}; - -Storage.prototype._readHelper = function(walletId, k, cb) { - var wk = this._key(walletId, k); - this._read(wk, function(v) { - return cb(v, k); - }); -}; - -Storage.prototype.readWallet_Old = function(walletId, cb) { - var self = this; - this.storage.allKeys(function(allKeys) { - var obj = {}; - var keys = _.filter(allKeys, function(k) { - if (k.indexOf(walletId + '::') === 0) return true; - }); - if (keys.length === 0) return cb(new Error('Wallet ' + walletId + ' not found')); - var count = keys.length; - _.each(keys, function(k) { - self._read(k, function(v) { - obj[k.split('::')[1]] = v; - if (--count === 0) return cb(null, obj); - }) - }); - }); -}; - -Storage.prototype.readWallet = function(walletId, cb) { - var self = this; - this.storage.allKeys(function(allKeys) { - var keys = _.filter(allKeys, function(k) { - if ((k === 'wallet::' + walletId) || k.indexOf('wallet::' + walletId) === 0) return true; - }); - if (keys.length === 0) return cb(new Error('Wallet ' + walletId + ' not found')); - self._read(keys[0], function(v) { - if (_.isNull(v)) return cb(new Error('Could not decrypt wallet data')); - return cb(null, v); - }) - }); -}; - -Storage.prototype.getMany = function(walletId, keys, cb) { - preconditions.checkArgument(cb); - - var self = this; - var ret = {}; - - var l = keys.length, - i = 0; - - for (var ii in keys) { - this._readHelper(walletId, keys[ii], function(v, k) { - ret[k] = v; - if (++i == l) { - return cb(ret); - } - }); - } -}; - -Storage.prototype._getWalletIds = function(cb) { - preconditions.checkArgument(cb); - var walletIds = []; - var uniq = {}; - this.storage.allKeys(function(keys) { - for (var ii in keys) { - var key = keys[ii]; - var split = key.split('::'); - if (split.length == 2) { - var walletId = split[0]; - - if (!walletId || walletId === 'nameFor' || walletId === 'lock' || walletId === 'wallet') - continue; - - if (typeof uniq[walletId] === 'undefined') { - walletIds.push(walletId); - uniq[walletId] = 1; - } - } - } - return cb(walletIds); - }); -}; - -Storage.prototype.getWallets_Old = function(cb) { - preconditions.checkArgument(cb); - - if (this.wListCache.ts > Date.now()) - return cb(this.wListCache.data) - - var wallets = []; - var self = this; - - this._getWalletIds(function(ids) { - var l = ids.length, - i = 0; - if (!l) - return cb([]); - - _.each(ids, function(id) { - self.getGlobal('nameFor::' + id, function(name) { - wallets.push({ - id: id, - name: name, - }); - if (++i == l) { - self.wListCache.data = wallets; - self.wListCache.ts = Date.now() + CACHE_DURATION; - return cb(wallets); - } - }); - }); - }); -}; - -Storage.prototype.getWallets2 = function(cb) { - var self = this; - var re = /wallet::([^_]+)(_?(.*))/; - - this.storage.allKeys(function(allKeys) { - var wallets = _.compact(_.map(allKeys, function(key) { - if (key.indexOf('wallet::') !== 0) - return null; - var match = key.match(re); - if (match.length != 4) - return null; - return { - id: match[1], - name: match[3] ? match[3] : undefined, - }; - })); - - return cb(wallets); - }); -}; - -Storage.prototype.getWallets = function(cb) { - var self = this; - self.getWallets2(function(wallets) { - self.getWallets_Old(function(wallets2) { - var ids = _.pluck(wallets, 'id'); - _.each(wallets2, function(w) { - if (!_.contains(ids, w.id)) - wallets.push(w); - }); - return cb(wallets); - }); - }) -}; - - -Storage.prototype.deleteWallet_Old = function(walletId, cb) { - preconditions.checkArgument(walletId); - preconditions.checkArgument(cb); - var err; - var self = this; - - var toDelete = {}; - - this.storage.allKeys(function(allKeys) { - for (var ii in allKeys) { - var key = allKeys[ii]; - var split = key.split('::'); - if (split.length == 2 && split[0] === walletId) { - toDelete[key] = 1; - }; - } - var l = Object.keys(toDelete).length, - j = 0; - if (!l) - return cb(new Error('WNOTFOUND: Wallet not found')); - - toDelete['nameFor::' + walletId] = 1; - l++; - - for (var i in toDelete) { - self.removeGlobal(i, function() { - if (++j == l) - return cb(err); - }); - - } - }); -}; - -Storage.prototype.deleteWallet = function(walletId, cb) { - preconditions.checkArgument(walletId); - preconditions.checkArgument(cb); - - var self = this; - this.getWallets2(function(wallets) { - var w = _.findWhere(wallets, { - id: walletId - }); - if (!w) - return cb(new Error('WNOTFOUND: Wallet not found')); - self.removeGlobal('wallet::' + walletId + (w.name ? '_' + w.name : ''), function() { - return cb(); - }); - }); -}; - -Storage.prototype.setLastOpened = function(walletId, cb) { - this.setGlobal('lastOpened', walletId, cb); -}; - -Storage.prototype.getLastOpened = function(cb) { - this.getGlobal('lastOpened', cb); -}; - -Storage.prototype.setFromObj = function(key, obj, cb) { - preconditions.checkArgument(key); - preconditions.checkArgument(cb); - this._write(key, obj, function() { - return cb(); - }); -}; - - -// remove all values -Storage.prototype.clearAll = function(cb) { - this.storage.clear(cb); -}; - -Storage.prototype.import = function(base64) { - var decryptedStr = this._decrypt(base64); - return JSON.parse(decryptedStr); -}; - -Storage.prototype.export = function(obj) { - var string = JSON.stringify(obj); - return this._encrypt(string); -}; - - -module.exports = Storage; diff --git a/test/Storage.js b/test/Storage.js index 17a63287f..dafda888d 100644 --- a/test/Storage.js +++ b/test/Storage.js @@ -81,11 +81,11 @@ describe('Storage model', function() { }); }); - describe('#_getWalletIds', function() { + describe('#_getWalletIds_Old', function() { it('should get wallet ids', function(done) { s._write('1::hola', 'juan', function() { s._write('2::hola', 'juan', function() { - s._getWalletIds(function(v) { + s._getWalletIds_Old(function(v) { v.should.deep.equal(['1', '2']); done(); }); @@ -118,13 +118,13 @@ describe('Storage model', function() { }); } - describe('#getWallets_Old', function() { + describe('#getWallets1_Old', function() { it('should retrieve wallets from storage', function(done) { s._write('1::hola', 'juan', function() { s._write('2::hola', 'juan', function() { s.setGlobal('nameFor::1', 'hola', function() { - s.getWallets_Old(function(ws) { + s.getWallets1_Old(function(ws) { ws[0].should.deep.equal({ id: '1', name: 'hola', @@ -151,7 +151,7 @@ describe('Storage model', function() { }, 1); }; - s.getWallets_Old(function(ws) { + s.getWallets1_Old(function(ws) { ws[0].should.deep.equal({ id: '1', name: 'hola', @@ -168,7 +168,7 @@ describe('Storage model', function() { }); }); - describe('#getWallets2', function() { + describe('#getWallets2_Old', function() { it('should retrieve wallets from storage', function(done) { var w1 = { name: 'juan', @@ -181,7 +181,7 @@ describe('Storage model', function() { }; s.setFromObj('wallet::1_wallet1', w1, function() { s.setFromObj('wallet::2', w2, function() { - s.getWallets2(function(ws) { + s.getWallets2_Old(function(ws) { ws[0].should.deep.equal({ id: '1', name: 'wallet1', @@ -215,7 +215,7 @@ describe('Storage model', function() { s._write('3::name', 'matias', function() { s._write('1::name', 'juan', function() { s.setGlobal('nameFor::3', 'wallet3', function() { - s.getWallets(function(ws) { + s.getWallets_Old(function(ws) { ws.length.should.equal(3); ws[0].should.deep.equal({ id: '1', @@ -307,7 +307,7 @@ describe('Storage model', function() { s.setFromObj('wallet::2', w2, function() { s.deleteWallet('1', function(err) { should.not.exist(err); - s.getWallets2(function(ws) { + s.getWallets2_Old(function(ws) { ws.length.should.equal(1); ws[0].id.should.equal('2'); done(); diff --git a/test/test.Identity.js b/test/test.Identity.js index 914a8e0c8..dcb3e5272 100644 --- a/test/test.Identity.js +++ b/test/test.Identity.js @@ -162,9 +162,6 @@ describe('Identity model', function() { wf.storage.import.calledOnce.should.be.true; wf.fromObj.calledWith('walletObj').should.be.true; }); - }); - - describe('#import', function() { it('should import and update indexes', function() { var wallet = { id: "fake wallet", @@ -174,14 +171,14 @@ describe('Identity model', function() { }; wf.fromEncryptedObj = sinon.stub().returns(wallet); - var w = wf.import("encrypted", "password"); + var w = wf.fromEncryptedObj("encrypted", "password"); should.exist(w); wallet.should.equal(w); }); it('should import with a wrong password', function() { wf.fromEncryptedObj = sinon.stub().returns(null); - var w = wf.import("encrypted", "passwordasdfasdf"); + var w = wf.fromEncryptedObj("encrypted", "passwordasdfasdf"); should.not.exist(w); }); }); @@ -272,7 +269,7 @@ describe('Identity model', function() { describe('#read', function() { it('should fail to read unexisting wallet', function(done) { - wf.storage.readWallet = sinon.stub().yields(null, {}); + wf.storage.getFirst = sinon.stub().yields(null, {}); wf.read('id', [], function(err, w) { should.not.exist(w); @@ -284,7 +281,7 @@ describe('Identity model', function() { }); }); it('should fail to read broken wallet', function(done) { - wf.storage.readWallet = sinon.stub().yields(null, { + wf.storage.getFirst = sinon.stub().yields(null, { 'opts': 1 }); wf.read('id', [], function(err, w) { @@ -298,7 +295,7 @@ describe('Identity model', function() { }); it('should read existing wallet', function(done) { var wf = new Identity(config, '0.0.1'); - wf.storage.readWallet = sinon.stub().yields(null, { + wf.storage.getFirst = sinon.stub().yields(null, { 'opts': 1 }); wf.fromObj = sinon.stub().returns('ok'); @@ -568,7 +565,7 @@ describe('Identity model', function() { wf.storage.setPassphrase = sinon.spy(); wf.storage.import.withArgs('dummy').returns(JSON.parse(legacy1)); - var w = wf.import('dummy', 'xxx'); + var w = wf.fromEncryptedObj('dummy', 'xxx'); should.exist(w); wf.storage.setPassphrase.calledOnce.should.equal(true); wf.storage.setPassphrase.getCall(0).args[0].should.equal('xxx');