@onekeyfe/hardware-cli 1.2.0-alpha.34 → 1.2.0-alpha.36
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/dist/cli.js +9 -3
- package/dist/deviceSelection.d.ts +1 -1
- package/dist/pinentry.d.ts +1 -0
- package/dist/sdk.d.ts +8 -0
- package/dist/sdk.js +12 -3
- package/package.json +6 -6
- package/src/__tests__/wallet-session.test.ts +9 -0
- package/src/cli.ts +15 -3
- package/src/deviceSelection.ts +1 -1
- package/src/pinentry.ts +1 -0
- package/src/sdk.ts +12 -4
package/dist/cli.js
CHANGED
|
@@ -633,7 +633,14 @@ sessionCmd
|
|
|
633
633
|
});
|
|
634
634
|
return;
|
|
635
635
|
}
|
|
636
|
-
const device = searchResult.payload
|
|
636
|
+
const device = (0, deviceSelection_1.selectSearchDevice)(searchResult.payload, globalOpts.connectId);
|
|
637
|
+
if (!device) {
|
|
638
|
+
outputResult(globalOpts, {
|
|
639
|
+
success: false,
|
|
640
|
+
payload: { error: 'No matching device found', code: 'NO_DEVICE' },
|
|
641
|
+
});
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
637
644
|
const connectId = device.connectId || globalOpts.connectId;
|
|
638
645
|
// 2. Unlock if locked — getPassphraseState below talks to a live
|
|
639
646
|
// device session, which a locked device will reject with an obscure
|
|
@@ -678,8 +685,7 @@ sessionCmd
|
|
|
678
685
|
.description('Clear cached device session')
|
|
679
686
|
.action(() => runCommand({}, async ({ sdk, globalOpts }) => {
|
|
680
687
|
const searchResult = await sdk.searchDevices();
|
|
681
|
-
const device =
|
|
682
|
-
searchResult?.payload?.[0];
|
|
688
|
+
const device = (0, deviceSelection_1.selectSearchDevice)(searchResult?.payload ?? [], globalOpts.connectId);
|
|
683
689
|
const deviceId = device?.deviceId || device?.features?.device_id;
|
|
684
690
|
if (deviceId) {
|
|
685
691
|
await (0, session_1.clearSessionFromKeychain)(deviceId);
|
package/dist/pinentry.d.ts
CHANGED
package/dist/sdk.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* but public SDK responses never expose new device session ids
|
|
10
10
|
*/
|
|
11
11
|
import HardwareSDK from '@onekeyfe/hd-common-connect-sdk';
|
|
12
|
+
import type { PinentryResult } from './pinentry';
|
|
12
13
|
export interface SDKOptions {
|
|
13
14
|
connectId?: string;
|
|
14
15
|
passphraseState?: string;
|
|
@@ -16,6 +17,13 @@ export interface SDKOptions {
|
|
|
16
17
|
debug?: boolean;
|
|
17
18
|
transport?: 'usb' | 'ble';
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Prompt user to select wallet type (aligns with app-monorepo flow):
|
|
22
|
+
* 1. Standard wallet (no passphrase)
|
|
23
|
+
* 2. Hidden wallet — enter passphrase via pinentry (secure OS dialog)
|
|
24
|
+
* 3. Hidden wallet — enter passphrase on device screen
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolvePassphraseByChoice(choice: '1' | '2' | '3' | '4'): Promise<PinentryResult>;
|
|
19
27
|
export declare function createSDK(opts: SDKOptions): Promise<typeof HardwareSDK>;
|
|
20
28
|
/**
|
|
21
29
|
* Release the SDK and clear the singleton. Must be called before the CLI
|
package/dist/sdk.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.disposeSDK = exports.createSDK = void 0;
|
|
39
|
+
exports.disposeSDK = exports.createSDK = exports.resolvePassphraseByChoice = void 0;
|
|
40
40
|
const readline = __importStar(require("node:readline"));
|
|
41
41
|
const hd_common_connect_sdk_1 = __importDefault(require("@onekeyfe/hd-common-connect-sdk"));
|
|
42
42
|
const hd_core_1 = require("@onekeyfe/hd-core");
|
|
@@ -76,8 +76,15 @@ function resolvePassphraseByChoice(choice) {
|
|
|
76
76
|
return Promise.resolve({ value: '', passphraseOnDevice: false });
|
|
77
77
|
if (choice === '2')
|
|
78
78
|
return (0, pinentry_1.promptPassphraseViaPinentry)();
|
|
79
|
+
if (choice === '4')
|
|
80
|
+
return Promise.resolve({
|
|
81
|
+
value: '',
|
|
82
|
+
passphraseOnDevice: false,
|
|
83
|
+
attachPinOnDevice: true,
|
|
84
|
+
});
|
|
79
85
|
return Promise.resolve({ value: '', passphraseOnDevice: true });
|
|
80
86
|
}
|
|
87
|
+
exports.resolvePassphraseByChoice = resolvePassphraseByChoice;
|
|
81
88
|
function promptPassphraseMode() {
|
|
82
89
|
if (!process.stdin.isTTY) {
|
|
83
90
|
return Promise.resolve({ value: '', passphraseOnDevice: true });
|
|
@@ -94,16 +101,17 @@ function promptPassphraseMode() {
|
|
|
94
101
|
' 1. Standard wallet (no passphrase)',
|
|
95
102
|
' 2. Hidden wallet — enter passphrase on this computer (pinentry)',
|
|
96
103
|
' 3. Hidden wallet — enter passphrase on device screen',
|
|
104
|
+
' 4. Attach PIN wallet — enter Attach PIN on device screen',
|
|
97
105
|
'',
|
|
98
106
|
].join('\n'));
|
|
99
107
|
rl.question('Enter selection [1/2/3]: ', answer => {
|
|
100
108
|
const n = answer.trim();
|
|
101
|
-
if (n === '1' || n === '2' || n === '3') {
|
|
109
|
+
if (n === '1' || n === '2' || n === '3' || n === '4') {
|
|
102
110
|
rl.close();
|
|
103
111
|
resolvePassphraseByChoice(n).then(resolve);
|
|
104
112
|
return;
|
|
105
113
|
}
|
|
106
|
-
process.stderr.write('Invalid selection. Enter 1, 2, or
|
|
114
|
+
process.stderr.write('Invalid selection. Enter 1, 2, 3, or 4.\n');
|
|
107
115
|
prompt();
|
|
108
116
|
});
|
|
109
117
|
};
|
|
@@ -147,6 +155,7 @@ function registerEventHandlers(sdk) {
|
|
|
147
155
|
payload: {
|
|
148
156
|
value: result.value,
|
|
149
157
|
passphraseOnDevice: result.passphraseOnDevice,
|
|
158
|
+
attachPinOnDevice: result.attachPinOnDevice,
|
|
150
159
|
save: false,
|
|
151
160
|
},
|
|
152
161
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hardware-cli",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.36",
|
|
4
4
|
"description": "OneKey hardware wallet CLI for testing device communication",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"test": "jest"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@onekeyfe/hd-common-connect-sdk": "1.2.0-alpha.
|
|
35
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
36
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
37
|
-
"@onekeyfe/hd-transport-usb": "1.2.0-alpha.
|
|
34
|
+
"@onekeyfe/hd-common-connect-sdk": "1.2.0-alpha.36",
|
|
35
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.36",
|
|
36
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.36",
|
|
37
|
+
"@onekeyfe/hd-transport-usb": "1.2.0-alpha.36",
|
|
38
38
|
"@stoprocent/noble": "2.3.16",
|
|
39
39
|
"commander": "^12.0.0"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "94f0fec6ea1dfd4ffea2dae8ea2b0b4a2a6cf2be"
|
|
42
42
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { prepareSession } from '../cli';
|
|
2
|
+
import { resolvePassphraseByChoice } from '../sdk';
|
|
2
3
|
import { preloadSessionFromKeychain } from '../session';
|
|
3
4
|
|
|
4
5
|
jest.mock('../session', () => ({
|
|
@@ -7,6 +8,14 @@ jest.mock('../session', () => ({
|
|
|
7
8
|
}));
|
|
8
9
|
|
|
9
10
|
describe('CLI wallet session', () => {
|
|
11
|
+
test('maps the Attach PIN choice to an on-device Attach PIN response', async () => {
|
|
12
|
+
await expect(resolvePassphraseByChoice('4')).resolves.toEqual({
|
|
13
|
+
value: '',
|
|
14
|
+
passphraseOnDevice: false,
|
|
15
|
+
attachPinOnDevice: true,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
10
19
|
test('uses the public wallet identity without persisting an internal session id', async () => {
|
|
11
20
|
const sdk = {
|
|
12
21
|
searchDevices: jest.fn().mockResolvedValue({
|
package/src/cli.ts
CHANGED
|
@@ -808,7 +808,17 @@ sessionCmd
|
|
|
808
808
|
});
|
|
809
809
|
return;
|
|
810
810
|
}
|
|
811
|
-
const device =
|
|
811
|
+
const device = selectSearchDevice(
|
|
812
|
+
searchResult.payload as Array<SearchDevice & { features?: Features }>,
|
|
813
|
+
globalOpts.connectId
|
|
814
|
+
);
|
|
815
|
+
if (!device) {
|
|
816
|
+
outputResult(globalOpts, {
|
|
817
|
+
success: false,
|
|
818
|
+
payload: { error: 'No matching device found', code: 'NO_DEVICE' },
|
|
819
|
+
});
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
812
822
|
const connectId = device.connectId || globalOpts.connectId;
|
|
813
823
|
|
|
814
824
|
// 2. Unlock if locked — getPassphraseState below talks to a live
|
|
@@ -860,8 +870,10 @@ sessionCmd
|
|
|
860
870
|
.action(() =>
|
|
861
871
|
runCommand({}, async ({ sdk, globalOpts }) => {
|
|
862
872
|
const searchResult = await sdk.searchDevices();
|
|
863
|
-
const device =
|
|
864
|
-
(searchResult?.payload as
|
|
873
|
+
const device = selectSearchDevice(
|
|
874
|
+
(searchResult?.payload as Array<SearchDevice & { features?: Features }>) ?? [],
|
|
875
|
+
globalOpts.connectId
|
|
876
|
+
);
|
|
865
877
|
const deviceId = device?.deviceId || device?.features?.device_id;
|
|
866
878
|
if (deviceId) {
|
|
867
879
|
await clearSessionFromKeychain(deviceId);
|
package/src/deviceSelection.ts
CHANGED
package/src/pinentry.ts
CHANGED
package/src/sdk.ts
CHANGED
|
@@ -59,9 +59,15 @@ let sdkReadyPromise: Promise<typeof HardwareSDK> | null = null;
|
|
|
59
59
|
* 2. Hidden wallet — enter passphrase via pinentry (secure OS dialog)
|
|
60
60
|
* 3. Hidden wallet — enter passphrase on device screen
|
|
61
61
|
*/
|
|
62
|
-
function resolvePassphraseByChoice(choice: '1' | '2' | '3'): Promise<PinentryResult> {
|
|
62
|
+
export function resolvePassphraseByChoice(choice: '1' | '2' | '3' | '4'): Promise<PinentryResult> {
|
|
63
63
|
if (choice === '1') return Promise.resolve({ value: '', passphraseOnDevice: false });
|
|
64
64
|
if (choice === '2') return promptPassphraseViaPinentry();
|
|
65
|
+
if (choice === '4')
|
|
66
|
+
return Promise.resolve({
|
|
67
|
+
value: '',
|
|
68
|
+
passphraseOnDevice: false,
|
|
69
|
+
attachPinOnDevice: true,
|
|
70
|
+
});
|
|
65
71
|
return Promise.resolve({ value: '', passphraseOnDevice: true });
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -84,18 +90,19 @@ function promptPassphraseMode(): Promise<PinentryResult> {
|
|
|
84
90
|
' 1. Standard wallet (no passphrase)',
|
|
85
91
|
' 2. Hidden wallet — enter passphrase on this computer (pinentry)',
|
|
86
92
|
' 3. Hidden wallet — enter passphrase on device screen',
|
|
93
|
+
' 4. Attach PIN wallet — enter Attach PIN on device screen',
|
|
87
94
|
'',
|
|
88
95
|
].join('\n')
|
|
89
96
|
);
|
|
90
97
|
|
|
91
98
|
rl.question('Enter selection [1/2/3]: ', answer => {
|
|
92
|
-
const n = answer.trim() as '1' | '2' | '3';
|
|
93
|
-
if (n === '1' || n === '2' || n === '3') {
|
|
99
|
+
const n = answer.trim() as '1' | '2' | '3' | '4';
|
|
100
|
+
if (n === '1' || n === '2' || n === '3' || n === '4') {
|
|
94
101
|
rl.close();
|
|
95
102
|
resolvePassphraseByChoice(n).then(resolve);
|
|
96
103
|
return;
|
|
97
104
|
}
|
|
98
|
-
process.stderr.write('Invalid selection. Enter 1, 2, or
|
|
105
|
+
process.stderr.write('Invalid selection. Enter 1, 2, 3, or 4.\n');
|
|
99
106
|
prompt();
|
|
100
107
|
});
|
|
101
108
|
};
|
|
@@ -143,6 +150,7 @@ function registerEventHandlers(sdk: typeof HardwareSDK): void {
|
|
|
143
150
|
payload: {
|
|
144
151
|
value: result.value,
|
|
145
152
|
passphraseOnDevice: result.passphraseOnDevice,
|
|
153
|
+
attachPinOnDevice: result.attachPinOnDevice,
|
|
146
154
|
save: false,
|
|
147
155
|
},
|
|
148
156
|
});
|