@onekeyfe/hd-core 1.2.8-alpha.6 → 1.2.8-alpha.7
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 +0 -27
- package/__tests__/DeviceCommands.test.ts +66 -13
- package/__tests__/core-error-output.test.ts +34 -3
- package/__tests__/device-lifecycle-events.test.ts +64 -17
- package/__tests__/device-pool-state.test.ts +50 -0
- package/__tests__/protocol-v2-bootloader-mode.test.ts +31 -2
- package/__tests__/protocol-v2.test.ts +0 -47
- package/__tests__/refresh-device-state.test.ts +19 -17
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetDeviceState.d.ts.map +1 -1
- package/dist/api/index.d.ts +0 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.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 +4 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +9 -14
- package/dist/index.js +38 -148
- package/dist/inject.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +0 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +0 -2
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/params.d.ts +1 -0
- 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 +8 -25
- package/src/api/GetDeviceState.ts +2 -5
- package/src/api/index.ts +0 -1
- package/src/core/index.ts +3 -7
- package/src/data/messages/messages.json +0 -51
- package/src/device/Device.ts +11 -1
- package/src/device/DeviceCommands.ts +15 -1
- package/src/device/DevicePool.ts +12 -2
- package/src/events/core.ts +2 -2
- package/src/events/logBlockEvent.ts +0 -1
- package/src/inject.ts +0 -2
- package/src/types/api/export.ts +0 -1
- package/src/types/api/index.ts +0 -2
- package/src/types/params.ts +1 -1
- package/__tests__/btc-derive-context-hash.test.ts +0 -200
- package/dist/api/btc/BTCDeriveContextHash.d.ts +0 -16
- package/dist/api/btc/BTCDeriveContextHash.d.ts.map +0 -1
- package/dist/types/api/btcDeriveContextHash.d.ts +0 -10
- package/dist/types/api/btcDeriveContextHash.d.ts.map +0 -1
- package/src/api/btc/BTCDeriveContextHash.ts +0 -90
- package/src/types/api/btcDeriveContextHash.ts +0 -15
package/src/device/Device.ts
CHANGED
|
@@ -248,6 +248,9 @@ export class Device extends EventEmitter {
|
|
|
248
248
|
/** Canonical device-state cache; legacy Features is a compatibility projection. */
|
|
249
249
|
private stateStore = new DeviceStateStore();
|
|
250
250
|
|
|
251
|
+
/** Retain the old public identity only for disconnect notifications after wipe. */
|
|
252
|
+
private deviceBeforeWipe: DeviceTyped | null = null;
|
|
253
|
+
|
|
251
254
|
/** Force the next initialization to reload DeviceInfo after reconnect or reboot. */
|
|
252
255
|
private protocolV2StateNeedsReload = false;
|
|
253
256
|
|
|
@@ -351,6 +354,8 @@ export class Device extends EventEmitter {
|
|
|
351
354
|
toMessageObject(): DeviceTyped | null {
|
|
352
355
|
if (this.isUnacquired() || !this.features) return null;
|
|
353
356
|
|
|
357
|
+
this.deviceBeforeWipe = null;
|
|
358
|
+
|
|
354
359
|
const env = DataManager.getSettings('env');
|
|
355
360
|
const deviceType = this.getCurrentDeviceType();
|
|
356
361
|
|
|
@@ -395,6 +400,10 @@ export class Device extends EventEmitter {
|
|
|
395
400
|
};
|
|
396
401
|
}
|
|
397
402
|
|
|
403
|
+
toDisconnectMessageObject(): DeviceTyped | null {
|
|
404
|
+
return this.toMessageObject() ?? this.deviceBeforeWipe;
|
|
405
|
+
}
|
|
406
|
+
|
|
398
407
|
/**
|
|
399
408
|
* Device connect
|
|
400
409
|
* @returns {Promise<boolean>}
|
|
@@ -1364,6 +1373,7 @@ export class Device extends EventEmitter {
|
|
|
1364
1373
|
}
|
|
1365
1374
|
|
|
1366
1375
|
invalidateAfterWipe() {
|
|
1376
|
+
this.deviceBeforeWipe = this.toMessageObject() ?? this.deviceBeforeWipe;
|
|
1367
1377
|
const deviceId = this.getCurrentDeviceId();
|
|
1368
1378
|
if (deviceId) {
|
|
1369
1379
|
deviceWalletSessionStore.deleteDevice(deviceId);
|
|
@@ -1801,7 +1811,7 @@ export class Device extends EventEmitter {
|
|
|
1801
1811
|
// both allow and require cases might generate single unexpected mode
|
|
1802
1812
|
if (!this.isUnacquired()) {
|
|
1803
1813
|
// allow cases
|
|
1804
|
-
if (this.isBootloader()
|
|
1814
|
+
if ((this.isBootloader() || this.isRomloader()) && !allow.includes(UI_REQUEST.BOOTLOADER)) {
|
|
1805
1815
|
return UI_REQUEST.BOOTLOADER;
|
|
1806
1816
|
}
|
|
1807
1817
|
if (!this.isInitialized() && !allow.includes(UI_REQUEST.NOT_INITIALIZE)) {
|
|
@@ -549,6 +549,16 @@ export class DeviceCommands {
|
|
|
549
549
|
this.device.isProtocolV2() &&
|
|
550
550
|
DEVICE_CONTROL_CALLS.has(callType) &&
|
|
551
551
|
subcode === DeviceErrorCode.DeviceError_Busy;
|
|
552
|
+
const isProtocolV2PinCancelledBusyFailure =
|
|
553
|
+
this.device.isProtocolV2() &&
|
|
554
|
+
!DEVICE_SESSION_CALLS.has(callType) &&
|
|
555
|
+
subcode === DeviceSessionErrorCode.DeviceSessionError_UserCancelled &&
|
|
556
|
+
/^pin cancelled$/i.test(normalizedMessage);
|
|
557
|
+
const isProtocolV2FirmwareUpdateBusyFailure =
|
|
558
|
+
this.device.isProtocolV2() &&
|
|
559
|
+
/^requested command not allowed while a firmware update is in progress$/i.test(
|
|
560
|
+
normalizedMessage
|
|
561
|
+
);
|
|
552
562
|
const isLegacyProtocolV2LockedFailure =
|
|
553
563
|
this.device.isProtocolV2() && /^device (?:is )?locked$/i.test(normalizedMessage);
|
|
554
564
|
if (
|
|
@@ -606,7 +616,11 @@ export class DeviceCommands {
|
|
|
606
616
|
subcode,
|
|
607
617
|
firmwareMessage: message,
|
|
608
618
|
});
|
|
609
|
-
} else if (
|
|
619
|
+
} else if (
|
|
620
|
+
isProtocolV2DeviceBusyFailure ||
|
|
621
|
+
isProtocolV2PinCancelledBusyFailure ||
|
|
622
|
+
isProtocolV2FirmwareUpdateBusyFailure
|
|
623
|
+
) {
|
|
610
624
|
error = ERRORS.TypedError(HardwareErrorCode.DeviceBusy, message, {
|
|
611
625
|
failureCode: code,
|
|
612
626
|
subcode,
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -114,7 +114,11 @@ export class DevicePool extends EventEmitter {
|
|
|
114
114
|
const exist = canPathIdentifyDevice(cachedPath)
|
|
115
115
|
? descriptorList.find(d => d.path === cachedPath)
|
|
116
116
|
: undefined;
|
|
117
|
-
if (
|
|
117
|
+
if (
|
|
118
|
+
exist &&
|
|
119
|
+
!initOptions?.forceProtocolDetection &&
|
|
120
|
+
!(device.needReloadDevice && device.isUnacquired())
|
|
121
|
+
) {
|
|
118
122
|
// Log.debug('find existed Device: ', connectId);
|
|
119
123
|
device.updateDescriptor(exist, true);
|
|
120
124
|
await this._refreshRuntimeState(device, initOptions);
|
|
@@ -170,7 +174,13 @@ export class DevicePool extends EventEmitter {
|
|
|
170
174
|
const forceProtocolDetection = initOptions?.forceProtocolDetection === true;
|
|
171
175
|
const isNewDevice = !cachedDevice;
|
|
172
176
|
const device = cachedDevice ?? Device.fromDescriptor(descriptor);
|
|
173
|
-
if (
|
|
177
|
+
if (
|
|
178
|
+
isNewDevice ||
|
|
179
|
+
forceProtocolDetection ||
|
|
180
|
+
(device.needReloadDevice && device.isUnacquired())
|
|
181
|
+
) {
|
|
182
|
+
// Wipe invalidates state while the same USB path can remain discoverable.
|
|
183
|
+
if (cachedDevice) device.updateDescriptor(descriptor, true);
|
|
174
184
|
device.deviceConnector = this.connector;
|
|
175
185
|
// Search/discovery acquires outside Device.run(). Start a new attempt so
|
|
176
186
|
// a previous user cancel does not hide this device from later searches.
|
package/src/events/core.ts
CHANGED
|
@@ -54,9 +54,9 @@ export const parseMessage = (messageData: any): CoreMessage => {
|
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
export const createErrorMessage = (error: Error & { code?: string | number }): Unsuccessful => {
|
|
57
|
-
let payload = { error: error.message, code: error.code };
|
|
57
|
+
let payload: Unsuccessful['payload'] = { error: error.message, code: error.code };
|
|
58
58
|
if (error instanceof HardwareError) {
|
|
59
|
-
payload = { error: error.message, code: error.errorCode };
|
|
59
|
+
payload = { error: error.message, code: error.errorCode, params: error.params };
|
|
60
60
|
}
|
|
61
61
|
return {
|
|
62
62
|
success: false,
|
|
@@ -11,7 +11,6 @@ export const LogBlockEvent: Set<string> = new Set([
|
|
|
11
11
|
// These resource/file APIs did not exist in 1.1.32. Skip the payload so
|
|
12
12
|
// the log layer does not copy huge Base64 or binary data.
|
|
13
13
|
const LogPayloadBlockMethod: Set<string> = new Set([
|
|
14
|
-
'btcDeriveContextHash',
|
|
15
14
|
'deviceUploadNft',
|
|
16
15
|
'deviceUploadWallpaper',
|
|
17
16
|
'uploadPortfolio',
|
package/src/inject.ts
CHANGED
|
@@ -309,8 +309,6 @@ export const createCoreApi = (
|
|
|
309
309
|
call({ ...params, connectId, deviceId, method: 'btcGetAddress' }),
|
|
310
310
|
btcGetPublicKey: (connectId, deviceId, params) =>
|
|
311
311
|
call({ ...params, connectId, deviceId, method: 'btcGetPublicKey' }),
|
|
312
|
-
btcDeriveContextHash: (connectId, deviceId, params) =>
|
|
313
|
-
call({ ...params, connectId, deviceId, method: 'btcDeriveContextHash' }),
|
|
314
312
|
btcSignMessage: (connectId, deviceId, params) =>
|
|
315
313
|
call({ ...params, connectId, deviceId, method: 'btcSignMessage' }),
|
|
316
314
|
btcSignPsbt: (connectId, deviceId, params) =>
|
package/src/types/api/export.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export type { BTCAddress, BTCGetAddressParams } from './btcGetAddress';
|
|
2
2
|
export type { BTCPublicKey, BTCGetPublicKeyParams } from './btcGetPublicKey';
|
|
3
|
-
export type { BTCDeriveContextHashParams } from './btcDeriveContextHash';
|
|
4
3
|
export type { BTCSignMessageParams } from './btcSignMessage';
|
|
5
4
|
export type { BTCVerifyMessageParams } from './btcVerifyMessage';
|
|
6
5
|
export type {
|
package/src/types/api/index.ts
CHANGED
|
@@ -73,7 +73,6 @@ import type { evmSignTypedData } from './evmSignTypedData';
|
|
|
73
73
|
import type { evmVerifyMessage } from './evmVerifyMessage';
|
|
74
74
|
import type { btcGetAddress } from './btcGetAddress';
|
|
75
75
|
import type { btcGetPublicKey } from './btcGetPublicKey';
|
|
76
|
-
import type { btcDeriveContextHash } from './btcDeriveContextHash';
|
|
77
76
|
import type { btcSignMessage } from './btcSignMessage';
|
|
78
77
|
import type { btcSignPsbt } from './btcSignPsbt';
|
|
79
78
|
import type { btcSignTransaction } from './btcSignTransaction';
|
|
@@ -287,7 +286,6 @@ export type CoreApi = {
|
|
|
287
286
|
*/
|
|
288
287
|
btcGetAddress: typeof btcGetAddress;
|
|
289
288
|
btcGetPublicKey: typeof btcGetPublicKey;
|
|
290
|
-
btcDeriveContextHash: typeof btcDeriveContextHash;
|
|
291
289
|
btcSignMessage: typeof btcSignMessage;
|
|
292
290
|
btcSignPsbt: typeof btcSignPsbt;
|
|
293
291
|
btcSignTransaction: typeof btcSignTransaction;
|
package/src/types/params.ts
CHANGED
|
@@ -83,7 +83,7 @@ export type Params<T> = CommonParams & T & { bundle?: undefined };
|
|
|
83
83
|
|
|
84
84
|
export interface Unsuccessful {
|
|
85
85
|
success: false;
|
|
86
|
-
payload: { error: string; code?: string | number };
|
|
86
|
+
payload: { error: string; code?: string | number; params?: Record<string, unknown> };
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export interface Success<T> {
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
|
|
3
|
-
import BTCDeriveContextHash from '../src/api/btc/BTCDeriveContextHash';
|
|
4
|
-
import { findMethod } from '../src/api/utils';
|
|
5
|
-
import { getLogBlockLabel, getSafeLogPayload } from '../src/events/logBlockEvent';
|
|
6
|
-
import { createCoreApi } from '../src/inject';
|
|
7
|
-
import { Device } from '../src/device/Device';
|
|
8
|
-
|
|
9
|
-
import type { DeviceFirmwareRange } from '../src/types';
|
|
10
|
-
|
|
11
|
-
jest.mock('../src/data/config', () => ({
|
|
12
|
-
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
13
|
-
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
const createMethod = (overrides: Record<string, unknown> = {}) =>
|
|
17
|
-
new BTCDeriveContextHash({
|
|
18
|
-
id: 1,
|
|
19
|
-
payload: {
|
|
20
|
-
method: 'btcDeriveContextHash',
|
|
21
|
-
path: "m/84'/0'/0'/0/0",
|
|
22
|
-
appName: 'test-app',
|
|
23
|
-
context: 'deadbeef',
|
|
24
|
-
network: 'bitcoin-mainnet',
|
|
25
|
-
...overrides,
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('btcDeriveContextHash', () => {
|
|
30
|
-
test('forwards the public API call through the existing dispatcher', async () => {
|
|
31
|
-
const call = jest
|
|
32
|
-
.fn()
|
|
33
|
-
.mockResolvedValue({ success: true, payload: { secret: '00'.repeat(32) } });
|
|
34
|
-
const api = createCoreApi(call);
|
|
35
|
-
const params = {
|
|
36
|
-
path: "m/84'/0'/0'/0/0",
|
|
37
|
-
appName: 'test-app',
|
|
38
|
-
context: 'deadbeef',
|
|
39
|
-
network: 'bitcoin-mainnet' as const,
|
|
40
|
-
};
|
|
41
|
-
await api.btcDeriveContextHash('connect-id', 'device-id', params);
|
|
42
|
-
expect(call).toHaveBeenCalledWith({
|
|
43
|
-
...params,
|
|
44
|
-
connectId: 'connect-id',
|
|
45
|
-
deviceId: 'device-id',
|
|
46
|
-
method: 'btcDeriveContextHash',
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test.each([
|
|
51
|
-
['bitcoin-mainnet', 'BITCOIN_MAINNET'],
|
|
52
|
-
['bitcoin-testnet', 'BITCOIN_TESTNET'],
|
|
53
|
-
['bitcoin-signet', 'BITCOIN_SIGNET'],
|
|
54
|
-
['bitcoin-regtest', 'BITCOIN_REGTEST'],
|
|
55
|
-
])('maps %s and returns the device result', async (network, wireNetwork) => {
|
|
56
|
-
const method = createMethod({ network });
|
|
57
|
-
method.init();
|
|
58
|
-
const response = { secret: '00'.repeat(32) };
|
|
59
|
-
const typedCall = jest.fn().mockResolvedValue({ message: response });
|
|
60
|
-
method.device = { commands: { typedCall } } as unknown as Device;
|
|
61
|
-
|
|
62
|
-
await expect(method.run()).resolves.toBe(response);
|
|
63
|
-
expect(typedCall).toHaveBeenCalledWith(
|
|
64
|
-
'BabylonDeriveContextHash',
|
|
65
|
-
'BabylonDerivedContextHash',
|
|
66
|
-
{
|
|
67
|
-
address_n: [2147483732, 2147483648, 2147483648, 0, 0],
|
|
68
|
-
script_type: 'SPENDWITNESS',
|
|
69
|
-
app_name: '746573742d617070',
|
|
70
|
-
context: 'deadbeef',
|
|
71
|
-
network: wireNetwork,
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test.each([
|
|
77
|
-
["m/44'/0'/0'/0/0", 'SPENDADDRESS'],
|
|
78
|
-
["m/49'/0'/0'/0/0", 'SPENDP2SHWITNESS'],
|
|
79
|
-
[[2147483734, 2147483648, 2147483648, 0, 0], 'SPENDTAPROOT'],
|
|
80
|
-
])('uses the selected path script type for %s', (path, scriptType) => {
|
|
81
|
-
const method = createMethod({ path });
|
|
82
|
-
method.init();
|
|
83
|
-
expect(method.params.script_type).toBe(scriptType);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('accepts the maximum app name and context sizes', () => {
|
|
87
|
-
const method = createMethod({ appName: 'a'.repeat(64), context: 'ab'.repeat(1024) });
|
|
88
|
-
expect(() => method.init()).not.toThrow();
|
|
89
|
-
expect(method.params.context).toHaveLength(2048);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test.each([
|
|
93
|
-
{ appName: '' },
|
|
94
|
-
{ appName: 'a'.repeat(65) },
|
|
95
|
-
{ appName: 'Test-App' },
|
|
96
|
-
{ appName: 'test_app' },
|
|
97
|
-
{ appName: '你好' },
|
|
98
|
-
{ appName: null },
|
|
99
|
-
{ context: '' },
|
|
100
|
-
{ context: 'abc' },
|
|
101
|
-
{ context: 'DEADBEEF' },
|
|
102
|
-
{ context: '0xdeadbeef' },
|
|
103
|
-
{ context: 'gg' },
|
|
104
|
-
{ context: 'ab'.repeat(1025) },
|
|
105
|
-
{ context: null },
|
|
106
|
-
{ network: '' },
|
|
107
|
-
{ network: 'litecoin' },
|
|
108
|
-
{ network: 'toString' },
|
|
109
|
-
{ network: 1 },
|
|
110
|
-
{ path: 'm' },
|
|
111
|
-
{ path: "m/84x'/0'/0'/0/0" },
|
|
112
|
-
{ path: "m/2147483648'/0'/0'/0/0" },
|
|
113
|
-
{ path: [2147483732, 2147483648, 2147483648, 0, 0.5] },
|
|
114
|
-
{ path: [2147483732, 2147483648, 2147483648, 0, 4294967296] },
|
|
115
|
-
])('rejects invalid inputs before a device call: %j', overrides => {
|
|
116
|
-
expect(() => createMethod(overrides).init()).toThrow(
|
|
117
|
-
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
118
|
-
);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test('rejects sparse numeric paths before a device call', () => {
|
|
122
|
-
const sparsePath = [2147483732, 2147483648, 2147483648, 0, 5];
|
|
123
|
-
delete sparsePath[3];
|
|
124
|
-
|
|
125
|
-
[Array<number>(3), sparsePath].forEach(path => {
|
|
126
|
-
expect(() => createMethod({ path }).init()).toThrow(
|
|
127
|
-
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test('registers the public method and restricts it to supported firmware and protocol', () => {
|
|
133
|
-
const method = findMethod({ id: 1, payload: { ...createMethod().payload } });
|
|
134
|
-
method.init();
|
|
135
|
-
expect(method).toBeInstanceOf(BTCDeriveContextHash);
|
|
136
|
-
expect(method.strictCheckDeviceSupport).toBe(true);
|
|
137
|
-
expect(() => method.assertProtocolSupported('V2', EFirmwareType.Universal)).toThrow(
|
|
138
|
-
expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotSupportMethod })
|
|
139
|
-
);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test.each([EDeviceType.Classic1s, EDeviceType.ClassicPure])(
|
|
143
|
-
'resolves the firmware requirement for %s through the device support check',
|
|
144
|
-
deviceType => {
|
|
145
|
-
const method = createMethod();
|
|
146
|
-
const device = Object.create(Device.prototype) as Device;
|
|
147
|
-
device.getCurrentDeviceType = jest.fn(() => deviceType);
|
|
148
|
-
const range: DeviceFirmwareRange = method.getVersionRange();
|
|
149
|
-
|
|
150
|
-
expect(device.getCurrentMethodVersionRange(type => range[type])).toEqual({ min: '3.21.0' });
|
|
151
|
-
expect(() => method.assertProtocolSupported('V1', EFirmwareType.Universal)).not.toThrow();
|
|
152
|
-
}
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
test.each([EDeviceType.Classic, EDeviceType.Mini, EDeviceType.Touch, EDeviceType.Pro])(
|
|
156
|
-
'keeps %s outside the supported firmware range',
|
|
157
|
-
deviceType => {
|
|
158
|
-
const method = createMethod();
|
|
159
|
-
const device = Object.create(Device.prototype) as Device;
|
|
160
|
-
device.getCurrentDeviceType = jest.fn(() => deviceType);
|
|
161
|
-
const range: DeviceFirmwareRange = method.getVersionRange();
|
|
162
|
-
|
|
163
|
-
expect(device.getCurrentMethodVersionRange(type => range[type])).toBeUndefined();
|
|
164
|
-
}
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
test('propagates device rejection without returning a secret', async () => {
|
|
168
|
-
const method = createMethod();
|
|
169
|
-
method.init();
|
|
170
|
-
const error = new Error('User rejected');
|
|
171
|
-
method.device = {
|
|
172
|
-
commands: { typedCall: jest.fn().mockRejectedValue(error) },
|
|
173
|
-
} as unknown as Device;
|
|
174
|
-
await expect(method.run()).rejects.toBe(error);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test.each([undefined, '00', '00'.repeat(33)])(
|
|
178
|
-
'rejects malformed device responses',
|
|
179
|
-
async secret => {
|
|
180
|
-
const method = createMethod();
|
|
181
|
-
method.init();
|
|
182
|
-
method.device = {
|
|
183
|
-
commands: { typedCall: jest.fn().mockResolvedValue({ message: { secret } }) },
|
|
184
|
-
} as unknown as Device;
|
|
185
|
-
await expect(method.run()).rejects.toMatchObject({
|
|
186
|
-
errorCode: HardwareErrorCode.CallMethodError,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
test('blocks API request and response payloads in logs', () => {
|
|
192
|
-
const request = { payload: { method: 'btcDeriveContextHash' } };
|
|
193
|
-
const label = getLogBlockLabel(request);
|
|
194
|
-
expect(label).toBe('btcDeriveContextHash');
|
|
195
|
-
expect(getSafeLogPayload({ payload: { secret: '00'.repeat(32) } }, label)).toEqual({
|
|
196
|
-
method: 'btcDeriveContextHash',
|
|
197
|
-
payload: '[REDACTED]',
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { BaseMethod } from '../BaseMethod';
|
|
2
|
-
import type { BabylonDeriveContextHash } from '@onekeyfe/hd-transport';
|
|
3
|
-
export default class BTCDeriveContextHash extends BaseMethod<BabylonDeriveContextHash> {
|
|
4
|
-
strictCheckDeviceSupport: boolean;
|
|
5
|
-
init(): void;
|
|
6
|
-
getVersionRange(): {
|
|
7
|
-
classic1s: {
|
|
8
|
-
min: string;
|
|
9
|
-
};
|
|
10
|
-
classicpure: {
|
|
11
|
-
min: string;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
run(): Promise<import("@onekeyfe/hd-transport").BabylonDerivedContextHash>;
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=BTCDeriveContextHash.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BTCDeriveContextHash.d.ts","sourceRoot":"","sources":["../../../src/api/btc/BTCDeriveContextHash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EAAE,wBAAwB,EAA2B,MAAM,wBAAwB,CAAC;AAUhG,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,UAAU,CAAC,wBAAwB,CAAC;IACpF,wBAAwB,UAAQ;IAEhC,IAAI;IAgDJ,eAAe;;;;;;;;IAOT,GAAG;CAcV"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { BabylonDerivedContextHash } from '@onekeyfe/hd-transport';
|
|
2
|
-
import type { CommonParams, Response } from '../params';
|
|
3
|
-
export type BTCDeriveContextHashParams = {
|
|
4
|
-
path: string | number[];
|
|
5
|
-
appName: string;
|
|
6
|
-
context: string;
|
|
7
|
-
network: 'bitcoin-mainnet' | 'bitcoin-testnet' | 'bitcoin-signet' | 'bitcoin-regtest';
|
|
8
|
-
};
|
|
9
|
-
export declare function btcDeriveContextHash(connectId: string, deviceId: string, params: CommonParams & BTCDeriveContextHashParams): Response<BabylonDerivedContextHash>;
|
|
10
|
-
//# sourceMappingURL=btcDeriveContextHash.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"btcDeriveContextHash.d.ts","sourceRoot":"","sources":["../../../src/types/api/btcDeriveContextHash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;CACvF,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GAAG,0BAA0B,GAChD,QAAQ,CAAC,yBAAyB,CAAC,CAAC"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
import { Buffer } from 'buffer';
|
|
3
|
-
|
|
4
|
-
import { BaseMethod } from '../BaseMethod';
|
|
5
|
-
import { invalidParameter, validateParams } from '../helpers/paramsValidator';
|
|
6
|
-
import { getScriptType, validatePath } from '../helpers/pathUtils';
|
|
7
|
-
|
|
8
|
-
import type { BabylonDeriveContextHash, CanonicalBitcoinNetwork } from '@onekeyfe/hd-transport';
|
|
9
|
-
import type { BTCDeriveContextHashParams } from '../../types';
|
|
10
|
-
|
|
11
|
-
const NETWORKS: Record<BTCDeriveContextHashParams['network'], CanonicalBitcoinNetwork> = {
|
|
12
|
-
'bitcoin-mainnet': 'BITCOIN_MAINNET',
|
|
13
|
-
'bitcoin-testnet': 'BITCOIN_TESTNET',
|
|
14
|
-
'bitcoin-signet': 'BITCOIN_SIGNET',
|
|
15
|
-
'bitcoin-regtest': 'BITCOIN_REGTEST',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default class BTCDeriveContextHash extends BaseMethod<BabylonDeriveContextHash> {
|
|
19
|
-
strictCheckDeviceSupport = true;
|
|
20
|
-
|
|
21
|
-
init() {
|
|
22
|
-
this.checkDeviceId = true;
|
|
23
|
-
this.allowUsePreInitialize = true;
|
|
24
|
-
|
|
25
|
-
validateParams(this.payload, [
|
|
26
|
-
{ name: 'path', required: true },
|
|
27
|
-
{ name: 'appName', type: 'string', required: true },
|
|
28
|
-
{ name: 'context', type: 'string', required: true },
|
|
29
|
-
{ name: 'network', type: 'string', required: true },
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
const { path, appName, context, network } = this.payload;
|
|
33
|
-
if (typeof appName !== 'string' || !/^[a-z0-9-]{1,64}$/.test(appName)) {
|
|
34
|
-
throw invalidParameter(
|
|
35
|
-
'appName must contain 1..64 ASCII lowercase letters, digits or hyphens'
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
if (typeof context !== 'string' || !/^(?:[0-9a-f]{2}){1,1024}$/.test(context)) {
|
|
39
|
-
throw invalidParameter('context must be 1..1024 bytes of lowercase hex without a prefix');
|
|
40
|
-
}
|
|
41
|
-
if (typeof network !== 'string' || !Object.prototype.hasOwnProperty.call(NETWORKS, network)) {
|
|
42
|
-
throw invalidParameter('Unsupported Bitcoin network');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Reject malformed or overflowing indices before validatePath can truncate them.
|
|
46
|
-
if (
|
|
47
|
-
(typeof path === 'string' &&
|
|
48
|
-
(!/^m(?:\/\d+'?)+$/i.test(path) ||
|
|
49
|
-
path
|
|
50
|
-
.split('/')
|
|
51
|
-
.slice(1)
|
|
52
|
-
.some(index => Number(index.replace(/'/g, '')) >= 0x80000000))) ||
|
|
53
|
-
(Array.isArray(path) &&
|
|
54
|
-
path.findIndex(index => !Number.isInteger(index) || index < 0 || index > 0xffffffff) !== -1)
|
|
55
|
-
) {
|
|
56
|
-
throw invalidParameter('Not a valid BIP-32 path');
|
|
57
|
-
}
|
|
58
|
-
const addressN = validatePath(path, 3);
|
|
59
|
-
|
|
60
|
-
this.params = {
|
|
61
|
-
address_n: addressN,
|
|
62
|
-
script_type: getScriptType(addressN),
|
|
63
|
-
app_name: Buffer.from(appName, 'ascii').toString('hex'),
|
|
64
|
-
context,
|
|
65
|
-
network: NETWORKS[network as BTCDeriveContextHashParams['network']],
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
getVersionRange() {
|
|
70
|
-
return {
|
|
71
|
-
classic1s: { min: '3.21.0' },
|
|
72
|
-
classicpure: { min: '3.21.0' },
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async run() {
|
|
77
|
-
const { message } = await this.device.commands.typedCall(
|
|
78
|
-
'BabylonDeriveContextHash',
|
|
79
|
-
'BabylonDerivedContextHash',
|
|
80
|
-
this.params
|
|
81
|
-
);
|
|
82
|
-
if (typeof message.secret !== 'string' || !/^[0-9a-f]{64}$/.test(message.secret)) {
|
|
83
|
-
throw ERRORS.TypedError(
|
|
84
|
-
HardwareErrorCode.CallMethodError,
|
|
85
|
-
'Invalid Babylon context hash response'
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
return message;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { BabylonDerivedContextHash } from '@onekeyfe/hd-transport';
|
|
2
|
-
import type { CommonParams, Response } from '../params';
|
|
3
|
-
|
|
4
|
-
export type BTCDeriveContextHashParams = {
|
|
5
|
-
path: string | number[];
|
|
6
|
-
appName: string;
|
|
7
|
-
context: string;
|
|
8
|
-
network: 'bitcoin-mainnet' | 'bitcoin-testnet' | 'bitcoin-signet' | 'bitcoin-regtest';
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export declare function btcDeriveContextHash(
|
|
12
|
-
connectId: string,
|
|
13
|
-
deviceId: string,
|
|
14
|
-
params: CommonParams & BTCDeriveContextHashParams
|
|
15
|
-
): Response<BabylonDerivedContextHash>;
|