feat(connect): assert message schema in every typedCall

This commit is contained in:
Tomáš Martykán
2023-12-14 09:08:59 +01:00
committed by martin
parent 25420c4e8e
commit 44430e47ff
4 changed files with 19 additions and 14 deletions

View File

@@ -22,7 +22,7 @@ import { initLog } from '../utils/debug';
import type { Device } from './Device';
import type { CoinInfo, BitcoinNetworkInfo, Network } from '../types';
import type { HDNodeResponse } from '../types/api/getPublicKey';
import { Validate } from '@trezor/schema-utils';
// import { Assert } from '@trezor/schema-utils';
type MessageType = Messages.MessageType;
type MessageKey = keyof MessageType;
@@ -43,7 +43,7 @@ export type PassphrasePromptResponse = {
const logger = initLog('DeviceCommands');
const assertType = (res: DefaultMessageResponse, resType: string | string[]) => {
const assertType = (res: DefaultMessageResponse, resType: MessageKey | MessageKey[]) => {
const splitResTypes = Array.isArray(resType) ? resType : resType.split('|');
if (!splitResTypes.includes(res.type)) {
throw ERRORS.TypedError(
@@ -420,6 +420,9 @@ export class DeviceCommands {
if (this.disposed) {
throw ERRORS.TypedError('Runtime', 'typedCall: DeviceCommands already disposed');
}
// Assert message type
// msg is allowed to be undefined for some calls, in that case the schema is an empty object
// Assert(Messages.MessageType.properties[type], msg ?? {});
const response = await this._commonCall(type, msg);
try {
assertType(response, resType);
@@ -436,15 +439,6 @@ export class DeviceCommands {
return response;
}
typedCallV2<T extends Messages.MessageKey, R extends Messages.MessageKey>(
type: T,
resType: R,
msg?: Messages.MessageType[T],
): Promise<TypedResponseMessage<R>> {
Validate(Messages.MessageType.properties[type], msg);
return this.typedCall(type, resType, msg);
}
async _commonCall(type: MessageKey, msg?: DefaultMessageResponse['message']) {
const resp = await this.call(type, msg);
if (this.disposed) {

View File

@@ -130,7 +130,7 @@ const TYPE_PATCH = {
'CardanoSignTxInit.ttl': UINT_TYPE,
'CardanoSignTxInit.validity_interval_start': UINT_TYPE,
'CardanoSignTxInit.total_collateral': UINT_TYPE,
'CardanoToken.mint_amount': UINT_TYPE,
'CardanoToken.mint_amount': 'number | string', // TODO: Sint64 support
'CardanoNativeScript.invalid_before': UINT_TYPE,
'CardanoNativeScript.invalid_hereafter': UINT_TYPE,
'EosAsset.symbol': 'string',
@@ -169,9 +169,10 @@ const TYPE_PATCH = {
'EosActionNewAccount.creator': 'string',
'EosActionNewAccount.name': 'string',
'ResetDevice.backup_type': 'string | number', // BackupType is a enum. in Features displayed as string, in resetDevice method param accepted as number
'StellarAssetType.type': '0 | 1 | 2',
//'StellarAssetType.type': '0 | 1 | 2', // TODO: test if this is correct
'StellarAssetType.type': '"NATIVE" | "ALPHANUM4" | "ALPHANUM12"',
'StellarSignTx.sequence_number': UINT_TYPE,
'StellarSignTx.memo_id': 'string',
'StellarSignTx.memo_id': UINT_TYPE,
'StellarSignTx.memo_hash': 'Buffer | string',
'StellarCreateAccountOp.starting_balance': UINT_TYPE,
'StellarPathPaymentStrictReceiveOp.send_max': UINT_TYPE,

View File

@@ -20,6 +20,10 @@ export function Assert<T extends TSchema>(schema: T, value: unknown): asserts va
const errors = Value.Errors(schema, value);
const error = errors.First();
if (error) {
if (error.value == null && error.schema[Optional] === 'Optional') {
// Optional can also accept null values
return;
}
throw new InvalidParameter(error.message, error.path, error.value);
}
}

View File

@@ -65,4 +65,10 @@ describe('Assert', () => {
);
}
});
it('should also accept null if optional', () => {
const schema = Type.Object({ type: Type.Optional(Type.String()) });
const value = { type: null };
expect(() => Assert(schema, value)).not.toThrow();
});
});