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

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.
@@ -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,
@@ -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;IAsKJ,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"}
package/dist/index.js CHANGED
@@ -52052,6 +52052,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52052
52052
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
52053
52053
  preparedPlan,
52054
52054
  deviceIdentity: this.protocolV2ExpectedSerialNumber,
52055
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
52055
52056
  });
52056
52057
  const hostBinding = resolveFirmwareUpdateHostBinding(memoryHost.hostBindingGeneration, preparedPlan.preparedPlanDigest);
52057
52058
  this.params.preparedPlan = preparedPlan;
@@ -52176,17 +52177,43 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52176
52177
  if (archiveArtifacts.length !== 1) {
52177
52178
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52178
52179
  }
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) {
52180
+ const archiveArtifact = archiveArtifacts[0];
52181
+ const archiveSource = yield this.openProtocolV2PreparedSource(archiveArtifact.artifact);
52182
+ if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
52183
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52184
+ }
52185
+ let archiveBinary;
52186
+ try {
52187
+ archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
52188
+ }
52189
+ finally {
52190
+ yield archiveSource.close();
52191
+ }
52192
+ const archiveDigest = bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
52193
+ if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
52194
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive does not match its approved receipt', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52195
+ }
52196
+ const verifiedArchive = yield this.prepareProtocolV2LocalResourceArchive(archiveBinary);
52197
+ const entries = (_c = archiveArtifact.materializedEntries) !== null && _c !== void 0 ? _c : [];
52198
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
52199
+ if (entries.length !== verifiedArchive.materializedEntries.length ||
52200
+ verifiedArchive.materializedEntries.some(entry => {
52201
+ const preparedEntry = entriesByName.get(entry.entryName);
52202
+ const digest = bytesToHex(sha256.sha256(new Uint8Array(entry.binary)));
52203
+ return (!preparedEntry ||
52204
+ preparedEntry.artifact.size !== entry.binary.byteLength ||
52205
+ preparedEntry.artifact.sha256.toLowerCase() !== digest);
52206
+ })) {
52207
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource entries do not match the approved archive', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52208
+ }
52209
+ const verifiedEntriesByName = new Map(verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary]));
52210
+ const manifestBinary = verifiedEntriesByName.get('manifest.json');
52211
+ if (!manifestBinary) {
52184
52212
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52185
52213
  }
52186
- const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
52187
52214
  let manifestValue;
52188
52215
  try {
52189
- manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
52216
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
52190
52217
  }
52191
52218
  catch (error) {
52192
52219
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
@@ -52199,28 +52226,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52199
52226
  if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
52200
52227
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52201
52228
  }
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
52229
  let totalSize = 0;
52211
52230
  const sources = [];
52212
52231
  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()) {
52232
+ const binary = verifiedEntriesByName.get(file.archive_path);
52233
+ if (!binary || binary.byteLength !== file.size) {
52217
52234
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52218
52235
  }
52219
- totalSize += entry.artifact.size;
52236
+ totalSize += binary.byteLength;
52220
52237
  if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
52221
52238
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52222
52239
  }
52223
- const source = yield this.openProtocolV2PreparedSource(entry.artifact);
52240
+ const source = yield this.openProtocolV2MemorySource(binary);
52224
52241
  const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
52225
52242
  ? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
52226
52243
  : null;
@@ -52369,6 +52386,16 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52369
52386
  const serialNumber = (_b = (_a = deviceInfo.hw) === null || _a === void 0 ? void 0 : _a.serial_no) === null || _b === void 0 ? void 0 : _b.trim();
52370
52387
  return serialNumber || undefined;
52371
52388
  }
52389
+ getProtocolV2PreparedPlanDeviceModel(features) {
52390
+ const currentDeviceType = this.device.getCurrentDeviceType();
52391
+ const featureDeviceType = features ? getDeviceType(features) : undefined;
52392
+ const deviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
52393
+ ? currentDeviceType
52394
+ : featureDeviceType;
52395
+ return deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo
52396
+ ? String(deviceType)
52397
+ : undefined;
52398
+ }
52372
52399
  getProtocolV2ConnectionRoute() {
52373
52400
  var _a, _b, _c, _d, _e;
52374
52401
  const descriptor = this.device.originalDescriptor;
@@ -52404,6 +52431,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52404
52431
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
52405
52432
  preparedPlan: this.params.preparedPlan,
52406
52433
  deviceIdentity: serialNumber,
52434
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
52407
52435
  });
52408
52436
  }
52409
52437
  else if ((_b = this.params) === null || _b === void 0 ? void 0 : _b.expectedDeviceId) {
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.94",
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.94",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.94",
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": "8bbaf25f01cd18ae64959efdcae60afb4435f259"
48
48
  }
@@ -1129,6 +1129,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1129
1129
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
1130
1130
  preparedPlan,
1131
1131
  deviceIdentity: this.protocolV2ExpectedSerialNumber,
1132
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
1132
1133
  });
1133
1134
  const hostBinding = resolveFirmwareUpdateHostBinding(
1134
1135
  memoryHost.hostBindingGeneration,
@@ -1320,13 +1321,59 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1320
1321
  );
1321
1322
  }
1322
1323
 
1323
- const entries = archiveArtifacts[0].materializedEntries ?? [];
1324
- const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
1324
+ const archiveArtifact = archiveArtifacts[0];
1325
+ const archiveSource = await this.openProtocolV2PreparedSource(archiveArtifact.artifact);
1326
+ if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
1327
+ throw ERRORS.TypedError(
1328
+ HardwareErrorCode.RuntimeError,
1329
+ 'Protocol V2 prepared resource archive exceeds the total size limit',
1330
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1331
+ );
1332
+ }
1333
+
1334
+ let archiveBinary: ArrayBuffer;
1335
+ try {
1336
+ archiveBinary = await readFirmwareByteSourceFully(archiveSource);
1337
+ } finally {
1338
+ await archiveSource.close();
1339
+ }
1340
+ const archiveDigest = bytesToHex(sha256(new Uint8Array(archiveBinary)));
1341
+ if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
1342
+ throw ERRORS.TypedError(
1343
+ HardwareErrorCode.RuntimeError,
1344
+ 'Protocol V2 prepared resource archive does not match its approved receipt',
1345
+ { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1346
+ );
1347
+ }
1348
+
1349
+ // materializedEntries 由宿主生成,只有与获批 ZIP 的规范字节完全一致后才能使用。
1350
+ const verifiedArchive = await this.prepareProtocolV2LocalResourceArchive(archiveBinary);
1351
+ const entries = archiveArtifact.materializedEntries ?? [];
1352
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry] as const));
1325
1353
  if (
1326
- !manifestEntry ||
1327
- manifestEntry.artifact.size <= 0 ||
1328
- manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
1354
+ entries.length !== verifiedArchive.materializedEntries.length ||
1355
+ verifiedArchive.materializedEntries.some(entry => {
1356
+ const preparedEntry = entriesByName.get(entry.entryName);
1357
+ const digest = bytesToHex(sha256(new Uint8Array(entry.binary)));
1358
+ return (
1359
+ !preparedEntry ||
1360
+ preparedEntry.artifact.size !== entry.binary.byteLength ||
1361
+ preparedEntry.artifact.sha256.toLowerCase() !== digest
1362
+ );
1363
+ })
1329
1364
  ) {
1365
+ throw ERRORS.TypedError(
1366
+ HardwareErrorCode.RuntimeError,
1367
+ 'Protocol V2 prepared resource entries do not match the approved archive',
1368
+ { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1369
+ );
1370
+ }
1371
+
1372
+ const verifiedEntriesByName = new Map(
1373
+ verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary] as const)
1374
+ );
1375
+ const manifestBinary = verifiedEntriesByName.get('manifest.json');
1376
+ if (!manifestBinary) {
1330
1377
  throw ERRORS.TypedError(
1331
1378
  HardwareErrorCode.RuntimeError,
1332
1379
  'Protocol V2 prepared resource archive has no valid manifest.json',
@@ -1334,12 +1381,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1334
1381
  );
1335
1382
  }
1336
1383
 
1337
- const manifestSource = await this.openProtocolV2PreparedSource(manifestEntry.artifact);
1338
1384
  let manifestValue: unknown;
1339
1385
  try {
1340
- manifestValue = JSON.parse(
1341
- new TextDecoder().decode(await readFirmwareByteSourceFully(manifestSource))
1342
- );
1386
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
1343
1387
  } catch (error) {
1344
1388
  throw ERRORS.TypedError(
1345
1389
  HardwareErrorCode.RuntimeError,
@@ -1360,35 +1404,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1360
1404
  );
1361
1405
  }
1362
1406
 
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
1407
  let totalSize = 0;
1377
1408
  const sources: ProtocolV2ResourceBundleSource[] = [];
1378
1409
  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
- ) {
1410
+ const binary = verifiedEntriesByName.get(file.archive_path);
1411
+ if (!binary || binary.byteLength !== file.size) {
1385
1412
  throw ERRORS.TypedError(
1386
1413
  HardwareErrorCode.RuntimeError,
1387
1414
  `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`,
1388
1415
  { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1389
1416
  );
1390
1417
  }
1391
- totalSize += entry.artifact.size;
1418
+ totalSize += binary.byteLength;
1392
1419
  if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
1393
1420
  throw ERRORS.TypedError(
1394
1421
  HardwareErrorCode.RuntimeError,
@@ -1396,7 +1423,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1396
1423
  { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1397
1424
  );
1398
1425
  }
1399
- const source = await this.openProtocolV2PreparedSource(entry.artifact);
1426
+ // 使用从获批 ZIP 中提取的规范字节,避免宿主在校验后替换 entry reader 内容。
1427
+ const source = await this.openProtocolV2MemorySource(binary);
1400
1428
  const header =
1401
1429
  source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
1402
1430
  ? parseProtocolV2OkppHeader(
@@ -1573,6 +1601,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1573
1601
  return serialNumber || undefined;
1574
1602
  }
1575
1603
 
1604
+ private getProtocolV2PreparedPlanDeviceModel(features?: Features) {
1605
+ const currentDeviceType = this.device.getCurrentDeviceType();
1606
+ const featureDeviceType = features ? getDeviceType(features) : undefined;
1607
+ const deviceType =
1608
+ currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
1609
+ ? currentDeviceType
1610
+ : featureDeviceType;
1611
+ return deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo
1612
+ ? String(deviceType)
1613
+ : undefined;
1614
+ }
1615
+
1576
1616
  private getProtocolV2ConnectionRoute() {
1577
1617
  const descriptor = this.device.originalDescriptor;
1578
1618
  return (
@@ -1613,6 +1653,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1613
1653
  assertFirmwareUpdatePreparedPlanDeviceIdentity({
1614
1654
  preparedPlan: this.params.preparedPlan,
1615
1655
  deviceIdentity: serialNumber,
1656
+ deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
1616
1657
  });
1617
1658
  } else if (this.params?.expectedDeviceId) {
1618
1659
  assertProtocolV2ReconnectIdentity(this.params?.expectedDeviceId, serialNumber);