@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 =
|
|
6163
|
-
const bootSha256 =
|
|
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
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
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
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
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;
|
|
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
|
|
52180
|
-
const
|
|
52181
|
-
if (
|
|
52182
|
-
|
|
52183
|
-
|
|
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(
|
|
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
|
|
52214
|
-
if (!
|
|
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 +=
|
|
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.
|
|
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.
|
|
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.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
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": "
|
|
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
|
|
1324
|
-
const
|
|
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
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
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
|
|
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 +=
|
|
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
|
-
|
|
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);
|