@onekeyfe/hd-core 1.2.2-alpha.100 → 1.2.2-alpha.102
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 +20 -4
- package/__tests__/DeviceCommands.test.ts +13 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +0 -2
- package/__tests__/check-firmware-release-protocol-v2.test.ts +0 -2
- package/__tests__/device-lifecycle-events.test.ts +102 -0
- package/__tests__/deviceUploadNft.test.ts +68 -0
- package/__tests__/evmSignTypedData.test.ts +42 -0
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +825 -12
- package/__tests__/logBlockEvent.test.ts +45 -122
- package/__tests__/open-wallet-session.test.ts +781 -69
- package/__tests__/pro2HostAssetPackage.test.ts +165 -0
- package/__tests__/protocol-v2-resources.test.ts +7 -4
- package/__tests__/protocol-v2-unlock-policy.test.ts +35 -1
- package/__tests__/protocol-v2.test.ts +937 -74
- package/__tests__/protocolV2FileWrite.test.ts +40 -0
- package/__tests__/sol-sign-offchain-message.test.ts +64 -0
- package/dist/api/FirmwareUpdateV4.d.ts +5 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +1 -0
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +2 -2
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +2 -2
- package/dist/api/helpers/protocolV2FileWrite.d.ts +1 -0
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts +2 -0
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +4 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +1 -1
- package/dist/device/Device.d.ts +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DeviceConnector.d.ts +1 -1
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +3 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +38 -16
- package/dist/index.js +2569 -1555
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +2 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +3 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -4
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/api/solSignOffchainMessage.d.ts +1 -0
- package/dist/types/api/solSignOffchainMessage.d.ts.map +1 -1
- package/dist/types/settings.d.ts +2 -2
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +3 -0
- package/dist/utils/deviceFeaturesUtils.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/pro2HostAssetPackage.d.ts +8 -0
- package/dist/utils/pro2HostAssetPackage.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +474 -83
- package/src/api/OpenWalletSession.ts +39 -12
- package/src/api/UploadPortfolio.ts +5 -4
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +5 -2
- package/src/api/evm/EVMSignTypedData.ts +1 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +9 -3
- package/src/api/helpers/protocolV2FileWrite.ts +11 -5
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +7 -1
- package/src/api/protocol-v2/DeviceUploadNft.ts +31 -8
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +33 -8
- package/src/api/protocol-v2/helpers.ts +8 -0
- package/src/api/solana/SolSignOffchainMessage.ts +44 -4
- package/src/core/RequestQueue.ts +16 -1
- package/src/core/index.ts +179 -27
- package/src/data/messages/messages-protocol-v2.json +1591 -1382
- package/src/data/messages/messages.json +8 -5
- package/src/device/Device.ts +3 -1
- package/src/device/DeviceConnector.ts +7 -3
- package/src/events/logBlockEvent.ts +6 -75
- package/src/events/ui-request.ts +3 -0
- package/src/protocols/protocol-v2/resources.ts +9 -1
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +8 -1
- package/src/protocols/protocol-v2/walletSession.ts +223 -56
- package/src/types/api/protocolV2.ts +3 -4
- package/src/types/api/solSignOffchainMessage.ts +2 -0
- package/src/types/settings.ts +4 -2
- package/src/utils/deviceFeaturesUtils.ts +4 -0
- package/src/utils/pro2HostAssetPackage.ts +400 -0
|
@@ -63,35 +63,50 @@ const negotiateEventlessWalletSession = async (device: Device) => {
|
|
|
63
63
|
const getDeviceSession = async (device: Device, request: DeviceSessionGet) =>
|
|
64
64
|
device.commands.typedCall('DeviceSessionGet', 'DeviceSession', request);
|
|
65
65
|
|
|
66
|
+
const STANDARD_SEED_DOMAINS = [DeviceSessionSeedDomain.SeedDomain_Standard];
|
|
67
|
+
const CARDANO_SEED_DOMAINS = [
|
|
68
|
+
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
69
|
+
DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const buildDeviceSessionSeedDomains = (deriveCardano?: boolean): DeviceSessionSeedDomain[] =>
|
|
73
|
+
deriveCardano === true ? CARDANO_SEED_DOMAINS : STANDARD_SEED_DOMAINS;
|
|
74
|
+
|
|
75
|
+
const deviceSessionHasCardano = (message: { seed_domains?: DeviceSessionSeedDomain[] }) =>
|
|
76
|
+
Array.isArray(message.seed_domains) &&
|
|
77
|
+
message.seed_domains.includes(DeviceSessionSeedDomain.SeedDomain_Cardano);
|
|
78
|
+
|
|
79
|
+
// origin/dev Get is read/resume only. Seed generation lives on AskPassphrase.
|
|
66
80
|
const buildDeviceSessionGetRequest = ({
|
|
67
81
|
sessionId,
|
|
68
82
|
expectedPassphraseState,
|
|
69
|
-
deriveCardano,
|
|
70
83
|
}: {
|
|
71
84
|
sessionId?: string;
|
|
72
85
|
expectedPassphraseState?: string;
|
|
73
|
-
deriveCardano?: boolean;
|
|
74
86
|
} = {}): DeviceSessionGet => ({
|
|
75
87
|
...(sessionId ? { session_id: sessionId } : {}),
|
|
76
88
|
...(expectedPassphraseState ? { btc_test_address: expectedPassphraseState } : {}),
|
|
77
|
-
seed_domains:
|
|
78
|
-
deriveCardano === undefined
|
|
79
|
-
? []
|
|
80
|
-
: [
|
|
81
|
-
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
82
|
-
...(deriveCardano ? [DeviceSessionSeedDomain.SeedDomain_Cardano] : []),
|
|
83
|
-
],
|
|
84
89
|
});
|
|
85
90
|
|
|
86
|
-
const askDevicePassphrase = async (
|
|
87
|
-
|
|
91
|
+
const askDevicePassphrase = async (
|
|
92
|
+
device: Device,
|
|
93
|
+
requestPayload: Omit<DeviceSessionAskPassphrase, 'seed_domains'>,
|
|
94
|
+
deriveCardano?: boolean,
|
|
95
|
+
onStatusRefreshed?: () => void
|
|
96
|
+
) => {
|
|
97
|
+
await device.commands.typedCall('DeviceSessionAskPassphrase', 'Success', {
|
|
98
|
+
...requestPayload,
|
|
99
|
+
seed_domains: buildDeviceSessionSeedDomains(deriveCardano),
|
|
100
|
+
});
|
|
88
101
|
await refreshProtocolV2DeviceStatus(device);
|
|
102
|
+
onStatusRefreshed?.();
|
|
89
103
|
};
|
|
90
104
|
|
|
91
105
|
const selectDeviceSession = async (
|
|
92
106
|
device: Device,
|
|
93
107
|
expectedPassphraseState?: string,
|
|
94
|
-
deriveCardano?: boolean
|
|
108
|
+
deriveCardano?: boolean,
|
|
109
|
+
onStatusRefreshed?: () => void
|
|
95
110
|
) => {
|
|
96
111
|
const existsAttachPinUser = device.features?.attachToPinEnabled === true;
|
|
97
112
|
const metadata = {
|
|
@@ -153,15 +168,36 @@ const selectDeviceSession = async (
|
|
|
153
168
|
emitUiEvent: false,
|
|
154
169
|
interaction: attachPinInteraction,
|
|
155
170
|
});
|
|
156
|
-
|
|
171
|
+
onStatusRefreshed?.();
|
|
172
|
+
if (deriveCardano === true) {
|
|
173
|
+
await askDevicePassphrase(
|
|
174
|
+
device,
|
|
175
|
+
{ passphrase: '', on_device: false },
|
|
176
|
+
true,
|
|
177
|
+
onStatusRefreshed
|
|
178
|
+
);
|
|
179
|
+
// Firmware AskPassphrase Success clears unlocked_by_attach_to_pin.
|
|
180
|
+
// Identity is still the Attach PIN wallet; keep the SDK flag so a later
|
|
181
|
+
// passphrase picker still locks instead of prompting.
|
|
182
|
+
if (device.features) {
|
|
183
|
+
device.features.unlockedAttachPin = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const attachPinSession = await getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
187
|
+
return Object.assign(attachPinSession, { viaAttachPin: true as const });
|
|
157
188
|
}
|
|
158
189
|
|
|
159
190
|
if (hasHostPassphrase) {
|
|
160
|
-
await askDevicePassphrase(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
191
|
+
await askDevicePassphrase(
|
|
192
|
+
device,
|
|
193
|
+
{
|
|
194
|
+
passphrase: hostPassphrase,
|
|
195
|
+
on_device: false,
|
|
196
|
+
},
|
|
197
|
+
deriveCardano,
|
|
198
|
+
onStatusRefreshed
|
|
199
|
+
);
|
|
200
|
+
return getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
165
201
|
}
|
|
166
202
|
|
|
167
203
|
const passphraseOnDeviceInteraction = device.createProtocolV2UiPhaseMetadata?.(
|
|
@@ -172,8 +208,8 @@ const selectDeviceSession = async (
|
|
|
172
208
|
...metadata,
|
|
173
209
|
...(passphraseOnDeviceInteraction ? { interaction: passphraseOnDeviceInteraction } : {}),
|
|
174
210
|
});
|
|
175
|
-
await askDevicePassphrase(device, { on_device: true });
|
|
176
|
-
return getDeviceSession(device, buildDeviceSessionGetRequest(
|
|
211
|
+
await askDevicePassphrase(device, { on_device: true }, deriveCardano, onStatusRefreshed);
|
|
212
|
+
return getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
177
213
|
};
|
|
178
214
|
|
|
179
215
|
export async function getProtocolV2WalletSession(
|
|
@@ -191,11 +227,17 @@ export async function getProtocolV2WalletSession(
|
|
|
191
227
|
deriveCardano?: boolean;
|
|
192
228
|
/** Read the wallet already selected by Attach PIN without reopening wallet selection. */
|
|
193
229
|
readCurrentAttachPinSession?: boolean;
|
|
230
|
+
/** The current call already selected the Main PIN during its unlock preflight. */
|
|
231
|
+
mainPinSelected?: boolean;
|
|
194
232
|
}
|
|
195
233
|
) {
|
|
196
234
|
const forceWalletSelection =
|
|
197
235
|
options?.forceWalletSelection === true || options?.initSession === true;
|
|
198
236
|
const readCurrentAttachPinSession = options?.readCurrentAttachPinSession === true;
|
|
237
|
+
const sessionIsAttachPinWallet = (session?: unknown) =>
|
|
238
|
+
readCurrentAttachPinSession ||
|
|
239
|
+
(session as { viaAttachPin?: boolean } | undefined)?.viaAttachPin === true ||
|
|
240
|
+
device.features?.unlockedAttachPin === true;
|
|
199
241
|
|
|
200
242
|
if (forceWalletSelection) {
|
|
201
243
|
if (options.onlyMainPin) {
|
|
@@ -227,10 +269,20 @@ export async function getProtocolV2WalletSession(
|
|
|
227
269
|
: undefined;
|
|
228
270
|
let response;
|
|
229
271
|
let resumed = false;
|
|
230
|
-
let
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
272
|
+
let walletStatusRefreshed = false;
|
|
273
|
+
const markWalletStatusRefreshed = () => {
|
|
274
|
+
walletStatusRefreshed = true;
|
|
275
|
+
};
|
|
276
|
+
if (options?.onlyMainPin && options.mainPinSelected !== true) {
|
|
277
|
+
await refreshProtocolV2DeviceStatus(device);
|
|
278
|
+
markWalletStatusRefreshed();
|
|
279
|
+
}
|
|
280
|
+
let mainPinAuthenticated =
|
|
281
|
+
options?.mainPinSelected === true ||
|
|
282
|
+
(options?.onlyMainPin === true &&
|
|
283
|
+
device.features?.unlocked === true &&
|
|
284
|
+
device.features?.unlockedAttachPin === false);
|
|
285
|
+
let standardWalletSelected = options?.mainPinSelected === true;
|
|
234
286
|
|
|
235
287
|
const clearCurrentWalletSession = () => {
|
|
236
288
|
if (options?.onlyMainPin) {
|
|
@@ -240,8 +292,41 @@ export async function getProtocolV2WalletSession(
|
|
|
240
292
|
}
|
|
241
293
|
};
|
|
242
294
|
|
|
295
|
+
const sessionGetRequest = ({
|
|
296
|
+
sessionId,
|
|
297
|
+
expectedPassphraseState: passphraseState,
|
|
298
|
+
}: {
|
|
299
|
+
sessionId?: string;
|
|
300
|
+
expectedPassphraseState?: string;
|
|
301
|
+
} = {}) =>
|
|
302
|
+
buildDeviceSessionGetRequest({
|
|
303
|
+
sessionId,
|
|
304
|
+
expectedPassphraseState: passphraseState,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const askEmptyPassphraseAndGet = async ({
|
|
308
|
+
deriveCardano,
|
|
309
|
+
keepAttachPin,
|
|
310
|
+
}: {
|
|
311
|
+
deriveCardano?: boolean;
|
|
312
|
+
keepAttachPin?: boolean;
|
|
313
|
+
} = {}) => {
|
|
314
|
+
await askDevicePassphrase(
|
|
315
|
+
device,
|
|
316
|
+
{ passphrase: '', on_device: false },
|
|
317
|
+
deriveCardano,
|
|
318
|
+
markWalletStatusRefreshed
|
|
319
|
+
);
|
|
320
|
+
if (keepAttachPin && device.features) {
|
|
321
|
+
device.features.unlockedAttachPin = true;
|
|
322
|
+
}
|
|
323
|
+
const session = await getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
324
|
+
return keepAttachPin ? Object.assign(session, { viaAttachPin: true as const }) : session;
|
|
325
|
+
};
|
|
326
|
+
|
|
243
327
|
const rejectMismatchedAttachPinWallet = async () => {
|
|
244
328
|
const features = await refreshProtocolV2DeviceStatus(device);
|
|
329
|
+
markWalletStatusRefreshed();
|
|
245
330
|
if (features.unlockedAttachPin !== true) {
|
|
246
331
|
return;
|
|
247
332
|
}
|
|
@@ -260,35 +345,63 @@ export async function getProtocolV2WalletSession(
|
|
|
260
345
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
261
346
|
};
|
|
262
347
|
|
|
348
|
+
// The passphrase picker would prompt. Empty host AskPassphrase does not;
|
|
349
|
+
// that path is Attach PIN / standard Cardano. Switching to a different
|
|
350
|
+
// passphrase wallet still locks first.
|
|
351
|
+
const lockAttachPinBeforePassphraseSelection = async () => {
|
|
352
|
+
if (readCurrentAttachPinSession || options?.onlyMainPin) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (device.features?.unlockedAttachPin !== true) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
await rejectMismatchedAttachPinWallet();
|
|
359
|
+
};
|
|
360
|
+
|
|
263
361
|
if (options?.onlyMainPin && options.rejectAttachPinForMainWallet) {
|
|
264
362
|
await rejectMismatchedAttachPinWallet();
|
|
265
363
|
}
|
|
266
364
|
|
|
267
365
|
const selectMainPin = async (force = false) => {
|
|
268
|
-
if (force || !
|
|
366
|
+
if (force || !mainPinAuthenticated) {
|
|
269
367
|
await device.unlockDevice(DeviceSessionPinType.Main, {
|
|
270
368
|
source: 'wallet-session-coordinator',
|
|
271
369
|
reason: expectedPassphraseState ? 'session-recovery' : 'open-wallet',
|
|
272
370
|
deviceOnly: true,
|
|
273
371
|
});
|
|
274
|
-
|
|
372
|
+
markWalletStatusRefreshed();
|
|
373
|
+
mainPinAuthenticated = true;
|
|
374
|
+
standardWalletSelected = true;
|
|
275
375
|
}
|
|
276
376
|
};
|
|
277
377
|
|
|
278
|
-
const selectStandardWallet = async () => {
|
|
279
|
-
// Main PIN authenticates the device; an empty host passphrase selects the standard derivation.
|
|
280
|
-
await selectMainPin();
|
|
378
|
+
const selectStandardWallet = async (forceMainPin = false) => {
|
|
281
379
|
if (device.features?.passphraseProtection === true) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
380
|
+
// Main PIN authenticates the device; an empty host passphrase selects the standard derivation.
|
|
381
|
+
await selectMainPin();
|
|
382
|
+
await askDevicePassphrase(
|
|
383
|
+
device,
|
|
384
|
+
{
|
|
385
|
+
passphrase: '',
|
|
386
|
+
on_device: false,
|
|
387
|
+
},
|
|
388
|
+
options?.deriveCardano,
|
|
389
|
+
markWalletStatusRefreshed
|
|
390
|
+
);
|
|
391
|
+
standardWalletSelected = true;
|
|
392
|
+
} else if (!standardWalletSelected) {
|
|
393
|
+
// Without passphrase protection there is no empty-passphrase selector.
|
|
394
|
+
// An unlocked non-Attach-PIN device is already in the only available wallet context.
|
|
395
|
+
// Force Main PIN only when recovering from a mismatched cached standard session.
|
|
396
|
+
await selectMainPin(forceMainPin);
|
|
397
|
+
standardWalletSelected = true;
|
|
286
398
|
}
|
|
287
399
|
};
|
|
288
400
|
|
|
289
401
|
if (readCurrentAttachPinSession) {
|
|
290
402
|
const status = await requestProtocolV2DeviceStatus(device);
|
|
291
403
|
device.updateProtocolV2Status(status);
|
|
404
|
+
markWalletStatusRefreshed();
|
|
292
405
|
if (
|
|
293
406
|
status.unlocked !== true ||
|
|
294
407
|
status.passphrase_enabled !== true ||
|
|
@@ -297,10 +410,7 @@ export async function getProtocolV2WalletSession(
|
|
|
297
410
|
device.clearInternalState();
|
|
298
411
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
299
412
|
}
|
|
300
|
-
response = await getDeviceSession(
|
|
301
|
-
device,
|
|
302
|
-
buildDeviceSessionGetRequest({ deriveCardano: options?.deriveCardano })
|
|
303
|
-
);
|
|
413
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
304
414
|
} else if (options?.onlyMainPin) {
|
|
305
415
|
expectedPassphraseState = cachedStandardSession?.passphraseState;
|
|
306
416
|
if (cachedStandardSession) {
|
|
@@ -310,10 +420,9 @@ export async function getProtocolV2WalletSession(
|
|
|
310
420
|
}
|
|
311
421
|
response = await getDeviceSession(
|
|
312
422
|
device,
|
|
313
|
-
|
|
423
|
+
sessionGetRequest({
|
|
314
424
|
sessionId: cachedStandardSession.sessionId,
|
|
315
425
|
expectedPassphraseState,
|
|
316
|
-
deriveCardano: options?.deriveCardano,
|
|
317
426
|
})
|
|
318
427
|
);
|
|
319
428
|
resumed = true;
|
|
@@ -328,19 +437,15 @@ export async function getProtocolV2WalletSession(
|
|
|
328
437
|
|
|
329
438
|
if (!response) {
|
|
330
439
|
await selectStandardWallet();
|
|
331
|
-
response = await getDeviceSession(
|
|
332
|
-
device,
|
|
333
|
-
buildDeviceSessionGetRequest({ deriveCardano: options?.deriveCardano })
|
|
334
|
-
);
|
|
440
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
335
441
|
}
|
|
336
442
|
} else if (cachedSessionId && expectedPassphraseState) {
|
|
337
443
|
try {
|
|
338
444
|
response = await getDeviceSession(
|
|
339
445
|
device,
|
|
340
|
-
|
|
446
|
+
sessionGetRequest({
|
|
341
447
|
sessionId: cachedSessionId,
|
|
342
448
|
expectedPassphraseState,
|
|
343
|
-
deriveCardano: options?.deriveCardano,
|
|
344
449
|
})
|
|
345
450
|
);
|
|
346
451
|
resumed = true;
|
|
@@ -350,14 +455,18 @@ export async function getProtocolV2WalletSession(
|
|
|
350
455
|
throw error;
|
|
351
456
|
}
|
|
352
457
|
resumed = false;
|
|
458
|
+
if (device.features?.unlockedAttachPin === true) {
|
|
459
|
+
// Locking invalidates the old handle, but Attach PIN already selected the wallet.
|
|
460
|
+
// Read the current session and validate its passphrase state below.
|
|
461
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
462
|
+
}
|
|
353
463
|
}
|
|
354
464
|
} else if (expectedPassphraseState) {
|
|
355
465
|
try {
|
|
356
466
|
response = await getDeviceSession(
|
|
357
467
|
device,
|
|
358
|
-
|
|
468
|
+
sessionGetRequest({
|
|
359
469
|
expectedPassphraseState,
|
|
360
|
-
deriveCardano: options?.deriveCardano,
|
|
361
470
|
})
|
|
362
471
|
);
|
|
363
472
|
} catch (error) {
|
|
@@ -372,7 +481,13 @@ export async function getProtocolV2WalletSession(
|
|
|
372
481
|
device.clearInternalState();
|
|
373
482
|
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
374
483
|
}
|
|
375
|
-
|
|
484
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
485
|
+
response = await selectDeviceSession(
|
|
486
|
+
device,
|
|
487
|
+
expectedPassphraseState,
|
|
488
|
+
options?.deriveCardano,
|
|
489
|
+
markWalletStatusRefreshed
|
|
490
|
+
);
|
|
376
491
|
}
|
|
377
492
|
|
|
378
493
|
let { message } = response;
|
|
@@ -395,14 +510,17 @@ export async function getProtocolV2WalletSession(
|
|
|
395
510
|
}
|
|
396
511
|
if (options?.onlyMainPin) {
|
|
397
512
|
device.clearStandardInternalState?.();
|
|
398
|
-
await selectStandardWallet();
|
|
399
|
-
response = await getDeviceSession(
|
|
400
|
-
device,
|
|
401
|
-
buildDeviceSessionGetRequest({ deriveCardano: options?.deriveCardano })
|
|
402
|
-
);
|
|
513
|
+
await selectStandardWallet(true);
|
|
514
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
403
515
|
} else {
|
|
404
516
|
device.clearInternalState();
|
|
405
|
-
|
|
517
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
518
|
+
response = await selectDeviceSession(
|
|
519
|
+
device,
|
|
520
|
+
expectedPassphraseState,
|
|
521
|
+
options?.deriveCardano,
|
|
522
|
+
markWalletStatusRefreshed
|
|
523
|
+
);
|
|
406
524
|
}
|
|
407
525
|
message = response.message;
|
|
408
526
|
try {
|
|
@@ -422,6 +540,54 @@ export async function getProtocolV2WalletSession(
|
|
|
422
540
|
}
|
|
423
541
|
}
|
|
424
542
|
|
|
543
|
+
// origin/dev generates Cardano on AskPassphrase, not Get. Empty host
|
|
544
|
+
// passphrase is the Attach PIN / standard-wallet secret. Hidden wallets
|
|
545
|
+
// still need a real passphrase Ask. Passphrase-off Get auto-requests Cardano.
|
|
546
|
+
if (options?.deriveCardano === true && !deviceSessionHasCardano(message)) {
|
|
547
|
+
if (options?.resumeOnly) {
|
|
548
|
+
device.clearInternalState();
|
|
549
|
+
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
550
|
+
}
|
|
551
|
+
resumed = false;
|
|
552
|
+
const previousAddress = message.btc_test_address;
|
|
553
|
+
if (sessionIsAttachPinWallet(response)) {
|
|
554
|
+
response = await askEmptyPassphraseAndGet({ deriveCardano: true, keepAttachPin: true });
|
|
555
|
+
} else if (device.features?.passphraseProtection === false) {
|
|
556
|
+
response = await getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
557
|
+
} else if (options?.onlyMainPin) {
|
|
558
|
+
await selectMainPin();
|
|
559
|
+
response = await askEmptyPassphraseAndGet({ deriveCardano: true });
|
|
560
|
+
} else {
|
|
561
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
562
|
+
response = await selectDeviceSession(
|
|
563
|
+
device,
|
|
564
|
+
expectedPassphraseState,
|
|
565
|
+
true,
|
|
566
|
+
markWalletStatusRefreshed
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
message = response.message;
|
|
570
|
+
try {
|
|
571
|
+
assertCompleteDeviceSession(message);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
if (options?.onlyMainPin) {
|
|
574
|
+
device.clearStandardInternalState?.();
|
|
575
|
+
} else {
|
|
576
|
+
device.clearInternalState();
|
|
577
|
+
}
|
|
578
|
+
throw error;
|
|
579
|
+
}
|
|
580
|
+
if (previousAddress && previousAddress !== message.btc_test_address) {
|
|
581
|
+
await rejectMismatchedAttachPinWallet();
|
|
582
|
+
clearCurrentWalletSession();
|
|
583
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
584
|
+
}
|
|
585
|
+
if (!deviceSessionHasCardano(message)) {
|
|
586
|
+
clearCurrentWalletSession();
|
|
587
|
+
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
425
591
|
const internalStateArgs = [
|
|
426
592
|
true,
|
|
427
593
|
message.btc_test_address,
|
|
@@ -436,9 +602,9 @@ export async function getProtocolV2WalletSession(
|
|
|
436
602
|
}
|
|
437
603
|
|
|
438
604
|
let unlockedAttachPin: boolean | undefined;
|
|
439
|
-
if (readCurrentAttachPinSession) {
|
|
605
|
+
if (readCurrentAttachPinSession || sessionIsAttachPinWallet(response)) {
|
|
440
606
|
unlockedAttachPin = true;
|
|
441
|
-
} else if (
|
|
607
|
+
} else if (mainPinAuthenticated) {
|
|
442
608
|
unlockedAttachPin = false;
|
|
443
609
|
}
|
|
444
610
|
|
|
@@ -447,6 +613,7 @@ export async function getProtocolV2WalletSession(
|
|
|
447
613
|
newSession: message.session_id,
|
|
448
614
|
unlockedAttachPin,
|
|
449
615
|
resumed,
|
|
616
|
+
walletStatusRefreshed,
|
|
450
617
|
};
|
|
451
618
|
}
|
|
452
619
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CommonParams, Response } from '../params';
|
|
2
2
|
import type { OnboardingStatus, Success } from '@onekeyfe/hd-transport';
|
|
3
3
|
import type { DeviceRebootParams } from '../../api/protocol-v2/helpers';
|
|
4
|
+
import type { UploadPortfolioParams } from '../../api/UploadPortfolio';
|
|
4
5
|
import type {
|
|
5
6
|
DeviceUploadWallpaperParams,
|
|
6
7
|
DeviceUploadWallpaperResponse,
|
|
@@ -12,6 +13,7 @@ import type {
|
|
|
12
13
|
|
|
13
14
|
// Re-export implementation parameter types as the single source of truth.
|
|
14
15
|
export type { DeviceRebootParams, RebootTypeInput } from '../../api/protocol-v2/helpers';
|
|
16
|
+
export type { UploadPortfolioParams } from '../../api/UploadPortfolio';
|
|
15
17
|
export type {
|
|
16
18
|
DeviceUploadWallpaperParams,
|
|
17
19
|
DeviceUploadWallpaperResponse,
|
|
@@ -67,8 +69,5 @@ export declare function deviceUploadNft(
|
|
|
67
69
|
|
|
68
70
|
export declare function uploadPortfolio(
|
|
69
71
|
connectId: string,
|
|
70
|
-
params:
|
|
71
|
-
packageBase64: string;
|
|
72
|
-
timeoutMs?: number | string;
|
|
73
|
-
}
|
|
72
|
+
params: UploadPortfolioParams
|
|
74
73
|
): Response<FileInfo & { portfolioUpdated: true }>;
|
|
@@ -15,6 +15,8 @@ export type SolSignOffchainMessageParams = {
|
|
|
15
15
|
messageVersion?: SolanaOffChainMessageVersion;
|
|
16
16
|
messageFormat?: SolanaOffChainMessageFormat;
|
|
17
17
|
applicationDomainHex?: string;
|
|
18
|
+
/** 32-byte public keys encoded as hex, strictly sorted and unique. */
|
|
19
|
+
requiredSigners?: string[];
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export declare function solSignOffchainMessage(
|
package/src/types/settings.ts
CHANGED
|
@@ -77,7 +77,8 @@ export type IProtocolV2Resources = {
|
|
|
77
77
|
/** STM32 firmware config */
|
|
78
78
|
export type IFirmwareReleaseInfo = {
|
|
79
79
|
required: boolean;
|
|
80
|
-
|
|
80
|
+
/** Legacy release artifact URL. Protocol V2 releases use component URLs. */
|
|
81
|
+
url?: string;
|
|
81
82
|
/**
|
|
82
83
|
* Firmware type (bitcoinonly or universal)
|
|
83
84
|
* This field is not present in the remote config, but will be inferred from the firmware field name
|
|
@@ -106,7 +107,8 @@ export type IFirmwareReleaseInfo = {
|
|
|
106
107
|
bootloaderChangelog?: {
|
|
107
108
|
[k in ILocale]: string;
|
|
108
109
|
};
|
|
109
|
-
|
|
110
|
+
/** Legacy release artifact SHA-256. Protocol V2 releases use component fingerprints. */
|
|
111
|
+
fingerprint?: string;
|
|
110
112
|
expectedSize?: number;
|
|
111
113
|
version: IVersionArray;
|
|
112
114
|
changelog: {
|
|
@@ -110,6 +110,7 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
|
|
|
110
110
|
initSession?: boolean;
|
|
111
111
|
deriveCardano?: boolean;
|
|
112
112
|
rejectAttachPinForMainWallet?: boolean;
|
|
113
|
+
mainPinSelected?: boolean;
|
|
113
114
|
}
|
|
114
115
|
) => {
|
|
115
116
|
if (device.isProtocolV2()) {
|
|
@@ -127,6 +128,7 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
|
|
|
127
128
|
onlyMainPin: options?.onlyMainPin,
|
|
128
129
|
deriveCardano: options?.deriveCardano,
|
|
129
130
|
rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
|
|
131
|
+
mainPinSelected: options?.mainPinSelected,
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -194,6 +196,7 @@ export const getPassphraseState = async (
|
|
|
194
196
|
initSession?: boolean;
|
|
195
197
|
deriveCardano?: boolean;
|
|
196
198
|
rejectAttachPinForMainWallet?: boolean;
|
|
199
|
+
mainPinSelected?: boolean;
|
|
197
200
|
}
|
|
198
201
|
): Promise<{
|
|
199
202
|
passphraseState: string | undefined;
|
|
@@ -216,6 +219,7 @@ export const getPassphraseState = async (
|
|
|
216
219
|
onlyMainPin: options?.onlyMainPin,
|
|
217
220
|
deriveCardano: options?.deriveCardano,
|
|
218
221
|
rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
|
|
222
|
+
mainPinSelected: options?.mainPinSelected,
|
|
219
223
|
});
|
|
220
224
|
}
|
|
221
225
|
|