@onekeyfe/hd-core 1.2.2-alpha.8 → 1.2.2
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/README.md +1 -1
- package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +503 -10
- package/__tests__/DeviceCommands.test.ts +254 -1
- package/__tests__/core-error-output.test.ts +169 -1
- package/__tests__/device-lifecycle-events.test.ts +432 -15
- package/__tests__/logBlockEvent.test.ts +45 -122
- package/__tests__/open-wallet-session-error-response.test.ts +2 -2
- package/__tests__/open-wallet-session.test.ts +94 -363
- package/__tests__/protocol-v2.test.ts +132 -2
- package/__tests__/public-device-state-api.test.ts +2 -7
- package/__tests__/search-devices.test.ts +196 -8
- package/__tests__/sol-sign-offchain-message.test.ts +64 -0
- package/dist/api/FirmwareUpdateV4.d.ts +1 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetFeatures.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts +2 -15
- package/dist/api/SearchDevices.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/AllNetworkGetAddress.d.ts +2 -0
- package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +7 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts.map +1 -1
- package/dist/api/device/DeviceVerify.d.ts.map +1 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts +3 -0
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +1 -1
- package/dist/data-manager/TransportManager.d.ts +2 -0
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +2 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +5 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +35 -30
- package/dist/index.js +620 -325
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/getFeatures.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +1 -10
- package/dist/types/api/openWalletSession.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/params.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +9 -4
- package/src/api/GetFeatures.ts +1 -0
- package/src/api/GetPassphraseState.ts +1 -0
- package/src/api/OpenWalletSession.ts +7 -77
- package/src/api/SearchDevices.ts +121 -27
- package/src/api/UploadPortfolio.ts +5 -4
- package/src/api/allnetwork/AllNetworkGetAddress.ts +79 -45
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +95 -24
- package/src/api/allnetwork/AllNetworkGetAddressByLoop.ts +3 -0
- package/src/api/device/DeviceVerify.ts +8 -0
- package/src/api/solana/SolSignOffchainMessage.ts +44 -4
- package/src/core/RequestQueue.ts +36 -1
- package/src/core/index.ts +178 -63
- package/src/data/messages/messages-protocol-v2.json +49 -33
- package/src/data/messages/messages.json +8 -5
- package/src/data-manager/TransportManager.ts +14 -3
- package/src/device/Device.ts +58 -27
- package/src/device/DeviceCommands.ts +29 -2
- package/src/events/logBlockEvent.ts +6 -75
- package/src/protocols/protocol-v2/walletSession.ts +18 -2
- package/src/types/api/getFeatures.ts +2 -1
- package/src/types/api/getPassphraseState.ts +2 -5
- package/src/types/api/openWalletSession.ts +7 -19
- package/src/types/api/protocolV2.ts +3 -4
- package/src/types/api/solSignOffchainMessage.ts +2 -0
- package/src/types/params.ts +7 -0
|
@@ -26,12 +26,16 @@ jest.mock('../src/data/config', () => ({
|
|
|
26
26
|
const createDevice = ({
|
|
27
27
|
passphraseProtection = true,
|
|
28
28
|
unlockedAttachPin = false,
|
|
29
|
+
refreshedUnlocked = true,
|
|
30
|
+
refreshedPassphraseProtection = passphraseProtection,
|
|
29
31
|
refreshedUnlockedAttachPin = unlockedAttachPin,
|
|
30
32
|
typedCall = jest.fn(),
|
|
31
33
|
promptPassphrase = jest.fn(),
|
|
32
34
|
}: {
|
|
33
35
|
passphraseProtection?: boolean;
|
|
34
36
|
unlockedAttachPin?: boolean;
|
|
37
|
+
refreshedUnlocked?: boolean;
|
|
38
|
+
refreshedPassphraseProtection?: boolean;
|
|
35
39
|
refreshedUnlockedAttachPin?: boolean;
|
|
36
40
|
typedCall?: jest.Mock;
|
|
37
41
|
promptPassphrase?: jest.Mock;
|
|
@@ -50,11 +54,11 @@ const createDevice = ({
|
|
|
50
54
|
return {
|
|
51
55
|
message: {
|
|
52
56
|
device_id: 'device-1',
|
|
53
|
-
unlocked:
|
|
57
|
+
unlocked: refreshedUnlocked,
|
|
54
58
|
attach_to_pin_enabled: unlockedAttachPin,
|
|
55
59
|
unlocked_attach_pin: refreshedUnlockedAttachPin,
|
|
56
60
|
unlocked_by_attach_to_pin: refreshedUnlockedAttachPin,
|
|
57
|
-
passphrase_enabled:
|
|
61
|
+
passphrase_enabled: refreshedPassphraseProtection,
|
|
58
62
|
},
|
|
59
63
|
};
|
|
60
64
|
}
|
|
@@ -95,6 +99,8 @@ const createDevice = ({
|
|
|
95
99
|
unlockDevice: jest.fn(),
|
|
96
100
|
updateProtocolV2Status: jest.fn((status: Record<string, unknown>) => {
|
|
97
101
|
device.features.unlocked = status.unlocked ?? device.features.unlocked;
|
|
102
|
+
device.features.passphraseProtection =
|
|
103
|
+
status.passphrase_enabled ?? device.features.passphraseProtection;
|
|
98
104
|
device.features.attachToPinEnabled =
|
|
99
105
|
status.attach_to_pin_enabled ?? device.features.attachToPinEnabled;
|
|
100
106
|
device.features.unlockedAttachPin =
|
|
@@ -182,6 +188,65 @@ describe('openWalletSession', () => {
|
|
|
182
188
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
|
|
183
189
|
});
|
|
184
190
|
|
|
191
|
+
test('refreshes stale wallet status before accepting an only-Main-PIN session', async () => {
|
|
192
|
+
let attachPinSelected = true;
|
|
193
|
+
const typedCall = jest.fn((request: string) => {
|
|
194
|
+
if (request === 'ProtocolInfoRequest') {
|
|
195
|
+
return { message: { version: 2 } };
|
|
196
|
+
}
|
|
197
|
+
if (request === 'DeviceSessionGet') {
|
|
198
|
+
return {
|
|
199
|
+
message: {
|
|
200
|
+
btc_test_address: 'standard-state',
|
|
201
|
+
session_id: 'standard-session',
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (request === 'DeviceSessionAskPassphrase') {
|
|
206
|
+
return { message: {} };
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
209
|
+
});
|
|
210
|
+
const device = createDevice({
|
|
211
|
+
passphraseProtection: false,
|
|
212
|
+
unlockedAttachPin: false,
|
|
213
|
+
typedCall,
|
|
214
|
+
});
|
|
215
|
+
device.commands.typedCall.mockImplementation((request: string, ...args: unknown[]) => {
|
|
216
|
+
if (request === 'DeviceStatusGet') {
|
|
217
|
+
return {
|
|
218
|
+
message: {
|
|
219
|
+
device_id: 'device-1',
|
|
220
|
+
unlocked: true,
|
|
221
|
+
attach_to_pin_enabled: true,
|
|
222
|
+
unlocked_attach_pin: attachPinSelected,
|
|
223
|
+
unlocked_by_attach_to_pin: attachPinSelected,
|
|
224
|
+
passphrase_enabled: true,
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return typedCall(request, ...args);
|
|
229
|
+
});
|
|
230
|
+
device.unlockDevice.mockImplementation(() => {
|
|
231
|
+
attachPinSelected = false;
|
|
232
|
+
device.features.unlockedAttachPin = false;
|
|
233
|
+
return Promise.resolve(device.features);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await expect(
|
|
237
|
+
getProtocolV2WalletSession(device as any, { onlyMainPin: true })
|
|
238
|
+
).resolves.toMatchObject({
|
|
239
|
+
unlockedAttachPin: false,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
expect(device.commands.typedCall).toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
243
|
+
expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main, {
|
|
244
|
+
source: 'wallet-session-coordinator',
|
|
245
|
+
reason: 'open-wallet',
|
|
246
|
+
deviceOnly: true,
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
185
250
|
test('still requires Main PIN when a cached standard session resolves to another wallet', async () => {
|
|
186
251
|
let sessionGetCount = 0;
|
|
187
252
|
const typedCall = jest.fn((request: string) => {
|
|
@@ -267,8 +332,7 @@ describe('openWalletSession', () => {
|
|
|
267
332
|
}
|
|
268
333
|
throw new Error(`Unexpected request: ${request}`);
|
|
269
334
|
});
|
|
270
|
-
const device = createDevice({ typedCall });
|
|
271
|
-
device.features.unlockedAttachPin = true;
|
|
335
|
+
const device = createDevice({ refreshedUnlockedAttachPin: true, typedCall });
|
|
272
336
|
|
|
273
337
|
await getProtocolV2WalletSession(device as any, { onlyMainPin: true });
|
|
274
338
|
|
|
@@ -918,45 +982,6 @@ describe('openWalletSession', () => {
|
|
|
918
982
|
);
|
|
919
983
|
});
|
|
920
984
|
|
|
921
|
-
test('uses an explicit wallet binding to resume on Protocol V2', async () => {
|
|
922
|
-
const typedCall = jest
|
|
923
|
-
.fn()
|
|
924
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
925
|
-
.mockResolvedValueOnce({
|
|
926
|
-
message: {
|
|
927
|
-
btc_test_address: 'hidden-state',
|
|
928
|
-
session_id: 'renewed-session',
|
|
929
|
-
},
|
|
930
|
-
});
|
|
931
|
-
const promptPassphrase = jest.fn();
|
|
932
|
-
const method = new OpenWalletSession({
|
|
933
|
-
payload: {
|
|
934
|
-
method: 'openWalletSession',
|
|
935
|
-
connectId: 'connect-id',
|
|
936
|
-
mode: 'resume-hidden',
|
|
937
|
-
deviceId: 'device-1',
|
|
938
|
-
passphraseState: 'hidden-state',
|
|
939
|
-
},
|
|
940
|
-
});
|
|
941
|
-
method.init();
|
|
942
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
943
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
944
|
-
|
|
945
|
-
await expect(method.run()).resolves.toEqual({
|
|
946
|
-
protocol: 'V2',
|
|
947
|
-
walletType: 'hidden',
|
|
948
|
-
deviceId: 'device-1',
|
|
949
|
-
passphraseState: 'hidden-state',
|
|
950
|
-
resumed: true,
|
|
951
|
-
});
|
|
952
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
953
|
-
session_id: 'known-session',
|
|
954
|
-
btc_test_address: 'hidden-state',
|
|
955
|
-
...standardSessionGet,
|
|
956
|
-
});
|
|
957
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
958
|
-
});
|
|
959
|
-
|
|
960
985
|
test.each([
|
|
961
986
|
{
|
|
962
987
|
mode: 'standard',
|
|
@@ -971,12 +996,6 @@ describe('openWalletSession', () => {
|
|
|
971
996
|
deviceId: 'device-1',
|
|
972
997
|
passphraseState: 'hidden-state',
|
|
973
998
|
},
|
|
974
|
-
{
|
|
975
|
-
mode: 'resume-hidden',
|
|
976
|
-
deviceId: 'device-1',
|
|
977
|
-
passphraseState: 'hidden-state',
|
|
978
|
-
initSession: false,
|
|
979
|
-
},
|
|
980
999
|
])('rejects legacy parameters combined with explicit mode: %o', params => {
|
|
981
1000
|
const method = new OpenWalletSession({
|
|
982
1001
|
payload: {
|
|
@@ -1012,63 +1031,7 @@ describe('openWalletSession', () => {
|
|
|
1012
1031
|
}
|
|
1013
1032
|
);
|
|
1014
1033
|
|
|
1015
|
-
test('
|
|
1016
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
1017
|
-
type: 'PassphraseState',
|
|
1018
|
-
message: {
|
|
1019
|
-
passphrase_state: 'hidden-state',
|
|
1020
|
-
session_id: 'known-session',
|
|
1021
|
-
unlocked_attach_pin: false,
|
|
1022
|
-
},
|
|
1023
|
-
});
|
|
1024
|
-
const method = new OpenWalletSession({
|
|
1025
|
-
payload: {
|
|
1026
|
-
method: 'openWalletSession',
|
|
1027
|
-
connectId: 'connect-id',
|
|
1028
|
-
mode: 'resume-hidden',
|
|
1029
|
-
deviceId: 'device-1',
|
|
1030
|
-
passphraseState: 'hidden-state',
|
|
1031
|
-
},
|
|
1032
|
-
});
|
|
1033
|
-
method.init();
|
|
1034
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1035
|
-
const device = createDevice({ typedCall });
|
|
1036
|
-
device.isProtocolV2 = () => false;
|
|
1037
|
-
device.features = {
|
|
1038
|
-
...device.features,
|
|
1039
|
-
deviceId: 'device-1',
|
|
1040
|
-
unlocked: true,
|
|
1041
|
-
sessionId: null,
|
|
1042
|
-
};
|
|
1043
|
-
device.getCurrentFirmwareVersionString = () => '4.15.0';
|
|
1044
|
-
device.getCurrentDeviceType = () => EDeviceType.Pro;
|
|
1045
|
-
device.getFeatures = jest.fn();
|
|
1046
|
-
method.device = device as any;
|
|
1047
|
-
|
|
1048
|
-
await expect(method.run()).resolves.toMatchObject({
|
|
1049
|
-
protocol: 'V1',
|
|
1050
|
-
walletType: 'hidden',
|
|
1051
|
-
passphraseState: 'hidden-state',
|
|
1052
|
-
resumed: true,
|
|
1053
|
-
});
|
|
1054
|
-
expect(device.initialize).toHaveBeenCalledWith({
|
|
1055
|
-
deviceId: 'device-1',
|
|
1056
|
-
passphraseState: 'hidden-state',
|
|
1057
|
-
});
|
|
1058
|
-
expect(typedCall).toHaveBeenCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
1059
|
-
passphrase_state: 'hidden-state',
|
|
1060
|
-
});
|
|
1061
|
-
});
|
|
1062
|
-
|
|
1063
|
-
test('rejects a Protocol V1 resume when the device returns another hidden wallet', async () => {
|
|
1064
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
1065
|
-
type: 'PassphraseState',
|
|
1066
|
-
message: {
|
|
1067
|
-
passphrase_state: 'other-hidden-state',
|
|
1068
|
-
session_id: 'other-session',
|
|
1069
|
-
unlocked_attach_pin: false,
|
|
1070
|
-
},
|
|
1071
|
-
});
|
|
1034
|
+
test('rejects the removed resume-hidden mode', () => {
|
|
1072
1035
|
const method = new OpenWalletSession({
|
|
1073
1036
|
payload: {
|
|
1074
1037
|
method: 'openWalletSession',
|
|
@@ -1076,28 +1039,15 @@ describe('openWalletSession', () => {
|
|
|
1076
1039
|
mode: 'resume-hidden',
|
|
1077
1040
|
deviceId: 'device-1',
|
|
1078
1041
|
passphraseState: 'hidden-state',
|
|
1079
|
-
},
|
|
1042
|
+
} as any,
|
|
1080
1043
|
});
|
|
1081
|
-
method.init();
|
|
1082
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1083
|
-
const device = createDevice({ typedCall });
|
|
1084
|
-
device.isProtocolV2 = () => false;
|
|
1085
|
-
device.features = {
|
|
1086
|
-
...device.features,
|
|
1087
|
-
deviceId: 'device-1',
|
|
1088
|
-
unlocked: true,
|
|
1089
|
-
sessionId: null,
|
|
1090
|
-
};
|
|
1091
|
-
device.getCurrentFirmwareVersionString = () => '4.15.0';
|
|
1092
|
-
device.getCurrentDeviceType = () => EDeviceType.Pro;
|
|
1093
|
-
device.getFeatures = jest.fn();
|
|
1094
|
-
method.device = device as any;
|
|
1095
1044
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1045
|
+
expect(() => method.init()).toThrow(
|
|
1046
|
+
expect.objectContaining({
|
|
1047
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
1048
|
+
message: 'Parameter [mode] must be one of standard or select-hidden.',
|
|
1049
|
+
})
|
|
1050
|
+
);
|
|
1101
1051
|
});
|
|
1102
1052
|
|
|
1103
1053
|
test('opens the standard wallet without selecting a hidden wallet', async () => {
|
|
@@ -1157,7 +1107,7 @@ describe('openWalletSession', () => {
|
|
|
1157
1107
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'standard' },
|
|
1158
1108
|
});
|
|
1159
1109
|
method.init();
|
|
1160
|
-
const device = createDevice({ typedCall });
|
|
1110
|
+
const device = createDevice({ refreshedUnlocked: false, typedCall });
|
|
1161
1111
|
device.features.unlocked = false;
|
|
1162
1112
|
device.getDeviceState = jest
|
|
1163
1113
|
.fn()
|
|
@@ -1257,6 +1207,7 @@ describe('openWalletSession', () => {
|
|
|
1257
1207
|
});
|
|
1258
1208
|
|
|
1259
1209
|
test('switches from Attach PIN to Main PIN before opening the standard wallet', async () => {
|
|
1210
|
+
let attachPinSelected = true;
|
|
1260
1211
|
const typedCall = jest
|
|
1261
1212
|
.fn()
|
|
1262
1213
|
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
@@ -1273,6 +1224,21 @@ describe('openWalletSession', () => {
|
|
|
1273
1224
|
method.init();
|
|
1274
1225
|
const device = createDevice({ typedCall });
|
|
1275
1226
|
device.features.unlockedAttachPin = true;
|
|
1227
|
+
device.commands.typedCall.mockImplementation((request: string, ...args: unknown[]) => {
|
|
1228
|
+
if (request === 'DeviceStatusGet') {
|
|
1229
|
+
return {
|
|
1230
|
+
message: {
|
|
1231
|
+
device_id: 'device-1',
|
|
1232
|
+
unlocked: true,
|
|
1233
|
+
attach_to_pin_enabled: true,
|
|
1234
|
+
unlocked_attach_pin: attachPinSelected,
|
|
1235
|
+
unlocked_by_attach_to_pin: attachPinSelected,
|
|
1236
|
+
passphrase_enabled: true,
|
|
1237
|
+
},
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
return typedCall(request, ...args);
|
|
1241
|
+
});
|
|
1276
1242
|
device.getDeviceState = jest
|
|
1277
1243
|
.fn()
|
|
1278
1244
|
.mockResolvedValueOnce({
|
|
@@ -1292,6 +1258,7 @@ describe('openWalletSession', () => {
|
|
|
1292
1258
|
},
|
|
1293
1259
|
});
|
|
1294
1260
|
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
1261
|
+
attachPinSelected = false;
|
|
1295
1262
|
device.features.unlockedAttachPin = false;
|
|
1296
1263
|
return Promise.resolve(device.features);
|
|
1297
1264
|
});
|
|
@@ -1801,242 +1768,6 @@ describe('openWalletSession', () => {
|
|
|
1801
1768
|
}
|
|
1802
1769
|
);
|
|
1803
1770
|
|
|
1804
|
-
test('resumes a known hidden wallet without prompting or device selection', async () => {
|
|
1805
|
-
const typedCall = jest
|
|
1806
|
-
.fn()
|
|
1807
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1808
|
-
.mockResolvedValueOnce({
|
|
1809
|
-
message: {
|
|
1810
|
-
btc_test_address: 'hidden-state',
|
|
1811
|
-
session_id: 'renewed-session',
|
|
1812
|
-
},
|
|
1813
|
-
});
|
|
1814
|
-
const promptPassphrase = jest.fn();
|
|
1815
|
-
const method = new OpenWalletSession({
|
|
1816
|
-
payload: {
|
|
1817
|
-
method: 'openWalletSession',
|
|
1818
|
-
connectId: 'connect-id',
|
|
1819
|
-
mode: 'resume-hidden',
|
|
1820
|
-
deviceId: 'device-1',
|
|
1821
|
-
passphraseState: 'hidden-state',
|
|
1822
|
-
},
|
|
1823
|
-
});
|
|
1824
|
-
method.init();
|
|
1825
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1826
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
1827
|
-
|
|
1828
|
-
await expect(method.run()).resolves.toEqual({
|
|
1829
|
-
protocol: 'V2',
|
|
1830
|
-
walletType: 'hidden',
|
|
1831
|
-
deviceId: 'device-1',
|
|
1832
|
-
passphraseState: 'hidden-state',
|
|
1833
|
-
resumed: true,
|
|
1834
|
-
});
|
|
1835
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1836
|
-
session_id: 'known-session',
|
|
1837
|
-
btc_test_address: 'hidden-state',
|
|
1838
|
-
...standardSessionGet,
|
|
1839
|
-
});
|
|
1840
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1841
|
-
});
|
|
1842
|
-
|
|
1843
|
-
test('validates a locked Protocol V2 resume binding after deviceId refresh', async () => {
|
|
1844
|
-
const typedCall = jest
|
|
1845
|
-
.fn()
|
|
1846
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1847
|
-
.mockResolvedValueOnce({
|
|
1848
|
-
message: {
|
|
1849
|
-
btc_test_address: 'hidden-state',
|
|
1850
|
-
session_id: 'renewed-session',
|
|
1851
|
-
},
|
|
1852
|
-
});
|
|
1853
|
-
const method = new OpenWalletSession({
|
|
1854
|
-
payload: {
|
|
1855
|
-
method: 'openWalletSession',
|
|
1856
|
-
connectId: 'connect-id',
|
|
1857
|
-
mode: 'resume-hidden',
|
|
1858
|
-
deviceId: 'device-1',
|
|
1859
|
-
passphraseState: 'hidden-state',
|
|
1860
|
-
},
|
|
1861
|
-
});
|
|
1862
|
-
method.init();
|
|
1863
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1864
|
-
const device = createDevice({ typedCall });
|
|
1865
|
-
device.features.unlocked = false;
|
|
1866
|
-
device.getDeviceState = jest
|
|
1867
|
-
.fn()
|
|
1868
|
-
.mockResolvedValueOnce({
|
|
1869
|
-
identity: { deviceId: undefined },
|
|
1870
|
-
status: { unlocked: false, passphraseProtection: true },
|
|
1871
|
-
})
|
|
1872
|
-
.mockResolvedValueOnce({
|
|
1873
|
-
identity: { deviceId: 'device-1' },
|
|
1874
|
-
status: {
|
|
1875
|
-
unlocked: true,
|
|
1876
|
-
passphraseProtection: true,
|
|
1877
|
-
unlockedAttachPin: false,
|
|
1878
|
-
},
|
|
1879
|
-
});
|
|
1880
|
-
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
1881
|
-
device.features.unlocked = true;
|
|
1882
|
-
return Promise.resolve(device.features);
|
|
1883
|
-
});
|
|
1884
|
-
method.device = device as any;
|
|
1885
|
-
|
|
1886
|
-
await expect(method.run()).resolves.toMatchObject({
|
|
1887
|
-
protocol: 'V2',
|
|
1888
|
-
walletType: 'hidden',
|
|
1889
|
-
deviceId: 'device-1',
|
|
1890
|
-
passphraseState: 'hidden-state',
|
|
1891
|
-
resumed: true,
|
|
1892
|
-
});
|
|
1893
|
-
expect(device.unlockDevice).toHaveBeenCalledTimes(1);
|
|
1894
|
-
expect(device.getDeviceState).toHaveBeenCalledTimes(2);
|
|
1895
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1896
|
-
session_id: 'known-session',
|
|
1897
|
-
btc_test_address: 'hidden-state',
|
|
1898
|
-
...standardSessionGet,
|
|
1899
|
-
});
|
|
1900
|
-
const sessionGetCall = typedCall.mock.calls.findIndex(
|
|
1901
|
-
([requestName]) => requestName === 'DeviceSessionGet'
|
|
1902
|
-
);
|
|
1903
|
-
expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
|
|
1904
|
-
typedCall.mock.invocationCallOrder[sessionGetCall]
|
|
1905
|
-
);
|
|
1906
|
-
});
|
|
1907
|
-
|
|
1908
|
-
test('rejects a Protocol V2 resume when the refreshed deviceId does not match', async () => {
|
|
1909
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
1910
|
-
message: {
|
|
1911
|
-
btc_test_address: 'hidden-state',
|
|
1912
|
-
session_id: 'renewed-session',
|
|
1913
|
-
},
|
|
1914
|
-
});
|
|
1915
|
-
const method = new OpenWalletSession({
|
|
1916
|
-
payload: {
|
|
1917
|
-
method: 'openWalletSession',
|
|
1918
|
-
connectId: 'connect-id',
|
|
1919
|
-
mode: 'resume-hidden',
|
|
1920
|
-
deviceId: 'device-1',
|
|
1921
|
-
passphraseState: 'hidden-state',
|
|
1922
|
-
},
|
|
1923
|
-
});
|
|
1924
|
-
method.init();
|
|
1925
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1926
|
-
const device = createDevice({ typedCall });
|
|
1927
|
-
device.features.unlocked = false;
|
|
1928
|
-
device.getDeviceState = jest
|
|
1929
|
-
.fn()
|
|
1930
|
-
.mockResolvedValueOnce({
|
|
1931
|
-
identity: { deviceId: undefined },
|
|
1932
|
-
status: { passphraseProtection: true },
|
|
1933
|
-
})
|
|
1934
|
-
.mockResolvedValueOnce({
|
|
1935
|
-
identity: { deviceId: 'other-device' },
|
|
1936
|
-
status: {
|
|
1937
|
-
unlocked: true,
|
|
1938
|
-
passphraseProtection: true,
|
|
1939
|
-
unlockedAttachPin: false,
|
|
1940
|
-
},
|
|
1941
|
-
});
|
|
1942
|
-
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
1943
|
-
device.features.unlocked = true;
|
|
1944
|
-
return Promise.resolve(device.features);
|
|
1945
|
-
});
|
|
1946
|
-
method.device = device as any;
|
|
1947
|
-
|
|
1948
|
-
await expect(method.run()).rejects.toMatchObject({
|
|
1949
|
-
errorCode: HardwareErrorCode.DeviceCheckDeviceIdError,
|
|
1950
|
-
});
|
|
1951
|
-
expect(typedCall).not.toHaveBeenCalled();
|
|
1952
|
-
expect(device.clearInternalState).not.toHaveBeenCalled();
|
|
1953
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
|
|
1954
|
-
});
|
|
1955
|
-
|
|
1956
|
-
test('reselects the expected hidden wallet when a cached Protocol V2 session is invalid', async () => {
|
|
1957
|
-
const typedCall = jest
|
|
1958
|
-
.fn()
|
|
1959
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1960
|
-
.mockRejectedValueOnce(
|
|
1961
|
-
Object.assign(new Error('Invalid session'), {
|
|
1962
|
-
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
1963
|
-
})
|
|
1964
|
-
)
|
|
1965
|
-
.mockResolvedValueOnce({ message: {} })
|
|
1966
|
-
.mockResolvedValueOnce({
|
|
1967
|
-
message: {
|
|
1968
|
-
btc_test_address: 'hidden-state',
|
|
1969
|
-
session_id: 'renewed-session',
|
|
1970
|
-
},
|
|
1971
|
-
});
|
|
1972
|
-
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
|
|
1973
|
-
const method = new OpenWalletSession({
|
|
1974
|
-
payload: {
|
|
1975
|
-
method: 'openWalletSession',
|
|
1976
|
-
connectId: 'connect-id',
|
|
1977
|
-
mode: 'resume-hidden',
|
|
1978
|
-
deviceId: 'device-1',
|
|
1979
|
-
passphraseState: 'hidden-state',
|
|
1980
|
-
},
|
|
1981
|
-
});
|
|
1982
|
-
method.init();
|
|
1983
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
|
|
1984
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
1985
|
-
|
|
1986
|
-
await expect(method.run()).resolves.toEqual({
|
|
1987
|
-
protocol: 'V2',
|
|
1988
|
-
walletType: 'hidden',
|
|
1989
|
-
deviceId: 'device-1',
|
|
1990
|
-
passphraseState: 'hidden-state',
|
|
1991
|
-
resumed: false,
|
|
1992
|
-
});
|
|
1993
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1994
|
-
session_id: 'expired-session',
|
|
1995
|
-
btc_test_address: 'hidden-state',
|
|
1996
|
-
...standardSessionGet,
|
|
1997
|
-
});
|
|
1998
|
-
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
1999
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
|
|
2000
|
-
});
|
|
2001
|
-
|
|
2002
|
-
test('selects the expected hidden wallet when Protocol V2 has no cached session', async () => {
|
|
2003
|
-
const typedCall = jest
|
|
2004
|
-
.fn()
|
|
2005
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
2006
|
-
.mockResolvedValueOnce({
|
|
2007
|
-
message: {
|
|
2008
|
-
btc_test_address: 'hidden-state',
|
|
2009
|
-
session_id: 'new-session',
|
|
2010
|
-
},
|
|
2011
|
-
});
|
|
2012
|
-
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
|
|
2013
|
-
const method = new OpenWalletSession({
|
|
2014
|
-
payload: {
|
|
2015
|
-
method: 'openWalletSession',
|
|
2016
|
-
connectId: 'connect-id',
|
|
2017
|
-
mode: 'resume-hidden',
|
|
2018
|
-
deviceId: 'device-1',
|
|
2019
|
-
passphraseState: 'hidden-state',
|
|
2020
|
-
},
|
|
2021
|
-
});
|
|
2022
|
-
method.init();
|
|
2023
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
2024
|
-
|
|
2025
|
-
await expect(method.run()).resolves.toEqual({
|
|
2026
|
-
protocol: 'V2',
|
|
2027
|
-
walletType: 'hidden',
|
|
2028
|
-
deviceId: 'device-1',
|
|
2029
|
-
passphraseState: 'hidden-state',
|
|
2030
|
-
resumed: false,
|
|
2031
|
-
});
|
|
2032
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
2033
|
-
btc_test_address: 'hidden-state',
|
|
2034
|
-
...standardSessionGet,
|
|
2035
|
-
});
|
|
2036
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2037
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('new-session');
|
|
2038
|
-
});
|
|
2039
|
-
|
|
2040
1771
|
test.each([false, true])(
|
|
2041
1772
|
'openWalletSession does not thread CommonParams.deriveCardano: %s',
|
|
2042
1773
|
async deriveCardano => {
|