@onekeyfe/hd-core 1.2.0-alpha.12 → 1.2.0-alpha.14

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 (57) hide show
  1. package/__tests__/DeviceCommands.test.ts +47 -0
  2. package/__tests__/protocol-v2-bootloader-mode.test.ts +37 -0
  3. package/__tests__/protocol-v2.test.ts +146 -58
  4. package/__tests__/protocolV2FileWrite.test.ts +12 -0
  5. package/dist/api/FileWrite.d.ts +1 -0
  6. package/dist/api/FileWrite.d.ts.map +1 -1
  7. package/dist/api/FirmwareUpdateV4.d.ts +2 -0
  8. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  9. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  10. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  11. package/dist/api/index.d.ts +0 -1
  12. package/dist/api/index.d.ts.map +1 -1
  13. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
  14. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  15. package/dist/device/Device.d.ts.map +1 -1
  16. package/dist/device/DeviceCommands.d.ts.map +1 -1
  17. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  18. package/dist/index.d.ts +4 -8
  19. package/dist/index.js +524 -168
  20. package/dist/inject.d.ts.map +1 -1
  21. package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
  22. package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
  23. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  24. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  25. package/dist/types/api/index.d.ts +1 -2
  26. package/dist/types/api/index.d.ts.map +1 -1
  27. package/dist/types/api/protocolV2.d.ts +0 -4
  28. package/dist/types/api/protocolV2.d.ts.map +1 -1
  29. package/dist/types/device.d.ts +2 -1
  30. package/dist/types/device.d.ts.map +1 -1
  31. package/dist/utils/patch.d.ts +1 -1
  32. package/dist/utils/patch.d.ts.map +1 -1
  33. package/package.json +4 -4
  34. package/src/api/FileWrite.ts +3 -1
  35. package/src/api/FirmwareUpdateV4.ts +46 -6
  36. package/src/api/UploadPortfolio.ts +3 -1
  37. package/src/api/cardano/CardanoSignMessage.ts +1 -1
  38. package/src/api/cardano/CardanoSignTransaction.ts +1 -1
  39. package/src/api/helpers/protocolV2FileWrite.ts +10 -6
  40. package/src/api/index.ts +0 -1
  41. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +9 -3
  42. package/src/api/protocol-v2/helpers.ts +0 -3
  43. package/src/data/messages/messages-protocol-v2.json +422 -16
  44. package/src/data/messages/messages.json +0 -8
  45. package/src/device/Device.ts +7 -17
  46. package/src/device/DeviceCommands.ts +3 -1
  47. package/src/deviceProfile/buildDeviceFeatures.ts +8 -0
  48. package/src/inject.ts +0 -2
  49. package/src/protocols/protocol-v2/lockedError.ts +10 -0
  50. package/src/protocols/protocol-v2/unlockRetry.ts +1 -11
  51. package/src/protocols/protocol-v2/walletSession.ts +25 -10
  52. package/src/types/api/index.ts +0 -2
  53. package/src/types/api/protocolV2.ts +0 -6
  54. package/src/types/device.ts +5 -1
  55. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts +0 -13
  56. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts.map +0 -1
  57. package/src/api/protocol-v2/FilesystemDiskControl.ts +0 -50
@@ -18,6 +18,7 @@ export type FileWriteParams = {
18
18
  chunkLen?: number;
19
19
  overwrite?: boolean;
20
20
  append?: boolean;
21
+ emitProgress?: boolean;
21
22
  uiPercentage?: number;
22
23
  timeoutMs?: number | string;
23
24
  };
@@ -40,6 +41,7 @@ export default class FileWrite extends BaseMethod<FileWriteParams> {
40
41
  chunkLen: validateOptionalNonNegativeInteger(this.payload.chunkLen, 'chunkLen'),
41
42
  overwrite: this.payload.overwrite ?? offset === 0,
42
43
  append: this.payload.append ?? false,
44
+ emitProgress: this.payload.emitProgress ?? true,
43
45
  uiPercentage: validateOptionalPercentage(this.payload.uiPercentage, 'uiPercentage'),
44
46
  timeoutMs: validateOptionalNonNegativeInteger(this.payload.timeoutMs, 'timeoutMs'),
45
47
  };
@@ -60,7 +62,7 @@ export default class FileWrite extends BaseMethod<FileWriteParams> {
60
62
  timeoutMs: this.params.timeoutMs === undefined ? undefined : Number(this.params.timeoutMs),
61
63
  throwIfAborted: () => this.throwIfAborted(),
62
64
  onProgress: payload => {
63
- if (typeof this.postMessage === 'function') {
65
+ if (this.params.emitProgress && typeof this.postMessage === 'function') {
64
66
  this.postMessage(createUiMessage(UI_REQUEST.DEVICE_PROGRESS, payload));
65
67
  }
66
68
  },
@@ -379,6 +379,25 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
379
379
  };
380
380
  };
381
381
 
382
+ export const assertProtocolV2ReconnectIdentity = (
383
+ expectedDeviceId?: string,
384
+ actualDeviceId?: string
385
+ ) => {
386
+ if (!expectedDeviceId) return;
387
+ if (!actualDeviceId) {
388
+ throw ERRORS.TypedError(
389
+ HardwareErrorCode.DeviceNotFound,
390
+ 'Protocol V2 reconnect identity unavailable'
391
+ );
392
+ }
393
+ if (actualDeviceId !== expectedDeviceId) {
394
+ throw ERRORS.TypedError(
395
+ HardwareErrorCode.DeviceNotFound,
396
+ `Protocol V2 reconnect identity mismatch: expected ${expectedDeviceId}, received ${actualDeviceId}`
397
+ );
398
+ }
399
+ };
400
+
382
401
  /**
383
402
  * FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
384
403
  *
@@ -388,6 +407,8 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
388
407
  * - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
389
408
  */
390
409
  export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
410
+ private protocolV2ExpectedDeviceId?: string;
411
+
391
412
  init() {
392
413
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
393
414
  this.requireDeviceMode = [];
@@ -476,6 +497,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
476
497
 
477
498
  private async runProtocolV2() {
478
499
  const deviceFeatures = await this.getProtocolV2DeviceFeatures();
500
+ this.protocolV2ExpectedDeviceId = deviceFeatures.deviceId ?? undefined;
479
501
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
480
502
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
481
503
 
@@ -917,6 +939,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
917
939
  timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
918
940
  });
919
941
  const features = this.device.updateProtocolV2Features(deviceInfo);
942
+ assertProtocolV2ReconnectIdentity(
943
+ this.protocolV2ExpectedDeviceId,
944
+ features.deviceId ?? undefined
945
+ );
920
946
  if (features?.bootloaderMode) {
921
947
  return features;
922
948
  }
@@ -1134,6 +1160,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1134
1160
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1135
1161
  });
1136
1162
  const features = this.device.updateProtocolV2Features(deviceInfo);
1163
+ assertProtocolV2ReconnectIdentity(
1164
+ this.protocolV2ExpectedDeviceId,
1165
+ features.deviceId ?? undefined
1166
+ );
1137
1167
  if (this.isProtocolV2NormalModeFeatures(features)) {
1138
1168
  Log.log('Protocol V2 firmware install finished; device is back in normal mode');
1139
1169
  return true;
@@ -1288,6 +1318,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1288
1318
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1289
1319
  });
1290
1320
  const features = this.device.updateProtocolV2Features(deviceInfo);
1321
+ assertProtocolV2ReconnectIdentity(
1322
+ this.protocolV2ExpectedDeviceId,
1323
+ features.deviceId ?? undefined
1324
+ );
1291
1325
  if (features.bootloaderMode || features.mode === 'bootloader') {
1292
1326
  throw ERRORS.TypedError(
1293
1327
  HardwareErrorCode.DeviceNotFound,
@@ -1334,6 +1368,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1334
1368
  this.device.commands.disposed = false;
1335
1369
  this.device.getCommands().mainId = this.device.mainId ?? '';
1336
1370
  await this.device.initialize();
1371
+ assertProtocolV2ReconnectIdentity(
1372
+ this.protocolV2ExpectedDeviceId,
1373
+ this.device.getCurrentDeviceId()
1374
+ );
1337
1375
  return;
1338
1376
  }
1339
1377
 
@@ -1355,6 +1393,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1355
1393
  this.device.commands.disposed = false;
1356
1394
  this.device.getCommands().mainId = this.device.mainId ?? '';
1357
1395
  await this.device.initialize();
1396
+ assertProtocolV2ReconnectIdentity(
1397
+ this.protocolV2ExpectedDeviceId,
1398
+ this.device.getCurrentDeviceId()
1399
+ );
1358
1400
  }
1359
1401
 
1360
1402
  private async protocolV2CommonUpdateProcess(params: ProtocolV2FileTransferParams) {
@@ -1416,12 +1458,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1416
1458
  overwrite,
1417
1459
  progress
1418
1460
  );
1419
- const processedByte = Number(writeRes.message.processed_byte);
1420
- const nextOffset =
1421
- Number.isFinite(processedByte) && processedByte > offset
1422
- ? processedByte
1423
- : offset + chunkLength;
1424
- if (nextOffset <= offset || nextOffset > payload.byteLength) {
1461
+ const rawProcessedByte = writeRes.message.processed_byte;
1462
+ const processedByte = Number(rawProcessedByte);
1463
+ const nextOffset = rawProcessedByte === undefined ? offset + chunkLength : processedByte;
1464
+ if (!Number.isFinite(nextOffset) || nextOffset <= offset || nextOffset > chunkEnd) {
1425
1465
  throw ERRORS.TypedError(
1426
1466
  HardwareErrorCode.EmmcFileWriteFirmwareError,
1427
1467
  `invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
@@ -6,7 +6,7 @@ export type UploadPortfolioParams = {
6
6
  timeoutMs?: number | string;
7
7
  };
8
8
 
9
- const PORTFOLIO_PENDING_PATH = 'vol1:/portfolio/portfolio.pfol.pending';
9
+ const PORTFOLIO_PENDING_PATH = 'vol1:/portfolio/portfolio.okpkg.pending';
10
10
  const PORTFOLIO_CHUNK_SIZE = 2048;
11
11
 
12
12
  export default class UploadPortfolio extends FileWrite {
@@ -20,9 +20,11 @@ export default class UploadPortfolio extends FileWrite {
20
20
  chunkSize: PORTFOLIO_CHUNK_SIZE,
21
21
  overwrite: true,
22
22
  append: false,
23
+ emitProgress: false,
23
24
  timeoutMs,
24
25
  };
25
26
  super.init();
27
+ this.unlockPolicy = 'retry-on-locked';
26
28
  }
27
29
 
28
30
  async run() {
@@ -14,7 +14,7 @@ export default class CardanoSignMessage extends BaseMethod<CardanoSignMessagePar
14
14
  init() {
15
15
  this.checkDeviceId = true;
16
16
  this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
17
- this.allowUsePreInitialize = true;
17
+ this.allowUsePreInitialize = false;
18
18
 
19
19
  const { payload } = this;
20
20
  validateParams(payload, [
@@ -48,7 +48,7 @@ export default class CardanoSignTransaction extends BaseMethod<any> {
48
48
  init() {
49
49
  this.checkDeviceId = true;
50
50
  this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
51
- this.allowUsePreInitialize = true;
51
+ this.allowUsePreInitialize = false;
52
52
 
53
53
  this.hasBundle = !!this.payload?.bundle;
54
54
 
@@ -129,17 +129,21 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
129
129
  );
130
130
  options.throwIfAborted?.();
131
131
  lastMessage = response.message;
132
- const processedByte = Number(response.message?.processed_byte);
133
- written =
134
- Number.isFinite(processedByte) && processedByte > offset
135
- ? processedByte - startOffset
136
- : written + chunk.byteLength;
137
- if (written > dataLength) {
132
+ const rawProcessedByte = response.message?.processed_byte;
133
+ const processedByte = Number(rawProcessedByte);
134
+ if (
135
+ rawProcessedByte !== undefined &&
136
+ (!Number.isFinite(processedByte) ||
137
+ processedByte <= offset ||
138
+ processedByte > offset + chunk.byteLength)
139
+ ) {
138
140
  throw ERRORS.TypedError(
139
141
  HardwareErrorCode.RuntimeError,
140
142
  `FilesystemFileWrite invalid processed_byte ${processedByte}`
141
143
  );
142
144
  }
145
+ written =
146
+ rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
143
147
  chunks += 1;
144
148
  const elapsedMs = Date.now() - startTime;
145
149
  const transferredBytes = Math.min(written, dataLength);
package/src/api/index.ts CHANGED
@@ -61,7 +61,6 @@ export { default as deviceSettingsPageShow } from './protocol-v2/DeviceSettingsP
61
61
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
62
62
  export { default as filesystemPermissionFix } from './protocol-v2/FilesystemPermissionFix';
63
63
  export { default as filesystemFormat } from './protocol-v2/FilesystemFormat';
64
- export { default as filesystemDiskControl } from './protocol-v2/FilesystemDiskControl';
65
64
  export { default as fileRead } from './FileRead';
66
65
  export { default as fileWrite } from './FileWrite';
67
66
  export { default as fileDelete } from './FileDelete';
@@ -4,11 +4,12 @@ import { bytesToHex } from '@noble/hashes/utils';
4
4
  import { BaseMethod } from '../BaseMethod';
5
5
  import { invalidParameter } from '../helpers/filesystemValidation';
6
6
  import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
7
+ import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
7
8
  import {
8
- encodePro2Wallpaper,
9
9
  PRO2_WALLPAPER_HEIGHT,
10
10
  PRO2_WALLPAPER_WIDTH,
11
11
  type Pro2WallpaperColorFormat,
12
+ encodePro2Wallpaper,
12
13
  } from '../../utils/pro2Wallpaper';
13
14
 
14
15
  export type DeviceUploadWallpaperParams = {
@@ -90,7 +91,7 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
90
91
 
91
92
  private async upload() {
92
93
  if (this.uploaded) return;
93
- const encoded = this.encoded;
94
+ const { encoded } = this;
94
95
  if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
95
96
 
96
97
  await writeProtocolV2File({
@@ -102,12 +103,17 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
102
103
  overwrite: true,
103
104
  append: false,
104
105
  throwIfAborted: () => this.throwIfAborted(),
106
+ onProgress: payload => {
107
+ if (typeof this.postMessage === 'function') {
108
+ this.postMessage(createUiMessage(UI_REQUEST.DEVICE_PROGRESS, payload));
109
+ }
110
+ },
105
111
  });
106
112
  this.uploaded = true;
107
113
  }
108
114
 
109
115
  async run(): Promise<DeviceUploadWallpaperResponse> {
110
- const encoded = this.encoded;
116
+ const { encoded } = this;
111
117
  if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
112
118
  await this.ensureDirectory();
113
119
  await this.upload();
@@ -118,9 +118,6 @@ export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
118
118
  message.includes('connection has timed out unexpectedly') ||
119
119
  message.includes('connection error has occured') ||
120
120
  message.includes('connection error has occurred') ||
121
- message.includes('transferIn') ||
122
- message.includes('transferin') ||
123
- message.includes('usbdevice') ||
124
121
  message.includes('multiplatformbleadapter') ||
125
122
  message.includes('multipalformebleadapter') ||
126
123
  compactMessage.includes('rxerrorerror6') ||