@onekeyfe/hd-core 1.2.0-alpha.40 → 1.2.0-alpha.41
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__/AllNetworkGetAddressBase.tracing.test.ts +0 -78
- package/__tests__/DeviceEventRegistration.test.ts +0 -6
- package/__tests__/connectSettings.test.ts +47 -5
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -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-preparation-error.test.ts +27 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -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 +59 -31
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +58 -0
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/get-device-state.test.ts +12 -132
- package/__tests__/homescreen.test.ts +1 -41
- package/__tests__/logBlockEvent.test.ts +1 -1
- package/__tests__/open-wallet-session.test.ts +18 -259
- package/__tests__/protocol-v2-unlock-policy.test.ts +35 -86
- package/__tests__/protocol-v2.test.ts +632 -333
- package/__tests__/public-pro2-api-boundary.test.ts +0 -1
- package/dist/api/BaseMethod.d.ts +1 -3
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.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 +22 -5
- 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/allnetwork/AllNetworkGetAddressBase.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/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/FirmwarePreparationError.d.ts +3 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +8 -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 +25 -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/progressThrottle.d.ts +3 -0
- package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
- 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 +0 -2
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +0 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/deviceEventRegistration.d.ts +0 -2
- package/dist/core/deviceEventRegistration.d.ts.map +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 +4 -22
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/events/device.d.ts +0 -4
- 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 +2 -27
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +181 -88
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3162 -1614
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
- package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +3 -3
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +3 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +10 -0
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +1 -4
- 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 +4 -0
- package/dist/types/api/checkAllFirmwareRelease.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 +28 -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/index.d.ts +10 -3
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +0 -3
- package/dist/types/api/protocolV2.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 +0 -2
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +0 -4
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Wallpaper.d.ts +0 -10
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +10 -8
- package/src/api/CheckAllFirmwareRelease.ts +51 -6
- package/src/api/FirmwareUpdateV2.ts +298 -120
- package/src/api/FirmwareUpdateV3.ts +263 -57
- package/src/api/FirmwareUpdateV4.ts +748 -281
- package/src/api/GetPassphraseState.ts +1 -7
- package/src/api/OpenWalletSession.ts +17 -54
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +11 -32
- package/src/api/device/DeviceUnlock.ts +1 -1
- package/src/api/device/DeviceUpdateBootloader.ts +122 -6
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwarePreparationError.ts +12 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +57 -0
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +745 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +392 -0
- package/src/api/firmware/progressThrottle.ts +44 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +140 -22
- package/src/api/helpers/protocolV2FileWrite.ts +4 -11
- package/src/api/index.ts +0 -1
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -3
- package/src/core/deviceEventRegistration.ts +0 -4
- package/src/core/index.ts +75 -118
- package/src/data/messages/messages-protocol-v2.json +0 -10
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +21 -193
- package/src/events/device.ts +0 -4
- package/src/events/logBlockEvent.ts +0 -1
- package/src/events/ui-request.ts +2 -32
- package/src/index.ts +5 -0
- package/src/inject.ts +22 -3
- package/src/lowLevelInject.ts +5 -1
- package/src/protocols/protocol-v2/features.ts +2 -9
- package/src/protocols/protocol-v2/lockedError.ts +10 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +5 -31
- package/src/protocols/protocol-v2/unlockPolicy.ts +105 -1
- package/src/protocols/protocol-v2/unlockRetry.ts +109 -0
- package/src/protocols/protocol-v2/walletSession.ts +18 -93
- package/src/topLevelInject.ts +5 -1
- package/src/types/api/checkAllFirmwareRelease.ts +4 -0
- 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 +38 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/index.ts +14 -2
- package/src/types/api/protocolV2.ts +0 -13
- package/src/types/settings.ts +13 -0
- package/src/utils/deviceFeaturesUtils.ts +0 -4
- package/src/utils/homescreen.ts +6 -32
- package/src/utils/index.ts +1 -6
- package/src/utils/pro2Wallpaper.ts +8 -35
- package/__tests__/deviceUploadNft.test.ts +0 -187
- package/__tests__/pro2Nft.test.ts +0 -108
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +0 -56
- package/__tests__/uiProgressThrottle.test.ts +0 -74
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +0 -30
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +0 -22
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +0 -1
- package/dist/utils/pro2Nft.d.ts +0 -29
- package/dist/utils/pro2Nft.d.ts.map +0 -1
- package/dist/utils/uiProgressThrottle.d.ts +0 -3
- package/dist/utils/uiProgressThrottle.d.ts.map +0 -1
- package/src/api/protocol-v2/DeviceUploadNft.ts +0 -166
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -117
- package/src/utils/pro2Nft.ts +0 -91
- package/src/utils/uiProgressThrottle.ts +0 -63
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
3
2
|
|
|
4
3
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
5
4
|
import { refreshProtocolV2DeviceStatus } from '../protocols/protocol-v2/walletSession';
|
|
@@ -25,12 +24,7 @@ export default class GetPassphraseState extends BaseMethod {
|
|
|
25
24
|
if (isProtocolV2 && this.payload.useEmptyPassphrase !== true) {
|
|
26
25
|
const features = await refreshProtocolV2DeviceStatus(this.device);
|
|
27
26
|
if (features.unlocked === false) {
|
|
28
|
-
await this.device.unlockDevice(
|
|
29
|
-
source: 'unlock-coordinator',
|
|
30
|
-
reason: 'device-locked',
|
|
31
|
-
deviceOnly: true,
|
|
32
|
-
method: 'getPassphraseState',
|
|
33
|
-
});
|
|
27
|
+
await this.device.unlockDevice();
|
|
34
28
|
}
|
|
35
29
|
}
|
|
36
30
|
const { passphraseState } = await getPassphraseStateWithRefreshDeviceInfo(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
3
2
|
|
|
4
3
|
import { deviceWalletSessionStore } from '../device/DeviceWalletSessionStore';
|
|
5
4
|
import { getProtocolV2WalletSession } from '../protocols/protocol-v2/walletSession';
|
|
@@ -91,40 +90,23 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
91
90
|
|
|
92
91
|
async run(): Promise<OpenWalletSessionPayload> {
|
|
93
92
|
const isProtocolV2 = this.device.isProtocolV2();
|
|
94
|
-
|
|
93
|
+
const state = await this.device.getDeviceState({ refreshSections: ['status'] });
|
|
95
94
|
let currentDeviceId = state.identity.deviceId;
|
|
96
|
-
const hasAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) =>
|
|
97
|
-
candidate.status.unlocked === true &&
|
|
98
|
-
typeof candidate.status.passphraseProtection === 'boolean' &&
|
|
99
|
-
typeof candidate.status.unlockedAttachPin === 'boolean';
|
|
100
|
-
const requireAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) => {
|
|
101
|
-
if (!hasAuthoritativeProtocolV2WalletStatus(candidate)) {
|
|
102
|
-
throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
|
|
103
|
-
}
|
|
104
|
-
return candidate;
|
|
105
|
-
};
|
|
106
95
|
const requireDeviceId = () => {
|
|
107
96
|
if (!currentDeviceId) {
|
|
108
97
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
|
|
109
98
|
}
|
|
110
99
|
return currentDeviceId;
|
|
111
100
|
};
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
currentDeviceId =
|
|
115
|
-
return
|
|
101
|
+
const refreshProtocolV2DeviceId = async () => {
|
|
102
|
+
const refreshedState = await this.device.getDeviceState({ refreshSections: ['status'] });
|
|
103
|
+
currentDeviceId = refreshedState.identity.deviceId;
|
|
104
|
+
return requireDeviceId();
|
|
116
105
|
};
|
|
117
|
-
const
|
|
118
|
-
if (isProtocolV2 &&
|
|
119
|
-
await this.device.unlockDevice(
|
|
120
|
-
source: 'unlock-coordinator',
|
|
121
|
-
reason: 'device-locked',
|
|
122
|
-
deviceOnly: true,
|
|
123
|
-
method: 'openWalletSession',
|
|
124
|
-
});
|
|
125
|
-
requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState());
|
|
106
|
+
const unlockProtocolV2IfLocked = async () => {
|
|
107
|
+
if (isProtocolV2 && state.status.unlocked === false) {
|
|
108
|
+
await this.device.unlockDevice();
|
|
126
109
|
}
|
|
127
|
-
return state;
|
|
128
110
|
};
|
|
129
111
|
|
|
130
112
|
const protocol = isProtocolV2 ? 'V2' : 'V1';
|
|
@@ -132,25 +114,13 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
132
114
|
if (this.params.mode === OpenWalletSessionMode.Standard) {
|
|
133
115
|
this.device.passphraseState = undefined;
|
|
134
116
|
const session = isProtocolV2
|
|
135
|
-
? await getProtocolV2WalletSession(this.device, {
|
|
136
|
-
onlyMainPin: true,
|
|
137
|
-
deriveCardano: this.payload.deriveCardano,
|
|
138
|
-
selectMainWalletBeforeRestore:
|
|
139
|
-
!hasAuthoritativeProtocolV2WalletStatus(state) ||
|
|
140
|
-
state.status.unlockedAttachPin === true,
|
|
141
|
-
})
|
|
117
|
+
? await getProtocolV2WalletSession(this.device, { onlyMainPin: true })
|
|
142
118
|
: await getPassphraseStateWithRefreshDeviceInfo(this.device, {
|
|
143
119
|
onlyMainPin: true,
|
|
144
120
|
initSession: this.payload.initSession,
|
|
145
121
|
});
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
: state;
|
|
149
|
-
const deviceId = requireDeviceId();
|
|
150
|
-
if (
|
|
151
|
-
session.unlockedAttachPin ||
|
|
152
|
-
(isProtocolV2 && refreshedState.status.unlockedAttachPin === true)
|
|
153
|
-
) {
|
|
122
|
+
const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
|
|
123
|
+
if (session.unlockedAttachPin) {
|
|
154
124
|
try {
|
|
155
125
|
await this.device.lockDevice();
|
|
156
126
|
} catch {
|
|
@@ -170,8 +140,8 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
170
140
|
|
|
171
141
|
if (this.params.mode === OpenWalletSessionMode.ResumeHidden) {
|
|
172
142
|
if (isProtocolV2) {
|
|
173
|
-
await
|
|
174
|
-
const refreshedDeviceId =
|
|
143
|
+
await unlockProtocolV2IfLocked();
|
|
144
|
+
const refreshedDeviceId = await refreshProtocolV2DeviceId();
|
|
175
145
|
if (refreshedDeviceId !== this.params.deviceId) {
|
|
176
146
|
deviceWalletSessionStore.delete(this.params.deviceId, this.params.passphraseState);
|
|
177
147
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
@@ -196,7 +166,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
196
166
|
const session = isProtocolV2
|
|
197
167
|
? await getProtocolV2WalletSession(this.device, {
|
|
198
168
|
expectedPassphraseState: this.params.passphraseState,
|
|
199
|
-
deriveCardano: this.payload.deriveCardano,
|
|
200
169
|
})
|
|
201
170
|
: await getPassphraseStateWithRefreshDeviceInfo(this.device, {
|
|
202
171
|
expectPassphraseState: this.params.passphraseState,
|
|
@@ -216,18 +185,12 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
216
185
|
}
|
|
217
186
|
|
|
218
187
|
this.device.passphraseState = undefined;
|
|
219
|
-
await
|
|
188
|
+
await unlockProtocolV2IfLocked();
|
|
220
189
|
const session = isProtocolV2
|
|
221
|
-
? await getProtocolV2WalletSession(this.device, {
|
|
222
|
-
forceWalletSelection: true,
|
|
223
|
-
deriveCardano: this.payload.deriveCardano,
|
|
224
|
-
})
|
|
190
|
+
? await getProtocolV2WalletSession(this.device, { forceWalletSelection: true })
|
|
225
191
|
: await getPassphraseStateWithRefreshDeviceInfo(this.device, { initSession: true });
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
: state;
|
|
229
|
-
const deviceId = requireDeviceId();
|
|
230
|
-
if (isProtocolV2 && refreshedState.status.passphraseProtection !== true) {
|
|
192
|
+
const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
|
|
193
|
+
if (isProtocolV2 && this.device.getCurrentPassphraseProtection() !== true) {
|
|
231
194
|
this.device.clearInternalState();
|
|
232
195
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase);
|
|
233
196
|
}
|
|
@@ -14,7 +14,6 @@ import { findMethod } from '../utils';
|
|
|
14
14
|
import { DEVICE, IFRAME, createUiMessage } from '../../events';
|
|
15
15
|
import { UI_REQUEST } from '../../constants/ui-request';
|
|
16
16
|
import { onDeviceButtonHandler } from '../../core';
|
|
17
|
-
import { runMethodWithUnlockPolicy } from '../../protocols/protocol-v2/unlockPolicyRunner';
|
|
18
17
|
import {
|
|
19
18
|
completeRequestContext,
|
|
20
19
|
createRequestContext,
|
|
@@ -376,34 +375,16 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
|
|
|
376
375
|
this.device.on(DEVICE.PASSPHRASE, onSignalAbort);
|
|
377
376
|
|
|
378
377
|
preCheckDeviceSupport(this.device, method);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Protocol V2 hands a wallet session to exactly one blockchain request.
|
|
392
|
-
// The parent all-network call consumes its first handoff while fetching
|
|
393
|
-
// the root fingerprint, so each nested chain method must resume the
|
|
394
|
-
// requested hidden wallet before it sends its own device command.
|
|
395
|
-
if (this.device.isProtocolV2() && this.payload.passphraseState) {
|
|
396
|
-
const passphraseStateSafety = await this.device.checkPassphraseStateSafety(
|
|
397
|
-
this.payload.passphraseState,
|
|
398
|
-
false,
|
|
399
|
-
this.payload.skipPassphraseCheck
|
|
400
|
-
);
|
|
401
|
-
if (!passphraseStateSafety) {
|
|
402
|
-
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
},
|
|
406
|
-
});
|
|
378
|
+
if (this.temporarySafetyCheckPrompted) {
|
|
379
|
+
method.temporarySafetyCheckPrompted = true;
|
|
380
|
+
} else {
|
|
381
|
+
const appliedTemporarySafetyCheck = await method.checkSafetyLevelOnTestNet();
|
|
382
|
+
if (appliedTemporarySafetyCheck) {
|
|
383
|
+
this.temporarySafetyCheckPrompted = true;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const response = await method.run();
|
|
407
388
|
|
|
408
389
|
if (!Array.isArray(response) || response.length === 0) {
|
|
409
390
|
throw new Error('No response');
|
|
@@ -458,9 +439,7 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
|
|
|
458
439
|
show_display: false,
|
|
459
440
|
});
|
|
460
441
|
|
|
461
|
-
|
|
462
|
-
this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
|
|
463
|
-
}
|
|
442
|
+
this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
|
|
464
443
|
|
|
465
444
|
if (res.message.root_fingerprint == null) {
|
|
466
445
|
throw ERRORS.TypedError(HardwareErrorCode.CallMethodInvalidParameter);
|
|
@@ -5,15 +5,23 @@ import { UI_REQUEST } from '../../constants/ui-request';
|
|
|
5
5
|
import { FirmwareUpdateTipMessage } from '../../events/ui-request';
|
|
6
6
|
import { FirmwareUpdateBaseMethod } from '../firmware/FirmwareUpdateBaseMethod';
|
|
7
7
|
import { getSysResourceBinary } from '../firmware/getBinary';
|
|
8
|
-
import { updateBootloader } from '../firmware/uploadFirmware';
|
|
8
|
+
import { updateBootloader, updateBootloaderFromSource } from '../firmware/uploadFirmware';
|
|
9
9
|
import { DeviceModelToTypes } from '../../types';
|
|
10
10
|
import { DataManager } from '../../data-manager';
|
|
11
|
-
import { checkBootloaderLength } from '../firmware/updateBootloader';
|
|
11
|
+
import { checkBootloaderLength, checkBootloaderSourceLength } from '../firmware/updateBootloader';
|
|
12
|
+
import { openFirmwareByteSource } from '../firmware/FirmwareArtifactSource';
|
|
13
|
+
import { resolveFirmwareUpdateHostBinding } from '../firmware/FirmwareHostBinding';
|
|
14
|
+
import {
|
|
15
|
+
assertFirmwareUpdatePreparedPlanBinding,
|
|
16
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
17
|
+
} from '../firmware/FirmwareUpdatePreparedPlan';
|
|
18
|
+
import { getDeviceUUID } from '../../utils';
|
|
12
19
|
|
|
13
20
|
import type { DeviceUpdateBootloaderParams } from '../../types/api/deviceUpdateBootloader';
|
|
14
21
|
import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
15
22
|
import type { Device } from '../../device/Device';
|
|
16
23
|
import type { Features } from '../../types';
|
|
24
|
+
import type { FirmwareByteSource } from '../firmware/FirmwareArtifactSource';
|
|
17
25
|
|
|
18
26
|
export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any> {
|
|
19
27
|
init() {
|
|
@@ -43,17 +51,68 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
|
|
|
43
51
|
return true;
|
|
44
52
|
}
|
|
45
53
|
|
|
54
|
+
async updateBootloaderWithEmmcFileWriteFromSource(_device: Device, source: FirmwareByteSource) {
|
|
55
|
+
const filePath = '0:boot/bootloader.bin';
|
|
56
|
+
|
|
57
|
+
this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
|
|
58
|
+
await this.emmcCommonUpdateProcessFromSource({
|
|
59
|
+
source,
|
|
60
|
+
filePath,
|
|
61
|
+
});
|
|
62
|
+
this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
|
|
63
|
+
await this.reboot(RebootType.Normal);
|
|
64
|
+
this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloaderSuccess);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
46
68
|
async updateTouchBootloader({
|
|
47
69
|
device,
|
|
48
70
|
features,
|
|
49
71
|
firmwareType,
|
|
72
|
+
binary: preparedBinary,
|
|
73
|
+
source: preparedSource,
|
|
50
74
|
}: {
|
|
51
75
|
device: Device;
|
|
52
76
|
features?: Features;
|
|
53
77
|
firmwareType: EFirmwareType;
|
|
78
|
+
binary?: ArrayBuffer;
|
|
79
|
+
source?: FirmwareByteSource;
|
|
54
80
|
}) {
|
|
55
|
-
|
|
81
|
+
if (preparedSource) {
|
|
82
|
+
if (!(await checkBootloaderSourceLength(preparedSource))) {
|
|
83
|
+
throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
|
|
84
|
+
}
|
|
85
|
+
if (features && device.isBootloader()) {
|
|
86
|
+
this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
|
|
87
|
+
const result = await this.updateBootloaderWithEmmcFileWriteFromSource(
|
|
88
|
+
device,
|
|
89
|
+
preparedSource
|
|
90
|
+
);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
if (features && !device.isBootloader()) {
|
|
94
|
+
await updateBootloaderFromSource(
|
|
95
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
96
|
+
this.postMessage,
|
|
97
|
+
device,
|
|
98
|
+
preparedSource
|
|
99
|
+
);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let binary = preparedBinary;
|
|
56
105
|
if (!binary) {
|
|
106
|
+
if (DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
107
|
+
throw ERRORS.TypedError(
|
|
108
|
+
HardwareErrorCode.RuntimeError,
|
|
109
|
+
'Bootloader must be prepared by the external firmware host',
|
|
110
|
+
{
|
|
111
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
112
|
+
artifactName: 'bootloader',
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
57
116
|
this.postTipMessage(FirmwareUpdateTipMessage.CheckLatestUiResource);
|
|
58
117
|
const resourceUrl = features
|
|
59
118
|
? DataManager.getBootloaderResource(features, firmwareType)
|
|
@@ -68,7 +127,7 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
|
|
|
68
127
|
}
|
|
69
128
|
}
|
|
70
129
|
|
|
71
|
-
if (!checkBootloaderLength(binary)) {
|
|
130
|
+
if (!binary || !checkBootloaderLength(binary)) {
|
|
72
131
|
throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
|
|
73
132
|
}
|
|
74
133
|
|
|
@@ -76,7 +135,8 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
|
|
|
76
135
|
if (features && device.isBootloader()) {
|
|
77
136
|
// Use emmcFileWrite + reboot logic for bootloader mode
|
|
78
137
|
this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
|
|
79
|
-
|
|
138
|
+
const result = await this.updateBootloaderWithEmmcFileWrite(device, binary);
|
|
139
|
+
return result;
|
|
80
140
|
}
|
|
81
141
|
|
|
82
142
|
if (features && !device.isBootloader()) {
|
|
@@ -96,13 +156,69 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
|
|
|
96
156
|
const { features } = device;
|
|
97
157
|
|
|
98
158
|
const payload = this.payload as DeviceUpdateBootloaderParams;
|
|
159
|
+
const hostBinding = payload.artifact
|
|
160
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
|
|
161
|
+
: undefined;
|
|
162
|
+
const executionParams = {
|
|
163
|
+
...payload,
|
|
164
|
+
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
165
|
+
};
|
|
166
|
+
if (payload.artifact) {
|
|
167
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
168
|
+
preparedPlan: payload.preparedPlan,
|
|
169
|
+
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
170
|
+
});
|
|
171
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
172
|
+
preparedPlan: payload.preparedPlan,
|
|
173
|
+
executor: 'v2',
|
|
174
|
+
scopeTargets: ['bootloader'],
|
|
175
|
+
bindings: [
|
|
176
|
+
{
|
|
177
|
+
target: 'bootloader',
|
|
178
|
+
artifact: payload.artifact,
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
const source = await openFirmwareByteSource({
|
|
183
|
+
artifact: payload.artifact,
|
|
184
|
+
reader: executionParams.artifactReader,
|
|
185
|
+
});
|
|
186
|
+
if (!source) {
|
|
187
|
+
throw ERRORS.TypedError(
|
|
188
|
+
HardwareErrorCode.RuntimeError,
|
|
189
|
+
'Bootloader artifact is not prepared'
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const deviceType = device.getCurrentDeviceType();
|
|
194
|
+
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
195
|
+
const firmwareType = payload.firmwareType ?? deviceFirmwareType;
|
|
196
|
+
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
197
|
+
return await this.updateTouchBootloader({
|
|
198
|
+
device,
|
|
199
|
+
features,
|
|
200
|
+
firmwareType,
|
|
201
|
+
source,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
} finally {
|
|
206
|
+
await source.close();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
99
209
|
|
|
210
|
+
const { binary } = payload;
|
|
100
211
|
const deviceType = device.getCurrentDeviceType();
|
|
101
212
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
102
213
|
const firmwareType = payload.firmwareType ?? deviceFirmwareType;
|
|
103
214
|
|
|
104
215
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
105
|
-
return this.updateTouchBootloader({
|
|
216
|
+
return this.updateTouchBootloader({
|
|
217
|
+
device,
|
|
218
|
+
features,
|
|
219
|
+
firmwareType,
|
|
220
|
+
binary,
|
|
221
|
+
});
|
|
106
222
|
}
|
|
107
223
|
|
|
108
224
|
return Promise.resolve(true);
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
FirmwareArtifactReader,
|
|
5
|
+
FirmwareArtifactReference,
|
|
6
|
+
} from '../../types/api/firmwareUpdate';
|
|
7
|
+
|
|
8
|
+
export const MAX_FIRMWARE_ARTIFACT_READ_BYTES = 256 * 1024;
|
|
9
|
+
|
|
10
|
+
export interface FirmwareByteSource {
|
|
11
|
+
readonly size: number;
|
|
12
|
+
readAt(offset: number, length: number): Promise<ArrayBuffer>;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const artifactError = (
|
|
17
|
+
code:
|
|
18
|
+
| 'FirmwareArtifactReceiptMismatch'
|
|
19
|
+
| 'FirmwareArtifactReaderInvalid'
|
|
20
|
+
| 'FirmwareArtifactReadOutOfBounds'
|
|
21
|
+
| 'FirmwareArtifactReadTooLarge',
|
|
22
|
+
message: string
|
|
23
|
+
): never => {
|
|
24
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, message, {
|
|
25
|
+
firmwareUpdateCode: code,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const assertSafeSize = (value: number, name: string) => {
|
|
30
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
31
|
+
artifactError('FirmwareArtifactReceiptMismatch', `${name} must be a positive safe integer`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const assertFirmwareArtifactReference = (
|
|
36
|
+
artifact: FirmwareArtifactReference
|
|
37
|
+
): FirmwareArtifactReference => {
|
|
38
|
+
if (
|
|
39
|
+
!artifact ||
|
|
40
|
+
typeof artifact.artifactRef !== 'string' ||
|
|
41
|
+
artifact.artifactRef.length === 0 ||
|
|
42
|
+
artifact.artifactRef.length > 160 ||
|
|
43
|
+
artifact.artifactRef.includes('/') ||
|
|
44
|
+
artifact.artifactRef.includes('\\')
|
|
45
|
+
) {
|
|
46
|
+
artifactError(
|
|
47
|
+
'FirmwareArtifactReceiptMismatch',
|
|
48
|
+
'Firmware artifactRef must be an opaque identifier'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
assertSafeSize(artifact.size, 'Firmware artifact size');
|
|
52
|
+
if (typeof artifact.sha256 !== 'string' || !/^[a-f0-9]{64}$/i.test(artifact.sha256)) {
|
|
53
|
+
artifactError(
|
|
54
|
+
'FirmwareArtifactReceiptMismatch',
|
|
55
|
+
'Firmware artifact sha256 must be a 32-byte hexadecimal digest'
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return artifact;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const assertFirmwareArtifactRead = (size: number, offset: number, length: number) => {
|
|
62
|
+
if (
|
|
63
|
+
!Number.isSafeInteger(offset) ||
|
|
64
|
+
offset < 0 ||
|
|
65
|
+
offset >= size ||
|
|
66
|
+
!Number.isSafeInteger(length) ||
|
|
67
|
+
length <= 0 ||
|
|
68
|
+
offset + length > size
|
|
69
|
+
) {
|
|
70
|
+
artifactError(
|
|
71
|
+
'FirmwareArtifactReadOutOfBounds',
|
|
72
|
+
`Firmware artifact read is outside size ${size}: offset=${offset}, length=${length}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (length > MAX_FIRMWARE_ARTIFACT_READ_BYTES) {
|
|
76
|
+
artifactError(
|
|
77
|
+
'FirmwareArtifactReadTooLarge',
|
|
78
|
+
`Firmware artifact read length ${length} exceeds ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const createMemoryFirmwareByteSource = (binary: ArrayBuffer): FirmwareByteSource => {
|
|
84
|
+
let bytes: Uint8Array | null = new Uint8Array(binary);
|
|
85
|
+
const { byteLength: size } = binary;
|
|
86
|
+
assertSafeSize(size, 'Firmware binary size');
|
|
87
|
+
return {
|
|
88
|
+
size,
|
|
89
|
+
readAt: (offset, length) => {
|
|
90
|
+
if (!bytes) {
|
|
91
|
+
return Promise.reject(
|
|
92
|
+
ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Firmware byte source is closed', {
|
|
93
|
+
firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
assertFirmwareArtifactRead(size, offset, length);
|
|
98
|
+
return Promise.resolve(bytes.slice(offset, offset + length).buffer);
|
|
99
|
+
},
|
|
100
|
+
close: () => {
|
|
101
|
+
bytes = null;
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
class ReaderFirmwareByteSource implements FirmwareByteSource {
|
|
108
|
+
readonly size: number;
|
|
109
|
+
|
|
110
|
+
private closed = false;
|
|
111
|
+
|
|
112
|
+
private reading = false;
|
|
113
|
+
|
|
114
|
+
private constructor(
|
|
115
|
+
private readonly reader: FirmwareArtifactReader,
|
|
116
|
+
private readonly readerId: string,
|
|
117
|
+
size: number
|
|
118
|
+
) {
|
|
119
|
+
this.size = size;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static async open(
|
|
123
|
+
artifact: FirmwareArtifactReference,
|
|
124
|
+
reader: FirmwareArtifactReader
|
|
125
|
+
): Promise<ReaderFirmwareByteSource> {
|
|
126
|
+
const opened = await reader.open({ artifactRef: artifact.artifactRef });
|
|
127
|
+
if (
|
|
128
|
+
!opened ||
|
|
129
|
+
typeof opened.readerId !== 'string' ||
|
|
130
|
+
opened.readerId.length === 0 ||
|
|
131
|
+
!Number.isSafeInteger(opened.size) ||
|
|
132
|
+
opened.size !== artifact.size
|
|
133
|
+
) {
|
|
134
|
+
if (opened?.readerId) {
|
|
135
|
+
await reader.close({ readerId: opened.readerId }).catch(() => undefined);
|
|
136
|
+
}
|
|
137
|
+
return artifactError(
|
|
138
|
+
'FirmwareArtifactReceiptMismatch',
|
|
139
|
+
`Firmware artifact opened with size ${opened?.size ?? 'unknown'}, expected ${artifact.size}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
return new ReaderFirmwareByteSource(reader, opened.readerId, opened.size);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async readAt(offset: number, length: number): Promise<ArrayBuffer> {
|
|
146
|
+
if (this.closed) {
|
|
147
|
+
return artifactError('FirmwareArtifactReaderInvalid', 'Firmware artifact reader is closed');
|
|
148
|
+
}
|
|
149
|
+
if (this.reading) {
|
|
150
|
+
return artifactError(
|
|
151
|
+
'FirmwareArtifactReaderInvalid',
|
|
152
|
+
'Firmware artifact reader only permits one in-flight read'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
assertFirmwareArtifactRead(this.size, offset, length);
|
|
156
|
+
this.reading = true;
|
|
157
|
+
try {
|
|
158
|
+
const result = await this.reader.read({
|
|
159
|
+
readerId: this.readerId,
|
|
160
|
+
offset,
|
|
161
|
+
length,
|
|
162
|
+
});
|
|
163
|
+
const expectedEof = offset + length === this.size;
|
|
164
|
+
if (
|
|
165
|
+
!result ||
|
|
166
|
+
!(result.data instanceof ArrayBuffer) ||
|
|
167
|
+
result.data.byteLength !== length ||
|
|
168
|
+
result.bytesRead !== length ||
|
|
169
|
+
result.eof !== expectedEof
|
|
170
|
+
) {
|
|
171
|
+
return artifactError(
|
|
172
|
+
'FirmwareArtifactReaderInvalid',
|
|
173
|
+
'Firmware artifact reader returned an invalid read result'
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return result.data;
|
|
177
|
+
} finally {
|
|
178
|
+
this.reading = false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async close(): Promise<void> {
|
|
183
|
+
if (this.closed) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
this.closed = true;
|
|
187
|
+
await this.reader.close({ readerId: this.readerId });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const openFirmwareByteSource = async ({
|
|
192
|
+
binary,
|
|
193
|
+
artifact,
|
|
194
|
+
reader,
|
|
195
|
+
}: {
|
|
196
|
+
binary?: ArrayBuffer;
|
|
197
|
+
artifact?: FirmwareArtifactReference;
|
|
198
|
+
reader?: FirmwareArtifactReader;
|
|
199
|
+
}): Promise<FirmwareByteSource | null> => {
|
|
200
|
+
if (binary && artifact) {
|
|
201
|
+
return artifactError(
|
|
202
|
+
'FirmwareArtifactReceiptMismatch',
|
|
203
|
+
'Firmware input must not contain both binary and artifactRef'
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (binary) {
|
|
207
|
+
return createMemoryFirmwareByteSource(binary);
|
|
208
|
+
}
|
|
209
|
+
if (!artifact) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
assertFirmwareArtifactReference(artifact);
|
|
213
|
+
if (!reader) {
|
|
214
|
+
return artifactError(
|
|
215
|
+
'FirmwareArtifactReaderInvalid',
|
|
216
|
+
'Firmware artifact reader is required for artifactRef input'
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
return ReaderFirmwareByteSource.open(artifact, reader);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export const readFirmwareByteSourceFully = async (
|
|
223
|
+
source: FirmwareByteSource
|
|
224
|
+
): Promise<ArrayBuffer> => {
|
|
225
|
+
const output = new Uint8Array(source.size);
|
|
226
|
+
let offset = 0;
|
|
227
|
+
while (offset < source.size) {
|
|
228
|
+
const length = Math.min(MAX_FIRMWARE_ARTIFACT_READ_BYTES, source.size - offset);
|
|
229
|
+
output.set(new Uint8Array(await source.readAt(offset, length)), offset);
|
|
230
|
+
offset += length;
|
|
231
|
+
}
|
|
232
|
+
return output.buffer;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const writeFirmwareByteSource = async ({
|
|
236
|
+
source,
|
|
237
|
+
chunkSize,
|
|
238
|
+
write,
|
|
239
|
+
}: {
|
|
240
|
+
source: FirmwareByteSource;
|
|
241
|
+
chunkSize: number;
|
|
242
|
+
write: (input: {
|
|
243
|
+
data: ArrayBuffer;
|
|
244
|
+
sourceOffset: number;
|
|
245
|
+
length: number;
|
|
246
|
+
first: boolean;
|
|
247
|
+
}) => Promise<number>;
|
|
248
|
+
}) => {
|
|
249
|
+
if (
|
|
250
|
+
!Number.isSafeInteger(chunkSize) ||
|
|
251
|
+
chunkSize <= 0 ||
|
|
252
|
+
chunkSize > MAX_FIRMWARE_ARTIFACT_READ_BYTES
|
|
253
|
+
) {
|
|
254
|
+
return artifactError(
|
|
255
|
+
'FirmwareArtifactReadTooLarge',
|
|
256
|
+
`Firmware artifact chunk size must be between 1 and ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
let offset = 0;
|
|
260
|
+
while (offset < source.size) {
|
|
261
|
+
const length = Math.min(chunkSize, source.size - offset);
|
|
262
|
+
const data = await source.readAt(offset, length);
|
|
263
|
+
const processed = await write({
|
|
264
|
+
data,
|
|
265
|
+
sourceOffset: offset,
|
|
266
|
+
length,
|
|
267
|
+
first: offset === 0,
|
|
268
|
+
});
|
|
269
|
+
if (processed !== length) {
|
|
270
|
+
return artifactError(
|
|
271
|
+
'FirmwareArtifactReaderInvalid',
|
|
272
|
+
`Firmware artifact writer processed ${processed} bytes, expected ${length}`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
offset += length;
|
|
276
|
+
}
|
|
277
|
+
return offset;
|
|
278
|
+
};
|