Skip to content

Commit

Permalink
feat(ironfish): Require passphrase when renaming encrypted accounts (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanjadvani authored Sep 5, 2024
1 parent df7be6f commit 22db8b3
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 5 deletions.
2 changes: 1 addition & 1 deletion ironfish/src/rpc/routes/wallet/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ routes.register<typeof RenameAccountRequestSchema, RenameAccountResponse>(
AssertHasRpcContext(request, context, 'wallet')

const account = getAccount(context.wallet, request.data.account)
await account.setName(request.data.newName)
await account.setName(request.data.newName, { passphrase: request.data.passphrase })
request.end()
},
)
5 changes: 3 additions & 2 deletions ironfish/src/rpc/routes/wallet/renameAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import { routes } from '../router'
import { AssertHasRpcContext } from '../rpcContext'
import { getAccount } from './utils'

export type RenameAccountRequest = { account: string; newName: string }
export type RenameAccountRequest = { account: string; newName: string; passphrase?: string }
export type RenameAccountResponse = undefined

export const RenameAccountRequestSchema: yup.ObjectSchema<RenameAccountRequest> = yup
.object({
account: yup.string().defined(),
newName: yup.string().defined(),
passphrase: yup.string().optional(),
})
.defined()

Expand All @@ -28,7 +29,7 @@ routes.register<typeof RenameAccountRequestSchema, RenameAccountResponse>(
AssertHasRpcContext(request, context, 'wallet')

const account = getAccount(context.wallet, request.data.account)
await account.setName(request.data.newName)
await account.setName(request.data.newName, { passphrase: request.data.passphrase })
request.end()
},
)
93 changes: 93 additions & 0 deletions ironfish/src/wallet/account/__fixtures__/account.test.ts.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -5903,5 +5903,98 @@
"sequence": 1
}
}
],
"Accounts setName should throw an error if the passphrase is missing and the wallet is encrypted": [
{
"value": {
"encrypted": false,
"version": 4,
"id": "6f0698b4-a99c-46aa-9391-59f0c55cd755",
"name": "accountA",
"spendingKey": "89001fcdef6bff7e9fd76d4ae6275bf6786afc2797eded9df094ae4a6894782d",
"viewKey": "389bc77ae499f3edc0dc445a732add6f36c275b260efe2c791cc515f6c2c0cd75f5b31e9b1f82edb0ee57b9304ece90d48f43c36d78660b04960b9692485d058",
"incomingViewKey": "fdd70ff012b4e48576bdd71207ebe1e3747811c77fa1a25862c3b869123ce007",
"outgoingViewKey": "9664b763a0418a476d072c715fcbbba58bcaf60cc951ba017195d75453131f11",
"publicAddress": "14a9bfb247dcf632f85ff79ebef222cc9ccf364f9b3e3e0ee39b75d68f80782a",
"createdAt": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
},
"scanningEnabled": true,
"proofAuthorizingKey": "8c11ae2523136f4b11bada56d9bcab2b6591cc99cf7aede8a238c5fefd7fce0d"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
}
}
],
"Accounts setName should throw an error if the passphrase is incorrect and the wallet is encrypted": [
{
"value": {
"encrypted": false,
"version": 4,
"id": "92b122e5-9f14-453b-a364-e20a7d107305",
"name": "accountA",
"spendingKey": "3d68ebfd3d600792fc94d583bbab97ab4d02b9f41aa2a6655e151e41d4a33d8d",
"viewKey": "51e699920432cf221351568ade21fb8af4110c7ad57ad90cc2664340d50d6f207a19eb846feb76588f467e4dce99d0da074ca680aca11d3d8c91bd47ae5d9081",
"incomingViewKey": "15f8cb20e3a7b494474f4c4737bc0403dbb5de6e532e2c83a4469cd7f95f5b02",
"outgoingViewKey": "fc1b2e0e85cca6ddaf657baf2c69c76b403afe1adadd73b794c5cb81724d240d",
"publicAddress": "899ea1e9be7202aedab0a41f6b9cf661ce20e41ba11c1ee9d15ac64d8c96a391",
"createdAt": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
},
"scanningEnabled": true,
"proofAuthorizingKey": "d0d08a05953a50a0ce8b35e0c410b7dde77e3bf6099aaa4fc413de2096f7ef0a"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
}
}
],
"Accounts setName should save the encrypted account if the passphrase is correct and the wallet is encrypted": [
{
"value": {
"encrypted": false,
"version": 4,
"id": "1dd7e196-ffed-4fe0-8dbd-c49f82bf44b7",
"name": "accountA",
"spendingKey": "71ec323628c95bd56df353ec444b8ceb3d463603e82a89d4ac3336bdf630993a",
"viewKey": "5219abc719ecb8954e77d89e60f4fc82588e8f619ba4da38b53ed0471aeccb200cc7cec29ca533c769c96213417f78ccfaf2ba3f12a4b948a0da242805eb044c",
"incomingViewKey": "d9d70e59490b44c078300a23376e4fc516b47a31231c77538d17740f399e3d00",
"outgoingViewKey": "e3eca4b31e0d4b48e27458db2eff35b4d713d84b0b07505fdc8d49b2e40ab69d",
"publicAddress": "fbc47fe75ef9534b28b95fd17288488b89a4b752191a323a3703520095e8c24b",
"createdAt": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
},
"scanningEnabled": true,
"proofAuthorizingKey": "f335356ed8f77c4facebc2ad9377ab05e6d71ec83aa772df0c23e2733458a10c"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
}
}
]
}
44 changes: 44 additions & 0 deletions ironfish/src/wallet/account/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { AsyncUtils } from '../../utils/async'
import { BalanceValue } from '../walletdb/balanceValue'
import { Account } from './account'
import { EncryptedAccount } from './encryptedAccount'

describe('Accounts', () => {
const nodeTest = createNodeTest()
Expand Down Expand Up @@ -186,6 +187,49 @@ describe('Accounts', () => {
await expect(account.setName('')).rejects.toThrow('Account name cannot be blank')
await expect(account.setName(' ')).rejects.toThrow('Account name cannot be blank')
})

it('should throw an error if the passphrase is missing and the wallet is encrypted', async () => {
const { node } = nodeTest
const passphrase = 'foo'

const account = await useAccountFixture(node.wallet, 'accountA')
await node.wallet.encrypt(passphrase)

await expect(account.setName('B')).rejects.toThrow()
})

it('should throw an error if the passphrase is incorrect and the wallet is encrypted', async () => {
const { node } = nodeTest
const passphrase = 'foo'

const account = await useAccountFixture(node.wallet, 'accountA')
await node.wallet.encrypt(passphrase)

await expect(account.setName('B', { passphrase: 'incorrect ' })).rejects.toThrow()
})

it('should save the encrypted account if the passphrase is correct and the wallet is encrypted', async () => {
const { node } = nodeTest
const passphrase = 'foo'
const newName = 'B'

const account = await useAccountFixture(node.wallet, 'accountA')
await node.wallet.encrypt(passphrase)

await account.setName(newName, { passphrase })

const accountValue = await node.wallet.walletDb.accounts.get(account.id)
Assert.isNotUndefined(accountValue)
Assert.isTrue(accountValue.encrypted)

const encryptedAccount = new EncryptedAccount({
data: accountValue.data,
walletDb: node.wallet.walletDb,
})
const decryptedAccount = encryptedAccount.decrypt(passphrase)

expect(decryptedAccount.name).toEqual(newName)
})
})

describe('loadPendingTransactions', () => {
Expand Down
15 changes: 13 additions & 2 deletions ironfish/src/wallet/account/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,25 @@ export class Account {
}
}

async setName(name: string, tx?: IDatabaseTransaction): Promise<void> {
async setName(
name: string,
options?: { passphrase?: string },
tx?: IDatabaseTransaction,
): Promise<void> {
if (!name.trim()) {
throw new Error('Account name cannot be blank')
}

const walletEncrypted = await this.walletDb.accountsEncrypted(tx)

this.name = name

await this.walletDb.setAccount(this, tx)
if (walletEncrypted) {
Assert.isNotUndefined(options?.passphrase)
await this.walletDb.setEncryptedAccount(this, options.passphrase, tx)
} else {
await this.walletDb.setAccount(this, tx)
}
}

async *getNotes(
Expand Down

0 comments on commit 22db8b3

Please sign in to comment.