diff --git a/packages/keymaster/src/db-wallet-json-enc.js b/packages/keymaster/src/db-wallet-json-enc.js index 92bdef8f..1398b8c0 100644 --- a/packages/keymaster/src/db-wallet-json-enc.js +++ b/packages/keymaster/src/db-wallet-json-enc.js @@ -1,9 +1,5 @@ -import fs from 'fs'; import crypto from 'crypto'; -const dataFolder = 'data'; -const walletName = `${dataFolder}/wallet.json`; - const algorithm = 'aes-256-cbc'; // Algorithm const keyLength = 32; // 256 bit AES-256 const ivLength = 16; // 128-bit AES block size @@ -11,21 +7,18 @@ const saltLength = 16; // 128-bit salt const iterations = 200000; // PBKDF2 iterations const digest = 'sha512'; // PBKDF2 hash function +let baseWallet; let passphrase; export function setPassphrase(pp) { passphrase = pp; } -export function saveWallet(wallet, overwrite = false) { - if (fs.existsSync(walletName) && !overwrite) { - return false; - } - - if (!fs.existsSync(dataFolder)) { - fs.mkdirSync(dataFolder, { recursive: true }); - } +export function setWallet(wallet) { + baseWallet = wallet; +} +export function saveWallet(wallet, overwrite = false) { if (!passphrase) { throw new Error('KC_ENCRYPTED_PASSPHRASE not set'); } @@ -45,24 +38,20 @@ export function saveWallet(wallet, overwrite = false) { data: encrypted }; - fs.writeFileSync(walletName, JSON.stringify(encryptedData, null, 4)); - - return true; + return baseWallet.saveWallet(encryptedData, overwrite); } export function loadWallet() { - if (!fs.existsSync(walletName)) { - return null; - } - if (!passphrase) { throw new Error('KC_ENCRYPTED_PASSPHRASE not set'); } - const encryptedJson = fs.readFileSync(walletName, 'utf8'); - const encryptedData = JSON.parse(encryptedJson); + const encryptedData = baseWallet.loadWallet(); + if (!encryptedData) { + return null; + } - if (!encryptedData || !encryptedData.salt || !encryptedData.iv || !encryptedData.data) { + if (!encryptedData.salt || !encryptedData.iv || !encryptedData.data) { throw new Error('Wallet not encrypted'); } diff --git a/packages/keymaster/src/db-wallet-json.js b/packages/keymaster/src/db-wallet-json.js index 22391f9c..efc703ca 100644 --- a/packages/keymaster/src/db-wallet-json.js +++ b/packages/keymaster/src/db-wallet-json.js @@ -22,11 +22,6 @@ export function loadWallet() { } const walletJson = fs.readFileSync(walletName); - const walletData = JSON.parse(walletJson); - - if (walletData && walletData.salt && walletData.iv && walletData.data) { - throw new Error('Wallet is encrypted'); - } - - return walletData; + + return JSON.parse(walletJson); } diff --git a/sample.env b/sample.env index 93000ecb..9290e878 100644 --- a/sample.env +++ b/sample.env @@ -12,7 +12,7 @@ KC_GATEKEEPER_PORT=4224 KC_GATEKEEPER_GC_INTERVAL=60 # Wallet -KC_ENCRYPTED_WALLET=false +# KC_ENCRYPTED_PASSPHRASE= # CLI KC_GATEKEEPER_URL=http://localhost:4224 diff --git a/scripts/keychain-cli.js b/scripts/keychain-cli.js index 858726fd..41e712f9 100644 --- a/scripts/keychain-cli.js +++ b/scripts/keychain-cli.js @@ -948,20 +948,37 @@ program return; } - db_wallet_enc.setPassphrase(keymasterPassphrase); - const wallet = db_wallet_json.loadWallet(); + let wallet = db_wallet_json.loadWallet(); + if (wallet && (wallet.salt && wallet.iv && wallet.data)) { + console.error('Wallet already encrypted'); + return; + } if (wallet === null) { + await keymaster.start({ + gatekeeper: gatekeeper_sdk, + wallet: db_wallet_json, + cipher, + }); await keymaster.newWallet(); - } else { - const ok = db_wallet_enc.saveWallet(wallet, true); - if (ok) { - console.log(UPDATE_OK); - } - else { - console.log(UPDATE_FAILED); + wallet = db_wallet_json.loadWallet(); + + if (wallet === null) { + console.error('Failed to create new wallet'); + return; } } + + db_wallet_enc.setPassphrase(keymasterPassphrase); + db_wallet_enc.setWallet(db_wallet_json); + + const ok = db_wallet_enc.saveWallet(wallet, true); + if (ok) { + console.log(UPDATE_OK); + } + else { + console.log(UPDATE_FAILED); + } } catch (error) { console.error(error.message); } @@ -1006,11 +1023,15 @@ program }); function getDBWallet() { + let wallet = db_wallet_json; + if (keymasterPassphrase) { db_wallet_enc.setPassphrase(keymasterPassphrase); - return db_wallet_enc; + db_wallet_enc.setWallet(wallet); + wallet = db_wallet_enc; } - return db_wallet_json; + + return wallet; } async function run() { diff --git a/tests/keymaster.test.js b/tests/keymaster.test.js index 4b267ece..aafbb499 100644 --- a/tests/keymaster.test.js +++ b/tests/keymaster.test.js @@ -96,6 +96,7 @@ describe('loadWallet', () => { afterEach(async () => { mockFs.restore(); wallet_enc.setPassphrase(undefined); + wallet_enc.setWallet(undefined); await keymaster.start({ gatekeeper, wallet, cipher }); }); @@ -123,28 +124,17 @@ describe('loadWallet', () => { it('loading non-existing encrypted wallet returns null', async () => { mockFs({}); - const wallet = wallet_enc.loadWallet(); - expect(wallet).toBe(null); - }); - - it('regular wallet should throw when loading encrypted wallet', async () => { - mockFs({}); - const mockWallet = { salt: 1, iv: 1, data: 1 }; - - const ok = await keymaster.saveWallet(mockWallet); + wallet_enc.setPassphrase('passphrase'); + wallet_enc.setWallet(wallet); - try { - await keymaster.loadWallet(); - throw new ExpectedExceptionError(); - } catch (error) { - expect(ok).toBe(true); - expect(error.message).toBe('Wallet is encrypted'); - } + const check_wallet = wallet_enc.loadWallet(); + expect(check_wallet).toBe(null); }); it('wallet should throw when passphrase not set', async () => { mockFs({}); const mockWallet = { mock: 1 }; + wallet_enc.setWallet(wallet); await keymaster.start({ gatekeeper, wallet: wallet_enc, cipher }); @@ -167,6 +157,7 @@ describe('loadWallet', () => { await keymaster.start({ gatekeeper, wallet: wallet_enc, cipher }); + wallet_enc.setWallet(wallet); wallet_enc.setPassphrase('passphrase'); const ok = await keymaster.saveWallet(mockWallet); @@ -191,6 +182,25 @@ describe('saveWallet', () => { await keymaster.start({ gatekeeper, wallet, cipher }); }); + it('test saving directly on the unencrypted wallet', async () => { + mockFs({}); + const mockWallet = { mock: 0 }; + + const ok = wallet.saveWallet(mockWallet); + expect(ok).toBe(true); + }); + + it('test saving directly on the encrypted wallet', async () => { + mockFs({}); + const mockWallet = { mock: 0 }; + + wallet_enc.setWallet(wallet); + wallet_enc.setPassphrase('passphrase'); + + const ok = wallet_enc.saveWallet(mockWallet); + expect(ok).toBe(true); + }); + it('should save a wallet', async () => { mockFs({}); const mockWallet = { mock: 0 }; @@ -270,6 +280,7 @@ describe('saveWallet', () => { mockFs({}); await keymaster.start({ gatekeeper, wallet: wallet_enc, cipher }); + wallet_enc.setWallet(wallet); wallet_enc.setPassphrase('passphrase'); const mockWallet1 = { mock: 1 }; @@ -306,6 +317,7 @@ describe('saveWallet', () => { fs.writeFileSync(walletFile, JSON.stringify(mockWallet, null, 4)); await keymaster.start({ gatekeeper, wallet: wallet_enc, cipher }); + wallet_enc.setWallet(wallet); wallet_enc.setPassphrase('passphrase'); try {