@onekeyfe/hd-core 1.2.3-alpha.3 → 1.2.3-alpha.4
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__/core-error-output.test.ts +169 -1
- package/__tests__/device-lifecycle-events.test.ts +350 -2
- package/__tests__/open-wallet-session-error-response.test.ts +2 -2
- package/__tests__/open-wallet-session.test.ts +8 -411
- package/__tests__/protocol-v2.test.ts +51 -0
- package/__tests__/public-device-state-api.test.ts +2 -7
- package/__tests__/search-devices.test.ts +196 -8
- 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/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/core/RequestQueue.d.ts +1 -0
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +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/index.d.ts +17 -19
- package/dist/index.js +449 -184
- 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/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/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/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/core/RequestQueue.ts +20 -0
- package/src/core/index.ts +135 -43
- package/src/data/messages/messages-protocol-v2.json +21 -0
- package/src/data-manager/TransportManager.ts +14 -3
- package/src/device/Device.ts +58 -27
- package/src/protocols/protocol-v2/walletSession.ts +7 -0
- 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/params.ts +7 -0
|
@@ -982,45 +982,6 @@ describe('openWalletSession', () => {
|
|
|
982
982
|
);
|
|
983
983
|
});
|
|
984
984
|
|
|
985
|
-
test('uses an explicit wallet binding to resume on Protocol V2', async () => {
|
|
986
|
-
const typedCall = jest
|
|
987
|
-
.fn()
|
|
988
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
989
|
-
.mockResolvedValueOnce({
|
|
990
|
-
message: {
|
|
991
|
-
btc_test_address: 'hidden-state',
|
|
992
|
-
session_id: 'renewed-session',
|
|
993
|
-
},
|
|
994
|
-
});
|
|
995
|
-
const promptPassphrase = jest.fn();
|
|
996
|
-
const method = new OpenWalletSession({
|
|
997
|
-
payload: {
|
|
998
|
-
method: 'openWalletSession',
|
|
999
|
-
connectId: 'connect-id',
|
|
1000
|
-
mode: 'resume-hidden',
|
|
1001
|
-
deviceId: 'device-1',
|
|
1002
|
-
passphraseState: 'hidden-state',
|
|
1003
|
-
},
|
|
1004
|
-
});
|
|
1005
|
-
method.init();
|
|
1006
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1007
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
1008
|
-
|
|
1009
|
-
await expect(method.run()).resolves.toEqual({
|
|
1010
|
-
protocol: 'V2',
|
|
1011
|
-
walletType: 'hidden',
|
|
1012
|
-
deviceId: 'device-1',
|
|
1013
|
-
passphraseState: 'hidden-state',
|
|
1014
|
-
resumed: true,
|
|
1015
|
-
});
|
|
1016
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1017
|
-
session_id: 'known-session',
|
|
1018
|
-
btc_test_address: 'hidden-state',
|
|
1019
|
-
...standardSessionGet,
|
|
1020
|
-
});
|
|
1021
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1022
|
-
});
|
|
1023
|
-
|
|
1024
985
|
test.each([
|
|
1025
986
|
{
|
|
1026
987
|
mode: 'standard',
|
|
@@ -1035,12 +996,6 @@ describe('openWalletSession', () => {
|
|
|
1035
996
|
deviceId: 'device-1',
|
|
1036
997
|
passphraseState: 'hidden-state',
|
|
1037
998
|
},
|
|
1038
|
-
{
|
|
1039
|
-
mode: 'resume-hidden',
|
|
1040
|
-
deviceId: 'device-1',
|
|
1041
|
-
passphraseState: 'hidden-state',
|
|
1042
|
-
initSession: false,
|
|
1043
|
-
},
|
|
1044
999
|
])('rejects legacy parameters combined with explicit mode: %o', params => {
|
|
1045
1000
|
const method = new OpenWalletSession({
|
|
1046
1001
|
payload: {
|
|
@@ -1076,15 +1031,7 @@ describe('openWalletSession', () => {
|
|
|
1076
1031
|
}
|
|
1077
1032
|
);
|
|
1078
1033
|
|
|
1079
|
-
test('
|
|
1080
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
1081
|
-
type: 'PassphraseState',
|
|
1082
|
-
message: {
|
|
1083
|
-
passphrase_state: 'hidden-state',
|
|
1084
|
-
session_id: 'known-session',
|
|
1085
|
-
unlocked_attach_pin: false,
|
|
1086
|
-
},
|
|
1087
|
-
});
|
|
1034
|
+
test('rejects the removed resume-hidden mode', () => {
|
|
1088
1035
|
const method = new OpenWalletSession({
|
|
1089
1036
|
payload: {
|
|
1090
1037
|
method: 'openWalletSession',
|
|
@@ -1092,76 +1039,15 @@ describe('openWalletSession', () => {
|
|
|
1092
1039
|
mode: 'resume-hidden',
|
|
1093
1040
|
deviceId: 'device-1',
|
|
1094
1041
|
passphraseState: 'hidden-state',
|
|
1095
|
-
},
|
|
1096
|
-
});
|
|
1097
|
-
method.init();
|
|
1098
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1099
|
-
const device = createDevice({ typedCall });
|
|
1100
|
-
device.isProtocolV2 = () => false;
|
|
1101
|
-
device.features = {
|
|
1102
|
-
...device.features,
|
|
1103
|
-
deviceId: 'device-1',
|
|
1104
|
-
unlocked: true,
|
|
1105
|
-
sessionId: null,
|
|
1106
|
-
};
|
|
1107
|
-
device.getCurrentFirmwareVersionString = () => '4.15.0';
|
|
1108
|
-
device.getCurrentDeviceType = () => EDeviceType.Pro;
|
|
1109
|
-
device.getFeatures = jest.fn();
|
|
1110
|
-
method.device = device as any;
|
|
1111
|
-
|
|
1112
|
-
await expect(method.run()).resolves.toMatchObject({
|
|
1113
|
-
protocol: 'V1',
|
|
1114
|
-
walletType: 'hidden',
|
|
1115
|
-
passphraseState: 'hidden-state',
|
|
1116
|
-
resumed: true,
|
|
1117
|
-
});
|
|
1118
|
-
expect(device.initialize).toHaveBeenCalledWith({
|
|
1119
|
-
deviceId: 'device-1',
|
|
1120
|
-
passphraseState: 'hidden-state',
|
|
1121
|
-
});
|
|
1122
|
-
expect(typedCall).toHaveBeenCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
1123
|
-
passphrase_state: 'hidden-state',
|
|
1042
|
+
} as any,
|
|
1124
1043
|
});
|
|
1125
|
-
});
|
|
1126
1044
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
unlocked_attach_pin: false,
|
|
1134
|
-
},
|
|
1135
|
-
});
|
|
1136
|
-
const method = new OpenWalletSession({
|
|
1137
|
-
payload: {
|
|
1138
|
-
method: 'openWalletSession',
|
|
1139
|
-
connectId: 'connect-id',
|
|
1140
|
-
mode: 'resume-hidden',
|
|
1141
|
-
deviceId: 'device-1',
|
|
1142
|
-
passphraseState: 'hidden-state',
|
|
1143
|
-
},
|
|
1144
|
-
});
|
|
1145
|
-
method.init();
|
|
1146
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1147
|
-
const device = createDevice({ typedCall });
|
|
1148
|
-
device.isProtocolV2 = () => false;
|
|
1149
|
-
device.features = {
|
|
1150
|
-
...device.features,
|
|
1151
|
-
deviceId: 'device-1',
|
|
1152
|
-
unlocked: true,
|
|
1153
|
-
sessionId: null,
|
|
1154
|
-
};
|
|
1155
|
-
device.getCurrentFirmwareVersionString = () => '4.15.0';
|
|
1156
|
-
device.getCurrentDeviceType = () => EDeviceType.Pro;
|
|
1157
|
-
device.getFeatures = jest.fn();
|
|
1158
|
-
method.device = device as any;
|
|
1159
|
-
|
|
1160
|
-
await expect(method.run()).rejects.toMatchObject({
|
|
1161
|
-
errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
|
|
1162
|
-
});
|
|
1163
|
-
expect(device.clearInternalState).toHaveBeenCalledTimes(1);
|
|
1164
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
|
|
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
|
+
);
|
|
1165
1051
|
});
|
|
1166
1052
|
|
|
1167
1053
|
test('opens the standard wallet without selecting a hidden wallet', async () => {
|
|
@@ -1882,295 +1768,6 @@ describe('openWalletSession', () => {
|
|
|
1882
1768
|
}
|
|
1883
1769
|
);
|
|
1884
1770
|
|
|
1885
|
-
test('resumes a known hidden wallet without prompting or device selection', async () => {
|
|
1886
|
-
const typedCall = jest
|
|
1887
|
-
.fn()
|
|
1888
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1889
|
-
.mockResolvedValueOnce({
|
|
1890
|
-
message: {
|
|
1891
|
-
btc_test_address: 'hidden-state',
|
|
1892
|
-
session_id: 'renewed-session',
|
|
1893
|
-
},
|
|
1894
|
-
});
|
|
1895
|
-
const promptPassphrase = jest.fn();
|
|
1896
|
-
const method = new OpenWalletSession({
|
|
1897
|
-
payload: {
|
|
1898
|
-
method: 'openWalletSession',
|
|
1899
|
-
connectId: 'connect-id',
|
|
1900
|
-
mode: 'resume-hidden',
|
|
1901
|
-
deviceId: 'device-1',
|
|
1902
|
-
passphraseState: 'hidden-state',
|
|
1903
|
-
},
|
|
1904
|
-
});
|
|
1905
|
-
method.init();
|
|
1906
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1907
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
1908
|
-
|
|
1909
|
-
await expect(method.run()).resolves.toEqual({
|
|
1910
|
-
protocol: 'V2',
|
|
1911
|
-
walletType: 'hidden',
|
|
1912
|
-
deviceId: 'device-1',
|
|
1913
|
-
passphraseState: 'hidden-state',
|
|
1914
|
-
resumed: true,
|
|
1915
|
-
});
|
|
1916
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1917
|
-
session_id: 'known-session',
|
|
1918
|
-
btc_test_address: 'hidden-state',
|
|
1919
|
-
...standardSessionGet,
|
|
1920
|
-
});
|
|
1921
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1922
|
-
});
|
|
1923
|
-
|
|
1924
|
-
test('validates a locked Protocol V2 resume binding after deviceId refresh', async () => {
|
|
1925
|
-
const typedCall = jest
|
|
1926
|
-
.fn()
|
|
1927
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1928
|
-
.mockResolvedValueOnce({
|
|
1929
|
-
message: {
|
|
1930
|
-
btc_test_address: 'hidden-state',
|
|
1931
|
-
session_id: 'renewed-session',
|
|
1932
|
-
},
|
|
1933
|
-
});
|
|
1934
|
-
const method = new OpenWalletSession({
|
|
1935
|
-
payload: {
|
|
1936
|
-
method: 'openWalletSession',
|
|
1937
|
-
connectId: 'connect-id',
|
|
1938
|
-
mode: 'resume-hidden',
|
|
1939
|
-
deviceId: 'device-1',
|
|
1940
|
-
passphraseState: 'hidden-state',
|
|
1941
|
-
},
|
|
1942
|
-
});
|
|
1943
|
-
method.init();
|
|
1944
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
1945
|
-
const device = createDevice({ typedCall });
|
|
1946
|
-
device.features.unlocked = false;
|
|
1947
|
-
device.getDeviceState = jest
|
|
1948
|
-
.fn()
|
|
1949
|
-
.mockResolvedValueOnce({
|
|
1950
|
-
identity: { deviceId: undefined },
|
|
1951
|
-
status: { unlocked: false, passphraseProtection: true },
|
|
1952
|
-
})
|
|
1953
|
-
.mockResolvedValueOnce({
|
|
1954
|
-
identity: { deviceId: 'device-1' },
|
|
1955
|
-
status: {
|
|
1956
|
-
unlocked: true,
|
|
1957
|
-
passphraseProtection: true,
|
|
1958
|
-
unlockedAttachPin: false,
|
|
1959
|
-
},
|
|
1960
|
-
});
|
|
1961
|
-
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
1962
|
-
device.features.unlocked = true;
|
|
1963
|
-
return Promise.resolve(device.features);
|
|
1964
|
-
});
|
|
1965
|
-
method.device = device as any;
|
|
1966
|
-
|
|
1967
|
-
await expect(method.run()).resolves.toMatchObject({
|
|
1968
|
-
protocol: 'V2',
|
|
1969
|
-
walletType: 'hidden',
|
|
1970
|
-
deviceId: 'device-1',
|
|
1971
|
-
passphraseState: 'hidden-state',
|
|
1972
|
-
resumed: true,
|
|
1973
|
-
});
|
|
1974
|
-
expect(device.unlockDevice).toHaveBeenCalledTimes(1);
|
|
1975
|
-
expect(device.getDeviceState).toHaveBeenCalledTimes(2);
|
|
1976
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
1977
|
-
session_id: 'known-session',
|
|
1978
|
-
btc_test_address: 'hidden-state',
|
|
1979
|
-
...standardSessionGet,
|
|
1980
|
-
});
|
|
1981
|
-
const sessionGetCall = typedCall.mock.calls.findIndex(
|
|
1982
|
-
([requestName]) => requestName === 'DeviceSessionGet'
|
|
1983
|
-
);
|
|
1984
|
-
expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
|
|
1985
|
-
typedCall.mock.invocationCallOrder[sessionGetCall]
|
|
1986
|
-
);
|
|
1987
|
-
});
|
|
1988
|
-
|
|
1989
|
-
test('rejects a Protocol V2 resume when the refreshed deviceId does not match', async () => {
|
|
1990
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
1991
|
-
message: {
|
|
1992
|
-
btc_test_address: 'hidden-state',
|
|
1993
|
-
session_id: 'renewed-session',
|
|
1994
|
-
},
|
|
1995
|
-
});
|
|
1996
|
-
const method = new OpenWalletSession({
|
|
1997
|
-
payload: {
|
|
1998
|
-
method: 'openWalletSession',
|
|
1999
|
-
connectId: 'connect-id',
|
|
2000
|
-
mode: 'resume-hidden',
|
|
2001
|
-
deviceId: 'device-1',
|
|
2002
|
-
passphraseState: 'hidden-state',
|
|
2003
|
-
},
|
|
2004
|
-
});
|
|
2005
|
-
method.init();
|
|
2006
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
|
|
2007
|
-
const device = createDevice({ typedCall });
|
|
2008
|
-
device.features.unlocked = false;
|
|
2009
|
-
device.getDeviceState = jest
|
|
2010
|
-
.fn()
|
|
2011
|
-
.mockResolvedValueOnce({
|
|
2012
|
-
identity: { deviceId: undefined },
|
|
2013
|
-
status: { passphraseProtection: true },
|
|
2014
|
-
})
|
|
2015
|
-
.mockResolvedValueOnce({
|
|
2016
|
-
identity: { deviceId: 'other-device' },
|
|
2017
|
-
status: {
|
|
2018
|
-
unlocked: true,
|
|
2019
|
-
passphraseProtection: true,
|
|
2020
|
-
unlockedAttachPin: false,
|
|
2021
|
-
},
|
|
2022
|
-
});
|
|
2023
|
-
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
2024
|
-
device.features.unlocked = true;
|
|
2025
|
-
return Promise.resolve(device.features);
|
|
2026
|
-
});
|
|
2027
|
-
method.device = device as any;
|
|
2028
|
-
|
|
2029
|
-
await expect(method.run()).rejects.toMatchObject({
|
|
2030
|
-
errorCode: HardwareErrorCode.DeviceCheckDeviceIdError,
|
|
2031
|
-
});
|
|
2032
|
-
expect(typedCall).not.toHaveBeenCalled();
|
|
2033
|
-
expect(device.clearInternalState).not.toHaveBeenCalled();
|
|
2034
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
|
|
2035
|
-
});
|
|
2036
|
-
|
|
2037
|
-
test('reselects the expected hidden wallet when a cached Protocol V2 session is invalid', async () => {
|
|
2038
|
-
const typedCall = jest
|
|
2039
|
-
.fn()
|
|
2040
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
2041
|
-
.mockRejectedValueOnce(
|
|
2042
|
-
Object.assign(new Error('Invalid session'), {
|
|
2043
|
-
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
2044
|
-
})
|
|
2045
|
-
)
|
|
2046
|
-
.mockResolvedValueOnce({ message: {} })
|
|
2047
|
-
.mockResolvedValueOnce({
|
|
2048
|
-
message: {
|
|
2049
|
-
btc_test_address: 'hidden-state',
|
|
2050
|
-
session_id: 'renewed-session',
|
|
2051
|
-
},
|
|
2052
|
-
});
|
|
2053
|
-
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
|
|
2054
|
-
const method = new OpenWalletSession({
|
|
2055
|
-
payload: {
|
|
2056
|
-
method: 'openWalletSession',
|
|
2057
|
-
connectId: 'connect-id',
|
|
2058
|
-
mode: 'resume-hidden',
|
|
2059
|
-
deviceId: 'device-1',
|
|
2060
|
-
passphraseState: 'hidden-state',
|
|
2061
|
-
},
|
|
2062
|
-
});
|
|
2063
|
-
method.init();
|
|
2064
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
|
|
2065
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
2066
|
-
|
|
2067
|
-
await expect(method.run()).resolves.toEqual({
|
|
2068
|
-
protocol: 'V2',
|
|
2069
|
-
walletType: 'hidden',
|
|
2070
|
-
deviceId: 'device-1',
|
|
2071
|
-
passphraseState: 'hidden-state',
|
|
2072
|
-
resumed: false,
|
|
2073
|
-
});
|
|
2074
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
2075
|
-
session_id: 'expired-session',
|
|
2076
|
-
btc_test_address: 'hidden-state',
|
|
2077
|
-
...standardSessionGet,
|
|
2078
|
-
});
|
|
2079
|
-
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
2080
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
|
|
2081
|
-
});
|
|
2082
|
-
|
|
2083
|
-
test('recovers the current Attach PIN wallet when the cached session is invalid', async () => {
|
|
2084
|
-
const typedCall = jest
|
|
2085
|
-
.fn()
|
|
2086
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
2087
|
-
.mockRejectedValueOnce(
|
|
2088
|
-
Object.assign(new Error('Invalid session'), {
|
|
2089
|
-
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
2090
|
-
})
|
|
2091
|
-
)
|
|
2092
|
-
.mockResolvedValueOnce({
|
|
2093
|
-
message: {
|
|
2094
|
-
btc_test_address: 'hidden-state',
|
|
2095
|
-
session_id: 'renewed-session',
|
|
2096
|
-
},
|
|
2097
|
-
});
|
|
2098
|
-
const promptPassphrase = jest.fn();
|
|
2099
|
-
const method = new OpenWalletSession({
|
|
2100
|
-
payload: {
|
|
2101
|
-
method: 'openWalletSession',
|
|
2102
|
-
connectId: 'connect-id',
|
|
2103
|
-
mode: 'resume-hidden',
|
|
2104
|
-
deviceId: 'device-1',
|
|
2105
|
-
passphraseState: 'hidden-state',
|
|
2106
|
-
},
|
|
2107
|
-
});
|
|
2108
|
-
method.init();
|
|
2109
|
-
deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
|
|
2110
|
-
const device = createDevice({ unlockedAttachPin: true, typedCall, promptPassphrase });
|
|
2111
|
-
method.device = device as any;
|
|
2112
|
-
|
|
2113
|
-
await expect(method.run()).resolves.toEqual({
|
|
2114
|
-
protocol: 'V2',
|
|
2115
|
-
walletType: 'hidden',
|
|
2116
|
-
deviceId: 'device-1',
|
|
2117
|
-
passphraseState: 'hidden-state',
|
|
2118
|
-
resumed: false,
|
|
2119
|
-
});
|
|
2120
|
-
expect(typedCall.mock.calls.filter(call => call[0] === 'DeviceSessionGet')).toEqual([
|
|
2121
|
-
[
|
|
2122
|
-
'DeviceSessionGet',
|
|
2123
|
-
'DeviceSession',
|
|
2124
|
-
{
|
|
2125
|
-
session_id: 'expired-session',
|
|
2126
|
-
btc_test_address: 'hidden-state',
|
|
2127
|
-
},
|
|
2128
|
-
],
|
|
2129
|
-
['DeviceSessionGet', 'DeviceSession', {}],
|
|
2130
|
-
]);
|
|
2131
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2132
|
-
expect(device.lockDevice).not.toHaveBeenCalled();
|
|
2133
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
|
|
2134
|
-
});
|
|
2135
|
-
|
|
2136
|
-
test('selects the expected hidden wallet when Protocol V2 has no cached session', async () => {
|
|
2137
|
-
const typedCall = jest
|
|
2138
|
-
.fn()
|
|
2139
|
-
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
2140
|
-
.mockResolvedValueOnce({
|
|
2141
|
-
message: {
|
|
2142
|
-
btc_test_address: 'hidden-state',
|
|
2143
|
-
session_id: 'new-session',
|
|
2144
|
-
},
|
|
2145
|
-
});
|
|
2146
|
-
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
|
|
2147
|
-
const method = new OpenWalletSession({
|
|
2148
|
-
payload: {
|
|
2149
|
-
method: 'openWalletSession',
|
|
2150
|
-
connectId: 'connect-id',
|
|
2151
|
-
mode: 'resume-hidden',
|
|
2152
|
-
deviceId: 'device-1',
|
|
2153
|
-
passphraseState: 'hidden-state',
|
|
2154
|
-
},
|
|
2155
|
-
});
|
|
2156
|
-
method.init();
|
|
2157
|
-
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
2158
|
-
|
|
2159
|
-
await expect(method.run()).resolves.toEqual({
|
|
2160
|
-
protocol: 'V2',
|
|
2161
|
-
walletType: 'hidden',
|
|
2162
|
-
deviceId: 'device-1',
|
|
2163
|
-
passphraseState: 'hidden-state',
|
|
2164
|
-
resumed: false,
|
|
2165
|
-
});
|
|
2166
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
2167
|
-
btc_test_address: 'hidden-state',
|
|
2168
|
-
...standardSessionGet,
|
|
2169
|
-
});
|
|
2170
|
-
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
2171
|
-
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('new-session');
|
|
2172
|
-
});
|
|
2173
|
-
|
|
2174
1771
|
test.each([false, true])(
|
|
2175
1772
|
'openWalletSession does not thread CommonParams.deriveCardano: %s',
|
|
2176
1773
|
async deriveCardano => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
2
3
|
import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
4
|
import { sha256 } from '@noble/hashes/sha256';
|
|
4
5
|
import { bytesToHex } from '@noble/hashes/utils';
|
|
@@ -1824,6 +1825,56 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1824
1825
|
]);
|
|
1825
1826
|
});
|
|
1826
1827
|
|
|
1828
|
+
test.each([false, true])(
|
|
1829
|
+
'rejects the first incorrect passphrase after a missing or expired session (cached: %s)',
|
|
1830
|
+
async cached => {
|
|
1831
|
+
const deviceId = `first-passphrase-error-${String(cached)}`;
|
|
1832
|
+
const device = Device.fromDescriptor({
|
|
1833
|
+
id: deviceId,
|
|
1834
|
+
path: deviceId,
|
|
1835
|
+
protocolType: 'V2',
|
|
1836
|
+
} as never);
|
|
1837
|
+
device.features = normalizeProtocolV2Features(
|
|
1838
|
+
{ ...descriptor, protocolType: 'V2' } as never,
|
|
1839
|
+
{
|
|
1840
|
+
status: { device_id: deviceId, unlocked: true, passphrase_enabled: true },
|
|
1841
|
+
}
|
|
1842
|
+
);
|
|
1843
|
+
device.passphraseState = 'expected-public-address';
|
|
1844
|
+
if (cached) {
|
|
1845
|
+
preloadSessionCache(deviceId, device.passphraseState, randomBytes(32).toString('hex'));
|
|
1846
|
+
}
|
|
1847
|
+
let reads = 0;
|
|
1848
|
+
const typedCall = createWalletSessionTypedCall(
|
|
1849
|
+
jest.fn((request: string) => {
|
|
1850
|
+
if (request === 'DeviceSessionAskPassphrase') return { message: {} };
|
|
1851
|
+
if (request === 'DeviceSessionGet') {
|
|
1852
|
+
reads += 1;
|
|
1853
|
+
if (reads === 1) {
|
|
1854
|
+
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
1855
|
+
}
|
|
1856
|
+
return {
|
|
1857
|
+
message: {
|
|
1858
|
+
session_id: randomBytes(32).toString('hex'),
|
|
1859
|
+
btc_test_address: 'different-public-address',
|
|
1860
|
+
},
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
throw new Error(`Unexpected request: ${request}`);
|
|
1864
|
+
})
|
|
1865
|
+
);
|
|
1866
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
1867
|
+
device.commands = { typedCall, promptPassphrase } as never;
|
|
1868
|
+
|
|
1869
|
+
await expect(getProtocolV2WalletSession(device)).rejects.toMatchObject({
|
|
1870
|
+
errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
|
|
1871
|
+
});
|
|
1872
|
+
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
1873
|
+
expect(reads).toBe(2);
|
|
1874
|
+
expect(device.getInternalState()).toBeUndefined();
|
|
1875
|
+
}
|
|
1876
|
+
);
|
|
1877
|
+
|
|
1827
1878
|
test('reselects a hidden wallet when the cached Pro2 session resolves to another wallet', async () => {
|
|
1828
1879
|
const device = Device.fromDescriptor({
|
|
1829
1880
|
id: 'cache-device-mismatch',
|
|
@@ -22,7 +22,6 @@ describe('public device state API boundary', () => {
|
|
|
22
22
|
expect((publicTypes as Record<string, unknown>).OpenWalletSessionMode).toEqual({
|
|
23
23
|
Standard: 'standard',
|
|
24
24
|
SelectHidden: 'select-hidden',
|
|
25
|
-
ResumeHidden: 'resume-hidden',
|
|
26
25
|
});
|
|
27
26
|
});
|
|
28
27
|
|
|
@@ -83,9 +82,7 @@ describe('public device state API boundary', () => {
|
|
|
83
82
|
useEmptyPassphrase: false,
|
|
84
83
|
});
|
|
85
84
|
await api.openWalletSession('device-2', {
|
|
86
|
-
mode: publicTypes.OpenWalletSessionMode.
|
|
87
|
-
deviceId: 'wallet-device-1',
|
|
88
|
-
passphraseState: 'wallet-state-1',
|
|
85
|
+
mode: publicTypes.OpenWalletSessionMode.SelectHidden,
|
|
89
86
|
});
|
|
90
87
|
await api.clearSessionCache({
|
|
91
88
|
deviceId: 'wallet-device-1',
|
|
@@ -100,9 +97,7 @@ describe('public device state API boundary', () => {
|
|
|
100
97
|
});
|
|
101
98
|
expect(call).toHaveBeenNthCalledWith(2, {
|
|
102
99
|
connectId: 'device-2',
|
|
103
|
-
mode: '
|
|
104
|
-
deviceId: 'wallet-device-1',
|
|
105
|
-
passphraseState: 'wallet-state-1',
|
|
100
|
+
mode: 'select-hidden',
|
|
106
101
|
method: 'openWalletSession',
|
|
107
102
|
});
|
|
108
103
|
expect(call).toHaveBeenNthCalledWith(3, {
|