@onekeyfe/hd-core 1.2.0-alpha.30 → 1.2.0-alpha.32
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__/check-all-firmware-release-protocol-v2.test.ts +251 -0
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-state-mapper.test.ts +10 -1
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
- package/__tests__/networkUtils.test.ts +20 -0
- package/__tests__/open-wallet-session.test.ts +19 -5
- package/__tests__/protocol-v2-firmware-targets.test.ts +18 -0
- package/__tests__/protocol-v2.test.ts +58 -240
- package/__tests__/public-device-state-api.test.ts +10 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts +24 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +6 -22
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/data-manager/DataManager.d.ts +0 -1
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/index.d.ts +43 -179
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1048 -2606
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +25 -7
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +2 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +0 -69
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +3 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +9 -3
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/device.d.ts +6 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +1 -13
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/networkUtils.d.ts +1 -0
- package/dist/utils/networkUtils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +368 -50
- package/src/api/FirmwareUpdateV2.ts +120 -298
- package/src/api/FirmwareUpdateV3.ts +56 -258
- package/src/api/FirmwareUpdateV4.ts +328 -765
- package/src/api/OpenWalletSession.ts +12 -8
- package/src/api/PromptWebDeviceAccess.ts +2 -6
- package/src/api/device/DeviceUpdateBootloader.ts +6 -122
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +22 -140
- package/src/data/messages/messages-protocol-v2.json +4 -0
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/DeviceStateMapper.ts +6 -0
- package/src/index.ts +0 -5
- package/src/inject.ts +2 -22
- package/src/lowLevelInject.ts +1 -5
- package/src/protocols/protocol-v2/walletSession.ts +2 -1
- package/src/topLevelInject.ts +1 -5
- package/src/types/api/checkAllFirmwareRelease.ts +46 -7
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +5 -18
- package/src/types/api/firmwareUpdate.ts +0 -76
- package/src/types/api/index.ts +6 -15
- package/src/types/api/openWalletSession.ts +12 -3
- package/src/types/device.ts +6 -0
- package/src/types/settings.ts +3 -13
- package/src/utils/networkUtils.ts +5 -3
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -174
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -30
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwarePreparationError.ts +0 -12
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -745
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -392
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -38
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -1,34 +1,295 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
import semver from 'semver';
|
|
2
3
|
|
|
3
|
-
import { BaseMethod } from './BaseMethod';
|
|
4
4
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
5
|
+
import { DataManager } from '../data-manager';
|
|
5
6
|
import {
|
|
6
7
|
getBleFirmwareReleaseInfo,
|
|
7
8
|
getBootloaderReleaseInfo,
|
|
8
9
|
getFirmwareReleaseInfo,
|
|
9
10
|
} from './firmware/releaseHelper';
|
|
10
|
-
import {
|
|
11
|
-
buildFirmwareUpdatePlan,
|
|
12
|
-
validateFirmwareUpdatePlanForceTargets,
|
|
13
|
-
} from './firmware/FirmwareUpdatePlan';
|
|
14
11
|
import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
getDeviceType,
|
|
19
|
-
getFirmwareType,
|
|
20
|
-
getLogger,
|
|
21
|
-
} from '../utils';
|
|
12
|
+
import { getDeviceFirmwareVersion, getDeviceType, getFirmwareType } from '../utils';
|
|
13
|
+
import { httpRequest } from '../utils/networkUtils';
|
|
14
|
+
import { BaseMethod } from './BaseMethod';
|
|
22
15
|
|
|
23
16
|
import type {
|
|
24
17
|
AllFirmwareRelease,
|
|
25
18
|
CheckAllFirmwareReleaseParams,
|
|
19
|
+
ProtocolV2FirmwareComponentRelease,
|
|
20
|
+
ProtocolV2FirmwareReleaseStatus,
|
|
26
21
|
} from '../types/api/checkAllFirmwareRelease';
|
|
27
|
-
import type {
|
|
22
|
+
import type { FirmwareUpdateV4Target } from '../types/api/firmwareUpdate';
|
|
23
|
+
import type {
|
|
24
|
+
DeviceFeaturesVerify,
|
|
25
|
+
DeviceStateVersions,
|
|
26
|
+
IFirmwareReleaseInfo,
|
|
27
|
+
IProtocolV2FirmwareComponent,
|
|
28
|
+
IProtocolV2FirmwareComponentTarget,
|
|
29
|
+
} from '../types';
|
|
30
|
+
|
|
31
|
+
const UPDATE_TARGET_BY_COMPONENT_TARGET: Readonly<
|
|
32
|
+
Partial<Record<IProtocolV2FirmwareComponentTarget, FirmwareUpdateV4Target>>
|
|
33
|
+
> = {
|
|
34
|
+
BOOTLOADER: 'boot',
|
|
35
|
+
APPLICATION_P1: 'app_v1',
|
|
36
|
+
APPLICATION_P2: 'app_v2',
|
|
37
|
+
COPROCESSOR: 'coprocessor',
|
|
38
|
+
SE01: 'se01',
|
|
39
|
+
SE02: 'se02',
|
|
40
|
+
SE03: 'se03',
|
|
41
|
+
SE04: 'se04',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const CURRENT_VERSION_BY_COMPONENT_TARGET: Readonly<
|
|
45
|
+
Record<IProtocolV2FirmwareComponentTarget, keyof DeviceStateVersions | null>
|
|
46
|
+
> = {
|
|
47
|
+
ROMLOADER: 'board',
|
|
48
|
+
BOOTLOADER: 'bootloader',
|
|
49
|
+
APPLICATION_P1: 'applicationP1',
|
|
50
|
+
APPLICATION_P2: 'applicationP2',
|
|
51
|
+
COPROCESSOR: 'ble',
|
|
52
|
+
SE01: 'se01',
|
|
53
|
+
SE02: 'se02',
|
|
54
|
+
SE03: 'se03',
|
|
55
|
+
SE04: 'se04',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const CURRENT_HASH_BY_COMPONENT_TARGET: Readonly<
|
|
59
|
+
Partial<Record<IProtocolV2FirmwareComponentTarget, keyof DeviceFeaturesVerify>>
|
|
60
|
+
> = {
|
|
61
|
+
BOOTLOADER: 'bootloaderHash',
|
|
62
|
+
APPLICATION_P1: 'applicationP1Hash',
|
|
63
|
+
APPLICATION_P2: 'applicationP2Hash',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const PROTOCOL_V2_PACKAGE_METADATA_END = 0x27f;
|
|
67
|
+
const PROTOCOL_V2_PACKAGE_PAYLOAD_HASH_OFFSET = 0x200;
|
|
68
|
+
const PROTOCOL_V2_PACKAGE_PAYLOAD_HASH_SIZE = 64;
|
|
69
|
+
|
|
70
|
+
function bytesToHex(bytes: Uint8Array): string {
|
|
71
|
+
return Array.from(bytes)
|
|
72
|
+
.map(byte => byte.toString(16).padStart(2, '0'))
|
|
73
|
+
.join('');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeHex(value: string | undefined): string | undefined {
|
|
77
|
+
const normalized = value?.replace(/^0x/i, '').toLowerCase();
|
|
78
|
+
return normalized && /^[0-9a-f]+$/.test(normalized) ? normalized : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function getRemoteComponentPayloadHash(url: string): Promise<string | null> {
|
|
82
|
+
try {
|
|
83
|
+
const binary = await httpRequest<ArrayBuffer>(url, 'binary', {
|
|
84
|
+
headers: { Range: `bytes=0-${PROTOCOL_V2_PACKAGE_METADATA_END}` },
|
|
85
|
+
connectTimeoutMs: 5000,
|
|
86
|
+
readTimeoutMs: 5000,
|
|
87
|
+
overallTimeoutMs: 10000,
|
|
88
|
+
maxRetries: 1,
|
|
89
|
+
retryDelayMs: 250,
|
|
90
|
+
});
|
|
91
|
+
const bytes = new Uint8Array(binary);
|
|
92
|
+
if (
|
|
93
|
+
bytes.byteLength <= PROTOCOL_V2_PACKAGE_METADATA_END ||
|
|
94
|
+
String.fromCharCode(...bytes.slice(0, 4)) !== 'OKPP'
|
|
95
|
+
) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return bytesToHex(
|
|
99
|
+
bytes.slice(
|
|
100
|
+
PROTOCOL_V2_PACKAGE_PAYLOAD_HASH_OFFSET,
|
|
101
|
+
PROTOCOL_V2_PACKAGE_PAYLOAD_HASH_OFFSET + PROTOCOL_V2_PACKAGE_PAYLOAD_HASH_SIZE
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function toVersionString(version: number[] | undefined): string | null {
|
|
110
|
+
return version?.length ? version.join('.') : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getOrderedComponentEntries(release: IFirmwareReleaseInfo) {
|
|
114
|
+
const components = release.components ?? {};
|
|
115
|
+
const orderedKeys = [
|
|
116
|
+
...(release.installOrder ?? []),
|
|
117
|
+
...Object.keys(components).filter(key => !release.installOrder?.includes(key)),
|
|
118
|
+
];
|
|
119
|
+
return orderedKeys
|
|
120
|
+
.map(key => {
|
|
121
|
+
const component = components[key];
|
|
122
|
+
return component ? ([key, component] as const) : undefined;
|
|
123
|
+
})
|
|
124
|
+
.filter((entry): entry is readonly [string, IProtocolV2FirmwareComponent] => !!entry);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function buildComponentRelease({
|
|
128
|
+
configKey,
|
|
129
|
+
component,
|
|
130
|
+
currentVersions,
|
|
131
|
+
currentVerification,
|
|
132
|
+
remotePayloadHash,
|
|
133
|
+
releaseRequired,
|
|
134
|
+
}: {
|
|
135
|
+
configKey: string;
|
|
136
|
+
component: IProtocolV2FirmwareComponent;
|
|
137
|
+
currentVersions: DeviceStateVersions;
|
|
138
|
+
currentVerification: Partial<DeviceFeaturesVerify>;
|
|
139
|
+
remotePayloadHash: string | null | undefined;
|
|
140
|
+
releaseRequired: boolean;
|
|
141
|
+
}): ProtocolV2FirmwareComponentRelease {
|
|
142
|
+
const componentTarget = component.target.toUpperCase() as IProtocolV2FirmwareComponentTarget;
|
|
143
|
+
const updateTarget = UPDATE_TARGET_BY_COMPONENT_TARGET[componentTarget] ?? null;
|
|
144
|
+
const currentVersionKey = CURRENT_VERSION_BY_COMPONENT_TARGET[componentTarget];
|
|
145
|
+
const currentVersion = currentVersionKey
|
|
146
|
+
? currentVersions[currentVersionKey] ??
|
|
147
|
+
(componentTarget === 'APPLICATION_P1' ? currentVersions.firmware : null) ??
|
|
148
|
+
null
|
|
149
|
+
: null;
|
|
150
|
+
const targetVersion = toVersionString(component.version);
|
|
151
|
+
|
|
152
|
+
let status: ProtocolV2FirmwareComponentRelease['status'] = 'unknown';
|
|
153
|
+
if (!updateTarget) {
|
|
154
|
+
status = 'unsupported';
|
|
155
|
+
} else if (
|
|
156
|
+
currentVersion &&
|
|
157
|
+
targetVersion &&
|
|
158
|
+
semver.valid(currentVersion) &&
|
|
159
|
+
semver.valid(targetVersion)
|
|
160
|
+
) {
|
|
161
|
+
if (semver.lt(currentVersion, targetVersion)) {
|
|
162
|
+
status = 'outdated';
|
|
163
|
+
} else if (semver.gt(currentVersion, targetVersion)) {
|
|
164
|
+
status = 'valid';
|
|
165
|
+
} else if (remotePayloadHash !== undefined) {
|
|
166
|
+
const currentHashKey = CURRENT_HASH_BY_COMPONENT_TARGET[componentTarget];
|
|
167
|
+
const currentHash = normalizeHex(
|
|
168
|
+
currentHashKey ? currentVerification[currentHashKey] : undefined
|
|
169
|
+
);
|
|
170
|
+
const expectedHash = normalizeHex(remotePayloadHash ?? undefined);
|
|
171
|
+
if (currentHash && expectedHash) {
|
|
172
|
+
status = expectedHash.startsWith(currentHash) ? 'valid' : 'outdated';
|
|
173
|
+
} else {
|
|
174
|
+
status = 'unknown';
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
status = 'valid';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
configKey,
|
|
183
|
+
componentTarget,
|
|
184
|
+
updateTarget,
|
|
185
|
+
currentVersion,
|
|
186
|
+
targetVersion,
|
|
187
|
+
status,
|
|
188
|
+
required: releaseRequired && status === 'outdated',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
type ProtocolV2FirmwareReleasePlan = {
|
|
193
|
+
firmwareType: EFirmwareType;
|
|
194
|
+
status: ProtocolV2FirmwareReleaseStatus;
|
|
195
|
+
hasUpgrade: boolean;
|
|
196
|
+
required: boolean;
|
|
197
|
+
currentVersions: DeviceStateVersions;
|
|
198
|
+
components: ProtocolV2FirmwareComponentRelease[];
|
|
199
|
+
targetsToUpdate: FirmwareUpdateV4Target[];
|
|
200
|
+
release: IFirmwareReleaseInfo | undefined;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export function buildProtocolV2FirmwareRelease({
|
|
204
|
+
currentVersions,
|
|
205
|
+
currentVerification = {},
|
|
206
|
+
remotePayloadHashes = {},
|
|
207
|
+
firmwareType,
|
|
208
|
+
release,
|
|
209
|
+
}: {
|
|
210
|
+
currentVersions: DeviceStateVersions;
|
|
211
|
+
currentVerification?: Partial<DeviceFeaturesVerify>;
|
|
212
|
+
remotePayloadHashes?: Readonly<Record<string, string | null>>;
|
|
213
|
+
firmwareType: EFirmwareType;
|
|
214
|
+
release: IFirmwareReleaseInfo | undefined;
|
|
215
|
+
}): ProtocolV2FirmwareReleasePlan {
|
|
216
|
+
if (!release) {
|
|
217
|
+
return {
|
|
218
|
+
firmwareType,
|
|
219
|
+
status: 'unavailable' as const,
|
|
220
|
+
hasUpgrade: false,
|
|
221
|
+
required: false,
|
|
222
|
+
currentVersions,
|
|
223
|
+
components: [],
|
|
224
|
+
targetsToUpdate: [],
|
|
225
|
+
release: undefined,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
28
228
|
|
|
29
|
-
|
|
229
|
+
let components = getOrderedComponentEntries(release).map(([configKey, component]) =>
|
|
230
|
+
buildComponentRelease({
|
|
231
|
+
configKey,
|
|
232
|
+
component,
|
|
233
|
+
currentVersions,
|
|
234
|
+
currentVerification,
|
|
235
|
+
remotePayloadHash: Object.prototype.hasOwnProperty.call(remotePayloadHashes, configKey)
|
|
236
|
+
? remotePayloadHashes[configKey]
|
|
237
|
+
: undefined,
|
|
238
|
+
releaseRequired: release.required,
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
if (!currentVersions.applicationP2) {
|
|
242
|
+
const applicationP1 = components.find(
|
|
243
|
+
component => component.componentTarget === 'APPLICATION_P1'
|
|
244
|
+
);
|
|
245
|
+
if (applicationP1) {
|
|
246
|
+
components = components.map(component =>
|
|
247
|
+
component.componentTarget === 'APPLICATION_P2' && component.status === 'unknown'
|
|
248
|
+
? {
|
|
249
|
+
...component,
|
|
250
|
+
currentVersion: currentVersions.applicationP1 ?? currentVersions.firmware,
|
|
251
|
+
status: applicationP1.status,
|
|
252
|
+
required: applicationP1.required,
|
|
253
|
+
}
|
|
254
|
+
: component
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const targetsToUpdate = components.flatMap(component =>
|
|
259
|
+
component.status === 'outdated' && component.updateTarget ? [component.updateTarget] : []
|
|
260
|
+
);
|
|
261
|
+
if (targetsToUpdate.length > 0 && release.resourceBundles?.length) {
|
|
262
|
+
targetsToUpdate.push('resource');
|
|
263
|
+
}
|
|
264
|
+
const uniqueTargetsToUpdate = Array.from(new Set(targetsToUpdate));
|
|
265
|
+
const hasUpgrade = uniqueTargetsToUpdate.length > 0;
|
|
266
|
+
const required = release.required && hasUpgrade;
|
|
267
|
+
let status: ProtocolV2FirmwareReleaseStatus = 'valid';
|
|
268
|
+
if (required) {
|
|
269
|
+
status = 'required';
|
|
270
|
+
} else if (hasUpgrade) {
|
|
271
|
+
status = 'outdated';
|
|
272
|
+
} else if (components.some(component => component.status === 'unknown')) {
|
|
273
|
+
status = 'unknown';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
firmwareType,
|
|
278
|
+
status,
|
|
279
|
+
hasUpgrade,
|
|
280
|
+
required,
|
|
281
|
+
currentVersions,
|
|
282
|
+
components,
|
|
283
|
+
targetsToUpdate: uniqueTargetsToUpdate,
|
|
284
|
+
release,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
30
287
|
|
|
31
288
|
export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
289
|
+
getSupportedProtocols() {
|
|
290
|
+
return ['V1', 'V2'] as const;
|
|
291
|
+
}
|
|
292
|
+
|
|
32
293
|
init() {
|
|
33
294
|
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
34
295
|
this.useDevicePassphraseState = false;
|
|
@@ -36,14 +297,13 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
36
297
|
}
|
|
37
298
|
|
|
38
299
|
async run() {
|
|
300
|
+
if (this.device.isProtocolV2()) {
|
|
301
|
+
return this.runProtocolV2();
|
|
302
|
+
}
|
|
303
|
+
|
|
39
304
|
const { features } = this.device;
|
|
40
|
-
const {
|
|
41
|
-
|
|
42
|
-
firmwareType: firmwareTypeParams,
|
|
43
|
-
platform,
|
|
44
|
-
forceUpdateTargets,
|
|
45
|
-
} = this.payload as CheckAllFirmwareReleaseParams;
|
|
46
|
-
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
305
|
+
const { checkBridgeRelease, firmwareType: firmwareTypeParams } = this
|
|
306
|
+
.payload as CheckAllFirmwareReleaseParams;
|
|
47
307
|
|
|
48
308
|
if (!features) {
|
|
49
309
|
return Promise.resolve(null);
|
|
@@ -74,32 +334,6 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
74
334
|
firmwareType,
|
|
75
335
|
});
|
|
76
336
|
const bleFirmwareReleaseInfo = getBleFirmwareReleaseInfo(features);
|
|
77
|
-
let firmwareUpdatePlan: FirmwareUpdatePlan | undefined;
|
|
78
|
-
try {
|
|
79
|
-
firmwareUpdatePlan = buildFirmwareUpdatePlan({
|
|
80
|
-
features,
|
|
81
|
-
firmwareType,
|
|
82
|
-
platform: platform ?? 'web',
|
|
83
|
-
firmware: firmwareRelease,
|
|
84
|
-
ble: bleFirmwareReleaseInfo,
|
|
85
|
-
bootloader: bootloaderRelease,
|
|
86
|
-
forceUpdateTargets: validatedForceUpdateTargets,
|
|
87
|
-
});
|
|
88
|
-
} catch (error) {
|
|
89
|
-
if (
|
|
90
|
-
validatedForceUpdateTargets.length > 0 ||
|
|
91
|
-
!(error instanceof HardwareError) ||
|
|
92
|
-
error.params?.firmwareUpdateCode !== 'FirmwarePlanInvalid'
|
|
93
|
-
) {
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
// A Plan is an optional external-host capability. Release checks remain
|
|
97
|
-
// available for legacy and recovery flows when a Plan cannot be built.
|
|
98
|
-
Log.warn(
|
|
99
|
-
'[CheckAllFirmwareRelease] Optional firmware Plan is unavailable; using the legacy release result'
|
|
100
|
-
);
|
|
101
|
-
firmwareUpdatePlan = undefined;
|
|
102
|
-
}
|
|
103
337
|
|
|
104
338
|
return {
|
|
105
339
|
firmware: firmwareRelease,
|
|
@@ -114,7 +348,91 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
114
348
|
}
|
|
115
349
|
: undefined,
|
|
116
350
|
features,
|
|
117
|
-
|
|
118
|
-
|
|
351
|
+
} as AllFirmwareRelease;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private async runProtocolV2(): Promise<AllFirmwareRelease> {
|
|
355
|
+
const state = await this.device.getDeviceState({
|
|
356
|
+
refreshSections: ['identity', 'versions', 'verification'],
|
|
357
|
+
});
|
|
358
|
+
if (state.identity.deviceType !== 'pro2') {
|
|
359
|
+
throw ERRORS.TypedError(
|
|
360
|
+
HardwareErrorCode.DeviceNotSupportMethod,
|
|
361
|
+
'checkAllFirmwareRelease requires a Pro2 device for Protocol V2'
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const { features } = this.device;
|
|
366
|
+
if (!features) {
|
|
367
|
+
throw ERRORS.TypedError(
|
|
368
|
+
HardwareErrorCode.RuntimeError,
|
|
369
|
+
'checkAllFirmwareRelease requires initialized device features'
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const { firmwareType: firmwareTypeParam } = this.payload as CheckAllFirmwareReleaseParams;
|
|
374
|
+
const firmwareType =
|
|
375
|
+
firmwareTypeParam ?? state.identity.firmwareType ?? EFirmwareType.Universal;
|
|
376
|
+
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
377
|
+
const remotePayloadHashes: Record<string, string | null> = {};
|
|
378
|
+
if (release) {
|
|
379
|
+
await Promise.all(
|
|
380
|
+
getOrderedComponentEntries(release).map(async ([configKey, component]) => {
|
|
381
|
+
const componentTarget =
|
|
382
|
+
component.target.toUpperCase() as IProtocolV2FirmwareComponentTarget;
|
|
383
|
+
if (!CURRENT_HASH_BY_COMPONENT_TARGET[componentTarget]) return;
|
|
384
|
+
const currentVersionKey = CURRENT_VERSION_BY_COMPONENT_TARGET[componentTarget];
|
|
385
|
+
const currentVersion = currentVersionKey
|
|
386
|
+
? state.versions[currentVersionKey] ??
|
|
387
|
+
(componentTarget === 'APPLICATION_P1' ? state.versions.firmware : null)
|
|
388
|
+
: null;
|
|
389
|
+
const targetVersion = toVersionString(component.version);
|
|
390
|
+
if (
|
|
391
|
+
currentVersion &&
|
|
392
|
+
targetVersion &&
|
|
393
|
+
semver.valid(currentVersion) &&
|
|
394
|
+
semver.valid(targetVersion) &&
|
|
395
|
+
semver.eq(currentVersion, targetVersion)
|
|
396
|
+
) {
|
|
397
|
+
const configuredPayloadHash = normalizeHex(component.payloadHash);
|
|
398
|
+
if (configuredPayloadHash) {
|
|
399
|
+
remotePayloadHashes[configKey] = configuredPayloadHash;
|
|
400
|
+
} else if (component.fingerprint && component.url) {
|
|
401
|
+
remotePayloadHashes[configKey] = await getRemoteComponentPayloadHash(component.url);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
const plan = buildProtocolV2FirmwareRelease({
|
|
408
|
+
currentVersions: state.versions,
|
|
409
|
+
currentVerification: state.verification,
|
|
410
|
+
remotePayloadHashes,
|
|
411
|
+
firmwareType,
|
|
412
|
+
release,
|
|
413
|
+
});
|
|
414
|
+
const firmwareStatus = plan.status === 'unavailable' ? 'unknown' : plan.status;
|
|
415
|
+
const emptyRelease = 'none' as const;
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
firmware: {
|
|
419
|
+
status: firmwareStatus,
|
|
420
|
+
changelog: release ? [release.changelog] : [],
|
|
421
|
+
release: release ?? emptyRelease,
|
|
422
|
+
bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
|
|
423
|
+
},
|
|
424
|
+
ble: {
|
|
425
|
+
status: 'valid',
|
|
426
|
+
release: emptyRelease,
|
|
427
|
+
},
|
|
428
|
+
bootloader: {
|
|
429
|
+
status: 'valid',
|
|
430
|
+
release: emptyRelease,
|
|
431
|
+
},
|
|
432
|
+
features,
|
|
433
|
+
protocol: 'V2',
|
|
434
|
+
deviceType: 'pro2',
|
|
435
|
+
...plan,
|
|
436
|
+
};
|
|
119
437
|
}
|
|
120
438
|
}
|