@onekeyfe/hd-core 1.2.2-alpha.4 → 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.
- package/__tests__/open-wallet-session.test.ts +388 -30
- package/__tests__/protocol-v2.test.ts +12 -7
- package/dist/index.js +108 -20
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +1 -1
- package/src/core/index.ts +2 -2
- package/src/data/messages/messages-protocol-v2.json +5 -0
- package/src/protocols/protocol-v2/walletSession.ts +135 -22
|
@@ -11,6 +11,13 @@ import {
|
|
|
11
11
|
getProtocolV2WalletSession,
|
|
12
12
|
} from '../src/protocols/protocol-v2/walletSession';
|
|
13
13
|
|
|
14
|
+
const STANDARD_SEED_DOMAINS = [DeviceSessionSeedDomain.SeedDomain_Standard];
|
|
15
|
+
const CARDANO_SEED_DOMAINS = [
|
|
16
|
+
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
17
|
+
DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
18
|
+
];
|
|
19
|
+
const standardSessionGet = {};
|
|
20
|
+
|
|
14
21
|
jest.mock('../src/data/config', () => ({
|
|
15
22
|
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
16
23
|
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
@@ -142,9 +149,9 @@ describe('openWalletSession', () => {
|
|
|
142
149
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
143
150
|
passphrase: '',
|
|
144
151
|
on_device: false,
|
|
145
|
-
seed_domains: [],
|
|
152
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
146
153
|
});
|
|
147
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
154
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
148
155
|
});
|
|
149
156
|
|
|
150
157
|
test('selects the Main PIN before opening the standard wallet when passphrase is disabled', async () => {
|
|
@@ -176,7 +183,7 @@ describe('openWalletSession', () => {
|
|
|
176
183
|
'Success',
|
|
177
184
|
expect.anything()
|
|
178
185
|
);
|
|
179
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
186
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
180
187
|
});
|
|
181
188
|
|
|
182
189
|
test('reuses a Main PIN selected by the current preflight when passphrase is disabled', async () => {
|
|
@@ -202,7 +209,7 @@ describe('openWalletSession', () => {
|
|
|
202
209
|
});
|
|
203
210
|
|
|
204
211
|
expect(device.unlockDevice).not.toHaveBeenCalled();
|
|
205
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
212
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
206
213
|
});
|
|
207
214
|
|
|
208
215
|
test('does not treat an Attach PIN DeviceStatus as the Main wallet', async () => {
|
|
@@ -329,9 +336,14 @@ describe('openWalletSession', () => {
|
|
|
329
336
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
330
337
|
passphrase: 'host hidden wallet',
|
|
331
338
|
on_device: false,
|
|
332
|
-
seed_domains: [],
|
|
339
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
333
340
|
});
|
|
334
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
341
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
342
|
+
3,
|
|
343
|
+
'DeviceSessionGet',
|
|
344
|
+
'DeviceSession',
|
|
345
|
+
standardSessionGet
|
|
346
|
+
);
|
|
335
347
|
});
|
|
336
348
|
|
|
337
349
|
test('keeps Legacy Protocol V1 getPassphraseState parameterless', async () => {
|
|
@@ -448,9 +460,14 @@ describe('openWalletSession', () => {
|
|
|
448
460
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
449
461
|
passphrase: 'host hidden wallet',
|
|
450
462
|
on_device: false,
|
|
451
|
-
seed_domains: [],
|
|
463
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
452
464
|
});
|
|
453
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
465
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
466
|
+
3,
|
|
467
|
+
'DeviceSessionGet',
|
|
468
|
+
'DeviceSession',
|
|
469
|
+
standardSessionGet
|
|
470
|
+
);
|
|
454
471
|
});
|
|
455
472
|
|
|
456
473
|
test('refreshes Pro2 status and unlocks before selecting a hidden wallet when locked', async () => {
|
|
@@ -724,7 +741,11 @@ describe('openWalletSession', () => {
|
|
|
724
741
|
});
|
|
725
742
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
726
743
|
expect(device.unlockDevice).not.toHaveBeenCalled();
|
|
727
|
-
expect(device.commands.typedCall).toHaveBeenCalledWith(
|
|
744
|
+
expect(device.commands.typedCall).toHaveBeenCalledWith(
|
|
745
|
+
'DeviceSessionGet',
|
|
746
|
+
'DeviceSession',
|
|
747
|
+
standardSessionGet
|
|
748
|
+
);
|
|
728
749
|
expect(device.commands.typedCall).not.toHaveBeenCalledWith(
|
|
729
750
|
'DeviceSessionAskPassphrase',
|
|
730
751
|
'Success',
|
|
@@ -820,9 +841,9 @@ describe('openWalletSession', () => {
|
|
|
820
841
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
821
842
|
passphrase: 'host hidden wallet',
|
|
822
843
|
on_device: false,
|
|
823
|
-
seed_domains: [],
|
|
844
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
824
845
|
});
|
|
825
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
846
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
826
847
|
expect(promptPassphrase).toHaveBeenCalled();
|
|
827
848
|
expect(deviceWalletSessionStore.get('device-1', 'new-hidden-state')).toBe('new-hidden-session');
|
|
828
849
|
});
|
|
@@ -894,6 +915,7 @@ describe('openWalletSession', () => {
|
|
|
894
915
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
895
916
|
session_id: 'known-session',
|
|
896
917
|
btc_test_address: 'hidden-state',
|
|
918
|
+
...standardSessionGet,
|
|
897
919
|
});
|
|
898
920
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
899
921
|
});
|
|
@@ -1076,9 +1098,9 @@ describe('openWalletSession', () => {
|
|
|
1076
1098
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1077
1099
|
passphrase: '',
|
|
1078
1100
|
on_device: false,
|
|
1079
|
-
seed_domains: [],
|
|
1101
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1080
1102
|
});
|
|
1081
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
1103
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
1082
1104
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1083
1105
|
expect(device.passphraseState).toBeUndefined();
|
|
1084
1106
|
});
|
|
@@ -1247,7 +1269,7 @@ describe('openWalletSession', () => {
|
|
|
1247
1269
|
reason: 'open-wallet',
|
|
1248
1270
|
deviceOnly: true,
|
|
1249
1271
|
});
|
|
1250
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
1272
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
1251
1273
|
});
|
|
1252
1274
|
|
|
1253
1275
|
test('selects a hidden wallet without exposing the internal device session', async () => {
|
|
@@ -1280,9 +1302,9 @@ describe('openWalletSession', () => {
|
|
|
1280
1302
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1281
1303
|
passphrase: 'host hidden wallet',
|
|
1282
1304
|
on_device: false,
|
|
1283
|
-
seed_domains: [],
|
|
1305
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1284
1306
|
});
|
|
1285
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
1307
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
1286
1308
|
expect(promptPassphrase).toHaveBeenCalled();
|
|
1287
1309
|
expect(device.passphraseState).toBeUndefined();
|
|
1288
1310
|
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('hidden-session');
|
|
@@ -1341,9 +1363,9 @@ describe('openWalletSession', () => {
|
|
|
1341
1363
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1342
1364
|
passphrase: 'host hidden wallet',
|
|
1343
1365
|
on_device: false,
|
|
1344
|
-
seed_domains: [],
|
|
1366
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1345
1367
|
});
|
|
1346
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
1368
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
1347
1369
|
});
|
|
1348
1370
|
|
|
1349
1371
|
test('selects an on-device passphrase wallet with an explicit on_device request', async () => {
|
|
@@ -1388,9 +1410,14 @@ describe('openWalletSession', () => {
|
|
|
1388
1410
|
});
|
|
1389
1411
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
1390
1412
|
on_device: true,
|
|
1391
|
-
seed_domains: [],
|
|
1413
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1392
1414
|
});
|
|
1393
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
1415
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
1416
|
+
3,
|
|
1417
|
+
'DeviceSessionGet',
|
|
1418
|
+
'DeviceSession',
|
|
1419
|
+
standardSessionGet
|
|
1420
|
+
);
|
|
1394
1421
|
expect(device.createProtocolV2UiPhaseMetadata).toHaveBeenNthCalledWith(
|
|
1395
1422
|
2,
|
|
1396
1423
|
'passphrase-on-device',
|
|
@@ -1441,9 +1468,14 @@ describe('openWalletSession', () => {
|
|
|
1441
1468
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
1442
1469
|
passphrase: 'host hidden wallet',
|
|
1443
1470
|
on_device: false,
|
|
1444
|
-
seed_domains: [],
|
|
1471
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1445
1472
|
});
|
|
1446
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
1473
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
1474
|
+
3,
|
|
1475
|
+
'DeviceSessionGet',
|
|
1476
|
+
'DeviceSession',
|
|
1477
|
+
standardSessionGet
|
|
1478
|
+
);
|
|
1447
1479
|
});
|
|
1448
1480
|
|
|
1449
1481
|
test('normalizes a Unicode Host passphrase before sending it to Pro2 firmware', async () => {
|
|
@@ -1465,7 +1497,7 @@ describe('openWalletSession', () => {
|
|
|
1465
1497
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
1466
1498
|
passphrase: 'cafe\u0301',
|
|
1467
1499
|
on_device: false,
|
|
1468
|
-
seed_domains: [],
|
|
1500
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1469
1501
|
});
|
|
1470
1502
|
});
|
|
1471
1503
|
|
|
@@ -1489,7 +1521,7 @@ describe('openWalletSession', () => {
|
|
|
1489
1521
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
1490
1522
|
passphrase,
|
|
1491
1523
|
on_device: false,
|
|
1492
|
-
seed_domains: [],
|
|
1524
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1493
1525
|
});
|
|
1494
1526
|
});
|
|
1495
1527
|
|
|
@@ -1525,7 +1557,7 @@ describe('openWalletSession', () => {
|
|
|
1525
1557
|
expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.AttachToPin, {
|
|
1526
1558
|
emitUiEvent: false,
|
|
1527
1559
|
});
|
|
1528
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession',
|
|
1560
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
1529
1561
|
});
|
|
1530
1562
|
|
|
1531
1563
|
test('uses the complete Attach PIN wire flow without a main PIN unlock', async () => {
|
|
@@ -1554,7 +1586,7 @@ describe('openWalletSession', () => {
|
|
|
1554
1586
|
['ProtocolInfoRequest', 'ProtocolInfo', { eventless_wallet_session: true }],
|
|
1555
1587
|
['DeviceSessionAskPin', 'Success', { type: DeviceSessionPinType.AttachToPin }],
|
|
1556
1588
|
['DeviceStatusGet', 'DeviceStatus', {}],
|
|
1557
|
-
['DeviceSessionGet', 'DeviceSession',
|
|
1589
|
+
['DeviceSessionGet', 'DeviceSession', standardSessionGet],
|
|
1558
1590
|
]);
|
|
1559
1591
|
expect(device.commands.typedCall).not.toHaveBeenCalledWith('DeviceSessionAskPin', 'Success', {
|
|
1560
1592
|
type: DeviceSessionPinType.Main,
|
|
@@ -1766,6 +1798,7 @@ describe('openWalletSession', () => {
|
|
|
1766
1798
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1767
1799
|
session_id: 'known-session',
|
|
1768
1800
|
btc_test_address: 'hidden-state',
|
|
1801
|
+
...standardSessionGet,
|
|
1769
1802
|
});
|
|
1770
1803
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1771
1804
|
});
|
|
@@ -1825,6 +1858,7 @@ describe('openWalletSession', () => {
|
|
|
1825
1858
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1826
1859
|
session_id: 'known-session',
|
|
1827
1860
|
btc_test_address: 'hidden-state',
|
|
1861
|
+
...standardSessionGet,
|
|
1828
1862
|
});
|
|
1829
1863
|
const sessionGetCall = typedCall.mock.calls.findIndex(
|
|
1830
1864
|
([requestName]) => requestName === 'DeviceSessionGet'
|
|
@@ -1922,6 +1956,7 @@ describe('openWalletSession', () => {
|
|
|
1922
1956
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1923
1957
|
session_id: 'expired-session',
|
|
1924
1958
|
btc_test_address: 'hidden-state',
|
|
1959
|
+
...standardSessionGet,
|
|
1925
1960
|
});
|
|
1926
1961
|
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
1927
1962
|
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
|
|
@@ -1959,6 +1994,7 @@ describe('openWalletSession', () => {
|
|
|
1959
1994
|
});
|
|
1960
1995
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1961
1996
|
btc_test_address: 'hidden-state',
|
|
1997
|
+
...standardSessionGet,
|
|
1962
1998
|
});
|
|
1963
1999
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1964
2000
|
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('new-session');
|
|
@@ -1998,9 +2034,13 @@ describe('openWalletSession', () => {
|
|
|
1998
2034
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1999
2035
|
passphrase: 'host hidden wallet',
|
|
2000
2036
|
on_device: false,
|
|
2001
|
-
seed_domains: [],
|
|
2037
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2002
2038
|
});
|
|
2003
|
-
expect(typedCall).toHaveBeenCalledWith(
|
|
2039
|
+
expect(typedCall).toHaveBeenCalledWith(
|
|
2040
|
+
'DeviceSessionGet',
|
|
2041
|
+
'DeviceSession',
|
|
2042
|
+
standardSessionGet
|
|
2043
|
+
);
|
|
2004
2044
|
}
|
|
2005
2045
|
);
|
|
2006
2046
|
|
|
@@ -2017,6 +2057,10 @@ describe('openWalletSession', () => {
|
|
|
2017
2057
|
message: {
|
|
2018
2058
|
btc_test_address: 'hidden-state',
|
|
2019
2059
|
session_id: 'new-session',
|
|
2060
|
+
seed_domains: [
|
|
2061
|
+
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
2062
|
+
DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
2063
|
+
],
|
|
2020
2064
|
},
|
|
2021
2065
|
};
|
|
2022
2066
|
}
|
|
@@ -2036,6 +2080,60 @@ describe('openWalletSession', () => {
|
|
|
2036
2080
|
passphraseState: 'hidden-state',
|
|
2037
2081
|
newSession: 'new-session',
|
|
2038
2082
|
});
|
|
2083
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2084
|
+
passphrase: 'host hidden wallet',
|
|
2085
|
+
on_device: false,
|
|
2086
|
+
seed_domains: CARDANO_SEED_DOMAINS,
|
|
2087
|
+
});
|
|
2088
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
2089
|
+
});
|
|
2090
|
+
|
|
2091
|
+
test('asks Cardano seed domains after Get reports a Standard-only session', async () => {
|
|
2092
|
+
const typedCall = jest.fn((request: string) => {
|
|
2093
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2094
|
+
return { message: { version: 2 } };
|
|
2095
|
+
}
|
|
2096
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
2097
|
+
return { message: {} };
|
|
2098
|
+
}
|
|
2099
|
+
if (request === 'DeviceSessionGet') {
|
|
2100
|
+
const hasCardanoAsk = typedCall.mock.calls.some(
|
|
2101
|
+
call =>
|
|
2102
|
+
call[0] === 'DeviceSessionAskPassphrase' &&
|
|
2103
|
+
Array.isArray(call[2]?.seed_domains) &&
|
|
2104
|
+
call[2].seed_domains.includes(DeviceSessionSeedDomain.SeedDomain_Cardano)
|
|
2105
|
+
);
|
|
2106
|
+
return {
|
|
2107
|
+
message: {
|
|
2108
|
+
btc_test_address: 'hidden-state',
|
|
2109
|
+
session_id: 'new-session',
|
|
2110
|
+
seed_domains: hasCardanoAsk
|
|
2111
|
+
? [
|
|
2112
|
+
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
2113
|
+
DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
2114
|
+
]
|
|
2115
|
+
: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2116
|
+
},
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2120
|
+
});
|
|
2121
|
+
const device = createDevice({
|
|
2122
|
+
typedCall,
|
|
2123
|
+
promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' }),
|
|
2124
|
+
});
|
|
2125
|
+
device.passphraseState = 'hidden-state';
|
|
2126
|
+
deviceWalletSessionStore.set('device-1', 'hidden-state', 'cached-session');
|
|
2127
|
+
|
|
2128
|
+
await getProtocolV2WalletSession(device as any, {
|
|
2129
|
+
expectedPassphraseState: 'hidden-state',
|
|
2130
|
+
deriveCardano: true,
|
|
2131
|
+
});
|
|
2132
|
+
|
|
2133
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
2134
|
+
session_id: 'cached-session',
|
|
2135
|
+
btc_test_address: 'hidden-state',
|
|
2136
|
+
});
|
|
2039
2137
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2040
2138
|
passphrase: 'host hidden wallet',
|
|
2041
2139
|
on_device: false,
|
|
@@ -2046,7 +2144,267 @@ describe('openWalletSession', () => {
|
|
|
2046
2144
|
});
|
|
2047
2145
|
});
|
|
2048
2146
|
|
|
2049
|
-
test('
|
|
2147
|
+
test('uses empty AskPassphrase to add Cardano on an Attach PIN session', async () => {
|
|
2148
|
+
const typedCall = jest.fn((request: string) => {
|
|
2149
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2150
|
+
return { message: { version: 2 } };
|
|
2151
|
+
}
|
|
2152
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
2153
|
+
return { message: {} };
|
|
2154
|
+
}
|
|
2155
|
+
if (request === 'DeviceSessionGet') {
|
|
2156
|
+
const askedCardano = typedCall.mock.calls.some(
|
|
2157
|
+
call =>
|
|
2158
|
+
call[0] === 'DeviceSessionAskPassphrase' &&
|
|
2159
|
+
Array.isArray(call[2]?.seed_domains) &&
|
|
2160
|
+
call[2].seed_domains.includes(DeviceSessionSeedDomain.SeedDomain_Cardano)
|
|
2161
|
+
);
|
|
2162
|
+
return {
|
|
2163
|
+
message: {
|
|
2164
|
+
btc_test_address: 'attach-state',
|
|
2165
|
+
session_id: 'attach-session',
|
|
2166
|
+
seed_domains: askedCardano ? CARDANO_SEED_DOMAINS : STANDARD_SEED_DOMAINS,
|
|
2167
|
+
},
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2171
|
+
});
|
|
2172
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'should-not-ask' });
|
|
2173
|
+
const device = createDevice({
|
|
2174
|
+
typedCall,
|
|
2175
|
+
promptPassphrase,
|
|
2176
|
+
unlockedAttachPin: true,
|
|
2177
|
+
});
|
|
2178
|
+
|
|
2179
|
+
await expect(
|
|
2180
|
+
getProtocolV2WalletSession(device as any, {
|
|
2181
|
+
readCurrentAttachPinSession: true,
|
|
2182
|
+
deriveCardano: true,
|
|
2183
|
+
})
|
|
2184
|
+
).resolves.toMatchObject({
|
|
2185
|
+
passphraseState: 'attach-state',
|
|
2186
|
+
newSession: 'attach-session',
|
|
2187
|
+
unlockedAttachPin: true,
|
|
2188
|
+
});
|
|
2189
|
+
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2190
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2191
|
+
passphrase: '',
|
|
2192
|
+
on_device: false,
|
|
2193
|
+
seed_domains: CARDANO_SEED_DOMAINS,
|
|
2194
|
+
});
|
|
2195
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
2196
|
+
expect(
|
|
2197
|
+
typedCall.mock.calls
|
|
2198
|
+
.filter(call => call[0] === 'DeviceSessionGet')
|
|
2199
|
+
.every(call => !('seed_domains' in (call[2] ?? {})))
|
|
2200
|
+
).toBe(true);
|
|
2201
|
+
});
|
|
2202
|
+
|
|
2203
|
+
test('uses empty AskPassphrase after selecting Attach PIN for Cardano intent', async () => {
|
|
2204
|
+
const typedCall = jest.fn((request: string) => {
|
|
2205
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2206
|
+
return { message: { version: 2 } };
|
|
2207
|
+
}
|
|
2208
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
2209
|
+
return { message: {} };
|
|
2210
|
+
}
|
|
2211
|
+
if (request === 'DeviceSessionGet') {
|
|
2212
|
+
return {
|
|
2213
|
+
message: {
|
|
2214
|
+
btc_test_address: 'attach-state',
|
|
2215
|
+
session_id: 'attach-session',
|
|
2216
|
+
seed_domains: CARDANO_SEED_DOMAINS,
|
|
2217
|
+
},
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2221
|
+
});
|
|
2222
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ attachPinOnDevice: true });
|
|
2223
|
+
const device = createDevice({ typedCall, promptPassphrase });
|
|
2224
|
+
device.features.attachToPinEnabled = true;
|
|
2225
|
+
|
|
2226
|
+
await expect(
|
|
2227
|
+
getProtocolV2WalletSession(device as any, {
|
|
2228
|
+
forceWalletSelection: true,
|
|
2229
|
+
deriveCardano: true,
|
|
2230
|
+
})
|
|
2231
|
+
).resolves.toMatchObject({
|
|
2232
|
+
passphraseState: 'attach-state',
|
|
2233
|
+
newSession: 'attach-session',
|
|
2234
|
+
unlockedAttachPin: true,
|
|
2235
|
+
});
|
|
2236
|
+
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
2237
|
+
expect(device.unlockDevice).toHaveBeenCalledWith(
|
|
2238
|
+
DeviceSessionPinType.AttachToPin,
|
|
2239
|
+
expect.objectContaining({ emitUiEvent: false })
|
|
2240
|
+
);
|
|
2241
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2242
|
+
passphrase: '',
|
|
2243
|
+
on_device: false,
|
|
2244
|
+
seed_domains: CARDANO_SEED_DOMAINS,
|
|
2245
|
+
});
|
|
2246
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
2247
|
+
expect(
|
|
2248
|
+
typedCall.mock.calls
|
|
2249
|
+
.filter(call => call[0] === 'DeviceSessionGet')
|
|
2250
|
+
.every(call => !('seed_domains' in (call[2] ?? {})))
|
|
2251
|
+
).toBe(true);
|
|
2252
|
+
});
|
|
2253
|
+
|
|
2254
|
+
test('still locks before a passphrase picker after Attach PIN Cardano empty Ask', async () => {
|
|
2255
|
+
const typedCall = jest.fn((request: string) => {
|
|
2256
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2257
|
+
return { message: { version: 2 } };
|
|
2258
|
+
}
|
|
2259
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
2260
|
+
return { message: {} };
|
|
2261
|
+
}
|
|
2262
|
+
if (request === 'DeviceSessionGet') {
|
|
2263
|
+
return {
|
|
2264
|
+
message: {
|
|
2265
|
+
btc_test_address: 'attach-state',
|
|
2266
|
+
session_id: 'attach-session',
|
|
2267
|
+
seed_domains: CARDANO_SEED_DOMAINS,
|
|
2268
|
+
},
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2272
|
+
});
|
|
2273
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'should-not-ask' });
|
|
2274
|
+
const device = createDevice({
|
|
2275
|
+
typedCall,
|
|
2276
|
+
promptPassphrase,
|
|
2277
|
+
unlockedAttachPin: true,
|
|
2278
|
+
});
|
|
2279
|
+
|
|
2280
|
+
await getProtocolV2WalletSession(device as any, {
|
|
2281
|
+
readCurrentAttachPinSession: true,
|
|
2282
|
+
deriveCardano: true,
|
|
2283
|
+
});
|
|
2284
|
+
await expect(
|
|
2285
|
+
getProtocolV2WalletSession(device as any, { forceWalletSelection: true })
|
|
2286
|
+
).rejects.toMatchObject({
|
|
2287
|
+
errorCode: HardwareErrorCode.DeviceCheckUnlockTypeError,
|
|
2288
|
+
});
|
|
2289
|
+
expect(device.lockDevice).toHaveBeenCalled();
|
|
2290
|
+
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2291
|
+
});
|
|
2292
|
+
|
|
2293
|
+
test('uses a second Get for Cardano when passphrase protection is off', async () => {
|
|
2294
|
+
const typedCall = jest.fn((request: string) => {
|
|
2295
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2296
|
+
return { message: { version: 2 } };
|
|
2297
|
+
}
|
|
2298
|
+
if (request === 'DeviceSessionGet') {
|
|
2299
|
+
const getCount = typedCall.mock.calls.filter(call => call[0] === 'DeviceSessionGet').length;
|
|
2300
|
+
return {
|
|
2301
|
+
message: {
|
|
2302
|
+
btc_test_address: 'standard-state',
|
|
2303
|
+
session_id: 'standard-session',
|
|
2304
|
+
seed_domains: getCount > 1 ? CARDANO_SEED_DOMAINS : STANDARD_SEED_DOMAINS,
|
|
2305
|
+
},
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2309
|
+
});
|
|
2310
|
+
const device = createDevice({
|
|
2311
|
+
typedCall,
|
|
2312
|
+
passphraseProtection: false,
|
|
2313
|
+
});
|
|
2314
|
+
|
|
2315
|
+
await expect(
|
|
2316
|
+
getProtocolV2WalletSession(device as any, {
|
|
2317
|
+
onlyMainPin: true,
|
|
2318
|
+
deriveCardano: true,
|
|
2319
|
+
})
|
|
2320
|
+
).resolves.toMatchObject({
|
|
2321
|
+
passphraseState: 'standard-state',
|
|
2322
|
+
newSession: 'standard-session',
|
|
2323
|
+
});
|
|
2324
|
+
expect(typedCall).not.toHaveBeenCalledWith(
|
|
2325
|
+
'DeviceSessionAskPassphrase',
|
|
2326
|
+
'Success',
|
|
2327
|
+
expect.anything()
|
|
2328
|
+
);
|
|
2329
|
+
expect(typedCall.mock.calls.filter(call => call[0] === 'DeviceSessionGet')).toHaveLength(2);
|
|
2330
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
2331
|
+
});
|
|
2332
|
+
|
|
2333
|
+
test('fails closed when Cardano fallback still lacks Cardano', async () => {
|
|
2334
|
+
const typedCall = jest.fn((request: string) => {
|
|
2335
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2336
|
+
return { message: { version: 2 } };
|
|
2337
|
+
}
|
|
2338
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
2339
|
+
return { message: {} };
|
|
2340
|
+
}
|
|
2341
|
+
if (request === 'DeviceSessionGet') {
|
|
2342
|
+
return {
|
|
2343
|
+
message: {
|
|
2344
|
+
btc_test_address: 'hidden-state',
|
|
2345
|
+
session_id: 'hidden-session',
|
|
2346
|
+
seed_domains: STANDARD_SEED_DOMAINS,
|
|
2347
|
+
},
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2351
|
+
});
|
|
2352
|
+
const device = createDevice({
|
|
2353
|
+
typedCall,
|
|
2354
|
+
promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' }),
|
|
2355
|
+
});
|
|
2356
|
+
deviceWalletSessionStore.set('device-1', 'hidden-state', 'cached-session');
|
|
2357
|
+
|
|
2358
|
+
await expect(
|
|
2359
|
+
getProtocolV2WalletSession(device as any, {
|
|
2360
|
+
expectedPassphraseState: 'hidden-state',
|
|
2361
|
+
deriveCardano: true,
|
|
2362
|
+
})
|
|
2363
|
+
).rejects.toMatchObject({
|
|
2364
|
+
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
2365
|
+
});
|
|
2366
|
+
expect(device.clearInternalState).toHaveBeenCalled();
|
|
2367
|
+
});
|
|
2368
|
+
|
|
2369
|
+
test('locks before selecting a passphrase wallet from an Attach PIN session', async () => {
|
|
2370
|
+
const typedCall = jest.fn((request: string) => {
|
|
2371
|
+
if (request === 'ProtocolInfoRequest') {
|
|
2372
|
+
return { message: { version: 2 } };
|
|
2373
|
+
}
|
|
2374
|
+
if (request === 'DeviceStatusGet') {
|
|
2375
|
+
return {
|
|
2376
|
+
message: {
|
|
2377
|
+
device_id: 'device-1',
|
|
2378
|
+
unlocked: true,
|
|
2379
|
+
passphrase_enabled: true,
|
|
2380
|
+
unlocked_by_attach_to_pin: true,
|
|
2381
|
+
},
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
2385
|
+
});
|
|
2386
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'should-not-ask' });
|
|
2387
|
+
const device = createDevice({
|
|
2388
|
+
typedCall,
|
|
2389
|
+
promptPassphrase,
|
|
2390
|
+
unlockedAttachPin: true,
|
|
2391
|
+
});
|
|
2392
|
+
|
|
2393
|
+
await expect(
|
|
2394
|
+
getProtocolV2WalletSession(device as any, { forceWalletSelection: true })
|
|
2395
|
+
).rejects.toMatchObject({
|
|
2396
|
+
errorCode: HardwareErrorCode.DeviceCheckUnlockTypeError,
|
|
2397
|
+
});
|
|
2398
|
+
expect(device.lockDevice).toHaveBeenCalled();
|
|
2399
|
+
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2400
|
+
expect(typedCall).not.toHaveBeenCalledWith(
|
|
2401
|
+
'DeviceSessionAskPassphrase',
|
|
2402
|
+
'Success',
|
|
2403
|
+
expect.anything()
|
|
2404
|
+
);
|
|
2405
|
+
});
|
|
2406
|
+
|
|
2407
|
+
test('asks Standard-only seed domains when deriveCardano is false', async () => {
|
|
2050
2408
|
const typedCall = jest.fn((request: string) => {
|
|
2051
2409
|
if (request === 'ProtocolInfoRequest') {
|
|
2052
2410
|
return { message: { version: 2 } };
|
|
@@ -2076,7 +2434,7 @@ describe('openWalletSession', () => {
|
|
|
2076
2434
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2077
2435
|
passphrase: 'host hidden wallet',
|
|
2078
2436
|
on_device: false,
|
|
2079
|
-
seed_domains: [],
|
|
2437
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2080
2438
|
});
|
|
2081
2439
|
});
|
|
2082
2440
|
});
|
|
@@ -7,6 +7,7 @@ import { encode as encodeJpeg } from 'jpeg-js';
|
|
|
7
7
|
import {
|
|
8
8
|
DeviceRebootType,
|
|
9
9
|
DeviceSessionPinType,
|
|
10
|
+
DeviceSessionSeedDomain,
|
|
10
11
|
DeviceSettingsPage,
|
|
11
12
|
DeviceType,
|
|
12
13
|
} from '@onekeyfe/hd-transport';
|
|
@@ -1115,7 +1116,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1115
1116
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1116
1117
|
passphrase: '',
|
|
1117
1118
|
on_device: false,
|
|
1118
|
-
seed_domains: [],
|
|
1119
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1119
1120
|
});
|
|
1120
1121
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
1121
1122
|
device.passphraseState = 'state-1';
|
|
@@ -1538,7 +1539,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1538
1539
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
1539
1540
|
passphrase: 'host hidden wallet',
|
|
1540
1541
|
on_device: false,
|
|
1541
|
-
seed_domains: [],
|
|
1542
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1542
1543
|
});
|
|
1543
1544
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
1544
1545
|
});
|
|
@@ -1768,7 +1769,11 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1768
1769
|
[
|
|
1769
1770
|
'DeviceSessionAskPassphrase',
|
|
1770
1771
|
'Success',
|
|
1771
|
-
{
|
|
1772
|
+
{
|
|
1773
|
+
passphrase: 'host hidden wallet',
|
|
1774
|
+
on_device: false,
|
|
1775
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
1776
|
+
},
|
|
1772
1777
|
],
|
|
1773
1778
|
['DeviceStatusGet', 'DeviceStatus', {}],
|
|
1774
1779
|
['DeviceSessionGet', 'DeviceSession', {}],
|
|
@@ -2230,7 +2235,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2230
2235
|
firmwareVersion: '4.15.0',
|
|
2231
2236
|
passphraseProtection: true,
|
|
2232
2237
|
sessionId: 'feature-session',
|
|
2233
|
-
unlockedAttachPin:
|
|
2238
|
+
unlockedAttachPin: false,
|
|
2234
2239
|
};
|
|
2235
2240
|
const typedCall = jest
|
|
2236
2241
|
.fn()
|
|
@@ -2585,7 +2590,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2585
2590
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
2586
2591
|
passphrase: 'host hidden wallet',
|
|
2587
2592
|
on_device: false,
|
|
2588
|
-
seed_domains: [],
|
|
2593
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2589
2594
|
});
|
|
2590
2595
|
expect(typedCall).toHaveBeenLastCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
2591
2596
|
});
|
|
@@ -2671,7 +2676,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2671
2676
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2672
2677
|
passphrase: 'host hidden wallet',
|
|
2673
2678
|
on_device: false,
|
|
2674
|
-
seed_domains: [],
|
|
2679
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2675
2680
|
});
|
|
2676
2681
|
expect(typedCall).toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
2677
2682
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
@@ -2780,7 +2785,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2780
2785
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {
|
|
2781
2786
|
passphrase: '',
|
|
2782
2787
|
on_device: false,
|
|
2783
|
-
seed_domains: [],
|
|
2788
|
+
seed_domains: [DeviceSessionSeedDomain.SeedDomain_Standard],
|
|
2784
2789
|
});
|
|
2785
2790
|
expect(typedCall).toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
2786
2791
|
expect(typedCall.mock.calls.filter(([request]) => request === 'DeviceStatusGet')).toHaveLength(
|
package/dist/index.js
CHANGED
|
@@ -39413,6 +39413,11 @@ var nested = {
|
|
|
39413
39413
|
btc_test_address: {
|
|
39414
39414
|
type: "string",
|
|
39415
39415
|
id: 2
|
|
39416
|
+
},
|
|
39417
|
+
seed_domains: {
|
|
39418
|
+
rule: "repeated",
|
|
39419
|
+
type: "DeviceSessionSeedDomain",
|
|
39420
|
+
id: 3
|
|
39416
39421
|
}
|
|
39417
39422
|
}
|
|
39418
39423
|
},
|
|
@@ -41794,12 +41799,14 @@ const negotiateEventlessWalletSession = (device) => __awaiter(void 0, void 0, vo
|
|
|
41794
41799
|
yield device.ensureProtocolV2RuntimeContext();
|
|
41795
41800
|
});
|
|
41796
41801
|
const getDeviceSession = (device, request) => __awaiter(void 0, void 0, void 0, function* () { return device.commands.typedCall('DeviceSessionGet', 'DeviceSession', request); });
|
|
41797
|
-
const
|
|
41798
|
-
|
|
41799
|
-
|
|
41800
|
-
|
|
41801
|
-
|
|
41802
|
-
|
|
41802
|
+
const STANDARD_SEED_DOMAINS = [hdTransport.DeviceSessionSeedDomain.SeedDomain_Standard];
|
|
41803
|
+
const CARDANO_SEED_DOMAINS = [
|
|
41804
|
+
hdTransport.DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
41805
|
+
hdTransport.DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
41806
|
+
];
|
|
41807
|
+
const buildDeviceSessionSeedDomains = (deriveCardano) => deriveCardano === true ? CARDANO_SEED_DOMAINS : STANDARD_SEED_DOMAINS;
|
|
41808
|
+
const deviceSessionHasCardano = (message) => Array.isArray(message.seed_domains) &&
|
|
41809
|
+
message.seed_domains.includes(hdTransport.DeviceSessionSeedDomain.SeedDomain_Cardano);
|
|
41803
41810
|
const buildDeviceSessionGetRequest = ({ sessionId, expectedPassphraseState, } = {}) => (Object.assign(Object.assign({}, (sessionId ? { session_id: sessionId } : {})), (expectedPassphraseState ? { btc_test_address: expectedPassphraseState } : {})));
|
|
41804
41811
|
const askDevicePassphrase = (device, requestPayload, deriveCardano, onStatusRefreshed) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41805
41812
|
yield device.commands.typedCall('DeviceSessionAskPassphrase', 'Success', Object.assign(Object.assign({}, requestPayload), { seed_domains: buildDeviceSessionSeedDomains(deriveCardano) }));
|
|
@@ -41840,7 +41847,14 @@ const selectDeviceSession = (device, expectedPassphraseState, deriveCardano, onS
|
|
|
41840
41847
|
interaction: attachPinInteraction,
|
|
41841
41848
|
});
|
|
41842
41849
|
onStatusRefreshed === null || onStatusRefreshed === void 0 ? void 0 : onStatusRefreshed();
|
|
41843
|
-
|
|
41850
|
+
if (deriveCardano === true) {
|
|
41851
|
+
yield askDevicePassphrase(device, { passphrase: '', on_device: false }, true, onStatusRefreshed);
|
|
41852
|
+
if (device.features) {
|
|
41853
|
+
device.features.unlockedAttachPin = true;
|
|
41854
|
+
}
|
|
41855
|
+
}
|
|
41856
|
+
const attachPinSession = yield getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
41857
|
+
return Object.assign(attachPinSession, { viaAttachPin: true });
|
|
41844
41858
|
}
|
|
41845
41859
|
if (hasHostPassphrase) {
|
|
41846
41860
|
yield askDevicePassphrase(device, {
|
|
@@ -41855,10 +41869,16 @@ const selectDeviceSession = (device, expectedPassphraseState, deriveCardano, onS
|
|
|
41855
41869
|
return getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
41856
41870
|
});
|
|
41857
41871
|
function getProtocolV2WalletSession(device, options) {
|
|
41858
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
41872
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
41859
41873
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41860
41874
|
const forceWalletSelection = (options === null || options === void 0 ? void 0 : options.forceWalletSelection) === true || (options === null || options === void 0 ? void 0 : options.initSession) === true;
|
|
41861
41875
|
const readCurrentAttachPinSession = (options === null || options === void 0 ? void 0 : options.readCurrentAttachPinSession) === true;
|
|
41876
|
+
const sessionIsAttachPinWallet = (session) => {
|
|
41877
|
+
var _a;
|
|
41878
|
+
return readCurrentAttachPinSession ||
|
|
41879
|
+
(session === null || session === void 0 ? void 0 : session.viaAttachPin) === true ||
|
|
41880
|
+
((_a = device.features) === null || _a === void 0 ? void 0 : _a.unlockedAttachPin) === true;
|
|
41881
|
+
};
|
|
41862
41882
|
if (forceWalletSelection) {
|
|
41863
41883
|
if (options.onlyMainPin) {
|
|
41864
41884
|
(_a = device.clearStandardInternalState) === null || _a === void 0 ? void 0 : _a.call(device);
|
|
@@ -41903,8 +41923,20 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41903
41923
|
device.clearInternalState();
|
|
41904
41924
|
}
|
|
41905
41925
|
};
|
|
41926
|
+
const sessionGetRequest = ({ sessionId, expectedPassphraseState: passphraseState, } = {}) => buildDeviceSessionGetRequest({
|
|
41927
|
+
sessionId,
|
|
41928
|
+
expectedPassphraseState: passphraseState,
|
|
41929
|
+
});
|
|
41930
|
+
const askEmptyPassphraseAndGet = ({ deriveCardano, keepAttachPin, } = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
41931
|
+
yield askDevicePassphrase(device, { passphrase: '', on_device: false }, deriveCardano, markWalletStatusRefreshed);
|
|
41932
|
+
if (keepAttachPin && device.features) {
|
|
41933
|
+
device.features.unlockedAttachPin = true;
|
|
41934
|
+
}
|
|
41935
|
+
const session = yield getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
41936
|
+
return keepAttachPin ? Object.assign(session, { viaAttachPin: true }) : session;
|
|
41937
|
+
});
|
|
41906
41938
|
const rejectMismatchedAttachPinWallet = () => __awaiter(this, void 0, void 0, function* () {
|
|
41907
|
-
var
|
|
41939
|
+
var _m;
|
|
41908
41940
|
const features = yield refreshProtocolV2DeviceStatus(device);
|
|
41909
41941
|
markWalletStatusRefreshed();
|
|
41910
41942
|
if (features.unlockedAttachPin !== true) {
|
|
@@ -41913,10 +41945,10 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41913
41945
|
try {
|
|
41914
41946
|
yield device.lockDevice();
|
|
41915
41947
|
}
|
|
41916
|
-
catch (
|
|
41948
|
+
catch (_o) {
|
|
41917
41949
|
}
|
|
41918
41950
|
if (options === null || options === void 0 ? void 0 : options.rejectAttachPinForMainWallet) {
|
|
41919
|
-
(
|
|
41951
|
+
(_m = device.clearStandardInternalState) === null || _m === void 0 ? void 0 : _m.call(device);
|
|
41920
41952
|
device.clearInternalState();
|
|
41921
41953
|
}
|
|
41922
41954
|
else {
|
|
@@ -41924,6 +41956,16 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41924
41956
|
}
|
|
41925
41957
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
41926
41958
|
});
|
|
41959
|
+
const lockAttachPinBeforePassphraseSelection = () => __awaiter(this, void 0, void 0, function* () {
|
|
41960
|
+
var _p;
|
|
41961
|
+
if (readCurrentAttachPinSession || (options === null || options === void 0 ? void 0 : options.onlyMainPin)) {
|
|
41962
|
+
return;
|
|
41963
|
+
}
|
|
41964
|
+
if (((_p = device.features) === null || _p === void 0 ? void 0 : _p.unlockedAttachPin) !== true) {
|
|
41965
|
+
return;
|
|
41966
|
+
}
|
|
41967
|
+
yield rejectMismatchedAttachPinWallet();
|
|
41968
|
+
});
|
|
41927
41969
|
if ((options === null || options === void 0 ? void 0 : options.onlyMainPin) && options.rejectAttachPinForMainWallet) {
|
|
41928
41970
|
yield rejectMismatchedAttachPinWallet();
|
|
41929
41971
|
}
|
|
@@ -41940,8 +41982,8 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41940
41982
|
}
|
|
41941
41983
|
});
|
|
41942
41984
|
const selectStandardWallet = () => __awaiter(this, void 0, void 0, function* () {
|
|
41943
|
-
var
|
|
41944
|
-
if (((
|
|
41985
|
+
var _q;
|
|
41986
|
+
if (((_q = device.features) === null || _q === void 0 ? void 0 : _q.passphraseProtection) === true) {
|
|
41945
41987
|
yield selectMainPin();
|
|
41946
41988
|
yield askDevicePassphrase(device, {
|
|
41947
41989
|
passphrase: '',
|
|
@@ -41963,7 +42005,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41963
42005
|
device.clearInternalState();
|
|
41964
42006
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
41965
42007
|
}
|
|
41966
|
-
response = yield getDeviceSession(device,
|
|
42008
|
+
response = yield getDeviceSession(device, sessionGetRequest());
|
|
41967
42009
|
}
|
|
41968
42010
|
else if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
|
|
41969
42011
|
expectedPassphraseState = cachedStandardSession === null || cachedStandardSession === void 0 ? void 0 : cachedStandardSession.passphraseState;
|
|
@@ -41972,7 +42014,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41972
42014
|
if (options === null || options === void 0 ? void 0 : options.selectMainWalletBeforeRestore) {
|
|
41973
42015
|
yield selectMainPin();
|
|
41974
42016
|
}
|
|
41975
|
-
response = yield getDeviceSession(device,
|
|
42017
|
+
response = yield getDeviceSession(device, sessionGetRequest({
|
|
41976
42018
|
sessionId: cachedStandardSession.sessionId,
|
|
41977
42019
|
expectedPassphraseState,
|
|
41978
42020
|
}));
|
|
@@ -41988,12 +42030,12 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41988
42030
|
}
|
|
41989
42031
|
if (!response) {
|
|
41990
42032
|
yield selectStandardWallet();
|
|
41991
|
-
response = yield getDeviceSession(device,
|
|
42033
|
+
response = yield getDeviceSession(device, sessionGetRequest());
|
|
41992
42034
|
}
|
|
41993
42035
|
}
|
|
41994
42036
|
else if (cachedSessionId && expectedPassphraseState) {
|
|
41995
42037
|
try {
|
|
41996
|
-
response = yield getDeviceSession(device,
|
|
42038
|
+
response = yield getDeviceSession(device, sessionGetRequest({
|
|
41997
42039
|
sessionId: cachedSessionId,
|
|
41998
42040
|
expectedPassphraseState,
|
|
41999
42041
|
}));
|
|
@@ -42009,7 +42051,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42009
42051
|
}
|
|
42010
42052
|
else if (expectedPassphraseState) {
|
|
42011
42053
|
try {
|
|
42012
|
-
response = yield getDeviceSession(device,
|
|
42054
|
+
response = yield getDeviceSession(device, sessionGetRequest({
|
|
42013
42055
|
expectedPassphraseState,
|
|
42014
42056
|
}));
|
|
42015
42057
|
}
|
|
@@ -42024,6 +42066,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42024
42066
|
device.clearInternalState();
|
|
42025
42067
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
|
|
42026
42068
|
}
|
|
42069
|
+
yield lockAttachPinBeforePassphraseSelection();
|
|
42027
42070
|
response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano, markWalletStatusRefreshed);
|
|
42028
42071
|
}
|
|
42029
42072
|
let { message } = response;
|
|
@@ -42049,10 +42092,11 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42049
42092
|
if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
|
|
42050
42093
|
(_h = device.clearStandardInternalState) === null || _h === void 0 ? void 0 : _h.call(device);
|
|
42051
42094
|
yield selectStandardWallet();
|
|
42052
|
-
response = yield getDeviceSession(device,
|
|
42095
|
+
response = yield getDeviceSession(device, sessionGetRequest());
|
|
42053
42096
|
}
|
|
42054
42097
|
else {
|
|
42055
42098
|
device.clearInternalState();
|
|
42099
|
+
yield lockAttachPinBeforePassphraseSelection();
|
|
42056
42100
|
response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano, markWalletStatusRefreshed);
|
|
42057
42101
|
}
|
|
42058
42102
|
message = response.message;
|
|
@@ -42074,6 +42118,50 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42074
42118
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
42075
42119
|
}
|
|
42076
42120
|
}
|
|
42121
|
+
if ((options === null || options === void 0 ? void 0 : options.deriveCardano) === true && !deviceSessionHasCardano(message)) {
|
|
42122
|
+
if (options === null || options === void 0 ? void 0 : options.resumeOnly) {
|
|
42123
|
+
device.clearInternalState();
|
|
42124
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
|
|
42125
|
+
}
|
|
42126
|
+
resumed = false;
|
|
42127
|
+
const previousAddress = message.btc_test_address;
|
|
42128
|
+
if (sessionIsAttachPinWallet(response)) {
|
|
42129
|
+
response = yield askEmptyPassphraseAndGet({ deriveCardano: true, keepAttachPin: true });
|
|
42130
|
+
}
|
|
42131
|
+
else if (((_k = device.features) === null || _k === void 0 ? void 0 : _k.passphraseProtection) === false) {
|
|
42132
|
+
response = yield getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
42133
|
+
}
|
|
42134
|
+
else if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
|
|
42135
|
+
yield selectMainPin();
|
|
42136
|
+
response = yield askEmptyPassphraseAndGet({ deriveCardano: true });
|
|
42137
|
+
}
|
|
42138
|
+
else {
|
|
42139
|
+
yield lockAttachPinBeforePassphraseSelection();
|
|
42140
|
+
response = yield selectDeviceSession(device, expectedPassphraseState, true, markWalletStatusRefreshed);
|
|
42141
|
+
}
|
|
42142
|
+
message = response.message;
|
|
42143
|
+
try {
|
|
42144
|
+
assertCompleteDeviceSession(message);
|
|
42145
|
+
}
|
|
42146
|
+
catch (error) {
|
|
42147
|
+
if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
|
|
42148
|
+
(_l = device.clearStandardInternalState) === null || _l === void 0 ? void 0 : _l.call(device);
|
|
42149
|
+
}
|
|
42150
|
+
else {
|
|
42151
|
+
device.clearInternalState();
|
|
42152
|
+
}
|
|
42153
|
+
throw error;
|
|
42154
|
+
}
|
|
42155
|
+
if (previousAddress && previousAddress !== message.btc_test_address) {
|
|
42156
|
+
yield rejectMismatchedAttachPinWallet();
|
|
42157
|
+
clearCurrentWalletSession();
|
|
42158
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
42159
|
+
}
|
|
42160
|
+
if (!deviceSessionHasCardano(message)) {
|
|
42161
|
+
clearCurrentWalletSession();
|
|
42162
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
|
|
42163
|
+
}
|
|
42164
|
+
}
|
|
42077
42165
|
const internalStateArgs = [
|
|
42078
42166
|
true,
|
|
42079
42167
|
message.btc_test_address,
|
|
@@ -42088,7 +42176,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42088
42176
|
device.updateInternalState(...internalStateArgs);
|
|
42089
42177
|
}
|
|
42090
42178
|
let unlockedAttachPin;
|
|
42091
|
-
if (readCurrentAttachPinSession) {
|
|
42179
|
+
if (readCurrentAttachPinSession || sessionIsAttachPinWallet(response)) {
|
|
42092
42180
|
unlockedAttachPin = true;
|
|
42093
42181
|
}
|
|
42094
42182
|
else if (mainPinAuthenticated) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walletSession.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/walletSession.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAuBlD,wBAAsB,6BAA6B,CAAC,MAAM,EAAE,MAAM,0DAGjE;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE,MAAM,qCAGjE;AAED,wBAAsB,qCAAqC,CAAC,MAAM,EAAE,MAAM,oBAgBzE;
|
|
1
|
+
{"version":3,"file":"walletSession.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/walletSession.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAuBlD,wBAAsB,6BAA6B,CAAC,MAAM,EAAE,MAAM,0DAGjE;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE,MAAM,qCAGjE;AAED,wBAAsB,qCAAqC,CAAC,MAAM,EAAE,MAAM,oBAgBzE;AA8JD,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;;;;;;GAuXF;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,MAAM,EACd,uBAAuB,EAAE,MAAM,EAC/B,aAAa,CAAC,EAAE,OAAO;;;;;;GAOxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.2-alpha.
|
|
3
|
+
"version": "1.2.2-alpha.6",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.2-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.2-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.6",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.6",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"buffer": "^6.0.3",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"@types/w3c-web-usb": "^1.0.10",
|
|
47
47
|
"@types/web-bluetooth": "^0.0.21"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "538d5371d9369747beabf68c5dc7a617531bace2"
|
|
50
50
|
}
|
|
@@ -394,7 +394,7 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
|
|
|
394
394
|
// requested standard or hidden wallet before sending its device command.
|
|
395
395
|
const useEmptyPassphrase = this.payload.useEmptyPassphrase === true;
|
|
396
396
|
// Nested Cardano methods opt in to [Standard, Cardano] if Ask rebuilds.
|
|
397
|
-
// Other chains
|
|
397
|
+
// Other chains stay Standard-only.
|
|
398
398
|
const deriveCardano = method.name.startsWith('cardano') ? true : undefined;
|
|
399
399
|
const shouldResumeWalletSession = useEmptyPassphrase || !!this.payload.passphraseState;
|
|
400
400
|
if (this.device.isProtocolV2() && shouldResumeWalletSession) {
|
package/src/core/index.ts
CHANGED
|
@@ -105,8 +105,8 @@ function resolveDeriveCardano(method: BaseMethod): boolean | undefined {
|
|
|
105
105
|
if (method.name.startsWith('cardano')) {
|
|
106
106
|
return true;
|
|
107
107
|
}
|
|
108
|
-
// V1 Initialize only
|
|
109
|
-
//
|
|
108
|
+
// V1 Initialize only sends derive_cardano on an explicit true.
|
|
109
|
+
// V2 AskPassphrase maps true to [Standard, Cardano] and anything else to [Standard].
|
|
110
110
|
if (method.payload?.deriveCardano === true) {
|
|
111
111
|
return true;
|
|
112
112
|
}
|
|
@@ -12334,6 +12334,11 @@
|
|
|
12334
12334
|
"btc_test_address": {
|
|
12335
12335
|
"type": "string",
|
|
12336
12336
|
"id": 2
|
|
12337
|
+
},
|
|
12338
|
+
"seed_domains": {
|
|
12339
|
+
"rule": "repeated",
|
|
12340
|
+
"type": "DeviceSessionSeedDomain",
|
|
12341
|
+
"id": 3
|
|
12337
12342
|
}
|
|
12338
12343
|
}
|
|
12339
12344
|
},
|
|
@@ -63,21 +63,20 @@ 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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const STANDARD_SEED_DOMAINS = [DeviceSessionSeedDomain.SeedDomain_Standard];
|
|
67
|
+
const CARDANO_SEED_DOMAINS = [
|
|
68
|
+
DeviceSessionSeedDomain.SeedDomain_Standard,
|
|
69
|
+
DeviceSessionSeedDomain.SeedDomain_Cardano,
|
|
70
|
+
];
|
|
71
|
+
|
|
71
72
|
const buildDeviceSessionSeedDomains = (deriveCardano?: boolean): DeviceSessionSeedDomain[] =>
|
|
72
|
-
deriveCardano === true
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Seed domains are applied when creating a passphrase session, not when reading/resuming one.
|
|
80
|
-
// Current firmware rejects unknown DeviceSessionGet fields, including leftover seed_domains.
|
|
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.
|
|
81
80
|
const buildDeviceSessionGetRequest = ({
|
|
82
81
|
sessionId,
|
|
83
82
|
expectedPassphraseState,
|
|
@@ -170,7 +169,22 @@ const selectDeviceSession = async (
|
|
|
170
169
|
interaction: attachPinInteraction,
|
|
171
170
|
});
|
|
172
171
|
onStatusRefreshed?.();
|
|
173
|
-
|
|
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 });
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
if (hasHostPassphrase) {
|
|
@@ -220,6 +234,10 @@ export async function getProtocolV2WalletSession(
|
|
|
220
234
|
const forceWalletSelection =
|
|
221
235
|
options?.forceWalletSelection === true || options?.initSession === true;
|
|
222
236
|
const readCurrentAttachPinSession = options?.readCurrentAttachPinSession === true;
|
|
237
|
+
const sessionIsAttachPinWallet = (session?: { viaAttachPin?: boolean }) =>
|
|
238
|
+
readCurrentAttachPinSession ||
|
|
239
|
+
session?.viaAttachPin === true ||
|
|
240
|
+
device.features?.unlockedAttachPin === true;
|
|
223
241
|
|
|
224
242
|
if (forceWalletSelection) {
|
|
225
243
|
if (options.onlyMainPin) {
|
|
@@ -270,6 +288,38 @@ export async function getProtocolV2WalletSession(
|
|
|
270
288
|
}
|
|
271
289
|
};
|
|
272
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
|
+
|
|
273
323
|
const rejectMismatchedAttachPinWallet = async () => {
|
|
274
324
|
const features = await refreshProtocolV2DeviceStatus(device);
|
|
275
325
|
markWalletStatusRefreshed();
|
|
@@ -291,6 +341,19 @@ export async function getProtocolV2WalletSession(
|
|
|
291
341
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
292
342
|
};
|
|
293
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
|
+
|
|
294
357
|
if (options?.onlyMainPin && options.rejectAttachPinForMainWallet) {
|
|
295
358
|
await rejectMismatchedAttachPinWallet();
|
|
296
359
|
}
|
|
@@ -341,7 +404,7 @@ export async function getProtocolV2WalletSession(
|
|
|
341
404
|
device.clearInternalState();
|
|
342
405
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
343
406
|
}
|
|
344
|
-
response = await getDeviceSession(device,
|
|
407
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
345
408
|
} else if (options?.onlyMainPin) {
|
|
346
409
|
expectedPassphraseState = cachedStandardSession?.passphraseState;
|
|
347
410
|
if (cachedStandardSession) {
|
|
@@ -351,7 +414,7 @@ export async function getProtocolV2WalletSession(
|
|
|
351
414
|
}
|
|
352
415
|
response = await getDeviceSession(
|
|
353
416
|
device,
|
|
354
|
-
|
|
417
|
+
sessionGetRequest({
|
|
355
418
|
sessionId: cachedStandardSession.sessionId,
|
|
356
419
|
expectedPassphraseState,
|
|
357
420
|
})
|
|
@@ -368,13 +431,13 @@ export async function getProtocolV2WalletSession(
|
|
|
368
431
|
|
|
369
432
|
if (!response) {
|
|
370
433
|
await selectStandardWallet();
|
|
371
|
-
response = await getDeviceSession(device,
|
|
434
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
372
435
|
}
|
|
373
436
|
} else if (cachedSessionId && expectedPassphraseState) {
|
|
374
437
|
try {
|
|
375
438
|
response = await getDeviceSession(
|
|
376
439
|
device,
|
|
377
|
-
|
|
440
|
+
sessionGetRequest({
|
|
378
441
|
sessionId: cachedSessionId,
|
|
379
442
|
expectedPassphraseState,
|
|
380
443
|
})
|
|
@@ -391,7 +454,7 @@ export async function getProtocolV2WalletSession(
|
|
|
391
454
|
try {
|
|
392
455
|
response = await getDeviceSession(
|
|
393
456
|
device,
|
|
394
|
-
|
|
457
|
+
sessionGetRequest({
|
|
395
458
|
expectedPassphraseState,
|
|
396
459
|
})
|
|
397
460
|
);
|
|
@@ -407,6 +470,7 @@ export async function getProtocolV2WalletSession(
|
|
|
407
470
|
device.clearInternalState();
|
|
408
471
|
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
409
472
|
}
|
|
473
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
410
474
|
response = await selectDeviceSession(
|
|
411
475
|
device,
|
|
412
476
|
expectedPassphraseState,
|
|
@@ -436,9 +500,10 @@ export async function getProtocolV2WalletSession(
|
|
|
436
500
|
if (options?.onlyMainPin) {
|
|
437
501
|
device.clearStandardInternalState?.();
|
|
438
502
|
await selectStandardWallet();
|
|
439
|
-
response = await getDeviceSession(device,
|
|
503
|
+
response = await getDeviceSession(device, sessionGetRequest());
|
|
440
504
|
} else {
|
|
441
505
|
device.clearInternalState();
|
|
506
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
442
507
|
response = await selectDeviceSession(
|
|
443
508
|
device,
|
|
444
509
|
expectedPassphraseState,
|
|
@@ -464,6 +529,54 @@ export async function getProtocolV2WalletSession(
|
|
|
464
529
|
}
|
|
465
530
|
}
|
|
466
531
|
|
|
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.
|
|
535
|
+
if (options?.deriveCardano === true && !deviceSessionHasCardano(message)) {
|
|
536
|
+
if (options?.resumeOnly) {
|
|
537
|
+
device.clearInternalState();
|
|
538
|
+
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
539
|
+
}
|
|
540
|
+
resumed = false;
|
|
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) {
|
|
545
|
+
response = await getDeviceSession(device, buildDeviceSessionGetRequest());
|
|
546
|
+
} else if (options?.onlyMainPin) {
|
|
547
|
+
await selectMainPin();
|
|
548
|
+
response = await askEmptyPassphraseAndGet({ deriveCardano: true });
|
|
549
|
+
} else {
|
|
550
|
+
await lockAttachPinBeforePassphraseSelection();
|
|
551
|
+
response = await selectDeviceSession(
|
|
552
|
+
device,
|
|
553
|
+
expectedPassphraseState,
|
|
554
|
+
true,
|
|
555
|
+
markWalletStatusRefreshed
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
message = response.message;
|
|
559
|
+
try {
|
|
560
|
+
assertCompleteDeviceSession(message);
|
|
561
|
+
} catch (error) {
|
|
562
|
+
if (options?.onlyMainPin) {
|
|
563
|
+
device.clearStandardInternalState?.();
|
|
564
|
+
} else {
|
|
565
|
+
device.clearInternalState();
|
|
566
|
+
}
|
|
567
|
+
throw error;
|
|
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
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
467
580
|
const internalStateArgs = [
|
|
468
581
|
true,
|
|
469
582
|
message.btc_test_address,
|
|
@@ -478,7 +591,7 @@ export async function getProtocolV2WalletSession(
|
|
|
478
591
|
}
|
|
479
592
|
|
|
480
593
|
let unlockedAttachPin: boolean | undefined;
|
|
481
|
-
if (readCurrentAttachPinSession) {
|
|
594
|
+
if (readCurrentAttachPinSession || sessionIsAttachPinWallet(response)) {
|
|
482
595
|
unlockedAttachPin = true;
|
|
483
596
|
} else if (mainPinAuthenticated) {
|
|
484
597
|
unlockedAttachPin = false;
|