diff --git a/README.md b/README.md index a644024ca..27c28899c 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,12 @@ Library used by [Hathor Wallet](https://github.com/HathorNetwork/hathor-wallet). ## Install -`npm install @hathor/wallet-lib` \ No newline at end of file +`npm install @hathor/wallet-lib` + +## Setting storage + +This lib requires a storage to be set so it can persist data. Take a look at `src/storage.js` for the methods this storage object should implement. +``` +const hathorLib = require('@hathor/wallet-lib'); +hathorLib.storage.setStorage(storageFactory); +``` diff --git a/__tests__/address.test.js b/__tests__/address.test.js index 678b3420d..595f0d5c3 100644 --- a/__tests__/address.test.js +++ b/__tests__/address.test.js @@ -9,6 +9,8 @@ import wallet from '../src/wallet'; import { GAP_LIMIT } from '../src/constants'; import WebSocketHandler from '../src/WebSocketHandler'; +const storage = require('../src/storage').default; + beforeEach(() => { WebSocketHandler.started = false; wallet.cleanLocalStorage(); @@ -18,107 +20,106 @@ test('Update address', () => { let address1 = '1zEETJWa3U6fBm8eUXbG7ddj6k4KjoR7j'; let index1 = 10; wallet.updateAddress(address1, index1, false); - expect(localStorage.getItem('wallet:address')).toBe(address1); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(index1); + expect(storage.getItem('wallet:address')).toBe(address1); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(index1); let address2 = '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'; let index2 = 20; wallet.updateAddress(address2, index2, false); - expect(localStorage.getItem('wallet:address')).toBe(address2); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(index2); + expect(storage.getItem('wallet:address')).toBe(address2); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(index2); }) test('Has a new address already generated', () => { - localStorage.setItem('wallet:lastGeneratedIndex', 10); - localStorage.setItem('wallet:lastSharedIndex', 9); + storage.setItem('wallet:lastGeneratedIndex', 10); + storage.setItem('wallet:lastSharedIndex', 9); expect(wallet.hasNewAddress()).toBe(true); - localStorage.setItem('wallet:lastSharedIndex', 10); + storage.setItem('wallet:lastSharedIndex', 10); expect(wallet.hasNewAddress()).toBe(false); - localStorage.setItem('wallet:lastSharedIndex', 11); + storage.setItem('wallet:lastSharedIndex', 11); expect(wallet.hasNewAddress()).toBe(false); }); test('Get next address already generated', () => { - localStorage.setItem('wallet:lastSharedIndex', 9); - localStorage.setItem('wallet:data', JSON.stringify({keys: {'1zEETJWa3U6fBm8eUXbG7ddj6k4KjoR7j': {index: 9}, '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {index: 10}}})); + storage.setItem('wallet:lastSharedIndex', 9); + storage.setItem('wallet:data', {keys: {'1zEETJWa3U6fBm8eUXbG7ddj6k4KjoR7j': {index: 9}, '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {index: 10}}}); wallet.getNextAddress() - expect(localStorage.getItem('wallet:address')).toBe('171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(10); + expect(storage.getItem('wallet:address')).toBe('171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(10); }); test('Can generate new address', () => { - localStorage.setItem('wallet:lastUsedIndex', 2); - localStorage.setItem('wallet:lastGeneratedIndex', 30); + storage.setItem('wallet:lastUsedIndex', 2); + storage.setItem('wallet:lastGeneratedIndex', 30); expect(wallet.canGenerateNewAddress()).toBe(false); - localStorage.setItem('wallet:lastUsedIndex', 10); + storage.setItem('wallet:lastUsedIndex', 10); expect(wallet.canGenerateNewAddress()).toBe(false); - localStorage.setItem('wallet:lastUsedIndex', 11); + storage.setItem('wallet:lastUsedIndex', 11); expect(wallet.canGenerateNewAddress()).toBe(true); - localStorage.setItem('wallet:lastUsedIndex', 17); + storage.setItem('wallet:lastUsedIndex', 17); expect(wallet.canGenerateNewAddress()).toBe(true); }); -test('Generate new address', () => { +test('Generate new address', async () => { WebSocketHandler.started = true; let words = 'purse orchard camera cloud piece joke hospital mechanic timber horror shoulder rebuild you decrease garlic derive rebuild random naive elbow depart okay parrot cliff'; let pin = '123456'; - wallet.executeGenerateWallet(words, '', pin, 'password', true); - - let data = JSON.parse(localStorage.getItem('wallet:data')); - expect(Object.keys(data.keys).length).toBe(GAP_LIMIT); - expect(parseInt(localStorage.getItem('wallet:lastGeneratedIndex'), 10)).toBe(GAP_LIMIT - 1); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(0); + await wallet.executeGenerateWallet(words, '', pin, 'password', true); + let data = storage.getItem('wallet:data'); + expect(Object.keys(data.keys).length).toBe(GAP_LIMIT + 1); + expect(parseInt(storage.getItem('wallet:lastGeneratedIndex'), 10)).toBe(GAP_LIMIT); + expect(storage.store.getItem('wallet:lastSharedIndex')).toBe(0); for (let address in data.keys) { if (data.keys[address].index === 0) { - expect(localStorage.getItem('wallet:address')).toBe(address); + expect(storage.getItem('wallet:address')).toBe(address); break; } } // Set last shared index as last generated also - localStorage.setItem('wallet:lastSharedIndex', GAP_LIMIT - 1); + storage.setItem('wallet:lastSharedIndex', GAP_LIMIT - 1); wallet.generateNewAddress(); - let newData = JSON.parse(localStorage.getItem('wallet:data')); + let newData = storage.getItem('wallet:data'); expect(Object.keys(newData.keys).length).toBe(GAP_LIMIT + 1); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(GAP_LIMIT); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(GAP_LIMIT); for (let address in newData.keys) { if (newData.keys[address].index === GAP_LIMIT) { - expect(localStorage.getItem('wallet:address')).toBe(address); + expect(storage.getItem('wallet:address')).toBe(address); break; } } }); -test('Last used index', () => { +test('Last used index', async () => { WebSocketHandler.started = true; let words = 'purse orchard camera cloud piece joke hospital mechanic timber horror shoulder rebuild you decrease garlic derive rebuild random naive elbow depart okay parrot cliff'; let pin = '123456'; - wallet.executeGenerateWallet(words, '', pin, 'password', true); + await wallet.executeGenerateWallet(words, '', pin, 'password', true); - let data = JSON.parse(localStorage.getItem('wallet:data')); + let data = storage.getItem('wallet:data'); for (let address in data.keys) { if (data.keys[address].index === 12) { wallet.setLastUsedIndex(address); - expect(parseInt(localStorage.getItem('wallet:lastUsedIndex'), 10)).toBe(12); - expect(localStorage.getItem('wallet:lastUsedAddress')).toBe(address); + expect(parseInt(storage.getItem('wallet:lastUsedIndex'), 10)).toBe(12); + expect(storage.getItem('wallet:lastUsedAddress')).toBe(address); break; } } }); -test('Subscribe address to websocket', (done) => { +test('Subscribe address to websocket', done => { let address = '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'; WebSocketHandler.started = true; WebSocketHandler.on('subscribe_success', (wsData) => { @@ -147,9 +148,9 @@ test('Subscribe all addresses to websocket', (done) => { for (let address of addresses) { keys[address] = {}; } - localStorage.setItem('wallet:data', JSON.stringify({keys: keys})); + storage.setItem('wallet:data', {keys: keys}); WebSocketHandler.started = true; - WebSocketHandler.on('subscribe_success', (wsData) => { + WebSocketHandler.on('subscribe_success', function handler(wsData) { let foundIndex = -1; for (let [idx, address] of addresses.entries()) { if (address === wsData.address) { @@ -164,6 +165,7 @@ test('Subscribe all addresses to websocket', (done) => { if (addresses.length === 0) { // If got here test was successful, so ending it + WebSocketHandler.removeListener('subscribe_success', handler); done(); } }); diff --git a/__tests__/encryption.test.js b/__tests__/encryption.test.js index b5d04d29d..79a250705 100644 --- a/__tests__/encryption.test.js +++ b/__tests__/encryption.test.js @@ -7,6 +7,8 @@ import wallet from '../src/wallet'; +const storage = require('../src/storage').default; + test('Private key encryption/decryption', () => { const pin = '123456'; const password = 'password'; @@ -20,7 +22,7 @@ test('Private key encryption/decryption', () => { expect(wallet.isPasswordCorrect(password)).toBeTruthy(); expect(wallet.isPasswordCorrect(pin)).toBeFalsy(); - let accessData = JSON.parse(localStorage.getItem('wallet:accessData')); + let accessData = storage.getItem('wallet:accessData'); let decrypted = wallet.decryptData(accessData.mainKey, pin); let decryptedWords = wallet.decryptData(accessData.words, password); diff --git a/__tests__/new_wallet.test.js b/__tests__/new_wallet.test.js index c4ab53a8e..fd8592495 100644 --- a/__tests__/new_wallet.test.js +++ b/__tests__/new_wallet.test.js @@ -11,6 +11,8 @@ import { HDPrivateKey } from 'bitcore-lib'; import CryptoJS from 'crypto-js'; import WebSocketHandler from '../src/WebSocketHandler'; +const storage = require('../src/storage').default; + var addressUsed = ''; var addressShared = ''; var txId = '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e'; @@ -53,22 +55,22 @@ mock.onGet('thin_wallet/address_history').reply((config) => { }); const checkData = () => { - check(localStorage.getItem('wallet:address'), addressShared, doneCb); - check(localStorage.getItem('wallet:lastUsedAddress'), addressUsed, doneCb); - check(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10), 1, doneCb); - check(parseInt(localStorage.getItem('wallet:lastUsedIndex'), 10), 0, doneCb); - check(parseInt(localStorage.getItem('wallet:lastGeneratedIndex'), 10), 20, doneCb); - let accessData = localStorage.getItem('wallet:accessData'); + check(storage.getItem('wallet:address'), addressShared, doneCb); + check(storage.getItem('wallet:lastUsedAddress'), addressUsed, doneCb); + check(parseInt(storage.getItem('wallet:lastSharedIndex'), 10), 1, doneCb); + check(parseInt(storage.getItem('wallet:lastUsedIndex'), 10), 0, doneCb); + check(parseInt(storage.getItem('wallet:lastGeneratedIndex'), 10), 20, doneCb); + let accessData = storage.getItem('wallet:accessData'); checkNot(accessData, null, doneCb); - let accessDataJson = JSON.parse(accessData); + let accessDataJson = accessData; check('mainKey' in accessDataJson, true, doneCb); check(typeof accessDataJson['mainKey'], 'string', doneCb); check('hash' in accessDataJson, true, doneCb); check(accessDataJson['hash'], CryptoJS.SHA256(CryptoJS.SHA256(pin)).toString(), doneCb); - let walletData = localStorage.getItem('wallet:data'); + let walletData = storage.getItem('wallet:data'); checkNot(walletData, null, doneCb); - let walletDataJson = JSON.parse(walletData); + let walletDataJson = walletData; check('historyTransactions' in walletDataJson, true, doneCb); check(typeof walletDataJson['historyTransactions'], 'object', doneCb); check('00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e' in walletDataJson['historyTransactions'], true, doneCb); @@ -86,7 +88,7 @@ beforeEach(() => { test('Generate new HD wallet', (done) => { doneCb = done; - // Generate new wallet and save data in localStorage + // Generate new wallet and save data in storage const words = wallet.generateWalletWords(256); check(wallet.wordsValid(words).valid, true, done); const promise = wallet.executeGenerateWallet(words, '', pin, 'password', true); @@ -105,7 +107,7 @@ test('Generate HD wallet from predefined words', (done) => { addressShared = 'WgSpcCwYAbtt31S2cqU7hHJkUHdac2EPWG'; - // Generate new wallet and save data in localStorage + // Generate new wallet and save data in storage const promise = wallet.executeGenerateWallet(words, '', pin, 'password', true); promise.then(() => { diff --git a/__tests__/tokens_utils.js b/__tests__/tokens_utils.js index 5bf45d7ae..1d2491306 100644 --- a/__tests__/tokens_utils.js +++ b/__tests__/tokens_utils.js @@ -12,6 +12,8 @@ import wallet from '../src/wallet'; import { util } from 'bitcore-lib'; import WebSocketHandler from '../src/WebSocketHandler'; +const storage = require('../src/storage').default; + const createdTxHash = '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e'; const createdToken = util.buffer.bufferToHex(tokens.getTokenUID(createdTxHash, 0)); @@ -46,7 +48,7 @@ test('Token UID', () => { }); const readyLoadHistory = (pin) => { - const encrypted = JSON.parse(localStorage.getItem('wallet:accessData')).mainKey; + const encrypted = storage.getItem('wallet:accessData').mainKey; const privKeyStr = wallet.decryptData(encrypted, pin); const privKey = HDPrivateKey(privKeyStr) return wallet.loadAddressHistory(0, GAP_LIMIT, privKey, pin); @@ -55,13 +57,13 @@ const readyLoadHistory = (pin) => { test('New token', (done) => { const words = 'connect sunny silent cabin leopard start turtle tortoise dial timber woman genre pave tuna rice indicate gown draft palm collect retreat meadow assume spray'; const pin = '123456'; - // Generate new wallet and save data in localStorage + // Generate new wallet and save data in storage wallet.executeGenerateWallet(words, '', pin, 'password', false); const promise = readyLoadHistory(pin); - const address = localStorage.getItem('wallet:address'); + const address = storage.getItem('wallet:address'); promise.then(() => { - // Adding data to localStorage to be used in the signing process - const savedData = JSON.parse(localStorage.getItem('wallet:data')); + // Adding data to storage to be used in the signing process + const savedData = storage.getItem('wallet:data'); const createdKey = `${createdTxHash},0`; savedData['historyTransactions'] = { '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e': { @@ -76,7 +78,7 @@ test('New token', (done) => { ] } }; - localStorage.setItem('wallet:data', JSON.stringify(savedData)); + storage.setItem('wallet:data', savedData); const input = {'tx_id': '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e', 'index': '0', 'token': '00', 'address': address}; const output = {'address': address, 'value': 100, 'tokenData': 0}; const tokenName = 'TestCoin'; diff --git a/__tests__/transaction_utils.test.js b/__tests__/transaction_utils.test.js index f2e0a4c60..b9faf9296 100644 --- a/__tests__/transaction_utils.test.js +++ b/__tests__/transaction_utils.test.js @@ -12,16 +12,18 @@ import buffer from 'buffer'; import { OP_PUSHDATA1 } from '../src/opcodes'; import { DEFAULT_TX_VERSION } from '../src/constants'; +const storage = require('../src/storage').default; + test('Tx weight constants', () => { transaction.updateTransactionWeightConstants(10, 1.5, 8); - expect(parseFloat(localStorage.getItem('wallet:txMinWeight'))).toBe(10); - expect(parseFloat(localStorage.getItem('wallet:txWeightCoefficient'))).toBe(1.5); - expect(parseFloat(localStorage.getItem('wallet:txMinWeightK'))).toBe(8); + expect(parseFloat(storage.getItem('wallet:txMinWeight'))).toBe(10); + expect(parseFloat(storage.getItem('wallet:txWeightCoefficient'))).toBe(1.5); + expect(parseFloat(storage.getItem('wallet:txMinWeightK'))).toBe(8); transaction.updateTransactionWeightConstants(15, 1.2, 10); - expect(parseFloat(localStorage.getItem('wallet:txMinWeight'))).toBe(15); - expect(parseFloat(localStorage.getItem('wallet:txWeightCoefficient'))).toBe(1.2); - expect(parseFloat(localStorage.getItem('wallet:txMinWeightK'))).toBe(10); + expect(parseFloat(storage.getItem('wallet:txMinWeight'))).toBe(15); + expect(parseFloat(storage.getItem('wallet:txWeightCoefficient'))).toBe(1.2); + expect(parseFloat(storage.getItem('wallet:txMinWeightK'))).toBe(10); }); test('Unsigned int to bytes', () => { @@ -164,14 +166,14 @@ test('Create input data', () => { expect(transaction.createInputData(signature, pubkeyBytes2).length).toBe(123); }); -test('Prepare data to send tokens', (done) => { +test('Prepare data to send tokens', async (done) => { // Now we will update the data in the inputs let words = 'purse orchard camera cloud piece joke hospital mechanic timber horror shoulder rebuild you decrease garlic derive rebuild random naive elbow depart okay parrot cliff'; - // Generate new wallet and save data in localStorage - wallet.executeGenerateWallet(words, '', '123456', 'password', true); - // Adding data to localStorage to be used in the signing process - let savedData = JSON.parse(localStorage.getItem('wallet:data')); - let addr = localStorage.getItem('wallet:address'); + // Generate new wallet and save data in storage + await wallet.executeGenerateWallet(words, '', '123456', 'password', true); + // Adding data to storage to be used in the signing process + let savedData = storage.getItem('wallet:data'); + let addr = storage.getItem('wallet:address'); savedData['historyTransactions'] = { '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e': { 'tx_id': '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e', @@ -185,7 +187,7 @@ test('Prepare data to send tokens', (done) => { ] } }; - localStorage.setItem('wallet:data', JSON.stringify(savedData)); + storage.setItem('wallet:data', savedData); // First get data to sign let tx_id = '00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e'; diff --git a/__tests__/wallet.test.js b/__tests__/wallet.test.js index 3b2b38bb2..93efd4d4c 100644 --- a/__tests__/wallet.test.js +++ b/__tests__/wallet.test.js @@ -9,6 +9,8 @@ import wallet from '../src/wallet'; import dateFormatter from '../src/date'; import { HATHOR_TOKEN_CONFIG } from '../src/constants'; +const storage = require('../src/storage').default; + test('Wallet operations for transaction', () => { const words = wallet.generateWalletWords(256); wallet.executeGenerateWallet(words, '', '123456', 'password', false); @@ -129,9 +131,9 @@ test('Wallet operations for transaction', () => { '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {}, } - const xpubkey = JSON.parse(localStorage.getItem('wallet:data')).xpubkey; + const xpubkey = storage.getItem('wallet:data').xpubkey; - localStorage.setItem('wallet:data', JSON.stringify({keys, historyTransactions, xpubkey})); + storage.setItem('wallet:data', {keys, historyTransactions, xpubkey}); const expectedBalance = { '00': { diff --git a/__tests__/wallet_utils.test.js b/__tests__/wallet_utils.test.js index 0b5ad26f5..1a80e83db 100644 --- a/__tests__/wallet_utils.test.js +++ b/__tests__/wallet_utils.test.js @@ -8,10 +8,13 @@ import wallet from '../src/wallet'; import dateFormatter from '../src/date'; +const storage = require('../src/storage').default; + beforeEach(() => { wallet.cleanLocalStorage(); }); + test('Loaded', () => { expect(wallet.loaded()).toBeFalsy(); const words = wallet.generateWalletWords(256); @@ -20,33 +23,33 @@ test('Loaded', () => { }); test('Clean local storage', () => { - localStorage.setItem('wallet:accessData', '{}'); - localStorage.setItem('wallet:data', '{}'); - localStorage.setItem('wallet:address', '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'); - localStorage.setItem('wallet:lastSharedIndex', 1); - localStorage.setItem('wallet:lastGeneratedIndex', 19); - localStorage.setItem('wallet:lastUsedIndex', 0); - localStorage.setItem('wallet:lastUsedAddress', '1knH3y5dZuC8DQBaLhgJP33fGBr6vstr8'); + storage.setItem('wallet:accessData', {}); + storage.setItem('wallet:data', {}); + storage.setItem('wallet:address', '171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r'); + storage.setItem('wallet:lastSharedIndex', 1); + storage.setItem('wallet:lastGeneratedIndex', 19); + storage.setItem('wallet:lastUsedIndex', 0); + storage.setItem('wallet:lastUsedAddress', '1knH3y5dZuC8DQBaLhgJP33fGBr6vstr8'); wallet.cleanLocalStorage(); - expect(localStorage.getItem('wallet:accessData')).toBeNull(); - expect(localStorage.getItem('wallet:data')).toBeNull(); - expect(localStorage.getItem('wallet:address')).toBeNull(); - expect(localStorage.getItem('wallet:lastSharedIndex')).toBeNull(); - expect(localStorage.getItem('wallet:lastGeneratedIndex')).toBeNull(); - expect(localStorage.getItem('wallet:lastUsedIndex')).toBeNull(); - expect(localStorage.getItem('wallet:lastUsedAddress')).toBeNull(); + expect(storage.getItem('wallet:accessData')).toBeNull(); + expect(storage.getItem('wallet:data')).toBeNull(); + expect(storage.getItem('wallet:address')).toBeNull(); + expect(storage.getItem('wallet:lastSharedIndex')).toBeNull(); + expect(storage.getItem('wallet:lastGeneratedIndex')).toBeNull(); + expect(storage.getItem('wallet:lastUsedIndex')).toBeNull(); + expect(storage.getItem('wallet:lastUsedAddress')).toBeNull(); }); -test('Save address history to localStorage', () => { - expect(localStorage.getItem('wallet:data')).toBeNull(); - localStorage.setItem('wallet:data', '{}'); +test('Save address history to storage', () => { + expect(storage.getItem('wallet:data')).toBeNull(); + storage.setItem('wallet:data', {}); const historyTransactions = {'id': {'tx_id': 'id'}} const allTokens = new Set(['00']); wallet.saveAddressHistory(historyTransactions, allTokens); - let data = JSON.parse(localStorage.getItem('wallet:data')); + let data = storage.getItem('wallet:data'); expect(data.historyTransactions).toEqual(expect.objectContaining(historyTransactions)); expect(data.allTokens).toEqual(expect.objectContaining(allTokens)); }); @@ -86,7 +89,7 @@ test('Inputs from amount', () => { 'inputs': [], }, } - localStorage.setItem('wallet:data', JSON.stringify({'keys': {'171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {}}})); + storage.setItem('wallet:data', {'keys': {'171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {}}}); const ret1 = wallet.getInputsFromAmount(historyTransactionts, 10, '01'); expect(ret1.inputs.length).toBe(0); @@ -129,21 +132,21 @@ test('Can use unspent txs', () => { expect(wallet.canUseUnspentTx(unspentTx3)).toBe(false); }); -test('Output change', () => { +test('Output change', async () => { const words = wallet.generateWalletWords(256); - wallet.executeGenerateWallet(words, '', '123456', 'password', true); - let lastSharedIndex = parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10); - let address = localStorage.getItem('wallet:address'); + await wallet.executeGenerateWallet(words, '', '123456', 'password', true); + let lastSharedIndex = storage.getItem('wallet:lastSharedIndex'); + let address = storage.getItem('wallet:address'); let change = wallet.getOutputChange(1000, '00'); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(lastSharedIndex+1); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(lastSharedIndex+1); expect(change.address).toBe(address); expect(change.value).toBe(1000); - expect(localStorage.getItem('wallet:address')).not.toBe(address); + expect(storage.getItem('wallet:address')).not.toBe(address); - localStorage.setItem('wallet:lastSharedIndex', localStorage.getItem('wallet:lastGeneratedIndex')); + storage.setItem('wallet:lastSharedIndex', storage.getItem('wallet:lastGeneratedIndex')); wallet.getOutputChange(1000, '00'); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(parseInt(localStorage.getItem('wallet:lastGeneratedIndex'), 10)); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(parseInt(storage.getItem('wallet:lastGeneratedIndex'), 10)); }); test('Unspent txs exist', () => { @@ -172,7 +175,7 @@ test('Unspent txs exist', () => { }, } - localStorage.setItem('wallet:data', JSON.stringify({'keys': {'171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {}}})); + storage.setItem('wallet:data', {'keys': {'171hK8MaRpG2SqQMMQ34EdTharUmP1Qk4r': {}}}); expect(wallet.checkUnspentTxExists(historyTransactionts, '0', '0', '00').exists).toBe(false); expect(wallet.checkUnspentTxExists(historyTransactionts, '0', '0', '01').exists).toBe(false); @@ -197,33 +200,31 @@ test('Wallet backup', () => { expect(wallet.isBackupDone()).toBe(false); }); -test('Get wallet words', () => { +test('Get wallet words', async () => { const words = wallet.generateWalletWords(256); - wallet.executeGenerateWallet(words, '', '123456', 'password', true); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(0) + await wallet.executeGenerateWallet(words, '', '123456', 'password', true); + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(0) - const sharedAddress = localStorage.getItem('wallet:address'); - const key = JSON.parse(localStorage.getItem('wallet:data')).keys[sharedAddress]; + const sharedAddress = storage.getItem('wallet:address'); + const key = storage.getItem('wallet:data').keys[sharedAddress]; expect(wallet.getWalletWords('password')).toBe(words); wallet.addPassphrase('passphrase', '123456', 'password'); expect(wallet.getWalletWords('password')).toBe(words); - expect(parseInt(localStorage.getItem('wallet:lastSharedIndex'), 10)).toBe(0) + expect(parseInt(storage.getItem('wallet:lastSharedIndex'), 10)).toBe(0) - const newSharedAddress = localStorage.getItem('wallet:address'); + const newSharedAddress = storage.getItem('wallet:address'); expect(sharedAddress).not.toBe(newSharedAddress); - expect(key.index).toBe(JSON.parse(localStorage.getItem('wallet:data')).keys[newSharedAddress].index); + expect(key.index).toBe(storage.getItem('wallet:data').keys[newSharedAddress].index); }); -test('Change server', () => { +test('Change server', async () => { const words = wallet.generateWalletWords(256); - wallet.executeGenerateWallet(words, '', '123456', 'password', true); - const accessData = JSON.parse(localStorage.getItem('wallet:accessData')); - const keys = JSON.parse(localStorage.getItem('wallet:data')).keys; - + await wallet.executeGenerateWallet(words, '', '123456', 'password', true); + const accessData = storage.getItem('wallet:accessData'); + const keys = storage.getItem('wallet:data').keys; wallet.reloadData(); - - expect(JSON.parse(localStorage.getItem('wallet:accessData'))).toEqual(accessData); + expect(storage.getItem('wallet:accessData')).toEqual(accessData); }); test('Started', () => { @@ -232,22 +233,22 @@ test('Started', () => { expect(wallet.started()).toBe(true); }); -test('Reset all data', () => { +test('Reset all data', async () => { const words = wallet.generateWalletWords(256); - wallet.executeGenerateWallet(words, '', '123456', 'password', true); + await wallet.executeGenerateWallet(words, '', '123456', 'password', true); wallet.markWalletAsStarted(); const server = 'http://server'; wallet.changeServer(server); - expect(localStorage.getItem('wallet:server')).toBe(server); + expect(storage.getItem('wallet:server')).toBe(server); wallet.lock(); wallet.resetAllData(); - expect(localStorage.getItem('wallet:started')).toBeNull(); - expect(localStorage.getItem('wallet:server')).toBeNull(); - expect(localStorage.getItem('wallet:locked')).toBeNull(); - expect(localStorage.getItem('wallet:accessData')).toBeNull(); - expect(localStorage.getItem('wallet:data')).toBeNull(); + expect(storage.getItem('wallet:started')).toBeNull(); + expect(storage.getItem('wallet:server')).toBeNull(); + expect(storage.getItem('wallet:locked')).toBeNull(); + expect(storage.getItem('wallet:accessData')).toBeNull(); + expect(storage.getItem('wallet:data')).toBeNull(); }); test('Closed', () => { diff --git a/index.js b/index.js index 3ad2df1ef..1992ecb86 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ var walletApi = require('./lib/api/wallet'); var txApi = require('./lib/api/txApi'); var versionApi = require('./lib/api/version'); var axios = require('./lib/api/axiosInstance'); +var storage = require('./lib/storage'); module.exports = { helpers: helpers.default, @@ -26,4 +27,5 @@ module.exports = { errors: errors, constants: constants, axios: axios, -} \ No newline at end of file + storage: storage.default, +} diff --git a/package.json b/package.json index 5f2cfb2c7..6cefb501a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hathor/wallet-lib", - "version": "0.1.2", + "version": "0.2.0", "description": "Library used by Hathor Wallet", "jest": { "setupFilesAfterEnv": [ diff --git a/setupTests.js b/setupTests.js index 70e1fec19..6ad6cf1af 100644 --- a/setupTests.js +++ b/setupTests.js @@ -5,8 +5,37 @@ * LICENSE file in the root directory of this source tree. */ +// Creating memory storage to be used in the place of localStorage +class MemoryOnlyStore { + constructor() { + this.hathorMemoryStorage = {}; + } + + getItem(key) { + const ret = this.hathorMemoryStorage[key]; + if (ret === undefined) { + return null + } + return ret; + } + + setItem(key, value) { + this.hathorMemoryStorage[key] = value; + } + + removeItem(key) { + delete this.hathorMemoryStorage[key]; + } + + clear() { + this.hathorMemoryStorage = {}; + } +} + // Mocking localStorage for tests import 'jest-localstorage-mock'; +const storage = require('./src/storage').default; +storage.setStore(new MemoryOnlyStore()); // Mocking WebSocket for tests import { Server, WebSocket } from 'mock-socket'; @@ -14,7 +43,7 @@ global.WebSocket = WebSocket; import helpers from './src/helpers'; -localStorage.setItem('wallet:server', 'http://localhost:8080/'); +storage.setItem('wallet:server', 'http://localhost:8080/'); let wsURL = helpers.getWSServerURL(); // Creating a ws mock server @@ -70,4 +99,7 @@ mock.onGet('version').reply((config) => { return [200, data]; }); +import WS from './src/WebSocketHandler'; +WS.setup(); + global.window = {}; diff --git a/src/WebSocketHandler.js b/src/WebSocketHandler.js index 213b1559a..adfb96a5a 100644 --- a/src/WebSocketHandler.js +++ b/src/WebSocketHandler.js @@ -29,7 +29,6 @@ class WS extends EventEmitter { this.connected = undefined; // Store variable that is passed to Redux if ws is online this.isOnline = undefined; - this.setup(); } return WS.instance; diff --git a/src/helpers.js b/src/helpers.js index f31350839..424802d06 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -8,6 +8,8 @@ import { GENESIS_BLOCK, DECIMAL_PLACES, DEFAULT_SERVER } from './constants'; import path from 'path'; +import storage from './storage'; + /** * Helper methods * @@ -170,7 +172,7 @@ const helpers = { * @inner */ getServerURL() { - let server = localStorage.getItem('wallet:server'); + let server = storage.getItem('wallet:server'); if (server === null) { server = DEFAULT_SERVER; } diff --git a/src/storage.js b/src/storage.js new file mode 100644 index 000000000..2358352bf --- /dev/null +++ b/src/storage.js @@ -0,0 +1,79 @@ +/** + * Copyright (c) Hathor Labs and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Interface to use the storage object set by the client + * + * This storage should have the same methods as localStorage (from the browser) and has + * to support storaing js objects. It should handle any serialization needed. + * + * @class + * @name Storage + */ +class Storage { + constructor() { + this.store = null; + } + + /** + * Set the underlying store object + * + * @param {Object} myStorage The store to be used + */ + setStore(myStorage) { + this.store = myStorage; + } + + /** + * Return the current value associated with the given key + * + * @param {string} key Key associated with the object + * + * @return {Object} the object stored + */ + getItem(key) { + return this.store.getItem(key); + } + + /** + * Add the given object to the storage + * + * @param {string} key Key associated with the object + * @param {Object} value Object to be stored + */ + setItem(key, value) { + return this.store.setItem(key, value); + } + + /** + * Remove the key and associated object from storage + * + * @param {string} key Key associated with the object + */ + removeItem(key) { + return this.store.removeItem(key); + } + + /** + * Remove all key and associated objects from storage + */ + clear() { + return this.store.clear(); + } + + /** + * This method is optional and may be used to initialize the storage before the + * lib starts using it + */ + preStart() { + return this.store.preStart(); + } +} + +const instance = new Storage(); + +export default instance; diff --git a/src/tokens.js b/src/tokens.js index c8a0b9600..8aaeeeb36 100644 --- a/src/tokens.js +++ b/src/tokens.js @@ -6,6 +6,7 @@ */ import transaction from './transaction'; +import storage from './storage'; import { crypto, util } from 'bitcore-lib'; import walletApi from './api/wallet'; import { AddressError, OutputValueError } from './errors'; @@ -39,7 +40,7 @@ const tokens = { }, /** - * Add a new token to the localStorage and redux + * Add a new token to the storage and redux * * @param {string} uid Token uid * @param {string} name Token name @@ -59,7 +60,7 @@ const tokens = { }, /** - * Edit token name and symbol. Save in localStorage and redux + * Edit token name and symbol. Save in storage and redux * * @param {string} uid Token uid to be edited * @param {string} name New token name @@ -80,7 +81,7 @@ const tokens = { }, /** - * Unregister token from localStorage and redux + * Unregister token from storage and redux * * @param {string} uid Token uid to be unregistered * @@ -145,7 +146,7 @@ const tokens = { }, /** - * Returns the saved tokens in localStorage + * Returns the saved tokens in storage * * @return {Object} Array of objects ({'name', 'symbol', 'uid'}) of saved tokens * @@ -153,17 +154,15 @@ const tokens = { * @inner */ getTokens() { - let dataToken = localStorage.getItem('wallet:tokens'); - if (dataToken) { - dataToken = localStorage.memory ? dataToken : JSON.parse(dataToken); - } else { + let dataToken = storage.getItem('wallet:tokens'); + if (!dataToken) { dataToken = [HATHOR_TOKEN_CONFIG]; } return dataToken; }, /** - * Updates the saved tokens in localStorage + * Updates the saved tokens in storage * * @param {Object} Array of objects ({'name', 'symbol', 'uid'}) with new tokens * @@ -172,8 +171,7 @@ const tokens = { * */ saveToStorage(newTokens) { - const dataTokens = localStorage.memory ? newTokens : JSON.stringify(newTokens); - localStorage.setItem('wallet:tokens', dataTokens); + storage.setItem('wallet:tokens', newTokens); }, /** @@ -291,7 +289,7 @@ const tokens = { const promise = new Promise((resolve, reject) => { walletApi.sendTokens(txHex, (response) => { if (response.success) { - // Save in localStorage and redux new token configuration + // Save in storage and redux new token configuration this.addToken(response.tx.tokens[0], name, symbol); const mintPromise = this.mintTokens(response.tx.hash, response.tx.tokens[0], address, mintAmount, pin) mintPromise.then(() => { diff --git a/src/transaction.js b/src/transaction.js index 7c6c2ddf9..7e1f30f4e 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -11,11 +11,13 @@ import { HDPrivateKey, crypto, encoding, util } from 'bitcore-lib'; import { AddressError, OutputValueError } from './errors'; import dateFormatter from './date'; import helpers from './helpers'; +import storage from './storage'; import wallet from './wallet'; import buffer from 'buffer'; import Long from 'long'; import walletApi from './api/wallet'; + /** * Transaction utils with methods to serialize, create and handle transactions * @@ -320,8 +322,8 @@ const transaction = { * @inner */ getSignature(index, hash, pin) { - const accessData = localStorage.getItem('wallet:accessData'); - const encryptedPrivateKey = localStorage.memory ? accessData.mainKey : JSON.parse(accessData).mainKey; + const accessData = storage.getItem('wallet:accessData'); + const encryptedPrivateKey = accessData.mainKey; const privateKeyStr = wallet.decryptData(encryptedPrivateKey, pin); const key = HDPrivateKey(privateKeyStr) const derivedKey = key.derive(index); @@ -541,7 +543,7 @@ const transaction = { }, /** - * Save txMinWeight and txWeightCoefficient to localStorage + * Save txMinWeight and txWeightCoefficient to storage * * @param {number} txMinWeight Minimum allowed weight for a tx (float) * @param {number} txWeightCoefficient Coefficient to be used when calculating tx weight (float) @@ -550,9 +552,9 @@ const transaction = { * @inner */ updateTransactionWeightConstants(txMinWeight, txWeightCoefficient, txMinWeightK) { - localStorage.setItem('wallet:txMinWeight', txMinWeight); - localStorage.setItem('wallet:txWeightCoefficient', txWeightCoefficient); - localStorage.setItem('wallet:txMinWeightK', txMinWeightK); + storage.setItem('wallet:txMinWeight', txMinWeight); + storage.setItem('wallet:txWeightCoefficient', txWeightCoefficient); + storage.setItem('wallet:txMinWeightK', txMinWeightK); }, /** @@ -564,9 +566,9 @@ const transaction = { * @inner */ getTransactionWeightConstants() { - return {'txMinWeight': parseFloat(localStorage.getItem('wallet:txMinWeight')), - 'txWeightCoefficient': parseFloat(localStorage.getItem('wallet:txWeightCoefficient')), - 'txMinWeightK': parseFloat(localStorage.getItem('wallet:txMinWeightK'))} + return {'txMinWeight': parseFloat(storage.getItem('wallet:txMinWeight')), + 'txWeightCoefficient': parseFloat(storage.getItem('wallet:txWeightCoefficient')), + 'txMinWeightK': parseFloat(storage.getItem('wallet:txMinWeightK'))} } } diff --git a/src/wallet.js b/src/wallet.js index eb7ca801c..e59010e92 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -14,13 +14,14 @@ import tokens from './tokens'; import helpers from './helpers'; import { OutputValueError } from './errors'; import version from './version'; +import storage from './storage'; import WebSocketHandler from './WebSocketHandler'; import dateFormatter from './date'; import _ from 'lodash'; /** - * We use localStorage and Redux to save data. - * In localStorage we have the following keys (prefixed by wallet:) + * We use storage and Redux to save data. + * In storage we have the following keys (prefixed by wallet:) * - data: object with data from the wallet including (all have full description in the reducers file) * . historyTransactions: Object of transactions indexed by tx_id * - accessData: object with data to access the wallet @@ -88,7 +89,7 @@ const wallet = { /** * Start a new HD wallet with new private key - * Encrypt this private key and save data in localStorage + * Encrypt this private key and save data in storage * * @param {string} words Words to generate the HD Wallet seed * @param {string} passphrase @@ -109,7 +110,7 @@ const wallet = { let encryptedData = this.encryptData(privkey.xprivkey, pin) let encryptedDataWords = this.encryptData(words, password) - // Save in localStorage the encrypted private key and the hash of the pin and password + // Save in storage the encrypted private key and the hash of the pin and password let access = { mainKey: encryptedData.encrypted.toString(), hash: encryptedData.hash.toString(), @@ -122,11 +123,8 @@ const wallet = { xpubkey: privkey.xpubkey, } - access = localStorage.memory ? access : JSON.stringify(access); - walletData = localStorage.memory ? walletData : JSON.stringify(walletData); - - localStorage.setItem('wallet:accessData', access); - localStorage.setItem('wallet:data', walletData); + storage.setItem('wallet:accessData', access); + storage.setItem('wallet:data', walletData); let promise = null; if (loadHistory) { @@ -145,7 +143,7 @@ const wallet = { * @inner */ getLastGeneratedIndex() { - const raw = localStorage.getItem('wallet:lastGeneratedIndex'); + const raw = storage.getItem('wallet:lastGeneratedIndex'); if (!raw) { return 0; } @@ -161,18 +159,14 @@ const wallet = { * @inner */ getWalletData() { - const data = localStorage.getItem('wallet:data'); - if (!data) { - return null; - } - return localStorage.memory ? data : JSON.parse(data); + return storage.getItem('wallet:data'); }, /** * Load the history for each of the addresses of a new generated wallet * We always search until the GAP_LIMIT. If we have any history in the middle of the searched addresses * we search again until we have the GAP_LIMIT of addresses without any transactions - * The loaded history is added to localStorage and Redux + * The loaded history is added to storage and Redux * * @param {number} startIndex Address index to start to load history * @param {number} count How many addresses I will load @@ -200,7 +194,7 @@ const wallet = { // Subscribe in websocket to this address updates this.subscribeAddress(address.toString()); - if (localStorage.getItem('wallet:address') === null) { + if (storage.getItem('wallet:address') === null) { // If still don't have an address to show on the screen this.updateAddress(address.toString(), i); } @@ -208,11 +202,10 @@ const wallet = { let lastGeneratedIndex = this.getLastGeneratedIndex(); if (lastGeneratedIndex < stopIndex - 1) { - localStorage.setItem('wallet:lastGeneratedIndex', stopIndex - 1); + storage.setItem('wallet:lastGeneratedIndex', stopIndex - 1); } - dataJson = localStorage.memory ? dataJson : JSON.stringify(dataJson); - localStorage.setItem('wallet:data', dataJson); + storage.setItem('wallet:data', dataJson); walletApi.getAddressHistory(addresses, (response) => { const data = this.getWalletData(); @@ -247,7 +240,7 @@ const wallet = { }, /** - * Update address shared in localStorage and redux + * Update address shared in storage and redux * * @param {string} lastSharedAddress * @param {number} lastSharedIndex @@ -255,8 +248,8 @@ const wallet = { * @inner */ updateAddress(lastSharedAddress, lastSharedIndex) { - localStorage.setItem('wallet:address', lastSharedAddress); - localStorage.setItem('wallet:lastSharedIndex', lastSharedIndex); + storage.setItem('wallet:address', lastSharedAddress); + storage.setItem('wallet:lastSharedIndex', lastSharedIndex); }, /** @@ -317,10 +310,9 @@ const wallet = { * @inner */ isPinCorrect(pin) { - const accessData = localStorage.getItem('wallet:accessData'); - const data = localStorage.memory ? accessData : JSON.parse(accessData); + const accessData = storage.getItem('wallet:accessData'); const pinHash = this.hashPassword(pin).toString(); - return pinHash === data.hash; + return pinHash === accessData.hash; }, /** @@ -334,10 +326,9 @@ const wallet = { * @inner */ isPasswordCorrect(password) { - const accessData = localStorage.getItem('wallet:accessData'); - const data = localStorage.memory ? accessData : JSON.parse(accessData); + const accessData = storage.getItem('wallet:accessData'); const passwordHash = this.hashPassword(password).toString(); - return passwordHash === data.hashPasswd; + return passwordHash === accessData.hashPasswd; }, /** @@ -356,7 +347,7 @@ const wallet = { /** * Get next address after the last shared one (only if it's already generated) - * Update the data in localStorage and Redux + * Update the data in storage and Redux * * @memberof Wallet * @inner @@ -423,14 +414,13 @@ const wallet = { this.updateAddress(newAddress.toString(), newIndex); let lastGeneratedIndex = this.getLastGeneratedIndex(); if (newIndex > lastGeneratedIndex) { - localStorage.setItem('wallet:lastGeneratedIndex', newIndex); + storage.setItem('wallet:lastGeneratedIndex', newIndex); } // Save new keys to local storage let data = this.getWalletData(); data.keys[newAddress.toString()] = {privkey: null, index: newIndex}; - data = localStorage.memory ? data : JSON.stringify(data); - localStorage.setItem('wallet:data', data); + storage.setItem('wallet:data', data); // Subscribe in ws to new address updates this.subscribeAddress(newAddress.toString()); @@ -447,7 +437,7 @@ const wallet = { * @inner */ getAddressToUse() { - const address = localStorage.getItem('wallet:address'); + const address = storage.getItem('wallet:address'); // Updating address because the last one was used if (this.hasNewAddress()) { this.getNextAddress(); @@ -463,7 +453,7 @@ const wallet = { * * @param {Object} tx Transaction object * @param {string} selectedToken Token uid - * @param {Object} walletData Wallet data in localStorage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() + * @param {Object} walletData Wallet data in storage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() * * @return {boolean} * @@ -589,7 +579,7 @@ const wallet = { }, /** - * Save wallet data from redux to localStorage + * Save wallet data from redux to storage * * @param {Object} historyTransactions * @param {Object} allTokens Set of all tokens added to the wallet @@ -601,8 +591,7 @@ const wallet = { let data = this.getWalletData(); data['historyTransactions'] = historyTransactions; data['allTokens'] = [...allTokens]; - data = localStorage.memory ? data : JSON.stringify(data); - localStorage.setItem('wallet:data', data); + storage.setItem('wallet:data', data); }, /** @@ -614,7 +603,7 @@ const wallet = { * @inner */ loaded() { - return localStorage.getItem('wallet:accessData') !== null; + return storage.getItem('wallet:accessData') !== null; }, /** @@ -626,7 +615,7 @@ const wallet = { * @inner */ started() { - return localStorage.getItem('wallet:started') !== null; + return storage.getItem('wallet:started') !== null; }, /** @@ -638,7 +627,7 @@ const wallet = { * @inner */ markWalletAsStarted() { - return localStorage.setItem('wallet:started', true); + return storage.setItem('wallet:started', true); }, /** @@ -693,7 +682,7 @@ const wallet = { }, /** - * Get an address, find its index and set as last used in localStorage + * Get an address, find its index and set as last used in storage * * @param {string} address * @memberof Wallet @@ -705,8 +694,8 @@ const wallet = { let index = data.keys[address].index; const lastUsedIndex = this.getLastUsedIndex(); if (lastUsedIndex === null || index > parseInt(lastUsedIndex, 10)) { - localStorage.setItem('wallet:lastUsedAddress', address); - localStorage.setItem('wallet:lastUsedIndex', index); + storage.setItem('wallet:lastUsedAddress', address); + storage.setItem('wallet:lastUsedIndex', index); } } }, @@ -733,7 +722,7 @@ const wallet = { * @inner */ cleanServer() { - localStorage.removeItem('wallet:server'); + storage.removeItem('wallet:server'); }, /* @@ -745,27 +734,27 @@ const wallet = { resetAllData() { this.cleanWallet(); this.cleanServer(); - localStorage.removeItem('wallet:started'); - localStorage.removeItem('wallet:backup'); - localStorage.removeItem('wallet:locked'); - localStorage.removeItem('wallet:tokens'); - localStorage.removeItem('wallet:sentry'); + storage.removeItem('wallet:started'); + storage.removeItem('wallet:backup'); + storage.removeItem('wallet:locked'); + storage.removeItem('wallet:tokens'); + storage.removeItem('wallet:sentry'); }, /** - * Remove all localStorages saved items + * Remove all storage saved items * @memberof Wallet * @inner */ cleanLocalStorage() { - localStorage.removeItem('wallet:accessData'); - localStorage.removeItem('wallet:data'); - localStorage.removeItem('wallet:address'); - localStorage.removeItem('wallet:lastSharedIndex'); - localStorage.removeItem('wallet:lastGeneratedIndex'); - localStorage.removeItem('wallet:lastUsedIndex'); - localStorage.removeItem('wallet:lastUsedAddress'); - localStorage.removeItem('wallet:closed'); + storage.removeItem('wallet:accessData'); + storage.removeItem('wallet:data'); + storage.removeItem('wallet:address'); + storage.removeItem('wallet:lastSharedIndex'); + storage.removeItem('wallet:lastGeneratedIndex'); + storage.removeItem('wallet:lastUsedIndex'); + storage.removeItem('wallet:lastUsedAddress'); + storage.removeItem('wallet:closed'); }, /* @@ -891,7 +880,7 @@ const wallet = { * @inner */ lock() { - localStorage.setItem('wallet:locked', true); + storage.setItem('wallet:locked', true); }, /* @@ -901,7 +890,7 @@ const wallet = { * @inner */ unlock() { - localStorage.removeItem('wallet:locked'); + storage.removeItem('wallet:locked'); }, /* @@ -913,7 +902,7 @@ const wallet = { * @inner */ isLocked() { - return localStorage.getItem('wallet:locked') !== null; + return storage.getItem('wallet:locked') !== null; }, /* @@ -925,17 +914,17 @@ const wallet = { * @inner */ wasClosed() { - return localStorage.getItem('wallet:closed') !== null; + return storage.getItem('wallet:closed') !== null; }, /* - * Set in localStorage as closed + * Set in storage as closed * * @memberof Wallet * @inner */ close() { - localStorage.setItem('wallet:closed', true); + storage.setItem('wallet:closed', true); }, /** @@ -949,29 +938,28 @@ const wallet = { * @inner */ getWalletWords(password) { - const accessData = localStorage.getItem('wallet:accessData'); - const data = localStorage.memory ? accessData : JSON.parse(accessData); - return this.decryptData(data.words, password); + const accessData = storage.getItem('wallet:accessData'); + return this.decryptData(accessData.words, password); }, /* - * Save backup done in localStorage + * Save backup done in storage * * @memberof Wallet * @inner */ markBackupAsDone() { - localStorage.setItem('wallet:backup', true); + storage.setItem('wallet:backup', true); }, /* - * Save backup not done in localStorage + * Save backup not done in storage * * @memberof Wallet * @inner */ markBackupAsNotDone() { - localStorage.removeItem('wallet:backup'); + storage.removeItem('wallet:backup'); }, /* @@ -983,19 +971,18 @@ const wallet = { * @inner */ isBackupDone() { - return localStorage.getItem('wallet:backup') !== null; + return storage.getItem('wallet:backup') !== null; }, /* - * Reload data in the localStorage + * Reload data in the storage * * @memberof Wallet * @inner */ reloadData() { // Get old access data - const accessDataStorage = localStorage.getItem('wallet:accessData'); - let accessData = localStorage.memory ? accessDataStorage : JSON.parse(accessDataStorage); + const accessData = storage.getItem('wallet:accessData'); const walletData = this.getWalletData(); this.cleanWallet(); @@ -1007,12 +994,8 @@ const wallet = { xpubkey: walletData.xpubkey, } - // Prepare to save new data - accessData = localStorage.memory ? accessData : JSON.stringify(accessData); - newWalletData = localStorage.memory ? newWalletData : JSON.stringify(newWalletData); - - localStorage.setItem('wallet:accessData', accessData); - localStorage.setItem('wallet:data', newWalletData); + storage.setItem('wallet:accessData', accessData); + storage.setItem('wallet:data', newWalletData); // Load history from new server const promise = this.loadAddressHistory(0, GAP_LIMIT); @@ -1034,7 +1017,7 @@ const wallet = { }, /* - * Change server in localStorage + * Change server in storage * * @param {string} newServer New server to connect * @@ -1042,7 +1025,7 @@ const wallet = { * @inner */ changeServer(newServer) { - localStorage.setItem('wallet:server', newServer); + storage.setItem('wallet:server', newServer); }, /* @@ -1123,16 +1106,16 @@ const wallet = { }, /** - * Get localStorage index and, in case is not null, parse to int + * Get storage index and, in case is not null, parse to int * - * @param {string} key Index key to get in the localStorage + * @param {string} key Index key to get in the storage * * @return {number} Index parsed to integer or null * @memberof Wallet * @inner */ getLocalStorageIndex(key) { - let index = localStorage.getItem(`wallet:${key}`); + let index = storage.getItem(`wallet:${key}`); if (index !== null) { index = parseInt(index, 10); } @@ -1140,7 +1123,7 @@ const wallet = { }, /** - * Get localStorage last used index (in case is not set return null) + * Get storage last used index (in case is not set return null) * * @return {number} Last used index parsed to integer or null * @memberof Wallet @@ -1151,7 +1134,7 @@ const wallet = { }, /** - * Get localStorage last shared index (in case is not set return null) + * Get storage last shared index (in case is not set return null) * * @return {number} Last shared index parsed to integer or null * @memberof Wallet @@ -1170,7 +1153,7 @@ const wallet = { * @param {Set} allTokens Set of all tokens (uid) already added * @param {Array} newHistory Array of new data that arrived from the server to be added to local data * @param {function} resolve Resolve method from promise to be called after finishing handling the new history - * @param {Object} dataJson Wallet data in localStorage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() + * @param {Object} dataJson Wallet data in storage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() * @param {function} reject Reject method from promise to be called if an error happens * * @throws {OutputValueError} Will throw an error if one of the output value is invalid @@ -1248,7 +1231,7 @@ const wallet = { } } - // Saving to localStorage before resolving the promise + // Saving to storage before resolving the promise this.saveAddressHistory(historyTransactions, allTokens); const lastGeneratedIndex = this.getLastGeneratedIndex(); @@ -1282,7 +1265,7 @@ const wallet = { * Check if address is from the loaded wallet * * @param {string} address Address to check - * @param {Object} data Wallet data in localStorage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() + * @param {Object} data Wallet data in storage already loaded. This parameter is optional and if nothing is passed, the data will be loaded again. We expect this field to be the return of the method wallet.getWalletData() * * @return {boolean} * @memberof Wallet