@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.
Files changed (123) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +251 -0
  2. package/__tests__/connectSettings.test.ts +5 -47
  3. package/__tests__/device-state-mapper.test.ts +10 -1
  4. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  5. package/__tests__/networkUtils.test.ts +20 -0
  6. package/__tests__/open-wallet-session.test.ts +19 -5
  7. package/__tests__/protocol-v2-firmware-targets.test.ts +18 -0
  8. package/__tests__/protocol-v2.test.ts +58 -240
  9. package/__tests__/public-device-state-api.test.ts +10 -1
  10. package/dist/api/CheckAllFirmwareRelease.d.ts +24 -1
  11. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  12. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  13. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  14. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  15. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  16. package/dist/api/FirmwareUpdateV4.d.ts +6 -22
  17. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  18. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  19. package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
  20. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  21. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  22. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
  23. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  24. package/dist/api/firmware/getBinary.d.ts +0 -7
  25. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  26. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  27. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  28. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  29. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  30. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  31. package/dist/data-manager/DataManager.d.ts +0 -1
  32. package/dist/data-manager/DataManager.d.ts.map +1 -1
  33. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  34. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  35. package/dist/index.d.ts +43 -179
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1048 -2606
  38. package/dist/inject.d.ts.map +1 -1
  39. package/dist/lowLevelInject.d.ts.map +1 -1
  40. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  41. package/dist/topLevelInject.d.ts.map +1 -1
  42. package/dist/types/api/checkAllFirmwareRelease.d.ts +25 -7
  43. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  44. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  45. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  46. package/dist/types/api/export.d.ts +2 -4
  47. package/dist/types/api/export.d.ts.map +1 -1
  48. package/dist/types/api/firmwareUpdate.d.ts +0 -69
  49. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  50. package/dist/types/api/index.d.ts +3 -10
  51. package/dist/types/api/index.d.ts.map +1 -1
  52. package/dist/types/api/openWalletSession.d.ts +9 -3
  53. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  54. package/dist/types/device.d.ts +6 -0
  55. package/dist/types/device.d.ts.map +1 -1
  56. package/dist/types/settings.d.ts +1 -13
  57. package/dist/types/settings.d.ts.map +1 -1
  58. package/dist/utils/networkUtils.d.ts +1 -0
  59. package/dist/utils/networkUtils.d.ts.map +1 -1
  60. package/package.json +4 -4
  61. package/src/api/CheckAllFirmwareRelease.ts +368 -50
  62. package/src/api/FirmwareUpdateV2.ts +120 -298
  63. package/src/api/FirmwareUpdateV3.ts +56 -258
  64. package/src/api/FirmwareUpdateV4.ts +328 -765
  65. package/src/api/OpenWalletSession.ts +12 -8
  66. package/src/api/PromptWebDeviceAccess.ts +2 -6
  67. package/src/api/device/DeviceUpdateBootloader.ts +6 -122
  68. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
  69. package/src/api/firmware/updateBootloader.ts +4 -19
  70. package/src/api/firmware/uploadFirmware.ts +22 -140
  71. package/src/data/messages/messages-protocol-v2.json +4 -0
  72. package/src/data-manager/DataManager.ts +33 -33
  73. package/src/data-manager/connectSettings.ts +0 -11
  74. package/src/device/DeviceStateMapper.ts +6 -0
  75. package/src/index.ts +0 -5
  76. package/src/inject.ts +2 -22
  77. package/src/lowLevelInject.ts +1 -5
  78. package/src/protocols/protocol-v2/walletSession.ts +2 -1
  79. package/src/topLevelInject.ts +1 -5
  80. package/src/types/api/checkAllFirmwareRelease.ts +46 -7
  81. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  82. package/src/types/api/export.ts +5 -18
  83. package/src/types/api/firmwareUpdate.ts +0 -76
  84. package/src/types/api/index.ts +6 -15
  85. package/src/types/api/openWalletSession.ts +12 -3
  86. package/src/types/device.ts +6 -0
  87. package/src/types/settings.ts +3 -13
  88. package/src/utils/networkUtils.ts +5 -3
  89. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -174
  90. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  91. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  92. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  93. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  94. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  95. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
  96. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  97. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  98. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  99. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  100. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  101. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  102. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  103. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  104. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  105. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  106. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  107. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -30
  108. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  109. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  110. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  111. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  112. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  113. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  114. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  115. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  116. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  117. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  118. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  119. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -745
  120. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -392
  121. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  122. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  123. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -1,34 +1,295 @@
1
- import { HardwareError } from '@onekeyfe/hd-shared';
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
- LoggerNames,
17
- getDeviceFirmwareVersion,
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 { FirmwareUpdatePlan } from '../types/api/firmwareUpdatePlan';
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
- const Log = getLogger(LoggerNames.Method);
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
- checkBridgeRelease,
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
- firmwareUpdatePlan,
118
- } as unknown as AllFirmwareRelease;
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
  }