-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reject
Swap
approvals with foreign claim addresses (#821)
* Fix mock typing * Assert valid swaps when authorizing a transaction * Fix typings issues * Rename helper * Simply accept an Address * Create new isControlledAddress helper * Fix mock * Use the new helper * Remove claim address from SwapViewComponent * Simplify syntax * Rename helper * Add back claim address to UI
- Loading branch information
1 parent
6798f17
commit 2479c24
Showing
13 changed files
with
220 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
...ter/src/grpc/custody/authorize/assert-swap-claim-addresses-belong-to-current-user.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { assertSwapClaimAddressesBelongToCurrentUser } from './assert-swap-claim-addresses-belong-to-current-user'; | ||
import { | ||
ActionPlan, | ||
TransactionPlan, | ||
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; | ||
import { Code, ConnectError } from '@connectrpc/connect'; | ||
import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; | ||
|
||
const currentUserAddress1 = new Address({ | ||
inner: new Uint8Array([1, 2, 3]), | ||
}); | ||
|
||
const currentUserAddress2 = new Address({ | ||
inner: new Uint8Array([4, 5, 6]), | ||
}); | ||
|
||
const otherUserAddress = new Address({ | ||
inner: new Uint8Array([7, 8, 9]), | ||
}); | ||
|
||
const swapWithCurrentUserAddress1 = new ActionPlan({ | ||
action: { | ||
case: 'swap', | ||
value: { | ||
swapPlaintext: { | ||
claimAddress: currentUserAddress1, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const swapWithCurrentUserAddress2 = new ActionPlan({ | ||
action: { | ||
case: 'swap', | ||
value: { | ||
swapPlaintext: { | ||
claimAddress: currentUserAddress2, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const swapWithOtherUserAddress = new ActionPlan({ | ||
action: { | ||
case: 'swap', | ||
value: { | ||
swapPlaintext: { | ||
claimAddress: otherUserAddress, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const swapWithUndefinedAddress = new ActionPlan({ | ||
action: { | ||
case: 'swap', | ||
value: { | ||
swapPlaintext: {}, | ||
}, | ||
}, | ||
}); | ||
|
||
const mockIsControlledAddress = (address?: Address) => | ||
!!address && [currentUserAddress1, currentUserAddress2].includes(address); | ||
|
||
describe('assertSwapClaimAddressesBelongToCurrentUser()', () => { | ||
describe('when the transaction plan has no swaps', () => { | ||
it('does not throw', () => { | ||
expect(() => | ||
assertSwapClaimAddressesBelongToCurrentUser(new TransactionPlan(), mockIsControlledAddress), | ||
).not.toThrow(); | ||
}); | ||
}); | ||
|
||
describe('when the transaction plan has swaps', () => { | ||
describe("when all of the swaps' `claimAddress`es belong to the current user", () => { | ||
it('does not throw', () => { | ||
const plan = new TransactionPlan({ | ||
actions: [swapWithCurrentUserAddress1, swapWithCurrentUserAddress2], | ||
}); | ||
|
||
expect(() => | ||
assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress), | ||
).not.toThrow(); | ||
}); | ||
}); | ||
|
||
describe("when any of the swaps' `claimAddress`es do not belong to the current user", () => { | ||
it('throws a `ConnectError` with the `PermissionDenied` code', () => { | ||
const plan = new TransactionPlan({ | ||
actions: [swapWithCurrentUserAddress1, swapWithOtherUserAddress], | ||
}); | ||
|
||
expect.assertions(2); | ||
|
||
try { | ||
assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress); | ||
} catch (error) { | ||
expect(error).toBeInstanceOf(ConnectError); | ||
expect((error as ConnectError).code).toBe(Code.PermissionDenied); | ||
} | ||
}); | ||
}); | ||
|
||
describe("when any of the swaps' `claimAddress`es are empty", () => { | ||
it('throws a `ConnectError` with the `PermissionDenied` code', () => { | ||
const plan = new TransactionPlan({ | ||
actions: [swapWithUndefinedAddress], | ||
}); | ||
|
||
expect.assertions(2); | ||
|
||
try { | ||
assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress); | ||
} catch (error) { | ||
expect(error).toBeInstanceOf(ConnectError); | ||
expect((error as ConnectError).code).toBe(Code.PermissionDenied); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
19 changes: 19 additions & 0 deletions
19
...s/router/src/grpc/custody/authorize/assert-swap-claim-addresses-belong-to-current-user.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; | ||
import { TransactionPlan } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; | ||
import { Code, ConnectError } from '@connectrpc/connect'; | ||
|
||
export const assertSwapClaimAddressesBelongToCurrentUser = ( | ||
plan: TransactionPlan, | ||
isControlledAddress: (address?: Address) => boolean, | ||
): void => { | ||
plan.actions.forEach(action => { | ||
if (action.action.case !== 'swap') return; | ||
|
||
if (!isControlledAddress(action.action.value.swapPlaintext?.claimAddress)) { | ||
throw new ConnectError( | ||
"Tried to initiate a swap with a claim address belonging to a different user. This means that, when the swap is claimed, the funds would go to someone else's address, not yours. This should never happen. The website you are using may be trying to steal your funds!", | ||
Code.PermissionDenied, | ||
); | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 11 additions & 3 deletions
14
...ages/router/src/grpc/custody/authorize.ts → ...outer/src/grpc/custody/authorize/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.