@onekeyfe/hd-core 1.2.0-alpha.93 → 1.2.0-alpha.95

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.
@@ -2,6 +2,7 @@ import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
4
4
  import FirmwareUpdateV3 from '../../src/api/FirmwareUpdateV3';
5
+ import FirmwareUpdateV4 from '../../src/api/FirmwareUpdateV4';
5
6
  import DeviceUpdateBootloader from '../../src/api/device/DeviceUpdateBootloader';
6
7
  import {
7
8
  registerFirmwareUpdateHostBinding,
@@ -95,6 +96,47 @@ const registerMismatchedHost = () => {
95
96
  return { artifactReader, hostBindingGeneration };
96
97
  };
97
98
 
99
+ const createPreparedV4Plan = () => {
100
+ const sha256 = 'c'.repeat(64);
101
+ const artifact: FirmwareArtifactReference = {
102
+ artifactRef: `fw:${sha256}`,
103
+ size: 4,
104
+ sha256,
105
+ };
106
+ const plan = buildFirmwareUpdatePlan({
107
+ features: {
108
+ deviceType: EDeviceType.Pro2,
109
+ serialNo: 'pro2-device-id',
110
+ firmwareVersion: '1.0.0',
111
+ bootloaderVersion: '1.0.0',
112
+ } as Features,
113
+ firmwareType: EFirmwareType.Universal,
114
+ platform: 'desktop',
115
+ firmware: {
116
+ status: 'outdated',
117
+ release: {
118
+ components: {
119
+ applicationP1: {
120
+ target: 'APPLICATION_P1',
121
+ url: 'https://firmware.onekey.so/pro2/application-p1.bin',
122
+ expectedSize: artifact.size,
123
+ fingerprint: artifact.sha256,
124
+ },
125
+ },
126
+ },
127
+ },
128
+ ble: noUpdate,
129
+ bootloader: noUpdate,
130
+ });
131
+ expect(plan.executor).toBe('v4');
132
+ const preparedPlan = prepareFirmwareUpdatePlan({
133
+ plan,
134
+ leaseRef: 'fwlease:v4:app_v1',
135
+ artifacts: [{ artifactId: 'component:app_v1', artifact }],
136
+ });
137
+ return { artifact, preparedPlan };
138
+ };
139
+
98
140
  describe('prepared firmware host digest binding', () => {
99
141
  afterEach(() => {
100
142
  unregisterFirmwareUpdateHostBinding();
@@ -123,6 +165,51 @@ describe('prepared firmware host digest binding', () => {
123
165
  expect(artifactReader.open).not.toHaveBeenCalled();
124
166
  });
125
167
 
168
+ test('FirmwareUpdateV2 rejects a direct reader when the prepared host generation is missing', () => {
169
+ const { artifact, preparedPlan } = createPreparedPlan({
170
+ executor: 'v2',
171
+ target: 'firmware',
172
+ });
173
+ const directArtifactReader = {
174
+ open: jest.fn(),
175
+ read: jest.fn(),
176
+ close: jest.fn(),
177
+ };
178
+ const method = new FirmwareUpdateV2({
179
+ id: 1,
180
+ payload: {
181
+ method: 'firmwareUpdateV2',
182
+ platform: 'desktop',
183
+ updateType: 'firmware',
184
+ artifact,
185
+ preparedPlan,
186
+ artifactReader: directArtifactReader,
187
+ },
188
+ });
189
+
190
+ expect(() => method.init()).toThrow('host binding generation NaN is stale');
191
+ expect(directArtifactReader.open).not.toHaveBeenCalled();
192
+ });
193
+
194
+ test('FirmwareUpdateV2 does not treat a binary call carrying a prepared plan as legacy', () => {
195
+ const { preparedPlan } = createPreparedPlan({
196
+ executor: 'v2',
197
+ target: 'firmware',
198
+ });
199
+ const method = new FirmwareUpdateV2({
200
+ id: 1,
201
+ payload: {
202
+ method: 'firmwareUpdateV2',
203
+ platform: 'desktop',
204
+ updateType: 'firmware',
205
+ binary: new ArrayBuffer(4),
206
+ preparedPlan,
207
+ },
208
+ });
209
+
210
+ expect(() => method.init()).toThrow('Prepared firmware plans require a prepared artifact');
211
+ });
212
+
126
213
  test('FirmwareUpdateV3 rejects a host registered for another prepared plan', () => {
127
214
  const { artifact, preparedPlan } = createPreparedPlan({
128
215
  executor: 'v3',
@@ -144,6 +231,31 @@ describe('prepared firmware host digest binding', () => {
144
231
  expect(artifactReader.open).not.toHaveBeenCalled();
145
232
  });
146
233
 
234
+ test('FirmwareUpdateV3 rejects a direct reader when the prepared host generation is missing', () => {
235
+ const { artifact, preparedPlan } = createPreparedPlan({
236
+ executor: 'v3',
237
+ target: 'firmware',
238
+ });
239
+ const directArtifactReader = {
240
+ open: jest.fn(),
241
+ read: jest.fn(),
242
+ close: jest.fn(),
243
+ };
244
+ const method = new FirmwareUpdateV3({
245
+ id: 1,
246
+ payload: {
247
+ method: 'firmwareUpdateV3',
248
+ platform: 'desktop',
249
+ artifacts: { firmware: artifact },
250
+ preparedPlan,
251
+ artifactReader: directArtifactReader,
252
+ },
253
+ });
254
+
255
+ expect(() => method.init()).toThrow('host binding generation NaN is stale');
256
+ expect(directArtifactReader.open).not.toHaveBeenCalled();
257
+ });
258
+
147
259
  test('DeviceUpdateBootloader rejects a host registered for another prepared plan', async () => {
148
260
  const { artifact, preparedPlan } = createPreparedPlan({
149
261
  executor: 'v2',
@@ -170,6 +282,133 @@ describe('prepared firmware host digest binding', () => {
170
282
  expect(artifactReader.open).not.toHaveBeenCalled();
171
283
  });
172
284
 
285
+ test('DeviceUpdateBootloader rejects a direct reader when the prepared host generation is missing', async () => {
286
+ const { artifact, preparedPlan } = createPreparedPlan({
287
+ executor: 'v2',
288
+ target: 'bootloader',
289
+ });
290
+ const directArtifactReader = {
291
+ open: jest.fn(),
292
+ read: jest.fn(),
293
+ close: jest.fn(),
294
+ };
295
+ const method = new DeviceUpdateBootloader({
296
+ id: 1,
297
+ payload: {
298
+ method: 'deviceUpdateBootloader',
299
+ artifact,
300
+ preparedPlan,
301
+ artifactReader: directArtifactReader,
302
+ },
303
+ });
304
+ method.device = {
305
+ features: {
306
+ deviceType: EDeviceType.Classic1s,
307
+ serialNo: 'classic-device-id',
308
+ },
309
+ } as any;
310
+
311
+ await expect(method.run()).rejects.toThrow('host binding generation NaN is stale');
312
+ expect(directArtifactReader.open).not.toHaveBeenCalled();
313
+ });
314
+
315
+ test('DeviceUpdateBootloader does not treat a binary call carrying a prepared plan as legacy', async () => {
316
+ const { preparedPlan } = createPreparedPlan({
317
+ executor: 'v2',
318
+ target: 'bootloader',
319
+ });
320
+ const method = new DeviceUpdateBootloader({
321
+ id: 1,
322
+ payload: {
323
+ method: 'deviceUpdateBootloader',
324
+ binary: new ArrayBuffer(4),
325
+ preparedPlan,
326
+ },
327
+ });
328
+ method.device = { features: undefined } as any;
329
+
330
+ await expect(method.run()).rejects.toThrow(
331
+ 'Prepared bootloader plans require exactly one prepared artifact'
332
+ );
333
+ });
334
+
335
+ test('FirmwareUpdateV4 rejects a prepared plan without a host binding generation', () => {
336
+ const { preparedPlan } = createPreparedV4Plan();
337
+ const directArtifactReader = {
338
+ open: jest.fn(),
339
+ read: jest.fn(),
340
+ close: jest.fn(),
341
+ };
342
+ const method = new FirmwareUpdateV4({
343
+ id: 1,
344
+ payload: {
345
+ method: 'firmwareUpdateV4',
346
+ platform: 'desktop',
347
+ preparedPlan,
348
+ artifactReader: directArtifactReader,
349
+ },
350
+ });
351
+
352
+ expect(() => method.init()).toThrow('host binding generation NaN is stale');
353
+ expect(directArtifactReader.open).not.toHaveBeenCalled();
354
+ });
355
+
356
+ test('FirmwareUpdateV4 rejects a host registered for another prepared plan', () => {
357
+ const { preparedPlan } = createPreparedV4Plan();
358
+ const { artifactReader, hostBindingGeneration } = registerMismatchedHost();
359
+ const method = new FirmwareUpdateV4({
360
+ id: 1,
361
+ payload: {
362
+ method: 'firmwareUpdateV4',
363
+ platform: 'desktop',
364
+ preparedPlan,
365
+ hostBindingGeneration,
366
+ },
367
+ });
368
+
369
+ expect(() => method.init()).toThrow('does not match the prepared plan');
370
+ expect(artifactReader.open).not.toHaveBeenCalled();
371
+ });
372
+
373
+ test('FirmwareUpdateV4 obtains the prepared reader only from the digest-bound host', async () => {
374
+ const { artifact, preparedPlan } = createPreparedV4Plan();
375
+ const directArtifactReader = {
376
+ open: jest.fn(),
377
+ read: jest.fn(),
378
+ close: jest.fn(),
379
+ };
380
+ const boundArtifactReader = {
381
+ open: jest.fn().mockResolvedValue({ readerId: 'bound-reader', size: artifact.size }),
382
+ read: jest.fn(),
383
+ close: jest.fn(),
384
+ };
385
+ const hostBindingGeneration = registerFirmwareUpdateHostBinding({
386
+ preparedPlanDigest: preparedPlan.preparedPlanDigest,
387
+ artifactReader: boundArtifactReader,
388
+ });
389
+ const method = new FirmwareUpdateV4({
390
+ id: 1,
391
+ payload: {
392
+ method: 'firmwareUpdateV4',
393
+ platform: 'desktop',
394
+ preparedPlan,
395
+ hostBindingGeneration,
396
+ artifactReader: directArtifactReader,
397
+ },
398
+ });
399
+
400
+ method.init();
401
+ const executionReader = (
402
+ method as unknown as {
403
+ params: { artifactReader: typeof boundArtifactReader };
404
+ }
405
+ ).params.artifactReader;
406
+ await executionReader.open({ artifactRef: artifact.artifactRef });
407
+
408
+ expect(boundArtifactReader.open).toHaveBeenCalledWith({ artifactRef: artifact.artifactRef });
409
+ expect(directArtifactReader.open).not.toHaveBeenCalled();
410
+ });
411
+
173
412
  test('keeps non-prepared direct binary calls on the legacy paths', async () => {
174
413
  const v2 = new FirmwareUpdateV2({
175
414
  id: 1,
@@ -6159,8 +6159,8 @@ describe('Protocol V2 firmware update targets', () => {
6159
6159
  });
6160
6160
  const imagesBinary = createProtocolV2OkppBinary();
6161
6161
  const bootBinary = createProtocolV2OkppBinary({ payloadHashByte: 0x33 });
6162
- const imagesSha256 = '1'.repeat(64);
6163
- const bootSha256 = '2'.repeat(64);
6162
+ const imagesSha256 = bytesToHex(sha256(new Uint8Array(imagesBinary)));
6163
+ const bootSha256 = bytesToHex(sha256(new Uint8Array(bootBinary)));
6164
6164
  const manifest = {
6165
6165
  schema: 1,
6166
6166
  artifact_name: 'pro2-resource',
@@ -6198,11 +6198,38 @@ describe('Protocol V2 firmware update targets', () => {
6198
6198
  ],
6199
6199
  };
6200
6200
  const manifestBinary = new TextEncoder().encode(JSON.stringify(manifest)).buffer;
6201
- const artifacts = new Map([
6202
- ['manifest', manifestBinary],
6203
- ['images', imagesBinary],
6204
- ['boot', bootBinary],
6205
- ]);
6201
+ const zip = new JSZip();
6202
+ zip.file('manifest.json', manifestBinary);
6203
+ zip.file('bundles/images/images.okpkg', imagesBinary);
6204
+ zip.file('loaders/bootloader/boot_resource.okpkg', bootBinary);
6205
+ const archiveBinary = await zip.generateAsync({ type: 'arraybuffer' });
6206
+ const preparedEntries = [
6207
+ {
6208
+ entryName: 'manifest.json',
6209
+ artifact: {
6210
+ artifactRef: 'manifest',
6211
+ size: manifestBinary.byteLength,
6212
+ sha256: bytesToHex(sha256(new Uint8Array(manifestBinary))),
6213
+ },
6214
+ },
6215
+ {
6216
+ entryName: 'bundles/images/images.okpkg',
6217
+ artifact: {
6218
+ artifactRef: 'images',
6219
+ size: imagesBinary.byteLength,
6220
+ sha256: imagesSha256,
6221
+ },
6222
+ },
6223
+ {
6224
+ entryName: 'loaders/bootloader/boot_resource.okpkg',
6225
+ artifact: {
6226
+ artifactRef: 'boot',
6227
+ size: bootBinary.byteLength,
6228
+ sha256: bootSha256,
6229
+ },
6230
+ },
6231
+ ];
6232
+ const artifacts = new Map([['archive', archiveBinary]]);
6206
6233
  (method as any).params = {
6207
6234
  targetsToUpdate: ['resource'],
6208
6235
  preparedPlan: {
@@ -6212,32 +6239,12 @@ describe('Protocol V2 firmware update targets', () => {
6212
6239
  role: 'resourceBundle',
6213
6240
  target: 'resource',
6214
6241
  container: 'zip',
6215
- materializedEntries: [
6216
- {
6217
- entryName: 'manifest.json',
6218
- artifact: {
6219
- artifactRef: 'manifest',
6220
- size: manifestBinary.byteLength,
6221
- sha256: '0'.repeat(64),
6222
- },
6223
- },
6224
- {
6225
- entryName: 'bundles/images/images.okpkg',
6226
- artifact: {
6227
- artifactRef: 'images',
6228
- size: imagesBinary.byteLength,
6229
- sha256: imagesSha256,
6230
- },
6231
- },
6232
- {
6233
- entryName: 'loaders/bootloader/boot_resource.okpkg',
6234
- artifact: {
6235
- artifactRef: 'boot',
6236
- size: bootBinary.byteLength,
6237
- sha256: bootSha256,
6238
- },
6239
- },
6240
- ],
6242
+ artifact: {
6243
+ artifactRef: 'archive',
6244
+ size: archiveBinary.byteLength,
6245
+ sha256: bytesToHex(sha256(new Uint8Array(archiveBinary))),
6246
+ },
6247
+ materializedEntries: preparedEntries,
6241
6248
  },
6242
6249
  ],
6243
6250
  },
@@ -6264,6 +6271,11 @@ describe('Protocol V2 firmware update targets', () => {
6264
6271
  }),
6265
6272
  ]);
6266
6273
  await Promise.all(sources.map(source => source.source.close()));
6274
+
6275
+ preparedEntries[1].artifact.sha256 = 'f'.repeat(64);
6276
+ await expect((method as any).prepareProtocolV2ResourceArchiveSources()).rejects.toThrow(
6277
+ 'entries do not match the approved archive'
6278
+ );
6267
6279
  });
6268
6280
 
6269
6281
  test('binds a prepared resource archive to the selected host generation', () => {
@@ -7754,6 +7766,88 @@ describe('Protocol V2 firmware reconnect identity', () => {
7754
7766
  expect((method as any).protocolV2ExpectedPath).toBe('000000000000');
7755
7767
  });
7756
7768
 
7769
+ test('executes a serial-less Pro2 prepared plan when the live model matches', async () => {
7770
+ const planWithoutDigest = {
7771
+ schemaVersion: 2 as const,
7772
+ executor: 'v4' as const,
7773
+ deviceIdentity: 'unavailable',
7774
+ deviceModel: 'pro2',
7775
+ firmwareType: EFirmwareType.Universal,
7776
+ platform: 'web' as const,
7777
+ targetsToUpdate: ['boot' as const],
7778
+ artifacts: [
7779
+ {
7780
+ artifactId: 'component:boot',
7781
+ role: 'component' as const,
7782
+ target: 'boot' as const,
7783
+ url: 'https://example.com/bootloader.bin',
7784
+ container: 'raw' as const,
7785
+ logicalName: 'bootloader',
7786
+ },
7787
+ ],
7788
+ };
7789
+ const preparedPlan = prepareFirmwareUpdatePlan({
7790
+ plan: {
7791
+ ...planWithoutDigest,
7792
+ planDigest: digestFirmwareUpdateContract(planWithoutDigest),
7793
+ },
7794
+ leaseRef: 'serial-less-v4-executor-test',
7795
+ artifacts: [
7796
+ {
7797
+ artifactId: 'component:boot',
7798
+ artifact: {
7799
+ artifactRef: 'serial-less-bootloader',
7800
+ size: 1,
7801
+ sha256: 'a'.repeat(64),
7802
+ },
7803
+ },
7804
+ ],
7805
+ });
7806
+ const hostBindingGeneration = registerFirmwareUpdateHostBinding({
7807
+ preparedPlanDigest: preparedPlan.preparedPlanDigest,
7808
+ artifactReader: {
7809
+ open: jest.fn(),
7810
+ read: jest.fn(),
7811
+ close: jest.fn(),
7812
+ },
7813
+ });
7814
+ try {
7815
+ const method = new FirmwareUpdateV4({
7816
+ id: 1,
7817
+ payload: {
7818
+ method: 'firmwareUpdateV4',
7819
+ platform: 'web',
7820
+ preparedPlan,
7821
+ hostBindingGeneration,
7822
+ },
7823
+ });
7824
+ method.init();
7825
+ const typedCall = jest.fn().mockResolvedValue({
7826
+ type: 'DeviceInfo',
7827
+ message: { protocol_version: 1, hw: {} },
7828
+ });
7829
+ (method as any).device = stubDevice({
7830
+ originalDescriptor: { protocolType: 'V2', path: 'serial-less-pro2' },
7831
+ features: {
7832
+ deviceType: 'pro2',
7833
+ firmwareVersion: '1.0.0',
7834
+ capabilities: [],
7835
+ },
7836
+ getCommands: () => ({ typedCall }),
7837
+ });
7838
+ (method as any).runProtocolV2PreparedArtifacts = jest
7839
+ .fn()
7840
+ .mockResolvedValue('serial-less-result');
7841
+
7842
+ await expect(method.run()).resolves.toBe('serial-less-result');
7843
+ expect((method as any).runProtocolV2PreparedArtifacts).toHaveBeenCalled();
7844
+ expect((method as any).protocolV2ExpectedSerialNumber).toBeUndefined();
7845
+ expect((method as any).protocolV2ExpectedPath).toBe('serial-less-pro2');
7846
+ } finally {
7847
+ unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
7848
+ }
7849
+ });
7850
+
7757
7851
  test('uses the BLE read limit when reading an existing firmware bundle header', async () => {
7758
7852
  const method = new FirmwareUpdateV4({
7759
7853
  id: 1,
@@ -6,6 +6,7 @@ import type { FirmwareUpdatePreparedPlan } from '../types/api/firmwareUpdatePrep
6
6
  type Params = {
7
7
  binary?: ArrayBuffer;
8
8
  artifact?: FirmwareArtifactReference;
9
+ hostBindingGeneration?: number;
9
10
  resourceEntries?: Array<{
10
11
  entryName: string;
11
12
  artifact: FirmwareArtifactReference;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA0B1C,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,KAAK,MAAM,GAAG;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAkFF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI;IAuFJ,cAAc,YAAa,MAAM,UAS/B;YAEY,qCAAqC;IAkBnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YA8FvC,4BAA4B;IAyB1C,qBAAqB;IAUrB,uBAAuB,CAAC,UAAU,EAAE,MAAM;IAc1C,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,YAAY,EAAE,aAAa;IAwBtF,GAAG;CAgQV"}
1
+ {"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA0B1C,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,KAAK,MAAM,GAAG;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAkFF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI;IA6FJ,cAAc,YAAa,MAAM,UAS/B;YAEY,qCAAqC;IAkBnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YA8FvC,4BAA4B;IAyB1C,qBAAqB;IAUrB,uBAAuB,CAAC,UAAU,EAAE,MAAM;IAc1C,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,YAAY,EAAE,aAAa;IAwBtF,GAAG;CAgQV"}
@@ -36,6 +36,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
36
36
  private getProtocolV2RequestedTargets;
37
37
  private getProtocolV2DeviceFeatures;
38
38
  private getProtocolV2SerialNumber;
39
+ private getProtocolV2PreparedPlanDeviceModel;
39
40
  private getProtocolV2ConnectionRoute;
40
41
  private assertProtocolV2DeviceInfoIdentity;
41
42
  private getProtocolV2DeviceInfoTimeout;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAyBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAkC/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA2ErC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAgB/B;AAgWD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAsKJ,OAAO,CAAC,8BAA8B;IAwBhC,GAAG;;;;;YAKK,aAAa;YAsHb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqG/B,gCAAgC;YA8HhC,qCAAqC;YA0IrC,gCAAgC;YAgBhC,uCAAuC;YAwHvC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,4BAA4B;IAUpC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mCAAmC;IAe3C,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAuDjC,+BAA+B;IA6E7C,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA+C9B,kCAAkC;IA+BhD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YAiCvB,8BAA8B;YA8D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
1
+ {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAyBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAkC/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA2ErC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAgB/B;AAgWD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IA0KJ,OAAO,CAAC,8BAA8B;IAwBhC,GAAG;;;;;YAKK,aAAa;YAsHb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqG/B,gCAAgC;YA+HhC,qCAAqC;YA0IrC,gCAAgC;YAgBhC,uCAAuC;YAmJvC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,oCAAoC;IAY5C,OAAO,CAAC,4BAA4B;IAUpC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAmBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mCAAmC;IAe3C,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAuDjC,+BAA+B;IA6E7C,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA+C9B,kCAAkC;IA+BhD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YAiCvB,8BAA8B;YA8D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceUpdateBootloader.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceUpdateBootloader.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAiBhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,wBAAwB,CAAC,GAAG,CAAC;IAC/E,IAAI;IAOE,iCAAiC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAoBtE,2CAA2C,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB;IAcvF,qBAAqB,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,cAAc,GACvB,EAAE;QACD,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,YAAY,EAAE,aAAa,CAAC;QAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,MAAM,CAAC,EAAE,kBAAkB,CAAC;KAC7B;IA0EK,GAAG;CAgFV"}
1
+ {"version":3,"file":"DeviceUpdateBootloader.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceUpdateBootloader.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAiBhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,wBAAwB,CAAC,GAAG,CAAC;IAC/E,IAAI;IAOE,iCAAiC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAoBtE,2CAA2C,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB;IAcvF,qBAAqB,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,cAAc,GACvB,EAAE;QACD,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,YAAY,EAAE,aAAa,CAAC;QAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,MAAM,CAAC,EAAE,kBAAkB,CAAC;KAC7B;IA0EK,GAAG;CA8FV"}
package/dist/index.d.ts CHANGED
@@ -1413,6 +1413,7 @@ type FirmwareUpdateV4Target = 'boot'
1413
1413
  | 'boot_resources' | 'app_v1' | 'app_v2' | 'coprocessor' | 'resource' | 'se01' | 'se02' | 'se03' | 'se04';
1414
1414
  interface FirmwareUpdateV4Params {
1415
1415
  preparedPlan?: FirmwareUpdatePreparedPlan;
1416
+ /** Required whenever preparedPlan is present; Core resolves the reader from this digest-bound host. */
1416
1417
  hostBindingGeneration?: number;
1417
1418
  platform: IPlatform;
1418
1419
  expectedDeviceId?: string;
package/dist/index.js CHANGED
@@ -49777,18 +49777,26 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
49777
49777
  });
49778
49778
  }
49779
49779
  run() {
49780
- var _a, _b, _c;
49780
+ var _a, _b;
49781
49781
  return __awaiter(this, void 0, void 0, function* () {
49782
49782
  const { device } = this;
49783
49783
  const { features } = device;
49784
49784
  const payload = this.payload;
49785
- const preparedPlan = payload.artifact
49785
+ const hasPreparedPlan = payload.preparedPlan !== undefined;
49786
+ const hasPreparedArtifact = payload.artifact !== undefined;
49787
+ if (hasPreparedPlan !== hasPreparedArtifact) {
49788
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared bootloader plans require exactly one prepared artifact');
49789
+ }
49790
+ if (payload.binary !== undefined && hasPreparedArtifact) {
49791
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Bootloader binary and prepared artifact are mutually exclusive');
49792
+ }
49793
+ const preparedPlan = hasPreparedArtifact
49786
49794
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
49787
49795
  : undefined;
49788
- const hostBinding = preparedPlan
49789
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest)
49790
- : undefined;
49791
- const executionParams = Object.assign(Object.assign({}, payload), { artifactReader: (_a = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _a !== void 0 ? _a : payload.artifactReader });
49796
+ const artifactReader = preparedPlan
49797
+ ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
49798
+ : payload.artifactReader;
49799
+ const executionParams = Object.assign(Object.assign({}, payload), { artifactReader });
49792
49800
  if (payload.artifact) {
49793
49801
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
49794
49802
  preparedPlan,
@@ -49817,7 +49825,7 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
49817
49825
  try {
49818
49826
  const deviceType = device.getCurrentDeviceType();
49819
49827
  const deviceFirmwareType = device.getCurrentFirmwareType();
49820
- const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
49828
+ const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
49821
49829
  if (DeviceModelToTypes.model_touch.includes(deviceType)) {
49822
49830
  return yield this.updateTouchBootloader({
49823
49831
  device,
@@ -49835,7 +49843,7 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
49835
49843
  const { binary } = payload;
49836
49844
  const deviceType = device.getCurrentDeviceType();
49837
49845
  const deviceFirmwareType = device.getCurrentFirmwareType();
49838
- const firmwareType = (_c = payload.firmwareType) !== null && _c !== void 0 ? _c : deviceFirmwareType;
49846
+ const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
49839
49847
  if (DeviceModelToTypes.model_touch.includes(deviceType)) {
49840
49848
  return this.updateTouchBootloader({
49841
49849
  device,
@@ -50189,6 +50197,9 @@ class FirmwareUpdateV2 extends BaseMethod {
50189
50197
  payload.artifact !== undefined) {
50190
50198
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware update binary and artifact are mutually exclusive');
50191
50199
  }
50200
+ if (payload.preparedPlan !== undefined && payload.artifact === undefined) {
50201
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans require a prepared artifact');
50202
+ }
50192
50203
  if (!payload.updateType) {
50193
50204
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'updateType is required');
50194
50205
  }
@@ -50564,7 +50575,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
50564
50575
  this.artifactSources = [];
50565
50576
  }
50566
50577
  init() {
50567
- var _a, _b, _c, _d, _e, _f;
50578
+ var _a, _b, _c, _d, _e;
50568
50579
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
50569
50580
  this.requireDeviceMode = [];
50570
50581
  this.useDevicePassphraseState = false;
@@ -50585,10 +50596,10 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
50585
50596
  const preparedPlan = payload.artifacts || payload.preparedPlan
50586
50597
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
50587
50598
  : undefined;
50588
- const hostBinding = preparedPlan
50589
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest)
50590
- : undefined;
50591
- if (hostBinding) {
50599
+ const artifactReader = preparedPlan
50600
+ ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
50601
+ : payload.artifactReader;
50602
+ if (preparedPlan) {
50592
50603
  assertFirmwareUpdatePreparedPlanBinding({
50593
50604
  preparedPlan,
50594
50605
  executor: 'v3',
@@ -50639,7 +50650,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
50639
50650
  resourceBinary: payload.resourceBinary,
50640
50651
  firmwareType: payload.firmwareType,
50641
50652
  platform: payload.platform,
50642
- artifactReader: (_f = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _f !== void 0 ? _f : payload.artifactReader,
50653
+ artifactReader,
50643
50654
  artifacts: payload.artifacts,
50644
50655
  };
50645
50656
  }
@@ -51637,7 +51648,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51637
51648
  return ['V2'];
51638
51649
  }
51639
51650
  init() {
51640
- var _a, _b, _c;
51651
+ var _a, _b;
51641
51652
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
51642
51653
  this.requireDeviceMode = [];
51643
51654
  this.unlockPolicy = 'unlock-before-run';
@@ -51696,9 +51707,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51696
51707
  if (preparedPlan && hasLocalArtifacts) {
51697
51708
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy or local firmware inputs');
51698
51709
  }
51699
- const hostBinding = payload.hostBindingGeneration !== undefined
51700
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.preparedPlanDigest)
51701
- : undefined;
51710
+ let { artifactReader } = payload;
51711
+ if (preparedPlan) {
51712
+ artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader;
51713
+ }
51714
+ else if (payload.hostBindingGeneration !== undefined) {
51715
+ artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration).artifactReader;
51716
+ }
51702
51717
  if (preparedPlan) {
51703
51718
  assertFirmwareUpdatePreparedPlanBinding({
51704
51719
  preparedPlan,
@@ -51764,7 +51779,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51764
51779
  : payload.expectedTargetVersions,
51765
51780
  platform: payload.platform,
51766
51781
  expectedDeviceId: payload.expectedDeviceId,
51767
- artifactReader: (_c = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _c !== void 0 ? _c : payload.artifactReader,
51782
+ artifactReader,
51768
51783
  componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
51769
51784
  };
51770
51785
  }
@@ -52052,6 +52067,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52052
52067
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
52053
52068
  preparedPlan,
52054
52069
  deviceIdentity: this.protocolV2ExpectedSerialNumber,
52070
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
52055
52071
  });
52056
52072
  const hostBinding = resolveFirmwareUpdateHostBinding(memoryHost.hostBindingGeneration, preparedPlan.preparedPlanDigest);
52057
52073
  this.params.preparedPlan = preparedPlan;
@@ -52176,17 +52192,43 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52176
52192
  if (archiveArtifacts.length !== 1) {
52177
52193
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52178
52194
  }
52179
- const entries = (_c = archiveArtifacts[0].materializedEntries) !== null && _c !== void 0 ? _c : [];
52180
- const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
52181
- if (!manifestEntry ||
52182
- manifestEntry.artifact.size <= 0 ||
52183
- manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
52195
+ const archiveArtifact = archiveArtifacts[0];
52196
+ const archiveSource = yield this.openProtocolV2PreparedSource(archiveArtifact.artifact);
52197
+ if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
52198
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52199
+ }
52200
+ let archiveBinary;
52201
+ try {
52202
+ archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
52203
+ }
52204
+ finally {
52205
+ yield archiveSource.close();
52206
+ }
52207
+ const archiveDigest = bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
52208
+ if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
52209
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive does not match its approved receipt', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52210
+ }
52211
+ const verifiedArchive = yield this.prepareProtocolV2LocalResourceArchive(archiveBinary);
52212
+ const entries = (_c = archiveArtifact.materializedEntries) !== null && _c !== void 0 ? _c : [];
52213
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
52214
+ if (entries.length !== verifiedArchive.materializedEntries.length ||
52215
+ verifiedArchive.materializedEntries.some(entry => {
52216
+ const preparedEntry = entriesByName.get(entry.entryName);
52217
+ const digest = bytesToHex(sha256.sha256(new Uint8Array(entry.binary)));
52218
+ return (!preparedEntry ||
52219
+ preparedEntry.artifact.size !== entry.binary.byteLength ||
52220
+ preparedEntry.artifact.sha256.toLowerCase() !== digest);
52221
+ })) {
52222
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource entries do not match the approved archive', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52223
+ }
52224
+ const verifiedEntriesByName = new Map(verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary]));
52225
+ const manifestBinary = verifiedEntriesByName.get('manifest.json');
52226
+ if (!manifestBinary) {
52184
52227
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52185
52228
  }
52186
- const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
52187
52229
  let manifestValue;
52188
52230
  try {
52189
- manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
52231
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
52190
52232
  }
52191
52233
  catch (error) {
52192
52234
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
@@ -52199,28 +52241,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52199
52241
  if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
52200
52242
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52201
52243
  }
52202
- const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
52203
- const expectedEntryNames = new Set([
52204
- 'manifest.json',
52205
- ...selectedFiles.map(file => file.archive_path),
52206
- ]);
52207
- if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
52208
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52209
- }
52210
52244
  let totalSize = 0;
52211
52245
  const sources = [];
52212
52246
  for (const [index, file] of selectedFiles.entries()) {
52213
- const entry = entriesByName.get(file.archive_path);
52214
- if (!entry ||
52215
- entry.artifact.size !== file.size ||
52216
- entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()) {
52247
+ const binary = verifiedEntriesByName.get(file.archive_path);
52248
+ if (!binary || binary.byteLength !== file.size) {
52217
52249
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52218
52250
  }
52219
- totalSize += entry.artifact.size;
52251
+ totalSize += binary.byteLength;
52220
52252
  if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
52221
52253
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52222
52254
  }
52223
- const source = yield this.openProtocolV2PreparedSource(entry.artifact);
52255
+ const source = yield this.openProtocolV2MemorySource(binary);
52224
52256
  const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
52225
52257
  ? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
52226
52258
  : null;
@@ -52369,6 +52401,16 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52369
52401
  const serialNumber = (_b = (_a = deviceInfo.hw) === null || _a === void 0 ? void 0 : _a.serial_no) === null || _b === void 0 ? void 0 : _b.trim();
52370
52402
  return serialNumber || undefined;
52371
52403
  }
52404
+ getProtocolV2PreparedPlanDeviceModel(features) {
52405
+ const currentDeviceType = this.device.getCurrentDeviceType();
52406
+ const featureDeviceType = features ? getDeviceType(features) : undefined;
52407
+ const deviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
52408
+ ? currentDeviceType
52409
+ : featureDeviceType;
52410
+ return deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo
52411
+ ? String(deviceType)
52412
+ : undefined;
52413
+ }
52372
52414
  getProtocolV2ConnectionRoute() {
52373
52415
  var _a, _b, _c, _d, _e;
52374
52416
  const descriptor = this.device.originalDescriptor;
@@ -52404,6 +52446,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52404
52446
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
52405
52447
  preparedPlan: this.params.preparedPlan,
52406
52448
  deviceIdentity: serialNumber,
52449
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
52407
52450
  });
52408
52451
  }
52409
52452
  else if ((_b = this.params) === null || _b === void 0 ? void 0 : _b.expectedDeviceId) {
@@ -1 +1 @@
1
- {"version":3,"file":"firmwareUpdate.d.ts","sourceRoot":"","sources":["../../../src/types/api/firmwareUpdate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"firmwareUpdate.d.ts","sourceRoot":"","sources":["../../../src/types/api/firmwareUpdate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.93",
3
+ "version": "1.2.0-alpha.95",
4
4
  "description": "Core processes and APIs for communicating with OneKey hardware devices.",
5
5
  "author": "OneKey",
6
6
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
25
25
  "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-shared": "1.2.0-alpha.93",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.93",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.95",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.95",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "bytebuffer": "^5.0.1",
@@ -44,5 +44,5 @@
44
44
  "@types/w3c-web-usb": "^1.0.10",
45
45
  "@types/web-bluetooth": "^0.0.21"
46
46
  },
47
- "gitHead": "0cae321e989b47b8c05455b2d59755e5322f2bb1"
47
+ "gitHead": "efd79360b765d83a31d12f2403da4e79ed2ccffc"
48
48
  }
@@ -47,6 +47,7 @@ import type { FirmwareUpdatePreparedPlan } from '../types/api/firmwareUpdatePrep
47
47
  type Params = {
48
48
  binary?: ArrayBuffer;
49
49
  artifact?: FirmwareArtifactReference;
50
+ hostBindingGeneration?: number;
50
51
  resourceEntries?: Array<{
51
52
  entryName: string;
52
53
  artifact: FirmwareArtifactReference;
@@ -171,6 +172,12 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
171
172
  'Firmware update binary and artifact are mutually exclusive'
172
173
  );
173
174
  }
175
+ if (payload.preparedPlan !== undefined && payload.artifact === undefined) {
176
+ throw ERRORS.TypedError(
177
+ HardwareErrorCode.CallMethodInvalidParameter,
178
+ 'Prepared firmware plans require a prepared artifact'
179
+ );
180
+ }
174
181
 
175
182
  if (!payload.updateType) {
176
183
  throw ERRORS.TypedError(
@@ -82,13 +82,13 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
82
82
  payload.artifacts || payload.preparedPlan
83
83
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
84
84
  : undefined;
85
- const hostBinding = preparedPlan
85
+ const artifactReader = preparedPlan
86
86
  ? resolveFirmwareUpdateHostBinding(
87
87
  payload.hostBindingGeneration,
88
88
  preparedPlan.preparedPlanDigest
89
- )
90
- : undefined;
91
- if (hostBinding) {
89
+ ).artifactReader
90
+ : payload.artifactReader;
91
+ if (preparedPlan) {
92
92
  assertFirmwareUpdatePreparedPlanBinding({
93
93
  preparedPlan,
94
94
  executor: 'v3',
@@ -142,7 +142,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
142
142
  resourceBinary: payload.resourceBinary,
143
143
  firmwareType: payload.firmwareType,
144
144
  platform: payload.platform,
145
- artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
145
+ artifactReader,
146
146
  artifacts: payload.artifacts,
147
147
  };
148
148
  }
@@ -640,13 +640,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
640
640
  'Prepared firmware plans cannot be combined with legacy or local firmware inputs'
641
641
  );
642
642
  }
643
- const hostBinding =
644
- payload.hostBindingGeneration !== undefined
645
- ? resolveFirmwareUpdateHostBinding(
646
- payload.hostBindingGeneration,
647
- preparedPlan?.preparedPlanDigest
648
- )
649
- : undefined;
643
+ let { artifactReader } = payload;
644
+ if (preparedPlan) {
645
+ artifactReader = resolveFirmwareUpdateHostBinding(
646
+ payload.hostBindingGeneration,
647
+ preparedPlan.preparedPlanDigest
648
+ ).artifactReader;
649
+ } else if (payload.hostBindingGeneration !== undefined) {
650
+ artifactReader = resolveFirmwareUpdateHostBinding(
651
+ payload.hostBindingGeneration
652
+ ).artifactReader;
653
+ }
650
654
  if (preparedPlan) {
651
655
  assertFirmwareUpdatePreparedPlanBinding({
652
656
  preparedPlan,
@@ -731,7 +735,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
731
735
  : payload.expectedTargetVersions,
732
736
  platform: payload.platform,
733
737
  expectedDeviceId: payload.expectedDeviceId,
734
- artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
738
+ artifactReader,
735
739
  componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
736
740
  };
737
741
  }
@@ -1129,6 +1133,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1129
1133
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
1130
1134
  preparedPlan,
1131
1135
  deviceIdentity: this.protocolV2ExpectedSerialNumber,
1136
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
1132
1137
  });
1133
1138
  const hostBinding = resolveFirmwareUpdateHostBinding(
1134
1139
  memoryHost.hostBindingGeneration,
@@ -1320,13 +1325,59 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1320
1325
  );
1321
1326
  }
1322
1327
 
1323
- const entries = archiveArtifacts[0].materializedEntries ?? [];
1324
- const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
1328
+ const archiveArtifact = archiveArtifacts[0];
1329
+ const archiveSource = await this.openProtocolV2PreparedSource(archiveArtifact.artifact);
1330
+ if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
1331
+ throw ERRORS.TypedError(
1332
+ HardwareErrorCode.RuntimeError,
1333
+ 'Protocol V2 prepared resource archive exceeds the total size limit',
1334
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1335
+ );
1336
+ }
1337
+
1338
+ let archiveBinary: ArrayBuffer;
1339
+ try {
1340
+ archiveBinary = await readFirmwareByteSourceFully(archiveSource);
1341
+ } finally {
1342
+ await archiveSource.close();
1343
+ }
1344
+ const archiveDigest = bytesToHex(sha256(new Uint8Array(archiveBinary)));
1345
+ if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
1346
+ throw ERRORS.TypedError(
1347
+ HardwareErrorCode.RuntimeError,
1348
+ 'Protocol V2 prepared resource archive does not match its approved receipt',
1349
+ { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1350
+ );
1351
+ }
1352
+
1353
+ // materializedEntries 由宿主生成,只有与获批 ZIP 的规范字节完全一致后才能使用。
1354
+ const verifiedArchive = await this.prepareProtocolV2LocalResourceArchive(archiveBinary);
1355
+ const entries = archiveArtifact.materializedEntries ?? [];
1356
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry] as const));
1325
1357
  if (
1326
- !manifestEntry ||
1327
- manifestEntry.artifact.size <= 0 ||
1328
- manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
1358
+ entries.length !== verifiedArchive.materializedEntries.length ||
1359
+ verifiedArchive.materializedEntries.some(entry => {
1360
+ const preparedEntry = entriesByName.get(entry.entryName);
1361
+ const digest = bytesToHex(sha256(new Uint8Array(entry.binary)));
1362
+ return (
1363
+ !preparedEntry ||
1364
+ preparedEntry.artifact.size !== entry.binary.byteLength ||
1365
+ preparedEntry.artifact.sha256.toLowerCase() !== digest
1366
+ );
1367
+ })
1329
1368
  ) {
1369
+ throw ERRORS.TypedError(
1370
+ HardwareErrorCode.RuntimeError,
1371
+ 'Protocol V2 prepared resource entries do not match the approved archive',
1372
+ { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1373
+ );
1374
+ }
1375
+
1376
+ const verifiedEntriesByName = new Map(
1377
+ verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary] as const)
1378
+ );
1379
+ const manifestBinary = verifiedEntriesByName.get('manifest.json');
1380
+ if (!manifestBinary) {
1330
1381
  throw ERRORS.TypedError(
1331
1382
  HardwareErrorCode.RuntimeError,
1332
1383
  'Protocol V2 prepared resource archive has no valid manifest.json',
@@ -1334,12 +1385,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1334
1385
  );
1335
1386
  }
1336
1387
 
1337
- const manifestSource = await this.openProtocolV2PreparedSource(manifestEntry.artifact);
1338
1388
  let manifestValue: unknown;
1339
1389
  try {
1340
- manifestValue = JSON.parse(
1341
- new TextDecoder().decode(await readFirmwareByteSourceFully(manifestSource))
1342
- );
1390
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
1343
1391
  } catch (error) {
1344
1392
  throw ERRORS.TypedError(
1345
1393
  HardwareErrorCode.RuntimeError,
@@ -1360,35 +1408,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1360
1408
  );
1361
1409
  }
1362
1410
 
1363
- const entriesByName = new Map(entries.map(entry => [entry.entryName, entry] as const));
1364
- const expectedEntryNames = new Set([
1365
- 'manifest.json',
1366
- ...selectedFiles.map(file => file.archive_path),
1367
- ]);
1368
- if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
1369
- throw ERRORS.TypedError(
1370
- HardwareErrorCode.RuntimeError,
1371
- 'Protocol V2 prepared resource archive contains an unexpected entry',
1372
- { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1373
- );
1374
- }
1375
-
1376
1411
  let totalSize = 0;
1377
1412
  const sources: ProtocolV2ResourceBundleSource[] = [];
1378
1413
  for (const [index, file] of selectedFiles.entries()) {
1379
- const entry = entriesByName.get(file.archive_path);
1380
- if (
1381
- !entry ||
1382
- entry.artifact.size !== file.size ||
1383
- entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()
1384
- ) {
1414
+ const binary = verifiedEntriesByName.get(file.archive_path);
1415
+ if (!binary || binary.byteLength !== file.size) {
1385
1416
  throw ERRORS.TypedError(
1386
1417
  HardwareErrorCode.RuntimeError,
1387
1418
  `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`,
1388
1419
  { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1389
1420
  );
1390
1421
  }
1391
- totalSize += entry.artifact.size;
1422
+ totalSize += binary.byteLength;
1392
1423
  if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
1393
1424
  throw ERRORS.TypedError(
1394
1425
  HardwareErrorCode.RuntimeError,
@@ -1396,7 +1427,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1396
1427
  { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1397
1428
  );
1398
1429
  }
1399
- const source = await this.openProtocolV2PreparedSource(entry.artifact);
1430
+ // 使用从获批 ZIP 中提取的规范字节,避免宿主在校验后替换 entry reader 内容。
1431
+ const source = await this.openProtocolV2MemorySource(binary);
1400
1432
  const header =
1401
1433
  source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
1402
1434
  ? parseProtocolV2OkppHeader(
@@ -1573,6 +1605,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1573
1605
  return serialNumber || undefined;
1574
1606
  }
1575
1607
 
1608
+ private getProtocolV2PreparedPlanDeviceModel(features?: Features) {
1609
+ const currentDeviceType = this.device.getCurrentDeviceType();
1610
+ const featureDeviceType = features ? getDeviceType(features) : undefined;
1611
+ const deviceType =
1612
+ currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
1613
+ ? currentDeviceType
1614
+ : featureDeviceType;
1615
+ return deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo
1616
+ ? String(deviceType)
1617
+ : undefined;
1618
+ }
1619
+
1576
1620
  private getProtocolV2ConnectionRoute() {
1577
1621
  const descriptor = this.device.originalDescriptor;
1578
1622
  return (
@@ -1613,6 +1657,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1613
1657
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
1614
1658
  preparedPlan: this.params.preparedPlan,
1615
1659
  deviceIdentity: serialNumber,
1660
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
1616
1661
  });
1617
1662
  } else if (this.params?.expectedDeviceId) {
1618
1663
  assertProtocolV2ReconnectIdentity(this.params?.expectedDeviceId, serialNumber);
@@ -158,18 +158,32 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
158
158
  const { features } = device;
159
159
 
160
160
  const payload = this.payload as DeviceUpdateBootloaderParams;
161
- const preparedPlan = payload.artifact
161
+ const hasPreparedPlan = payload.preparedPlan !== undefined;
162
+ const hasPreparedArtifact = payload.artifact !== undefined;
163
+ if (hasPreparedPlan !== hasPreparedArtifact) {
164
+ throw ERRORS.TypedError(
165
+ HardwareErrorCode.CallMethodInvalidParameter,
166
+ 'Prepared bootloader plans require exactly one prepared artifact'
167
+ );
168
+ }
169
+ if (payload.binary !== undefined && hasPreparedArtifact) {
170
+ throw ERRORS.TypedError(
171
+ HardwareErrorCode.CallMethodInvalidParameter,
172
+ 'Bootloader binary and prepared artifact are mutually exclusive'
173
+ );
174
+ }
175
+ const preparedPlan = hasPreparedArtifact
162
176
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
163
177
  : undefined;
164
- const hostBinding = preparedPlan
178
+ const artifactReader = preparedPlan
165
179
  ? resolveFirmwareUpdateHostBinding(
166
180
  payload.hostBindingGeneration,
167
181
  preparedPlan.preparedPlanDigest
168
- )
169
- : undefined;
182
+ ).artifactReader
183
+ : payload.artifactReader;
170
184
  const executionParams = {
171
185
  ...payload,
172
- artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
186
+ artifactReader,
173
187
  };
174
188
  if (payload.artifact) {
175
189
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
@@ -133,6 +133,7 @@ export type FirmwareUpdateV4Target =
133
133
 
134
134
  export interface FirmwareUpdateV4Params {
135
135
  preparedPlan?: FirmwareUpdatePreparedPlan;
136
+ /** Required whenever preparedPlan is present; Core resolves the reader from this digest-bound host. */
136
137
  hostBindingGeneration?: number;
137
138
  platform: IPlatform;
138
139
  expectedDeviceId?: string;