diff --git a/packages/core/src/api/BaseMethod.ts b/packages/core/src/api/BaseMethod.ts index e41631c84..b5316b591 100644 --- a/packages/core/src/api/BaseMethod.ts +++ b/packages/core/src/api/BaseMethod.ts @@ -1,3 +1,5 @@ +import semver from 'semver'; +import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared'; import { supportInputPinOnSoftware, supportModifyHomescreen } from '../utils/deviceFeaturesUtils'; import { createDeviceMessage } from '../events/device'; import { UI_REQUEST } from '../constants/ui-request'; @@ -6,7 +8,8 @@ import DeviceConnector from '../device/DeviceConnector'; import { DeviceFirmwareRange, KnownDevice } from '../types'; import { CoreMessage, createFirmwareMessage, createUiMessage, DEVICE, FIRMWARE } from '../events'; import { getBleFirmwareReleaseInfo, getFirmwareReleaseInfo } from './firmware/releaseHelper'; -import { getLogger, LoggerNames } from '../utils'; +import { getDeviceFirmwareVersion, getLogger, getMethodVersionRange, LoggerNames } from '../utils'; +import { DataManager } from '../data-manager'; const Log = getLogger(LoggerNames.Method); @@ -81,6 +84,12 @@ export abstract class BaseMethod { */ skipForceUpdateCheck = false; + /** + * 是否需要预先检查版本限制 + * @default false + */ + preCheckVersionLimit = false; + // @ts-expect-error: strictPropertyInitialization postMessage: (message: CoreMessage) => void; @@ -127,6 +136,53 @@ export abstract class BaseMethod { ); } + handleUnsupportedMethodError(error?: HardwareError) { + console.log('handleUnsupportedMethodError:', error); + + if ( + // Not unexpected message is not processed + !error?.message?.includes('Failure_UnexpectedMessage') || + // Only preCheckVersionLimit will have no error + (error == null && !this.preCheckVersionLimit) + ) { + return undefined; + } + + const versionRange = getMethodVersionRange( + this.device.features, + type => this.getVersionRange()[type] + ); + + if (!versionRange || !this.device.features) { + return ERRORS.TypedError(HardwareErrorCode.UnsupportedMethod); + } + const newVersionStatus = DataManager.getFirmwareStatus(this.device.features); + const currentVersion = getDeviceFirmwareVersion(this.device.features).join('.'); + if (semver.valid(versionRange.min) && semver.lt(currentVersion, versionRange.min)) { + if (newVersionStatus === 'none' || newVersionStatus === 'valid') { + throw ERRORS.TypedError(HardwareErrorCode.NewFirmwareUnRelease); + } + + return ERRORS.TypedError( + HardwareErrorCode.CallMethodNeedUpgradeFirmware, + `Device firmware version is too low, please update to ${versionRange.min}`, + { current: currentVersion, require: versionRange.min } + ); + } + + if ( + versionRange.max && + semver.valid(versionRange.max) && + semver.gte(currentVersion, versionRange.max) + ) { + return ERRORS.TypedError( + HardwareErrorCode.CallMethodDeprecated, + `Device firmware version is too high, this method has been deprecated in ${versionRange.max}`, + { current: currentVersion, deprecated: versionRange.max } + ); + } + } + checkDeviceSupportFeature() { if (!this.device || !this.device.features) return; const inputPinOnSoftware = supportInputPinOnSoftware(this.device.features); diff --git a/packages/core/src/api/btc/BTCGetAddress.ts b/packages/core/src/api/btc/BTCGetAddress.ts index f621891f3..82d986337 100644 --- a/packages/core/src/api/btc/BTCGetAddress.ts +++ b/packages/core/src/api/btc/BTCGetAddress.ts @@ -10,6 +10,8 @@ import { getBitcoinForkVersionRange } from './helpers/versionLimit'; export default class BTCGetAddress extends BaseMethod { hasBundle = false; + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/btc/BTCGetPublicKey.ts b/packages/core/src/api/btc/BTCGetPublicKey.ts index 2821bf3f3..5e0358ddb 100644 --- a/packages/core/src/api/btc/BTCGetPublicKey.ts +++ b/packages/core/src/api/btc/BTCGetPublicKey.ts @@ -11,6 +11,8 @@ import { getBitcoinForkVersionRange } from './helpers/versionLimit'; export default class BTCGetPublicKey extends BaseMethod { hasBundle = false; + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/btc/BTCSignMessage.ts b/packages/core/src/api/btc/BTCSignMessage.ts index 57e35cf18..c2fdb89d8 100644 --- a/packages/core/src/api/btc/BTCSignMessage.ts +++ b/packages/core/src/api/btc/BTCSignMessage.ts @@ -8,6 +8,8 @@ import { getCoinAndScriptType } from './helpers/btcParamsUtils'; import { getBitcoinForkVersionRange } from './helpers/versionLimit'; export default class BTCSignMessage extends BaseMethod { + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/btc/BTCSignPsbt.ts b/packages/core/src/api/btc/BTCSignPsbt.ts index 4c128e01a..dd37d9e1d 100644 --- a/packages/core/src/api/btc/BTCSignPsbt.ts +++ b/packages/core/src/api/btc/BTCSignPsbt.ts @@ -6,6 +6,8 @@ import { formatAnyHex } from '../helpers/hexUtils'; import { getCoinInfo } from './helpers/btcParamsUtils'; export default class BTCSignPsbt extends BaseMethod { + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/btc/BTCSignTransaction.ts b/packages/core/src/api/btc/BTCSignTransaction.ts index 61a442c3e..222ca695b 100644 --- a/packages/core/src/api/btc/BTCSignTransaction.ts +++ b/packages/core/src/api/btc/BTCSignTransaction.ts @@ -25,6 +25,8 @@ type Params = { coinName: string; }; export default class BTCSignTransaction extends BaseMethod { + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/btc/BTCVerifyMessage.ts b/packages/core/src/api/btc/BTCVerifyMessage.ts index 5e8c3358c..e932ae9fa 100644 --- a/packages/core/src/api/btc/BTCVerifyMessage.ts +++ b/packages/core/src/api/btc/BTCVerifyMessage.ts @@ -8,6 +8,8 @@ import { getCoinInfo } from './helpers/btcParamsUtils'; import { getBitcoinForkVersionRange } from './helpers/versionLimit'; export default class BTCVerifyMessage extends BaseMethod { + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode, UI_REQUEST.INITIALIZE]; diff --git a/packages/core/src/api/evm/EVMSignTransaction.ts b/packages/core/src/api/evm/EVMSignTransaction.ts index d7f0b55af..a454889c8 100644 --- a/packages/core/src/api/evm/EVMSignTransaction.ts +++ b/packages/core/src/api/evm/EVMSignTransaction.ts @@ -10,6 +10,8 @@ import { signTransaction } from './latest/signTransaction'; import { signTransaction as signTransactionLegacyV1 } from './legacyV1/signTransaction'; export default class EVMSignTransaction extends BaseMethod { + preCheckVersionLimit = true; + addressN: number[] = []; isEIP1559 = false; diff --git a/packages/core/src/api/polkadot/PolkadotGetAddress.ts b/packages/core/src/api/polkadot/PolkadotGetAddress.ts index 1d28494ee..1eeb30f82 100644 --- a/packages/core/src/api/polkadot/PolkadotGetAddress.ts +++ b/packages/core/src/api/polkadot/PolkadotGetAddress.ts @@ -9,6 +9,8 @@ import { getPolkadotVersionRangeWithBundle } from './networks'; export default class PolkadotGetAddress extends BaseMethod { hasBundle = false; + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode]; diff --git a/packages/core/src/api/polkadot/PolkadotSignTransaction.ts b/packages/core/src/api/polkadot/PolkadotSignTransaction.ts index 733c1c017..97968e872 100644 --- a/packages/core/src/api/polkadot/PolkadotSignTransaction.ts +++ b/packages/core/src/api/polkadot/PolkadotSignTransaction.ts @@ -9,6 +9,8 @@ import { getPolkadotVersionRange } from './networks'; export default class PolkadotSignTransaction extends BaseMethod { hasBundle = false; + preCheckVersionLimit = true; + init() { this.checkDeviceId = true; this.notAllowDeviceMode = [...this.notAllowDeviceMode]; diff --git a/packages/core/src/api/solana/SolSignTransaction.ts b/packages/core/src/api/solana/SolSignTransaction.ts index 65ab9257b..04d40e309 100644 --- a/packages/core/src/api/solana/SolSignTransaction.ts +++ b/packages/core/src/api/solana/SolSignTransaction.ts @@ -7,6 +7,8 @@ import { SolanaSignedTx, SolanaSignTransactionParams } from '../../types'; import { formatAnyHex } from '../helpers/hexUtils'; export default class SolSignTransaction extends BaseMethod { + preCheckVersionLimit = true; + hasBundle = false; init() { diff --git a/packages/core/src/core/index.ts b/packages/core/src/core/index.ts index d24500858..b61ca27e3 100644 --- a/packages/core/src/core/index.ts +++ b/packages/core/src/core/index.ts @@ -1,4 +1,3 @@ -import semver from 'semver'; import EventEmitter from 'events'; import { Features, LowlevelTransportSharedPlugin, OneKeyDeviceInfo } from '@onekeyfe/hd-transport'; import { @@ -8,15 +7,7 @@ import { HardwareError, HardwareErrorCode, } from '@onekeyfe/hd-shared'; -import { - getDeviceFirmwareVersion, - enableLog, - getLogger, - LoggerNames, - setLoggerPostMessage, - wait, - getMethodVersionRange, -} from '../utils'; +import { enableLog, getLogger, LoggerNames, setLoggerPostMessage, wait } from '../utils'; import { supportNewPassphrase } from '../utils/deviceFeaturesUtils'; import { Device, DeviceEvents, InitOptions, RunOptions } from '../device/Device'; import { DeviceList } from '../device/DeviceList'; @@ -108,7 +99,10 @@ export const callAPI = async (message: CoreMessage) => { const response = await method.run(); return createResponseMessage(method.responseID, true, response); } catch (error) { - return createResponseMessage(method.responseID, false, { error }); + const unsupportedMethodError = method.handleUnsupportedMethodError(error); + return createResponseMessage(method.responseID, false, { + error: unsupportedMethodError ?? error, + }); } } @@ -162,11 +156,6 @@ export const callAPI = async (message: CoreMessage) => { try { const inner = async (): Promise => { // check firmware version - const versionRange = getMethodVersionRange( - device.features, - type => method.getVersionRange()[type] - ); - if (device.features) { await DataManager.checkAndReloadData(); const newVersionStatus = DataManager.getFirmwareStatus(device.features); @@ -182,33 +171,10 @@ export const callAPI = async (message: CoreMessage) => { ); } - if (versionRange) { - const currentVersion = getDeviceFirmwareVersion(device.features).join('.'); - if (semver.valid(versionRange.min) && semver.lt(currentVersion, versionRange.min)) { - if (newVersionStatus === 'none' || newVersionStatus === 'valid') { - throw ERRORS.TypedError(HardwareErrorCode.NewFirmwareUnRelease); - } - - return Promise.reject( - ERRORS.TypedError( - HardwareErrorCode.CallMethodNeedUpgradeFirmware, - `Device firmware version is too low, please update to ${versionRange.min}`, - { current: currentVersion, require: versionRange.min } - ) - ); - } - if ( - versionRange.max && - semver.valid(versionRange.max) && - semver.gte(currentVersion, versionRange.max) - ) { - return Promise.reject( - ERRORS.TypedError( - HardwareErrorCode.CallMethodDeprecated, - `Device firmware version is too high, this method has been deprecated in ${versionRange.max}`, - { current: currentVersion, deprecated: versionRange.max } - ) - ); + if (method.preCheckVersionLimit) { + const error = method.handleUnsupportedMethodError(); + if (error) { + throw error; } } } @@ -306,7 +272,10 @@ export const callAPI = async (message: CoreMessage) => { _callPromise?.resolve(messageResponse); } catch (error) { Log.debug('Call API - Inner Method Run Error: ', error); - messageResponse = createResponseMessage(method.responseID, false, { error }); + const unsupportedMethodError = method.handleUnsupportedMethodError(error); + messageResponse = createResponseMessage(method.responseID, false, { + error: unsupportedMethodError ?? error, + }); _callPromise?.resolve(messageResponse); } }; diff --git a/packages/shared/src/HardwareError.ts b/packages/shared/src/HardwareError.ts index 5ffb578d0..6b832c309 100644 --- a/packages/shared/src/HardwareError.ts +++ b/packages/shared/src/HardwareError.ts @@ -363,6 +363,11 @@ export const HardwareErrorCode = { */ BridgeDeviceDisconnected: 817, + /** + * Unsupported Method + */ + UnsupportedMethod: 818, + /** * Lowlevel transport connect error */ @@ -480,7 +485,7 @@ export const HardwareErrorCodeMessage: HardwareErrorCodeMessageMapping = { [HardwareErrorCode.CheckDownloadFileError]: 'Check download file error', [HardwareErrorCode.NotInSigningMode]: 'not in signing mode', [HardwareErrorCode.DataOverload]: 'Params data overload', - + [HardwareErrorCode.UnsupportedMethod]: 'Unsupported method', /** * Lowlevel transport */