@onekeyfe/hd-core 1.2.2-alpha.5 → 1.2.2-alpha.6

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.
@@ -76,9 +76,7 @@ const deviceSessionHasCardano = (message: { seed_domains?: DeviceSessionSeedDoma
76
76
  Array.isArray(message.seed_domains) &&
77
77
  message.seed_domains.includes(DeviceSessionSeedDomain.SeedDomain_Cardano);
78
78
 
79
- // AskPassphrase.seed_domains selects which seeds to generate. DeviceSessionGet
80
- // only resumes or reads the current session; firmware rejects unknown Get
81
- // fields, including leftover seed_domains.
79
+ // origin/dev Get is read/resume only. Seed generation lives on AskPassphrase.
82
80
  const buildDeviceSessionGetRequest = ({
83
81
  sessionId,
84
82
  expectedPassphraseState,
@@ -171,7 +169,22 @@ const selectDeviceSession = async (
171
169
  interaction: attachPinInteraction,
172
170
  });
173
171
  onStatusRefreshed?.();
174
- return getDeviceSession(device, buildDeviceSessionGetRequest());
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 });
175
188
  }
176
189
 
177
190
  if (hasHostPassphrase) {
@@ -221,6 +234,10 @@ export async function getProtocolV2WalletSession(
221
234
  const forceWalletSelection =
222
235
  options?.forceWalletSelection === true || options?.initSession === true;
223
236
  const readCurrentAttachPinSession = options?.readCurrentAttachPinSession === true;
237
+ const sessionIsAttachPinWallet = (session?: { viaAttachPin?: boolean }) =>
238
+ readCurrentAttachPinSession ||
239
+ session?.viaAttachPin === true ||
240
+ device.features?.unlockedAttachPin === true;
224
241
 
225
242
  if (forceWalletSelection) {
226
243
  if (options.onlyMainPin) {
@@ -271,6 +288,38 @@ export async function getProtocolV2WalletSession(
271
288
  }
272
289
  };
273
290
 
291
+ const sessionGetRequest = ({
292
+ sessionId,
293
+ expectedPassphraseState: passphraseState,
294
+ }: {
295
+ sessionId?: string;
296
+ expectedPassphraseState?: string;
297
+ } = {}) =>
298
+ buildDeviceSessionGetRequest({
299
+ sessionId,
300
+ expectedPassphraseState: passphraseState,
301
+ });
302
+
303
+ const askEmptyPassphraseAndGet = async ({
304
+ deriveCardano,
305
+ keepAttachPin,
306
+ }: {
307
+ deriveCardano?: boolean;
308
+ keepAttachPin?: boolean;
309
+ } = {}) => {
310
+ await askDevicePassphrase(
311
+ device,
312
+ { passphrase: '', on_device: false },
313
+ deriveCardano,
314
+ markWalletStatusRefreshed
315
+ );
316
+ if (keepAttachPin && device.features) {
317
+ device.features.unlockedAttachPin = true;
318
+ }
319
+ const session = await getDeviceSession(device, buildDeviceSessionGetRequest());
320
+ return keepAttachPin ? Object.assign(session, { viaAttachPin: true as const }) : session;
321
+ };
322
+
274
323
  const rejectMismatchedAttachPinWallet = async () => {
275
324
  const features = await refreshProtocolV2DeviceStatus(device);
276
325
  markWalletStatusRefreshed();
@@ -292,6 +341,19 @@ export async function getProtocolV2WalletSession(
292
341
  throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
293
342
  };
294
343
 
344
+ // The passphrase picker would prompt. Empty host AskPassphrase does not;
345
+ // that path is Attach PIN / standard Cardano. Switching to a different
346
+ // passphrase wallet still locks first.
347
+ const lockAttachPinBeforePassphraseSelection = async () => {
348
+ if (readCurrentAttachPinSession || options?.onlyMainPin) {
349
+ return;
350
+ }
351
+ if (device.features?.unlockedAttachPin !== true) {
352
+ return;
353
+ }
354
+ await rejectMismatchedAttachPinWallet();
355
+ };
356
+
295
357
  if (options?.onlyMainPin && options.rejectAttachPinForMainWallet) {
296
358
  await rejectMismatchedAttachPinWallet();
297
359
  }
@@ -342,7 +404,7 @@ export async function getProtocolV2WalletSession(
342
404
  device.clearInternalState();
343
405
  throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
344
406
  }
345
- response = await getDeviceSession(device, buildDeviceSessionGetRequest());
407
+ response = await getDeviceSession(device, sessionGetRequest());
346
408
  } else if (options?.onlyMainPin) {
347
409
  expectedPassphraseState = cachedStandardSession?.passphraseState;
348
410
  if (cachedStandardSession) {
@@ -352,7 +414,7 @@ export async function getProtocolV2WalletSession(
352
414
  }
353
415
  response = await getDeviceSession(
354
416
  device,
355
- buildDeviceSessionGetRequest({
417
+ sessionGetRequest({
356
418
  sessionId: cachedStandardSession.sessionId,
357
419
  expectedPassphraseState,
358
420
  })
@@ -369,13 +431,13 @@ export async function getProtocolV2WalletSession(
369
431
 
370
432
  if (!response) {
371
433
  await selectStandardWallet();
372
- response = await getDeviceSession(device, buildDeviceSessionGetRequest());
434
+ response = await getDeviceSession(device, sessionGetRequest());
373
435
  }
374
436
  } else if (cachedSessionId && expectedPassphraseState) {
375
437
  try {
376
438
  response = await getDeviceSession(
377
439
  device,
378
- buildDeviceSessionGetRequest({
440
+ sessionGetRequest({
379
441
  sessionId: cachedSessionId,
380
442
  expectedPassphraseState,
381
443
  })
@@ -392,7 +454,7 @@ export async function getProtocolV2WalletSession(
392
454
  try {
393
455
  response = await getDeviceSession(
394
456
  device,
395
- buildDeviceSessionGetRequest({
457
+ sessionGetRequest({
396
458
  expectedPassphraseState,
397
459
  })
398
460
  );
@@ -408,6 +470,7 @@ export async function getProtocolV2WalletSession(
408
470
  device.clearInternalState();
409
471
  throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
410
472
  }
473
+ await lockAttachPinBeforePassphraseSelection();
411
474
  response = await selectDeviceSession(
412
475
  device,
413
476
  expectedPassphraseState,
@@ -437,9 +500,10 @@ export async function getProtocolV2WalletSession(
437
500
  if (options?.onlyMainPin) {
438
501
  device.clearStandardInternalState?.();
439
502
  await selectStandardWallet();
440
- response = await getDeviceSession(device, buildDeviceSessionGetRequest());
503
+ response = await getDeviceSession(device, sessionGetRequest());
441
504
  } else {
442
505
  device.clearInternalState();
506
+ await lockAttachPinBeforePassphraseSelection();
443
507
  response = await selectDeviceSession(
444
508
  device,
445
509
  expectedPassphraseState,
@@ -465,18 +529,25 @@ export async function getProtocolV2WalletSession(
465
529
  }
466
530
  }
467
531
 
468
- // DeviceSession.seed_domains reports what the SE already generated. Get
469
- // cannot add Cardano, so a Cardano call on a Standard-only session must Ask again.
532
+ // origin/dev generates Cardano on AskPassphrase, not Get. Empty host
533
+ // passphrase is the Attach PIN / standard-wallet secret. Hidden wallets
534
+ // still need a real passphrase Ask. Passphrase-off Get auto-requests Cardano.
470
535
  if (options?.deriveCardano === true && !deviceSessionHasCardano(message)) {
471
536
  if (options?.resumeOnly) {
472
537
  device.clearInternalState();
473
538
  throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
474
539
  }
475
540
  resumed = false;
476
- if (options?.onlyMainPin) {
477
- await selectStandardWallet();
541
+ const previousAddress = message.btc_test_address;
542
+ if (sessionIsAttachPinWallet(response)) {
543
+ response = await askEmptyPassphraseAndGet({ deriveCardano: true, keepAttachPin: true });
544
+ } else if (device.features?.passphraseProtection === false) {
478
545
  response = await getDeviceSession(device, buildDeviceSessionGetRequest());
546
+ } else if (options?.onlyMainPin) {
547
+ await selectMainPin();
548
+ response = await askEmptyPassphraseAndGet({ deriveCardano: true });
479
549
  } else {
550
+ await lockAttachPinBeforePassphraseSelection();
480
551
  response = await selectDeviceSession(
481
552
  device,
482
553
  expectedPassphraseState,
@@ -495,6 +566,15 @@ export async function getProtocolV2WalletSession(
495
566
  }
496
567
  throw error;
497
568
  }
569
+ if (previousAddress && previousAddress !== message.btc_test_address) {
570
+ await rejectMismatchedAttachPinWallet();
571
+ clearCurrentWalletSession();
572
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
573
+ }
574
+ if (!deviceSessionHasCardano(message)) {
575
+ clearCurrentWalletSession();
576
+ throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
577
+ }
498
578
  }
499
579
 
500
580
  const internalStateArgs = [
@@ -511,7 +591,7 @@ export async function getProtocolV2WalletSession(
511
591
  }
512
592
 
513
593
  let unlockedAttachPin: boolean | undefined;
514
- if (readCurrentAttachPinSession) {
594
+ if (readCurrentAttachPinSession || sessionIsAttachPinWallet(response)) {
515
595
  unlockedAttachPin = true;
516
596
  } else if (mainPinAuthenticated) {
517
597
  unlockedAttachPin = false;