@onekeyfe/hd-core 1.2.2-alpha.109 → 1.2.2-alpha.110
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__/device-lifecycle-events.test.ts +37 -0
- package/__tests__/protocol-v2.test.ts +51 -0
- package/dist/api/device/DeviceVerify.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/device/DeviceVerify.ts +8 -0
- package/src/protocols/protocol-v2/walletSession.ts +7 -0
|
@@ -15,12 +15,17 @@ import {
|
|
|
15
15
|
} from '../src/core';
|
|
16
16
|
import { DataManager } from '../src/data-manager';
|
|
17
17
|
import GetDeviceState from '../src/api/GetDeviceState';
|
|
18
|
+
import DeviceVerify from '../src/api/device/DeviceVerify';
|
|
18
19
|
import TransportManager from '../src/data-manager/TransportManager';
|
|
19
20
|
import { Device } from '../src/device/Device';
|
|
20
21
|
import { cancelDeviceInPrompt, cancelDeviceWithInitialize } from '../src/device/DeviceCommands';
|
|
21
22
|
import { DevicePool } from '../src/device/DevicePool';
|
|
22
23
|
import { CORE_EVENT, DEVICE, IFRAME } from '../src/events';
|
|
23
24
|
import { PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE } from '../src/protocols/protocol-v2';
|
|
25
|
+
import {
|
|
26
|
+
ProtocolV2UiInteractionCoordinator,
|
|
27
|
+
resolveProtocolV2UiInteraction,
|
|
28
|
+
} from '../src/protocols/protocol-v2/uiInteraction';
|
|
24
29
|
|
|
25
30
|
import type Core from '../src/core';
|
|
26
31
|
import type { CoreMessage } from '../src/events';
|
|
@@ -776,6 +781,38 @@ describe('public device lifecycle events', () => {
|
|
|
776
781
|
}
|
|
777
782
|
);
|
|
778
783
|
|
|
784
|
+
test.each(['react-native', 'desktop-web-ble', 'webusb', 'desktop-webusb'] as const)(
|
|
785
|
+
'sends Cancel once for device verification on an already unlocked Protocol V2 %s device',
|
|
786
|
+
async env => {
|
|
787
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue(env as never);
|
|
788
|
+
const device = createInitializedDevice('V2');
|
|
789
|
+
device.originalDescriptor.session = device.mainId;
|
|
790
|
+
jest.spyOn(device, 'hasDeviceAcquire').mockReturnValue(true);
|
|
791
|
+
const post = jest.fn().mockResolvedValue(undefined);
|
|
792
|
+
const cancel = jest.fn().mockResolvedValue(undefined);
|
|
793
|
+
device.commands = {
|
|
794
|
+
transport: { post },
|
|
795
|
+
cancelDevice: () => cancelDeviceInPrompt(device, false),
|
|
796
|
+
cancel,
|
|
797
|
+
} as never;
|
|
798
|
+
const method = new DeviceVerify({
|
|
799
|
+
payload: { method: 'deviceVerify', dataHex: '00' },
|
|
800
|
+
});
|
|
801
|
+
method.init();
|
|
802
|
+
const postMessage = jest.fn();
|
|
803
|
+
const coordinator = new ProtocolV2UiInteractionCoordinator(device, postMessage);
|
|
804
|
+
device.beginProtocolV2UiInteraction();
|
|
805
|
+
coordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
|
|
806
|
+
|
|
807
|
+
await device.interruptionFromUser();
|
|
808
|
+
await device.interruptionFromUser();
|
|
809
|
+
|
|
810
|
+
expect(post).toHaveBeenCalledTimes(1);
|
|
811
|
+
expect(post).toHaveBeenCalledWith(device.mainId, 'Cancel', {});
|
|
812
|
+
expect(cancel).toHaveBeenCalledTimes(1);
|
|
813
|
+
}
|
|
814
|
+
);
|
|
815
|
+
|
|
779
816
|
test.each(['react-native', 'webusb', 'desktop-webusb'] as const)(
|
|
780
817
|
'sends a fallback Cancel for an acquired Protocol V2 %s call with an open UI',
|
|
781
818
|
async env => {
|
|
@@ -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',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceVerify.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceVerify.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,UAAU,CAAC,wBAAwB,CAAC;IAC5E,qBAAqB;IAIrB,IAAI;
|
|
1
|
+
{"version":3,"file":"DeviceVerify.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceVerify.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,UAAU,CAAC,wBAAwB,CAAC;IAC5E,qBAAqB;IAIrB,IAAI;IAwBE,GAAG;CAsDV"}
|
package/dist/index.js
CHANGED
|
@@ -41878,6 +41878,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
41878
41878
|
? device.getInternalState()
|
|
41879
41879
|
: undefined;
|
|
41880
41880
|
let response;
|
|
41881
|
+
let walletSelectionRequested = false;
|
|
41881
41882
|
let resumed = false;
|
|
41882
41883
|
let walletStatusRefreshed = false;
|
|
41883
41884
|
const markWalletStatusRefreshed = () => {
|
|
@@ -42049,6 +42050,7 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42049
42050
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
|
|
42050
42051
|
}
|
|
42051
42052
|
yield lockAttachPinBeforePassphraseSelection();
|
|
42053
|
+
walletSelectionRequested = true;
|
|
42052
42054
|
response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano, markWalletStatusRefreshed);
|
|
42053
42055
|
}
|
|
42054
42056
|
let { message } = response;
|
|
@@ -42071,6 +42073,10 @@ function getProtocolV2WalletSession(device, options) {
|
|
|
42071
42073
|
device.clearInternalState();
|
|
42072
42074
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
|
|
42073
42075
|
}
|
|
42076
|
+
if (walletSelectionRequested) {
|
|
42077
|
+
clearCurrentWalletSession();
|
|
42078
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
42079
|
+
}
|
|
42074
42080
|
if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
|
|
42075
42081
|
(_j = device.clearStandardInternalState) === null || _j === void 0 ? void 0 : _j.call(device);
|
|
42076
42082
|
yield selectStandardWallet(true);
|
|
@@ -49178,6 +49184,14 @@ class DeviceVerify extends BaseMethod {
|
|
|
49178
49184
|
this.unlockPolicy = 'unlock-before-run';
|
|
49179
49185
|
this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
|
|
49180
49186
|
this.useDevicePassphraseState = false;
|
|
49187
|
+
this.protocolV2UiInteraction = {
|
|
49188
|
+
request: 'button',
|
|
49189
|
+
source: 'method-lifecycle',
|
|
49190
|
+
reason: 'device-management',
|
|
49191
|
+
completion: 'operation-completed',
|
|
49192
|
+
deviceOnly: true,
|
|
49193
|
+
operation: 'deviceVerify',
|
|
49194
|
+
};
|
|
49181
49195
|
validateParams(this.payload, [{ name: 'dataHex', type: 'hexString' }]);
|
|
49182
49196
|
this.params = {
|
|
49183
49197
|
data: formatAnyHex(this.payload.dataHex),
|
|
@@ -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;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;;;;;;
|
|
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;;;;;;GAyYF;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.110",
|
|
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.110",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.110",
|
|
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": "80a959fb1e9383ce948b911fddece1265b40051f"
|
|
50
50
|
}
|
|
@@ -22,6 +22,14 @@ export default class DeviceVerify extends BaseMethod<BixinVerifyDeviceRequest> {
|
|
|
22
22
|
// the main PIN or an Attach PIN may authorize them.
|
|
23
23
|
this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
|
|
24
24
|
this.useDevicePassphraseState = false;
|
|
25
|
+
this.protocolV2UiInteraction = {
|
|
26
|
+
request: 'button',
|
|
27
|
+
source: 'method-lifecycle',
|
|
28
|
+
reason: 'device-management',
|
|
29
|
+
completion: 'operation-completed',
|
|
30
|
+
deviceOnly: true,
|
|
31
|
+
operation: 'deviceVerify',
|
|
32
|
+
};
|
|
25
33
|
|
|
26
34
|
// check payload
|
|
27
35
|
validateParams(this.payload, [{ name: 'dataHex', type: 'hexString' }]);
|
|
@@ -268,6 +268,7 @@ export async function getProtocolV2WalletSession(
|
|
|
268
268
|
? device.getInternalState()
|
|
269
269
|
: undefined;
|
|
270
270
|
let response;
|
|
271
|
+
let walletSelectionRequested = false;
|
|
271
272
|
let resumed = false;
|
|
272
273
|
let walletStatusRefreshed = false;
|
|
273
274
|
const markWalletStatusRefreshed = () => {
|
|
@@ -482,6 +483,7 @@ export async function getProtocolV2WalletSession(
|
|
|
482
483
|
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
483
484
|
}
|
|
484
485
|
await lockAttachPinBeforePassphraseSelection();
|
|
486
|
+
walletSelectionRequested = true;
|
|
485
487
|
response = await selectDeviceSession(
|
|
486
488
|
device,
|
|
487
489
|
expectedPassphraseState,
|
|
@@ -508,6 +510,11 @@ export async function getProtocolV2WalletSession(
|
|
|
508
510
|
device.clearInternalState();
|
|
509
511
|
throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
|
|
510
512
|
}
|
|
513
|
+
// Report a fresh selection mismatch before asking for input again.
|
|
514
|
+
if (walletSelectionRequested) {
|
|
515
|
+
clearCurrentWalletSession();
|
|
516
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
517
|
+
}
|
|
511
518
|
if (options?.onlyMainPin) {
|
|
512
519
|
device.clearStandardInternalState?.();
|
|
513
520
|
await selectStandardWallet(true);
|