@onekeyfe/hd-core 1.2.2-alpha.117 → 1.2.2-alpha.119
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__/search-devices.test.ts +87 -22
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/index.js +26 -5
- package/package.json +4 -4
- package/src/api/SearchDevices.ts +43 -8
|
@@ -106,9 +106,13 @@ describe('SearchDevices', () => {
|
|
|
106
106
|
}
|
|
107
107
|
);
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
const BOOTLOADER_PATH = '00000000000000000000000000000000';
|
|
110
|
+
|
|
111
|
+
const runOwnedSearch = (
|
|
112
|
+
path: string,
|
|
113
|
+
ownerDevice?: unknown,
|
|
114
|
+
usbHandles: unknown[] = [{ vendorId: 0x1209, productId: 0x4f4c }]
|
|
115
|
+
) => {
|
|
112
116
|
const method = new SearchDevices({
|
|
113
117
|
id: 1,
|
|
114
118
|
payload: { method: 'searchDevices' },
|
|
@@ -117,34 +121,95 @@ describe('SearchDevices', () => {
|
|
|
117
121
|
method.context = {
|
|
118
122
|
requestQueue: {
|
|
119
123
|
getRequestTasksId: () => [2],
|
|
120
|
-
getRequestTasksIdByConnectId: (connectId: string) => (connectId ===
|
|
124
|
+
getRequestTasksIdByConnectId: (connectId: string) => (connectId === path ? [2] : []),
|
|
125
|
+
getTask: (requestId: number) =>
|
|
126
|
+
requestId === 2 ? { method: { device: ownerDevice } } : undefined,
|
|
121
127
|
},
|
|
122
128
|
} as never;
|
|
123
129
|
method.connector = {
|
|
124
130
|
enumerate: jest.fn().mockResolvedValue({
|
|
125
|
-
descriptors:
|
|
126
|
-
{
|
|
127
|
-
path: 'serial-V2',
|
|
128
|
-
device: usbDevice,
|
|
129
|
-
commType: 'webusb',
|
|
130
|
-
},
|
|
131
|
-
],
|
|
131
|
+
descriptors: usbHandles.map(device => ({ path, device, commType: 'webusb' })),
|
|
132
132
|
}),
|
|
133
133
|
} as never;
|
|
134
|
+
return method.run();
|
|
135
|
+
};
|
|
134
136
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
const createOwnerDevice = (path: string, usbHandle: unknown, serialNo: string) => ({
|
|
138
|
+
mainId: path,
|
|
139
|
+
features: { serial_no: serialNo },
|
|
140
|
+
originalDescriptor: { path, device: usbHandle },
|
|
141
|
+
toMessageObject: () => ({ connectId: serialNo, serialNo, uuid: serialNo }),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test.each(['serial-V2', 'usb-1209-4f4c-onekey', BOOTLOADER_PATH])(
|
|
145
|
+
'owned WebUSB cache miss on %s reports the path without inventing an identity or probing',
|
|
146
|
+
async path => {
|
|
147
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
148
|
+
|
|
149
|
+
await expect(runOwnedSearch(path)).resolves.toEqual([
|
|
150
|
+
{
|
|
151
|
+
connectId: path,
|
|
152
|
+
uuid: '',
|
|
153
|
+
serialNo: null,
|
|
154
|
+
deviceId: null,
|
|
155
|
+
deviceType: 'unknown',
|
|
156
|
+
name: path,
|
|
157
|
+
commType: 'webusb',
|
|
158
|
+
},
|
|
159
|
+
]);
|
|
160
|
+
expect(mockGetDevices).not.toHaveBeenCalled();
|
|
161
|
+
expect(mockConfigureTransport).not.toHaveBeenCalled();
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
test('owned WebUSB cache miss reports the owning request device identity', async () => {
|
|
166
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
167
|
+
const usbHandle = { vendorId: 0x1209, productId: 0x4f4c };
|
|
168
|
+
const ownerDevice = createOwnerDevice(BOOTLOADER_PATH, usbHandle, 'PRO2SERIAL');
|
|
169
|
+
|
|
170
|
+
await expect(runOwnedSearch(BOOTLOADER_PATH, ownerDevice, [usbHandle])).resolves.toEqual([
|
|
171
|
+
{ connectId: 'PRO2SERIAL', serialNo: 'PRO2SERIAL', uuid: 'PRO2SERIAL' },
|
|
145
172
|
]);
|
|
146
173
|
expect(mockGetDevices).not.toHaveBeenCalled();
|
|
147
|
-
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('owned WebUSB cache miss ignores an owning request device bound to another path', async () => {
|
|
177
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
178
|
+
const usbHandle = { vendorId: 0x1209, productId: 0x4f4c };
|
|
179
|
+
const ownerDevice = createOwnerDevice('other-path', usbHandle, 'OTHERSERIAL');
|
|
180
|
+
|
|
181
|
+
await expect(runOwnedSearch('usb-1209-4f4c-onekey', ownerDevice, [usbHandle])).resolves.toEqual(
|
|
182
|
+
[expect.objectContaining({ connectId: 'usb-1209-4f4c-onekey', uuid: '', serialNo: null })]
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('a second device on the shared bootloader path does not take the owner identity', async () => {
|
|
187
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
188
|
+
const ownerHandle = { vendorId: 0x1209, productId: 0x4f4c };
|
|
189
|
+
const otherHandle = { vendorId: 0x1209, productId: 0x4f4c };
|
|
190
|
+
const ownerDevice = createOwnerDevice(BOOTLOADER_PATH, ownerHandle, 'MINISERIAL');
|
|
191
|
+
|
|
192
|
+
await expect(
|
|
193
|
+
runOwnedSearch(BOOTLOADER_PATH, ownerDevice, [ownerHandle, otherHandle])
|
|
194
|
+
).resolves.toEqual([
|
|
195
|
+
{ connectId: 'MINISERIAL', serialNo: 'MINISERIAL', uuid: 'MINISERIAL' },
|
|
196
|
+
expect.objectContaining({ connectId: BOOTLOADER_PATH, uuid: '', serialNo: null }),
|
|
197
|
+
]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('a device swapped onto the bound bootloader path does not take the owner identity', async () => {
|
|
201
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
202
|
+
const ownerDevice = createOwnerDevice(
|
|
203
|
+
BOOTLOADER_PATH,
|
|
204
|
+
{ vendorId: 0x1209, productId: 0x4f4c },
|
|
205
|
+
'MINISERIAL'
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
await expect(
|
|
209
|
+
runOwnedSearch(BOOTLOADER_PATH, ownerDevice, [{ vendorId: 0x1209, productId: 0x4f4c }])
|
|
210
|
+
).resolves.toEqual([
|
|
211
|
+
expect.objectContaining({ connectId: BOOTLOADER_PATH, uuid: '', serialNo: null }),
|
|
212
|
+
]);
|
|
148
213
|
});
|
|
149
214
|
|
|
150
215
|
test('searchDevices resolves empty when WebUSB bring-up is unavailable', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchDevices.d.ts","sourceRoot":"","sources":["../../src/api/SearchDevices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,eAAe,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"SearchDevices.d.ts","sourceRoot":"","sources":["../../src/api/SearchDevices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,eAAe,MAAM,2BAA2B,CAAC;AAyE7D,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,UAAU;IACnD,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,IAAI;IAME,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAuFrC"}
|
package/dist/index.js
CHANGED
|
@@ -47277,18 +47277,38 @@ class PreInitialize extends BaseMethod {
|
|
|
47277
47277
|
}
|
|
47278
47278
|
|
|
47279
47279
|
const Log$e = getLogger(exports.LoggerNames.DevicePool);
|
|
47280
|
+
const getDescriptorKeys = (descriptor) => [descriptor.path, descriptor.id].filter((key) => typeof key === 'string' && key.length > 0);
|
|
47280
47281
|
const isOwnedByActiveWebUsbRequest = (descriptor, requestQueue) => {
|
|
47281
47282
|
if (!requestQueue)
|
|
47282
47283
|
return false;
|
|
47283
|
-
|
|
47284
|
-
|
|
47284
|
+
return getDescriptorKeys(descriptor).some(key => requestQueue.getRequestTasksIdByConnectId(key).length > 0);
|
|
47285
|
+
};
|
|
47286
|
+
const getUsbHandle = (descriptor) => descriptor === null || descriptor === void 0 ? void 0 : descriptor.device;
|
|
47287
|
+
const getOwningRequestDevice = (descriptor, requestQueue) => {
|
|
47288
|
+
var _a, _b;
|
|
47289
|
+
if (!requestQueue)
|
|
47290
|
+
return undefined;
|
|
47291
|
+
const usbHandle = getUsbHandle(descriptor);
|
|
47292
|
+
if (usbHandle === undefined)
|
|
47293
|
+
return undefined;
|
|
47294
|
+
for (const key of getDescriptorKeys(descriptor)) {
|
|
47295
|
+
for (const requestId of requestQueue.getRequestTasksIdByConnectId(key)) {
|
|
47296
|
+
const device = (_a = requestQueue.getTask(requestId)) === null || _a === void 0 ? void 0 : _a.method.device;
|
|
47297
|
+
if ((device === null || device === void 0 ? void 0 : device.features) &&
|
|
47298
|
+
(device.mainId === key || ((_b = device.originalDescriptor) === null || _b === void 0 ? void 0 : _b.path) === key) &&
|
|
47299
|
+
getUsbHandle(device.originalDescriptor) === usbHandle) {
|
|
47300
|
+
return device;
|
|
47301
|
+
}
|
|
47302
|
+
}
|
|
47303
|
+
}
|
|
47304
|
+
return undefined;
|
|
47285
47305
|
};
|
|
47286
47306
|
const toSearchDeviceFromDescriptor = (descriptor) => {
|
|
47287
47307
|
const connectId = descriptor.path || descriptor.id || null;
|
|
47288
47308
|
return {
|
|
47289
47309
|
connectId,
|
|
47290
|
-
uuid:
|
|
47291
|
-
serialNo:
|
|
47310
|
+
uuid: '',
|
|
47311
|
+
serialNo: null,
|
|
47292
47312
|
deviceId: null,
|
|
47293
47313
|
deviceType: hdShared.EDeviceType.Unknown,
|
|
47294
47314
|
name: descriptor.name || connectId || '',
|
|
@@ -47342,7 +47362,8 @@ class SearchDevices extends BaseMethod {
|
|
|
47342
47362
|
for (const descriptor of devicesDescriptor) {
|
|
47343
47363
|
if (hasActiveWebUsbRequest && isOwnedByActiveWebUsbRequest(descriptor, requestQueue)) {
|
|
47344
47364
|
const cached = DevicePool.getDeviceByPath(descriptor.path);
|
|
47345
|
-
const
|
|
47365
|
+
const known = (cached === null || cached === void 0 ? void 0 : cached.features) ? cached : getOwningRequestDevice(descriptor, requestQueue);
|
|
47366
|
+
const message = known ? toSearchDevice(known) : null;
|
|
47346
47367
|
deviceList.push(message !== null && message !== void 0 ? message : toSearchDeviceFromDescriptor(descriptor));
|
|
47347
47368
|
}
|
|
47348
47369
|
else {
|
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.119",
|
|
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.119",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.119",
|
|
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": "222ec4a49467e77a73766a07227069d76d9116f6"
|
|
50
50
|
}
|
package/src/api/SearchDevices.ts
CHANGED
|
@@ -15,25 +15,59 @@ const Log = getLogger(LoggerNames.DevicePool);
|
|
|
15
15
|
|
|
16
16
|
type RequestQueueLookup = {
|
|
17
17
|
getRequestTasksIdByConnectId: (connectId: string) => number[];
|
|
18
|
+
getTask: (requestId: number) => { method: { device?: Device } } | undefined;
|
|
18
19
|
};
|
|
19
20
|
|
|
21
|
+
const getDescriptorKeys = (descriptor: DeviceDescriptor) =>
|
|
22
|
+
[descriptor.path, descriptor.id].filter(
|
|
23
|
+
(key): key is string => typeof key === 'string' && key.length > 0
|
|
24
|
+
);
|
|
25
|
+
|
|
20
26
|
const isOwnedByActiveWebUsbRequest = (
|
|
21
27
|
descriptor: DeviceDescriptor,
|
|
22
28
|
requestQueue?: RequestQueueLookup
|
|
23
29
|
) => {
|
|
24
30
|
if (!requestQueue) return false;
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
return getDescriptorKeys(descriptor).some(
|
|
32
|
+
key => requestQueue.getRequestTasksIdByConnectId(key).length > 0
|
|
27
33
|
);
|
|
28
|
-
return keys.some(key => requestQueue.getRequestTasksIdByConnectId(key).length > 0);
|
|
29
34
|
};
|
|
30
35
|
|
|
36
|
+
const getUsbHandle = (descriptor?: DeviceDescriptor) =>
|
|
37
|
+
(descriptor as { device?: unknown } | undefined)?.device;
|
|
38
|
+
|
|
39
|
+
const getOwningRequestDevice = (
|
|
40
|
+
descriptor: DeviceDescriptor,
|
|
41
|
+
requestQueue?: RequestQueueLookup
|
|
42
|
+
) => {
|
|
43
|
+
if (!requestQueue) return undefined;
|
|
44
|
+
const usbHandle = getUsbHandle(descriptor);
|
|
45
|
+
// A path alone can be shared (the all-zero bootloader path, a synthesized serial-less
|
|
46
|
+
// path), so the owner's identity is only reported for the USB handle it actually bound.
|
|
47
|
+
if (usbHandle === undefined) return undefined;
|
|
48
|
+
for (const key of getDescriptorKeys(descriptor)) {
|
|
49
|
+
for (const requestId of requestQueue.getRequestTasksIdByConnectId(key)) {
|
|
50
|
+
const device = requestQueue.getTask(requestId)?.method.device;
|
|
51
|
+
if (
|
|
52
|
+
device?.features &&
|
|
53
|
+
(device.mainId === key || device.originalDescriptor?.path === key) &&
|
|
54
|
+
getUsbHandle(device.originalDescriptor) === usbHandle
|
|
55
|
+
) {
|
|
56
|
+
return device;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// A USB path is a routing key (the USB serial, a synthesized usb-vid-pid-name, or the
|
|
64
|
+
// bootloader placeholder), not a hardware identity, so it never fills uuid/serialNo.
|
|
31
65
|
const toSearchDeviceFromDescriptor = (descriptor: DeviceDescriptor): SearchDevice => {
|
|
32
66
|
const connectId = descriptor.path || descriptor.id || null;
|
|
33
67
|
return {
|
|
34
68
|
connectId,
|
|
35
|
-
uuid:
|
|
36
|
-
serialNo:
|
|
69
|
+
uuid: '',
|
|
70
|
+
serialNo: null,
|
|
37
71
|
deviceId: null,
|
|
38
72
|
deviceType: EDeviceType.Unknown,
|
|
39
73
|
name: descriptor.name || connectId || '',
|
|
@@ -108,9 +142,10 @@ export default class SearchDevices extends BaseMethod {
|
|
|
108
142
|
for (const descriptor of devicesDescriptor) {
|
|
109
143
|
if (hasActiveWebUsbRequest && isOwnedByActiveWebUsbRequest(descriptor, requestQueue)) {
|
|
110
144
|
const cached = DevicePool.getDeviceByPath(descriptor.path);
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
//
|
|
145
|
+
const known = cached?.features ? cached : getOwningRequestDevice(descriptor, requestQueue);
|
|
146
|
+
const message = known ? toSearchDevice(known) : null;
|
|
147
|
+
// Do not probe a path an in-flight request already owns. A cache miss is still a
|
|
148
|
+
// connected device: report the owning request's device, or the path with no identity.
|
|
114
149
|
deviceList.push(message ?? toSearchDeviceFromDescriptor(descriptor));
|
|
115
150
|
} else {
|
|
116
151
|
try {
|