@onekeyfe/hd-core 1.2.2-alpha.12 → 1.2.2-alpha.122
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 +379 -15
- 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 +86 -0
- 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/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 +1 -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/index.d.ts +35 -30
- package/dist/index.js +558 -234
- 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/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 +20 -0
- package/src/core/index.ts +156 -50
- 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/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/api/protocolV2.ts +3 -4
- package/src/types/api/solSignOffchainMessage.ts +2 -0
- 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';
|
|
@@ -536,6 +537,41 @@ describe('UploadPortfolio', () => {
|
|
|
536
537
|
});
|
|
537
538
|
});
|
|
538
539
|
|
|
540
|
+
test('emits transfer progress when progress UI is requested', async () => {
|
|
541
|
+
const typedCall = jest
|
|
542
|
+
.fn()
|
|
543
|
+
.mockResolvedValueOnce({ message: { processed_byte: 3 } })
|
|
544
|
+
.mockResolvedValueOnce({ message: { message: 'Portfolio updated' } });
|
|
545
|
+
const method = new UploadPortfolio({
|
|
546
|
+
id: 1,
|
|
547
|
+
payload: {
|
|
548
|
+
method: 'uploadPortfolio',
|
|
549
|
+
packageBase64: 'AQID',
|
|
550
|
+
uiMode: 'progress',
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
(method as any).device = stubPortfolioDevice({ commands: { typedCall } });
|
|
554
|
+
method.postMessage = jest.fn();
|
|
555
|
+
|
|
556
|
+
method.init();
|
|
557
|
+
await method.run();
|
|
558
|
+
|
|
559
|
+
expect(method.unlockPolicy).toBe('none');
|
|
560
|
+
expect(method.protocolV2UiMode).toBe('auto');
|
|
561
|
+
expect(method.protocolV2UiInteraction).toBeUndefined();
|
|
562
|
+
expect(method.payload.emitProgress).toBe(true);
|
|
563
|
+
expect(method.postMessage).toHaveBeenCalledWith({
|
|
564
|
+
event: 'UI_EVENT',
|
|
565
|
+
type: UI_REQUEST.DEVICE_PROGRESS,
|
|
566
|
+
payload: expect.objectContaining({
|
|
567
|
+
progress: 100,
|
|
568
|
+
transferredBytes: 3,
|
|
569
|
+
totalBytes: 3,
|
|
570
|
+
elapsedMs: expect.any(Number),
|
|
571
|
+
}),
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
|
|
539
575
|
test('does not apply PortfolioUpdate when staging fails', async () => {
|
|
540
576
|
const typedCall = jest.fn().mockRejectedValue(new Error('write failed'));
|
|
541
577
|
const method = new UploadPortfolio({
|
|
@@ -1789,6 +1825,56 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1789
1825
|
]);
|
|
1790
1826
|
});
|
|
1791
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
|
+
|
|
1792
1878
|
test('reselects a hidden wallet when the cached Pro2 session resolves to another wallet', async () => {
|
|
1793
1879
|
const device = Device.fromDescriptor({
|
|
1794
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, {
|