Skip to content

Commit 08c1066

Browse files
authored
feat(ironfish): Add passphrase to import account for encrypted dbs (#5352)
* feat(ironfish): Add passphrase to import account for encrypted dbs * feat(ironfish): Move valid passphrase check to db
1 parent 67a8f6e commit 08c1066

File tree

6 files changed

+482
-6
lines changed

6 files changed

+482
-6
lines changed

ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7824,5 +7824,98 @@
78247824
}
78257825
]
78267826
}
7827+
],
7828+
"Wallet importAccount should throw an error when the wallet is encrypted and there is no passphrase": [
7829+
{
7830+
"value": {
7831+
"encrypted": false,
7832+
"version": 4,
7833+
"id": "a01a5314-b884-444b-8eec-c47aa8492756",
7834+
"name": "A",
7835+
"spendingKey": "ad2eddc5a1dc1230df218496213ca6c6382118d96d2c8ffaf384cf76bb832fbe",
7836+
"viewKey": "564c0f3f9b408d26e472300f7db570f08255df2b90b97dc41438f0ed9c85b698c5626317e4209ac92e44ef4f824ae9606e721bbfcc6410be388c0d5800188768",
7837+
"incomingViewKey": "34cb22d6ee1babef87814ab2c2ad4289eb1aa26273a8726379c5e7b1f06d4b03",
7838+
"outgoingViewKey": "8c474949652b7890d821edce628b53c753c1f96d558d3bca80ab2ed75bf44a76",
7839+
"publicAddress": "e46acb643c937f7d370046d710383c84cbab530f979c650f4f692121ffdd730e",
7840+
"createdAt": {
7841+
"hash": {
7842+
"type": "Buffer",
7843+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7844+
},
7845+
"sequence": 1
7846+
},
7847+
"scanningEnabled": true,
7848+
"proofAuthorizingKey": "2cd5ee2aa54f226ef01b6e50882c8d366fc6e20106a6165995b29cd7feb64609"
7849+
},
7850+
"head": {
7851+
"hash": {
7852+
"type": "Buffer",
7853+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7854+
},
7855+
"sequence": 1
7856+
}
7857+
}
7858+
],
7859+
"Wallet importAccount should encrypt and store the account if the wallet is encrypted": [
7860+
{
7861+
"value": {
7862+
"encrypted": false,
7863+
"version": 4,
7864+
"id": "49e2a0d9-797c-4e00-be2e-30bb721c7abc",
7865+
"name": "A",
7866+
"spendingKey": "4a7bb3f99b2179be0c2d8ed2e64c777db53373fe7591ce3f7af1f646645f2669",
7867+
"viewKey": "b6be34f85957f7da7c357b96295b8456f8d6abd7e00c9fa6b804990a0f3c5c066899f395efc2e88d1d2f61b6e1ef1be4c3c7914005bf08e295153c3a634f9d00",
7868+
"incomingViewKey": "6fd24b8877ab029879f6c185d089a57fa155f13cdf4d3fe2608e849c2e7dce04",
7869+
"outgoingViewKey": "babbc58950db472c941fc697cc167e8095770b29c33de07c389b54e4ed26a012",
7870+
"publicAddress": "1b542a7505e93228fca0e5c31708fb0e1da57f5c992b3acc594ca7db1679e86a",
7871+
"createdAt": {
7872+
"hash": {
7873+
"type": "Buffer",
7874+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7875+
},
7876+
"sequence": 1
7877+
},
7878+
"scanningEnabled": true,
7879+
"proofAuthorizingKey": "443dff9087d0f23a139cd3ef3bb5065436f4a7cbe0fd68ed73f6be3cce0f400e"
7880+
},
7881+
"head": {
7882+
"hash": {
7883+
"type": "Buffer",
7884+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7885+
},
7886+
"sequence": 1
7887+
}
7888+
}
7889+
],
7890+
"Wallet importAccount should throw an error when the wallet is encrypted and the passphrase is incorrect": [
7891+
{
7892+
"value": {
7893+
"encrypted": false,
7894+
"version": 4,
7895+
"id": "f314a1b1-2f72-4cdb-b642-1846639885df",
7896+
"name": "A",
7897+
"spendingKey": "d27ae281a962d050b624cc11f0c575e19e270b095e94fa7f2e225984263bb98d",
7898+
"viewKey": "8e56b51f4f2f9bdc084ba04b192550458114750dca61942b8f148ae8af0c2320647305a1a1770c56fc2bde2b36e7f5ed7927b6ffe272db5def306aa2df9639c3",
7899+
"incomingViewKey": "2629fceae11c0b2d2b56a1f918947533f1c1fbe7b45be4c77527970aa877e701",
7900+
"outgoingViewKey": "a90418c4fb17dd151a5678c58cbc0cd0134d9245b1597d48709464a0154a07c2",
7901+
"publicAddress": "dc4182b4a354566727d3b8e41287b6c89028cae6129360447f40dcb2212a284d",
7902+
"createdAt": {
7903+
"hash": {
7904+
"type": "Buffer",
7905+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7906+
},
7907+
"sequence": 1
7908+
},
7909+
"scanningEnabled": true,
7910+
"proofAuthorizingKey": "e47274a4b3cd00b89727106857ad3dfe8ed1c2b94b95721a6d08bdd702d73101"
7911+
},
7912+
"head": {
7913+
"hash": {
7914+
"type": "Buffer",
7915+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7916+
},
7917+
"sequence": 1
7918+
}
7919+
}
78277920
]
78287921
}

ironfish/src/wallet/wallet.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
} from './errors'
3131
import { toAccountImport } from './exporter'
3232
import { AssetStatus, Wallet } from './wallet'
33+
import { DecryptedAccountValue } from './walletdb/accountValue'
3334

3435
describe('Wallet', () => {
3536
const nodeTest = createNodeTest()
@@ -651,6 +652,77 @@ describe('Wallet', () => {
651652

652653
expect(accountBImport.createdAt).toBeDefined()
653654
})
655+
656+
it('should throw an error when the wallet is encrypted and there is no passphrase', async () => {
657+
const { node } = await nodeTest.createSetup()
658+
const passphrase = 'foo'
659+
660+
await useAccountFixture(node.wallet, 'A')
661+
await node.wallet.encrypt(passphrase)
662+
663+
const key = generateKey()
664+
const accountValue: DecryptedAccountValue = {
665+
encrypted: false,
666+
id: '0',
667+
name: 'new-account',
668+
version: 1,
669+
createdAt: null,
670+
scanningEnabled: false,
671+
...key,
672+
}
673+
674+
await expect(node.wallet.importAccount(accountValue)).rejects.toThrow()
675+
})
676+
677+
it('should throw an error when the wallet is encrypted and the passphrase is incorrect', async () => {
678+
const { node } = await nodeTest.createSetup()
679+
const passphrase = 'foo'
680+
681+
await useAccountFixture(node.wallet, 'A')
682+
await node.wallet.encrypt(passphrase)
683+
684+
const key = generateKey()
685+
const accountValue: DecryptedAccountValue = {
686+
encrypted: false,
687+
id: '0',
688+
name: 'new-account',
689+
version: 1,
690+
createdAt: null,
691+
scanningEnabled: false,
692+
...key,
693+
}
694+
695+
await expect(
696+
node.wallet.importAccount(accountValue, { passphrase: 'incorrect' }),
697+
).rejects.toThrow('Your passphrase is incorrect')
698+
})
699+
700+
it('should encrypt and store the account if the wallet is encrypted', async () => {
701+
const { node } = await nodeTest.createSetup()
702+
const passphrase = 'foo'
703+
704+
await useAccountFixture(node.wallet, 'A')
705+
await node.wallet.encrypt(passphrase)
706+
707+
const key = generateKey()
708+
const accountValue: DecryptedAccountValue = {
709+
encrypted: false,
710+
id: '0',
711+
name: 'new-account',
712+
version: 1,
713+
createdAt: null,
714+
scanningEnabled: false,
715+
...key,
716+
}
717+
718+
const account = await node.wallet.importAccount(accountValue, { passphrase })
719+
expect(account.name).toEqual(accountValue.name)
720+
expect(account.viewKey).toEqual(key.viewKey)
721+
expect(account.incomingViewKey).toEqual(key.incomingViewKey)
722+
expect(account.outgoingViewKey).toEqual(key.outgoingViewKey)
723+
expect(account.spendingKey).toEqual(key.spendingKey)
724+
expect(account.publicAddress).toEqual(key.publicAddress)
725+
})
654726
})
655727

656728
describe('expireTransactions', () => {

ironfish/src/wallet/wallet.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,7 @@ export class Wallet {
13971397

13981398
async importAccount(
13991399
accountValue: AccountImport,
1400-
options?: { createdAt?: number },
1400+
options?: { createdAt?: number; passphrase?: string },
14011401
): Promise<Account> {
14021402
let multisigKeys = accountValue.multisigKeys
14031403
const name = accountValue.name
@@ -1468,7 +1468,14 @@ export class Wallet {
14681468
})
14691469

14701470
await this.walletDb.db.transaction(async (tx) => {
1471-
await this.walletDb.setAccount(account, tx)
1471+
const encrypted = await this.walletDb.accountsEncrypted(tx)
1472+
1473+
if (encrypted) {
1474+
Assert.isNotUndefined(options?.passphrase)
1475+
await this.walletDb.setEncryptedAccount(account, options.passphrase, tx)
1476+
} else {
1477+
await this.walletDb.setAccount(account, tx)
1478+
}
14721479

14731480
if (createdAt !== null) {
14741481
const previousBlock = await this.chainGetBlock({ sequence: createdAt.sequence - 1 })

ironfish/src/wallet/walletdb/__fixtures__/walletdb.test.ts.fixture

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,5 +1181,160 @@
11811181
"sequence": 1
11821182
}
11831183
}
1184+
],
1185+
"WalletDB setEncryptedAccount throws an error if existing accounts are decrypted": [
1186+
{
1187+
"value": {
1188+
"encrypted": false,
1189+
"version": 4,
1190+
"id": "0327e33a-b3f8-44de-9e31-f62c0b957ff9",
1191+
"name": "A",
1192+
"spendingKey": "4073e1efc8ca5779108f7e54033aec1d612a8423f0a2e3a4536af6a2223b08fd",
1193+
"viewKey": "e26e4085b6c0301b1cd8f0e9115e7eea63de80848b09476f304f002ba7365f5c0ab80794346f4b2185256543a5da0b9223824df459b1ccff8b03cf6ca6e4e5ac",
1194+
"incomingViewKey": "6f2ac227d5d4a5704839f4fccea70f2f37016c046e68c60d5234eebfc6eaf903",
1195+
"outgoingViewKey": "2b0364b99c1971d8a5cff5333c29b7c5b5b2164d20c6171944009bbb7cae038b",
1196+
"publicAddress": "614991cb72e5b0997f1311835aa8f15b723c234a819cf36b09121284a36c6909",
1197+
"createdAt": {
1198+
"hash": {
1199+
"type": "Buffer",
1200+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1201+
},
1202+
"sequence": 1
1203+
},
1204+
"scanningEnabled": true,
1205+
"proofAuthorizingKey": "1197fb366b1e4db881d28adb2aeac1546cb969cc0c2515c9efebfe995bc9a705"
1206+
},
1207+
"head": {
1208+
"hash": {
1209+
"type": "Buffer",
1210+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1211+
},
1212+
"sequence": 1
1213+
}
1214+
}
1215+
],
1216+
"WalletDB setEncryptedAccount saves the account": [
1217+
{
1218+
"value": {
1219+
"encrypted": false,
1220+
"version": 4,
1221+
"id": "2d4ff08d-b895-427f-b08e-7daf670f26a9",
1222+
"name": "A",
1223+
"spendingKey": "a6977d360e93d4210c8101eee39aa84d291b615f6dbdeb7d463901e4d4604b2b",
1224+
"viewKey": "49f2ae0a4f8efb153fdaedf92067f60829ad6c3fe946a08ca54594fd145d63894997083e2e9f20780bff1bf36237d0bf6ab2b0683de8756abe89b18cced457e9",
1225+
"incomingViewKey": "cf24a9f69b4179bc336abf6827f493f64d970ddf91b2d121e7af94eedb1dfd07",
1226+
"outgoingViewKey": "2e7cd9c8c91e729c1c8f0597838bd34a2292daa3989e3194e12a131e962066ea",
1227+
"publicAddress": "9c4afe0900874d1c94955a21eb1bab1fb6e3ae310f79f407423341eaa8ea1467",
1228+
"createdAt": {
1229+
"hash": {
1230+
"type": "Buffer",
1231+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1232+
},
1233+
"sequence": 1
1234+
},
1235+
"scanningEnabled": true,
1236+
"proofAuthorizingKey": "216a960dfcc50b928b8d56cb3eb1e4aa536df07ba9d440dbb21c237e95c1cf02"
1237+
},
1238+
"head": {
1239+
"hash": {
1240+
"type": "Buffer",
1241+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1242+
},
1243+
"sequence": 1
1244+
}
1245+
}
1246+
],
1247+
"WalletDB canDecryptAccounts throws an error if the accounts are decrypted": [
1248+
{
1249+
"value": {
1250+
"encrypted": false,
1251+
"version": 4,
1252+
"id": "acbb2960-da97-4cf8-b66a-8bf01ddaeb67",
1253+
"name": "A",
1254+
"spendingKey": "86635081a46875b009ad5f525a3b41e66c5ffca00f2ae97864ab4d398398dc7e",
1255+
"viewKey": "483f046c9e044e9110f371b6b4b09925d77077fc9df3f5d6510fe9da4e11ce473e9c198a40335c0687a744a49cc4a7c096c32bee370caf7562a3a3c59c6cdf73",
1256+
"incomingViewKey": "0d9d2bf42ea2d2f1d656533b9fe6d9797eb646a02f4effe3dcda3bc9d955ed03",
1257+
"outgoingViewKey": "f824913fcd864447bfedbcce962ef8e3309623f518b00cd67252267fb0bb3edd",
1258+
"publicAddress": "4f0198b74577e1a81fc23aff6f180e386eeabb38c3e5376f526908488a6b1833",
1259+
"createdAt": {
1260+
"hash": {
1261+
"type": "Buffer",
1262+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1263+
},
1264+
"sequence": 1
1265+
},
1266+
"scanningEnabled": true,
1267+
"proofAuthorizingKey": "ee9140e033b9336689556554006fd016153d6bc3bbbeee736fe4a527e66c6a04"
1268+
},
1269+
"head": {
1270+
"hash": {
1271+
"type": "Buffer",
1272+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1273+
},
1274+
"sequence": 1
1275+
}
1276+
}
1277+
],
1278+
"WalletDB canDecryptAccounts returns false if the passphrase is invalid": [
1279+
{
1280+
"value": {
1281+
"encrypted": false,
1282+
"version": 4,
1283+
"id": "6bef8a6e-d6e2-4448-bf24-21662211354d",
1284+
"name": "A",
1285+
"spendingKey": "ec168ca1316b3bf7cf0cdf0a3adecf9b7972e6ae156a729f2719ac4e157c6da4",
1286+
"viewKey": "0ce8d5f8a3c8b2073178f59a3870db54332f93b8ae0d20c773c8128021c6a93771bff1b891392e16feed8ded0f9ca05af870526f4326f6249def2675604653ae",
1287+
"incomingViewKey": "81ef82de4bd28b919f710e8782feb30d394d94137eb5a031e4c4f5d003afa404",
1288+
"outgoingViewKey": "aaea23ee6e02849596138db4623b59a2303d271c5279e7d0a834804e5a13ae97",
1289+
"publicAddress": "686d8506997e2a6ceb5a0b8311e8d4e6d9a273e151168cb0241adbf6df46f75c",
1290+
"createdAt": {
1291+
"hash": {
1292+
"type": "Buffer",
1293+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1294+
},
1295+
"sequence": 1
1296+
},
1297+
"scanningEnabled": true,
1298+
"proofAuthorizingKey": "a84451b5708e3349f33c6a9c77e3260409534e9c54f327968a464edff4a00408"
1299+
},
1300+
"head": {
1301+
"hash": {
1302+
"type": "Buffer",
1303+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1304+
},
1305+
"sequence": 1
1306+
}
1307+
}
1308+
],
1309+
"WalletDB canDecryptAccounts returns true if the passphrase is valid": [
1310+
{
1311+
"value": {
1312+
"encrypted": false,
1313+
"version": 4,
1314+
"id": "29a6dffb-eb57-418d-b748-2cb6b1544350",
1315+
"name": "A",
1316+
"spendingKey": "6d9175f29df2be3f8c7df0187e0b2197b31001209c22813b289e86894d054564",
1317+
"viewKey": "bbefff5ef688ac872511b1e3560dfd81af1d316b34ea177152edc2f31531bf9e50e0df53ab8f0bfde8e6b0f3cd85566cddb745c418fb8f13a10ad8f293b0e36d",
1318+
"incomingViewKey": "5d5a144161b657eea271b8d6242b9ba674938adaf10805d159cdf88bf7c18906",
1319+
"outgoingViewKey": "89e3e88af3d337bb79ac160c0358261e282bcafdc9fc6473b5cc676107f80b6d",
1320+
"publicAddress": "af2ba2cdf2fae3074d30e363e9027fa8bb36ec932cd233fd246d2a623691e612",
1321+
"createdAt": {
1322+
"hash": {
1323+
"type": "Buffer",
1324+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1325+
},
1326+
"sequence": 1
1327+
},
1328+
"scanningEnabled": true,
1329+
"proofAuthorizingKey": "01dfdc97107f322332ad1300e236f9c377cbc7b5e0c9ed327b403bd6ceb08a03"
1330+
},
1331+
"head": {
1332+
"hash": {
1333+
"type": "Buffer",
1334+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
1335+
},
1336+
"sequence": 1
1337+
}
1338+
}
11841339
]
11851340
}

0 commit comments

Comments
 (0)