@onekeyfe/hd-core 1.2.0-alpha.79 → 1.2.0-alpha.80

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 (53) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +51 -5
  2. package/__tests__/check-firmware-release-protocol-v2.test.ts +164 -0
  3. package/__tests__/protocol-v2-resources.test.ts +24 -8
  4. package/__tests__/protocol-v2.test.ts +195 -49
  5. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -3
  6. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  7. package/dist/api/CheckBLEFirmwareRelease.d.ts +2 -1
  8. package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
  9. package/dist/api/CheckBootloaderRelease.d.ts +3 -2
  10. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  11. package/dist/api/CheckFirmwareRelease.d.ts +2 -1
  12. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  13. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  14. package/dist/api/firmware/protocolV2Release.d.ts +33 -0
  15. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -0
  16. package/dist/index.d.ts +35 -49
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +340 -183
  19. package/dist/protocols/protocol-v2/resources.d.ts +0 -4
  20. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  21. package/dist/types/api/checkAllFirmwareRelease.d.ts +20 -9
  22. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  23. package/dist/types/api/checkBLEFirmwareRelease.d.ts +2 -13
  24. package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
  25. package/dist/types/api/checkBootloaderRelease.d.ts +2 -6
  26. package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
  27. package/dist/types/api/checkFirmwareRelease.d.ts +2 -13
  28. package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
  29. package/dist/types/api/checkFirmwareTypeAvailable.d.ts +2 -2
  30. package/dist/types/api/checkFirmwareTypeAvailable.d.ts.map +1 -1
  31. package/dist/types/api/export.d.ts +1 -1
  32. package/dist/types/api/export.d.ts.map +1 -1
  33. package/dist/types/api/firmwareUpdate.d.ts +1 -1
  34. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  35. package/dist/types/settings.d.ts +3 -1
  36. package/dist/types/settings.d.ts.map +1 -1
  37. package/package.json +4 -4
  38. package/src/api/CheckAllFirmwareRelease.ts +49 -49
  39. package/src/api/CheckBLEFirmwareRelease.ts +41 -3
  40. package/src/api/CheckBootloaderRelease.ts +40 -1
  41. package/src/api/CheckFirmwareRelease.ts +37 -3
  42. package/src/api/FirmwareUpdateV4.ts +35 -15
  43. package/src/api/firmware/protocolV2Release.ts +166 -0
  44. package/src/index.ts +0 -1
  45. package/src/protocols/protocol-v2/resources.ts +19 -25
  46. package/src/types/api/checkAllFirmwareRelease.ts +27 -13
  47. package/src/types/api/checkBLEFirmwareRelease.ts +4 -13
  48. package/src/types/api/checkBootloaderRelease.ts +2 -6
  49. package/src/types/api/checkFirmwareRelease.ts +2 -13
  50. package/src/types/api/checkFirmwareTypeAvailable.ts +2 -2
  51. package/src/types/api/export.ts +6 -1
  52. package/src/types/api/firmwareUpdate.ts +2 -3
  53. package/src/types/settings.ts +3 -1
@@ -73,7 +73,9 @@ const release: IFirmwareReleaseInfo = {
73
73
  };
74
74
 
75
75
  const resourceSource = {
76
- manifestUrl: 'https://example.com/pro2-resource/manifest.json',
76
+ archiveUrl: 'https://example.com/pro2-resource/pro2-resource.zip',
77
+ archiveSha256: 'a'.repeat(64),
78
+ archiveSize: 16_815_479,
77
79
  };
78
80
 
79
81
  describe('checkAllFirmwareRelease Protocol V2 support', () => {
@@ -328,8 +330,9 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
328
330
  deviceType: 'pro2',
329
331
  status: 'required',
330
332
  resourceStatus: 'unknown',
331
- resourceManifestUrl: resourceSource.manifestUrl,
332
- targetsToUpdate: ['boot', 'app_v1'],
333
+ resourceArchive: resourceSource,
334
+ resourcePreparationRequired: true,
335
+ targetsToUpdate: ['boot', 'app_v1', 'resource'],
333
336
  firmware: {
334
337
  status: 'required',
335
338
  },
@@ -417,13 +420,56 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
417
420
  await expect(method.run()).resolves.toMatchObject({
418
421
  protocol: 'V2',
419
422
  resourceStatus: 'unknown',
420
- resourceManifestUrl: resourceSource.manifestUrl,
421
- targetsToUpdate: ['boot', 'app_v1'],
423
+ resourceArchive: resourceSource,
424
+ resourcePreparationRequired: true,
425
+ targetsToUpdate: ['boot', 'app_v1', 'resource'],
422
426
  });
423
427
  expect(typedCall).not.toHaveBeenCalled();
424
428
  }
425
429
  );
426
430
 
431
+ test('requires manifest preparation when only Protocol V2 resources may have changed', async () => {
432
+ const currentRelease: IFirmwareReleaseInfo = {
433
+ ...release,
434
+ required: false,
435
+ installOrder: ['applicationP1'],
436
+ components: {
437
+ applicationP1: {
438
+ target: 'APPLICATION_P1',
439
+ url: 'https://example.com/application-p1.okpkg',
440
+ version: [1, 0, 0],
441
+ },
442
+ },
443
+ };
444
+ const method = new CheckAllFirmwareRelease({
445
+ id: 1,
446
+ payload: {
447
+ method: 'checkAllFirmwareRelease',
448
+ firmwareType: EFirmwareType.Universal,
449
+ },
450
+ });
451
+ method.init();
452
+ method.device = {
453
+ isProtocolV2: () => true,
454
+ features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
455
+ getDeviceState: jest.fn().mockResolvedValue({
456
+ identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
457
+ status: { mode: 'normal' },
458
+ versions: { ...currentVersions, applicationP1: '1.0.0' },
459
+ }),
460
+ } as unknown as CheckAllFirmwareRelease['device'];
461
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(currentRelease);
462
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
463
+
464
+ await expect(method.run()).resolves.toMatchObject({
465
+ status: 'unknown',
466
+ hasUpgrade: true,
467
+ resourceStatus: 'unknown',
468
+ resourcePreparationRequired: true,
469
+ targetsToUpdate: ['resource'],
470
+ });
471
+ });
472
+
427
473
  test('continues forwarding the existing public method', async () => {
428
474
  const call = jest.fn().mockResolvedValue({ success: true, payload: {} });
429
475
  const api = createCoreApi(call as CoreApi['call']) as CoreApi;
@@ -0,0 +1,164 @@
1
+ import { EFirmwareType } from '@onekeyfe/hd-shared';
2
+
3
+ import CheckAllFirmwareRelease from '../src/api/CheckAllFirmwareRelease';
4
+ import CheckBLEFirmwareRelease from '../src/api/CheckBLEFirmwareRelease';
5
+ import CheckBootloaderRelease from '../src/api/CheckBootloaderRelease';
6
+ import CheckFirmwareRelease from '../src/api/CheckFirmwareRelease';
7
+ import { DataManager } from '../src/data-manager';
8
+
9
+ import type { IFirmwareReleaseInfo } from '../src/types';
10
+
11
+ jest.mock('../src/data/config', () => ({
12
+ DEFAULT_DOMAIN: 'https://example.com/',
13
+ getSDKVersion: () => '0.0.0-test',
14
+ }));
15
+
16
+ const release: IFirmwareReleaseInfo = {
17
+ required: false,
18
+ version: [2, 0, 0],
19
+ url: 'https://example.com/application-p1.okpkg',
20
+ fingerprint: 'release-fingerprint',
21
+ changelog: {
22
+ 'zh-CN': '更新',
23
+ 'en-US': 'Update',
24
+ },
25
+ installOrder: ['bootloader', 'applicationP1', 'coprocessor'],
26
+ components: {
27
+ bootloader: {
28
+ target: 'BOOTLOADER',
29
+ url: 'https://example.com/bootloader.okpkg',
30
+ version: [2, 0, 0],
31
+ },
32
+ applicationP1: {
33
+ target: 'APPLICATION_P1',
34
+ url: 'https://example.com/application-p1.okpkg',
35
+ version: [2, 0, 0],
36
+ },
37
+ coprocessor: {
38
+ target: 'COPROCESSOR',
39
+ url: 'https://example.com/coprocessor.okpkg',
40
+ version: [2, 0, 0],
41
+ },
42
+ },
43
+ };
44
+
45
+ const createDevice = (deviceType: 'pro2' | 'neo') => ({
46
+ isProtocolV2: () => true,
47
+ features: {
48
+ deviceType,
49
+ firmwareVersion: '1.0.0',
50
+ },
51
+ getDeviceState: jest.fn().mockResolvedValue({
52
+ identity: {
53
+ deviceType,
54
+ firmwareType: EFirmwareType.Universal,
55
+ },
56
+ status: { mode: 'normal' },
57
+ versions: {
58
+ firmware: '1.0.0',
59
+ applicationP1: '1.0.0',
60
+ bootloader: '1.0.0',
61
+ board: '1.0.0',
62
+ ble: '1.0.0',
63
+ },
64
+ }),
65
+ });
66
+
67
+ describe.each(['pro2', 'neo'] as const)('Protocol V2 release checks for %s', deviceType => {
68
+ afterEach(() => {
69
+ jest.restoreAllMocks();
70
+ });
71
+
72
+ test('supports firmware, BLE, bootloader, and aggregate release checks', async () => {
73
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
74
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue({
75
+ archiveUrl: `https://example.com/${deviceType}/pro2-resource.zip`,
76
+ archiveSha256: 'a'.repeat(64),
77
+ archiveSize: 16_815_479,
78
+ });
79
+
80
+ const firmwareMethod = new CheckFirmwareRelease({
81
+ id: 1,
82
+ payload: { method: 'checkFirmwareRelease' },
83
+ });
84
+ firmwareMethod.init();
85
+ firmwareMethod.device = createDevice(deviceType) as unknown as CheckFirmwareRelease['device'];
86
+
87
+ const bleMethod = new CheckBLEFirmwareRelease({
88
+ id: 2,
89
+ payload: { method: 'checkBLEFirmwareRelease' },
90
+ });
91
+ bleMethod.init();
92
+ bleMethod.device = createDevice(deviceType) as unknown as CheckBLEFirmwareRelease['device'];
93
+
94
+ const bootloaderMethod = new CheckBootloaderRelease({
95
+ id: 3,
96
+ payload: { method: 'checkBootloaderRelease' },
97
+ });
98
+ bootloaderMethod.init();
99
+ bootloaderMethod.device = createDevice(
100
+ deviceType
101
+ ) as unknown as CheckBootloaderRelease['device'];
102
+
103
+ const allMethod = new CheckAllFirmwareRelease({
104
+ id: 4,
105
+ payload: { method: 'checkAllFirmwareRelease' },
106
+ });
107
+ allMethod.init();
108
+ allMethod.device = createDevice(deviceType) as unknown as CheckAllFirmwareRelease['device'];
109
+
110
+ await expect(firmwareMethod.run()).resolves.toMatchObject({
111
+ status: 'outdated',
112
+ shouldUpdate: true,
113
+ release,
114
+ });
115
+ await expect(bleMethod.run()).resolves.toMatchObject({
116
+ status: 'outdated',
117
+ shouldUpdate: true,
118
+ release: {
119
+ protocol: 'V2',
120
+ configKey: 'coprocessor',
121
+ componentTarget: 'COPROCESSOR',
122
+ target: 'COPROCESSOR',
123
+ url: 'https://example.com/coprocessor.okpkg',
124
+ version: [2, 0, 0],
125
+ },
126
+ });
127
+ await expect(bootloaderMethod.run()).resolves.toMatchObject({
128
+ status: 'outdated',
129
+ shouldUpdate: true,
130
+ release: {
131
+ protocol: 'V2',
132
+ configKey: 'bootloader',
133
+ componentTarget: 'BOOTLOADER',
134
+ target: 'BOOTLOADER',
135
+ url: 'https://example.com/bootloader.okpkg',
136
+ version: [2, 0, 0],
137
+ },
138
+ });
139
+ await expect(allMethod.run()).resolves.toMatchObject({
140
+ protocol: 'V2',
141
+ deviceType,
142
+ status: 'outdated',
143
+ hasUpgrade: true,
144
+ resourcePreparationRequired: true,
145
+ targetsToUpdate: ['boot', 'app_v1', 'coprocessor', 'resource'],
146
+ firmware: { status: 'outdated', shouldUpdate: true },
147
+ ble: {
148
+ status: 'outdated',
149
+ shouldUpdate: true,
150
+ release: { componentTarget: 'COPROCESSOR' },
151
+ },
152
+ bootloader: {
153
+ status: 'outdated',
154
+ shouldUpdate: true,
155
+ release: { componentTarget: 'BOOTLOADER' },
156
+ },
157
+ });
158
+
159
+ expect(firmwareMethod.getSupportedProtocols()).toEqual(['V1', 'V2']);
160
+ expect(bleMethod.getSupportedProtocols()).toEqual(['V1', 'V2']);
161
+ expect(bootloaderMethod.getSupportedProtocols()).toEqual(['V1', 'V2']);
162
+ expect(allMethod.getSupportedProtocols()).toEqual(['V1', 'V2']);
163
+ });
164
+ });
@@ -22,7 +22,9 @@ const bytesToHex = (bytes: Uint8Array) =>
22
22
  Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
23
23
 
24
24
  const resourceSource = {
25
- manifestUrl: 'https://example.com/resource/manifest.json',
25
+ archiveUrl: 'https://example.com/resource/pro2-resource.zip',
26
+ archiveSha256: 'a'.repeat(64),
27
+ archiveSize: 16_815_479,
26
28
  };
27
29
 
28
30
  const manifestFiles = [
@@ -122,8 +124,23 @@ describe('Pro2 resource configuration', () => {
122
124
  test('rejects missing source and malformed manifest paths', () => {
123
125
  expect(() => parseProtocolV2Resources({})).toThrow('source is required');
124
126
  expect(() =>
125
- parseProtocolV2Resources({ source: { manifestUrl: 'http://example.com/manifest.json' } })
127
+ parseProtocolV2Resources({
128
+ source: {
129
+ ...resourceSource,
130
+ archiveUrl: 'http://example.com/pro2-resource.zip',
131
+ },
132
+ })
126
133
  ).toThrow('must use HTTPS');
134
+ expect(() =>
135
+ parseProtocolV2Resources({
136
+ source: { ...resourceSource, archiveSha256: 'invalid' },
137
+ })
138
+ ).toThrow('SHA-256');
139
+ expect(() =>
140
+ parseProtocolV2Resources({
141
+ source: { ...resourceSource, archiveSize: 0 },
142
+ })
143
+ ).toThrow('positive integer');
127
144
  expect(() =>
128
145
  parseProtocolV2ResourceManifest({
129
146
  ...resourceManifest,
@@ -141,12 +158,11 @@ describe('Pro2 resource configuration', () => {
141
158
  archivePath: file.archive_path,
142
159
  binary: file.binary,
143
160
  })),
144
- targetsToUpdate: ['boot_resources'],
161
+ targetsToUpdate: ['resource'],
145
162
  });
146
- expect(prepared.map(file => file.devicePath)).toEqual([
147
- 'vol0:/loaders/bootloader/boot_resource.okpkg',
148
- 'vol0:/loaders/rom/params.okpkg',
149
- ]);
163
+ expect(prepared.map(file => file.devicePath)).toEqual(
164
+ manifestFiles.map(file => file.device_path)
165
+ );
150
166
  expect(() =>
151
167
  prepareProtocolV2ResourceFiles({
152
168
  manifest: resourceManifest,
@@ -171,7 +187,7 @@ describe('Pro2 resource configuration', () => {
171
187
  );
172
188
  });
173
189
 
174
- test('applies a validated pre-release config and exposes its manifest source', async () => {
190
+ test('applies a validated pre-release config and exposes its archive source', async () => {
175
191
  const configFetcher = jest.fn().mockResolvedValue(createRemoteConfig());
176
192
 
177
193
  await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
@@ -114,6 +114,26 @@ jest.mock('../src/data/config', () => ({
114
114
  DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
115
115
  }));
116
116
 
117
+ const createProtocolV2OkppBinary = ({
118
+ version = [1, 2, 3],
119
+ payloadHashByte = 0x11,
120
+ headerHashByte = 0x22,
121
+ }: {
122
+ version?: [number, number, number];
123
+ payloadHashByte?: number;
124
+ headerHashByte?: number;
125
+ } = {}) => {
126
+ const bytes = new Uint8Array(0x52a0);
127
+ bytes.set([0x4f, 0x4b, 0x50, 0x50], 0);
128
+ bytes.set([0x52, 0x45, 0x53, 0x43], 0x08);
129
+ const view = new DataView(bytes.buffer);
130
+ view.setUint32(0x0c, 0x52a0, true);
131
+ view.setUint32(0x10, version[0] * 0x10000 + version[1] * 0x100 + version[2], true);
132
+ bytes.fill(payloadHashByte, 0x200, 0x240);
133
+ bytes.fill(headerHashByte, 0x240, 0x280);
134
+ return bytes.buffer;
135
+ };
136
+
117
137
  const createWalletSessionTypedCall = (
118
138
  implementation = jest.fn(),
119
139
  status: Partial<DeviceStatus> = { passphrase_enabled: true }
@@ -5554,6 +5574,7 @@ describe('Protocol V2 firmware update targets', () => {
5554
5574
  (method as any).waitForProtocolV2FirmwareUpdateComplete = jest
5555
5575
  .fn()
5556
5576
  .mockResolvedValue(undefined);
5577
+ (method as any).isProtocolV2ResourceBundleUpToDate = jest.fn().mockResolvedValue(false);
5557
5578
 
5558
5579
  await (method as any).executeProtocolV2Update({
5559
5580
  resourceBundles: [
@@ -5561,6 +5582,9 @@ describe('Protocol V2 firmware update targets', () => {
5561
5582
  name: 'images.okpkg',
5562
5583
  binary: new Uint8Array([1, 2]).buffer,
5563
5584
  devicePath: 'vol0:/bundles/images/images.okpkg',
5585
+ version: [1, 2, 3],
5586
+ payloadHash: '11'.repeat(64),
5587
+ headerHash: '22'.repeat(64),
5564
5588
  },
5565
5589
  ],
5566
5590
  bootloaderBinary: null,
@@ -5585,6 +5609,13 @@ describe('Protocol V2 firmware update targets', () => {
5585
5609
  2,
5586
5610
  expect.objectContaining({ processedSize: 0, totalSize: 1 })
5587
5611
  );
5612
+ expect((method as any).isProtocolV2ResourceBundleUpToDate).toHaveBeenCalledWith(
5613
+ expect.objectContaining({
5614
+ version: [1, 2, 3],
5615
+ payloadHash: '11'.repeat(64),
5616
+ headerHash: '22'.repeat(64),
5617
+ })
5618
+ );
5588
5619
  });
5589
5620
 
5590
5621
  test('installs and verifies bootloader before syncing manifest resources', () => {
@@ -6111,58 +6142,118 @@ describe('Protocol V2 firmware update targets', () => {
6111
6142
  });
6112
6143
  });
6113
6144
 
6114
- test.each(['resource', 'boot_resources'] as const)(
6115
- 'treats manual resource files as authoritative payload for %s',
6116
- async target => {
6117
- const resourceBundle = new Uint8Array([1, 2, 3]).buffer;
6118
- const method = new FirmwareUpdateV4({
6119
- id: 1,
6120
- payload: {
6121
- method: 'firmwareUpdateV4',
6122
- platform: 'web',
6123
- targetsToUpdate: [target],
6124
- resourceFiles: [
6125
- {
6126
- binary: resourceBundle,
6127
- devicePath: ' VOL0:/resource/images/images.okpkg ',
6128
- },
6129
- ],
6145
+ test('treats manual resource files as authoritative payload for resource', async () => {
6146
+ const resourceBundle = createProtocolV2OkppBinary();
6147
+ const method = new FirmwareUpdateV4({
6148
+ id: 1,
6149
+ payload: {
6150
+ method: 'firmwareUpdateV4',
6151
+ platform: 'web',
6152
+ targetsToUpdate: ['resource'],
6153
+ resourceFiles: [
6154
+ {
6155
+ binary: resourceBundle,
6156
+ devicePath: ' VOL0:/resource/images/images.okpkg ',
6157
+ },
6158
+ ],
6159
+ },
6160
+ });
6161
+ method.init();
6162
+ (method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
6163
+ (method as any).device = stubDevice({
6164
+ originalDescriptor: { protocolType: 'V2' },
6165
+ features: { deviceType: 'pro2', firmwareVersion: '0.0.0', capabilities: [] },
6166
+ });
6167
+ (method as any).prepareRemoteProtocolV2Binaries = jest.fn();
6168
+ (method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(true);
6169
+ (method as any).executeProtocolV2Update = jest.fn().mockResolvedValue(undefined);
6170
+ (method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
6171
+ (method as any).waitForProtocolV2FinalFeatures = jest.fn().mockResolvedValue({
6172
+ bootloaderVersion: '1.0.0',
6173
+ bleVersion: '0.0.0',
6174
+ firmwareVersion: '1.0.0',
6175
+ });
6176
+ method.postTipMessage = jest.fn();
6177
+
6178
+ await method.run();
6179
+
6180
+ expect(forceReloadDataSpy).not.toHaveBeenCalled();
6181
+ expect((method as any).prepareRemoteProtocolV2Binaries).not.toHaveBeenCalled();
6182
+ expect((method as any).executeProtocolV2Update).toHaveBeenCalledWith(
6183
+ expect.objectContaining({
6184
+ resourceBundles: [
6185
+ {
6186
+ name: 'images.okpkg',
6187
+ binary: resourceBundle,
6188
+ devicePath: 'vol0:/resource/images/images.okpkg',
6189
+ version: [1, 2, 3],
6190
+ payloadHash: '11'.repeat(64),
6191
+ headerHash: '22'.repeat(64),
6192
+ },
6193
+ ],
6194
+ })
6195
+ );
6196
+ });
6197
+
6198
+ test('combines prepared firmware components with explicit manifest resource files', async () => {
6199
+ const resourceBundle = createProtocolV2OkppBinary();
6200
+ const method = new FirmwareUpdateV4({
6201
+ id: 1,
6202
+ payload: {
6203
+ method: 'firmwareUpdateV4',
6204
+ platform: 'web',
6205
+ },
6206
+ });
6207
+ method.init();
6208
+ (method as any).params = {
6209
+ targetsToUpdate: ['app_v1', 'resource'],
6210
+ resourceFiles: [
6211
+ {
6212
+ binary: resourceBundle,
6213
+ devicePath: 'vol0:/bundles/images/images.okpkg',
6130
6214
  },
6131
- });
6132
- method.init();
6133
- (method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
6134
- (method as any).device = stubDevice({
6135
- originalDescriptor: { protocolType: 'V2' },
6136
- features: { deviceType: 'pro2', firmwareVersion: '0.0.0', capabilities: [] },
6137
- });
6138
- (method as any).prepareRemoteProtocolV2Binaries = jest.fn();
6139
- (method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(true);
6140
- (method as any).executeProtocolV2Update = jest.fn().mockResolvedValue(undefined);
6141
- (method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
6142
- (method as any).waitForProtocolV2FinalFeatures = jest.fn().mockResolvedValue({
6143
- bootloaderVersion: '1.0.0',
6144
- bleVersion: '0.0.0',
6145
- firmwareVersion: '1.0.0',
6146
- });
6147
- method.postTipMessage = jest.fn();
6215
+ ],
6216
+ };
6217
+ const firmwareSource = { size: 10 };
6218
+ const resourceSource = { size: resourceBundle.byteLength };
6219
+ (method as any).prepareProtocolV2InstallSources = jest.fn().mockResolvedValue([
6220
+ {
6221
+ fileName: 'application_p1.bin',
6222
+ source: firmwareSource,
6223
+ targetId: 4,
6224
+ kind: 'firmware',
6225
+ },
6226
+ ]);
6227
+ (method as any).prepareProtocolV2ResourceSources = jest.fn();
6228
+ (method as any).openProtocolV2MemorySource = jest.fn().mockResolvedValue(resourceSource);
6229
+ (method as any).executeProtocolV2SourceUpdate = jest.fn().mockResolvedValue(undefined);
6230
+ (method as any).closeProtocolV2PreparedSources = jest.fn().mockResolvedValue(undefined);
6231
+ method.postTipMessage = jest.fn();
6148
6232
 
6149
- await method.run();
6233
+ await (method as any).runProtocolV2PreparedArtifacts({ deviceType: 'pro2' }, 'universal');
6150
6234
 
6151
- expect(forceReloadDataSpy).not.toHaveBeenCalled();
6152
- expect((method as any).prepareRemoteProtocolV2Binaries).not.toHaveBeenCalled();
6153
- expect((method as any).executeProtocolV2Update).toHaveBeenCalledWith(
6154
- expect.objectContaining({
6155
- resourceBundles: [
6156
- {
6157
- name: 'images.okpkg',
6158
- binary: resourceBundle,
6159
- devicePath: 'vol0:/resource/images/images.okpkg',
6160
- },
6161
- ],
6162
- })
6163
- );
6164
- }
6165
- );
6235
+ expect((method as any).prepareProtocolV2ResourceSources).not.toHaveBeenCalled();
6236
+ expect((method as any).executeProtocolV2SourceUpdate).toHaveBeenCalledWith({
6237
+ installSources: [
6238
+ {
6239
+ fileName: 'application_p1.bin',
6240
+ source: firmwareSource,
6241
+ targetId: 4,
6242
+ kind: 'firmware',
6243
+ },
6244
+ ],
6245
+ resourceSources: [
6246
+ {
6247
+ name: 'images.okpkg',
6248
+ source: resourceSource,
6249
+ devicePath: 'vol0:/bundles/images/images.okpkg',
6250
+ version: [1, 2, 3],
6251
+ payloadHash: '11'.repeat(64),
6252
+ headerHash: '22'.repeat(64),
6253
+ },
6254
+ ],
6255
+ });
6256
+ });
6166
6257
 
6167
6258
  test('rejects manual RESC bundle paths before bootloader entry', async () => {
6168
6259
  const method = new FirmwareUpdateV4({
@@ -7086,6 +7177,61 @@ describe('Protocol V2 firmware reconnect identity', () => {
7086
7177
  expect(Math.max(...readChunkLengths)).toBe(900);
7087
7178
  });
7088
7179
 
7180
+ test('skips resource transfer when installed okpkg hashes match the downloaded package', async () => {
7181
+ const method = new FirmwareUpdateV4({
7182
+ id: 1,
7183
+ payload: {
7184
+ method: 'firmwareUpdateV4',
7185
+ platform: 'web',
7186
+ },
7187
+ });
7188
+ method.init();
7189
+ const installedBinary = new Uint8Array(createProtocolV2OkppBinary());
7190
+ const typedCall = jest.fn((requestType: string, _responseType: string, request: any) => {
7191
+ if (requestType === 'FilesystemPathInfoQuery') {
7192
+ return Promise.resolve({
7193
+ message: { exist: true, directory: false, size: installedBinary.byteLength },
7194
+ });
7195
+ }
7196
+ if (requestType === 'FilesystemFileRead') {
7197
+ return Promise.resolve({
7198
+ message: {
7199
+ data: installedBinary.slice(
7200
+ Number(request.file.offset),
7201
+ Number(request.file.offset) + Number(request.chunk_len)
7202
+ ),
7203
+ },
7204
+ });
7205
+ }
7206
+ throw new Error(`Unexpected request: ${requestType}`);
7207
+ });
7208
+ (method as any).device = stubDevice({
7209
+ getCommands: () => ({ typedCall }),
7210
+ });
7211
+ method.postTipMessage = jest.fn();
7212
+ method.postProgressMessage = jest.fn();
7213
+ (method as any).protocolV2SourceUpdateProcess = jest.fn();
7214
+
7215
+ await (method as any).executeProtocolV2TransferPhase({
7216
+ installSources: [],
7217
+ resourceSources: [
7218
+ {
7219
+ name: 'images.okpkg',
7220
+ source: { size: installedBinary.byteLength },
7221
+ devicePath: 'vol0:/bundles/images/images.okpkg',
7222
+ version: [1, 2, 3],
7223
+ payloadHash: '11'.repeat(64),
7224
+ headerHash: '22'.repeat(64),
7225
+ },
7226
+ ],
7227
+ });
7228
+
7229
+ expect(typedCall).toHaveBeenCalledWith('FilesystemPathInfoQuery', 'FilesystemPathInfo', {
7230
+ path: 'vol0:/bundles/images/images.okpkg',
7231
+ });
7232
+ expect((method as any).protocolV2SourceUpdateProcess).not.toHaveBeenCalled();
7233
+ });
7234
+
7089
7235
  test('rejects a manually supplied resource file when its manifest hash does not match', () => {
7090
7236
  const method = new FirmwareUpdateV4({
7091
7237
  id: 1,
@@ -1,9 +1,9 @@
1
- import { EFirmwareType } from '@onekeyfe/hd-shared';
2
1
  import { BaseMethod } from './BaseMethod';
2
+ import type { EFirmwareType } from '@onekeyfe/hd-shared';
3
3
  import type { AllFirmwareRelease, ProtocolV2FirmwareComponentRelease, ProtocolV2FirmwareReleaseStatus } from '../types/api/checkAllFirmwareRelease';
4
4
  import type { FirmwareUpdateV4Target } from '../types/api/firmwareUpdate';
5
5
  import type { DeviceFeaturesVerify, DeviceStateVersions, IFirmwareReleaseInfo } from '../types';
6
- type ProtocolV2FirmwareReleasePlan = {
6
+ export type ProtocolV2FirmwareReleasePlan = {
7
7
  firmwareType: EFirmwareType;
8
8
  status: ProtocolV2FirmwareReleaseStatus;
9
9
  hasUpgrade: boolean;
@@ -28,5 +28,4 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
28
28
  run(): Promise<AllFirmwareRelease | null>;
29
29
  private runProtocolV2;
30
30
  }
31
- export {};
32
31
  //# sourceMappingURL=CheckAllFirmwareRelease.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAqB1C,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,KAAK,6BAA6B,GAAG;IACnC,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CAmE5B"}
1
+ {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA8B1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CA+D5B"}
@@ -1,7 +1,8 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  export default class CheckBLEFirmwareRelease extends BaseMethod {
3
+ getSupportedProtocols(): readonly ["V1", "V2"];
3
4
  init(): void;
4
- run(): Promise<null> | Promise<{
5
+ run(): Promise<import("..").FirmwareReleaseCheckResult | {
5
6
  status: import("..").IDeviceBLEFirmwareStatus;
6
7
  changelog: {
7
8
  "zh-CN": string;
@@ -1 +1 @@
1
- {"version":3,"file":"CheckBLEFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckBLEFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI1C,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,IAAI;IAUJ,GAAG;;;;;;;;;CAOJ"}
1
+ {"version":3,"file":"CheckBLEFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckBLEFirmwareRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAY1C,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAUE,GAAG;;;;;;;;;CA+BV"}
@@ -1,7 +1,8 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  export default class CheckBootloaderRelease extends BaseMethod {
3
+ getSupportedProtocols(): readonly ["V1", "V2"];
3
4
  init(): void;
4
- run(): Promise<{
5
+ run(): Promise<import("..").FirmwareReleaseCheckResult | {
5
6
  status: string;
6
7
  changelog: ({
7
8
  "zh-CN": string;
@@ -10,6 +11,6 @@ export default class CheckBootloaderRelease extends BaseMethod {
10
11
  release: import("..").IFirmwareReleaseInfo | undefined;
11
12
  bootloaderMode: boolean;
12
13
  shouldUpdate: boolean;
13
- } | null>;
14
+ }>;
14
15
  }
15
16
  //# sourceMappingURL=CheckBootloaderRelease.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CheckBootloaderRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckBootloaderRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,UAAU;IAC5D,IAAI;IAME,GAAG;;;;;;;;;;CAiBV"}
1
+ {"version":3,"file":"CheckBootloaderRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckBootloaderRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAc1C,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,UAAU;IAC5D,qBAAqB;IAIrB,IAAI;IAME,GAAG;;;;;;;;;;CA0CV"}
@@ -1,7 +1,8 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  export default class CheckFirmwareRelease extends BaseMethod {
3
+ getSupportedProtocols(): readonly ["V1", "V2"];
3
4
  init(): void;
4
- run(): Promise<null> | Promise<{
5
+ run(): Promise<import("..").FirmwareReleaseCheckResult | {
5
6
  status: import("..").IDeviceFirmwareStatus;
6
7
  changelog: {
7
8
  "zh-CN": string;