@onekeyfe/hd-core 1.2.0-alpha.162 → 1.2.0-alpha.164
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.
- package/__tests__/device-state-events.test.ts +2 -2
- package/__tests__/device-state-mapper.test.ts +2 -11
- package/__tests__/device-utils.test.ts +0 -6
- package/__tests__/firmware-memory-host.test.ts +126 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +3 -13
- package/__tests__/protocol-v2-resources.test.ts +2 -35
- package/__tests__/protocol-v2.test.ts +42 -89
- package/__tests__/search-devices.test.ts +3 -4
- package/dist/api/FirmwareUpdateV4.d.ts +1 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +22 -0
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +15 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/index.d.ts +22 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +298 -102
- package/dist/protocols/protocol-v2/resources.d.ts +0 -1
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +179 -75
- package/src/api/SearchDevices.ts +2 -2
- package/src/api/firmware/FirmwareMemoryHost.ts +143 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +41 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +6 -10
- package/src/core/index.ts +97 -6
- package/src/device/Device.ts +1 -3
- package/src/device/DeviceStateMapper.ts +2 -2
- package/src/deviceProfile/buildDeviceFeatures.ts +2 -7
- package/src/index.ts +6 -0
- package/src/protocols/protocol-v2/resources.ts +12 -16
- package/src/types/api/firmwareUpdate.ts +1 -1
- package/src/utils/deviceFeaturesCompat.ts +4 -9
- package/src/utils/deviceInfoUtils.ts +1 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deviceInfoUtils.d.ts","sourceRoot":"","sources":["../../src/utils/deviceInfoUtils.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAKlE,eAAO,MAAM,aAAa,cAAe,mBAAmB,KAAG,WAClC,CAAC;AAM9B,eAAO,MAAM,sBAAsB,UAAW,MAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"deviceInfoUtils.d.ts","sourceRoot":"","sources":["../../src/utils/deviceInfoUtils.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAKlE,eAAO,MAAM,aAAa,cAAe,mBAAmB,KAAG,WAClC,CAAC;AAM9B,eAAO,MAAM,sBAAsB,UAAW,MAAM,KAAG,WAmBtD,CAAC;AAMF,eAAO,MAAM,gBAAgB,cAAe,mBAAmB,KAAG,MAAM,GAAG,IAC3C,CAAC;AAKjC,eAAO,MAAM,iBAAiB,cAAe,mBAAmB,KAAG,MAClC,CAAC;AAKlC,eAAO,MAAM,aAAa,cANmB,mBAAmB,KAAG,MAMrB,CAAC;AAK/C,eAAO,MAAM,cAAc,cAAe,mBAAmB,kBAkB5D,CAAC;AAMF,eAAO,MAAM,qBAAqB,aACtB,mBAAmB,GAAG,SAAS,iCACV,WAAW,GAAG,YAAY,KAAK,aAAa,GAAG,SAAS,KACtF,aAAa,GAAG,SAyBlB,CAAC;AAEF,eAAO,MAAM,eAAe,cAAe,mBAAmB,gDACzB,CAAC"}
|
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.164",
|
|
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.164",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.164",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"buffer": "^6.0.3",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"@types/w3c-web-usb": "^1.0.10",
|
|
47
47
|
"@types/web-bluetooth": "^0.0.21"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "8a6f829b0ea1544d2c5f7a1fd0cc0f08d6df7dcd"
|
|
50
50
|
}
|
|
@@ -32,13 +32,11 @@ import {
|
|
|
32
32
|
} from '../protocols/protocol-v2';
|
|
33
33
|
import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
|
|
34
34
|
import {
|
|
35
|
-
PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH,
|
|
36
35
|
PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
37
36
|
PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE,
|
|
38
|
-
type ProtocolV2ResourcePackageHeader,
|
|
39
|
-
isProtocolV2ResourceArchiveEntryName,
|
|
40
37
|
parseProtocolV2ResourcePackage,
|
|
41
38
|
parseProtocolV2ResourcePackageHeader,
|
|
39
|
+
type ProtocolV2ResourcePackageHeader,
|
|
42
40
|
} from '../protocols/protocol-v2/resources';
|
|
43
41
|
import {
|
|
44
42
|
getProtocolV2UnknownErrorText,
|
|
@@ -49,12 +47,20 @@ import {
|
|
|
49
47
|
readFirmwareByteSourceFully,
|
|
50
48
|
writeFirmwareByteSource,
|
|
51
49
|
} from './firmware/FirmwareArtifactSource';
|
|
52
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
registerFirmwareUpdateHostBinding,
|
|
52
|
+
resolveFirmwareUpdateHostBinding,
|
|
53
|
+
unregisterFirmwareUpdateHostBinding,
|
|
54
|
+
} from './firmware/FirmwareHostBinding';
|
|
53
55
|
import {
|
|
54
56
|
assertFirmwareUpdatePreparedPlanBinding,
|
|
55
57
|
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
58
|
+
prepareFirmwareUpdatePlan,
|
|
56
59
|
validateFirmwareUpdatePreparedPlan,
|
|
57
60
|
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
61
|
+
import { prepareFirmwareUpdateV4MemoryHost } from './firmware/FirmwareMemoryHost';
|
|
62
|
+
import { buildProtocolV2LocalFirmwareUpdatePlan } from './firmware/FirmwareUpdatePlan';
|
|
63
|
+
|
|
58
64
|
import type {
|
|
59
65
|
FirmwareArtifactReference,
|
|
60
66
|
FirmwareUpdateV4Params,
|
|
@@ -71,6 +77,11 @@ import type {
|
|
|
71
77
|
KnownDevice,
|
|
72
78
|
} from '../types';
|
|
73
79
|
import type { FirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
80
|
+
import type {
|
|
81
|
+
FirmwareMemoryArtifact,
|
|
82
|
+
FirmwareMemoryArtifactEntry,
|
|
83
|
+
FirmwareUpdateV4MemoryHost,
|
|
84
|
+
} from './firmware/FirmwareMemoryHost';
|
|
74
85
|
|
|
75
86
|
const Log = getLogger(LoggerNames.Method);
|
|
76
87
|
|
|
@@ -219,6 +230,7 @@ type ProtocolV2ResourceBundleSource = {
|
|
|
219
230
|
|
|
220
231
|
type ProtocolV2LocalResourceArchive = {
|
|
221
232
|
binary: ArrayBuffer;
|
|
233
|
+
materializedEntries: FirmwareMemoryArtifactEntry[];
|
|
222
234
|
resources: Array<{
|
|
223
235
|
entryName: string;
|
|
224
236
|
binary: ArrayBuffer;
|
|
@@ -780,7 +792,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
780
792
|
this.params.resourceArchiveBinary &&
|
|
781
793
|
this.params.targetsToUpdate?.includes('resource')
|
|
782
794
|
) {
|
|
783
|
-
|
|
795
|
+
const localMemoryHost = await this.prepareProtocolV2LocalMemoryHost({
|
|
796
|
+
features: deviceFeatures,
|
|
797
|
+
firmwareType,
|
|
798
|
+
});
|
|
799
|
+
try {
|
|
800
|
+
return await this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
801
|
+
} finally {
|
|
802
|
+
localMemoryHost.release();
|
|
803
|
+
}
|
|
784
804
|
}
|
|
785
805
|
|
|
786
806
|
const hasPreparedComponentArtifacts = Object.values(this.params.componentArtifacts ?? {}).some(
|
|
@@ -793,12 +813,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
793
813
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
794
814
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
795
815
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
796
|
-
let
|
|
816
|
+
let resourceMemoryHost: FirmwareUpdateV4MemoryHost | undefined;
|
|
797
817
|
try {
|
|
798
818
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
799
819
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
800
820
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
801
|
-
explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
821
|
+
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
802
822
|
bootloaderBinary,
|
|
803
823
|
fwBinaryMap,
|
|
804
824
|
});
|
|
@@ -854,9 +874,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
854
874
|
deviceFeatures,
|
|
855
875
|
firmwareType
|
|
856
876
|
);
|
|
877
|
+
resourceMemoryHost = await this.prepareProtocolV2LocalMemoryHost({
|
|
878
|
+
features: deviceFeatures,
|
|
879
|
+
firmwareType,
|
|
880
|
+
availableInstallItems: installItems ?? explicitInstallItems,
|
|
881
|
+
});
|
|
857
882
|
}
|
|
858
883
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
859
884
|
} catch (err) {
|
|
885
|
+
resourceMemoryHost?.release();
|
|
860
886
|
if (
|
|
861
887
|
typeof err === 'object' &&
|
|
862
888
|
err !== null &&
|
|
@@ -871,11 +897,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
871
897
|
throw normalizeFirmwarePreparationError(err);
|
|
872
898
|
}
|
|
873
899
|
|
|
874
|
-
if (
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
900
|
+
if (resourceMemoryHost) {
|
|
901
|
+
try {
|
|
902
|
+
return await this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType, false);
|
|
903
|
+
} finally {
|
|
904
|
+
resourceMemoryHost.release();
|
|
905
|
+
}
|
|
879
906
|
}
|
|
880
907
|
|
|
881
908
|
if (!bootloaderBinary && fwBinaryMap.length === 0 && !installItems?.length) {
|
|
@@ -1028,69 +1055,133 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1028
1055
|
return installSources;
|
|
1029
1056
|
}
|
|
1030
1057
|
|
|
1031
|
-
private async
|
|
1032
|
-
|
|
1033
|
-
|
|
1058
|
+
private async prepareProtocolV2LocalMemoryHost({
|
|
1059
|
+
features,
|
|
1060
|
+
firmwareType,
|
|
1061
|
+
availableInstallItems = this.buildProtocolV2InstallItems({
|
|
1062
|
+
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
1063
|
+
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
1064
|
+
}),
|
|
1034
1065
|
}: {
|
|
1066
|
+
features: Features;
|
|
1067
|
+
firmwareType: EFirmwareType;
|
|
1035
1068
|
availableInstallItems?: ProtocolV2InstallItem[];
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
}
|
|
1069
|
+
}): Promise<FirmwareUpdateV4MemoryHost> {
|
|
1070
|
+
const requestedComponentTargets = new Set(
|
|
1071
|
+
(this.params.targetsToUpdate ?? []).filter(
|
|
1072
|
+
(target): target is Exclude<FirmwareUpdateV4Target, 'resource' | 'boot_resources'> =>
|
|
1073
|
+
target !== 'resource' && target !== 'boot_resources'
|
|
1074
|
+
)
|
|
1075
|
+
);
|
|
1076
|
+
const localComponentTargets = new Set(
|
|
1077
|
+
availableInstallItems.flatMap(item => {
|
|
1078
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
1079
|
+
return target ? [target] : [];
|
|
1080
|
+
})
|
|
1081
|
+
);
|
|
1082
|
+
const missingTarget = Array.from(requestedComponentTargets).find(
|
|
1083
|
+
target => !localComponentTargets.has(target)
|
|
1084
|
+
);
|
|
1085
|
+
if (missingTarget) {
|
|
1086
|
+
throw ERRORS.TypedError(
|
|
1087
|
+
HardwareErrorCode.RuntimeError,
|
|
1088
|
+
`Protocol V2 local update has no binary for requested target ${missingTarget}`,
|
|
1089
|
+
{
|
|
1090
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
1091
|
+
artifactName: missingTarget,
|
|
1092
|
+
}
|
|
1056
1093
|
);
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1094
|
+
}
|
|
1095
|
+
const installItems = this.filterProtocolV2LocalInstallItems(availableInstallItems);
|
|
1096
|
+
|
|
1097
|
+
const planArtifacts: Parameters<typeof buildProtocolV2LocalFirmwareUpdatePlan>[0]['artifacts'] =
|
|
1098
|
+
[];
|
|
1099
|
+
const memoryArtifacts: FirmwareMemoryArtifact[] = [];
|
|
1100
|
+
for (const item of installItems) {
|
|
1101
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
1102
|
+
if (!target || item.binary.byteLength <= 0) {
|
|
1061
1103
|
throw ERRORS.TypedError(
|
|
1062
|
-
HardwareErrorCode.
|
|
1063
|
-
|
|
1104
|
+
HardwareErrorCode.RuntimeError,
|
|
1105
|
+
`Protocol V2 local firmware artifact is invalid: ${item.fileName}`,
|
|
1106
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1064
1107
|
);
|
|
1065
1108
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1109
|
+
const artifactId = `component:${target}`;
|
|
1110
|
+
planArtifacts.push({
|
|
1111
|
+
artifactId,
|
|
1112
|
+
target,
|
|
1113
|
+
container: 'raw',
|
|
1114
|
+
logicalName: item.fileName,
|
|
1115
|
+
expectedSize: item.binary.byteLength,
|
|
1116
|
+
expectedSha256: bytesToHex(sha256(new Uint8Array(item.binary))),
|
|
1117
|
+
...(this.params.expectedTargetVersions?.[target]
|
|
1118
|
+
? { targetVersion: this.params.expectedTargetVersions[target] }
|
|
1119
|
+
: {}),
|
|
1072
1120
|
});
|
|
1073
|
-
|
|
1074
|
-
await this.closeProtocolV2PreparedSources();
|
|
1121
|
+
memoryArtifacts.push({ artifactId, binary: item.binary });
|
|
1075
1122
|
}
|
|
1076
|
-
}
|
|
1077
1123
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1124
|
+
const resourceArchive = await this.prepareProtocolV2LocalResourceArchive(
|
|
1125
|
+
this.params.resourceArchiveBinary as ArrayBuffer
|
|
1126
|
+
);
|
|
1127
|
+
const resourceArtifactId = 'resource:archive';
|
|
1128
|
+
planArtifacts.push({
|
|
1129
|
+
artifactId: resourceArtifactId,
|
|
1130
|
+
target: 'resource',
|
|
1131
|
+
container: 'zip',
|
|
1132
|
+
logicalName: 'protocol-v2-local-resource-archive',
|
|
1133
|
+
expectedSize: resourceArchive.binary.byteLength,
|
|
1134
|
+
expectedSha256: bytesToHex(sha256(new Uint8Array(resourceArchive.binary))),
|
|
1135
|
+
});
|
|
1136
|
+
memoryArtifacts.push({
|
|
1137
|
+
artifactId: resourceArtifactId,
|
|
1138
|
+
binary: resourceArchive.binary,
|
|
1139
|
+
materializedEntries: resourceArchive.materializedEntries,
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
const plan = buildProtocolV2LocalFirmwareUpdatePlan({
|
|
1143
|
+
features,
|
|
1144
|
+
firmwareType,
|
|
1145
|
+
platform: this.params.platform,
|
|
1146
|
+
artifacts: planArtifacts,
|
|
1147
|
+
});
|
|
1148
|
+
let memoryHost: FirmwareUpdateV4MemoryHost | undefined;
|
|
1149
|
+
try {
|
|
1150
|
+
memoryHost = prepareFirmwareUpdateV4MemoryHost({
|
|
1151
|
+
sdk: {
|
|
1152
|
+
prepareFirmwareUpdatePlan,
|
|
1153
|
+
registerFirmwareUpdateHostBinding,
|
|
1154
|
+
unregisterFirmwareUpdateHostBinding,
|
|
1155
|
+
},
|
|
1156
|
+
plan,
|
|
1157
|
+
artifacts: memoryArtifacts,
|
|
1091
1158
|
});
|
|
1159
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(memoryHost.preparedPlan);
|
|
1160
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
1161
|
+
preparedPlan,
|
|
1162
|
+
executor: 'v4',
|
|
1163
|
+
platform: this.params.platform,
|
|
1164
|
+
scopeTargets: [],
|
|
1165
|
+
bindings: [],
|
|
1166
|
+
});
|
|
1167
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
1168
|
+
preparedPlan,
|
|
1169
|
+
deviceIdentity: this.protocolV2ExpectedSerialNumber,
|
|
1170
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
|
|
1171
|
+
});
|
|
1172
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(
|
|
1173
|
+
memoryHost.hostBindingGeneration,
|
|
1174
|
+
preparedPlan.preparedPlanDigest
|
|
1175
|
+
);
|
|
1176
|
+
this.params.preparedPlan = preparedPlan;
|
|
1177
|
+
this.params.targetsToUpdate = [...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[];
|
|
1178
|
+
this.params.artifactReader = hostBinding.artifactReader;
|
|
1179
|
+
this.params.componentArtifacts = undefined;
|
|
1180
|
+
return memoryHost;
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
memoryHost?.release();
|
|
1183
|
+
throw error;
|
|
1092
1184
|
}
|
|
1093
|
-
return sources;
|
|
1094
1185
|
}
|
|
1095
1186
|
|
|
1096
1187
|
private async prepareProtocolV2LocalResourceArchive(
|
|
@@ -1115,7 +1206,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1115
1206
|
}
|
|
1116
1207
|
const zipEntries = Object.values(zip.files);
|
|
1117
1208
|
const resourceEntries = zipEntries.filter(
|
|
1118
|
-
entry => !entry.dir &&
|
|
1209
|
+
entry => !entry.dir && entry.name.toLowerCase().endsWith('.okpkg')
|
|
1119
1210
|
);
|
|
1120
1211
|
if (
|
|
1121
1212
|
resourceEntries.length === 0 ||
|
|
@@ -1129,6 +1220,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1129
1220
|
}
|
|
1130
1221
|
|
|
1131
1222
|
let totalSize = 0;
|
|
1223
|
+
const materializedEntries: FirmwareMemoryArtifactEntry[] = [];
|
|
1132
1224
|
const resources: ProtocolV2LocalResourceArchive['resources'] = [];
|
|
1133
1225
|
const devicePaths = new Set<string>();
|
|
1134
1226
|
for (const entry of resourceEntries) {
|
|
@@ -1172,9 +1264,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1172
1264
|
);
|
|
1173
1265
|
}
|
|
1174
1266
|
devicePaths.add(canonicalDevicePath);
|
|
1267
|
+
materializedEntries.push({ entryName: entry.name, binary: fileBinary });
|
|
1175
1268
|
resources.push({ entryName: entry.name, binary: fileBinary, header });
|
|
1176
1269
|
}
|
|
1177
|
-
return { binary, resources };
|
|
1270
|
+
return { binary, materializedEntries, resources };
|
|
1178
1271
|
}
|
|
1179
1272
|
|
|
1180
1273
|
private async prepareProtocolV2ResourceSources(): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
@@ -1241,7 +1334,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1241
1334
|
|
|
1242
1335
|
// The verified ZIP bytes are authoritative. Non-okpkg entries are release
|
|
1243
1336
|
// metadata only; each RESOURCE package carries its own device path.
|
|
1244
|
-
|
|
1337
|
+
const verifiedArchive = await this.prepareProtocolV2LocalResourceArchive(archiveBinary);
|
|
1338
|
+
const sources: ProtocolV2ResourceBundleSource[] = [];
|
|
1339
|
+
for (const resource of verifiedArchive.resources) {
|
|
1340
|
+
const source = await this.openProtocolV2MemorySource(resource.binary);
|
|
1341
|
+
sources.push({
|
|
1342
|
+
name: resource.entryName.split('/').pop() ?? resource.entryName,
|
|
1343
|
+
source,
|
|
1344
|
+
devicePath: resource.header.devicePath,
|
|
1345
|
+
version: resource.header.version,
|
|
1346
|
+
payloadHash: resource.header.payloadHash,
|
|
1347
|
+
headerHash: resource.header.headerHash,
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
return sources;
|
|
1245
1351
|
}
|
|
1246
1352
|
|
|
1247
1353
|
private async runProtocolV2PreparedArtifacts(
|
|
@@ -1725,12 +1831,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1725
1831
|
return `vol0:/${path}`;
|
|
1726
1832
|
}
|
|
1727
1833
|
|
|
1728
|
-
private getProtocolV2ResourceComparePath(devicePath: string) {
|
|
1729
|
-
return isProtocolV2BootResourcePackagePath(devicePath)
|
|
1730
|
-
? PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH
|
|
1731
|
-
: devicePath;
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
1834
|
private async readProtocolV2DeviceFileHeader(path: string, expectedSize?: number) {
|
|
1735
1835
|
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
1736
1836
|
const filePath = this.getProtocolV2ResourceFilePath(path);
|
|
@@ -1793,7 +1893,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1793
1893
|
|
|
1794
1894
|
try {
|
|
1795
1895
|
const header = await this.readProtocolV2DeviceFileHeader(
|
|
1796
|
-
|
|
1896
|
+
bundle.devicePath,
|
|
1797
1897
|
bundle.source.size
|
|
1798
1898
|
);
|
|
1799
1899
|
if (!header) return false;
|
|
@@ -2052,7 +2152,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2052
2152
|
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
2053
2153
|
const resourcesToSync: ProtocolV2ResourceBundleSource[] = [];
|
|
2054
2154
|
for (const resource of resourceSources) {
|
|
2055
|
-
|
|
2155
|
+
// Early boot promotes this mounted package's staging file. Always replace any
|
|
2156
|
+
// stale staging bytes with the artifact approved by the current PreparedPlan,
|
|
2157
|
+
// even when the mounted final file itself is already current.
|
|
2158
|
+
const requiresFreshStaging = isProtocolV2BootResourcePackagePath(resource.devicePath);
|
|
2159
|
+
if (!requiresFreshStaging && (await this.isProtocolV2ResourceBundleUpToDate(resource))) {
|
|
2056
2160
|
Log.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
2057
2161
|
} else {
|
|
2058
2162
|
resourcesToSync.push(resource);
|
package/src/api/SearchDevices.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizePro2FindMyAdvertisementName } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { BaseMethod } from './BaseMethod';
|
|
4
4
|
import TransportManager from '../data-manager/TransportManager';
|
|
@@ -40,7 +40,7 @@ export default class SearchDevices extends BaseMethod {
|
|
|
40
40
|
seenIds.add(lowerId);
|
|
41
41
|
const rawBleName =
|
|
42
42
|
device.name ?? (device as unknown as { localName?: string }).localName ?? '';
|
|
43
|
-
const bleName =
|
|
43
|
+
const bleName = normalizePro2FindMyAdvertisementName(rawBleName);
|
|
44
44
|
devices.push({
|
|
45
45
|
...device,
|
|
46
46
|
connectId: device.id,
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
2
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
3
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
4
|
+
|
|
5
|
+
import type { CoreApi } from '../../types/api';
|
|
6
|
+
import type {
|
|
7
|
+
FirmwareArtifactReader,
|
|
8
|
+
FirmwareArtifactReference,
|
|
9
|
+
} from '../../types/api/firmwareUpdate';
|
|
10
|
+
import type { FirmwareUpdatePlan } from '../../types/api/firmwareUpdatePlan';
|
|
11
|
+
|
|
12
|
+
export type FirmwareMemoryArtifactEntry = {
|
|
13
|
+
entryName: string;
|
|
14
|
+
binary: ArrayBuffer;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type FirmwareMemoryArtifact = {
|
|
18
|
+
artifactId: string;
|
|
19
|
+
binary: ArrayBuffer;
|
|
20
|
+
materializedEntries?: FirmwareMemoryArtifactEntry[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type FirmwareUpdateV4MemoryHost = {
|
|
24
|
+
preparedPlan: ReturnType<CoreApi['prepareFirmwareUpdatePlan']>;
|
|
25
|
+
hostBindingGeneration: number;
|
|
26
|
+
release: () => void;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let memoryHostSequence = 0;
|
|
30
|
+
|
|
31
|
+
const createReference = (binary: ArrayBuffer, prefix: string): FirmwareArtifactReference => {
|
|
32
|
+
const digest = bytesToHex(sha256(new Uint8Array(binary)));
|
|
33
|
+
return {
|
|
34
|
+
artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
|
|
35
|
+
size: binary.byteLength,
|
|
36
|
+
sha256: digest,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function prepareFirmwareUpdateV4MemoryHost({
|
|
41
|
+
sdk,
|
|
42
|
+
plan,
|
|
43
|
+
artifacts,
|
|
44
|
+
}: {
|
|
45
|
+
sdk: Pick<
|
|
46
|
+
CoreApi,
|
|
47
|
+
| 'prepareFirmwareUpdatePlan'
|
|
48
|
+
| 'registerFirmwareUpdateHostBinding'
|
|
49
|
+
| 'unregisterFirmwareUpdateHostBinding'
|
|
50
|
+
>;
|
|
51
|
+
plan: FirmwareUpdatePlan;
|
|
52
|
+
artifacts: FirmwareMemoryArtifact[];
|
|
53
|
+
}): FirmwareUpdateV4MemoryHost {
|
|
54
|
+
if (plan.executor !== 'v4') {
|
|
55
|
+
throw ERRORS.TypedError(
|
|
56
|
+
HardwareErrorCode.RuntimeError,
|
|
57
|
+
'Firmware memory host only supports V4 plans'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
memoryHostSequence += 1;
|
|
61
|
+
const hostId = `${Date.now()}:${memoryHostSequence}`;
|
|
62
|
+
const binaries = new Map<string, Uint8Array>();
|
|
63
|
+
const inputs = artifacts.map((input, artifactIndex) => {
|
|
64
|
+
const artifactBinary = new Uint8Array(input.binary).slice();
|
|
65
|
+
const artifact = createReference(
|
|
66
|
+
artifactBinary.buffer as ArrayBuffer,
|
|
67
|
+
`${hostId}:artifact:${artifactIndex}`
|
|
68
|
+
);
|
|
69
|
+
binaries.set(artifact.artifactRef, artifactBinary);
|
|
70
|
+
const materializedEntries = input.materializedEntries?.map((entry, entryIndex) => {
|
|
71
|
+
const entryArtifact = createReference(
|
|
72
|
+
entry.binary,
|
|
73
|
+
`${hostId}:entry:${artifactIndex}:${entryIndex}`
|
|
74
|
+
);
|
|
75
|
+
// Entry references are compact receipts for bytes that will be re-derived
|
|
76
|
+
// from the verified archive. Retaining another readable copy here doubles
|
|
77
|
+
// resource memory without adding an execution trust boundary.
|
|
78
|
+
return {
|
|
79
|
+
entryName: entry.entryName,
|
|
80
|
+
artifact: entryArtifact,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
artifactId: input.artifactId,
|
|
85
|
+
artifact,
|
|
86
|
+
...(materializedEntries?.length ? { materializedEntries } : {}),
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
const preparedPlan = sdk.prepareFirmwareUpdatePlan({
|
|
90
|
+
plan,
|
|
91
|
+
leaseRef: `fwmemlease:${hostId}`,
|
|
92
|
+
artifacts: inputs,
|
|
93
|
+
});
|
|
94
|
+
const readers = new Map<string, Uint8Array>();
|
|
95
|
+
let readerSequence = 0;
|
|
96
|
+
const artifactReader: FirmwareArtifactReader = {
|
|
97
|
+
open({ artifactRef }) {
|
|
98
|
+
const binary = binaries.get(artifactRef);
|
|
99
|
+
if (!binary) {
|
|
100
|
+
throw ERRORS.TypedError(
|
|
101
|
+
HardwareErrorCode.RuntimeError,
|
|
102
|
+
'Firmware memory artifact is unavailable'
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
readerSequence += 1;
|
|
106
|
+
const readerId = `fwmemreader:${hostId}:${readerSequence}`;
|
|
107
|
+
readers.set(readerId, binary);
|
|
108
|
+
return Promise.resolve({ readerId, size: binary.byteLength });
|
|
109
|
+
},
|
|
110
|
+
read({ readerId, offset, length }) {
|
|
111
|
+
const binary = readers.get(readerId);
|
|
112
|
+
if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
|
|
113
|
+
throw ERRORS.TypedError(
|
|
114
|
+
HardwareErrorCode.RuntimeError,
|
|
115
|
+
'Firmware memory artifact read is invalid'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const data = binary.slice(offset, offset + length).buffer;
|
|
119
|
+
return Promise.resolve({
|
|
120
|
+
data,
|
|
121
|
+
bytesRead: data.byteLength,
|
|
122
|
+
eof: offset + length === binary.byteLength,
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
close({ readerId }) {
|
|
126
|
+
readers.delete(readerId);
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({
|
|
131
|
+
artifactReader,
|
|
132
|
+
preparedPlanDigest: preparedPlan.preparedPlanDigest,
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
preparedPlan,
|
|
136
|
+
hostBindingGeneration,
|
|
137
|
+
release: () => {
|
|
138
|
+
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
139
|
+
readers.clear();
|
|
140
|
+
binaries.clear();
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -654,6 +654,47 @@ const finalizeFirmwareUpdatePlan = ({
|
|
|
654
654
|
});
|
|
655
655
|
};
|
|
656
656
|
|
|
657
|
+
export type ProtocolV2LocalFirmwareUpdatePlanArtifact = {
|
|
658
|
+
artifactId: string;
|
|
659
|
+
target: Exclude<FirmwareUpdateV4Target, 'boot_resources'>;
|
|
660
|
+
container: 'raw' | 'zip';
|
|
661
|
+
logicalName: string;
|
|
662
|
+
expectedSize: number;
|
|
663
|
+
expectedSha256: string;
|
|
664
|
+
targetVersion?: string;
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
export const buildProtocolV2LocalFirmwareUpdatePlan = ({
|
|
668
|
+
features,
|
|
669
|
+
firmwareType,
|
|
670
|
+
platform,
|
|
671
|
+
artifacts,
|
|
672
|
+
}: {
|
|
673
|
+
features: Features;
|
|
674
|
+
firmwareType: EFirmwareType;
|
|
675
|
+
platform: FirmwareUpdatePlatform;
|
|
676
|
+
artifacts: ProtocolV2LocalFirmwareUpdatePlanArtifact[];
|
|
677
|
+
}): FirmwareUpdatePlan => {
|
|
678
|
+
if (artifacts.length === 0) {
|
|
679
|
+
return planError('Protocol V2 local firmware plan has no artifacts');
|
|
680
|
+
}
|
|
681
|
+
const plan = finalizeFirmwareUpdatePlan({
|
|
682
|
+
features,
|
|
683
|
+
firmwareType,
|
|
684
|
+
platform,
|
|
685
|
+
artifacts: artifacts.map(artifact => ({
|
|
686
|
+
...artifact,
|
|
687
|
+
role: artifact.target === 'resource' ? 'resourceBundle' : 'component',
|
|
688
|
+
url: `https://local-firmware.invalid/${encodeURIComponent(artifact.artifactId)}`,
|
|
689
|
+
})),
|
|
690
|
+
targetsToUpdate: artifacts.map(artifact => artifact.target),
|
|
691
|
+
});
|
|
692
|
+
if (plan.executor !== 'v4') {
|
|
693
|
+
return planError('Protocol V2 local firmware plan requires executor v4');
|
|
694
|
+
}
|
|
695
|
+
return plan;
|
|
696
|
+
};
|
|
697
|
+
|
|
657
698
|
export const buildProtocolV2FirmwareUpdatePlan = ({
|
|
658
699
|
features,
|
|
659
700
|
firmwareType,
|
|
@@ -71,13 +71,6 @@ export const getFirmwareUpdateResourceName = (value: unknown): string => {
|
|
|
71
71
|
return resourceName;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
const getPreparedEntryIdentity = (entryName: unknown): string => {
|
|
75
|
-
getFirmwareUpdateResourceName(entryName);
|
|
76
|
-
// Protocol V2 resource ZIPs can ship the same basename from different
|
|
77
|
-
// directories, such as rom/params.okpkg and bootloader/params.okpkg.
|
|
78
|
-
return (entryName as string).toLowerCase();
|
|
79
|
-
};
|
|
80
|
-
|
|
81
74
|
const assertPreparedEntry = (value: unknown): FirmwareUpdatePreparedEntry => {
|
|
82
75
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
83
76
|
return preparedPlanError('Firmware prepared plan entry must be an object');
|
|
@@ -148,8 +141,11 @@ const assertPreparedArtifacts = ({
|
|
|
148
141
|
}
|
|
149
142
|
if (
|
|
150
143
|
materializedEntries &&
|
|
151
|
-
new Set(
|
|
152
|
-
materializedEntries.
|
|
144
|
+
new Set(
|
|
145
|
+
materializedEntries.map(entry =>
|
|
146
|
+
getFirmwareUpdateResourceName(entry.entryName).toLowerCase()
|
|
147
|
+
)
|
|
148
|
+
).size !== materializedEntries.length
|
|
153
149
|
) {
|
|
154
150
|
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
155
151
|
}
|
|
@@ -285,7 +281,7 @@ export const validateFirmwareUpdatePreparedPlan = (value: unknown): FirmwareUpda
|
|
|
285
281
|
const materializedEntryNames =
|
|
286
282
|
artifact.materializedEntries?.map(entry => {
|
|
287
283
|
assertPreparedEntry(entry);
|
|
288
|
-
return
|
|
284
|
+
return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
|
|
289
285
|
}) ?? [];
|
|
290
286
|
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
291
287
|
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|