@onekeyfe/hd-core 1.2.0-alpha.21 → 1.2.0-alpha.23
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__/DeviceCommands.test.ts +85 -0
- package/__tests__/connectSettings.test.ts +47 -5
- package/__tests__/device-identity.test.ts +24 -2
- package/__tests__/device-settings.test.ts +2 -2
- package/__tests__/device-wallet-session-store.test.ts +152 -7
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +86 -0
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
- package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +326 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +213 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +39 -30
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/logBlockEvent.test.ts +17 -0
- package/__tests__/open-wallet-session.test.ts +311 -12
- package/__tests__/pro2Wallpaper.test.ts +7 -18
- package/__tests__/protocol-v2-unlock-policy.test.ts +45 -0
- package/__tests__/protocol-v2.test.ts +685 -177
- package/__tests__/public-device-state-api.test.ts +69 -62
- package/__tests__/public-pro2-api-boundary.test.ts +8 -34
- package/dist/api/BaseMethod.d.ts +2 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/ClearSessionCache.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +11 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +7 -3
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +29 -10
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxGetAddress.d.ts +1 -0
- package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessage.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignTransaction.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +1 -1
- package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +7 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +23 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +30 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +7 -0
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +0 -17
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
- package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +1 -0
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +3 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/events/device.d.ts +1 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +273 -230
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3060 -1676
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +4 -0
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/unlockRetry.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 +3 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUnlock.d.ts +2 -2
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +4 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +69 -0
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts +27 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +10 -19
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +1 -0
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -76
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/api/sessionCache.d.ts +4 -1
- package/dist/types/api/sessionCache.d.ts.map +1 -1
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +8 -3
- package/src/api/CheckAllFirmwareRelease.ts +23 -3
- package/src/api/ClearSessionCache.ts +4 -0
- package/src/api/FirmwareUpdate.ts +8 -1
- package/src/api/FirmwareUpdateV2.ts +292 -120
- package/src/api/FirmwareUpdateV3.ts +256 -55
- package/src/api/FirmwareUpdateV4.ts +821 -331
- package/src/api/GetPassphraseState.ts +11 -5
- package/src/api/OpenWalletSession.ts +74 -25
- package/src/api/UploadPortfolio.ts +1 -1
- package/src/api/conflux/ConfluxGetAddress.ts +2 -0
- package/src/api/conflux/ConfluxSignMessage.ts +2 -0
- package/src/api/conflux/ConfluxSignMessageCIP23.ts +2 -0
- package/src/api/conflux/ConfluxSignTransaction.ts +2 -0
- package/src/api/device/DeviceChangePin.ts +1 -1
- package/src/api/device/DeviceUnlock.ts +1 -2
- package/src/api/device/DeviceUpdateBootloader.ts +122 -6
- package/src/api/device/DeviceWipe.ts +3 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +50 -0
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +621 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +392 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +140 -22
- package/src/api/helpers/protocolV2FileWrite.ts +6 -0
- package/src/api/index.ts +0 -18
- package/src/api/nexa/NexaSignTransaction.ts +2 -0
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
- package/src/core/index.ts +1 -0
- package/src/data/messages/messages-protocol-v2.json +35 -1
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +80 -67
- package/src/device/DeviceCommands.ts +76 -159
- package/src/device/DeviceStateMapper.ts +18 -1
- package/src/device/DeviceStateProjector.ts +7 -1
- package/src/events/device.ts +1 -0
- package/src/events/logBlockEvent.ts +1 -14
- package/src/events/ui-request.ts +1 -0
- package/src/index.ts +5 -0
- package/src/inject.ts +22 -25
- package/src/lowLevelInject.ts +5 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +2 -3
- package/src/protocols/protocol-v2/unlockPolicy.ts +105 -0
- package/src/protocols/protocol-v2/unlockRetry.ts +1 -3
- package/src/protocols/protocol-v2/walletSession.ts +86 -9
- package/src/topLevelInject.ts +5 -1
- package/src/types/api/checkAllFirmwareRelease.ts +3 -0
- package/src/types/api/deviceUnlock.ts +2 -5
- package/src/types/api/deviceUpdateBootloader.ts +6 -0
- package/src/types/api/export.ts +18 -0
- package/src/types/api/firmwareUpdate.ts +76 -0
- package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
- package/src/types/api/firmwareUpdatePlan.ts +36 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/getPassphraseState.ts +4 -3
- package/src/types/api/index.ts +14 -34
- package/src/types/api/openWalletSession.ts +2 -0
- package/src/types/api/protocolV2.ts +3 -156
- package/src/types/api/sessionCache.ts +9 -4
- package/src/types/settings.ts +13 -0
- package/src/utils/deviceFeaturesUtils.ts +5 -1
- package/src/utils/deviceInfoUtils.ts +3 -16
package/src/api/BaseMethod.ts
CHANGED
|
@@ -23,8 +23,12 @@ import type { CoreMessage } from '../events';
|
|
|
23
23
|
import type { ProtocolV2InteractionDescriptor } from '../protocols/protocol-v2/uiInteraction';
|
|
24
24
|
import type { RequestContext } from '../utils/tracing';
|
|
25
25
|
import type { CoreContext } from '../core';
|
|
26
|
+
import {
|
|
27
|
+
getProtocolV2UnlockPolicy,
|
|
28
|
+
type UnlockPolicy,
|
|
29
|
+
} from '../protocols/protocol-v2/unlockPolicy';
|
|
26
30
|
|
|
27
|
-
export type UnlockPolicy
|
|
31
|
+
export type { UnlockPolicy } from '../protocols/protocol-v2/unlockPolicy';
|
|
28
32
|
export type ProtocolV2UiMode = 'auto' | 'none';
|
|
29
33
|
|
|
30
34
|
const Log = getLogger(LoggerNames.Method);
|
|
@@ -171,8 +175,8 @@ export abstract class BaseMethod<Params = undefined> {
|
|
|
171
175
|
*/
|
|
172
176
|
requireProtocolV2 = false;
|
|
173
177
|
|
|
174
|
-
/** Core unlocks and retries Protocol V2
|
|
175
|
-
unlockPolicy: UnlockPolicy = '
|
|
178
|
+
/** Core unlocks and retries only explicitly replay-safe Protocol V2 methods. */
|
|
179
|
+
unlockPolicy: UnlockPolicy = 'none';
|
|
176
180
|
|
|
177
181
|
/** Non-blocking Protocol V2 interaction synthesized by the SDK. */
|
|
178
182
|
protocolV2UiInteraction?: ProtocolV2InteractionDescriptor;
|
|
@@ -206,6 +210,7 @@ export abstract class BaseMethod<Params = undefined> {
|
|
|
206
210
|
this.useDevice = true;
|
|
207
211
|
this.allowDeviceMode = [UI_REQUEST.NOT_INITIALIZE];
|
|
208
212
|
this.requireDeviceMode = [];
|
|
213
|
+
this.unlockPolicy = getProtocolV2UnlockPolicy(this.name);
|
|
209
214
|
}
|
|
210
215
|
|
|
211
216
|
abstract init(): void;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getBootloaderReleaseInfo,
|
|
6
6
|
getFirmwareReleaseInfo,
|
|
7
7
|
} from './firmware/releaseHelper';
|
|
8
|
+
import { buildFirmwareUpdatePlan } from './firmware/FirmwareUpdatePlan';
|
|
8
9
|
import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
|
|
9
10
|
import { getDeviceFirmwareVersion, getDeviceType, getFirmwareType } from '../utils';
|
|
10
11
|
|
|
@@ -22,8 +23,11 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
22
23
|
|
|
23
24
|
async run() {
|
|
24
25
|
const { features } = this.device;
|
|
25
|
-
const {
|
|
26
|
-
|
|
26
|
+
const {
|
|
27
|
+
checkBridgeRelease,
|
|
28
|
+
firmwareType: firmwareTypeParams,
|
|
29
|
+
platform,
|
|
30
|
+
} = this.payload as CheckAllFirmwareReleaseParams;
|
|
27
31
|
|
|
28
32
|
if (!features) {
|
|
29
33
|
return Promise.resolve(null);
|
|
@@ -54,6 +58,21 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
54
58
|
firmwareType,
|
|
55
59
|
});
|
|
56
60
|
const bleFirmwareReleaseInfo = getBleFirmwareReleaseInfo(features);
|
|
61
|
+
let firmwareUpdatePlan;
|
|
62
|
+
try {
|
|
63
|
+
firmwareUpdatePlan = buildFirmwareUpdatePlan({
|
|
64
|
+
features,
|
|
65
|
+
firmwareType,
|
|
66
|
+
platform: platform ?? 'web',
|
|
67
|
+
firmware: firmwareRelease,
|
|
68
|
+
ble: bleFirmwareReleaseInfo,
|
|
69
|
+
bootloader: bootloaderRelease,
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
// A Plan is an optional external-host capability. Release checks remain
|
|
73
|
+
// available for legacy and recovery flows when a Plan cannot be built.
|
|
74
|
+
firmwareUpdatePlan = undefined;
|
|
75
|
+
}
|
|
57
76
|
|
|
58
77
|
return {
|
|
59
78
|
firmware: firmwareRelease,
|
|
@@ -68,6 +87,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
68
87
|
}
|
|
69
88
|
: undefined,
|
|
70
89
|
features,
|
|
71
|
-
|
|
90
|
+
firmwareUpdatePlan,
|
|
91
|
+
} as unknown as AllFirmwareRelease;
|
|
72
92
|
}
|
|
73
93
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { BaseMethod } from './BaseMethod';
|
|
2
|
+
import { invalidParameter } from './helpers/paramsValidator';
|
|
2
3
|
import { deviceWalletSessionStore } from '../device/DeviceWalletSessionStore';
|
|
3
4
|
|
|
4
5
|
import type { ClearSessionCacheParams } from '../types/api/sessionCache';
|
|
5
6
|
|
|
6
7
|
export default class ClearSessionCache extends BaseMethod<ClearSessionCacheParams> {
|
|
7
8
|
init() {
|
|
9
|
+
if (this.payload.passphraseState !== undefined && !this.payload.deviceId) {
|
|
10
|
+
throw invalidParameter('Parameter [deviceId] is required with [passphraseState].');
|
|
11
|
+
}
|
|
8
12
|
this.useDevice = false;
|
|
9
13
|
this.useDevicePassphraseState = false;
|
|
10
14
|
this.skipForceUpdateCheck = true;
|
|
@@ -182,7 +182,7 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
let binary;
|
|
185
|
+
let binary: ArrayBuffer | undefined;
|
|
186
186
|
try {
|
|
187
187
|
if (params.binary) {
|
|
188
188
|
binary = this.params.binary;
|
|
@@ -207,6 +207,13 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
|
|
|
207
207
|
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
if (!binary) {
|
|
211
|
+
throw ERRORS.TypedError(
|
|
212
|
+
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
213
|
+
'Firmware binary is unavailable'
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
210
217
|
await this.device.acquire();
|
|
211
218
|
|
|
212
219
|
const response = await uploadFirmware(
|
|
@@ -14,18 +14,43 @@ import { BaseMethod } from './BaseMethod';
|
|
|
14
14
|
import { validateParams } from './helpers/paramsValidator';
|
|
15
15
|
import { DevicePool } from '../device/DevicePool';
|
|
16
16
|
import { getBinary, getInfo, getSysResourceBinary } from './firmware/getBinary';
|
|
17
|
-
import {
|
|
18
|
-
|
|
17
|
+
import {
|
|
18
|
+
updateResources,
|
|
19
|
+
updateResourcesFromSources,
|
|
20
|
+
uploadFirmwareFromSource,
|
|
21
|
+
} from './firmware/uploadFirmware';
|
|
22
|
+
import { LoggerNames, getDeviceUUID, getLogger, wait } from '../utils';
|
|
19
23
|
import { FirmwareUpdateTipMessage, createUiMessage } from '../events/ui-request';
|
|
20
24
|
import { DeviceModelToTypes } from '../types';
|
|
21
25
|
import { DataManager } from '../data-manager';
|
|
22
26
|
import { DEVICE } from '../events';
|
|
27
|
+
import { type FirmwareByteSource, openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
28
|
+
import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
|
|
29
|
+
import {
|
|
30
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
31
|
+
assertFirmwareUpdatePreparedPlanBinding,
|
|
32
|
+
getFirmwareUpdateResourceName,
|
|
33
|
+
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
23
34
|
|
|
24
35
|
import type { Features, KnownDevice } from '../types';
|
|
25
36
|
import type { FirmwareBinary } from './firmware/getBinary';
|
|
37
|
+
import type {
|
|
38
|
+
FirmwareArtifactReader,
|
|
39
|
+
FirmwareArtifactReference,
|
|
40
|
+
} from '../types/api/firmwareUpdate';
|
|
41
|
+
import type { FirmwareUpdatePreparedPlan } from '../types/api/firmwareUpdatePreparedPlan';
|
|
26
42
|
|
|
27
43
|
type Params = {
|
|
28
44
|
binary?: ArrayBuffer;
|
|
45
|
+
artifact?: FirmwareArtifactReference;
|
|
46
|
+
resourceArtifact?: FirmwareArtifactReference;
|
|
47
|
+
resourceEntries?: Array<{
|
|
48
|
+
entryName: string;
|
|
49
|
+
artifact: FirmwareArtifactReference;
|
|
50
|
+
}>;
|
|
51
|
+
artifactReader?: FirmwareArtifactReader;
|
|
52
|
+
preparedPlan?: FirmwareUpdatePreparedPlan;
|
|
53
|
+
platform?: FirmwareUpdatePreparedPlan['platform'];
|
|
29
54
|
version?: number[];
|
|
30
55
|
updateType: 'firmware' | 'ble';
|
|
31
56
|
forcedUpdateRes?: boolean;
|
|
@@ -106,6 +131,13 @@ const normalizeFirmwareBinary = (binary: unknown): FirmwareBinary | undefined =>
|
|
|
106
131
|
return normalized.buffer;
|
|
107
132
|
};
|
|
108
133
|
|
|
134
|
+
const toArrayBuffer = (binary: FirmwareBinary): ArrayBuffer => {
|
|
135
|
+
if (binary instanceof ArrayBuffer) {
|
|
136
|
+
return binary;
|
|
137
|
+
}
|
|
138
|
+
return new Uint8Array(binary.buffer, binary.byteOffset, binary.byteLength).slice().buffer;
|
|
139
|
+
};
|
|
140
|
+
|
|
109
141
|
export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
110
142
|
checkPromise: Deferred<any> | null = null;
|
|
111
143
|
|
|
@@ -152,6 +184,38 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
152
184
|
binary: payload.binary,
|
|
153
185
|
};
|
|
154
186
|
}
|
|
187
|
+
|
|
188
|
+
if ('artifact' in payload) {
|
|
189
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration);
|
|
190
|
+
const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
|
|
191
|
+
const resourceBindings = [
|
|
192
|
+
...(payload.resourceArtifact
|
|
193
|
+
? [{ target: 'resource' as const, artifact: payload.resourceArtifact }]
|
|
194
|
+
: []),
|
|
195
|
+
...(payload.resourceEntries ?? []).map(
|
|
196
|
+
(entry: { entryName: string; artifact: FirmwareArtifactReference }) => ({
|
|
197
|
+
target: 'resource' as const,
|
|
198
|
+
entryName: entry.entryName,
|
|
199
|
+
artifact: entry.artifact,
|
|
200
|
+
})
|
|
201
|
+
),
|
|
202
|
+
];
|
|
203
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
204
|
+
preparedPlan: payload.preparedPlan,
|
|
205
|
+
executor: 'v2',
|
|
206
|
+
platform: payload.platform,
|
|
207
|
+
scopeTargets: [target, ...(target === 'firmware' ? (['resource'] as const) : [])],
|
|
208
|
+
bindings: [{ target, artifact: payload.artifact }, ...resourceBindings],
|
|
209
|
+
});
|
|
210
|
+
this.params = {
|
|
211
|
+
...this.params,
|
|
212
|
+
preparedPlan: payload.preparedPlan,
|
|
213
|
+
artifact: payload.artifact,
|
|
214
|
+
resourceArtifact: payload.resourceArtifact,
|
|
215
|
+
resourceEntries: payload.resourceEntries,
|
|
216
|
+
artifactReader: hostBinding.artifactReader,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
155
219
|
}
|
|
156
220
|
|
|
157
221
|
postTipMessage = (message: string) => {
|
|
@@ -348,152 +412,260 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
348
412
|
'Protocol V2 firmware update must use firmwareUpdateV4'
|
|
349
413
|
);
|
|
350
414
|
}
|
|
415
|
+
if (params.preparedPlan) {
|
|
416
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
417
|
+
preparedPlan: params.preparedPlan,
|
|
418
|
+
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
351
421
|
|
|
352
422
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
353
423
|
const firmwareType = params.firmwareType ?? deviceFirmwareType;
|
|
354
424
|
|
|
355
425
|
this.checkVersionForCopyTouchResource(features, firmwareType);
|
|
356
426
|
|
|
357
|
-
let
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (params.binary !== undefined) {
|
|
365
|
-
preparedBinary = normalizeFirmwareBinary(params.binary);
|
|
366
|
-
if (!preparedBinary) {
|
|
367
|
-
throw new Error('firmware binary is empty or invalid');
|
|
427
|
+
let preparedSource: FirmwareByteSource | undefined;
|
|
428
|
+
try {
|
|
429
|
+
const acquireFirmwareSource = async (): Promise<FirmwareByteSource> => {
|
|
430
|
+
try {
|
|
431
|
+
if (preparedSource) {
|
|
432
|
+
return preparedSource;
|
|
368
433
|
}
|
|
369
|
-
return preparedBinary;
|
|
370
|
-
}
|
|
371
434
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
requestOptions: FIRMWARE_DOWNLOAD_REQUEST_OPTIONS,
|
|
387
|
-
});
|
|
388
|
-
preparedBinary = normalizeFirmwareBinary(firmware.binary);
|
|
389
|
-
if (!preparedBinary) {
|
|
390
|
-
throw new Error('downloaded firmware binary is empty or invalid');
|
|
391
|
-
}
|
|
392
|
-
this.postTipMessage('DownloadFirmwareSuccess');
|
|
393
|
-
return preparedBinary;
|
|
394
|
-
} catch (err) {
|
|
395
|
-
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
|
|
396
|
-
}
|
|
397
|
-
};
|
|
435
|
+
if (params.binary !== undefined) {
|
|
436
|
+
const binary = normalizeFirmwareBinary(params.binary);
|
|
437
|
+
if (!binary) {
|
|
438
|
+
throw new Error('firmware binary is empty or invalid');
|
|
439
|
+
}
|
|
440
|
+
const source = await openFirmwareByteSource({
|
|
441
|
+
binary: toArrayBuffer(binary),
|
|
442
|
+
});
|
|
443
|
+
if (!source) {
|
|
444
|
+
throw new Error('firmware binary is empty or invalid');
|
|
445
|
+
}
|
|
446
|
+
preparedSource = source;
|
|
447
|
+
return source;
|
|
448
|
+
}
|
|
398
449
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
450
|
+
if (params.artifact) {
|
|
451
|
+
const source = await openFirmwareByteSource({
|
|
452
|
+
artifact: params.artifact,
|
|
453
|
+
reader: params.artifactReader,
|
|
454
|
+
});
|
|
455
|
+
if (!source) {
|
|
456
|
+
throw new Error('firmware artifact is not prepared');
|
|
457
|
+
}
|
|
458
|
+
preparedSource = source;
|
|
459
|
+
return source;
|
|
460
|
+
}
|
|
405
461
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
features,
|
|
411
|
-
forcedUpdateRes: params.forcedUpdateRes,
|
|
412
|
-
firmwareType,
|
|
413
|
-
});
|
|
414
|
-
if (resourceUrl) {
|
|
415
|
-
this.postTipMessage('DownloadLatestUiResource');
|
|
416
|
-
const resource = await getSysResourceBinary(resourceUrl);
|
|
417
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
418
|
-
if (resource) {
|
|
419
|
-
await updateResources(
|
|
420
|
-
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
421
|
-
this.postMessage,
|
|
422
|
-
device,
|
|
423
|
-
resource.binary
|
|
462
|
+
if (!device.features) {
|
|
463
|
+
throw ERRORS.TypedError(
|
|
464
|
+
HardwareErrorCode.RuntimeError,
|
|
465
|
+
'no features found for this device'
|
|
424
466
|
);
|
|
425
467
|
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
468
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
469
|
+
if (
|
|
470
|
+
params.artifactReader ||
|
|
471
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only'
|
|
472
|
+
) {
|
|
473
|
+
throw ERRORS.TypedError(
|
|
474
|
+
HardwareErrorCode.RuntimeError,
|
|
475
|
+
'Firmware must be prepared by the external firmware host',
|
|
476
|
+
{
|
|
477
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
478
|
+
artifactName: 'firmware',
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
}
|
|
434
482
|
|
|
435
|
-
|
|
436
|
-
|
|
483
|
+
this.postTipMessage('DownloadFirmware');
|
|
484
|
+
const firmware = await getBinary({
|
|
485
|
+
features: device.features,
|
|
486
|
+
version: params.version,
|
|
487
|
+
updateType: params.updateType,
|
|
488
|
+
isUpdateBootloader: params.isUpdateBootloader,
|
|
489
|
+
firmwareType,
|
|
490
|
+
requestOptions: FIRMWARE_DOWNLOAD_REQUEST_OPTIONS,
|
|
491
|
+
});
|
|
492
|
+
const binary = normalizeFirmwareBinary(firmware.binary);
|
|
493
|
+
if (!binary) {
|
|
494
|
+
throw new Error('downloaded firmware binary is empty or invalid');
|
|
495
|
+
}
|
|
496
|
+
const source = await openFirmwareByteSource({
|
|
497
|
+
binary: toArrayBuffer(binary),
|
|
498
|
+
});
|
|
499
|
+
if (!source) {
|
|
500
|
+
throw new Error('downloaded firmware binary is empty or invalid');
|
|
501
|
+
}
|
|
502
|
+
preparedSource = source;
|
|
503
|
+
this.postTipMessage('DownloadFirmwareSuccess');
|
|
504
|
+
return source;
|
|
505
|
+
} catch (err) {
|
|
506
|
+
throw ERRORS.TypedError(
|
|
507
|
+
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
508
|
+
err.message ?? err
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
437
512
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (bootRes.type === 'CallMethodError') {
|
|
444
|
-
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure);
|
|
513
|
+
if (!device.isBootloader() && features) {
|
|
514
|
+
const serialNo = device.getCurrentSerialNo();
|
|
515
|
+
// should go to bootloader mode manually
|
|
516
|
+
if (this.isEnteredManuallyBoot()) {
|
|
517
|
+
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateManuallyEnterBoot);
|
|
445
518
|
}
|
|
446
|
-
this.postTipMessage('GoToBootloaderSuccess');
|
|
447
|
-
this.checkDeviceToBootloader(this.payload.connectId);
|
|
448
519
|
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
520
|
+
// All network-backed input must be ready before the first device mutation.
|
|
521
|
+
await acquireFirmwareSource();
|
|
522
|
+
|
|
523
|
+
// check & upgrade firmware resource
|
|
524
|
+
if (this.isSupportResourceUpdate(params.updateType)) {
|
|
525
|
+
this.postTipMessage('CheckLatestUiResource');
|
|
526
|
+
const resourceUrl = DataManager.getSysResourcesLatestRelease({
|
|
527
|
+
features,
|
|
528
|
+
forcedUpdateRes: params.forcedUpdateRes,
|
|
529
|
+
firmwareType,
|
|
530
|
+
});
|
|
531
|
+
if (resourceUrl) {
|
|
532
|
+
this.postTipMessage('DownloadLatestUiResource');
|
|
533
|
+
if (params.resourceEntries?.length) {
|
|
534
|
+
const sources: Array<{
|
|
535
|
+
entryName: string;
|
|
536
|
+
source: FirmwareByteSource;
|
|
537
|
+
}> = [];
|
|
538
|
+
try {
|
|
539
|
+
for (const entry of params.resourceEntries) {
|
|
540
|
+
const resourceName = getFirmwareUpdateResourceName(entry.entryName);
|
|
541
|
+
const source = await openFirmwareByteSource({
|
|
542
|
+
artifact: entry.artifact,
|
|
543
|
+
reader: params.artifactReader,
|
|
544
|
+
});
|
|
545
|
+
if (!source) {
|
|
546
|
+
throw new Error('Firmware resource entry is not prepared');
|
|
547
|
+
}
|
|
548
|
+
sources.push({ entryName: resourceName, source });
|
|
549
|
+
}
|
|
550
|
+
await updateResourcesFromSources(
|
|
551
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
552
|
+
this.postMessage,
|
|
553
|
+
device,
|
|
554
|
+
sources.map(entry => ({
|
|
555
|
+
entryName: entry.entryName,
|
|
556
|
+
source: entry.source,
|
|
557
|
+
}))
|
|
558
|
+
);
|
|
559
|
+
} finally {
|
|
560
|
+
await Promise.all(
|
|
561
|
+
sources.map(entry => entry.source.close().catch(() => undefined))
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
565
|
+
} else {
|
|
566
|
+
let resourceBinary: ArrayBuffer | Buffer;
|
|
567
|
+
if (params.resourceArtifact) {
|
|
568
|
+
throw ERRORS.TypedError(
|
|
569
|
+
HardwareErrorCode.RuntimeError,
|
|
570
|
+
'Firmware resource archive must be materialized into prepared entries',
|
|
571
|
+
{
|
|
572
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
573
|
+
artifactName: 'resource',
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
} else {
|
|
577
|
+
if (
|
|
578
|
+
params.artifactReader ||
|
|
579
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only'
|
|
580
|
+
) {
|
|
581
|
+
throw ERRORS.TypedError(
|
|
582
|
+
HardwareErrorCode.RuntimeError,
|
|
583
|
+
'Firmware resource must be prepared by the external firmware host',
|
|
584
|
+
{
|
|
585
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
586
|
+
artifactName: 'resource',
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
resourceBinary = (await getSysResourceBinary(resourceUrl)).binary;
|
|
591
|
+
}
|
|
592
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
593
|
+
await updateResources(
|
|
594
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
595
|
+
this.postMessage,
|
|
596
|
+
device,
|
|
597
|
+
resourceBinary
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
452
601
|
}
|
|
453
|
-
delete DevicePool.devicesCache[''];
|
|
454
|
-
await this.checkPromise?.promise;
|
|
455
|
-
this.checkPromise = null;
|
|
456
602
|
|
|
457
|
-
//
|
|
603
|
+
// The request may outlive the current transport command instance.
|
|
458
604
|
this.device?.commands?.checkDisposed();
|
|
459
605
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
606
|
+
// auto go to bootloader mode
|
|
607
|
+
try {
|
|
608
|
+
this.postTipMessage('AutoRebootToBootloader');
|
|
609
|
+
const bootRes = await commands.typedCall('DeviceBackToBoot', 'Success');
|
|
610
|
+
// @ts-expect-error
|
|
611
|
+
if (bootRes.type === 'CallMethodError') {
|
|
612
|
+
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure);
|
|
613
|
+
}
|
|
614
|
+
this.postTipMessage('GoToBootloaderSuccess');
|
|
615
|
+
this.checkDeviceToBootloader(this.payload.connectId);
|
|
616
|
+
|
|
617
|
+
// force clean classic device cache so that the device can initialize again
|
|
618
|
+
if (DeviceModelToTypes.model_classic.includes(deviceType)) {
|
|
619
|
+
DevicePool.clearDeviceCache(serialNo);
|
|
620
|
+
}
|
|
621
|
+
delete DevicePool.devicesCache[''];
|
|
622
|
+
await this.checkPromise?.promise;
|
|
623
|
+
this.checkPromise = null;
|
|
624
|
+
|
|
625
|
+
// check if the device commands has been disposed
|
|
626
|
+
this.device?.commands?.checkDisposed();
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Touch 1 with bootloader v2.5.0 issue: BLE chip need more time for looking up name, here change the delay time to 3000ms after rebooting.
|
|
630
|
+
*/
|
|
631
|
+
const isTouch = DeviceModelToTypes.model_touch.includes(deviceType);
|
|
632
|
+
await wait(isTouch ? 3000 : 1500);
|
|
633
|
+
} catch (e) {
|
|
634
|
+
if (e instanceof HardwareError) {
|
|
635
|
+
return Promise.reject(e);
|
|
636
|
+
}
|
|
637
|
+
console.log('auto go to bootloader mode failed: ', e);
|
|
638
|
+
return Promise.reject(
|
|
639
|
+
ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure)
|
|
640
|
+
);
|
|
468
641
|
}
|
|
469
|
-
console.log('auto go to bootloader mode failed: ', e);
|
|
470
|
-
return Promise.reject(
|
|
471
|
-
ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure)
|
|
472
|
-
);
|
|
473
642
|
}
|
|
474
|
-
}
|
|
475
643
|
|
|
476
|
-
|
|
477
|
-
|
|
644
|
+
// Devices already in bootloader mode still acquire through the same helper.
|
|
645
|
+
const source = await acquireFirmwareSource();
|
|
478
646
|
|
|
479
|
-
|
|
480
|
-
|
|
647
|
+
// check if the device commands has been disposed
|
|
648
|
+
this.device?.commands?.checkDisposed();
|
|
481
649
|
|
|
482
|
-
|
|
650
|
+
await this.device.acquire();
|
|
483
651
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
652
|
+
const response = await uploadFirmwareFromSource(
|
|
653
|
+
params.updateType,
|
|
654
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
655
|
+
this.postMessage,
|
|
656
|
+
device,
|
|
657
|
+
source,
|
|
658
|
+
true,
|
|
659
|
+
params.isUpdateBootloader
|
|
660
|
+
);
|
|
492
661
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
662
|
+
if (this.connectId) {
|
|
663
|
+
DevicePool.clearDeviceCache(this.connectId);
|
|
664
|
+
}
|
|
496
665
|
|
|
497
|
-
|
|
666
|
+
return response;
|
|
667
|
+
} finally {
|
|
668
|
+
await preparedSource?.close().catch(() => undefined);
|
|
669
|
+
}
|
|
498
670
|
}
|
|
499
671
|
}
|