Skip to content

Commit f6b340a

Browse files
authored
feat(ironfish): Add passphrase to reset account methods (#5354)
* feat(ironfish): Add passphrase to reset account methods * feat(ironfish): Fix validation for passphrase * feat(ironfish): Update return type
1 parent 3e3b650 commit f6b340a

File tree

5 files changed

+159
-4
lines changed

5 files changed

+159
-4
lines changed

ironfish/src/rpc/routes/wallet/resetAccount.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type ResetAccountRequest = {
1111
account: string
1212
resetCreatedAt?: boolean
1313
resetScanningEnabled?: boolean
14+
passphrase?: string
1415
}
1516
export type ResetAccountResponse = undefined
1617

@@ -19,6 +20,7 @@ export const ResetAccountRequestSchema: yup.ObjectSchema<ResetAccountRequest> =
1920
account: yup.string().defined(),
2021
resetCreatedAt: yup.boolean(),
2122
resetScanningEnabled: yup.boolean(),
23+
passphrase: yup.string().optional(),
2224
})
2325
.defined()
2426

@@ -37,6 +39,7 @@ routes.register<typeof ResetAccountRequestSchema, ResetAccountResponse>(
3739
await context.wallet.resetAccount(account, {
3840
resetCreatedAt: request.data.resetCreatedAt,
3941
resetScanningEnabled: request.data.resetScanningEnabled,
42+
passphrase: request.data.passphrase,
4043
})
4144

4245
request.end()

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

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7917,5 +7917,98 @@
79177917
"sequence": 1
79187918
}
79197919
}
7920+
],
7921+
"Wallet resetAccount should throw an error if the wallet is encrypted and the passphrase is not provided": [
7922+
{
7923+
"value": {
7924+
"encrypted": false,
7925+
"version": 4,
7926+
"id": "cfadf46a-dc13-4e7f-81e7-d74128b1cdbb",
7927+
"name": "A",
7928+
"spendingKey": "852f1b373ef781f1d29d9e9f39c9473f70f7603d871e442f76b227bba6d52cda",
7929+
"viewKey": "925996d92ca97ce6a76a9b9e4b167e2ba091d692205b6f70a160c1b355f59008a8b20cded41314b7b015450ad61c854badff212a6f210ca43937fb5755a2b024",
7930+
"incomingViewKey": "d098c5ff87958c2b3a855376ed8c6d41ddc23cf526ed5a352401ca91bdd5fa05",
7931+
"outgoingViewKey": "11ff38cfea5f9cd8be6f3bc04db871b77abc396b0cc3a1f01c944cb379ffcb0b",
7932+
"publicAddress": "ffd363ed6c09d9f3bee23c9da20f344e122c1f57cf07d163d38696d89c042785",
7933+
"createdAt": {
7934+
"hash": {
7935+
"type": "Buffer",
7936+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7937+
},
7938+
"sequence": 1
7939+
},
7940+
"scanningEnabled": true,
7941+
"proofAuthorizingKey": "1523258397a7359553b9a39cdd226eb92b11f2dd6d2376b3e33441b3db2c9803"
7942+
},
7943+
"head": {
7944+
"hash": {
7945+
"type": "Buffer",
7946+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7947+
},
7948+
"sequence": 1
7949+
}
7950+
}
7951+
],
7952+
"Wallet resetAccount should throw an error if the wallet is encrypted and the passphrase is incorrect": [
7953+
{
7954+
"value": {
7955+
"encrypted": false,
7956+
"version": 4,
7957+
"id": "e20a4166-8927-4d6e-8334-c38f14865a77",
7958+
"name": "A",
7959+
"spendingKey": "e0b052fdbab001478ffeb1fba279f7f89da1e4ff10e0fcd832b7be3263377e1f",
7960+
"viewKey": "d10d54e76cf646764de5bcc2761bbb7dd6d4585d3dabd11e3aa6736c0ee578876dfd7f312f32b12e9ff937956a4c24a595fc733bc18918c87f474f8fef57a046",
7961+
"incomingViewKey": "840566453558f7effbf43575d083203a24c7658995befab02927343a1515fa00",
7962+
"outgoingViewKey": "e5e2d8e98d4aa87be1faec3ed52b7ac48b4521f9c94a12910d562edc31fa8dfd",
7963+
"publicAddress": "3c47269fd0adc92a752ab55c85a49525a89ed48d46ccefa99dc2ed232d0f7556",
7964+
"createdAt": {
7965+
"hash": {
7966+
"type": "Buffer",
7967+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7968+
},
7969+
"sequence": 1
7970+
},
7971+
"scanningEnabled": true,
7972+
"proofAuthorizingKey": "4b1edb19d77dfeb2806d1a7bab98e562c75d0e9569eba5088b4e2f498d8b5707"
7973+
},
7974+
"head": {
7975+
"hash": {
7976+
"type": "Buffer",
7977+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7978+
},
7979+
"sequence": 1
7980+
}
7981+
}
7982+
],
7983+
"Wallet resetAccount save the encrypted account when the wallet is encrypted and passphrase is valid": [
7984+
{
7985+
"value": {
7986+
"encrypted": false,
7987+
"version": 4,
7988+
"id": "e75f5d8e-0338-400b-b166-31d0ba82b827",
7989+
"name": "A",
7990+
"spendingKey": "d4fd92b66615797fe372d90b5124b655d4b98489bc51de6ab62438640f8271e4",
7991+
"viewKey": "8997adb9c4271b2ce8c56d9444cad37bbcc8eba3a7aa55577a88d9661c097fdadee9ae53f5830acbccb39d7567bd21867132bf831ef40bd9542562304b64980c",
7992+
"incomingViewKey": "d589e64e471a7c588ae4906cd370c6fdc1d7eb25d6bab676fe17952625bab104",
7993+
"outgoingViewKey": "2d37c9ff2e401a3000c1f5c19463708923bc143c947a77fc9413f5852e40d34a",
7994+
"publicAddress": "31df6b319421f1108114f0efe9ac6b8479ec3a4cfe52f10fb0f4a7131e1ef948",
7995+
"createdAt": {
7996+
"hash": {
7997+
"type": "Buffer",
7998+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
7999+
},
8000+
"sequence": 1
8001+
},
8002+
"scanningEnabled": true,
8003+
"proofAuthorizingKey": "a27afb3eb769e16db0fb0a4feddc63c881da6bd194d6d0ea505971000468b203"
8004+
},
8005+
"head": {
8006+
"hash": {
8007+
"type": "Buffer",
8008+
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
8009+
},
8010+
"sequence": 1
8011+
}
8012+
}
79208013
]
79218014
}

ironfish/src/wallet/wallet.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,6 +2421,48 @@ describe('Wallet', () => {
24212421

24222422
expect(newAccount.scanningEnabled).toBe(true)
24232423
})
2424+
2425+
it('should throw an error if the wallet is encrypted and the passphrase is not provided', async () => {
2426+
const { node } = await nodeTest.createSetup()
2427+
const passphrase = 'foo'
2428+
2429+
const account = await useAccountFixture(node.wallet, 'A')
2430+
await node.wallet.encrypt(passphrase)
2431+
2432+
await expect(node.wallet.resetAccount(account)).rejects.toThrow()
2433+
})
2434+
2435+
it('should throw an error if the wallet is encrypted and the passphrase is incorrect', async () => {
2436+
const { node } = await nodeTest.createSetup()
2437+
const passphrase = 'foo'
2438+
2439+
const account = await useAccountFixture(node.wallet, 'A')
2440+
await node.wallet.encrypt(passphrase)
2441+
2442+
await expect(
2443+
node.wallet.resetAccount(account, { passphrase: 'incorrect' }),
2444+
).rejects.toThrow()
2445+
})
2446+
2447+
it('save the encrypted account when the wallet is encrypted and passphrase is valid', async () => {
2448+
const { node } = await nodeTest.createSetup()
2449+
const passphrase = 'foo'
2450+
2451+
const account = await useAccountFixture(node.wallet, 'A')
2452+
await node.wallet.encrypt(passphrase)
2453+
2454+
await node.wallet.resetAccount(account, { passphrase })
2455+
2456+
const newAccount = node.wallet.getAccountByName(account.name)
2457+
Assert.isNotNull(newAccount)
2458+
2459+
const encryptedAccount = node.wallet.encryptedAccountById.get(newAccount.id)
2460+
Assert.isNotUndefined(encryptedAccount)
2461+
2462+
const decryptedAccount = encryptedAccount.decrypt(passphrase)
2463+
expect(decryptedAccount.name).toEqual(account.name)
2464+
expect(decryptedAccount.spendingKey).toEqual(account.spendingKey)
2465+
})
24242466
})
24252467

24262468
describe('getTransactionType', () => {

ironfish/src/wallet/wallet.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,16 +352,18 @@ export class Wallet {
352352
options?: {
353353
resetCreatedAt?: boolean
354354
resetScanningEnabled?: boolean
355+
passphrase?: string
355356
},
356357
tx?: IDatabaseTransaction,
357358
): Promise<void> {
358359
await this.resetAccounts(options, tx)
359360
}
360361

361-
resetAccounts(
362+
async resetAccounts(
362363
options?: {
363364
resetCreatedAt?: boolean
364365
resetScanningEnabled?: boolean
366+
passphrase?: string
365367
},
366368
tx?: IDatabaseTransaction,
367369
): Promise<void> {
@@ -1517,6 +1519,7 @@ export class Wallet {
15171519
options?: {
15181520
resetCreatedAt?: boolean
15191521
resetScanningEnabled?: boolean
1522+
passphrase?: string
15201523
},
15211524
tx?: IDatabaseTransaction,
15221525
): Promise<void> {
@@ -1534,7 +1537,19 @@ export class Wallet {
15341537
this.logger.debug(`Resetting account name: ${account.name}, id: ${account.id}`)
15351538

15361539
await this.walletDb.db.withTransaction(tx, async (tx) => {
1537-
await this.walletDb.setAccount(newAccount, tx)
1540+
const encrypted = await this.walletDb.accountsEncrypted(tx)
1541+
1542+
if (encrypted) {
1543+
Assert.isNotUndefined(options?.passphrase)
1544+
const encryptedAccount = await this.walletDb.setEncryptedAccount(
1545+
newAccount,
1546+
options.passphrase,
1547+
tx,
1548+
)
1549+
this.encryptedAccountById.set(newAccount.id, encryptedAccount)
1550+
} else {
1551+
await this.walletDb.setAccount(newAccount, tx)
1552+
}
15381553

15391554
if (newAccount.createdAt !== null) {
15401555
const previousBlock = await this.chainGetBlock({

ironfish/src/wallet/walletdb/walletdb.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ export class WalletDB {
372372
account: Account,
373373
passphrase: string,
374374
tx?: IDatabaseTransaction,
375-
): Promise<void> {
376-
await this.db.withTransaction(tx, async (tx) => {
375+
): Promise<EncryptedAccount> {
376+
return this.db.withTransaction(tx, async (tx) => {
377377
const accountsEncrypted = await this.accountsEncrypted(tx)
378378
if (!accountsEncrypted) {
379379
throw new Error('Cannot save encrypted account when accounts are decrypted')
@@ -401,6 +401,8 @@ export class WalletDB {
401401
tx,
402402
)
403403
}
404+
405+
return encryptedAccount
404406
})
405407
}
406408

0 commit comments

Comments
 (0)