@onekeyfe/hd-core 1.2.0-alpha.105 → 1.2.0-alpha.106

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/__tests__/DeviceCommands.test.ts +90 -26
  2. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +0 -2
  3. package/__tests__/device-pool-state.test.ts +1 -5
  4. package/__tests__/deviceSettings.test.ts +0 -1
  5. package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +145 -0
  6. package/__tests__/logBlockEvent.test.ts +13 -1
  7. package/__tests__/protocol-v2.test.ts +447 -122
  8. package/__tests__/refresh-device-state.test.ts +0 -1
  9. package/__tests__/search-devices.test.ts +0 -2
  10. package/dist/api/FirmwareUpdateV4.d.ts +7 -3
  11. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  12. package/dist/api/GetDeviceState.d.ts.map +1 -1
  13. package/dist/api/SearchDevices.d.ts.map +1 -1
  14. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/device/Device.d.ts +0 -3
  17. package/dist/device/Device.d.ts.map +1 -1
  18. package/dist/device/DeviceCommands.d.ts.map +1 -1
  19. package/dist/device/DevicePool.d.ts +1 -1
  20. package/dist/device/DevicePool.d.ts.map +1 -1
  21. package/dist/events/logBlockEvent.d.ts.map +1 -1
  22. package/dist/index.d.ts +0 -6
  23. package/dist/index.js +251 -184
  24. package/dist/protocols/protocol-v2/features.d.ts +1 -1
  25. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  26. package/dist/types/api/getDeviceState.d.ts +0 -1
  27. package/dist/types/api/getDeviceState.d.ts.map +1 -1
  28. package/package.json +4 -4
  29. package/src/api/FirmwareUpdateV4.ts +262 -172
  30. package/src/api/GetDeviceState.ts +0 -1
  31. package/src/api/SearchDevices.ts +0 -2
  32. package/src/api/firmware/protocolV2Release.ts +0 -1
  33. package/src/core/index.ts +6 -6
  34. package/src/device/Device.ts +11 -48
  35. package/src/device/DeviceCommands.ts +4 -14
  36. package/src/device/DevicePool.ts +3 -11
  37. package/src/events/logBlockEvent.ts +14 -1
  38. package/src/protocols/protocol-v2/features.ts +9 -2
  39. package/src/types/api/getDeviceState.ts +0 -2
  40. package/src/utils/deviceSettings.ts +1 -1
  41. package/__tests__/protocol-v2-legacy-recovery.test.ts +0 -29
  42. package/dist/core/protocolV2LegacyRecovery.d.ts +0 -5
  43. package/dist/core/protocolV2LegacyRecovery.d.ts.map +0 -1
  44. package/src/core/protocolV2LegacyRecovery.ts +0 -12
@@ -60,7 +60,6 @@ export async function loadProtocolV2FirmwareReleaseContext({
60
60
  refreshSections: checkFirmwareHash
61
61
  ? ['identity', 'versions', 'verification']
62
62
  : ['identity', 'versions'],
63
- allowLegacyProtocolV2ProtocolInfo: true,
64
63
  });
65
64
  if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
66
65
  throw ERRORS.TypedError(
package/src/core/index.ts CHANGED
@@ -64,7 +64,6 @@ import {
64
64
  isProtocolV2UiEnabled,
65
65
  } from '../protocols/protocol-v2/uiInteraction';
66
66
  import { createUiProgressMessageFilter } from '../utils/uiProgressThrottle';
67
- import { isLegacyProtocolV2FirmwareRecoveryMethod } from './protocolV2LegacyRecovery';
68
67
 
69
68
  import type { ConnectSettings, Features, KnownDevice } from '../types';
70
69
  import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
@@ -110,9 +109,6 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
110
109
  connectProtocol: method?.payload.connectProtocol,
111
110
  forceProtocolDetection: method?.payload.forceProtocolDetection,
112
111
  protocolV2DeviceInfoTimeoutMs: method?.payload.protocolV2DeviceInfoTimeoutMs,
113
- ...(isLegacyProtocolV2FirmwareRecoveryMethod(method)
114
- ? { allowLegacyProtocolV2ProtocolInfo: true }
115
- : {}),
116
112
  });
117
113
 
118
114
  let _core: Core | undefined;
@@ -140,6 +136,9 @@ const toError = (error: unknown): Error | undefined => {
140
136
  }
141
137
  };
142
138
 
139
+ const isExpectedCompatibilityError = (error: unknown) =>
140
+ error instanceof HardwareError && error.errorCode === HardwareErrorCode.DeviceNotSupportMethod;
141
+
143
142
  const updateMethodRequestContext = (method: BaseMethod, updates: any) => {
144
143
  if (method.requestContext) {
145
144
  updateRequestContext(method.requestContext.responseID, updates);
@@ -697,7 +696,9 @@ const onCallDevice = async (
697
696
  try {
698
697
  return await task.callPromise.promise;
699
698
  } catch (e) {
700
- Log.debug('Device Run Error: ', e);
699
+ if (!isExpectedCompatibilityError(e)) {
700
+ Log.debug('Device Run Error: ', e);
701
+ }
701
702
  completeMethodRequestContext(method, e);
702
703
  return createResponseMessage(method.responseID, false, { error: e });
703
704
  }
@@ -1252,7 +1253,6 @@ const cleanup = () => {
1252
1253
  pendingUiPromises,
1253
1254
  ERRORS.TypedError(HardwareErrorCode.ActionCancelled, 'UI request was cancelled')
1254
1255
  );
1255
- Log.debug('Cleanup...');
1256
1256
  };
1257
1257
 
1258
1258
  const removeDeviceListener = (device: Device) => {
@@ -100,8 +100,6 @@ export type InitOptions = {
100
100
  protocolV2DeviceInfoTimeoutMs?: number;
101
101
  /** Refresh Protocol V2 runtime state before returning discovery results. */
102
102
  refreshRuntimeState?: boolean;
103
- /** Recovery-only compatibility used by discovery and Protocol V2 firmware updates. */
104
- allowLegacyProtocolV2ProtocolInfo?: boolean;
105
103
  /**
106
104
  * Protocol V1 Initialize response timeout override. Reboot-wait polling passes a
107
105
  * short value so an unanswered probe settles before the next poll tick.
@@ -984,17 +982,7 @@ export class Device extends EventEmitter {
984
982
  });
985
983
  // The default request excludes SE/hash data and therefore uses basic scope.
986
984
  // Full version and verification data require getDeviceState({ scope: 'firmware' }).
987
- const features = options?.allowLegacyProtocolV2ProtocolInfo
988
- ? await this.probeProtocolV2RuntimeState(
989
- deviceInfo,
990
- options.protocolV2DeviceInfoTimeoutMs,
991
- { allowLegacyProtocolV2ProtocolInfo: true }
992
- )
993
- : await this.probeProtocolV2RuntimeState(
994
- deviceInfo,
995
- options?.protocolV2DeviceInfoTimeoutMs
996
- );
997
- Log.debug('Protocol V2 features:', features);
985
+ await this.probeProtocolV2RuntimeState(deviceInfo, options?.protocolV2DeviceInfoTimeoutMs);
998
986
  } catch (error) {
999
987
  Log.error('Protocol V2 initialization failed:', error);
1000
988
  throw error;
@@ -1030,13 +1018,7 @@ export class Device extends EventEmitter {
1030
1018
  commands: this.commands,
1031
1019
  request: getProtocolV2DeviceInfoRequest(),
1032
1020
  });
1033
- if (params.allowLegacyProtocolV2ProtocolInfo) {
1034
- await this.probeProtocolV2RuntimeState(deviceInfo, undefined, {
1035
- allowLegacyProtocolV2ProtocolInfo: true,
1036
- });
1037
- } else {
1038
- await this.probeProtocolV2RuntimeState(deviceInfo);
1039
- }
1021
+ await this.probeProtocolV2RuntimeState(deviceInfo);
1040
1022
  refreshedDeviceInfo = deviceInfo;
1041
1023
  initializedWithDeviceInfo = true;
1042
1024
  } else {
@@ -1078,9 +1060,6 @@ export class Device extends EventEmitter {
1078
1060
  // during an explicit refresh so a device rebooted into application firmware
1079
1061
  // can leave the cached loader state.
1080
1062
  forceRuntimeContextRefresh: cachedMode === 'bootloader' || cachedMode === 'romloader',
1081
- ...(params.allowLegacyProtocolV2ProtocolInfo
1082
- ? { allowLegacyProtocolV2ProtocolInfo: true }
1083
- : {}),
1084
1063
  });
1085
1064
  }
1086
1065
 
@@ -1129,9 +1108,10 @@ export class Device extends EventEmitter {
1129
1108
  source,
1130
1109
  changedKeys: result.changedKeys,
1131
1110
  };
1132
- Log.debug('Device state patch committed', {
1111
+ Log.debug('Device state updated', {
1133
1112
  source,
1134
- keys: result.changedKeys,
1113
+ revision: result.revision,
1114
+ changedKeyCount: result.changedKeys.length,
1135
1115
  });
1136
1116
  this.emit(DEVICE.STATE, this, event);
1137
1117
  if (result.state.protocol === 'V1') {
@@ -1154,23 +1134,8 @@ export class Device extends EventEmitter {
1154
1134
 
1155
1135
  async ensureProtocolV2RuntimeContext(
1156
1136
  timeoutMs?: number,
1157
- options?: {
1158
- forceRefresh?: boolean;
1159
- allowLegacyProtocolV2ProtocolInfo?: boolean;
1160
- }
1137
+ options?: { forceRefresh?: boolean }
1161
1138
  ): Promise<ProtocolInfo> {
1162
- const assertProtocolInfoAllowed = (protocolInfo: ProtocolInfo) => {
1163
- if (
1164
- isLegacyProtocolV2ProtocolInfo(protocolInfo) &&
1165
- options?.allowLegacyProtocolV2ProtocolInfo !== true
1166
- ) {
1167
- throw ERRORS.TypedError(
1168
- HardwareErrorCode.DeviceInitializeFailed,
1169
- 'Legacy Protocol V2 ProtocolInfo is supported only during device discovery and firmware update.'
1170
- );
1171
- }
1172
- return protocolInfo;
1173
- };
1174
1139
  const cachedProtocolInfo =
1175
1140
  options?.forceRefresh === true
1176
1141
  ? undefined
@@ -1180,11 +1145,11 @@ export class Device extends EventEmitter {
1180
1145
  : undefined);
1181
1146
  if (cachedProtocolInfo) {
1182
1147
  this.protocolV2RuntimeContext = cachedProtocolInfo;
1183
- return assertProtocolInfoAllowed(cachedProtocolInfo);
1148
+ return cachedProtocolInfo;
1184
1149
  }
1185
1150
 
1186
1151
  if (this.protocolV2RuntimeContextPromise) {
1187
- return assertProtocolInfoAllowed(await this.protocolV2RuntimeContextPromise);
1152
+ return this.protocolV2RuntimeContextPromise;
1188
1153
  }
1189
1154
 
1190
1155
  const requestToken = {};
@@ -1206,7 +1171,7 @@ export class Device extends EventEmitter {
1206
1171
  this.protocolV2RuntimeContextPromise = pendingRequest;
1207
1172
 
1208
1173
  try {
1209
- return assertProtocolInfoAllowed(await pendingRequest);
1174
+ return await pendingRequest;
1210
1175
  } finally {
1211
1176
  if (this.protocolV2RuntimeContextPromise === pendingRequest) {
1212
1177
  this.protocolV2RuntimeContextPromise = undefined;
@@ -1222,16 +1187,14 @@ export class Device extends EventEmitter {
1222
1187
  timeoutMs?: number,
1223
1188
  options?: {
1224
1189
  forceRuntimeContextRefresh?: boolean;
1225
- allowLegacyProtocolV2ProtocolInfo?: boolean;
1226
1190
  }
1227
1191
  ) {
1228
1192
  const protocolInfo = await this.ensureProtocolV2RuntimeContext(timeoutMs, {
1229
1193
  forceRefresh: options?.forceRuntimeContextRefresh,
1230
- allowLegacyProtocolV2ProtocolInfo: options?.allowLegacyProtocolV2ProtocolInfo,
1231
1194
  });
1232
- const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
1233
- const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
1234
1195
  const runtimeDeviceInfo = deviceInfo ?? this.state?.raw?.protocolV2DeviceInfo;
1196
+ const runtimeMode = getProtocolV2RuntimeMode(protocolInfo, runtimeDeviceInfo);
1197
+ const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
1235
1198
  const protocolV2DeviceType = runtimeDeviceInfo
1236
1199
  ? resolveProtocolV2DeviceIdentity(runtimeDeviceInfo.hw?.Device_type).deviceType
1237
1200
  : this.getCurrentDeviceType();
@@ -304,13 +304,6 @@ export class DeviceCommands {
304
304
  const promise = this.transport.call(this.mainId, type, msg ?? {}, options) as any;
305
305
  this.callPromise = promise;
306
306
  const res = await promise;
307
- if (!shouldReduceDebug) {
308
- LogCore.debug(
309
- '[DeviceCommands] [call] Received',
310
- res.type,
311
- getSafeTransportLogPayload(res.message, res.type)
312
- );
313
- }
314
307
  return res;
315
308
  } catch (error) {
316
309
  LogCore.debug('[DeviceCommands] [call] Received error', {
@@ -445,13 +438,10 @@ export class DeviceCommands {
445
438
  if (!shouldReduceDebugForCall(callType)) {
446
439
  Log.debug('_filterCommonTypes: ', {
447
440
  request: callType,
448
- response:
449
- callType === 'DeviceFirmwareUpdateStatusGet'
450
- ? {
451
- type: res.type,
452
- message: getSafeTransportLogPayload(res.message, res.type),
453
- }
454
- : res.type,
441
+ response: {
442
+ type: res.type,
443
+ message: getSafeTransportLogPayload(res.message, res.type),
444
+ },
455
445
  });
456
446
  }
457
447
  } catch (error) {
@@ -182,7 +182,7 @@ export class DevicePool extends EventEmitter {
182
182
  try {
183
183
  await device.initialize(initOptions);
184
184
  if (initOptions?.refreshRuntimeState && device.isProtocolV2()) {
185
- await this._refreshProtocolV2DiscoveryState(device, initOptions);
185
+ await this._refreshProtocolV2DiscoveryState(device);
186
186
  }
187
187
  } finally {
188
188
  await device.release();
@@ -197,7 +197,7 @@ export class DevicePool extends EventEmitter {
197
197
  await device.run(
198
198
  async () => {
199
199
  try {
200
- await this._refreshProtocolV2DiscoveryState(device, initOptions);
200
+ await this._refreshProtocolV2DiscoveryState(device);
201
201
  } catch (error) {
202
202
  // Device.run releases after the callback; then propagate the actual read error.
203
203
  refreshError = error;
@@ -206,9 +206,6 @@ export class DevicePool extends EventEmitter {
206
206
  {
207
207
  connectProtocol: initOptions.connectProtocol,
208
208
  forceProtocolDetection: initOptions.forceProtocolDetection,
209
- ...(initOptions.allowLegacyProtocolV2ProtocolInfo
210
- ? { allowLegacyProtocolV2ProtocolInfo: true }
211
- : {}),
212
209
  }
213
210
  );
214
211
  if (refreshError instanceof Error) throw refreshError;
@@ -220,18 +217,13 @@ export class DevicePool extends EventEmitter {
220
217
  * error; settings only supplies a label, so its failure retains the existing name.
221
218
  * Device.getDeviceState skips unsupported status/settings calls in loader mode.
222
219
  */
223
- static async _refreshProtocolV2DiscoveryState(device: Device, initOptions?: InitOptions) {
224
- const stateReadOptions = initOptions?.allowLegacyProtocolV2ProtocolInfo
225
- ? { allowLegacyProtocolV2ProtocolInfo: true as const }
226
- : {};
220
+ static async _refreshProtocolV2DiscoveryState(device: Device) {
227
221
  await device.getDeviceState({
228
222
  refreshSections: ['status'],
229
- ...stateReadOptions,
230
223
  });
231
224
  try {
232
225
  await device.getDeviceState({
233
226
  refreshSections: ['settings'],
234
- ...stateReadOptions,
235
227
  });
236
228
  } catch (error) {
237
229
  Log.debug('Unable to refresh Protocol V2 device label during discovery', error);
@@ -17,6 +17,14 @@ const LogLabelMethod: Set<string> = new Set([
17
17
  'fileRead',
18
18
  ]);
19
19
 
20
+ // 资源上传参数可能包含很大的 Base64 字符串。这里按方法整段跳过,避免日志层
21
+ // 递归复制和序列化这些数据;资源 API 与传输内容本身保持不变。
22
+ const LogPayloadBlockMethod: Set<string> = new Set([
23
+ 'deviceUploadNft',
24
+ 'deviceUploadWallpaper',
25
+ 'uploadPortfolio',
26
+ ]);
27
+
20
28
  const SensitiveLogKeys: Set<string> = new Set([
21
29
  'devicestate',
22
30
  'entropy',
@@ -86,7 +94,12 @@ export function getLogBlockLabel(message: unknown): string | undefined {
86
94
  }
87
95
 
88
96
  export function getSafeLogPayload(value: unknown, blockLabel?: string): unknown {
89
- if (blockLabel && (LogBlockEvent.has(blockLabel) || isSigningMethod(blockLabel))) {
97
+ if (
98
+ blockLabel &&
99
+ (LogBlockEvent.has(blockLabel) ||
100
+ LogPayloadBlockMethod.has(blockLabel) ||
101
+ isSigningMethod(blockLabel))
102
+ ) {
90
103
  return { method: blockLabel, payload: '[REDACTED]' };
91
104
  }
92
105
 
@@ -97,11 +97,18 @@ export const parseProtocolV2BuildFingerprint = (
97
97
  };
98
98
 
99
99
  export const getProtocolV2RuntimeMode = (
100
- protocolInfo: ProtocolInfo
100
+ protocolInfo: ProtocolInfo,
101
+ deviceInfo?: ProtocolV2DeviceInfo
101
102
  ): ProtocolV2RuntimeMode | undefined => {
102
103
  const binary = parseProtocolV2BuildFingerprint(protocolInfo.build_fingerprint)?.binary;
103
104
  if (binary === 'application') return 'normal';
104
- return binary;
105
+ if (binary) return binary;
106
+
107
+ if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !deviceInfo?.fw?.application) {
108
+ if (deviceInfo?.fw?.romloader) return 'romloader';
109
+ if (deviceInfo?.fw?.bootloader) return 'bootloader';
110
+ }
111
+ return undefined;
105
112
  };
106
113
 
107
114
  // MessageType_DeviceStatusGet in the Protocol V2 protobuf registry.
@@ -11,8 +11,6 @@ export type GetDeviceStateParams = CommonParams & {
11
11
  export type DeviceStateReadOptions = {
12
12
  refreshSections?: DeviceStateSection[];
13
13
  includeRaw?: boolean;
14
- /** Internal recovery-only compatibility used by discovery and firmware update flows. */
15
- allowLegacyProtocolV2ProtocolInfo?: boolean;
16
14
  };
17
15
 
18
16
  export declare function getDeviceState(
@@ -200,7 +200,7 @@ export const getAutoShutDownOptions = (
200
200
  return withNever([60_000, 120_000, 300_000, 600_000], protocol);
201
201
  case EDeviceType.Pro2:
202
202
  case EDeviceType.Neo:
203
- return withNever([60_000, 120_000, 300_000, 600_000, 1_800_000], protocol);
203
+ return withNever([60_000, 120_000, 300_000, 600_000], protocol);
204
204
  default:
205
205
  return [];
206
206
  }
@@ -1,29 +0,0 @@
1
- import { isLegacyProtocolV2FirmwareRecoveryMethod } from '../src/core/protocolV2LegacyRecovery';
2
-
3
- import type { BaseMethod } from '../src/api/BaseMethod';
4
-
5
- const createMethod = (
6
- name: string,
7
- payload: Record<string, unknown>
8
- ): Pick<BaseMethod, 'name' | 'payload'> => ({
9
- name,
10
- payload: { method: name, ...payload },
11
- });
12
-
13
- describe('Protocol V2 legacy firmware recovery policy', () => {
14
- test.each([
15
- ['firmware state read', 'getDeviceState', { scope: 'firmware' }],
16
- ['firmware release check', 'checkAllFirmwareRelease', {}],
17
- ['firmware update', 'firmwareUpdateV4', {}],
18
- ])('allows legacy ProtocolInfo for %s', (_label, name, payload) => {
19
- expect(isLegacyProtocolV2FirmwareRecoveryMethod(createMethod(name, payload))).toBe(true);
20
- });
21
-
22
- test.each([
23
- ['runtime state read', 'getDeviceState', { scope: 'runtime' }],
24
- ['settings state read', 'getDeviceState', { scope: 'settings' }],
25
- ['ordinary API', 'getFeatures', {}],
26
- ])('rejects legacy ProtocolInfo for %s', (_label, name, payload) => {
27
- expect(isLegacyProtocolV2FirmwareRecoveryMethod(createMethod(name, payload))).toBe(false);
28
- });
29
- });
@@ -1,5 +0,0 @@
1
- import type { BaseMethod } from '../api/BaseMethod';
2
- type CoreMethodDescriptor = Pick<BaseMethod, 'name' | 'payload'>;
3
- export declare const isLegacyProtocolV2FirmwareRecoveryMethod: (method?: CoreMethodDescriptor) => boolean;
4
- export {};
5
- //# sourceMappingURL=protocolV2LegacyRecovery.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocolV2LegacyRecovery.d.ts","sourceRoot":"","sources":["../../src/core/protocolV2LegacyRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,KAAK,oBAAoB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAMjE,eAAO,MAAM,wCAAwC,YAAa,oBAAoB,KAAG,OAGb,CAAC"}
@@ -1,12 +0,0 @@
1
- import type { BaseMethod } from '../api/BaseMethod';
2
-
3
- type CoreMethodDescriptor = Pick<BaseMethod, 'name' | 'payload'>;
4
-
5
- /**
6
- * TEMPORARY COMPATIBILITY: Legacy ProtocolInfo is accepted only by the
7
- * firmware recovery entry points used before and during Protocol V2 updates.
8
- */
9
- export const isLegacyProtocolV2FirmwareRecoveryMethod = (method?: CoreMethodDescriptor): boolean =>
10
- method?.name === 'firmwareUpdateV4' ||
11
- method?.name === 'checkAllFirmwareRelease' ||
12
- (method?.name === 'getDeviceState' && method.payload.scope === 'firmware');