@onekeyfe/hwk-keystone-connector-usb 1.2.6-alpha.0 → 1.2.8-alpha.13
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/{chunk-VMQB3BQI.mjs → chunk-RZ6UI5PS.mjs} +86 -11
- package/dist/chunk-RZ6UI5PS.mjs.map +1 -0
- package/dist/{chunk-BYR5HEA3.js → chunk-U76BQU3H.js} +92 -17
- package/dist/chunk-U76BQU3H.js.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/dist/webusb.js +2 -2
- package/dist/webusb.mjs +1 -1
- package/package.json +4 -23
- package/dist/chunk-BYR5HEA3.js.map +0 -1
- package/dist/chunk-VMQB3BQI.mjs.map +0 -1
- package/dist/nodeusb.d.mts +0 -7
- package/dist/nodeusb.d.ts +0 -7
- package/dist/nodeusb.js +0 -13
- package/dist/nodeusb.js.map +0 -1
- package/dist/nodeusb.mjs +0 -13
- package/dist/nodeusb.mjs.map +0 -1
|
@@ -64,7 +64,10 @@ function mapKeystoneUsbError(err) {
|
|
|
64
64
|
const message = err instanceof Error ? err.message : String(err);
|
|
65
65
|
if (statusCode !== void 0) {
|
|
66
66
|
const fromDevice = isDeviceStatus(statusCode);
|
|
67
|
-
|
|
67
|
+
let code = fromDevice ? DEVICE_STATUS_MAP[statusCode] ?? HardwareErrorCode.UnknownError : CLIENT_STATUS_MAP[statusCode] ?? HardwareErrorCode.TransportError;
|
|
68
|
+
if (statusCode === Status.PRS_PARSING_DISALLOWED && !/\blocked\b/i.test(message)) {
|
|
69
|
+
code = HardwareErrorCode.DeviceBusy;
|
|
70
|
+
}
|
|
68
71
|
let origin;
|
|
69
72
|
if (fromDevice) {
|
|
70
73
|
origin = "device";
|
|
@@ -90,12 +93,14 @@ function mapKeystoneUsbError(err) {
|
|
|
90
93
|
|
|
91
94
|
// src/KeystoneUsbConnectorBase.ts
|
|
92
95
|
import { UR, URDecoder, UREncoder } from "@ngraveio/bc-ur";
|
|
96
|
+
import bytewords from "@ngraveio/bc-ur/dist/bytewords";
|
|
93
97
|
import { Actions } from "@keystonehq/hw-transport-usb";
|
|
94
98
|
import {
|
|
95
99
|
EConnectorInteraction,
|
|
96
100
|
HardwareErrorCode as HardwareErrorCode2,
|
|
97
101
|
MISSING_BIP32_MASTER_FINGERPRINT,
|
|
98
102
|
TypedEventEmitter,
|
|
103
|
+
assertBoundedCbor,
|
|
99
104
|
createHardwareLinkId,
|
|
100
105
|
createHardwareSearchTargetId,
|
|
101
106
|
createHwkError as createHwkError2,
|
|
@@ -113,20 +118,68 @@ var KEYSTONE_PUBLIC_DATA_UR_TYPE = "qr-hardware-call";
|
|
|
113
118
|
function toUrEncoded(ur) {
|
|
114
119
|
return new UREncoder(new UR(Buffer.from(ur.urData, "hex"), ur.urType), Infinity).nextPart().toUpperCase();
|
|
115
120
|
}
|
|
121
|
+
var MAX_UR_MESSAGE_BYTES = 1024 * 1024;
|
|
122
|
+
var MAX_UR_SEQ_LENGTH = 32768;
|
|
123
|
+
var CBOR_ARGUMENT_BYTES = [1, 2, 4, 8];
|
|
124
|
+
function readFountainPart(input) {
|
|
125
|
+
let offset = 0;
|
|
126
|
+
const readHead = (expectedMajor) => {
|
|
127
|
+
const initial = input[offset];
|
|
128
|
+
offset += 1;
|
|
129
|
+
if (Math.floor(initial / 32) !== expectedMajor) {
|
|
130
|
+
throw new Error("Keystone USB reply part is not a fountain part");
|
|
131
|
+
}
|
|
132
|
+
const info = initial % 32;
|
|
133
|
+
if (info < 24) return info;
|
|
134
|
+
const size = CBOR_ARGUMENT_BYTES[info - 24];
|
|
135
|
+
let value = 0;
|
|
136
|
+
for (let i = 0; i < size; i += 1) value = value * 256 + input[offset + i];
|
|
137
|
+
offset += size;
|
|
138
|
+
return value;
|
|
139
|
+
};
|
|
140
|
+
if (readHead(4) !== 5) throw new Error("Keystone USB reply part is not a fountain part");
|
|
141
|
+
const seqNum = readHead(0);
|
|
142
|
+
const seqLength = readHead(0);
|
|
143
|
+
const messageLength = readHead(0);
|
|
144
|
+
readHead(0);
|
|
145
|
+
const fragmentLength = readHead(2);
|
|
146
|
+
return { seqNum, seqLength, messageLength, fragmentLength };
|
|
147
|
+
}
|
|
148
|
+
function assertBoundedUrPart(part) {
|
|
149
|
+
const match = /^ur:[a-z0-9-]+\/(?:(\d{1,9})-(\d{1,9})\/)?([a-z]+)$/i.exec(part);
|
|
150
|
+
if (!match) throw new Error("Keystone USB reply part is not a UR");
|
|
151
|
+
const payload = Buffer.from(
|
|
152
|
+
bytewords.decode(match[3].toLowerCase(), bytewords.STYLES.MINIMAL),
|
|
153
|
+
"hex"
|
|
154
|
+
);
|
|
155
|
+
assertBoundedCbor(payload, MAX_UR_MESSAGE_BYTES);
|
|
156
|
+
if (match[1] === void 0) return;
|
|
157
|
+
const header = readFountainPart(payload);
|
|
158
|
+
if (header.seqNum < 1 || header.seqNum > header.seqLength || header.seqNum !== Number(match[1]) || header.seqLength !== Number(match[2]) || header.fragmentLength < 1 || header.messageLength < 1 || header.messageLength > MAX_UR_MESSAGE_BYTES || header.seqLength > MAX_UR_SEQ_LENGTH || header.seqLength !== Math.ceil(header.messageLength / header.fragmentLength)) {
|
|
159
|
+
throw new Error("Keystone USB reply part has inconsistent or oversized headers");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
116
162
|
function fromUrEncoded(encoded) {
|
|
117
163
|
const text = typeof encoded === "string" ? encoded.trim() : "";
|
|
118
164
|
const parts = text.split(/\s+/).filter(Boolean);
|
|
119
165
|
const decoder = new URDecoder();
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
try {
|
|
167
|
+
if (parts.length > MAX_UR_SEQ_LENGTH) throw new Error("Keystone USB reply has too many parts");
|
|
168
|
+
for (const part of parts) {
|
|
169
|
+
assertBoundedUrPart(part);
|
|
170
|
+
decoder.receivePart(part);
|
|
171
|
+
if (decoder.isComplete()) break;
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
123
174
|
}
|
|
124
175
|
if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {
|
|
125
176
|
const shape = typeof encoded === "string" ? `string len=${text.length} parts=${parts.length}` : typeof encoded;
|
|
126
177
|
throw createHwkError2({
|
|
127
178
|
code: HardwareErrorCode2.PayloadTooLarge,
|
|
128
179
|
message: `Keystone USB returned an incomplete BC-UR response (${shape})`,
|
|
129
|
-
origin: "device"
|
|
180
|
+
origin: "device",
|
|
181
|
+
// The device processed the request; only its reply is unusable.
|
|
182
|
+
params: { replyUnreadable: true }
|
|
130
183
|
});
|
|
131
184
|
}
|
|
132
185
|
const ur = decoder.resultUR();
|
|
@@ -265,7 +318,14 @@ var KeystoneUsbConnectorBase = class {
|
|
|
265
318
|
});
|
|
266
319
|
}
|
|
267
320
|
if (this.transportClass.connectDevice) {
|
|
321
|
+
if (availableDevices.length === 0) {
|
|
322
|
+
throw createHwkError2({
|
|
323
|
+
code: HardwareErrorCode2.DeviceNotFound,
|
|
324
|
+
message: "No Keystone USB device is available"
|
|
325
|
+
});
|
|
326
|
+
}
|
|
268
327
|
let readableDeviceFound = false;
|
|
328
|
+
let ambiguous = false;
|
|
269
329
|
let lastError;
|
|
270
330
|
let matched;
|
|
271
331
|
for (const device2 of availableDevices) {
|
|
@@ -275,8 +335,13 @@ var KeystoneUsbConnectorBase = class {
|
|
|
275
335
|
const candidateConfig = await this._readAppConfig(candidate.transport);
|
|
276
336
|
readableDeviceFound = true;
|
|
277
337
|
if (candidateConfig.mfp?.toLowerCase() === expectedMasterFingerprint.toLowerCase()) {
|
|
338
|
+
if (matched) {
|
|
339
|
+
candidate.dispose();
|
|
340
|
+
ambiguous = true;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
278
343
|
matched = { device: device2, opened: candidate, config: candidateConfig };
|
|
279
|
-
|
|
344
|
+
continue;
|
|
280
345
|
}
|
|
281
346
|
candidate.dispose();
|
|
282
347
|
} catch (error) {
|
|
@@ -284,11 +349,18 @@ var KeystoneUsbConnectorBase = class {
|
|
|
284
349
|
lastError = error;
|
|
285
350
|
}
|
|
286
351
|
}
|
|
352
|
+
if (ambiguous) {
|
|
353
|
+
matched?.opened.dispose();
|
|
354
|
+
throw createHwkError2({
|
|
355
|
+
code: HardwareErrorCode2.DeviceOneDeviceOnly,
|
|
356
|
+
message: "More than one connected Keystone reports this wallet; keep one connected"
|
|
357
|
+
});
|
|
358
|
+
}
|
|
287
359
|
if (!matched) {
|
|
288
360
|
if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);
|
|
289
361
|
throw createHwkError2({
|
|
290
362
|
code: HardwareErrorCode2.DeviceMismatch,
|
|
291
|
-
message:
|
|
363
|
+
message: "No connected Keystone matches the requested wallet"
|
|
292
364
|
});
|
|
293
365
|
}
|
|
294
366
|
selectedDevice = matched.device;
|
|
@@ -332,7 +404,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
332
404
|
if (expectedMasterFingerprint && config.mfp && config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()) {
|
|
333
405
|
throw createHwkError2({
|
|
334
406
|
code: HardwareErrorCode2.DeviceMismatch,
|
|
335
|
-
|
|
407
|
+
// The master fingerprint identifies the wallet; keep it out of messages that reach logs.
|
|
408
|
+
message: "Connected Keystone wallet does not match the requested wallet"
|
|
336
409
|
});
|
|
337
410
|
}
|
|
338
411
|
const sessionId = createHardwareLinkId("keystone");
|
|
@@ -445,6 +518,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
445
518
|
const encoded = toUrEncoded({ urType, urData });
|
|
446
519
|
const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;
|
|
447
520
|
const publicDataKey = session.mfp?.toLowerCase() ?? sessionId;
|
|
521
|
+
if (!isPublicDataRequest) this.publicDataConfirmedWallets.delete(publicDataKey);
|
|
448
522
|
const shouldShowConfirmation = !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);
|
|
449
523
|
if (shouldShowConfirmation) {
|
|
450
524
|
this.emitter.emit("ui-event", {
|
|
@@ -472,7 +546,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
472
546
|
Actions.CMD_CHECK_LOCK_STATUS,
|
|
473
547
|
""
|
|
474
548
|
);
|
|
475
|
-
return success({ locked: response.payload });
|
|
549
|
+
return success({ locked: response.payload === true });
|
|
476
550
|
}
|
|
477
551
|
case "getAppConfig":
|
|
478
552
|
return success(await this._readAppConfig(session.transport));
|
|
@@ -534,7 +608,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
534
608
|
});
|
|
535
609
|
}
|
|
536
610
|
return {
|
|
537
|
-
|
|
611
|
+
// Device-supplied text reaches the host UI and version gates; accept only a version number.
|
|
612
|
+
version: typeof response.firmwareVersion === "string" && /^\d{1,4}(\.\d{1,4}){1,3}(-[0-9A-Za-z.]{1,20})?$/.test(response.firmwareVersion) ? response.firmwareVersion : void 0,
|
|
538
613
|
mfp: masterFingerprint
|
|
539
614
|
};
|
|
540
615
|
}
|
|
@@ -560,4 +635,4 @@ export {
|
|
|
560
635
|
mapKeystoneUsbError,
|
|
561
636
|
KeystoneUsbConnectorBase
|
|
562
637
|
};
|
|
563
|
-
//# sourceMappingURL=chunk-
|
|
638
|
+
//# sourceMappingURL=chunk-RZ6UI5PS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/KeystoneUsbConnectorBase.ts"],"sourcesContent":["import { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport { Status } from '@keystonehq/hw-transport-error';\n\nimport type { HwkError, HwkErrorOrigin } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Firmware status words are the low end of `Status` (0..15); client codes start at\n * `ERR_DEVICE_NOT_OPENED` (0xA0000001), so anything below came from a device response frame.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/** Firmware status words from a device response (EAPDU_Readme.md in the Keystone USB SDK). */\nconst DEVICE_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.RSP_FAILURE_CODE]: HardwareErrorCode.UnknownError,\n [Status.PRS_INVALID_TOTAL_PACKETS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_INVALID_INDEX]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_PARSING_ERROR]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_PARSING_UNMATCHED]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_MISMATCHED_WALLET]: HardwareErrorCode.DeviceMismatch,\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: HardwareErrorCode.PinInvalid,\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: HardwareErrorCode.ChainNotSupported,\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_EXPORT_ADDRESS_ERROR]: HardwareErrorCode.UnknownError,\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_EXPORT_ADDRESS_BUSY]: HardwareErrorCode.DeviceBusyInternal,\n};\n\n/** Used when the transport forwarded only its 'unknown error' placeholder for a firmware status. */\nconst DEVICE_STATUS_MESSAGE: Partial<Record<number, string>> = {\n [Status.RSP_FAILURE_CODE]: 'Keystone reported a failure',\n [Status.PRS_INVALID_TOTAL_PACKETS]: 'Keystone rejected the request framing (total packets)',\n [Status.PRS_INVALID_INDEX]: 'Keystone rejected the request framing (packet index)',\n [Status.PRS_PARSING_REJECTED]: 'Rejected on the Keystone screen',\n [Status.PRS_PARSING_ERROR]: 'Keystone could not parse the request',\n [Status.PRS_PARSING_DISALLOWED]: 'Keystone declined the request in its current state',\n [Status.PRS_PARSING_UNMATCHED]: 'Keystone found no handler for the request',\n [Status.PRS_PARSING_MISMATCHED_WALLET]: 'The request belongs to a different Keystone wallet',\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: 'Keystone password verification failed',\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: 'Keystone does not support this chain',\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: 'Keystone rejected the address export parameters',\n [Status.PRS_EXPORT_ADDRESS_ERROR]: 'Keystone failed to export the address',\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: 'Keystone declined to export the address',\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: 'Address export rejected on the Keystone screen',\n [Status.PRS_EXPORT_ADDRESS_BUSY]: 'Keystone is busy with another request',\n};\n\n/** The placeholder both Keystone transports use when they have nothing better. */\nconst PLACEHOLDER_MESSAGE = /^unknown error\\b/i;\n\n/** Client-side (transport/framing) failures, never reached the device. */\nconst CLIENT_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.ERR_DEVICE_NOT_OPENED]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_DEVICE_NOT_FOUND]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_TIMEOUT]: HardwareErrorCode.OperationTimeout,\n [Status.ERR_DATA_TOO_LARGE]: HardwareErrorCode.PayloadTooLarge,\n [Status.ERR_NOT_SUPPORTED]: HardwareErrorCode.TransportNotAvailable,\n};\n\n/** WebUSB DOMExceptions; an unplug or bus reset mid-call is the common case. */\nconst DOM_EXCEPTION_MAP = new Map<string, { code: HardwareErrorCode; origin: HwkErrorOrigin }>([\n ['NotFoundError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['NetworkError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['SecurityError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['NotAllowedError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['InvalidStateError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n ['AbortError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n]);\n\n/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because\n * duplicate `@keystonehq/*` module instances break `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const fields: { name?: unknown; code?: unknown; transportErrorCode?: unknown } =\n err && typeof err === 'object' ? err : {};\n const domName = typeof fields.name === 'string' ? fields.name : undefined;\n\n // Only five-digit codes are HWK codes; legacy DOMException codes (NotFoundError\n // is 8) must not pass through as hardware errors.\n if (typeof fields.code === 'number' && fields.code >= 10000 && fields.code <= 99999) {\n return err as HwkError;\n }\n\n const statusCode =\n typeof fields.transportErrorCode === 'number' ? fields.transportErrorCode : undefined;\n\n const message = err instanceof Error ? err.message : String(err);\n\n if (statusCode !== undefined) {\n const fromDevice = isDeviceStatus(statusCode);\n // An unlisted firmware status keeps origin 'device'; 'transport' would make the\n // adapter tear down a live session over an on-device decline.\n let code = fromDevice\n ? DEVICE_STATUS_MAP[statusCode] ?? HardwareErrorCode.UnknownError\n : CLIENT_STATUS_MAP[statusCode] ?? HardwareErrorCode.TransportError;\n // Firmware also returns PRS_PARSING_DISALLOWED for an unfinished request, a pending approval\n // and a screen that takes no requests; only its \"Device is locked\" text means locked.\n if (statusCode === Status.PRS_PARSING_DISALLOWED && !/\\blocked\\b/i.test(message)) {\n code = HardwareErrorCode.DeviceBusy;\n }\n let origin: HwkErrorOrigin | undefined;\n if (fromDevice) {\n origin = 'device';\n } else if (code !== HardwareErrorCode.OperationTimeout) {\n origin = 'transport';\n }\n const description = DEVICE_STATUS_MESSAGE[statusCode];\n return createHwkError({\n code,\n // The device's own payload text wins over the table.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A timeout may be either side, so it stays unlabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : undefined;\n if (domMapping) {\n return createHwkError({ ...domMapping, message, params: { domExceptionName: domName } });\n }\n\n // This mapper only wraps transport calls, so 'transport' names the throw site.\n return createHwkError({ code: HardwareErrorCode.TransportError, message, origin: 'transport' });\n}\n","import { UR, URDecoder, UREncoder } from '@ngraveio/bc-ur';\n// Not re-exported by the package root; pinned with the package version.\nimport bytewords from '@ngraveio/bc-ur/dist/bytewords';\nimport { Actions } from '@keystonehq/hw-transport-usb';\nimport {\n EConnectorInteraction,\n HardwareErrorCode,\n MISSING_BIP32_MASTER_FINGERPRINT,\n TypedEventEmitter,\n assertBoundedCbor,\n createHardwareLinkId,\n createHardwareSearchTargetId,\n createHwkError,\n hasHardwareRuntimeIdPrefix,\n parseBip32MasterFingerprint,\n parseHardwareRuntimeId,\n serializeConnectorError,\n success,\n} from '@onekeyfe/hwk-adapter-core';\n\nimport { mapKeystoneUsbError } from './errors';\n\nimport type {\n ConnectorCallResult,\n ConnectorConnectTarget,\n ConnectorDevice,\n ConnectorEventMap,\n ConnectorEventType,\n ConnectorSearchDevicesOptions,\n ConnectorSession,\n IConnector,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\nimport type { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';\n\n/** Descriptor fields readable before opening; any may be absent if not published. */\nexport interface KeystoneUsbDeviceDescriptor {\n serialNumber?: string;\n productName?: string;\n manufacturerName?: string;\n vendorId?: number;\n productId?: number;\n /** Device release number (bcdDevice), split into its three nibble groups. */\n deviceVersionMajor?: number;\n deviceVersionMinor?: number;\n deviceVersionSubminor?: number;\n usbVersionMajor?: number;\n usbVersionMinor?: number;\n usbVersionSubminor?: number;\n deviceClass?: number;\n deviceSubclass?: number;\n deviceProtocol?: number;\n}\n\n/** The serial is not shown on the unit, so it would not help tell two devices apart. */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\n/** Static surface of `TransportWebUSB`, injected by `_subpath/webusb`. */\nexport interface KeystoneUsbTransportStatic {\n connect(config?: TransportConfig): Promise<TransportHID>;\n connectDevice?(\n device: KeystoneUsbDeviceDescriptor,\n config?: TransportConfig\n ): Promise<TransportHID>;\n getKeystoneDevices(): Promise<ReadonlyArray<KeystoneUsbDeviceDescriptor>>;\n requestPermission?(): Promise<void>;\n isSupported(): Promise<boolean>;\n /** Release transport-lifetime resources owned by the platform wrapper. */\n disposeTransport?(transport: TransportHID): void;\n}\n\ninterface KeystoneUr {\n urType: string;\n urData: string;\n}\n\ninterface UsbSession {\n transport: TransportHID;\n mfp?: string;\n dispose(): void;\n}\n\ninterface AppConfig {\n version?: string;\n mfp?: string;\n}\n\ninterface OpenedUsbTransport {\n transport: TransportHID;\n bindSessionId(sessionId: string): void;\n dispose(): void;\n}\n\ntype KeystoneUsbConnectInput =\n | { searchTargetId: string; expectedMasterFingerprint?: never }\n | { searchTargetId?: never; expectedMasterFingerprint: string }\n | { searchTargetId?: never; expectedMasterFingerprint?: never };\n\n// The SDK default of 15s is too short for on-device confirmation.\nconst DEFAULT_TIMEOUT_MS = 100_000;\n\nconst KEYSTONE_PUBLIC_DATA_UR_TYPE = 'qr-hardware-call';\n\nfunction toUrEncoded(ur: KeystoneUr): string {\n return new UREncoder(new UR(Buffer.from(ur.urData, 'hex'), ur.urType), Infinity)\n .nextPart()\n .toUpperCase();\n}\n\n/** The most data one reply may carry, whatever its fragment size. */\nconst MAX_UR_MESSAGE_BYTES = 1024 * 1024;\n/**\n * The fountain decoder's work per mixed part grows with the square of the part count, so a reply\n * cut into tiny fragments can stall it even within the byte limit.\n */\nconst MAX_UR_SEQ_LENGTH = 32_768;\n/** Argument bytes for CBOR additional info 24, 25, 26 and 27. */\nconst CBOR_ARGUMENT_BYTES = [1, 2, 4, 8];\n\n/** Reads `[seqNum, seqLen, messageLen, checksum, fragment]` from CBOR that passed the bounds. */\nfunction readFountainPart(input: Uint8Array) {\n let offset = 0;\n const readHead = (expectedMajor: number): number => {\n const initial = input[offset];\n offset += 1;\n if (Math.floor(initial / 32) !== expectedMajor) {\n throw new Error('Keystone USB reply part is not a fountain part');\n }\n const info = initial % 32;\n if (info < 24) return info;\n const size = CBOR_ARGUMENT_BYTES[info - 24];\n let value = 0;\n for (let i = 0; i < size; i += 1) value = value * 256 + input[offset + i];\n offset += size;\n return value;\n };\n if (readHead(4) !== 5) throw new Error('Keystone USB reply part is not a fountain part');\n const seqNum = readHead(0);\n const seqLength = readHead(0);\n const messageLength = readHead(0);\n readHead(0); // checksum\n const fragmentLength = readHead(2);\n return { seqNum, seqLength, messageLength, fragmentLength };\n}\n\n/** Checks one UR part from the device before the vendor decoder parses its CBOR. */\nfunction assertBoundedUrPart(part: string): void {\n const match = /^ur:[a-z0-9-]+\\/(?:(\\d{1,9})-(\\d{1,9})\\/)?([a-z]+)$/i.exec(part);\n if (!match) throw new Error('Keystone USB reply part is not a UR');\n // Minimal bytewords carry their own CRC32; decode throws on a mismatch.\n const payload = Buffer.from(\n bytewords.decode(match[3].toLowerCase(), bytewords.STYLES.MINIMAL),\n 'hex'\n );\n assertBoundedCbor(payload, MAX_UR_MESSAGE_BYTES);\n if (match[1] === undefined) return;\n const header = readFountainPart(payload);\n // The text header, the CBOR header and the real sizes must agree, so the declared part count\n // is tied to the data the reply actually carries. USB is lossless and Keystone answers with a\n // single-part UR, so a mixed fountain part (seqNum past seqLen) is refused: decoding each one\n // costs time quadratic in the part count.\n if (\n header.seqNum < 1 ||\n header.seqNum > header.seqLength ||\n header.seqNum !== Number(match[1]) ||\n header.seqLength !== Number(match[2]) ||\n header.fragmentLength < 1 ||\n header.messageLength < 1 ||\n header.messageLength > MAX_UR_MESSAGE_BYTES ||\n header.seqLength > MAX_UR_SEQ_LENGTH ||\n header.seqLength !== Math.ceil(header.messageLength / header.fragmentLength)\n ) {\n throw new Error('Keystone USB reply part has inconsistent or oversized headers');\n }\n}\n\nfunction fromUrEncoded(encoded: unknown): KeystoneUr {\n // One complete UR or whitespace-separated parts; EAPDU framing is the transport's job.\n const text = typeof encoded === 'string' ? encoded.trim() : '';\n const parts = text.split(/\\s+/).filter(Boolean);\n const decoder = new URDecoder();\n try {\n if (parts.length > MAX_UR_SEQ_LENGTH) throw new Error('Keystone USB reply has too many parts');\n for (const part of parts) {\n assertBoundedUrPart(part);\n decoder.receivePart(part);\n if (decoder.isComplete()) break;\n }\n } catch {\n // A part that does not decode is the device's reply, not a broken link: report it below as\n // an unreadable answer so the session is kept rather than re-claimed.\n }\n if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {\n const shape =\n typeof encoded === 'string'\n ? `string len=${text.length} parts=${parts.length}`\n : typeof encoded;\n throw createHwkError({\n code: HardwareErrorCode.PayloadTooLarge,\n message: `Keystone USB returned an incomplete BC-UR response (${shape})`,\n origin: 'device',\n // The device processed the request; only its reply is unusable.\n params: { replyUnreadable: true },\n });\n }\n const ur = decoder.resultUR();\n return { urType: ur.type, urData: ur.cbor.toString('hex') };\n}\n\n/**\n * Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so\n * `connect()` only caches the transport object.\n */\nexport class KeystoneUsbConnectorBase implements IConnector {\n readonly connectionType = 'usb' as const;\n\n private readonly transportClass: KeystoneUsbTransportStatic;\n\n private readonly timeoutMs: number;\n\n private readonly emitter = new TypedEventEmitter<ConnectorEventMap>();\n\n private readonly sessions = new Map<string, UsbSession>();\n\n private readonly discoveredDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private readonly availabilityDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private activeDiscoveryGeneration: symbol | undefined;\n\n private activeAvailabilityGeneration: symbol | undefined;\n\n /**\n * Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can\n * re-enumerate between exports, and that must not re-prompt.\n */\n private readonly publicDataConfirmedWallets = new Set<string>();\n\n constructor(transportClass: KeystoneUsbTransportStatic, options?: { timeoutMs?: number }) {\n this.transportClass = transportClass;\n this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n private _invalidateDiscoverySnapshot(): void {\n this.activeDiscoveryGeneration = undefined;\n this.discoveredDevices.clear();\n }\n\n private _invalidateAvailabilitySnapshot(): void {\n this.activeAvailabilityGeneration = undefined;\n this.availabilityDevices.clear();\n }\n\n async searchDevices(options?: ConnectorSearchDevicesOptions): Promise<ConnectorDevice[]> {\n const isAvailabilitySearch = options?.purpose === 'availability';\n const discoveryGeneration = Symbol(\n isAvailabilitySearch ? 'keystone-usb-availability' : 'keystone-usb-discovery'\n );\n if (isAvailabilitySearch) {\n this._invalidateAvailabilitySnapshot();\n this.activeAvailabilityGeneration = discoveryGeneration;\n } else {\n this._invalidateDiscoverySnapshot();\n this.activeDiscoveryGeneration = discoveryGeneration;\n }\n // Enumeration DOMException codes collide with the HWK range, so map them too.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // Without an mfp before opening, the target id names only this snapshot; platforms that\n // cannot reopen a cached descriptor fail closed on multi-device selection.\n if (\n (isAvailabilitySearch\n ? this.activeAvailabilityGeneration\n : this.activeDiscoveryGeneration) !== discoveryGeneration\n ) {\n return [];\n }\n return devices.map(device => {\n const connectId = createHardwareSearchTargetId('keystone');\n (isAvailabilitySearch ? this.availabilityDevices : this.discoveredDevices).set(\n connectId,\n device\n );\n return {\n connectId,\n deviceId: '',\n name: usbDisplayName(device),\n connectionType: 'usb',\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n // Verbatim descriptor fields; a missing key means the device did not publish it.\n raw: {\n serialNumber: device.serialNumber,\n productName: device.productName,\n manufacturerName: device.manufacturerName,\n vendorId: device.vendorId,\n productId: device.productId,\n deviceVersionMajor: device.deviceVersionMajor,\n deviceVersionMinor: device.deviceVersionMinor,\n deviceVersionSubminor: device.deviceVersionSubminor,\n usbVersionMajor: device.usbVersionMajor,\n usbVersionMinor: device.usbVersionMinor,\n usbVersionSubminor: device.usbVersionSubminor,\n deviceClass: device.deviceClass,\n deviceSubclass: device.deviceSubclass,\n deviceProtocol: device.deviceProtocol,\n },\n };\n });\n }\n\n async connect(searchTargetIdOrExpectedMasterFingerprint?: string): Promise<ConnectorSession> {\n return this._connectResolved(\n this._resolveConnectInput(searchTargetIdOrExpectedMasterFingerprint)\n );\n }\n\n async connectTarget(target: ConnectorConnectTarget): Promise<ConnectorSession> {\n switch (target.type) {\n case 'default':\n return this._connectResolved({});\n case 'search-target':\n return this._connectResolved({ searchTargetId: target.searchTargetId });\n case 'expected-device-identity': {\n const expectedMasterFingerprint = parseBip32MasterFingerprint(target.deviceIdentity);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a valid master fingerprint identity',\n });\n }\n return this._connectResolved({ expectedMasterFingerprint });\n }\n default:\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Unsupported Keystone USB connection target',\n });\n }\n }\n\n private async _connectResolved({\n searchTargetId,\n expectedMasterFingerprint,\n }: KeystoneUsbConnectInput): Promise<ConnectorSession> {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.Searching,\n payload: { sessionId: '' },\n });\n let selectedDevice = searchTargetId\n ? this.discoveredDevices.get(searchTargetId) ?? this.availabilityDevices.get(searchTargetId)\n : undefined;\n if (searchTargetId && !selectedDevice) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Keystone USB search target is not in the current scan: ${searchTargetId}`,\n recovery: { scope: 'search-target' },\n });\n }\n let openedTransport: OpenedUsbTransport | undefined;\n try {\n let config: AppConfig;\n\n if (expectedMasterFingerprint && !searchTargetId) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (!this.transportClass.connectDevice && availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot identify one of multiple connected Keystone devices',\n });\n }\n\n if (this.transportClass.connectDevice) {\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n let readableDeviceFound = false;\n let ambiguous = false;\n let lastError: unknown;\n let matched:\n | {\n device: KeystoneUsbDeviceDescriptor;\n opened: OpenedUsbTransport;\n config: AppConfig;\n }\n | undefined;\n for (const device of availableDevices) {\n let candidate: OpenedUsbTransport | undefined;\n try {\n // eslint-disable-next-line no-await-in-loop\n candidate = await this._openTransport(device);\n // eslint-disable-next-line no-await-in-loop\n const candidateConfig = await this._readAppConfig(candidate.transport);\n readableDeviceFound = true;\n if (candidateConfig.mfp?.toLowerCase() === expectedMasterFingerprint.toLowerCase()) {\n if (matched) {\n candidate.dispose();\n ambiguous = true;\n break;\n }\n matched = { device, opened: candidate, config: candidateConfig };\n // eslint-disable-next-line no-continue\n continue;\n }\n candidate.dispose();\n } catch (error) {\n candidate?.dispose();\n lastError = error;\n }\n }\n // The fingerprint is self-reported, so two claimants are refused, not ranked.\n if (ambiguous) {\n matched?.opened.dispose();\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'More than one connected Keystone reports this wallet; keep one connected',\n });\n }\n if (!matched) {\n if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: 'No connected Keystone matches the requested wallet',\n });\n }\n selectedDevice = matched.device;\n openedTransport = matched.opened;\n config = matched.config;\n } else {\n openedTransport = await this._openTransport();\n config = await this._readAppConfig(openedTransport.transport);\n }\n } else {\n if (!selectedDevice && this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'Select a Keystone USB device before connecting',\n });\n }\n [selectedDevice] = availableDevices;\n }\n if (selectedDevice && !this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot target one of multiple connected Keystone devices',\n });\n }\n }\n openedTransport = await this._openTransport(selectedDevice);\n config = await this._readAppConfig(openedTransport.transport);\n }\n\n const activeOpenedTransport = openedTransport;\n const { transport } = activeOpenedTransport;\n if (\n expectedMasterFingerprint &&\n config.mfp &&\n config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()\n ) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n // The master fingerprint identifies the wallet; keep it out of messages that reach logs.\n message: 'Connected Keystone wallet does not match the requested wallet',\n });\n }\n const sessionId = createHardwareLinkId('keystone');\n activeOpenedTransport.bindSessionId(sessionId);\n this.sessions.set(sessionId, {\n transport,\n mfp: config.mfp,\n dispose: () => activeOpenedTransport.dispose(),\n });\n openedTransport = undefined;\n const device: ConnectorDevice = {\n connectId: sessionId,\n deviceId: '',\n name: selectedDevice ? usbDisplayName(selectedDevice) : 'Keystone',\n model: selectedDevice?.productName,\n connectionType: 'usb',\n serialNumber: selectedDevice?.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint: config.mfp },\n };\n this.emitter.emit('device-connect', { device });\n return {\n sessionId,\n deviceInfo: this._toDeviceInfo(device, config.version, config.mfp),\n };\n } catch (err) {\n openedTransport?.dispose();\n throw mapKeystoneUsbError(err);\n }\n }\n\n private async _openTransport(device?: KeystoneUsbDeviceDescriptor): Promise<OpenedUsbTransport> {\n // A rejected candidate may keep its disconnect listener; a per-descriptor\n // holder stops it from retiring a later matched session.\n let connectedSessionId: string | undefined;\n const transportConfig: TransportConfig = {\n timeout: this.timeoutMs,\n disconnectListener: () =>\n connectedSessionId ? this.disconnect(connectedSessionId) : undefined,\n };\n const transport = await (device && this.transportClass.connectDevice\n ? this.transportClass.connectDevice(device, transportConfig)\n : this.transportClass.connect(transportConfig));\n let disposed = false;\n return {\n transport,\n bindSessionId(sessionId: string) {\n connectedSessionId = sessionId;\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this.transportClass.disposeTransport?.(transport);\n },\n };\n }\n\n private _resolveConnectInput(value?: string): KeystoneUsbConnectInput {\n if (!value) return {};\n\n const runtimeId = parseHardwareRuntimeId(value);\n if (runtimeId) {\n // Ownership is settled by the snapshot lookup in `_connectResolved`.\n if (runtimeId.kind === 'search-target' && runtimeId.vendor === 'keystone') {\n return { searchTargetId: value };\n }\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received an incompatible hardware runtime id',\n params: { kind: runtimeId.kind, vendor: runtimeId.vendor },\n });\n }\n\n if (hasHardwareRuntimeIdPrefix(value)) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received a malformed hardware runtime id',\n });\n }\n\n const expectedMasterFingerprint = parseBip32MasterFingerprint(value);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a search target or master fingerprint',\n });\n }\n return { expectedMasterFingerprint };\n }\n\n disconnect(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n this.sessions.delete(sessionId);\n if (session) {\n session.dispose();\n // No persistent claim to release; each send() already closed the device.\n this.emitter.emit('device-disconnect', { connectId: sessionId });\n }\n return Promise.resolve();\n }\n\n /** Keep the vendor transport as the EAPDU framing authority. */\n private async _sendResolveUr(transport: TransportHID, encodedUr: string): Promise<KeystoneUr> {\n const response = await transport.send<{ payload: string }>(Actions.CMD_RESOLVE_UR, encodedUr);\n return fromUrEncoded(response.payload);\n }\n\n async call(sessionId: string, method: string, params: unknown): Promise<ConnectorCallResult> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Unknown Keystone USB session: ${sessionId}`,\n })\n ),\n };\n }\n\n try {\n switch (method) {\n case 'resolveUr': {\n const { urType, urData } = params as KeystoneUr;\n const encoded = toUrEncoded({ urType, urData });\n const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;\n // Public-data export prompts once per wallet; signing always prompts. A signing request\n // leaves the device's export screen, so the next export may ask again and prompts again.\n const publicDataKey = session.mfp?.toLowerCase() ?? sessionId;\n if (!isPublicDataRequest) this.publicDataConfirmedWallets.delete(publicDataKey);\n const shouldShowConfirmation =\n !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.ConfirmOnDevice,\n payload: { sessionId },\n });\n }\n try {\n const response = await this._sendResolveUr(session.transport, encoded);\n if (isPublicDataRequest) {\n this.publicDataConfirmedWallets.add(publicDataKey);\n }\n return success(response);\n } finally {\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.InteractionComplete,\n payload: { sessionId },\n });\n }\n }\n }\n case 'checkLockStatus': {\n const response = await session.transport.send<{ payload: boolean }>(\n Actions.CMD_CHECK_LOCK_STATUS,\n ''\n );\n // `true` = locked is inferred from the SDK method name only; unverified on hardware.\n // Only a real boolean true counts, so a malformed reply never reads as a lock state.\n return success({ locked: response.payload === true });\n }\n case 'getAppConfig':\n return success(await this._readAppConfig(session.transport));\n default:\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.MethodNotSupported,\n message: `Unknown Keystone USB connector method: ${method}`,\n })\n ),\n };\n }\n } catch (err) {\n return { success: false, error: serializeConnectorError(mapKeystoneUsbError(err)) };\n }\n }\n\n // The SDK cannot interrupt an in-flight transfer; the pending send() settles or\n // times out on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // PIN/passphrase entry happens on the device touchscreen, never via the host.\n uiResponse(_response: UiResponseEvent): void {}\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.on(event, handler);\n }\n\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.off(event, handler);\n }\n\n reset(): void {\n for (const session of this.sessions.values()) {\n session.dispose();\n }\n this.sessions.clear();\n this._invalidateDiscoverySnapshot();\n this._invalidateAvailabilitySnapshot();\n this.publicDataConfirmedWallets.clear();\n }\n\n private async _readAppConfig(transport: TransportHID): Promise<AppConfig> {\n const response = await transport.send<Record<string, unknown>>(\n Actions.CMD_GET_DEVICE_VERSION,\n ''\n );\n const rawMasterFingerprint = response.walletMFP;\n const masterFingerprint = parseBip32MasterFingerprint(rawMasterFingerprint);\n if (masterFingerprint === MISSING_BIP32_MASTER_FINGERPRINT) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotInitialized,\n message: 'Keystone has no wallet yet; it reported an empty master fingerprint',\n });\n }\n if (rawMasterFingerprint !== undefined && !masterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message:\n 'Keystone returned an invalid master fingerprint; expected exactly 4 bytes (8 hex characters)',\n });\n }\n return {\n // Device-supplied text reaches the host UI and version gates; accept only a version number.\n version:\n typeof response.firmwareVersion === 'string' &&\n /^\\d{1,4}(\\.\\d{1,4}){1,3}(-[0-9A-Za-z.]{1,20})?$/.test(response.firmwareVersion)\n ? response.firmwareVersion\n : undefined,\n mfp: masterFingerprint,\n };\n }\n\n private _toDeviceInfo(\n device: ConnectorDevice,\n firmwareVersion?: string,\n masterFingerprint?: string\n ) {\n return {\n vendor: 'keystone' as const,\n // Model is the USB `productName`; empty, not 'unknown', so the host's\n // default-name fallback wins.\n model: device.model ?? '',\n modelName: device.modelName,\n firmwareVersion: firmwareVersion ?? '0.0.0',\n deviceId: device.deviceId,\n connectId: device.connectId,\n connectionType: 'usb' as const,\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint },\n };\n }\n}\n"],"mappings":"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","names":["HardwareErrorCode","createHwkError","createHwkError","HardwareErrorCode","device"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/errors.ts
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/errors.ts
|
|
2
2
|
var _hwkadaptercore = require('@onekeyfe/hwk-adapter-core');
|
|
3
3
|
var _hwtransporterror = require('@keystonehq/hw-transport-error');
|
|
4
4
|
function isDeviceStatus(statusCode) {
|
|
@@ -64,7 +64,10 @@ function mapKeystoneUsbError(err) {
|
|
|
64
64
|
const message = err instanceof Error ? err.message : String(err);
|
|
65
65
|
if (statusCode !== void 0) {
|
|
66
66
|
const fromDevice = isDeviceStatus(statusCode);
|
|
67
|
-
|
|
67
|
+
let code = fromDevice ? _nullishCoalesce(DEVICE_STATUS_MAP[statusCode], () => ( _hwkadaptercore.HardwareErrorCode.UnknownError)) : _nullishCoalesce(CLIENT_STATUS_MAP[statusCode], () => ( _hwkadaptercore.HardwareErrorCode.TransportError));
|
|
68
|
+
if (statusCode === _hwtransporterror.Status.PRS_PARSING_DISALLOWED && !/\blocked\b/i.test(message)) {
|
|
69
|
+
code = _hwkadaptercore.HardwareErrorCode.DeviceBusy;
|
|
70
|
+
}
|
|
68
71
|
let origin;
|
|
69
72
|
if (fromDevice) {
|
|
70
73
|
origin = "device";
|
|
@@ -90,6 +93,7 @@ function mapKeystoneUsbError(err) {
|
|
|
90
93
|
|
|
91
94
|
// src/KeystoneUsbConnectorBase.ts
|
|
92
95
|
var _bcur = require('@ngraveio/bc-ur');
|
|
96
|
+
var _bytewords = require('@ngraveio/bc-ur/dist/bytewords'); var _bytewords2 = _interopRequireDefault(_bytewords);
|
|
93
97
|
var _hwtransportusb = require('@keystonehq/hw-transport-usb');
|
|
94
98
|
|
|
95
99
|
|
|
@@ -105,6 +109,7 @@ var _hwtransportusb = require('@keystonehq/hw-transport-usb');
|
|
|
105
109
|
|
|
106
110
|
|
|
107
111
|
|
|
112
|
+
|
|
108
113
|
function usbDisplayName(device) {
|
|
109
114
|
return _optionalChain([device, 'access', _ => _.productName, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]) || "Keystone";
|
|
110
115
|
}
|
|
@@ -113,20 +118,68 @@ var KEYSTONE_PUBLIC_DATA_UR_TYPE = "qr-hardware-call";
|
|
|
113
118
|
function toUrEncoded(ur) {
|
|
114
119
|
return new (0, _bcur.UREncoder)(new (0, _bcur.UR)(Buffer.from(ur.urData, "hex"), ur.urType), Infinity).nextPart().toUpperCase();
|
|
115
120
|
}
|
|
121
|
+
var MAX_UR_MESSAGE_BYTES = 1024 * 1024;
|
|
122
|
+
var MAX_UR_SEQ_LENGTH = 32768;
|
|
123
|
+
var CBOR_ARGUMENT_BYTES = [1, 2, 4, 8];
|
|
124
|
+
function readFountainPart(input) {
|
|
125
|
+
let offset = 0;
|
|
126
|
+
const readHead = (expectedMajor) => {
|
|
127
|
+
const initial = input[offset];
|
|
128
|
+
offset += 1;
|
|
129
|
+
if (Math.floor(initial / 32) !== expectedMajor) {
|
|
130
|
+
throw new Error("Keystone USB reply part is not a fountain part");
|
|
131
|
+
}
|
|
132
|
+
const info = initial % 32;
|
|
133
|
+
if (info < 24) return info;
|
|
134
|
+
const size = CBOR_ARGUMENT_BYTES[info - 24];
|
|
135
|
+
let value = 0;
|
|
136
|
+
for (let i = 0; i < size; i += 1) value = value * 256 + input[offset + i];
|
|
137
|
+
offset += size;
|
|
138
|
+
return value;
|
|
139
|
+
};
|
|
140
|
+
if (readHead(4) !== 5) throw new Error("Keystone USB reply part is not a fountain part");
|
|
141
|
+
const seqNum = readHead(0);
|
|
142
|
+
const seqLength = readHead(0);
|
|
143
|
+
const messageLength = readHead(0);
|
|
144
|
+
readHead(0);
|
|
145
|
+
const fragmentLength = readHead(2);
|
|
146
|
+
return { seqNum, seqLength, messageLength, fragmentLength };
|
|
147
|
+
}
|
|
148
|
+
function assertBoundedUrPart(part) {
|
|
149
|
+
const match = /^ur:[a-z0-9-]+\/(?:(\d{1,9})-(\d{1,9})\/)?([a-z]+)$/i.exec(part);
|
|
150
|
+
if (!match) throw new Error("Keystone USB reply part is not a UR");
|
|
151
|
+
const payload = Buffer.from(
|
|
152
|
+
_bytewords2.default.decode(match[3].toLowerCase(), _bytewords2.default.STYLES.MINIMAL),
|
|
153
|
+
"hex"
|
|
154
|
+
);
|
|
155
|
+
_hwkadaptercore.assertBoundedCbor.call(void 0, payload, MAX_UR_MESSAGE_BYTES);
|
|
156
|
+
if (match[1] === void 0) return;
|
|
157
|
+
const header = readFountainPart(payload);
|
|
158
|
+
if (header.seqNum < 1 || header.seqNum > header.seqLength || header.seqNum !== Number(match[1]) || header.seqLength !== Number(match[2]) || header.fragmentLength < 1 || header.messageLength < 1 || header.messageLength > MAX_UR_MESSAGE_BYTES || header.seqLength > MAX_UR_SEQ_LENGTH || header.seqLength !== Math.ceil(header.messageLength / header.fragmentLength)) {
|
|
159
|
+
throw new Error("Keystone USB reply part has inconsistent or oversized headers");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
116
162
|
function fromUrEncoded(encoded) {
|
|
117
163
|
const text = typeof encoded === "string" ? encoded.trim() : "";
|
|
118
164
|
const parts = text.split(/\s+/).filter(Boolean);
|
|
119
165
|
const decoder = new (0, _bcur.URDecoder)();
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
try {
|
|
167
|
+
if (parts.length > MAX_UR_SEQ_LENGTH) throw new Error("Keystone USB reply has too many parts");
|
|
168
|
+
for (const part of parts) {
|
|
169
|
+
assertBoundedUrPart(part);
|
|
170
|
+
decoder.receivePart(part);
|
|
171
|
+
if (decoder.isComplete()) break;
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
123
174
|
}
|
|
124
175
|
if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {
|
|
125
176
|
const shape = typeof encoded === "string" ? `string len=${text.length} parts=${parts.length}` : typeof encoded;
|
|
126
177
|
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
127
178
|
code: _hwkadaptercore.HardwareErrorCode.PayloadTooLarge,
|
|
128
179
|
message: `Keystone USB returned an incomplete BC-UR response (${shape})`,
|
|
129
|
-
origin: "device"
|
|
180
|
+
origin: "device",
|
|
181
|
+
// The device processed the request; only its reply is unusable.
|
|
182
|
+
params: { replyUnreadable: true }
|
|
130
183
|
});
|
|
131
184
|
}
|
|
132
185
|
const ur = decoder.resultUR();
|
|
@@ -265,7 +318,14 @@ var KeystoneUsbConnectorBase = class {
|
|
|
265
318
|
});
|
|
266
319
|
}
|
|
267
320
|
if (this.transportClass.connectDevice) {
|
|
321
|
+
if (availableDevices.length === 0) {
|
|
322
|
+
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
323
|
+
code: _hwkadaptercore.HardwareErrorCode.DeviceNotFound,
|
|
324
|
+
message: "No Keystone USB device is available"
|
|
325
|
+
});
|
|
326
|
+
}
|
|
268
327
|
let readableDeviceFound = false;
|
|
328
|
+
let ambiguous = false;
|
|
269
329
|
let lastError;
|
|
270
330
|
let matched;
|
|
271
331
|
for (const device2 of availableDevices) {
|
|
@@ -275,8 +335,13 @@ var KeystoneUsbConnectorBase = class {
|
|
|
275
335
|
const candidateConfig = await this._readAppConfig(candidate.transport);
|
|
276
336
|
readableDeviceFound = true;
|
|
277
337
|
if (_optionalChain([candidateConfig, 'access', _6 => _6.mfp, 'optionalAccess', _7 => _7.toLowerCase, 'call', _8 => _8()]) === expectedMasterFingerprint.toLowerCase()) {
|
|
338
|
+
if (matched) {
|
|
339
|
+
candidate.dispose();
|
|
340
|
+
ambiguous = true;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
278
343
|
matched = { device: device2, opened: candidate, config: candidateConfig };
|
|
279
|
-
|
|
344
|
+
continue;
|
|
280
345
|
}
|
|
281
346
|
candidate.dispose();
|
|
282
347
|
} catch (error) {
|
|
@@ -284,11 +349,18 @@ var KeystoneUsbConnectorBase = class {
|
|
|
284
349
|
lastError = error;
|
|
285
350
|
}
|
|
286
351
|
}
|
|
352
|
+
if (ambiguous) {
|
|
353
|
+
_optionalChain([matched, 'optionalAccess', _11 => _11.opened, 'access', _12 => _12.dispose, 'call', _13 => _13()]);
|
|
354
|
+
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
355
|
+
code: _hwkadaptercore.HardwareErrorCode.DeviceOneDeviceOnly,
|
|
356
|
+
message: "More than one connected Keystone reports this wallet; keep one connected"
|
|
357
|
+
});
|
|
358
|
+
}
|
|
287
359
|
if (!matched) {
|
|
288
360
|
if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);
|
|
289
361
|
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
290
362
|
code: _hwkadaptercore.HardwareErrorCode.DeviceMismatch,
|
|
291
|
-
message:
|
|
363
|
+
message: "No connected Keystone matches the requested wallet"
|
|
292
364
|
});
|
|
293
365
|
}
|
|
294
366
|
selectedDevice = matched.device;
|
|
@@ -332,7 +404,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
332
404
|
if (expectedMasterFingerprint && config.mfp && config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()) {
|
|
333
405
|
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
334
406
|
code: _hwkadaptercore.HardwareErrorCode.DeviceMismatch,
|
|
335
|
-
|
|
407
|
+
// The master fingerprint identifies the wallet; keep it out of messages that reach logs.
|
|
408
|
+
message: "Connected Keystone wallet does not match the requested wallet"
|
|
336
409
|
});
|
|
337
410
|
}
|
|
338
411
|
const sessionId = _hwkadaptercore.createHardwareLinkId.call(void 0, "keystone");
|
|
@@ -347,9 +420,9 @@ var KeystoneUsbConnectorBase = class {
|
|
|
347
420
|
connectId: sessionId,
|
|
348
421
|
deviceId: "",
|
|
349
422
|
name: selectedDevice ? usbDisplayName(selectedDevice) : "Keystone",
|
|
350
|
-
model: _optionalChain([selectedDevice, 'optionalAccess',
|
|
423
|
+
model: _optionalChain([selectedDevice, 'optionalAccess', _14 => _14.productName]),
|
|
351
424
|
connectionType: "usb",
|
|
352
|
-
serialNumber: _optionalChain([selectedDevice, 'optionalAccess',
|
|
425
|
+
serialNumber: _optionalChain([selectedDevice, 'optionalAccess', _15 => _15.serialNumber]),
|
|
353
426
|
capabilities: { persistentDeviceIdentity: false },
|
|
354
427
|
raw: { masterFingerprint: config.mfp }
|
|
355
428
|
};
|
|
@@ -359,7 +432,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
359
432
|
deviceInfo: this._toDeviceInfo(device, config.version, config.mfp)
|
|
360
433
|
};
|
|
361
434
|
} catch (err) {
|
|
362
|
-
_optionalChain([openedTransport, 'optionalAccess',
|
|
435
|
+
_optionalChain([openedTransport, 'optionalAccess', _16 => _16.dispose, 'call', _17 => _17()]);
|
|
363
436
|
throw mapKeystoneUsbError(err);
|
|
364
437
|
}
|
|
365
438
|
}
|
|
@@ -379,7 +452,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
379
452
|
dispose: () => {
|
|
380
453
|
if (disposed) return;
|
|
381
454
|
disposed = true;
|
|
382
|
-
_optionalChain([this, 'access',
|
|
455
|
+
_optionalChain([this, 'access', _18 => _18.transportClass, 'access', _19 => _19.disposeTransport, 'optionalCall', _20 => _20(transport)]);
|
|
383
456
|
}
|
|
384
457
|
};
|
|
385
458
|
}
|
|
@@ -444,7 +517,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
444
517
|
const { urType, urData } = params;
|
|
445
518
|
const encoded = toUrEncoded({ urType, urData });
|
|
446
519
|
const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;
|
|
447
|
-
const publicDataKey = _nullishCoalesce(_optionalChain([session, 'access',
|
|
520
|
+
const publicDataKey = _nullishCoalesce(_optionalChain([session, 'access', _21 => _21.mfp, 'optionalAccess', _22 => _22.toLowerCase, 'call', _23 => _23()]), () => ( sessionId));
|
|
521
|
+
if (!isPublicDataRequest) this.publicDataConfirmedWallets.delete(publicDataKey);
|
|
448
522
|
const shouldShowConfirmation = !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);
|
|
449
523
|
if (shouldShowConfirmation) {
|
|
450
524
|
this.emitter.emit("ui-event", {
|
|
@@ -472,7 +546,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
472
546
|
_hwtransportusb.Actions.CMD_CHECK_LOCK_STATUS,
|
|
473
547
|
""
|
|
474
548
|
);
|
|
475
|
-
return _hwkadaptercore.success.call(void 0, { locked: response.payload });
|
|
549
|
+
return _hwkadaptercore.success.call(void 0, { locked: response.payload === true });
|
|
476
550
|
}
|
|
477
551
|
case "getAppConfig":
|
|
478
552
|
return _hwkadaptercore.success.call(void 0, await this._readAppConfig(session.transport));
|
|
@@ -534,7 +608,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
534
608
|
});
|
|
535
609
|
}
|
|
536
610
|
return {
|
|
537
|
-
|
|
611
|
+
// Device-supplied text reaches the host UI and version gates; accept only a version number.
|
|
612
|
+
version: typeof response.firmwareVersion === "string" && /^\d{1,4}(\.\d{1,4}){1,3}(-[0-9A-Za-z.]{1,20})?$/.test(response.firmwareVersion) ? response.firmwareVersion : void 0,
|
|
538
613
|
mfp: masterFingerprint
|
|
539
614
|
};
|
|
540
615
|
}
|
|
@@ -560,4 +635,4 @@ var KeystoneUsbConnectorBase = class {
|
|
|
560
635
|
|
|
561
636
|
|
|
562
637
|
exports.mapKeystoneUsbError = mapKeystoneUsbError; exports.KeystoneUsbConnectorBase = KeystoneUsbConnectorBase;
|
|
563
|
-
//# sourceMappingURL=chunk-
|
|
638
|
+
//# sourceMappingURL=chunk-U76BQU3H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-U76BQU3H.js","../src/errors.ts","../src/KeystoneUsbConnectorBase.ts"],"names":["HardwareErrorCode","createHwkError"],"mappings":"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","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-U76BQU3H.js","sourcesContent":[null,"import { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport { Status } from '@keystonehq/hw-transport-error';\n\nimport type { HwkError, HwkErrorOrigin } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Firmware status words are the low end of `Status` (0..15); client codes start at\n * `ERR_DEVICE_NOT_OPENED` (0xA0000001), so anything below came from a device response frame.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/** Firmware status words from a device response (EAPDU_Readme.md in the Keystone USB SDK). */\nconst DEVICE_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.RSP_FAILURE_CODE]: HardwareErrorCode.UnknownError,\n [Status.PRS_INVALID_TOTAL_PACKETS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_INVALID_INDEX]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_PARSING_ERROR]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_PARSING_UNMATCHED]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_MISMATCHED_WALLET]: HardwareErrorCode.DeviceMismatch,\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: HardwareErrorCode.PinInvalid,\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: HardwareErrorCode.ChainNotSupported,\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_EXPORT_ADDRESS_ERROR]: HardwareErrorCode.UnknownError,\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_EXPORT_ADDRESS_BUSY]: HardwareErrorCode.DeviceBusyInternal,\n};\n\n/** Used when the transport forwarded only its 'unknown error' placeholder for a firmware status. */\nconst DEVICE_STATUS_MESSAGE: Partial<Record<number, string>> = {\n [Status.RSP_FAILURE_CODE]: 'Keystone reported a failure',\n [Status.PRS_INVALID_TOTAL_PACKETS]: 'Keystone rejected the request framing (total packets)',\n [Status.PRS_INVALID_INDEX]: 'Keystone rejected the request framing (packet index)',\n [Status.PRS_PARSING_REJECTED]: 'Rejected on the Keystone screen',\n [Status.PRS_PARSING_ERROR]: 'Keystone could not parse the request',\n [Status.PRS_PARSING_DISALLOWED]: 'Keystone declined the request in its current state',\n [Status.PRS_PARSING_UNMATCHED]: 'Keystone found no handler for the request',\n [Status.PRS_PARSING_MISMATCHED_WALLET]: 'The request belongs to a different Keystone wallet',\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: 'Keystone password verification failed',\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: 'Keystone does not support this chain',\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: 'Keystone rejected the address export parameters',\n [Status.PRS_EXPORT_ADDRESS_ERROR]: 'Keystone failed to export the address',\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: 'Keystone declined to export the address',\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: 'Address export rejected on the Keystone screen',\n [Status.PRS_EXPORT_ADDRESS_BUSY]: 'Keystone is busy with another request',\n};\n\n/** The placeholder both Keystone transports use when they have nothing better. */\nconst PLACEHOLDER_MESSAGE = /^unknown error\\b/i;\n\n/** Client-side (transport/framing) failures, never reached the device. */\nconst CLIENT_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.ERR_DEVICE_NOT_OPENED]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_DEVICE_NOT_FOUND]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_TIMEOUT]: HardwareErrorCode.OperationTimeout,\n [Status.ERR_DATA_TOO_LARGE]: HardwareErrorCode.PayloadTooLarge,\n [Status.ERR_NOT_SUPPORTED]: HardwareErrorCode.TransportNotAvailable,\n};\n\n/** WebUSB DOMExceptions; an unplug or bus reset mid-call is the common case. */\nconst DOM_EXCEPTION_MAP = new Map<string, { code: HardwareErrorCode; origin: HwkErrorOrigin }>([\n ['NotFoundError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['NetworkError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['SecurityError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['NotAllowedError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['InvalidStateError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n ['AbortError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n]);\n\n/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because\n * duplicate `@keystonehq/*` module instances break `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const fields: { name?: unknown; code?: unknown; transportErrorCode?: unknown } =\n err && typeof err === 'object' ? err : {};\n const domName = typeof fields.name === 'string' ? fields.name : undefined;\n\n // Only five-digit codes are HWK codes; legacy DOMException codes (NotFoundError\n // is 8) must not pass through as hardware errors.\n if (typeof fields.code === 'number' && fields.code >= 10000 && fields.code <= 99999) {\n return err as HwkError;\n }\n\n const statusCode =\n typeof fields.transportErrorCode === 'number' ? fields.transportErrorCode : undefined;\n\n const message = err instanceof Error ? err.message : String(err);\n\n if (statusCode !== undefined) {\n const fromDevice = isDeviceStatus(statusCode);\n // An unlisted firmware status keeps origin 'device'; 'transport' would make the\n // adapter tear down a live session over an on-device decline.\n let code = fromDevice\n ? DEVICE_STATUS_MAP[statusCode] ?? HardwareErrorCode.UnknownError\n : CLIENT_STATUS_MAP[statusCode] ?? HardwareErrorCode.TransportError;\n // Firmware also returns PRS_PARSING_DISALLOWED for an unfinished request, a pending approval\n // and a screen that takes no requests; only its \"Device is locked\" text means locked.\n if (statusCode === Status.PRS_PARSING_DISALLOWED && !/\\blocked\\b/i.test(message)) {\n code = HardwareErrorCode.DeviceBusy;\n }\n let origin: HwkErrorOrigin | undefined;\n if (fromDevice) {\n origin = 'device';\n } else if (code !== HardwareErrorCode.OperationTimeout) {\n origin = 'transport';\n }\n const description = DEVICE_STATUS_MESSAGE[statusCode];\n return createHwkError({\n code,\n // The device's own payload text wins over the table.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A timeout may be either side, so it stays unlabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : undefined;\n if (domMapping) {\n return createHwkError({ ...domMapping, message, params: { domExceptionName: domName } });\n }\n\n // This mapper only wraps transport calls, so 'transport' names the throw site.\n return createHwkError({ code: HardwareErrorCode.TransportError, message, origin: 'transport' });\n}\n","import { UR, URDecoder, UREncoder } from '@ngraveio/bc-ur';\n// Not re-exported by the package root; pinned with the package version.\nimport bytewords from '@ngraveio/bc-ur/dist/bytewords';\nimport { Actions } from '@keystonehq/hw-transport-usb';\nimport {\n EConnectorInteraction,\n HardwareErrorCode,\n MISSING_BIP32_MASTER_FINGERPRINT,\n TypedEventEmitter,\n assertBoundedCbor,\n createHardwareLinkId,\n createHardwareSearchTargetId,\n createHwkError,\n hasHardwareRuntimeIdPrefix,\n parseBip32MasterFingerprint,\n parseHardwareRuntimeId,\n serializeConnectorError,\n success,\n} from '@onekeyfe/hwk-adapter-core';\n\nimport { mapKeystoneUsbError } from './errors';\n\nimport type {\n ConnectorCallResult,\n ConnectorConnectTarget,\n ConnectorDevice,\n ConnectorEventMap,\n ConnectorEventType,\n ConnectorSearchDevicesOptions,\n ConnectorSession,\n IConnector,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\nimport type { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';\n\n/** Descriptor fields readable before opening; any may be absent if not published. */\nexport interface KeystoneUsbDeviceDescriptor {\n serialNumber?: string;\n productName?: string;\n manufacturerName?: string;\n vendorId?: number;\n productId?: number;\n /** Device release number (bcdDevice), split into its three nibble groups. */\n deviceVersionMajor?: number;\n deviceVersionMinor?: number;\n deviceVersionSubminor?: number;\n usbVersionMajor?: number;\n usbVersionMinor?: number;\n usbVersionSubminor?: number;\n deviceClass?: number;\n deviceSubclass?: number;\n deviceProtocol?: number;\n}\n\n/** The serial is not shown on the unit, so it would not help tell two devices apart. */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\n/** Static surface of `TransportWebUSB`, injected by `_subpath/webusb`. */\nexport interface KeystoneUsbTransportStatic {\n connect(config?: TransportConfig): Promise<TransportHID>;\n connectDevice?(\n device: KeystoneUsbDeviceDescriptor,\n config?: TransportConfig\n ): Promise<TransportHID>;\n getKeystoneDevices(): Promise<ReadonlyArray<KeystoneUsbDeviceDescriptor>>;\n requestPermission?(): Promise<void>;\n isSupported(): Promise<boolean>;\n /** Release transport-lifetime resources owned by the platform wrapper. */\n disposeTransport?(transport: TransportHID): void;\n}\n\ninterface KeystoneUr {\n urType: string;\n urData: string;\n}\n\ninterface UsbSession {\n transport: TransportHID;\n mfp?: string;\n dispose(): void;\n}\n\ninterface AppConfig {\n version?: string;\n mfp?: string;\n}\n\ninterface OpenedUsbTransport {\n transport: TransportHID;\n bindSessionId(sessionId: string): void;\n dispose(): void;\n}\n\ntype KeystoneUsbConnectInput =\n | { searchTargetId: string; expectedMasterFingerprint?: never }\n | { searchTargetId?: never; expectedMasterFingerprint: string }\n | { searchTargetId?: never; expectedMasterFingerprint?: never };\n\n// The SDK default of 15s is too short for on-device confirmation.\nconst DEFAULT_TIMEOUT_MS = 100_000;\n\nconst KEYSTONE_PUBLIC_DATA_UR_TYPE = 'qr-hardware-call';\n\nfunction toUrEncoded(ur: KeystoneUr): string {\n return new UREncoder(new UR(Buffer.from(ur.urData, 'hex'), ur.urType), Infinity)\n .nextPart()\n .toUpperCase();\n}\n\n/** The most data one reply may carry, whatever its fragment size. */\nconst MAX_UR_MESSAGE_BYTES = 1024 * 1024;\n/**\n * The fountain decoder's work per mixed part grows with the square of the part count, so a reply\n * cut into tiny fragments can stall it even within the byte limit.\n */\nconst MAX_UR_SEQ_LENGTH = 32_768;\n/** Argument bytes for CBOR additional info 24, 25, 26 and 27. */\nconst CBOR_ARGUMENT_BYTES = [1, 2, 4, 8];\n\n/** Reads `[seqNum, seqLen, messageLen, checksum, fragment]` from CBOR that passed the bounds. */\nfunction readFountainPart(input: Uint8Array) {\n let offset = 0;\n const readHead = (expectedMajor: number): number => {\n const initial = input[offset];\n offset += 1;\n if (Math.floor(initial / 32) !== expectedMajor) {\n throw new Error('Keystone USB reply part is not a fountain part');\n }\n const info = initial % 32;\n if (info < 24) return info;\n const size = CBOR_ARGUMENT_BYTES[info - 24];\n let value = 0;\n for (let i = 0; i < size; i += 1) value = value * 256 + input[offset + i];\n offset += size;\n return value;\n };\n if (readHead(4) !== 5) throw new Error('Keystone USB reply part is not a fountain part');\n const seqNum = readHead(0);\n const seqLength = readHead(0);\n const messageLength = readHead(0);\n readHead(0); // checksum\n const fragmentLength = readHead(2);\n return { seqNum, seqLength, messageLength, fragmentLength };\n}\n\n/** Checks one UR part from the device before the vendor decoder parses its CBOR. */\nfunction assertBoundedUrPart(part: string): void {\n const match = /^ur:[a-z0-9-]+\\/(?:(\\d{1,9})-(\\d{1,9})\\/)?([a-z]+)$/i.exec(part);\n if (!match) throw new Error('Keystone USB reply part is not a UR');\n // Minimal bytewords carry their own CRC32; decode throws on a mismatch.\n const payload = Buffer.from(\n bytewords.decode(match[3].toLowerCase(), bytewords.STYLES.MINIMAL),\n 'hex'\n );\n assertBoundedCbor(payload, MAX_UR_MESSAGE_BYTES);\n if (match[1] === undefined) return;\n const header = readFountainPart(payload);\n // The text header, the CBOR header and the real sizes must agree, so the declared part count\n // is tied to the data the reply actually carries. USB is lossless and Keystone answers with a\n // single-part UR, so a mixed fountain part (seqNum past seqLen) is refused: decoding each one\n // costs time quadratic in the part count.\n if (\n header.seqNum < 1 ||\n header.seqNum > header.seqLength ||\n header.seqNum !== Number(match[1]) ||\n header.seqLength !== Number(match[2]) ||\n header.fragmentLength < 1 ||\n header.messageLength < 1 ||\n header.messageLength > MAX_UR_MESSAGE_BYTES ||\n header.seqLength > MAX_UR_SEQ_LENGTH ||\n header.seqLength !== Math.ceil(header.messageLength / header.fragmentLength)\n ) {\n throw new Error('Keystone USB reply part has inconsistent or oversized headers');\n }\n}\n\nfunction fromUrEncoded(encoded: unknown): KeystoneUr {\n // One complete UR or whitespace-separated parts; EAPDU framing is the transport's job.\n const text = typeof encoded === 'string' ? encoded.trim() : '';\n const parts = text.split(/\\s+/).filter(Boolean);\n const decoder = new URDecoder();\n try {\n if (parts.length > MAX_UR_SEQ_LENGTH) throw new Error('Keystone USB reply has too many parts');\n for (const part of parts) {\n assertBoundedUrPart(part);\n decoder.receivePart(part);\n if (decoder.isComplete()) break;\n }\n } catch {\n // A part that does not decode is the device's reply, not a broken link: report it below as\n // an unreadable answer so the session is kept rather than re-claimed.\n }\n if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {\n const shape =\n typeof encoded === 'string'\n ? `string len=${text.length} parts=${parts.length}`\n : typeof encoded;\n throw createHwkError({\n code: HardwareErrorCode.PayloadTooLarge,\n message: `Keystone USB returned an incomplete BC-UR response (${shape})`,\n origin: 'device',\n // The device processed the request; only its reply is unusable.\n params: { replyUnreadable: true },\n });\n }\n const ur = decoder.resultUR();\n return { urType: ur.type, urData: ur.cbor.toString('hex') };\n}\n\n/**\n * Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so\n * `connect()` only caches the transport object.\n */\nexport class KeystoneUsbConnectorBase implements IConnector {\n readonly connectionType = 'usb' as const;\n\n private readonly transportClass: KeystoneUsbTransportStatic;\n\n private readonly timeoutMs: number;\n\n private readonly emitter = new TypedEventEmitter<ConnectorEventMap>();\n\n private readonly sessions = new Map<string, UsbSession>();\n\n private readonly discoveredDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private readonly availabilityDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private activeDiscoveryGeneration: symbol | undefined;\n\n private activeAvailabilityGeneration: symbol | undefined;\n\n /**\n * Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can\n * re-enumerate between exports, and that must not re-prompt.\n */\n private readonly publicDataConfirmedWallets = new Set<string>();\n\n constructor(transportClass: KeystoneUsbTransportStatic, options?: { timeoutMs?: number }) {\n this.transportClass = transportClass;\n this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n private _invalidateDiscoverySnapshot(): void {\n this.activeDiscoveryGeneration = undefined;\n this.discoveredDevices.clear();\n }\n\n private _invalidateAvailabilitySnapshot(): void {\n this.activeAvailabilityGeneration = undefined;\n this.availabilityDevices.clear();\n }\n\n async searchDevices(options?: ConnectorSearchDevicesOptions): Promise<ConnectorDevice[]> {\n const isAvailabilitySearch = options?.purpose === 'availability';\n const discoveryGeneration = Symbol(\n isAvailabilitySearch ? 'keystone-usb-availability' : 'keystone-usb-discovery'\n );\n if (isAvailabilitySearch) {\n this._invalidateAvailabilitySnapshot();\n this.activeAvailabilityGeneration = discoveryGeneration;\n } else {\n this._invalidateDiscoverySnapshot();\n this.activeDiscoveryGeneration = discoveryGeneration;\n }\n // Enumeration DOMException codes collide with the HWK range, so map them too.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // Without an mfp before opening, the target id names only this snapshot; platforms that\n // cannot reopen a cached descriptor fail closed on multi-device selection.\n if (\n (isAvailabilitySearch\n ? this.activeAvailabilityGeneration\n : this.activeDiscoveryGeneration) !== discoveryGeneration\n ) {\n return [];\n }\n return devices.map(device => {\n const connectId = createHardwareSearchTargetId('keystone');\n (isAvailabilitySearch ? this.availabilityDevices : this.discoveredDevices).set(\n connectId,\n device\n );\n return {\n connectId,\n deviceId: '',\n name: usbDisplayName(device),\n connectionType: 'usb',\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n // Verbatim descriptor fields; a missing key means the device did not publish it.\n raw: {\n serialNumber: device.serialNumber,\n productName: device.productName,\n manufacturerName: device.manufacturerName,\n vendorId: device.vendorId,\n productId: device.productId,\n deviceVersionMajor: device.deviceVersionMajor,\n deviceVersionMinor: device.deviceVersionMinor,\n deviceVersionSubminor: device.deviceVersionSubminor,\n usbVersionMajor: device.usbVersionMajor,\n usbVersionMinor: device.usbVersionMinor,\n usbVersionSubminor: device.usbVersionSubminor,\n deviceClass: device.deviceClass,\n deviceSubclass: device.deviceSubclass,\n deviceProtocol: device.deviceProtocol,\n },\n };\n });\n }\n\n async connect(searchTargetIdOrExpectedMasterFingerprint?: string): Promise<ConnectorSession> {\n return this._connectResolved(\n this._resolveConnectInput(searchTargetIdOrExpectedMasterFingerprint)\n );\n }\n\n async connectTarget(target: ConnectorConnectTarget): Promise<ConnectorSession> {\n switch (target.type) {\n case 'default':\n return this._connectResolved({});\n case 'search-target':\n return this._connectResolved({ searchTargetId: target.searchTargetId });\n case 'expected-device-identity': {\n const expectedMasterFingerprint = parseBip32MasterFingerprint(target.deviceIdentity);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a valid master fingerprint identity',\n });\n }\n return this._connectResolved({ expectedMasterFingerprint });\n }\n default:\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Unsupported Keystone USB connection target',\n });\n }\n }\n\n private async _connectResolved({\n searchTargetId,\n expectedMasterFingerprint,\n }: KeystoneUsbConnectInput): Promise<ConnectorSession> {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.Searching,\n payload: { sessionId: '' },\n });\n let selectedDevice = searchTargetId\n ? this.discoveredDevices.get(searchTargetId) ?? this.availabilityDevices.get(searchTargetId)\n : undefined;\n if (searchTargetId && !selectedDevice) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Keystone USB search target is not in the current scan: ${searchTargetId}`,\n recovery: { scope: 'search-target' },\n });\n }\n let openedTransport: OpenedUsbTransport | undefined;\n try {\n let config: AppConfig;\n\n if (expectedMasterFingerprint && !searchTargetId) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (!this.transportClass.connectDevice && availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot identify one of multiple connected Keystone devices',\n });\n }\n\n if (this.transportClass.connectDevice) {\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n let readableDeviceFound = false;\n let ambiguous = false;\n let lastError: unknown;\n let matched:\n | {\n device: KeystoneUsbDeviceDescriptor;\n opened: OpenedUsbTransport;\n config: AppConfig;\n }\n | undefined;\n for (const device of availableDevices) {\n let candidate: OpenedUsbTransport | undefined;\n try {\n // eslint-disable-next-line no-await-in-loop\n candidate = await this._openTransport(device);\n // eslint-disable-next-line no-await-in-loop\n const candidateConfig = await this._readAppConfig(candidate.transport);\n readableDeviceFound = true;\n if (candidateConfig.mfp?.toLowerCase() === expectedMasterFingerprint.toLowerCase()) {\n if (matched) {\n candidate.dispose();\n ambiguous = true;\n break;\n }\n matched = { device, opened: candidate, config: candidateConfig };\n // eslint-disable-next-line no-continue\n continue;\n }\n candidate.dispose();\n } catch (error) {\n candidate?.dispose();\n lastError = error;\n }\n }\n // The fingerprint is self-reported, so two claimants are refused, not ranked.\n if (ambiguous) {\n matched?.opened.dispose();\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'More than one connected Keystone reports this wallet; keep one connected',\n });\n }\n if (!matched) {\n if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: 'No connected Keystone matches the requested wallet',\n });\n }\n selectedDevice = matched.device;\n openedTransport = matched.opened;\n config = matched.config;\n } else {\n openedTransport = await this._openTransport();\n config = await this._readAppConfig(openedTransport.transport);\n }\n } else {\n if (!selectedDevice && this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'Select a Keystone USB device before connecting',\n });\n }\n [selectedDevice] = availableDevices;\n }\n if (selectedDevice && !this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot target one of multiple connected Keystone devices',\n });\n }\n }\n openedTransport = await this._openTransport(selectedDevice);\n config = await this._readAppConfig(openedTransport.transport);\n }\n\n const activeOpenedTransport = openedTransport;\n const { transport } = activeOpenedTransport;\n if (\n expectedMasterFingerprint &&\n config.mfp &&\n config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()\n ) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n // The master fingerprint identifies the wallet; keep it out of messages that reach logs.\n message: 'Connected Keystone wallet does not match the requested wallet',\n });\n }\n const sessionId = createHardwareLinkId('keystone');\n activeOpenedTransport.bindSessionId(sessionId);\n this.sessions.set(sessionId, {\n transport,\n mfp: config.mfp,\n dispose: () => activeOpenedTransport.dispose(),\n });\n openedTransport = undefined;\n const device: ConnectorDevice = {\n connectId: sessionId,\n deviceId: '',\n name: selectedDevice ? usbDisplayName(selectedDevice) : 'Keystone',\n model: selectedDevice?.productName,\n connectionType: 'usb',\n serialNumber: selectedDevice?.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint: config.mfp },\n };\n this.emitter.emit('device-connect', { device });\n return {\n sessionId,\n deviceInfo: this._toDeviceInfo(device, config.version, config.mfp),\n };\n } catch (err) {\n openedTransport?.dispose();\n throw mapKeystoneUsbError(err);\n }\n }\n\n private async _openTransport(device?: KeystoneUsbDeviceDescriptor): Promise<OpenedUsbTransport> {\n // A rejected candidate may keep its disconnect listener; a per-descriptor\n // holder stops it from retiring a later matched session.\n let connectedSessionId: string | undefined;\n const transportConfig: TransportConfig = {\n timeout: this.timeoutMs,\n disconnectListener: () =>\n connectedSessionId ? this.disconnect(connectedSessionId) : undefined,\n };\n const transport = await (device && this.transportClass.connectDevice\n ? this.transportClass.connectDevice(device, transportConfig)\n : this.transportClass.connect(transportConfig));\n let disposed = false;\n return {\n transport,\n bindSessionId(sessionId: string) {\n connectedSessionId = sessionId;\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this.transportClass.disposeTransport?.(transport);\n },\n };\n }\n\n private _resolveConnectInput(value?: string): KeystoneUsbConnectInput {\n if (!value) return {};\n\n const runtimeId = parseHardwareRuntimeId(value);\n if (runtimeId) {\n // Ownership is settled by the snapshot lookup in `_connectResolved`.\n if (runtimeId.kind === 'search-target' && runtimeId.vendor === 'keystone') {\n return { searchTargetId: value };\n }\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received an incompatible hardware runtime id',\n params: { kind: runtimeId.kind, vendor: runtimeId.vendor },\n });\n }\n\n if (hasHardwareRuntimeIdPrefix(value)) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received a malformed hardware runtime id',\n });\n }\n\n const expectedMasterFingerprint = parseBip32MasterFingerprint(value);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a search target or master fingerprint',\n });\n }\n return { expectedMasterFingerprint };\n }\n\n disconnect(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n this.sessions.delete(sessionId);\n if (session) {\n session.dispose();\n // No persistent claim to release; each send() already closed the device.\n this.emitter.emit('device-disconnect', { connectId: sessionId });\n }\n return Promise.resolve();\n }\n\n /** Keep the vendor transport as the EAPDU framing authority. */\n private async _sendResolveUr(transport: TransportHID, encodedUr: string): Promise<KeystoneUr> {\n const response = await transport.send<{ payload: string }>(Actions.CMD_RESOLVE_UR, encodedUr);\n return fromUrEncoded(response.payload);\n }\n\n async call(sessionId: string, method: string, params: unknown): Promise<ConnectorCallResult> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Unknown Keystone USB session: ${sessionId}`,\n })\n ),\n };\n }\n\n try {\n switch (method) {\n case 'resolveUr': {\n const { urType, urData } = params as KeystoneUr;\n const encoded = toUrEncoded({ urType, urData });\n const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;\n // Public-data export prompts once per wallet; signing always prompts. A signing request\n // leaves the device's export screen, so the next export may ask again and prompts again.\n const publicDataKey = session.mfp?.toLowerCase() ?? sessionId;\n if (!isPublicDataRequest) this.publicDataConfirmedWallets.delete(publicDataKey);\n const shouldShowConfirmation =\n !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.ConfirmOnDevice,\n payload: { sessionId },\n });\n }\n try {\n const response = await this._sendResolveUr(session.transport, encoded);\n if (isPublicDataRequest) {\n this.publicDataConfirmedWallets.add(publicDataKey);\n }\n return success(response);\n } finally {\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.InteractionComplete,\n payload: { sessionId },\n });\n }\n }\n }\n case 'checkLockStatus': {\n const response = await session.transport.send<{ payload: boolean }>(\n Actions.CMD_CHECK_LOCK_STATUS,\n ''\n );\n // `true` = locked is inferred from the SDK method name only; unverified on hardware.\n // Only a real boolean true counts, so a malformed reply never reads as a lock state.\n return success({ locked: response.payload === true });\n }\n case 'getAppConfig':\n return success(await this._readAppConfig(session.transport));\n default:\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.MethodNotSupported,\n message: `Unknown Keystone USB connector method: ${method}`,\n })\n ),\n };\n }\n } catch (err) {\n return { success: false, error: serializeConnectorError(mapKeystoneUsbError(err)) };\n }\n }\n\n // The SDK cannot interrupt an in-flight transfer; the pending send() settles or\n // times out on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // PIN/passphrase entry happens on the device touchscreen, never via the host.\n uiResponse(_response: UiResponseEvent): void {}\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.on(event, handler);\n }\n\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.off(event, handler);\n }\n\n reset(): void {\n for (const session of this.sessions.values()) {\n session.dispose();\n }\n this.sessions.clear();\n this._invalidateDiscoverySnapshot();\n this._invalidateAvailabilitySnapshot();\n this.publicDataConfirmedWallets.clear();\n }\n\n private async _readAppConfig(transport: TransportHID): Promise<AppConfig> {\n const response = await transport.send<Record<string, unknown>>(\n Actions.CMD_GET_DEVICE_VERSION,\n ''\n );\n const rawMasterFingerprint = response.walletMFP;\n const masterFingerprint = parseBip32MasterFingerprint(rawMasterFingerprint);\n if (masterFingerprint === MISSING_BIP32_MASTER_FINGERPRINT) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotInitialized,\n message: 'Keystone has no wallet yet; it reported an empty master fingerprint',\n });\n }\n if (rawMasterFingerprint !== undefined && !masterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message:\n 'Keystone returned an invalid master fingerprint; expected exactly 4 bytes (8 hex characters)',\n });\n }\n return {\n // Device-supplied text reaches the host UI and version gates; accept only a version number.\n version:\n typeof response.firmwareVersion === 'string' &&\n /^\\d{1,4}(\\.\\d{1,4}){1,3}(-[0-9A-Za-z.]{1,20})?$/.test(response.firmwareVersion)\n ? response.firmwareVersion\n : undefined,\n mfp: masterFingerprint,\n };\n }\n\n private _toDeviceInfo(\n device: ConnectorDevice,\n firmwareVersion?: string,\n masterFingerprint?: string\n ) {\n return {\n vendor: 'keystone' as const,\n // Model is the USB `productName`; empty, not 'unknown', so the host's\n // default-name fallback wins.\n model: device.model ?? '',\n modelName: device.modelName,\n firmwareVersion: firmwareVersion ?? '0.0.0',\n deviceId: device.deviceId,\n connectId: device.connectId,\n connectionType: 'usb' as const,\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint },\n };\n }\n}\n"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -19,7 +19,7 @@ interface KeystoneUsbDeviceDescriptor {
|
|
|
19
19
|
deviceSubclass?: number;
|
|
20
20
|
deviceProtocol?: number;
|
|
21
21
|
}
|
|
22
|
-
/** Static surface of `TransportWebUSB
|
|
22
|
+
/** Static surface of `TransportWebUSB`, injected by `_subpath/webusb`. */
|
|
23
23
|
interface KeystoneUsbTransportStatic {
|
|
24
24
|
connect(config?: TransportConfig): Promise<TransportHID>;
|
|
25
25
|
connectDevice?(device: KeystoneUsbDeviceDescriptor, config?: TransportConfig): Promise<TransportHID>;
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ interface KeystoneUsbDeviceDescriptor {
|
|
|
19
19
|
deviceSubclass?: number;
|
|
20
20
|
deviceProtocol?: number;
|
|
21
21
|
}
|
|
22
|
-
/** Static surface of `TransportWebUSB
|
|
22
|
+
/** Static surface of `TransportWebUSB`, injected by `_subpath/webusb`. */
|
|
23
23
|
interface KeystoneUsbTransportStatic {
|
|
24
24
|
connect(config?: TransportConfig): Promise<TransportHID>;
|
|
25
25
|
connectDevice?(device: KeystoneUsbDeviceDescriptor, config?: TransportConfig): Promise<TransportHID>;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var _chunkU76BQU3Hjs = require('./chunk-U76BQU3H.js');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
exports.KeystoneUsbConnectorBase =
|
|
8
|
+
exports.KeystoneUsbConnectorBase = _chunkU76BQU3Hjs.KeystoneUsbConnectorBase; exports.mapKeystoneUsbError = _chunkU76BQU3Hjs.mapKeystoneUsbError;
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
package/dist/webusb.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkU76BQU3Hjs = require('./chunk-U76BQU3H.js');
|
|
4
4
|
|
|
5
5
|
// src/_subpath/webusb.ts
|
|
6
6
|
var _hwtransportwebusb = require('@keystonehq/hw-transport-webusb');
|
|
@@ -25,7 +25,7 @@ function createKeystoneWebUsbConnector(options) {
|
|
|
25
25
|
disconnectListenerCleanupByTransport.set(transport, cleanup);
|
|
26
26
|
return transport;
|
|
27
27
|
};
|
|
28
|
-
return new (0,
|
|
28
|
+
return new (0, _chunkU76BQU3Hjs.KeystoneUsbConnectorBase)(
|
|
29
29
|
{
|
|
30
30
|
connect: async (config) => {
|
|
31
31
|
await _hwtransportwebusb.TransportWebUSB.isSupported();
|
package/dist/webusb.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hwk-keystone-connector-usb",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "IConnector implementation for Keystone hardware wallets via
|
|
3
|
+
"version": "1.2.8-alpha.13",
|
|
4
|
+
"description": "IConnector implementation for Keystone hardware wallets via WebUSB",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -27,16 +27,6 @@
|
|
|
27
27
|
"types": "./dist/webusb.d.ts",
|
|
28
28
|
"default": "./dist/webusb.js"
|
|
29
29
|
}
|
|
30
|
-
},
|
|
31
|
-
"./nodeusb": {
|
|
32
|
-
"import": {
|
|
33
|
-
"types": "./dist/nodeusb.d.mts",
|
|
34
|
-
"default": "./dist/nodeusb.mjs"
|
|
35
|
-
},
|
|
36
|
-
"require": {
|
|
37
|
-
"types": "./dist/nodeusb.d.ts",
|
|
38
|
-
"default": "./dist/nodeusb.js"
|
|
39
|
-
}
|
|
40
30
|
}
|
|
41
31
|
},
|
|
42
32
|
"files": [
|
|
@@ -69,22 +59,13 @@
|
|
|
69
59
|
"@keystonehq/hw-transport-usb": "0.2.0",
|
|
70
60
|
"@keystonehq/hw-transport-webusb": "0.5.3",
|
|
71
61
|
"@ngraveio/bc-ur": "1.1.13",
|
|
72
|
-
"@onekeyfe/hwk-adapter-core": "1.2.
|
|
62
|
+
"@onekeyfe/hwk-adapter-core": "1.2.8-alpha.13"
|
|
73
63
|
},
|
|
74
64
|
"devDependencies": {
|
|
75
65
|
"@keystonehq/bc-ur-registry-eth": "0.22.1",
|
|
76
|
-
"@keystonehq/hw-transport-nodeusb": "0.2.0",
|
|
77
66
|
"rimraf": "^5.0.0",
|
|
78
67
|
"tsup": "^8.0.0",
|
|
79
68
|
"typescript": "^5.4.0"
|
|
80
69
|
},
|
|
81
|
-
"
|
|
82
|
-
"@keystonehq/hw-transport-nodeusb": "0.2.0"
|
|
83
|
-
},
|
|
84
|
-
"peerDependenciesMeta": {
|
|
85
|
-
"@keystonehq/hw-transport-nodeusb": {
|
|
86
|
-
"optional": true
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
"gitHead": "9aa91a0780c3169164da575deadf5d256013d416"
|
|
70
|
+
"gitHead": "ed22eddce37ce0562b329c42a6985b50949ca412"
|
|
90
71
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-BYR5HEA3.js","../src/errors.ts","../src/KeystoneUsbConnectorBase.ts"],"names":["HardwareErrorCode","createHwkError"],"mappings":"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","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-BYR5HEA3.js","sourcesContent":[null,"import { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport { Status } from '@keystonehq/hw-transport-error';\n\nimport type { HwkError, HwkErrorOrigin } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Firmware status words are the low end of `Status` (0..15); client codes start at\n * `ERR_DEVICE_NOT_OPENED` (0xA0000001), so anything below came from a device response frame.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/** Firmware status words from a device response (EAPDU_Readme.md in the Keystone USB SDK). */\nconst DEVICE_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.RSP_FAILURE_CODE]: HardwareErrorCode.UnknownError,\n [Status.PRS_INVALID_TOTAL_PACKETS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_INVALID_INDEX]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_PARSING_ERROR]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_PARSING_UNMATCHED]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_MISMATCHED_WALLET]: HardwareErrorCode.DeviceMismatch,\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: HardwareErrorCode.PinInvalid,\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: HardwareErrorCode.ChainNotSupported,\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_EXPORT_ADDRESS_ERROR]: HardwareErrorCode.UnknownError,\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_EXPORT_ADDRESS_BUSY]: HardwareErrorCode.DeviceBusyInternal,\n};\n\n/** Used when the transport forwarded only its 'unknown error' placeholder for a firmware status. */\nconst DEVICE_STATUS_MESSAGE: Partial<Record<number, string>> = {\n [Status.RSP_FAILURE_CODE]: 'Keystone reported a failure',\n [Status.PRS_INVALID_TOTAL_PACKETS]: 'Keystone rejected the request framing (total packets)',\n [Status.PRS_INVALID_INDEX]: 'Keystone rejected the request framing (packet index)',\n [Status.PRS_PARSING_REJECTED]: 'Rejected on the Keystone screen',\n [Status.PRS_PARSING_ERROR]: 'Keystone could not parse the request',\n [Status.PRS_PARSING_DISALLOWED]: 'Keystone declined the request in its current state',\n [Status.PRS_PARSING_UNMATCHED]: 'Keystone found no handler for the request',\n [Status.PRS_PARSING_MISMATCHED_WALLET]: 'The request belongs to a different Keystone wallet',\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: 'Keystone password verification failed',\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: 'Keystone does not support this chain',\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: 'Keystone rejected the address export parameters',\n [Status.PRS_EXPORT_ADDRESS_ERROR]: 'Keystone failed to export the address',\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: 'Keystone declined to export the address',\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: 'Address export rejected on the Keystone screen',\n [Status.PRS_EXPORT_ADDRESS_BUSY]: 'Keystone is busy with another request',\n};\n\n/** The placeholder both Keystone transports use when they have nothing better. */\nconst PLACEHOLDER_MESSAGE = /^unknown error\\b/i;\n\n/** Client-side (transport/framing) failures, never reached the device. */\nconst CLIENT_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.ERR_DEVICE_NOT_OPENED]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_DEVICE_NOT_FOUND]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_TIMEOUT]: HardwareErrorCode.OperationTimeout,\n [Status.ERR_DATA_TOO_LARGE]: HardwareErrorCode.PayloadTooLarge,\n [Status.ERR_NOT_SUPPORTED]: HardwareErrorCode.TransportNotAvailable,\n};\n\n/** WebUSB DOMExceptions; an unplug or bus reset mid-call is the common case. */\nconst DOM_EXCEPTION_MAP = new Map<string, { code: HardwareErrorCode; origin: HwkErrorOrigin }>([\n ['NotFoundError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['NetworkError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['SecurityError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['NotAllowedError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['InvalidStateError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n ['AbortError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n]);\n\n/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because\n * duplicate `@keystonehq/*` module instances break `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const fields: { name?: unknown; code?: unknown; transportErrorCode?: unknown } =\n err && typeof err === 'object' ? err : {};\n const domName = typeof fields.name === 'string' ? fields.name : undefined;\n\n // Only five-digit codes are HWK codes; legacy DOMException codes (NotFoundError\n // is 8) must not pass through as hardware errors.\n if (typeof fields.code === 'number' && fields.code >= 10000 && fields.code <= 99999) {\n return err as HwkError;\n }\n\n const statusCode =\n typeof fields.transportErrorCode === 'number' ? fields.transportErrorCode : undefined;\n\n const message = err instanceof Error ? err.message : String(err);\n\n if (statusCode !== undefined) {\n const fromDevice = isDeviceStatus(statusCode);\n // An unlisted firmware status keeps origin 'device'; 'transport' would make the\n // adapter tear down a live session over an on-device decline.\n const code = fromDevice\n ? DEVICE_STATUS_MAP[statusCode] ?? HardwareErrorCode.UnknownError\n : CLIENT_STATUS_MAP[statusCode] ?? HardwareErrorCode.TransportError;\n let origin: HwkErrorOrigin | undefined;\n if (fromDevice) {\n origin = 'device';\n } else if (code !== HardwareErrorCode.OperationTimeout) {\n origin = 'transport';\n }\n const description = DEVICE_STATUS_MESSAGE[statusCode];\n return createHwkError({\n code,\n // The device's own payload text wins over the table.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A timeout may be either side, so it stays unlabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : undefined;\n if (domMapping) {\n return createHwkError({ ...domMapping, message, params: { domExceptionName: domName } });\n }\n\n // This mapper only wraps transport calls, so 'transport' names the throw site.\n return createHwkError({ code: HardwareErrorCode.TransportError, message, origin: 'transport' });\n}\n","import { UR, URDecoder, UREncoder } from '@ngraveio/bc-ur';\nimport { Actions } from '@keystonehq/hw-transport-usb';\nimport {\n EConnectorInteraction,\n HardwareErrorCode,\n MISSING_BIP32_MASTER_FINGERPRINT,\n TypedEventEmitter,\n createHardwareLinkId,\n createHardwareSearchTargetId,\n createHwkError,\n hasHardwareRuntimeIdPrefix,\n parseBip32MasterFingerprint,\n parseHardwareRuntimeId,\n serializeConnectorError,\n success,\n} from '@onekeyfe/hwk-adapter-core';\n\nimport { mapKeystoneUsbError } from './errors';\n\nimport type {\n ConnectorCallResult,\n ConnectorConnectTarget,\n ConnectorDevice,\n ConnectorEventMap,\n ConnectorEventType,\n ConnectorSearchDevicesOptions,\n ConnectorSession,\n IConnector,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\nimport type { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';\n\n/** Descriptor fields readable before opening; any may be absent if not published. */\nexport interface KeystoneUsbDeviceDescriptor {\n serialNumber?: string;\n productName?: string;\n manufacturerName?: string;\n vendorId?: number;\n productId?: number;\n /** Device release number (bcdDevice), split into its three nibble groups. */\n deviceVersionMajor?: number;\n deviceVersionMinor?: number;\n deviceVersionSubminor?: number;\n usbVersionMajor?: number;\n usbVersionMinor?: number;\n usbVersionSubminor?: number;\n deviceClass?: number;\n deviceSubclass?: number;\n deviceProtocol?: number;\n}\n\n/** The serial is not shown on the unit, so it would not help tell two devices apart. */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\n/** Static surface of `TransportWebUSB`/`TransportNodeUSB`, injected by `_subpath/*`. */\nexport interface KeystoneUsbTransportStatic {\n connect(config?: TransportConfig): Promise<TransportHID>;\n connectDevice?(\n device: KeystoneUsbDeviceDescriptor,\n config?: TransportConfig\n ): Promise<TransportHID>;\n getKeystoneDevices(): Promise<ReadonlyArray<KeystoneUsbDeviceDescriptor>>;\n requestPermission?(): Promise<void>;\n isSupported(): Promise<boolean>;\n /** Release transport-lifetime resources owned by the platform wrapper. */\n disposeTransport?(transport: TransportHID): void;\n}\n\ninterface KeystoneUr {\n urType: string;\n urData: string;\n}\n\ninterface UsbSession {\n transport: TransportHID;\n mfp?: string;\n dispose(): void;\n}\n\ninterface AppConfig {\n version?: string;\n mfp?: string;\n}\n\ninterface OpenedUsbTransport {\n transport: TransportHID;\n bindSessionId(sessionId: string): void;\n dispose(): void;\n}\n\ntype KeystoneUsbConnectInput =\n | { searchTargetId: string; expectedMasterFingerprint?: never }\n | { searchTargetId?: never; expectedMasterFingerprint: string }\n | { searchTargetId?: never; expectedMasterFingerprint?: never };\n\n// The SDK default of 15s is too short for on-device confirmation.\nconst DEFAULT_TIMEOUT_MS = 100_000;\n\nconst KEYSTONE_PUBLIC_DATA_UR_TYPE = 'qr-hardware-call';\n\nfunction toUrEncoded(ur: KeystoneUr): string {\n return new UREncoder(new UR(Buffer.from(ur.urData, 'hex'), ur.urType), Infinity)\n .nextPart()\n .toUpperCase();\n}\n\nfunction fromUrEncoded(encoded: unknown): KeystoneUr {\n // One complete UR or whitespace-separated parts; EAPDU framing is the transport's job.\n const text = typeof encoded === 'string' ? encoded.trim() : '';\n const parts = text.split(/\\s+/).filter(Boolean);\n const decoder = new URDecoder();\n for (const part of parts) {\n decoder.receivePart(part);\n if (decoder.isComplete()) break;\n }\n if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {\n const shape =\n typeof encoded === 'string'\n ? `string len=${text.length} parts=${parts.length}`\n : typeof encoded;\n throw createHwkError({\n code: HardwareErrorCode.PayloadTooLarge,\n message: `Keystone USB returned an incomplete BC-UR response (${shape})`,\n origin: 'device',\n });\n }\n const ur = decoder.resultUR();\n return { urType: ur.type, urData: ur.cbor.toString('hex') };\n}\n\n/**\n * Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so\n * `connect()` only caches the transport object.\n */\nexport class KeystoneUsbConnectorBase implements IConnector {\n readonly connectionType = 'usb' as const;\n\n private readonly transportClass: KeystoneUsbTransportStatic;\n\n private readonly timeoutMs: number;\n\n private readonly emitter = new TypedEventEmitter<ConnectorEventMap>();\n\n private readonly sessions = new Map<string, UsbSession>();\n\n private readonly discoveredDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private readonly availabilityDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private activeDiscoveryGeneration: symbol | undefined;\n\n private activeAvailabilityGeneration: symbol | undefined;\n\n /**\n * Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can\n * re-enumerate between exports, and that must not re-prompt.\n */\n private readonly publicDataConfirmedWallets = new Set<string>();\n\n constructor(transportClass: KeystoneUsbTransportStatic, options?: { timeoutMs?: number }) {\n this.transportClass = transportClass;\n this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n private _invalidateDiscoverySnapshot(): void {\n this.activeDiscoveryGeneration = undefined;\n this.discoveredDevices.clear();\n }\n\n private _invalidateAvailabilitySnapshot(): void {\n this.activeAvailabilityGeneration = undefined;\n this.availabilityDevices.clear();\n }\n\n async searchDevices(options?: ConnectorSearchDevicesOptions): Promise<ConnectorDevice[]> {\n const isAvailabilitySearch = options?.purpose === 'availability';\n const discoveryGeneration = Symbol(\n isAvailabilitySearch ? 'keystone-usb-availability' : 'keystone-usb-discovery'\n );\n if (isAvailabilitySearch) {\n this._invalidateAvailabilitySnapshot();\n this.activeAvailabilityGeneration = discoveryGeneration;\n } else {\n this._invalidateDiscoverySnapshot();\n this.activeDiscoveryGeneration = discoveryGeneration;\n }\n // Enumeration DOMException codes collide with the HWK range, so map them too.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // Without an mfp before opening, the target id names only this snapshot; platforms that\n // cannot reopen a cached descriptor fail closed on multi-device selection.\n if (\n (isAvailabilitySearch\n ? this.activeAvailabilityGeneration\n : this.activeDiscoveryGeneration) !== discoveryGeneration\n ) {\n return [];\n }\n return devices.map(device => {\n const connectId = createHardwareSearchTargetId('keystone');\n (isAvailabilitySearch ? this.availabilityDevices : this.discoveredDevices).set(\n connectId,\n device\n );\n return {\n connectId,\n deviceId: '',\n name: usbDisplayName(device),\n connectionType: 'usb',\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n // Verbatim descriptor fields; a missing key means the device did not publish it.\n raw: {\n serialNumber: device.serialNumber,\n productName: device.productName,\n manufacturerName: device.manufacturerName,\n vendorId: device.vendorId,\n productId: device.productId,\n deviceVersionMajor: device.deviceVersionMajor,\n deviceVersionMinor: device.deviceVersionMinor,\n deviceVersionSubminor: device.deviceVersionSubminor,\n usbVersionMajor: device.usbVersionMajor,\n usbVersionMinor: device.usbVersionMinor,\n usbVersionSubminor: device.usbVersionSubminor,\n deviceClass: device.deviceClass,\n deviceSubclass: device.deviceSubclass,\n deviceProtocol: device.deviceProtocol,\n },\n };\n });\n }\n\n async connect(searchTargetIdOrExpectedMasterFingerprint?: string): Promise<ConnectorSession> {\n return this._connectResolved(\n this._resolveConnectInput(searchTargetIdOrExpectedMasterFingerprint)\n );\n }\n\n async connectTarget(target: ConnectorConnectTarget): Promise<ConnectorSession> {\n switch (target.type) {\n case 'default':\n return this._connectResolved({});\n case 'search-target':\n return this._connectResolved({ searchTargetId: target.searchTargetId });\n case 'expected-device-identity': {\n const expectedMasterFingerprint = parseBip32MasterFingerprint(target.deviceIdentity);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a valid master fingerprint identity',\n });\n }\n return this._connectResolved({ expectedMasterFingerprint });\n }\n default:\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Unsupported Keystone USB connection target',\n });\n }\n }\n\n private async _connectResolved({\n searchTargetId,\n expectedMasterFingerprint,\n }: KeystoneUsbConnectInput): Promise<ConnectorSession> {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.Searching,\n payload: { sessionId: '' },\n });\n let selectedDevice = searchTargetId\n ? this.discoveredDevices.get(searchTargetId) ?? this.availabilityDevices.get(searchTargetId)\n : undefined;\n if (searchTargetId && !selectedDevice) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Keystone USB search target is not in the current scan: ${searchTargetId}`,\n recovery: { scope: 'search-target' },\n });\n }\n let openedTransport: OpenedUsbTransport | undefined;\n try {\n let config: AppConfig;\n\n if (expectedMasterFingerprint && !searchTargetId) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (!this.transportClass.connectDevice && availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot identify one of multiple connected Keystone devices',\n });\n }\n\n if (this.transportClass.connectDevice) {\n let readableDeviceFound = false;\n let lastError: unknown;\n let matched:\n | {\n device: KeystoneUsbDeviceDescriptor;\n opened: OpenedUsbTransport;\n config: AppConfig;\n }\n | undefined;\n for (const device of availableDevices) {\n let candidate: OpenedUsbTransport | undefined;\n try {\n // eslint-disable-next-line no-await-in-loop\n candidate = await this._openTransport(device);\n // eslint-disable-next-line no-await-in-loop\n const candidateConfig = await this._readAppConfig(candidate.transport);\n readableDeviceFound = true;\n if (candidateConfig.mfp?.toLowerCase() === expectedMasterFingerprint.toLowerCase()) {\n matched = { device, opened: candidate, config: candidateConfig };\n break;\n }\n candidate.dispose();\n } catch (error) {\n candidate?.dispose();\n lastError = error;\n }\n }\n if (!matched) {\n if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: `No connected Keystone wallet matches fingerprint ${expectedMasterFingerprint}`,\n });\n }\n selectedDevice = matched.device;\n openedTransport = matched.opened;\n config = matched.config;\n } else {\n openedTransport = await this._openTransport();\n config = await this._readAppConfig(openedTransport.transport);\n }\n } else {\n if (!selectedDevice && this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'Select a Keystone USB device before connecting',\n });\n }\n [selectedDevice] = availableDevices;\n }\n if (selectedDevice && !this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot target one of multiple connected Keystone devices',\n });\n }\n }\n openedTransport = await this._openTransport(selectedDevice);\n config = await this._readAppConfig(openedTransport.transport);\n }\n\n const activeOpenedTransport = openedTransport;\n const { transport } = activeOpenedTransport;\n if (\n expectedMasterFingerprint &&\n config.mfp &&\n config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()\n ) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: `Connected Keystone wallet (mfp ${config.mfp}) does not match the requested wallet fingerprint (${expectedMasterFingerprint})`,\n });\n }\n const sessionId = createHardwareLinkId('keystone');\n activeOpenedTransport.bindSessionId(sessionId);\n this.sessions.set(sessionId, {\n transport,\n mfp: config.mfp,\n dispose: () => activeOpenedTransport.dispose(),\n });\n openedTransport = undefined;\n const device: ConnectorDevice = {\n connectId: sessionId,\n deviceId: '',\n name: selectedDevice ? usbDisplayName(selectedDevice) : 'Keystone',\n model: selectedDevice?.productName,\n connectionType: 'usb',\n serialNumber: selectedDevice?.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint: config.mfp },\n };\n this.emitter.emit('device-connect', { device });\n return {\n sessionId,\n deviceInfo: this._toDeviceInfo(device, config.version, config.mfp),\n };\n } catch (err) {\n openedTransport?.dispose();\n throw mapKeystoneUsbError(err);\n }\n }\n\n private async _openTransport(device?: KeystoneUsbDeviceDescriptor): Promise<OpenedUsbTransport> {\n // A rejected candidate may keep its disconnect listener; a per-descriptor\n // holder stops it from retiring a later matched session.\n let connectedSessionId: string | undefined;\n const transportConfig: TransportConfig = {\n timeout: this.timeoutMs,\n disconnectListener: () =>\n connectedSessionId ? this.disconnect(connectedSessionId) : undefined,\n };\n const transport = await (device && this.transportClass.connectDevice\n ? this.transportClass.connectDevice(device, transportConfig)\n : this.transportClass.connect(transportConfig));\n let disposed = false;\n return {\n transport,\n bindSessionId(sessionId: string) {\n connectedSessionId = sessionId;\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this.transportClass.disposeTransport?.(transport);\n },\n };\n }\n\n private _resolveConnectInput(value?: string): KeystoneUsbConnectInput {\n if (!value) return {};\n\n const runtimeId = parseHardwareRuntimeId(value);\n if (runtimeId) {\n // Ownership is settled by the snapshot lookup in `_connectResolved`.\n if (runtimeId.kind === 'search-target' && runtimeId.vendor === 'keystone') {\n return { searchTargetId: value };\n }\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received an incompatible hardware runtime id',\n params: { kind: runtimeId.kind, vendor: runtimeId.vendor },\n });\n }\n\n if (hasHardwareRuntimeIdPrefix(value)) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received a malformed hardware runtime id',\n });\n }\n\n const expectedMasterFingerprint = parseBip32MasterFingerprint(value);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a search target or master fingerprint',\n });\n }\n return { expectedMasterFingerprint };\n }\n\n disconnect(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n this.sessions.delete(sessionId);\n if (session) {\n session.dispose();\n // No persistent claim to release; each send() already closed the device.\n this.emitter.emit('device-disconnect', { connectId: sessionId });\n }\n return Promise.resolve();\n }\n\n /** Keep the vendor transport as the EAPDU framing authority. */\n private async _sendResolveUr(transport: TransportHID, encodedUr: string): Promise<KeystoneUr> {\n const response = await transport.send<{ payload: string }>(Actions.CMD_RESOLVE_UR, encodedUr);\n return fromUrEncoded(response.payload);\n }\n\n async call(sessionId: string, method: string, params: unknown): Promise<ConnectorCallResult> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Unknown Keystone USB session: ${sessionId}`,\n })\n ),\n };\n }\n\n try {\n switch (method) {\n case 'resolveUr': {\n const { urType, urData } = params as KeystoneUr;\n const encoded = toUrEncoded({ urType, urData });\n const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;\n // Public-data export prompts once per wallet; signing always prompts.\n const publicDataKey = session.mfp?.toLowerCase() ?? sessionId;\n const shouldShowConfirmation =\n !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.ConfirmOnDevice,\n payload: { sessionId },\n });\n }\n try {\n const response = await this._sendResolveUr(session.transport, encoded);\n if (isPublicDataRequest) {\n this.publicDataConfirmedWallets.add(publicDataKey);\n }\n return success(response);\n } finally {\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.InteractionComplete,\n payload: { sessionId },\n });\n }\n }\n }\n case 'checkLockStatus': {\n const response = await session.transport.send<{ payload: boolean }>(\n Actions.CMD_CHECK_LOCK_STATUS,\n ''\n );\n // `true` = locked is inferred from the SDK method name only; unverified on hardware.\n return success({ locked: response.payload });\n }\n case 'getAppConfig':\n return success(await this._readAppConfig(session.transport));\n default:\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.MethodNotSupported,\n message: `Unknown Keystone USB connector method: ${method}`,\n })\n ),\n };\n }\n } catch (err) {\n return { success: false, error: serializeConnectorError(mapKeystoneUsbError(err)) };\n }\n }\n\n // The SDK cannot interrupt an in-flight transfer; the pending send() settles or\n // times out on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // PIN/passphrase entry happens on the device touchscreen, never via the host.\n uiResponse(_response: UiResponseEvent): void {}\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.on(event, handler);\n }\n\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.off(event, handler);\n }\n\n reset(): void {\n for (const session of this.sessions.values()) {\n session.dispose();\n }\n this.sessions.clear();\n this._invalidateDiscoverySnapshot();\n this._invalidateAvailabilitySnapshot();\n this.publicDataConfirmedWallets.clear();\n }\n\n private async _readAppConfig(transport: TransportHID): Promise<AppConfig> {\n const response = await transport.send<Record<string, unknown>>(\n Actions.CMD_GET_DEVICE_VERSION,\n ''\n );\n const rawMasterFingerprint = response.walletMFP;\n const masterFingerprint = parseBip32MasterFingerprint(rawMasterFingerprint);\n if (masterFingerprint === MISSING_BIP32_MASTER_FINGERPRINT) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotInitialized,\n message: 'Keystone has no wallet yet; it reported an empty master fingerprint',\n });\n }\n if (rawMasterFingerprint !== undefined && !masterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message:\n 'Keystone returned an invalid master fingerprint; expected exactly 4 bytes (8 hex characters)',\n });\n }\n return {\n version: typeof response.firmwareVersion === 'string' ? response.firmwareVersion : undefined,\n mfp: masterFingerprint,\n };\n }\n\n private _toDeviceInfo(\n device: ConnectorDevice,\n firmwareVersion?: string,\n masterFingerprint?: string\n ) {\n return {\n vendor: 'keystone' as const,\n // Model is the USB `productName`; empty, not 'unknown', so the host's\n // default-name fallback wins.\n model: device.model ?? '',\n modelName: device.modelName,\n firmwareVersion: firmwareVersion ?? '0.0.0',\n deviceId: device.deviceId,\n connectId: device.connectId,\n connectionType: 'usb' as const,\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint },\n };\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/KeystoneUsbConnectorBase.ts"],"sourcesContent":["import { HardwareErrorCode, createHwkError } from '@onekeyfe/hwk-adapter-core';\nimport { Status } from '@keystonehq/hw-transport-error';\n\nimport type { HwkError, HwkErrorOrigin } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Firmware status words are the low end of `Status` (0..15); client codes start at\n * `ERR_DEVICE_NOT_OPENED` (0xA0000001), so anything below came from a device response frame.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/** Firmware status words from a device response (EAPDU_Readme.md in the Keystone USB SDK). */\nconst DEVICE_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.RSP_FAILURE_CODE]: HardwareErrorCode.UnknownError,\n [Status.PRS_INVALID_TOTAL_PACKETS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_INVALID_INDEX]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_PARSING_ERROR]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_PARSING_UNMATCHED]: HardwareErrorCode.InvalidParams,\n [Status.PRS_PARSING_MISMATCHED_WALLET]: HardwareErrorCode.DeviceMismatch,\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: HardwareErrorCode.PinInvalid,\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: HardwareErrorCode.ChainNotSupported,\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: HardwareErrorCode.InvalidParams,\n [Status.PRS_EXPORT_ADDRESS_ERROR]: HardwareErrorCode.UnknownError,\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: HardwareErrorCode.DeviceLocked,\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: HardwareErrorCode.UserRejected,\n [Status.PRS_EXPORT_ADDRESS_BUSY]: HardwareErrorCode.DeviceBusyInternal,\n};\n\n/** Used when the transport forwarded only its 'unknown error' placeholder for a firmware status. */\nconst DEVICE_STATUS_MESSAGE: Partial<Record<number, string>> = {\n [Status.RSP_FAILURE_CODE]: 'Keystone reported a failure',\n [Status.PRS_INVALID_TOTAL_PACKETS]: 'Keystone rejected the request framing (total packets)',\n [Status.PRS_INVALID_INDEX]: 'Keystone rejected the request framing (packet index)',\n [Status.PRS_PARSING_REJECTED]: 'Rejected on the Keystone screen',\n [Status.PRS_PARSING_ERROR]: 'Keystone could not parse the request',\n [Status.PRS_PARSING_DISALLOWED]: 'Keystone declined the request in its current state',\n [Status.PRS_PARSING_UNMATCHED]: 'Keystone found no handler for the request',\n [Status.PRS_PARSING_MISMATCHED_WALLET]: 'The request belongs to a different Keystone wallet',\n [Status.PRS_PARSING_VERIFY_PASSWORD_ERROR]: 'Keystone password verification failed',\n [Status.PRS_EXPORT_ADDRESS_UNSUPPORTED_CHAIN]: 'Keystone does not support this chain',\n [Status.PRS_EXPORT_ADDRESS_INVALID_PARAMS]: 'Keystone rejected the address export parameters',\n [Status.PRS_EXPORT_ADDRESS_ERROR]: 'Keystone failed to export the address',\n [Status.PRS_EXPORT_ADDRESS_DISALLOWED]: 'Keystone declined to export the address',\n [Status.PRS_EXPORT_ADDRESS_REJECTED]: 'Address export rejected on the Keystone screen',\n [Status.PRS_EXPORT_ADDRESS_BUSY]: 'Keystone is busy with another request',\n};\n\n/** The placeholder both Keystone transports use when they have nothing better. */\nconst PLACEHOLDER_MESSAGE = /^unknown error\\b/i;\n\n/** Client-side (transport/framing) failures, never reached the device. */\nconst CLIENT_STATUS_MAP: Partial<Record<number, HardwareErrorCode>> = {\n [Status.ERR_DEVICE_NOT_OPENED]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_DEVICE_NOT_FOUND]: HardwareErrorCode.DeviceNotFound,\n [Status.ERR_TIMEOUT]: HardwareErrorCode.OperationTimeout,\n [Status.ERR_DATA_TOO_LARGE]: HardwareErrorCode.PayloadTooLarge,\n [Status.ERR_NOT_SUPPORTED]: HardwareErrorCode.TransportNotAvailable,\n};\n\n/** WebUSB DOMExceptions; an unplug or bus reset mid-call is the common case. */\nconst DOM_EXCEPTION_MAP = new Map<string, { code: HardwareErrorCode; origin: HwkErrorOrigin }>([\n ['NotFoundError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['NetworkError', { code: HardwareErrorCode.DeviceNotFound, origin: 'transport' }],\n ['SecurityError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['NotAllowedError', { code: HardwareErrorCode.DevicePermissionDenied, origin: 'host' }],\n ['InvalidStateError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n ['AbortError', { code: HardwareErrorCode.DeviceBusy, origin: 'transport' }],\n]);\n\n/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because\n * duplicate `@keystonehq/*` module instances break `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const fields: { name?: unknown; code?: unknown; transportErrorCode?: unknown } =\n err && typeof err === 'object' ? err : {};\n const domName = typeof fields.name === 'string' ? fields.name : undefined;\n\n // Only five-digit codes are HWK codes; legacy DOMException codes (NotFoundError\n // is 8) must not pass through as hardware errors.\n if (typeof fields.code === 'number' && fields.code >= 10000 && fields.code <= 99999) {\n return err as HwkError;\n }\n\n const statusCode =\n typeof fields.transportErrorCode === 'number' ? fields.transportErrorCode : undefined;\n\n const message = err instanceof Error ? err.message : String(err);\n\n if (statusCode !== undefined) {\n const fromDevice = isDeviceStatus(statusCode);\n // An unlisted firmware status keeps origin 'device'; 'transport' would make the\n // adapter tear down a live session over an on-device decline.\n const code = fromDevice\n ? DEVICE_STATUS_MAP[statusCode] ?? HardwareErrorCode.UnknownError\n : CLIENT_STATUS_MAP[statusCode] ?? HardwareErrorCode.TransportError;\n let origin: HwkErrorOrigin | undefined;\n if (fromDevice) {\n origin = 'device';\n } else if (code !== HardwareErrorCode.OperationTimeout) {\n origin = 'transport';\n }\n const description = DEVICE_STATUS_MESSAGE[statusCode];\n return createHwkError({\n code,\n // The device's own payload text wins over the table.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A timeout may be either side, so it stays unlabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : undefined;\n if (domMapping) {\n return createHwkError({ ...domMapping, message, params: { domExceptionName: domName } });\n }\n\n // This mapper only wraps transport calls, so 'transport' names the throw site.\n return createHwkError({ code: HardwareErrorCode.TransportError, message, origin: 'transport' });\n}\n","import { UR, URDecoder, UREncoder } from '@ngraveio/bc-ur';\nimport { Actions } from '@keystonehq/hw-transport-usb';\nimport {\n EConnectorInteraction,\n HardwareErrorCode,\n MISSING_BIP32_MASTER_FINGERPRINT,\n TypedEventEmitter,\n createHardwareLinkId,\n createHardwareSearchTargetId,\n createHwkError,\n hasHardwareRuntimeIdPrefix,\n parseBip32MasterFingerprint,\n parseHardwareRuntimeId,\n serializeConnectorError,\n success,\n} from '@onekeyfe/hwk-adapter-core';\n\nimport { mapKeystoneUsbError } from './errors';\n\nimport type {\n ConnectorCallResult,\n ConnectorConnectTarget,\n ConnectorDevice,\n ConnectorEventMap,\n ConnectorEventType,\n ConnectorSearchDevicesOptions,\n ConnectorSession,\n IConnector,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\nimport type { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';\n\n/** Descriptor fields readable before opening; any may be absent if not published. */\nexport interface KeystoneUsbDeviceDescriptor {\n serialNumber?: string;\n productName?: string;\n manufacturerName?: string;\n vendorId?: number;\n productId?: number;\n /** Device release number (bcdDevice), split into its three nibble groups. */\n deviceVersionMajor?: number;\n deviceVersionMinor?: number;\n deviceVersionSubminor?: number;\n usbVersionMajor?: number;\n usbVersionMinor?: number;\n usbVersionSubminor?: number;\n deviceClass?: number;\n deviceSubclass?: number;\n deviceProtocol?: number;\n}\n\n/** The serial is not shown on the unit, so it would not help tell two devices apart. */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\n/** Static surface of `TransportWebUSB`/`TransportNodeUSB`, injected by `_subpath/*`. */\nexport interface KeystoneUsbTransportStatic {\n connect(config?: TransportConfig): Promise<TransportHID>;\n connectDevice?(\n device: KeystoneUsbDeviceDescriptor,\n config?: TransportConfig\n ): Promise<TransportHID>;\n getKeystoneDevices(): Promise<ReadonlyArray<KeystoneUsbDeviceDescriptor>>;\n requestPermission?(): Promise<void>;\n isSupported(): Promise<boolean>;\n /** Release transport-lifetime resources owned by the platform wrapper. */\n disposeTransport?(transport: TransportHID): void;\n}\n\ninterface KeystoneUr {\n urType: string;\n urData: string;\n}\n\ninterface UsbSession {\n transport: TransportHID;\n mfp?: string;\n dispose(): void;\n}\n\ninterface AppConfig {\n version?: string;\n mfp?: string;\n}\n\ninterface OpenedUsbTransport {\n transport: TransportHID;\n bindSessionId(sessionId: string): void;\n dispose(): void;\n}\n\ntype KeystoneUsbConnectInput =\n | { searchTargetId: string; expectedMasterFingerprint?: never }\n | { searchTargetId?: never; expectedMasterFingerprint: string }\n | { searchTargetId?: never; expectedMasterFingerprint?: never };\n\n// The SDK default of 15s is too short for on-device confirmation.\nconst DEFAULT_TIMEOUT_MS = 100_000;\n\nconst KEYSTONE_PUBLIC_DATA_UR_TYPE = 'qr-hardware-call';\n\nfunction toUrEncoded(ur: KeystoneUr): string {\n return new UREncoder(new UR(Buffer.from(ur.urData, 'hex'), ur.urType), Infinity)\n .nextPart()\n .toUpperCase();\n}\n\nfunction fromUrEncoded(encoded: unknown): KeystoneUr {\n // One complete UR or whitespace-separated parts; EAPDU framing is the transport's job.\n const text = typeof encoded === 'string' ? encoded.trim() : '';\n const parts = text.split(/\\s+/).filter(Boolean);\n const decoder = new URDecoder();\n for (const part of parts) {\n decoder.receivePart(part);\n if (decoder.isComplete()) break;\n }\n if (!parts.length || !decoder.isComplete() || !decoder.isSuccess()) {\n const shape =\n typeof encoded === 'string'\n ? `string len=${text.length} parts=${parts.length}`\n : typeof encoded;\n throw createHwkError({\n code: HardwareErrorCode.PayloadTooLarge,\n message: `Keystone USB returned an incomplete BC-UR response (${shape})`,\n origin: 'device',\n });\n }\n const ur = decoder.resultUR();\n return { urType: ur.type, urData: ur.cbor.toString('hex') };\n}\n\n/**\n * Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so\n * `connect()` only caches the transport object.\n */\nexport class KeystoneUsbConnectorBase implements IConnector {\n readonly connectionType = 'usb' as const;\n\n private readonly transportClass: KeystoneUsbTransportStatic;\n\n private readonly timeoutMs: number;\n\n private readonly emitter = new TypedEventEmitter<ConnectorEventMap>();\n\n private readonly sessions = new Map<string, UsbSession>();\n\n private readonly discoveredDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private readonly availabilityDevices = new Map<string, KeystoneUsbDeviceDescriptor>();\n\n private activeDiscoveryGeneration: symbol | undefined;\n\n private activeAvailabilityGeneration: symbol | undefined;\n\n /**\n * Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can\n * re-enumerate between exports, and that must not re-prompt.\n */\n private readonly publicDataConfirmedWallets = new Set<string>();\n\n constructor(transportClass: KeystoneUsbTransportStatic, options?: { timeoutMs?: number }) {\n this.transportClass = transportClass;\n this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n private _invalidateDiscoverySnapshot(): void {\n this.activeDiscoveryGeneration = undefined;\n this.discoveredDevices.clear();\n }\n\n private _invalidateAvailabilitySnapshot(): void {\n this.activeAvailabilityGeneration = undefined;\n this.availabilityDevices.clear();\n }\n\n async searchDevices(options?: ConnectorSearchDevicesOptions): Promise<ConnectorDevice[]> {\n const isAvailabilitySearch = options?.purpose === 'availability';\n const discoveryGeneration = Symbol(\n isAvailabilitySearch ? 'keystone-usb-availability' : 'keystone-usb-discovery'\n );\n if (isAvailabilitySearch) {\n this._invalidateAvailabilitySnapshot();\n this.activeAvailabilityGeneration = discoveryGeneration;\n } else {\n this._invalidateDiscoverySnapshot();\n this.activeDiscoveryGeneration = discoveryGeneration;\n }\n // Enumeration DOMException codes collide with the HWK range, so map them too.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // Without an mfp before opening, the target id names only this snapshot; platforms that\n // cannot reopen a cached descriptor fail closed on multi-device selection.\n if (\n (isAvailabilitySearch\n ? this.activeAvailabilityGeneration\n : this.activeDiscoveryGeneration) !== discoveryGeneration\n ) {\n return [];\n }\n return devices.map(device => {\n const connectId = createHardwareSearchTargetId('keystone');\n (isAvailabilitySearch ? this.availabilityDevices : this.discoveredDevices).set(\n connectId,\n device\n );\n return {\n connectId,\n deviceId: '',\n name: usbDisplayName(device),\n connectionType: 'usb',\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n // Verbatim descriptor fields; a missing key means the device did not publish it.\n raw: {\n serialNumber: device.serialNumber,\n productName: device.productName,\n manufacturerName: device.manufacturerName,\n vendorId: device.vendorId,\n productId: device.productId,\n deviceVersionMajor: device.deviceVersionMajor,\n deviceVersionMinor: device.deviceVersionMinor,\n deviceVersionSubminor: device.deviceVersionSubminor,\n usbVersionMajor: device.usbVersionMajor,\n usbVersionMinor: device.usbVersionMinor,\n usbVersionSubminor: device.usbVersionSubminor,\n deviceClass: device.deviceClass,\n deviceSubclass: device.deviceSubclass,\n deviceProtocol: device.deviceProtocol,\n },\n };\n });\n }\n\n async connect(searchTargetIdOrExpectedMasterFingerprint?: string): Promise<ConnectorSession> {\n return this._connectResolved(\n this._resolveConnectInput(searchTargetIdOrExpectedMasterFingerprint)\n );\n }\n\n async connectTarget(target: ConnectorConnectTarget): Promise<ConnectorSession> {\n switch (target.type) {\n case 'default':\n return this._connectResolved({});\n case 'search-target':\n return this._connectResolved({ searchTargetId: target.searchTargetId });\n case 'expected-device-identity': {\n const expectedMasterFingerprint = parseBip32MasterFingerprint(target.deviceIdentity);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a valid master fingerprint identity',\n });\n }\n return this._connectResolved({ expectedMasterFingerprint });\n }\n default:\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Unsupported Keystone USB connection target',\n });\n }\n }\n\n private async _connectResolved({\n searchTargetId,\n expectedMasterFingerprint,\n }: KeystoneUsbConnectInput): Promise<ConnectorSession> {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.Searching,\n payload: { sessionId: '' },\n });\n let selectedDevice = searchTargetId\n ? this.discoveredDevices.get(searchTargetId) ?? this.availabilityDevices.get(searchTargetId)\n : undefined;\n if (searchTargetId && !selectedDevice) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Keystone USB search target is not in the current scan: ${searchTargetId}`,\n recovery: { scope: 'search-target' },\n });\n }\n let openedTransport: OpenedUsbTransport | undefined;\n try {\n let config: AppConfig;\n\n if (expectedMasterFingerprint && !searchTargetId) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (!this.transportClass.connectDevice && availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot identify one of multiple connected Keystone devices',\n });\n }\n\n if (this.transportClass.connectDevice) {\n let readableDeviceFound = false;\n let lastError: unknown;\n let matched:\n | {\n device: KeystoneUsbDeviceDescriptor;\n opened: OpenedUsbTransport;\n config: AppConfig;\n }\n | undefined;\n for (const device of availableDevices) {\n let candidate: OpenedUsbTransport | undefined;\n try {\n // eslint-disable-next-line no-await-in-loop\n candidate = await this._openTransport(device);\n // eslint-disable-next-line no-await-in-loop\n const candidateConfig = await this._readAppConfig(candidate.transport);\n readableDeviceFound = true;\n if (candidateConfig.mfp?.toLowerCase() === expectedMasterFingerprint.toLowerCase()) {\n matched = { device, opened: candidate, config: candidateConfig };\n break;\n }\n candidate.dispose();\n } catch (error) {\n candidate?.dispose();\n lastError = error;\n }\n }\n if (!matched) {\n if (!readableDeviceFound && lastError) throw mapKeystoneUsbError(lastError);\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: `No connected Keystone wallet matches fingerprint ${expectedMasterFingerprint}`,\n });\n }\n selectedDevice = matched.device;\n openedTransport = matched.opened;\n config = matched.config;\n } else {\n openedTransport = await this._openTransport();\n config = await this._readAppConfig(openedTransport.transport);\n }\n } else {\n if (!selectedDevice && this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length === 0) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No Keystone USB device is available',\n });\n }\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'Select a Keystone USB device before connecting',\n });\n }\n [selectedDevice] = availableDevices;\n }\n if (selectedDevice && !this.transportClass.connectDevice) {\n const availableDevices = await this.transportClass.getKeystoneDevices();\n if (availableDevices.length > 1) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceOneDeviceOnly,\n message: 'This platform cannot target one of multiple connected Keystone devices',\n });\n }\n }\n openedTransport = await this._openTransport(selectedDevice);\n config = await this._readAppConfig(openedTransport.transport);\n }\n\n const activeOpenedTransport = openedTransport;\n const { transport } = activeOpenedTransport;\n if (\n expectedMasterFingerprint &&\n config.mfp &&\n config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()\n ) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: `Connected Keystone wallet (mfp ${config.mfp}) does not match the requested wallet fingerprint (${expectedMasterFingerprint})`,\n });\n }\n const sessionId = createHardwareLinkId('keystone');\n activeOpenedTransport.bindSessionId(sessionId);\n this.sessions.set(sessionId, {\n transport,\n mfp: config.mfp,\n dispose: () => activeOpenedTransport.dispose(),\n });\n openedTransport = undefined;\n const device: ConnectorDevice = {\n connectId: sessionId,\n deviceId: '',\n name: selectedDevice ? usbDisplayName(selectedDevice) : 'Keystone',\n model: selectedDevice?.productName,\n connectionType: 'usb',\n serialNumber: selectedDevice?.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint: config.mfp },\n };\n this.emitter.emit('device-connect', { device });\n return {\n sessionId,\n deviceInfo: this._toDeviceInfo(device, config.version, config.mfp),\n };\n } catch (err) {\n openedTransport?.dispose();\n throw mapKeystoneUsbError(err);\n }\n }\n\n private async _openTransport(device?: KeystoneUsbDeviceDescriptor): Promise<OpenedUsbTransport> {\n // A rejected candidate may keep its disconnect listener; a per-descriptor\n // holder stops it from retiring a later matched session.\n let connectedSessionId: string | undefined;\n const transportConfig: TransportConfig = {\n timeout: this.timeoutMs,\n disconnectListener: () =>\n connectedSessionId ? this.disconnect(connectedSessionId) : undefined,\n };\n const transport = await (device && this.transportClass.connectDevice\n ? this.transportClass.connectDevice(device, transportConfig)\n : this.transportClass.connect(transportConfig));\n let disposed = false;\n return {\n transport,\n bindSessionId(sessionId: string) {\n connectedSessionId = sessionId;\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this.transportClass.disposeTransport?.(transport);\n },\n };\n }\n\n private _resolveConnectInput(value?: string): KeystoneUsbConnectInput {\n if (!value) return {};\n\n const runtimeId = parseHardwareRuntimeId(value);\n if (runtimeId) {\n // Ownership is settled by the snapshot lookup in `_connectResolved`.\n if (runtimeId.kind === 'search-target' && runtimeId.vendor === 'keystone') {\n return { searchTargetId: value };\n }\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received an incompatible hardware runtime id',\n params: { kind: runtimeId.kind, vendor: runtimeId.vendor },\n });\n }\n\n if (hasHardwareRuntimeIdPrefix(value)) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector received a malformed hardware runtime id',\n });\n }\n\n const expectedMasterFingerprint = parseBip32MasterFingerprint(value);\n if (!expectedMasterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.InvalidParams,\n message: 'Keystone USB connector requires a search target or master fingerprint',\n });\n }\n return { expectedMasterFingerprint };\n }\n\n disconnect(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n this.sessions.delete(sessionId);\n if (session) {\n session.dispose();\n // No persistent claim to release; each send() already closed the device.\n this.emitter.emit('device-disconnect', { connectId: sessionId });\n }\n return Promise.resolve();\n }\n\n /** Keep the vendor transport as the EAPDU framing authority. */\n private async _sendResolveUr(transport: TransportHID, encodedUr: string): Promise<KeystoneUr> {\n const response = await transport.send<{ payload: string }>(Actions.CMD_RESOLVE_UR, encodedUr);\n return fromUrEncoded(response.payload);\n }\n\n async call(sessionId: string, method: string, params: unknown): Promise<ConnectorCallResult> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: `Unknown Keystone USB session: ${sessionId}`,\n })\n ),\n };\n }\n\n try {\n switch (method) {\n case 'resolveUr': {\n const { urType, urData } = params as KeystoneUr;\n const encoded = toUrEncoded({ urType, urData });\n const isPublicDataRequest = urType === KEYSTONE_PUBLIC_DATA_UR_TYPE;\n // Public-data export prompts once per wallet; signing always prompts.\n const publicDataKey = session.mfp?.toLowerCase() ?? sessionId;\n const shouldShowConfirmation =\n !isPublicDataRequest || !this.publicDataConfirmedWallets.has(publicDataKey);\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.ConfirmOnDevice,\n payload: { sessionId },\n });\n }\n try {\n const response = await this._sendResolveUr(session.transport, encoded);\n if (isPublicDataRequest) {\n this.publicDataConfirmedWallets.add(publicDataKey);\n }\n return success(response);\n } finally {\n if (shouldShowConfirmation) {\n this.emitter.emit('ui-event', {\n type: EConnectorInteraction.InteractionComplete,\n payload: { sessionId },\n });\n }\n }\n }\n case 'checkLockStatus': {\n const response = await session.transport.send<{ payload: boolean }>(\n Actions.CMD_CHECK_LOCK_STATUS,\n ''\n );\n // `true` = locked is inferred from the SDK method name only; unverified on hardware.\n return success({ locked: response.payload });\n }\n case 'getAppConfig':\n return success(await this._readAppConfig(session.transport));\n default:\n return {\n success: false,\n error: serializeConnectorError(\n createHwkError({\n code: HardwareErrorCode.MethodNotSupported,\n message: `Unknown Keystone USB connector method: ${method}`,\n })\n ),\n };\n }\n } catch (err) {\n return { success: false, error: serializeConnectorError(mapKeystoneUsbError(err)) };\n }\n }\n\n // The SDK cannot interrupt an in-flight transfer; the pending send() settles or\n // times out on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // PIN/passphrase entry happens on the device touchscreen, never via the host.\n uiResponse(_response: UiResponseEvent): void {}\n\n on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.on(event, handler);\n }\n\n off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void {\n this.emitter.off(event, handler);\n }\n\n reset(): void {\n for (const session of this.sessions.values()) {\n session.dispose();\n }\n this.sessions.clear();\n this._invalidateDiscoverySnapshot();\n this._invalidateAvailabilitySnapshot();\n this.publicDataConfirmedWallets.clear();\n }\n\n private async _readAppConfig(transport: TransportHID): Promise<AppConfig> {\n const response = await transport.send<Record<string, unknown>>(\n Actions.CMD_GET_DEVICE_VERSION,\n ''\n );\n const rawMasterFingerprint = response.walletMFP;\n const masterFingerprint = parseBip32MasterFingerprint(rawMasterFingerprint);\n if (masterFingerprint === MISSING_BIP32_MASTER_FINGERPRINT) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotInitialized,\n message: 'Keystone has no wallet yet; it reported an empty master fingerprint',\n });\n }\n if (rawMasterFingerprint !== undefined && !masterFingerprint) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message:\n 'Keystone returned an invalid master fingerprint; expected exactly 4 bytes (8 hex characters)',\n });\n }\n return {\n version: typeof response.firmwareVersion === 'string' ? response.firmwareVersion : undefined,\n mfp: masterFingerprint,\n };\n }\n\n private _toDeviceInfo(\n device: ConnectorDevice,\n firmwareVersion?: string,\n masterFingerprint?: string\n ) {\n return {\n vendor: 'keystone' as const,\n // Model is the USB `productName`; empty, not 'unknown', so the host's\n // default-name fallback wins.\n model: device.model ?? '',\n modelName: device.modelName,\n firmwareVersion: firmwareVersion ?? '0.0.0',\n deviceId: device.deviceId,\n connectId: device.connectId,\n connectionType: 'usb' as const,\n serialNumber: device.serialNumber,\n capabilities: { persistentDeviceIdentity: false },\n raw: { masterFingerprint },\n };\n }\n}\n"],"mappings":"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","names":["HardwareErrorCode","createHwkError","createHwkError","HardwareErrorCode","device"]}
|
package/dist/nodeusb.d.mts
DELETED
package/dist/nodeusb.d.ts
DELETED
package/dist/nodeusb.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
-
|
|
3
|
-
var _chunkBYR5HEA3js = require('./chunk-BYR5HEA3.js');
|
|
4
|
-
|
|
5
|
-
// src/_subpath/nodeusb.ts
|
|
6
|
-
var _hwtransportnodeusb = require('@keystonehq/hw-transport-nodeusb');
|
|
7
|
-
function createKeystoneNodeUsbConnector(options) {
|
|
8
|
-
return new (0, _chunkBYR5HEA3js.KeystoneUsbConnectorBase)(_hwtransportnodeusb.TransportNodeUSB, options);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
exports.createKeystoneNodeUsbConnector = createKeystoneNodeUsbConnector;
|
|
13
|
-
//# sourceMappingURL=nodeusb.js.map
|
package/dist/nodeusb.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/nodeusb.js","../src/_subpath/nodeusb.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACA;ACJA,sEAAiC;AAM1B,SAAS,8BAAA,CAA+B,OAAA,EAA8C;AAC3F,EAAA,OAAO,IAAI,8CAAA,CAAyB,oCAAA,EAAkB,OAAO,CAAA;AAC/D;ADCA;AACE;AACF,wEAAC","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/nodeusb.js","sourcesContent":[null,"import { TransportNodeUSB } from '@keystonehq/hw-transport-nodeusb';\n\nimport { KeystoneUsbConnectorBase } from '../KeystoneUsbConnectorBase';\n\nimport type { IConnector } from '@onekeyfe/hwk-adapter-core';\n\nexport function createKeystoneNodeUsbConnector(options?: { timeoutMs?: number }): IConnector {\n return new KeystoneUsbConnectorBase(TransportNodeUSB, options);\n}\n"]}
|
package/dist/nodeusb.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
KeystoneUsbConnectorBase
|
|
3
|
-
} from "./chunk-VMQB3BQI.mjs";
|
|
4
|
-
|
|
5
|
-
// src/_subpath/nodeusb.ts
|
|
6
|
-
import { TransportNodeUSB } from "@keystonehq/hw-transport-nodeusb";
|
|
7
|
-
function createKeystoneNodeUsbConnector(options) {
|
|
8
|
-
return new KeystoneUsbConnectorBase(TransportNodeUSB, options);
|
|
9
|
-
}
|
|
10
|
-
export {
|
|
11
|
-
createKeystoneNodeUsbConnector
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=nodeusb.mjs.map
|
package/dist/nodeusb.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/_subpath/nodeusb.ts"],"sourcesContent":["import { TransportNodeUSB } from '@keystonehq/hw-transport-nodeusb';\n\nimport { KeystoneUsbConnectorBase } from '../KeystoneUsbConnectorBase';\n\nimport type { IConnector } from '@onekeyfe/hwk-adapter-core';\n\nexport function createKeystoneNodeUsbConnector(options?: { timeoutMs?: number }): IConnector {\n return new KeystoneUsbConnectorBase(TransportNodeUSB, options);\n}\n"],"mappings":";;;;;AAAA,SAAS,wBAAwB;AAM1B,SAAS,+BAA+B,SAA8C;AAC3F,SAAO,IAAI,yBAAyB,kBAAkB,OAAO;AAC/D;","names":[]}
|