mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-08-12 01:17:43 +00:00
Improved validation of keysets provided by the mints
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
||||
0198388d-d8dc-72f2-b3e1-89f896656f07
|
||||
0198586c-6212-732d-a2cb-cf9537d9aab3
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "minibits_wallet",
|
||||
"version": "0.2.2-beta.29",
|
||||
"version": "0.2.2-beta.30",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android:clean": "cd android && ./gradlew clean",
|
||||
|
||||
@@ -39,21 +39,24 @@ export const ErrorModal: FC<ErrorModalProps> = function ({ error }) {
|
||||
}
|
||||
}
|
||||
|
||||
const backgroundColor = useThemeColor('error')
|
||||
const bg = useThemeColor('error')
|
||||
|
||||
return (
|
||||
<BottomModal
|
||||
isVisible={isErrorVisible}
|
||||
onBackdropPress={onClose}
|
||||
onBackButtonPress={onClose}
|
||||
style={{ backgroundColor }}
|
||||
onBackButtonPress={onClose}
|
||||
ContentComponent={
|
||||
<>
|
||||
<>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: spacing.small }}>
|
||||
<Icon icon="faInfoCircle" size={spacing.large} color="white" />
|
||||
<Icon icon="faTriangleExclamation" size={spacing.large} color={bg} />
|
||||
<Text style={{ color: 'white', marginLeft: spacing.small }}>{error.name}</Text>
|
||||
</View>
|
||||
<ScrollView>
|
||||
<ScrollView
|
||||
style={{
|
||||
//height: spacing.screenHeight * 0.1,
|
||||
maxHeight: spacing.screenHeight * 0.07,
|
||||
}}>
|
||||
<Text style={{ color: 'white', marginBottom: spacing.small }}>{error.message}</Text>
|
||||
</ScrollView>
|
||||
{error.params && isObj(error.params) && (
|
||||
|
||||
+41
-37
@@ -222,51 +222,55 @@ export const MintModel = types
|
||||
}))
|
||||
.actions(self => ({
|
||||
initKeyset(keyset: CashuMintKeyset, allKeysetIds: string[]) {
|
||||
// ATTN: const mintsStore = getRootStore(self).mintsStore does not work here (may be because it is being called from within loop)
|
||||
|
||||
// Do not add unit the wallet does not have configured
|
||||
try {
|
||||
if(!self.isUnitSupported(keyset.unit as MintUnit)) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, `Unsupported unit provided by the mint: ${keyset.unit}`)
|
||||
}
|
||||
|
||||
const existing = self.keysets.find(k => k.id === keyset.id)
|
||||
|
||||
if(!self.isUnitSupported(keyset.unit as MintUnit)) {
|
||||
throw new AppError(
|
||||
Err.VALIDATION_ERROR,
|
||||
`Unsupported unit provided by the mint`,
|
||||
{caller: 'initKeyset', unit: keyset.unit}
|
||||
)
|
||||
}
|
||||
|
||||
const existing = self.keysets.find(k => k.id === keyset.id)
|
||||
|
||||
if(existing) {
|
||||
if (existing.unit !== keyset.unit) {
|
||||
throw new AppError(
|
||||
Err.VALIDATION_ERROR,
|
||||
`Keyset unit mismatch, got ${keyset.unit}, expected ${existing.unit}`,
|
||||
{caller: 'initKeyset'}
|
||||
)
|
||||
}
|
||||
|
||||
if(keyset.input_fee_ppk && existing.input_fee_ppk !== keyset.input_fee_ppk) {
|
||||
self.setInputFeePpk(existing.id, keyset.input_fee_ppk)
|
||||
}
|
||||
|
||||
return existing
|
||||
}
|
||||
|
||||
// Prevent keysetId collision with other mints
|
||||
if(CashuUtils.isCollidingKeysetId(keyset.id, allKeysetIds)) {
|
||||
if(existing) {
|
||||
if (existing.unit !== keyset.unit) {
|
||||
throw new AppError(
|
||||
Err.VALIDATION_ERROR,
|
||||
`KeysetId validation failed, collision detected for ${keyset.id}`,
|
||||
{caller: 'initKeyset'}
|
||||
)
|
||||
`Keyset unit mismatch.`,
|
||||
{caller: 'initKeyset', existingUnit: existing.unit, keysetUnit: keyset.unit}
|
||||
)
|
||||
}
|
||||
|
||||
if(!keyset.input_fee_ppk) {
|
||||
keyset.input_fee_ppk = 0
|
||||
if(keyset.input_fee_ppk && existing.input_fee_ppk !== keyset.input_fee_ppk) {
|
||||
self.setInputFeePpk(existing.id, keyset.input_fee_ppk)
|
||||
}
|
||||
|
||||
self.addKeyset(keyset)
|
||||
self.addUnit(keyset.unit as MintUnit)
|
||||
self.createProofsCounter(keyset)
|
||||
return existing
|
||||
}
|
||||
|
||||
log.trace('[initKeyset]', {newKeyset: keyset})
|
||||
} catch (e: any) {
|
||||
throw new AppError(Err.WALLET_ERROR, '[initKeyset] ' + e.message)
|
||||
}
|
||||
// Prevent keysetId collision with other mints
|
||||
if(CashuUtils.isCollidingKeysetId(keyset.id, allKeysetIds)) {
|
||||
throw new AppError(
|
||||
Err.VALIDATION_ERROR,
|
||||
`KeysetId validation failed, collision detected.`,
|
||||
{caller: 'initKeyset', keysetId: keyset.id}
|
||||
)
|
||||
}
|
||||
|
||||
if(!keyset.input_fee_ppk) {
|
||||
keyset.input_fee_ppk = 0
|
||||
}
|
||||
|
||||
self.addKeyset(keyset)
|
||||
self.addUnit(keyset.unit as MintUnit)
|
||||
self.createProofsCounter(keyset)
|
||||
|
||||
log.trace('[initKeyset]', {newKeyset: keyset})
|
||||
|
||||
},
|
||||
initKeys(key: CashuMintKeys) {
|
||||
// Do not add unit the wallet does not have configured
|
||||
@@ -432,7 +436,7 @@ export const MintModel = types
|
||||
const counters = self.proofsCounters.filter(c => c.inFlightRequests && c.inFlightRequests.length > 0)
|
||||
return counters as MintProofsCounter[]
|
||||
},
|
||||
get allInFLightRequests(): InFlightRequest[] {
|
||||
get allInFlightRequests(): InFlightRequest[] {
|
||||
const requests = self.proofsCounters
|
||||
.flatMap((counter) => counter.inFlightRequests) // Combine all `inFlightRequests` arrays
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
PaymentRequest as CashuPaymentRequest,
|
||||
PaymentRequestPayload,
|
||||
} from '@cashu/cashu-ts'
|
||||
import { bytesToHex } from '@noble/hashes/utils'
|
||||
import AppError, {Err} from '../../utils/AppError'
|
||||
import { getDecodedToken } from '@cashu/cashu-ts'
|
||||
import {Proof} from '../../models/Proof'
|
||||
@@ -13,6 +14,7 @@ import { log } from '../logService'
|
||||
import { decodePaymentRequest, sumProofs } from '@cashu/cashu-ts/src/utils'
|
||||
import { NostrClient } from '../nostrService'
|
||||
import { getUnixTime } from 'date-fns/getUnixTime'
|
||||
import { Text } from '../../components'
|
||||
|
||||
export {CashuProof}
|
||||
|
||||
@@ -276,35 +278,42 @@ const validateMintKeys = function (keys: object): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function getKeysetIdInt(keysetIdHex: string) {
|
||||
return parseInt(`0x${keysetIdHex}`, 16) % (2 ** 31 - 1)
|
||||
function getKeysetIdInt(keysetId: string): bigint {
|
||||
if (/^[0-9a-fA-F]+$/.test(keysetId)) {
|
||||
return BigInt(`0x${keysetId}`) % BigInt(2 ** 31 - 1)
|
||||
} else {
|
||||
const bin = atob(keysetId)
|
||||
const hex = bytesToHex(new TextEncoder().encode(bin))
|
||||
return BigInt(`0x${hex}`) % BigInt(2 ** 31 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isCollidingKeysetId(
|
||||
newKeysetIdHex: string,
|
||||
newKeysetId: string,
|
||||
storedKeysetIds: string[],
|
||||
) {
|
||||
const newKeysetIdInt = getKeysetIdInt(newKeysetIdHex)
|
||||
const newKeysetIdInt = getKeysetIdInt(newKeysetId)
|
||||
return storedKeysetIds.some((storedId) => {
|
||||
const storedKeysetIdInt = getKeysetIdInt(storedId)
|
||||
if (storedId === newKeysetIdHex) {
|
||||
|
||||
if (storedId === newKeysetId) {
|
||||
// Colliding keyset ID!
|
||||
log.error('[isCollidingKeysetId] Colliding keyset ID', {
|
||||
newKeysetIdHex,
|
||||
newKeysetId,
|
||||
storedId,
|
||||
newKeysetIdInt,
|
||||
storedKeysetIdInt,
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
const storedKeysetIdInt = getKeysetIdInt(storedId)
|
||||
|
||||
if (storedKeysetIdInt === newKeysetIdInt) {
|
||||
// Colliding keyset ID integer!
|
||||
log.error('[isCollidingKeysetId] Colliding keyset ID integer', {
|
||||
newKeysetIdHex,
|
||||
newKeysetId,
|
||||
storedId,
|
||||
newKeysetIdInt,
|
||||
storedKeysetIdInt,
|
||||
newKeysetIdInt: newKeysetIdInt.toString(),
|
||||
storedKeysetIdInt: storedKeysetIdInt.toString(),
|
||||
})
|
||||
|
||||
return true
|
||||
@@ -397,3 +406,5 @@ export const CashuUtils = {
|
||||
isTokenP2PKLocked,
|
||||
isCollidingKeysetId
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1164,7 +1164,7 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
|
||||
|
||||
log.trace('[handleInFlightByMintTask]', {mintUrl: mint.mintUrl, inFlightCounters})
|
||||
|
||||
const allInFlightRequestLength = mint.allInFLightRequests?.length
|
||||
const allInFlightRequestLength = mint.allInFlightRequests?.length
|
||||
const errors: string[] = []
|
||||
|
||||
if(inFlightCounters && inFlightCounters.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user