@onekeyfe/hwk-keystone-connector-usb 1.2.3-alpha.8 → 1.2.5-alpha.0
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-K6NZTBAU.js → chunk-6RNO5GSF.js} +30 -64
- package/dist/chunk-6RNO5GSF.js.map +1 -0
- package/dist/{chunk-U7YVTDVR.mjs → chunk-YGAGPNT5.mjs} +30 -64
- package/dist/chunk-YGAGPNT5.mjs.map +1 -0
- package/dist/index.d.mts +10 -18
- package/dist/index.d.ts +10 -18
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/dist/nodeusb.js +2 -2
- package/dist/nodeusb.mjs +1 -1
- package/dist/webusb.d.mts +1 -5
- package/dist/webusb.d.ts +1 -5
- package/dist/webusb.js +2 -2
- package/dist/webusb.js.map +1 -1
- package/dist/webusb.mjs +1 -1
- package/dist/webusb.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-K6NZTBAU.js.map +0 -1
- package/dist/chunk-U7YVTDVR.mjs.map +0 -1
|
@@ -46,12 +46,21 @@ var CLIENT_STATUS_MAP = {
|
|
|
46
46
|
[_hwtransporterror.Status.ERR_DATA_TOO_LARGE]: _hwkadaptercore.HardwareErrorCode.PayloadTooLarge,
|
|
47
47
|
[_hwtransporterror.Status.ERR_NOT_SUPPORTED]: _hwkadaptercore.HardwareErrorCode.TransportNotAvailable
|
|
48
48
|
};
|
|
49
|
+
var DOM_EXCEPTION_MAP = /* @__PURE__ */ new Map([
|
|
50
|
+
["NotFoundError", { code: _hwkadaptercore.HardwareErrorCode.DeviceNotFound, origin: "transport" }],
|
|
51
|
+
["NetworkError", { code: _hwkadaptercore.HardwareErrorCode.DeviceNotFound, origin: "transport" }],
|
|
52
|
+
["SecurityError", { code: _hwkadaptercore.HardwareErrorCode.DevicePermissionDenied, origin: "host" }],
|
|
53
|
+
["NotAllowedError", { code: _hwkadaptercore.HardwareErrorCode.DevicePermissionDenied, origin: "host" }],
|
|
54
|
+
["InvalidStateError", { code: _hwkadaptercore.HardwareErrorCode.DeviceBusy, origin: "transport" }],
|
|
55
|
+
["AbortError", { code: _hwkadaptercore.HardwareErrorCode.DeviceBusy, origin: "transport" }]
|
|
56
|
+
]);
|
|
49
57
|
function mapKeystoneUsbError(err) {
|
|
50
|
-
const
|
|
51
|
-
|
|
58
|
+
const fields = err && typeof err === "object" ? err : {};
|
|
59
|
+
const domName = typeof fields.name === "string" ? fields.name : void 0;
|
|
60
|
+
if (typeof fields.code === "number" && fields.code >= 1e4 && fields.code <= 99999) {
|
|
52
61
|
return err;
|
|
53
62
|
}
|
|
54
|
-
const statusCode =
|
|
63
|
+
const statusCode = typeof fields.transportErrorCode === "number" ? fields.transportErrorCode : void 0;
|
|
55
64
|
const message = err instanceof Error ? err.message : String(err);
|
|
56
65
|
if (statusCode !== void 0) {
|
|
57
66
|
const fromDevice = isDeviceStatus(statusCode);
|
|
@@ -65,41 +74,16 @@ function mapKeystoneUsbError(err) {
|
|
|
65
74
|
const description = DEVICE_STATUS_MESSAGE[statusCode];
|
|
66
75
|
return _hwkadaptercore.createHwkError.call(void 0, {
|
|
67
76
|
code,
|
|
68
|
-
// The device's own payload text wins
|
|
69
|
-
// where the transport had nothing to forward.
|
|
77
|
+
// The device's own payload text wins over the table.
|
|
70
78
|
message: description && PLACEHOLDER_MESSAGE.test(message) ? `${description} (error_code: ${statusCode})` : message,
|
|
71
|
-
// A
|
|
72
|
-
// status codes came from the framing/pipe layer — EXCEPT the timeout,
|
|
73
|
-
// which is genuinely two-faced (the device may be sitting on a confirm
|
|
74
|
-
// screen waiting for a human, or the pipe may be dead) and stays
|
|
75
|
-
// unlabeled rather than mislabeled.
|
|
79
|
+
// A timeout may be either side, so it stays unlabeled.
|
|
76
80
|
origin,
|
|
77
81
|
params: { statusCode, details: err.details }
|
|
78
82
|
});
|
|
79
83
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
message,
|
|
84
|
-
origin: "transport",
|
|
85
|
-
params: { domExceptionName: domName }
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
if (domName === "SecurityError" || domName === "NotAllowedError") {
|
|
89
|
-
return _hwkadaptercore.createHwkError.call(void 0, {
|
|
90
|
-
code: _hwkadaptercore.HardwareErrorCode.DevicePermissionDenied,
|
|
91
|
-
message,
|
|
92
|
-
origin: "host",
|
|
93
|
-
params: { domExceptionName: domName }
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
if (domName === "InvalidStateError" || domName === "AbortError") {
|
|
97
|
-
return _hwkadaptercore.createHwkError.call(void 0, {
|
|
98
|
-
code: _hwkadaptercore.HardwareErrorCode.DeviceBusy,
|
|
99
|
-
message,
|
|
100
|
-
origin: "transport",
|
|
101
|
-
params: { domExceptionName: domName }
|
|
102
|
-
});
|
|
84
|
+
const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : void 0;
|
|
85
|
+
if (domMapping) {
|
|
86
|
+
return _hwkadaptercore.createHwkError.call(void 0, { ...domMapping, message, params: { domExceptionName: domName } });
|
|
103
87
|
}
|
|
104
88
|
return _hwkadaptercore.createHwkError.call(void 0, { code: _hwkadaptercore.HardwareErrorCode.TransportError, message, origin: "transport" });
|
|
105
89
|
}
|
|
@@ -154,11 +138,10 @@ var KeystoneUsbConnectorBase = class {
|
|
|
154
138
|
this.sessions = /* @__PURE__ */ new Map();
|
|
155
139
|
this.discoveredDevices = /* @__PURE__ */ new Map();
|
|
156
140
|
this.availabilityDevices = /* @__PURE__ */ new Map();
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
/** Wallets that already approved a public-data export, keyed by master fingerprint. */
|
|
141
|
+
/**
|
|
142
|
+
* Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can
|
|
143
|
+
* re-enumerate between exports, and that must not re-prompt.
|
|
144
|
+
*/
|
|
162
145
|
this.publicDataConfirmedWallets = /* @__PURE__ */ new Set();
|
|
163
146
|
this.transportClass = transportClass;
|
|
164
147
|
this.timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.timeoutMs]), () => ( DEFAULT_TIMEOUT_MS));
|
|
@@ -205,10 +188,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
205
188
|
connectionType: "usb",
|
|
206
189
|
serialNumber: device.serialNumber,
|
|
207
190
|
capabilities: { persistentDeviceIdentity: false },
|
|
208
|
-
//
|
|
209
|
-
// or defaulted: a missing key means the device published no such string
|
|
210
|
-
// descriptor. Promote a field onto the typed surface above once
|
|
211
|
-
// something actually consumes it.
|
|
191
|
+
// Verbatim descriptor fields; a missing key means the device did not publish it.
|
|
212
192
|
raw: {
|
|
213
193
|
serialNumber: device.serialNumber,
|
|
214
194
|
productName: device.productName,
|
|
@@ -346,12 +326,6 @@ var KeystoneUsbConnectorBase = class {
|
|
|
346
326
|
openedTransport = await this._openTransport(selectedDevice);
|
|
347
327
|
config = await this._readAppConfig(openedTransport.transport);
|
|
348
328
|
}
|
|
349
|
-
if (!openedTransport) {
|
|
350
|
-
throw _hwkadaptercore.createHwkError.call(void 0, {
|
|
351
|
-
code: _hwkadaptercore.HardwareErrorCode.DeviceNotFound,
|
|
352
|
-
message: "Keystone USB transport was not opened"
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
329
|
const activeOpenedTransport = openedTransport;
|
|
356
330
|
const { transport } = activeOpenedTransport;
|
|
357
331
|
if (expectedMasterFingerprint && config.mfp && config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()) {
|
|
@@ -499,10 +473,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
499
473
|
);
|
|
500
474
|
return _hwkadaptercore.success.call(void 0, { locked: response.payload });
|
|
501
475
|
}
|
|
502
|
-
case "getAppConfig":
|
|
503
|
-
|
|
504
|
-
return _hwkadaptercore.success.call(void 0, config);
|
|
505
|
-
}
|
|
476
|
+
case "getAppConfig":
|
|
477
|
+
return _hwkadaptercore.success.call(void 0, await this._readAppConfig(session.transport));
|
|
506
478
|
default:
|
|
507
479
|
return {
|
|
508
480
|
success: false,
|
|
@@ -518,15 +490,12 @@ var KeystoneUsbConnectorBase = class {
|
|
|
518
490
|
return { success: false, error: _hwkadaptercore.serializeConnectorError.call(void 0, mapKeystoneUsbError(err)) };
|
|
519
491
|
}
|
|
520
492
|
}
|
|
521
|
-
//
|
|
522
|
-
//
|
|
523
|
-
// best this connector can do is stop waiting on its side; the underlying
|
|
524
|
-
// `send()` promise still settles (or times out) on its own.
|
|
493
|
+
// The SDK cannot interrupt an in-flight transfer; the pending send() settles or
|
|
494
|
+
// times out on its own.
|
|
525
495
|
cancel(_sessionId) {
|
|
526
496
|
return Promise.resolve();
|
|
527
497
|
}
|
|
528
|
-
//
|
|
529
|
-
// happens on the device's own touchscreen — so there is nothing to answer.
|
|
498
|
+
// PIN/passphrase entry happens on the device touchscreen, never via the host.
|
|
530
499
|
uiResponse(_response) {
|
|
531
500
|
}
|
|
532
501
|
on(event, handler) {
|
|
@@ -565,11 +534,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
565
534
|
_toDeviceInfo(device, firmwareVersion, masterFingerprint) {
|
|
566
535
|
return {
|
|
567
536
|
vendor: "keystone",
|
|
568
|
-
//
|
|
569
|
-
//
|
|
570
|
-
// Empty rather than a literal 'unknown' when it says nothing, so the
|
|
571
|
-
// host's own default-name fallback can win instead of a fake model
|
|
572
|
-
// reaching the UI and the persisted device settings.
|
|
537
|
+
// Model is the USB `productName`; empty, not 'unknown', so the host's
|
|
538
|
+
// default-name fallback wins.
|
|
573
539
|
model: _nullishCoalesce(device.model, () => ( "")),
|
|
574
540
|
modelName: device.modelName,
|
|
575
541
|
firmwareVersion: _nullishCoalesce(firmwareVersion, () => ( "0.0.0")),
|
|
@@ -587,4 +553,4 @@ var KeystoneUsbConnectorBase = class {
|
|
|
587
553
|
|
|
588
554
|
|
|
589
555
|
exports.mapKeystoneUsbError = mapKeystoneUsbError; exports.KeystoneUsbConnectorBase = KeystoneUsbConnectorBase;
|
|
590
|
-
//# sourceMappingURL=chunk-
|
|
556
|
+
//# sourceMappingURL=chunk-6RNO5GSF.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-6RNO5GSF.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-6RNO5GSF.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 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 (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"]}
|
|
@@ -46,12 +46,21 @@ var CLIENT_STATUS_MAP = {
|
|
|
46
46
|
[Status.ERR_DATA_TOO_LARGE]: HardwareErrorCode.PayloadTooLarge,
|
|
47
47
|
[Status.ERR_NOT_SUPPORTED]: HardwareErrorCode.TransportNotAvailable
|
|
48
48
|
};
|
|
49
|
+
var DOM_EXCEPTION_MAP = /* @__PURE__ */ new Map([
|
|
50
|
+
["NotFoundError", { code: HardwareErrorCode.DeviceNotFound, origin: "transport" }],
|
|
51
|
+
["NetworkError", { code: HardwareErrorCode.DeviceNotFound, origin: "transport" }],
|
|
52
|
+
["SecurityError", { code: HardwareErrorCode.DevicePermissionDenied, origin: "host" }],
|
|
53
|
+
["NotAllowedError", { code: HardwareErrorCode.DevicePermissionDenied, origin: "host" }],
|
|
54
|
+
["InvalidStateError", { code: HardwareErrorCode.DeviceBusy, origin: "transport" }],
|
|
55
|
+
["AbortError", { code: HardwareErrorCode.DeviceBusy, origin: "transport" }]
|
|
56
|
+
]);
|
|
49
57
|
function mapKeystoneUsbError(err) {
|
|
50
|
-
const
|
|
51
|
-
|
|
58
|
+
const fields = err && typeof err === "object" ? err : {};
|
|
59
|
+
const domName = typeof fields.name === "string" ? fields.name : void 0;
|
|
60
|
+
if (typeof fields.code === "number" && fields.code >= 1e4 && fields.code <= 99999) {
|
|
52
61
|
return err;
|
|
53
62
|
}
|
|
54
|
-
const statusCode =
|
|
63
|
+
const statusCode = typeof fields.transportErrorCode === "number" ? fields.transportErrorCode : void 0;
|
|
55
64
|
const message = err instanceof Error ? err.message : String(err);
|
|
56
65
|
if (statusCode !== void 0) {
|
|
57
66
|
const fromDevice = isDeviceStatus(statusCode);
|
|
@@ -65,41 +74,16 @@ function mapKeystoneUsbError(err) {
|
|
|
65
74
|
const description = DEVICE_STATUS_MESSAGE[statusCode];
|
|
66
75
|
return createHwkError({
|
|
67
76
|
code,
|
|
68
|
-
// The device's own payload text wins
|
|
69
|
-
// where the transport had nothing to forward.
|
|
77
|
+
// The device's own payload text wins over the table.
|
|
70
78
|
message: description && PLACEHOLDER_MESSAGE.test(message) ? `${description} (error_code: ${statusCode})` : message,
|
|
71
|
-
// A
|
|
72
|
-
// status codes came from the framing/pipe layer — EXCEPT the timeout,
|
|
73
|
-
// which is genuinely two-faced (the device may be sitting on a confirm
|
|
74
|
-
// screen waiting for a human, or the pipe may be dead) and stays
|
|
75
|
-
// unlabeled rather than mislabeled.
|
|
79
|
+
// A timeout may be either side, so it stays unlabeled.
|
|
76
80
|
origin,
|
|
77
81
|
params: { statusCode, details: err.details }
|
|
78
82
|
});
|
|
79
83
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
message,
|
|
84
|
-
origin: "transport",
|
|
85
|
-
params: { domExceptionName: domName }
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
if (domName === "SecurityError" || domName === "NotAllowedError") {
|
|
89
|
-
return createHwkError({
|
|
90
|
-
code: HardwareErrorCode.DevicePermissionDenied,
|
|
91
|
-
message,
|
|
92
|
-
origin: "host",
|
|
93
|
-
params: { domExceptionName: domName }
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
if (domName === "InvalidStateError" || domName === "AbortError") {
|
|
97
|
-
return createHwkError({
|
|
98
|
-
code: HardwareErrorCode.DeviceBusy,
|
|
99
|
-
message,
|
|
100
|
-
origin: "transport",
|
|
101
|
-
params: { domExceptionName: domName }
|
|
102
|
-
});
|
|
84
|
+
const domMapping = domName ? DOM_EXCEPTION_MAP.get(domName) : void 0;
|
|
85
|
+
if (domMapping) {
|
|
86
|
+
return createHwkError({ ...domMapping, message, params: { domExceptionName: domName } });
|
|
103
87
|
}
|
|
104
88
|
return createHwkError({ code: HardwareErrorCode.TransportError, message, origin: "transport" });
|
|
105
89
|
}
|
|
@@ -154,11 +138,10 @@ var KeystoneUsbConnectorBase = class {
|
|
|
154
138
|
this.sessions = /* @__PURE__ */ new Map();
|
|
155
139
|
this.discoveredDevices = /* @__PURE__ */ new Map();
|
|
156
140
|
this.availabilityDevices = /* @__PURE__ */ new Map();
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
/** Wallets that already approved a public-data export, keyed by master fingerprint. */
|
|
141
|
+
/**
|
|
142
|
+
* Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can
|
|
143
|
+
* re-enumerate between exports, and that must not re-prompt.
|
|
144
|
+
*/
|
|
162
145
|
this.publicDataConfirmedWallets = /* @__PURE__ */ new Set();
|
|
163
146
|
this.transportClass = transportClass;
|
|
164
147
|
this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -205,10 +188,7 @@ var KeystoneUsbConnectorBase = class {
|
|
|
205
188
|
connectionType: "usb",
|
|
206
189
|
serialNumber: device.serialNumber,
|
|
207
190
|
capabilities: { persistentDeviceIdentity: false },
|
|
208
|
-
//
|
|
209
|
-
// or defaulted: a missing key means the device published no such string
|
|
210
|
-
// descriptor. Promote a field onto the typed surface above once
|
|
211
|
-
// something actually consumes it.
|
|
191
|
+
// Verbatim descriptor fields; a missing key means the device did not publish it.
|
|
212
192
|
raw: {
|
|
213
193
|
serialNumber: device.serialNumber,
|
|
214
194
|
productName: device.productName,
|
|
@@ -346,12 +326,6 @@ var KeystoneUsbConnectorBase = class {
|
|
|
346
326
|
openedTransport = await this._openTransport(selectedDevice);
|
|
347
327
|
config = await this._readAppConfig(openedTransport.transport);
|
|
348
328
|
}
|
|
349
|
-
if (!openedTransport) {
|
|
350
|
-
throw createHwkError2({
|
|
351
|
-
code: HardwareErrorCode2.DeviceNotFound,
|
|
352
|
-
message: "Keystone USB transport was not opened"
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
329
|
const activeOpenedTransport = openedTransport;
|
|
356
330
|
const { transport } = activeOpenedTransport;
|
|
357
331
|
if (expectedMasterFingerprint && config.mfp && config.mfp.toLowerCase() !== expectedMasterFingerprint.toLowerCase()) {
|
|
@@ -499,10 +473,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
499
473
|
);
|
|
500
474
|
return success({ locked: response.payload });
|
|
501
475
|
}
|
|
502
|
-
case "getAppConfig":
|
|
503
|
-
|
|
504
|
-
return success(config);
|
|
505
|
-
}
|
|
476
|
+
case "getAppConfig":
|
|
477
|
+
return success(await this._readAppConfig(session.transport));
|
|
506
478
|
default:
|
|
507
479
|
return {
|
|
508
480
|
success: false,
|
|
@@ -518,15 +490,12 @@ var KeystoneUsbConnectorBase = class {
|
|
|
518
490
|
return { success: false, error: serializeConnectorError(mapKeystoneUsbError(err)) };
|
|
519
491
|
}
|
|
520
492
|
}
|
|
521
|
-
//
|
|
522
|
-
//
|
|
523
|
-
// best this connector can do is stop waiting on its side; the underlying
|
|
524
|
-
// `send()` promise still settles (or times out) on its own.
|
|
493
|
+
// The SDK cannot interrupt an in-flight transfer; the pending send() settles or
|
|
494
|
+
// times out on its own.
|
|
525
495
|
cancel(_sessionId) {
|
|
526
496
|
return Promise.resolve();
|
|
527
497
|
}
|
|
528
|
-
//
|
|
529
|
-
// happens on the device's own touchscreen — so there is nothing to answer.
|
|
498
|
+
// PIN/passphrase entry happens on the device touchscreen, never via the host.
|
|
530
499
|
uiResponse(_response) {
|
|
531
500
|
}
|
|
532
501
|
on(event, handler) {
|
|
@@ -565,11 +534,8 @@ var KeystoneUsbConnectorBase = class {
|
|
|
565
534
|
_toDeviceInfo(device, firmwareVersion, masterFingerprint) {
|
|
566
535
|
return {
|
|
567
536
|
vendor: "keystone",
|
|
568
|
-
//
|
|
569
|
-
//
|
|
570
|
-
// Empty rather than a literal 'unknown' when it says nothing, so the
|
|
571
|
-
// host's own default-name fallback can win instead of a fake model
|
|
572
|
-
// reaching the UI and the persisted device settings.
|
|
537
|
+
// Model is the USB `productName`; empty, not 'unknown', so the host's
|
|
538
|
+
// default-name fallback wins.
|
|
573
539
|
model: device.model ?? "",
|
|
574
540
|
modelName: device.modelName,
|
|
575
541
|
firmwareVersion: firmwareVersion ?? "0.0.0",
|
|
@@ -587,4 +553,4 @@ export {
|
|
|
587
553
|
mapKeystoneUsbError,
|
|
588
554
|
KeystoneUsbConnectorBase
|
|
589
555
|
};
|
|
590
|
-
//# sourceMappingURL=chunk-
|
|
556
|
+
//# sourceMappingURL=chunk-YGAGPNT5.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 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 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 (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/index.d.mts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { IConnector, ConnectorSearchDevicesOptions, ConnectorDevice, ConnectorSession, ConnectorConnectTarget, ConnectorCallResult, UiResponseEvent, ConnectorEventType, ConnectorEventMap, HwkError } from '@onekeyfe/hwk-adapter-core';
|
|
2
2
|
import { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Static surface shared by `TransportWebUSB` and `TransportNodeUSB`; the
|
|
6
|
-
* platform-specific transport is injected by `_subpath/*`.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* What enumeration can see before the device is opened. WebUSB hands back a
|
|
10
|
-
* `USBDevice`; node-usb's wrapper exposes the same descriptor strings. Every
|
|
11
|
-
* field is optional because a device may simply not publish that string
|
|
12
|
-
* descriptor — read defensively, never assume presence.
|
|
13
|
-
*/
|
|
4
|
+
/** Descriptor fields readable before opening; any may be absent if not published. */
|
|
14
5
|
interface KeystoneUsbDeviceDescriptor {
|
|
15
6
|
serialNumber?: string;
|
|
16
7
|
productName?: string;
|
|
@@ -28,6 +19,7 @@ interface KeystoneUsbDeviceDescriptor {
|
|
|
28
19
|
deviceSubclass?: number;
|
|
29
20
|
deviceProtocol?: number;
|
|
30
21
|
}
|
|
22
|
+
/** Static surface of `TransportWebUSB`/`TransportNodeUSB`, injected by `_subpath/*`. */
|
|
31
23
|
interface KeystoneUsbTransportStatic {
|
|
32
24
|
connect(config?: TransportConfig): Promise<TransportHID>;
|
|
33
25
|
connectDevice?(device: KeystoneUsbDeviceDescriptor, config?: TransportConfig): Promise<TransportHID>;
|
|
@@ -38,9 +30,8 @@ interface KeystoneUsbTransportStatic {
|
|
|
38
30
|
disposeTransport?(transport: TransportHID): void;
|
|
39
31
|
}
|
|
40
32
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* object. `resolveUr` carries the same UR payloads as the QR channel.
|
|
33
|
+
* Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so
|
|
34
|
+
* `connect()` only caches the transport object.
|
|
44
35
|
*/
|
|
45
36
|
declare class KeystoneUsbConnectorBase implements IConnector {
|
|
46
37
|
readonly connectionType: "usb";
|
|
@@ -52,7 +43,10 @@ declare class KeystoneUsbConnectorBase implements IConnector {
|
|
|
52
43
|
private readonly availabilityDevices;
|
|
53
44
|
private activeDiscoveryGeneration;
|
|
54
45
|
private activeAvailabilityGeneration;
|
|
55
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can
|
|
48
|
+
* re-enumerate between exports, and that must not re-prompt.
|
|
49
|
+
*/
|
|
56
50
|
private readonly publicDataConfirmedWallets;
|
|
57
51
|
constructor(transportClass: KeystoneUsbTransportStatic, options?: {
|
|
58
52
|
timeoutMs?: number;
|
|
@@ -79,10 +73,8 @@ declare class KeystoneUsbConnectorBase implements IConnector {
|
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
/**
|
|
82
|
-
* Maps a Keystone USB SDK failure to `HardwareErrorCode`.
|
|
83
|
-
*
|
|
84
|
-
* duck-typed because duplicate `@keystonehq/*` module instances break
|
|
85
|
-
* `instanceof`.
|
|
76
|
+
* Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because
|
|
77
|
+
* duplicate `@keystonehq/*` module instances break `instanceof`.
|
|
86
78
|
*/
|
|
87
79
|
declare function mapKeystoneUsbError(err: unknown): HwkError;
|
|
88
80
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { IConnector, ConnectorSearchDevicesOptions, ConnectorDevice, ConnectorSession, ConnectorConnectTarget, ConnectorCallResult, UiResponseEvent, ConnectorEventType, ConnectorEventMap, HwkError } from '@onekeyfe/hwk-adapter-core';
|
|
2
2
|
import { TransportConfig, TransportHID } from '@keystonehq/hw-transport-usb';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Static surface shared by `TransportWebUSB` and `TransportNodeUSB`; the
|
|
6
|
-
* platform-specific transport is injected by `_subpath/*`.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* What enumeration can see before the device is opened. WebUSB hands back a
|
|
10
|
-
* `USBDevice`; node-usb's wrapper exposes the same descriptor strings. Every
|
|
11
|
-
* field is optional because a device may simply not publish that string
|
|
12
|
-
* descriptor — read defensively, never assume presence.
|
|
13
|
-
*/
|
|
4
|
+
/** Descriptor fields readable before opening; any may be absent if not published. */
|
|
14
5
|
interface KeystoneUsbDeviceDescriptor {
|
|
15
6
|
serialNumber?: string;
|
|
16
7
|
productName?: string;
|
|
@@ -28,6 +19,7 @@ interface KeystoneUsbDeviceDescriptor {
|
|
|
28
19
|
deviceSubclass?: number;
|
|
29
20
|
deviceProtocol?: number;
|
|
30
21
|
}
|
|
22
|
+
/** Static surface of `TransportWebUSB`/`TransportNodeUSB`, injected by `_subpath/*`. */
|
|
31
23
|
interface KeystoneUsbTransportStatic {
|
|
32
24
|
connect(config?: TransportConfig): Promise<TransportHID>;
|
|
33
25
|
connectDevice?(device: KeystoneUsbDeviceDescriptor, config?: TransportConfig): Promise<TransportHID>;
|
|
@@ -38,9 +30,8 @@ interface KeystoneUsbTransportStatic {
|
|
|
38
30
|
disposeTransport?(transport: TransportHID): void;
|
|
39
31
|
}
|
|
40
32
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* object. `resolveUr` carries the same UR payloads as the QR channel.
|
|
33
|
+
* Keystone USB `IConnector`. Each transport call is its own open/claim/transfer/close cycle, so
|
|
34
|
+
* `connect()` only caches the transport object.
|
|
44
35
|
*/
|
|
45
36
|
declare class KeystoneUsbConnectorBase implements IConnector {
|
|
46
37
|
readonly connectionType: "usb";
|
|
@@ -52,7 +43,10 @@ declare class KeystoneUsbConnectorBase implements IConnector {
|
|
|
52
43
|
private readonly availabilityDevices;
|
|
53
44
|
private activeDiscoveryGeneration;
|
|
54
45
|
private activeAvailabilityGeneration;
|
|
55
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Wallets (by mfp) that approved a public-data export. Connector-scoped because the device can
|
|
48
|
+
* re-enumerate between exports, and that must not re-prompt.
|
|
49
|
+
*/
|
|
56
50
|
private readonly publicDataConfirmedWallets;
|
|
57
51
|
constructor(transportClass: KeystoneUsbTransportStatic, options?: {
|
|
58
52
|
timeoutMs?: number;
|
|
@@ -79,10 +73,8 @@ declare class KeystoneUsbConnectorBase implements IConnector {
|
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
/**
|
|
82
|
-
* Maps a Keystone USB SDK failure to `HardwareErrorCode`.
|
|
83
|
-
*
|
|
84
|
-
* duck-typed because duplicate `@keystonehq/*` module instances break
|
|
85
|
-
* `instanceof`.
|
|
76
|
+
* Maps a Keystone USB SDK failure to `HardwareErrorCode`. Fields are read duck-typed because
|
|
77
|
+
* duplicate `@keystonehq/*` module instances break `instanceof`.
|
|
86
78
|
*/
|
|
87
79
|
declare function mapKeystoneUsbError(err: unknown): HwkError;
|
|
88
80
|
|
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 _chunk6RNO5GSFjs = require('./chunk-6RNO5GSF.js');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
exports.KeystoneUsbConnectorBase =
|
|
8
|
+
exports.KeystoneUsbConnectorBase = _chunk6RNO5GSFjs.KeystoneUsbConnectorBase; exports.mapKeystoneUsbError = _chunk6RNO5GSFjs.mapKeystoneUsbError;
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
package/dist/nodeusb.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunk6RNO5GSFjs = require('./chunk-6RNO5GSF.js');
|
|
4
4
|
|
|
5
5
|
// src/_subpath/nodeusb.ts
|
|
6
6
|
var _hwtransportnodeusb = require('@keystonehq/hw-transport-nodeusb');
|
|
7
7
|
function createKeystoneNodeUsbConnector(options) {
|
|
8
|
-
return new (0,
|
|
8
|
+
return new (0, _chunk6RNO5GSFjs.KeystoneUsbConnectorBase)(_hwtransportnodeusb.TransportNodeUSB, options);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
|
package/dist/nodeusb.mjs
CHANGED
package/dist/webusb.d.mts
CHANGED
|
@@ -3,11 +3,7 @@ import { IConnector } from '@onekeyfe/hwk-adapter-core';
|
|
|
3
3
|
declare function createKeystoneWebUsbConnector(options?: {
|
|
4
4
|
timeoutMs?: number;
|
|
5
5
|
}): IConnector;
|
|
6
|
-
/**
|
|
7
|
-
* Triggers the browser's WebUSB device picker. Must be called from a
|
|
8
|
-
* user-gesture handler (e.g. directly inside a button's `onclick`) — same
|
|
9
|
-
* requirement as any other WebUSB permission request.
|
|
10
|
-
*/
|
|
6
|
+
/** Opens the WebUSB device picker; must be called from a user-gesture handler. */
|
|
11
7
|
declare function requestKeystoneUsbPermission(): Promise<void>;
|
|
12
8
|
|
|
13
9
|
export { createKeystoneWebUsbConnector, requestKeystoneUsbPermission };
|
package/dist/webusb.d.ts
CHANGED
|
@@ -3,11 +3,7 @@ import { IConnector } from '@onekeyfe/hwk-adapter-core';
|
|
|
3
3
|
declare function createKeystoneWebUsbConnector(options?: {
|
|
4
4
|
timeoutMs?: number;
|
|
5
5
|
}): IConnector;
|
|
6
|
-
/**
|
|
7
|
-
* Triggers the browser's WebUSB device picker. Must be called from a
|
|
8
|
-
* user-gesture handler (e.g. directly inside a button's `onclick`) — same
|
|
9
|
-
* requirement as any other WebUSB permission request.
|
|
10
|
-
*/
|
|
6
|
+
/** Opens the WebUSB device picker; must be called from a user-gesture handler. */
|
|
11
7
|
declare function requestKeystoneUsbPermission(): Promise<void>;
|
|
12
8
|
|
|
13
9
|
export { createKeystoneWebUsbConnector, requestKeystoneUsbPermission };
|
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 _chunk6RNO5GSFjs = require('./chunk-6RNO5GSF.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, _chunk6RNO5GSFjs.KeystoneUsbConnectorBase)(
|
|
29
29
|
{
|
|
30
30
|
connect: async (config) => {
|
|
31
31
|
await _hwtransportwebusb.TransportWebUSB.isSupported();
|
package/dist/webusb.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/webusb.js","../src/_subpath/webusb.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACA;ACJA,oEAAgC;AAMzB,SAAS,6BAAA,CAA8B,OAAA,EAA8C;AAC1F,EAAA,MAAM,qCAAA,kBAAuC,IAAI,OAAA,CAA4B,CAAA;AAC7E,EAAA,MAAM,mBAAA,EAAqB,CACzB,MAAA,EACA,MAAA,EAAA,GACG;AACH,IAAA,MAAM,UAAA,EAAY,IAAI,uCAAA,CAAgB,MAAA,EAAQ,MAAM,CAAA;AACpD,IAAA,IAAI,iBAAA,EAAmB,IAAA;AACvB,IAAA,SAAS,YAAA,CAAa,KAAA,EAA2B;AAC/C,MAAA,GAAA,CAAI,KAAA,CAAM,OAAA,IAAW,MAAA,EAAQ,MAAA;AAC7B,MAAA,OAAA,CAAQ,CAAA;AACR,sBAAA,MAAA,2BAAQ,kBAAA,0BAAA,CAAqB,MAAM,GAAA;AACnC,MAAA,SAAA,CAAU,KAAA,CAAM,CAAA,CAAE,KAAA,CAAM,CAAA,EAAA,GAAM,KAAA,CAAS,CAAA;AAAA,IACzC;AACA,IAAA,MAAM,QAAA,EAAU,CAAA,EAAA,GAAM;AACpB,MAAA,GAAA,CAAI,CAAC,gBAAA,EAAkB,MAAA;AACvB,MAAA,iBAAA,EAAmB,KAAA;AACnB,MAAA,SAAA,CAAU,GAAA,CAAI,mBAAA,CAAoB,YAAA,EAAc,YAAY,CAAA;AAC5D,MAAA,oCAAA,CAAqC,MAAA,CAAO,SAAS,CAAA;AAAA,IACvD,CAAA;AACA,IAAA,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,YAAY,CAAA;AACzD,IAAA,oCAAA,CAAqC,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA;AAC3D,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AACA,EAAA,OAAO,IAAI,8CAAA;AAAA,IACT;AAAA,MACE,OAAA,EAAS,MAAA,CAAM,MAAA,EAAA,GAAU;AACvB,QAAA,MAAM,kCAAA,CAAgB,WAAA,CAAY,CAAA;AAClC,QAAA,MAAM,QAAA,EAAU,MAAM,kCAAA,CAAgB,kBAAA,CAAmB,CAAA;AACzD,QAAA,GAAA,CAAI,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG;AACxB,UAAA,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA;AAAA,QAC/E;AACA,QAAA,OAAO,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,EAAG,MAAM,CAAA;AAAA,MAC9C,CAAA;AAAA,MACA,aAAA,EAAe,CAAC,MAAA,EAAQ,MAAA,EAAA,GACtB,OAAA,CAAQ,OAAA,CAAQ,kBAAA,CAAmB,MAAA,EAAqB,MAAM,CAAC,CAAA;AAAA,MACjE,gBAAA,EAAkB,CAAA,SAAA,EAAA,GAAa;AAC7B,wBAAA,oCAAA,qBAAqC,GAAA,mBAAI,SAAmB,CAAA,0BAAA,CAAI,GAAA;AAAA,MAClE,CAAA;AAAA,MACA,kBAAA,EAAoB,CAAA,EAAA,GAAM,kCAAA,CAAgB,kBAAA,CAAmB,CAAA;AAAA,MAC7D,iBAAA,EAAmB,CAAA,EAAA,GAAM,kCAAA,CAAgB,iBAAA,CAAkB,CAAA;AAAA,MAC3D,WAAA,EAAa,CAAA,EAAA,GAAM,kCAAA,CAAgB,WAAA,CAAY;AAAA,IACjD,CAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/webusb.js","../src/_subpath/webusb.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACA;ACJA,oEAAgC;AAMzB,SAAS,6BAAA,CAA8B,OAAA,EAA8C;AAC1F,EAAA,MAAM,qCAAA,kBAAuC,IAAI,OAAA,CAA4B,CAAA;AAC7E,EAAA,MAAM,mBAAA,EAAqB,CACzB,MAAA,EACA,MAAA,EAAA,GACG;AACH,IAAA,MAAM,UAAA,EAAY,IAAI,uCAAA,CAAgB,MAAA,EAAQ,MAAM,CAAA;AACpD,IAAA,IAAI,iBAAA,EAAmB,IAAA;AACvB,IAAA,SAAS,YAAA,CAAa,KAAA,EAA2B;AAC/C,MAAA,GAAA,CAAI,KAAA,CAAM,OAAA,IAAW,MAAA,EAAQ,MAAA;AAC7B,MAAA,OAAA,CAAQ,CAAA;AACR,sBAAA,MAAA,2BAAQ,kBAAA,0BAAA,CAAqB,MAAM,GAAA;AACnC,MAAA,SAAA,CAAU,KAAA,CAAM,CAAA,CAAE,KAAA,CAAM,CAAA,EAAA,GAAM,KAAA,CAAS,CAAA;AAAA,IACzC;AACA,IAAA,MAAM,QAAA,EAAU,CAAA,EAAA,GAAM;AACpB,MAAA,GAAA,CAAI,CAAC,gBAAA,EAAkB,MAAA;AACvB,MAAA,iBAAA,EAAmB,KAAA;AACnB,MAAA,SAAA,CAAU,GAAA,CAAI,mBAAA,CAAoB,YAAA,EAAc,YAAY,CAAA;AAC5D,MAAA,oCAAA,CAAqC,MAAA,CAAO,SAAS,CAAA;AAAA,IACvD,CAAA;AACA,IAAA,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,YAAA,EAAc,YAAY,CAAA;AACzD,IAAA,oCAAA,CAAqC,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA;AAC3D,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AACA,EAAA,OAAO,IAAI,8CAAA;AAAA,IACT;AAAA,MACE,OAAA,EAAS,MAAA,CAAM,MAAA,EAAA,GAAU;AACvB,QAAA,MAAM,kCAAA,CAAgB,WAAA,CAAY,CAAA;AAClC,QAAA,MAAM,QAAA,EAAU,MAAM,kCAAA,CAAgB,kBAAA,CAAmB,CAAA;AACzD,QAAA,GAAA,CAAI,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG;AACxB,UAAA,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA;AAAA,QAC/E;AACA,QAAA,OAAO,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,EAAG,MAAM,CAAA;AAAA,MAC9C,CAAA;AAAA,MACA,aAAA,EAAe,CAAC,MAAA,EAAQ,MAAA,EAAA,GACtB,OAAA,CAAQ,OAAA,CAAQ,kBAAA,CAAmB,MAAA,EAAqB,MAAM,CAAC,CAAA;AAAA,MACjE,gBAAA,EAAkB,CAAA,SAAA,EAAA,GAAa;AAC7B,wBAAA,oCAAA,qBAAqC,GAAA,mBAAI,SAAmB,CAAA,0BAAA,CAAI,GAAA;AAAA,MAClE,CAAA;AAAA,MACA,kBAAA,EAAoB,CAAA,EAAA,GAAM,kCAAA,CAAgB,kBAAA,CAAmB,CAAA;AAAA,MAC7D,iBAAA,EAAmB,CAAA,EAAA,GAAM,kCAAA,CAAgB,iBAAA,CAAkB,CAAA;AAAA,MAC3D,WAAA,EAAa,CAAA,EAAA,GAAM,kCAAA,CAAgB,WAAA,CAAY;AAAA,IACjD,CAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAGA,MAAA,SAAsB,4BAAA,CAAA,EAA8C;AAClE,EAAA,MAAM,kCAAA,CAAgB,iBAAA,CAAkB,CAAA;AAC1C;ADLA;AACE;AACA;AACF,2IAAC","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/webusb.js","sourcesContent":[null,"import { TransportWebUSB } from '@keystonehq/hw-transport-webusb';\n\nimport { KeystoneUsbConnectorBase } from '../KeystoneUsbConnectorBase';\n\nimport type { IConnector } from '@onekeyfe/hwk-adapter-core';\n\nexport function createKeystoneWebUsbConnector(options?: { timeoutMs?: number }): IConnector {\n const disconnectListenerCleanupByTransport = new WeakMap<object, () => void>();\n const connectExactDevice = (\n device: USBDevice,\n config?: ConstructorParameters<typeof TransportWebUSB>[1]\n ) => {\n const transport = new TransportWebUSB(device, config);\n let listenerAttached = true;\n function onDisconnect(event: USBConnectionEvent) {\n if (event.device !== device) return;\n cleanup();\n config?.disconnectListener?.(device);\n transport.close().catch(() => undefined);\n }\n const cleanup = () => {\n if (!listenerAttached) return;\n listenerAttached = false;\n navigator.usb.removeEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.delete(transport);\n };\n navigator.usb.addEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.set(transport, cleanup);\n return transport;\n };\n return new KeystoneUsbConnectorBase(\n {\n connect: async config => {\n await TransportWebUSB.isSupported();\n const devices = await TransportWebUSB.getKeystoneDevices();\n if (devices.length !== 1) {\n throw new Error('Keystone WebUSB default connect requires exactly one device');\n }\n return connectExactDevice(devices[0], config);\n },\n connectDevice: (device, config) =>\n Promise.resolve(connectExactDevice(device as USBDevice, config)),\n disposeTransport: transport => {\n disconnectListenerCleanupByTransport.get(transport as object)?.();\n },\n getKeystoneDevices: () => TransportWebUSB.getKeystoneDevices(),\n requestPermission: () => TransportWebUSB.requestPermission(),\n isSupported: () => TransportWebUSB.isSupported(),\n },\n options\n );\n}\n\n/** Opens the WebUSB device picker; must be called from a user-gesture handler. */\nexport async function requestKeystoneUsbPermission(): Promise<void> {\n await TransportWebUSB.requestPermission();\n}\n"]}
|
package/dist/webusb.mjs
CHANGED
package/dist/webusb.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/_subpath/webusb.ts"],"sourcesContent":["import { TransportWebUSB } from '@keystonehq/hw-transport-webusb';\n\nimport { KeystoneUsbConnectorBase } from '../KeystoneUsbConnectorBase';\n\nimport type { IConnector } from '@onekeyfe/hwk-adapter-core';\n\nexport function createKeystoneWebUsbConnector(options?: { timeoutMs?: number }): IConnector {\n const disconnectListenerCleanupByTransport = new WeakMap<object, () => void>();\n const connectExactDevice = (\n device: USBDevice,\n config?: ConstructorParameters<typeof TransportWebUSB>[1]\n ) => {\n const transport = new TransportWebUSB(device, config);\n let listenerAttached = true;\n function onDisconnect(event: USBConnectionEvent) {\n if (event.device !== device) return;\n cleanup();\n config?.disconnectListener?.(device);\n transport.close().catch(() => undefined);\n }\n const cleanup = () => {\n if (!listenerAttached) return;\n listenerAttached = false;\n navigator.usb.removeEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.delete(transport);\n };\n navigator.usb.addEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.set(transport, cleanup);\n return transport;\n };\n return new KeystoneUsbConnectorBase(\n {\n connect: async config => {\n await TransportWebUSB.isSupported();\n const devices = await TransportWebUSB.getKeystoneDevices();\n if (devices.length !== 1) {\n throw new Error('Keystone WebUSB default connect requires exactly one device');\n }\n return connectExactDevice(devices[0], config);\n },\n connectDevice: (device, config) =>\n Promise.resolve(connectExactDevice(device as USBDevice, config)),\n disposeTransport: transport => {\n disconnectListenerCleanupByTransport.get(transport as object)?.();\n },\n getKeystoneDevices: () => TransportWebUSB.getKeystoneDevices(),\n requestPermission: () => TransportWebUSB.requestPermission(),\n isSupported: () => TransportWebUSB.isSupported(),\n },\n options\n );\n}\n\n
|
|
1
|
+
{"version":3,"sources":["../src/_subpath/webusb.ts"],"sourcesContent":["import { TransportWebUSB } from '@keystonehq/hw-transport-webusb';\n\nimport { KeystoneUsbConnectorBase } from '../KeystoneUsbConnectorBase';\n\nimport type { IConnector } from '@onekeyfe/hwk-adapter-core';\n\nexport function createKeystoneWebUsbConnector(options?: { timeoutMs?: number }): IConnector {\n const disconnectListenerCleanupByTransport = new WeakMap<object, () => void>();\n const connectExactDevice = (\n device: USBDevice,\n config?: ConstructorParameters<typeof TransportWebUSB>[1]\n ) => {\n const transport = new TransportWebUSB(device, config);\n let listenerAttached = true;\n function onDisconnect(event: USBConnectionEvent) {\n if (event.device !== device) return;\n cleanup();\n config?.disconnectListener?.(device);\n transport.close().catch(() => undefined);\n }\n const cleanup = () => {\n if (!listenerAttached) return;\n listenerAttached = false;\n navigator.usb.removeEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.delete(transport);\n };\n navigator.usb.addEventListener('disconnect', onDisconnect);\n disconnectListenerCleanupByTransport.set(transport, cleanup);\n return transport;\n };\n return new KeystoneUsbConnectorBase(\n {\n connect: async config => {\n await TransportWebUSB.isSupported();\n const devices = await TransportWebUSB.getKeystoneDevices();\n if (devices.length !== 1) {\n throw new Error('Keystone WebUSB default connect requires exactly one device');\n }\n return connectExactDevice(devices[0], config);\n },\n connectDevice: (device, config) =>\n Promise.resolve(connectExactDevice(device as USBDevice, config)),\n disposeTransport: transport => {\n disconnectListenerCleanupByTransport.get(transport as object)?.();\n },\n getKeystoneDevices: () => TransportWebUSB.getKeystoneDevices(),\n requestPermission: () => TransportWebUSB.requestPermission(),\n isSupported: () => TransportWebUSB.isSupported(),\n },\n options\n );\n}\n\n/** Opens the WebUSB device picker; must be called from a user-gesture handler. */\nexport async function requestKeystoneUsbPermission(): Promise<void> {\n await TransportWebUSB.requestPermission();\n}\n"],"mappings":";;;;;AAAA,SAAS,uBAAuB;AAMzB,SAAS,8BAA8B,SAA8C;AAC1F,QAAM,uCAAuC,oBAAI,QAA4B;AAC7E,QAAM,qBAAqB,CACzB,QACA,WACG;AACH,UAAM,YAAY,IAAI,gBAAgB,QAAQ,MAAM;AACpD,QAAI,mBAAmB;AACvB,aAAS,aAAa,OAA2B;AAC/C,UAAI,MAAM,WAAW,OAAQ;AAC7B,cAAQ;AACR,cAAQ,qBAAqB,MAAM;AACnC,gBAAU,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IACzC;AACA,UAAM,UAAU,MAAM;AACpB,UAAI,CAAC,iBAAkB;AACvB,yBAAmB;AACnB,gBAAU,IAAI,oBAAoB,cAAc,YAAY;AAC5D,2CAAqC,OAAO,SAAS;AAAA,IACvD;AACA,cAAU,IAAI,iBAAiB,cAAc,YAAY;AACzD,yCAAqC,IAAI,WAAW,OAAO;AAC3D,WAAO;AAAA,EACT;AACA,SAAO,IAAI;AAAA,IACT;AAAA,MACE,SAAS,OAAM,WAAU;AACvB,cAAM,gBAAgB,YAAY;AAClC,cAAM,UAAU,MAAM,gBAAgB,mBAAmB;AACzD,YAAI,QAAQ,WAAW,GAAG;AACxB,gBAAM,IAAI,MAAM,6DAA6D;AAAA,QAC/E;AACA,eAAO,mBAAmB,QAAQ,CAAC,GAAG,MAAM;AAAA,MAC9C;AAAA,MACA,eAAe,CAAC,QAAQ,WACtB,QAAQ,QAAQ,mBAAmB,QAAqB,MAAM,CAAC;AAAA,MACjE,kBAAkB,eAAa;AAC7B,6CAAqC,IAAI,SAAmB,IAAI;AAAA,MAClE;AAAA,MACA,oBAAoB,MAAM,gBAAgB,mBAAmB;AAAA,MAC7D,mBAAmB,MAAM,gBAAgB,kBAAkB;AAAA,MAC3D,aAAa,MAAM,gBAAgB,YAAY;AAAA,IACjD;AAAA,IACA;AAAA,EACF;AACF;AAGA,eAAsB,+BAA8C;AAClE,QAAM,gBAAgB,kBAAkB;AAC1C;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hwk-keystone-connector-usb",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5-alpha.0",
|
|
4
4
|
"description": "IConnector implementation for Keystone hardware wallets via USB (WebUSB + Node USB)",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"license": "MIT",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"@keystonehq/hw-transport-usb": "0.2.0",
|
|
70
70
|
"@keystonehq/hw-transport-webusb": "0.5.3",
|
|
71
71
|
"@ngraveio/bc-ur": "1.1.13",
|
|
72
|
-
"@onekeyfe/hwk-adapter-core": "1.2.
|
|
72
|
+
"@onekeyfe/hwk-adapter-core": "1.2.5-alpha.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@keystonehq/bc-ur-registry-eth": "0.22.1",
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"optional": true
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "e21d1c9a0afad287e854e568976ee62550a06b3e"
|
|
90
90
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-K6NZTBAU.js","../src/errors.ts","../src/KeystoneUsbConnectorBase.ts"],"names":["HardwareErrorCode","createHwkError"],"mappings":"AAAA;ACAA,4DAAkD;AAClD,kEAAuB;AAWvB,SAAS,cAAA,CAAe,UAAA,EAA6B;AACnD,EAAA,OAAO,WAAA,GAAc,EAAA,GAAK,WAAA,EAAa,wBAAA,CAAO,qBAAA;AAChD;AAMA,IAAM,kBAAA,EAAgE;AAAA,EACpE,CAAC,wBAAA,CAAO,gBAAgB,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EAC7C,CAAC,wBAAA,CAAO,yBAAyB,CAAA,EAAG,iCAAA,CAAkB,aAAA;AAAA,EACtD,CAAC,wBAAA,CAAO,iBAAiB,CAAA,EAAG,iCAAA,CAAkB,aAAA;AAAA,EAC9C,CAAC,wBAAA,CAAO,oBAAoB,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EACjD,CAAC,wBAAA,CAAO,iBAAiB,CAAA,EAAG,iCAAA,CAAkB,aAAA;AAAA,EAC9C,CAAC,wBAAA,CAAO,sBAAsB,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EACnD,CAAC,wBAAA,CAAO,qBAAqB,CAAA,EAAG,iCAAA,CAAkB,aAAA;AAAA,EAClD,CAAC,wBAAA,CAAO,6BAA6B,CAAA,EAAG,iCAAA,CAAkB,cAAA;AAAA,EAC1D,CAAC,wBAAA,CAAO,iCAAiC,CAAA,EAAG,iCAAA,CAAkB,UAAA;AAAA,EAC9D,CAAC,wBAAA,CAAO,oCAAoC,CAAA,EAAG,iCAAA,CAAkB,iBAAA;AAAA,EACjE,CAAC,wBAAA,CAAO,iCAAiC,CAAA,EAAG,iCAAA,CAAkB,aAAA;AAAA,EAC9D,CAAC,wBAAA,CAAO,wBAAwB,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EACrD,CAAC,wBAAA,CAAO,6BAA6B,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EAC1D,CAAC,wBAAA,CAAO,2BAA2B,CAAA,EAAG,iCAAA,CAAkB,YAAA;AAAA,EACxD,CAAC,wBAAA,CAAO,uBAAuB,CAAA,EAAG,iCAAA,CAAkB;AACtD,CAAA;AAOA,IAAM,sBAAA,EAAyD;AAAA,EAC7D,CAAC,wBAAA,CAAO,gBAAgB,CAAA,EAAG,6BAAA;AAAA,EAC3B,CAAC,wBAAA,CAAO,yBAAyB,CAAA,EAAG,uDAAA;AAAA,EACpC,CAAC,wBAAA,CAAO,iBAAiB,CAAA,EAAG,sDAAA;AAAA,EAC5B,CAAC,wBAAA,CAAO,oBAAoB,CAAA,EAAG,iCAAA;AAAA,EAC/B,CAAC,wBAAA,CAAO,iBAAiB,CAAA,EAAG,sCAAA;AAAA,EAC5B,CAAC,wBAAA,CAAO,sBAAsB,CAAA,EAAG,oDAAA;AAAA,EACjC,CAAC,wBAAA,CAAO,qBAAqB,CAAA,EAAG,2CAAA;AAAA,EAChC,CAAC,wBAAA,CAAO,6BAA6B,CAAA,EAAG,oDAAA;AAAA,EACxC,CAAC,wBAAA,CAAO,iCAAiC,CAAA,EAAG,uCAAA;AAAA,EAC5C,CAAC,wBAAA,CAAO,oCAAoC,CAAA,EAAG,sCAAA;AAAA,EAC/C,CAAC,wBAAA,CAAO,iCAAiC,CAAA,EAAG,iDAAA;AAAA,EAC5C,CAAC,wBAAA,CAAO,wBAAwB,CAAA,EAAG,uCAAA;AAAA,EACnC,CAAC,wBAAA,CAAO,6BAA6B,CAAA,EAAG,yCAAA;AAAA,EACxC,CAAC,wBAAA,CAAO,2BAA2B,CAAA,EAAG,gDAAA;AAAA,EACtC,CAAC,wBAAA,CAAO,uBAAuB,CAAA,EAAG;AACpC,CAAA;AAGA,IAAM,oBAAA,EAAsB,mBAAA;AAG5B,IAAM,kBAAA,EAAgE;AAAA,EACpE,CAAC,wBAAA,CAAO,qBAAqB,CAAA,EAAG,iCAAA,CAAkB,cAAA;AAAA,EAClD,CAAC,wBAAA,CAAO,oBAAoB,CAAA,EAAG,iCAAA,CAAkB,cAAA;AAAA,EACjD,CAAC,wBAAA,CAAO,WAAW,CAAA,EAAG,iCAAA,CAAkB,gBAAA;AAAA,EACxC,CAAC,wBAAA,CAAO,kBAAkB,CAAA,EAAG,iCAAA,CAAkB,eAAA;AAAA,EAC/C,CAAC,wBAAA,CAAO,iBAAiB,CAAA,EAAG,iCAAA,CAAkB;AAChD,CAAA;AAQO,SAAS,mBAAA,CAAoB,GAAA,EAAwB;AAC1D,EAAA,MAAM,QAAA,EACJ,IAAA,GAAO,OAAO,IAAA,IAAQ,SAAA,GAAY,OAAQ,GAAA,CAA2B,KAAA,IAAS,SAAA,EACzE,GAAA,CAAyB,KAAA,EAC1B,KAAA,CAAA;AAMN,EAAA,GAAA,CACE,IAAA,GACA,OAAO,IAAA,IAAQ,SAAA,GACf,OAAQ,GAAA,CAA2B,KAAA,IAAS,SAAA,GAC3C,GAAA,CAAyB,KAAA,GAAQ,IAAA,GACjC,GAAA,CAAyB,KAAA,GAAQ,KAAA,EAClC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,EACJ,IAAA,GACA,OAAO,IAAA,IAAQ,SAAA,GACf,OAAQ,GAAA,CAAyC,mBAAA,IAAuB,SAAA,EACnE,GAAA,CAAuC,mBAAA,EACxC,KAAA,CAAA;AAEN,EAAA,MAAM,QAAA,EAAU,IAAA,WAAe,MAAA,EAAQ,GAAA,CAAI,QAAA,EAAU,MAAA,CAAO,GAAG,CAAA;AAE/D,EAAA,GAAA,CAAI,WAAA,IAAe,KAAA,CAAA,EAAW;AAC5B,IAAA,MAAM,WAAA,EAAa,cAAA,CAAe,UAAU,CAAA;AAM5C,IAAA,MAAM,KAAA,EAAO,WAAA,mBACT,iBAAA,CAAkB,UAAU,CAAA,UAAK,iCAAA,CAAkB,eAAA,mBACnD,iBAAA,CAAkB,UAAU,CAAA,UAAK,iCAAA,CAAkB,gBAAA;AACvD,IAAA,IAAI,MAAA;AACJ,IAAA,GAAA,CAAI,UAAA,EAAY;AACd,MAAA,OAAA,EAAS,QAAA;AAAA,IACX,EAAA,KAAA,GAAA,CAAW,KAAA,IAAS,iCAAA,CAAkB,gBAAA,EAAkB;AACtD,MAAA,OAAA,EAAS,WAAA;AAAA,IACX;AACA,IAAA,MAAM,YAAA,EAAc,qBAAA,CAAsB,UAAU,CAAA;AACpD,IAAA,OAAO,4CAAA;AAAe,MACpB,IAAA;AAAA;AAAA;AAAA,MAGA,OAAA,EACE,YAAA,GAAe,mBAAA,CAAoB,IAAA,CAAK,OAAO,EAAA,EAC3C,CAAA,EAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAMN,MAAA;AACqE,MAAA;AACtE,IAAA;AACH,EAAA;AAM+D,EAAA;AACvC,IAAA;AACI,MAAA;AACxB,MAAA;AACQ,MAAA;AAC4B,MAAA;AACrC,IAAA;AACH,EAAA;AAC+C,EAAA;AACvB,IAAA;AACI,MAAA;AACxB,MAAA;AACQ,MAAA;AAC4B,MAAA;AACrC,IAAA;AACH,EAAA;AACiE,EAAA;AACzC,IAAA;AACI,MAAA;AACxB,MAAA;AACQ,MAAA;AAC4B,MAAA;AACrC,IAAA;AACH,EAAA;AAKgE,EAAA;AAClE;ADvEmE;AACA;AE1G1B;AACjB;AACxB;AACE;AACAA;AACA;AACA;AACA;AACAC;AACA;AACA;AACA;AACA;AACA;AACK;AAmD8D;AAC9B,EAAA;AACvC;AAqC2B;AAEU;AAEQ;AACmB,EAAA;AAGhE;AAEqD;AAIS,EAAA;AACd,EAAA;AAChB,EAAA;AACJ,EAAA;AACA,IAAA;AACE,IAAA;AAC5B,EAAA;AACiE,EAAA;AAGtC,IAAA;AAEJ,IAAA;AACK,MAAA;AACf,MAAA;AACD,MAAA;AACT,IAAA;AACH,EAAA;AAC4B,EAAA;AAC8B,EAAA;AAC5D;AAO4D;AA0BgC,EAAA;AAzBhE,IAAA;AAM0C,IAAA;AAEZ,IAAA;AAE0B,IAAA;AAEE,IAAA;AAWpF;AAAA;AAAA;AAAA;AAAA;AAA8D,IAAA;AAGtC,IAAA;AACiB,IAAA;AACzC,EAAA;AAE6C,EAAA;AACV,IAAA;AACJ,IAAA;AAC/B,EAAA;AAEgD,EAAA;AACV,IAAA;AACL,IAAA;AACjC,EAAA;AAEyF,EAAA;AACrC,IAAA;AACtB,IAAA;AAC2B,MAAA;AACvD,IAAA;AAC0B,IAAA;AACa,MAAA;AACD,MAAA;AAC/B,IAAA;AAC6B,MAAA;AACD,MAAA;AACnC,IAAA;AAII,IAAA;AACA,IAAA;AACqD,MAAA;AAC3C,IAAA;AACiB,MAAA;AAC/B,IAAA;AAQW,IAAA;AAGD,MAAA;AACV,IAAA;AAC6B,IAAA;AAC8B,MAAA;AACD,MAAA;AACtD,QAAA;AACA,QAAA;AACF,MAAA;AACO,MAAA;AACL,QAAA;AACU,QAAA;AACiB,QAAA;AACX,QAAA;AACK,QAAA;AAC2B,QAAA;AAAA;AAAA;AAAA;AAAA;AAK3C,QAAA;AACkB,UAAA;AACD,UAAA;AACK,UAAA;AACR,UAAA;AACC,UAAA;AACS,UAAA;AACA,UAAA;AACG,UAAA;AACN,UAAA;AACA,UAAA;AACG,UAAA;AACP,UAAA;AACG,UAAA;AACA,UAAA;AACzB,QAAA;AACF,MAAA;AACD,IAAA;AACH,EAAA;AAE6F,EAAA;AAC/E,IAAA;AACgB,MAAA;AAC5B,IAAA;AACF,EAAA;AAE+E,EAAA;AACxD,IAAA;AACd,MAAA;AAC4B,QAAA;AAC5B,MAAA;AACmD,QAAA;AACvB,MAAA;AACG,QAAA;AACF,QAAA;AACT,UAAA;AACK,YAAA;AACf,YAAA;AACV,UAAA;AACH,QAAA;AAC0D,QAAA;AAC5D,MAAA;AACA,MAAA;AACuB,QAAA;AACK,UAAA;AACf,UAAA;AACV,QAAA;AACL,IAAA;AACF,EAAA;AAE+B,EAAA;AAC7B,IAAA;AACA,IAAA;AACqD,EAAA;AACvB,IAAA;AACA,MAAA;AACH,MAAA;AAC1B,IAAA;AAE0B,IAAA;AAEY,IAAA;AAChB,MAAA;AACK,QAAA;AACf,QAAA;AAC0B,QAAA;AACpC,MAAA;AACH,IAAA;AACI,IAAA;AACA,IAAA;AACE,MAAA;AAE8C,MAAA;AACG,QAAA;AACQ,QAAA;AACpC,UAAA;AACK,YAAA;AACf,YAAA;AACV,UAAA;AACH,QAAA;AAEuC,QAAA;AACX,UAAA;AACtB,UAAA;AACA,UAAA;AAOmC,UAAA;AACjC,YAAA;AACA,YAAA;AAE0C,cAAA;AAEM,cAAA;AAC5B,cAAA;AACqB,cAAA;AACF,gBAAA;AACvC,gBAAA;AACF,cAAA;AACkB,cAAA;AACJ,YAAA;AACK,8BAAA;AACP,cAAA;AACd,YAAA;AACF,UAAA;AACc,UAAA;AACiC,YAAA;AACxB,YAAA;AACK,cAAA;AACf,cAAA;AACV,YAAA;AACH,UAAA;AACyB,UAAA;AACC,UAAA;AACT,UAAA;AACZ,QAAA;AACuC,UAAA;AACO,UAAA;AACrD,QAAA;AACK,MAAA;AACqD,QAAA;AACL,UAAA;AAChB,UAAA;AACZ,YAAA;AACK,cAAA;AACf,cAAA;AACV,YAAA;AACH,UAAA;AACiC,UAAA;AACV,YAAA;AACK,cAAA;AACf,cAAA;AACV,YAAA;AACH,UAAA;AACmB,UAAA;AACrB,QAAA;AAC0D,QAAA;AACL,UAAA;AAClB,UAAA;AACV,YAAA;AACK,cAAA;AACf,cAAA;AACV,YAAA;AACH,UAAA;AACF,QAAA;AAC0D,QAAA;AACP,QAAA;AACrD,MAAA;AAEsB,MAAA;AACC,QAAA;AACK,UAAA;AACf,UAAA;AACV,QAAA;AACH,MAAA;AAC8B,MAAA;AACR,MAAA;AAIT,MAAA;AAEU,QAAA;AACK,UAAA;AAC6B,UAAA;AACtD,QAAA;AACH,MAAA;AACiD,MAAA;AACJ,MAAA;AAChB,MAAA;AAC3B,QAAA;AACY,QAAA;AACiC,QAAA;AAC9C,MAAA;AACiB,MAAA;AACc,MAAA;AACnB,QAAA;AACD,QAAA;AAC8C,QAAA;AACjC,QAAA;AACP,QAAA;AACc,QAAA;AACkB,QAAA;AACX,QAAA;AACvC,MAAA;AAC8C,MAAA;AACvC,MAAA;AACL,QAAA;AACuD,QAAA;AACzD,MAAA;AACY,IAAA;AACa,sBAAA;AACI,MAAA;AAC/B,IAAA;AACF,EAAA;AAEgG,EAAA;AAG1F,IAAA;AACqC,IAAA;AACzB,MAAA;AAEc,MAAA;AAC9B,IAAA;AACuD,IAAA;AAGxC,IAAA;AACR,IAAA;AACL,MAAA;AACiC,MAAA;AACV,QAAA;AACvB,MAAA;AACe,MAAA;AACC,QAAA;AACH,QAAA;AACqC,wBAAA;AAClD,MAAA;AACF,IAAA;AACF,EAAA;AAEsE,EAAA;AAChD,IAAA;AAE0B,IAAA;AAC/B,IAAA;AAGuC,MAAA;AACnB,QAAA;AACjC,MAAA;AACqB,MAAA;AACK,QAAA;AACf,QAAA;AACgD,QAAA;AAC1D,MAAA;AACH,IAAA;AAEuC,IAAA;AAChB,MAAA;AACK,QAAA;AACf,QAAA;AACV,MAAA;AACH,IAAA;AAE8D,IAAA;AAC9B,IAAA;AACT,MAAA;AACK,QAAA;AACf,QAAA;AACV,MAAA;AACH,IAAA;AACmC,IAAA;AACrC,EAAA;AAE6C,EAAA;AACA,IAAA;AACb,IAAA;AACjB,IAAA;AACK,MAAA;AAIoC,MAAA;AACtD,IAAA;AACuB,IAAA;AACzB,EAAA;AAAA;AAG8F,EAAA;AACT,IAAA;AAC9C,IAAA;AACvC,EAAA;AAE6F,EAAA;AAChD,IAAA;AAC7B,IAAA;AACL,MAAA;AACI,QAAA;AACF,QAAA;AACU,UAAA;AACW,YAAA;AAC2B,YAAA;AACpD,UAAA;AACH,QAAA;AACF,MAAA;AACF,IAAA;AAEI,IAAA;AACc,MAAA;AACI,QAAA;AACW,UAAA;AACmB,UAAA;AACP,UAAA;AAIa,UAAA;AAEzB,UAAA;AACC,UAAA;AACI,YAAA;AACA,cAAA;AACP,cAAA;AACtB,YAAA;AACH,UAAA;AACI,UAAA;AACiD,YAAA;AAC1B,YAAA;AAC0B,cAAA;AACnD,YAAA;AACuB,YAAA;AACvB,UAAA;AAC4B,YAAA;AACI,cAAA;AACA,gBAAA;AACP,gBAAA;AACtB,cAAA;AACH,YAAA;AACF,UAAA;AACF,QAAA;AACwB,QAAA;AACmB,UAAA;AAC/B,YAAA;AACR,YAAA;AACF,UAAA;AAI2C,UAAA;AAC7C,QAAA;AACqB,QAAA;AAC8B,UAAA;AAC5B,UAAA;AACvB,QAAA;AACA,QAAA;AACS,UAAA;AACI,YAAA;AACF,YAAA;AACU,cAAA;AACW,gBAAA;AAC2B,gBAAA;AACpD,cAAA;AACH,YAAA;AACF,UAAA;AACJ,MAAA;AACY,IAAA;AAC4C,MAAA;AAC1D,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAAA;AAM0C,EAAA;AACjB,IAAA;AACzB,EAAA;AAAA;AAAA;AAI6C,EAAA;AAAC,EAAA;AAEkD,EAAA;AAChE,IAAA;AAChC,EAAA;AAEiG,EAAA;AAChE,IAAA;AACjC,EAAA;AAEc,EAAA;AACkC,IAAA;AAC5B,MAAA;AAClB,IAAA;AACoB,IAAA;AACc,IAAA;AACG,IAAA;AACC,IAAA;AACxC,EAAA;AAI+C,EAAA;AACZ,IAAA;AACvB,MAAA;AACR,MAAA;AACF,IAAA;AACsC,IAAA;AACgB,IAAA;AACQ,IAAA;AACvC,MAAA;AACK,QAAA;AAEtB,QAAA;AACH,MAAA;AACH,IAAA;AACO,IAAA;AACmD,MAAA;AACnD,MAAA;AACP,IAAA;AACF,EAAA;AAME,EAAA;AACO,IAAA;AACG,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMe,MAAA;AACL,MAAA;AACkB,MAAA;AACnB,MAAA;AACC,MAAA;AACF,MAAA;AACK,MAAA;AAC2B,MAAA;AACvB,MAAA;AAC3B,IAAA;AACF,EAAA;AACF;AFnFmE;AACA;AACA;AACA;AACA","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-keystone-connector-usb/dist/chunk-K6NZTBAU.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 occupy the low end of `Status` (0..15 today); client\n * codes start at `ERR_DEVICE_NOT_OPENED` (0xA0000001). Anything below that\n * boundary arrived inside a device response frame — see\n * `@keystonehq/hw-transport-webusb`, which throws\n * `TransportError(payload, result.status)` for every non-zero response status.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/**\n * Device-side outcomes (`Status` values reported inside a JSON response\n * payload's status word) — see EAPDU_Readme.md in the Keystone USB SDK repo.\n */\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/**\n * The Keystone transport only names client-side codes (its `ErrorInfo`); for a\n * firmware status it forwards the device's response payload and falls back to a\n * bare 'unknown error'. These fill that gap when the device sent no text.\n */\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/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Errors that already\n * carry a numeric `.code` pass through unchanged. `transportErrorCode` is read\n * duck-typed because duplicate `@keystonehq/*` module instances break\n * `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const domName =\n err && typeof err === 'object' && typeof (err as { name?: unknown }).name === 'string'\n ? (err as { name: string }).name\n : undefined;\n\n // Legacy DOMException codes overlap the low-numbered browser error table\n // (for example NotFoundError is 8). Only five-digit HWK codes are already\n // mapped errors; letting any numeric `.code` pass through turns a WebUSB\n // disconnect into an unknown hardware error at the app boundary.\n if (\n err &&\n typeof err === 'object' &&\n typeof (err as { code?: unknown }).code === 'number' &&\n (err as { code: number }).code >= 10000 &&\n (err as { code: number }).code <= 99999\n ) {\n return err as HwkError;\n }\n\n const statusCode =\n err &&\n typeof err === 'object' &&\n typeof (err as { transportErrorCode?: unknown }).transportErrorCode === 'number'\n ? (err as { transportErrorCode: number }).transportErrorCode\n : 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 is still the firmware answering, so it keeps\n // 'device' and only the code degrades. Guessing 'transport' there is what\n // makes KeystoneAdapter tear down a live USB session over an on-device\n // decline, and a real pipe death already arrives via the transport's\n // disconnect listener rather than a status word.\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; the table only covers the case\n // where the transport had nothing to forward.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A firmware status word is a result, never a link problem. Client-side\n // status codes came from the framing/pipe layer — EXCEPT the timeout,\n // which is genuinely two-faced (the device may be sitting on a confirm\n // screen waiting for a human, or the pipe may be dead) and stays\n // unlabeled rather than mislabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n // WebUSB failures are DOMExceptions. The device dropping off the bus\n // mid-call is the common one — every command here is its own\n // open/claim/transfer/release/close cycle, so an unplug or a bus reset lands\n // exactly here — and it deserves a message the user can act on.\n if (domName === 'NotFoundError' || domName === 'NetworkError') {\n return createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message,\n origin: 'transport',\n params: { domExceptionName: domName },\n });\n }\n if (domName === 'SecurityError' || domName === 'NotAllowedError') {\n return createHwkError({\n code: HardwareErrorCode.DevicePermissionDenied,\n message,\n origin: 'host',\n params: { domExceptionName: domName },\n });\n }\n if (domName === 'InvalidStateError' || domName === 'AbortError') {\n return createHwkError({\n code: HardwareErrorCode.DeviceBusy,\n message,\n origin: 'transport',\n params: { domExceptionName: domName },\n });\n }\n\n // Anything else that reached this mapper was thrown by the transport layer\n // (this function only wraps USB transport calls), so 'transport' is a fact\n // about the throw site, not a guess about the cause.\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 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/**\n * Static surface shared by `TransportWebUSB` and `TransportNodeUSB`; the\n * platform-specific transport is injected by `_subpath/*`.\n */\n/**\n * What enumeration can see before the device is opened. WebUSB hands back a\n * `USBDevice`; node-usb's wrapper exposes the same descriptor strings. Every\n * field is optional because a device may simply not publish that string\n * descriptor — read defensively, never assume presence.\n */\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/**\n * Enumeration-time display name. The serial is the only other field readable\n * before a device is opened, but it is not printed on the unit or shown in its\n * UI, so appending it cannot help anyone tell two Keystones apart — it only\n * makes the model harder to read.\n */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\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 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\nconst DEFAULT_TIMEOUT_MS = 100_000; // SDK's own raw default is 15s (\"may need users' action on the device\") — too short for real confirmation.\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 // Accept either one complete UR or multiple whitespace-separated parts.\n // The transport owns EAPDU framing; this function only validates and joins\n // the BC-UR text present in that response.\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 * `IConnector` for Keystone over USB. Each transport call is its own\n * open/claim/transfer/close cycle, so `connect()` only caches the transport\n * object. `resolveUr` carries the same UR payloads as the QR channel.\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 // Keystone may re-enumerate on the USB bus between public-data exports,\n // which replaces the physical transport session without starting a new\n // user operation. Keep this UI-only state at connector lifetime scope so\n // an internal recovery does not look like another first connection.\n /** Wallets that already approved a public-data export, keyed by master fingerprint. */\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 throws DOMExceptions whose legacy `.code` collides with the\n // five-digit HWK range, so it needs the same mapping as every other\n // transport call here.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // No mfp is available without opening+claiming the device. The target id\n // therefore identifies only this discovery snapshot; wallet identity is\n // learned and verified after connect. WebUSB can reopen the exact cached\n // descriptor. Platforms without that ability fail closed for multi-device\n // selection instead of silently opening a different unit.\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 // Everything enumeration can see, verbatim. Nothing here is normalized\n // or defaulted: a missing key means the device published no such string\n // descriptor. Promote a field onto the typed surface above once\n // something actually consumes 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: Awaited<ReturnType<KeystoneUsbConnectorBase['_readAppConfig']>>;\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: Awaited<ReturnType<KeystoneUsbConnectorBase['_readAppConfig']>>;\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 if (!openedTransport) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'Keystone USB transport was not opened',\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 can keep its USB disconnect listener. Give every\n // descriptor a separate holder so it cannot retire 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 // Whether this particular target is ours is settled by the snapshot\n // lookup in `_connectResolved`, not by anything encoded in the id.\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 (see class doc) — nothing to await\n // here beyond letting the underlying transport's own per-call close\n // run its course, which already happened on the last send().\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 asks for approval once per wallet: internal USB\n // re-enumeration must not reopen the toast, but a different device\n // has not approved anything yet. Signing always confirms.\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 // Naming-only assumption (no positive-case fixture to confirm\n // against) — `checkDeviceLockStatus`'s own name is the only\n // evidence `true` means locked; verify against real hardware.\n return success({ locked: response.payload });\n }\n case 'getAppConfig': {\n const config = await this._readAppConfig(session.transport);\n return success(config);\n }\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 // No protocol-level cancel exists over USB (verified: nothing in the SDK's\n // public surface can interrupt an in-flight transferIn/transferOut) — the\n // best this connector can do is stop waiting on its side; the underlying\n // `send()` promise still settles (or times out) on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // Keystone USB never relays PIN/passphrase through the host — entry always\n // happens on the device's own touchscreen — so there is nothing to answer.\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(\n transport: TransportHID\n ): Promise<{ version?: string; mfp?: string }> {\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 (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 // The device publishes its model as a USB string descriptor\n // (`productName`, e.g. \"Keystone 3 Pro\"); `device.model` carries it here.\n // Empty rather than a literal 'unknown' when it says nothing, so the\n // host's own default-name fallback can win instead of a fake model\n // reaching the UI and the persisted device settings.\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 occupy the low end of `Status` (0..15 today); client\n * codes start at `ERR_DEVICE_NOT_OPENED` (0xA0000001). Anything below that\n * boundary arrived inside a device response frame — see\n * `@keystonehq/hw-transport-webusb`, which throws\n * `TransportError(payload, result.status)` for every non-zero response status.\n */\nfunction isDeviceStatus(statusCode: number): boolean {\n return statusCode >= 0 && statusCode < Status.ERR_DEVICE_NOT_OPENED;\n}\n\n/**\n * Device-side outcomes (`Status` values reported inside a JSON response\n * payload's status word) — see EAPDU_Readme.md in the Keystone USB SDK repo.\n */\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/**\n * The Keystone transport only names client-side codes (its `ErrorInfo`); for a\n * firmware status it forwards the device's response payload and falls back to a\n * bare 'unknown error'. These fill that gap when the device sent no text.\n */\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/**\n * Maps a Keystone USB SDK failure to `HardwareErrorCode`. Errors that already\n * carry a numeric `.code` pass through unchanged. `transportErrorCode` is read\n * duck-typed because duplicate `@keystonehq/*` module instances break\n * `instanceof`.\n */\nexport function mapKeystoneUsbError(err: unknown): HwkError {\n const domName =\n err && typeof err === 'object' && typeof (err as { name?: unknown }).name === 'string'\n ? (err as { name: string }).name\n : undefined;\n\n // Legacy DOMException codes overlap the low-numbered browser error table\n // (for example NotFoundError is 8). Only five-digit HWK codes are already\n // mapped errors; letting any numeric `.code` pass through turns a WebUSB\n // disconnect into an unknown hardware error at the app boundary.\n if (\n err &&\n typeof err === 'object' &&\n typeof (err as { code?: unknown }).code === 'number' &&\n (err as { code: number }).code >= 10000 &&\n (err as { code: number }).code <= 99999\n ) {\n return err as HwkError;\n }\n\n const statusCode =\n err &&\n typeof err === 'object' &&\n typeof (err as { transportErrorCode?: unknown }).transportErrorCode === 'number'\n ? (err as { transportErrorCode: number }).transportErrorCode\n : 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 is still the firmware answering, so it keeps\n // 'device' and only the code degrades. Guessing 'transport' there is what\n // makes KeystoneAdapter tear down a live USB session over an on-device\n // decline, and a real pipe death already arrives via the transport's\n // disconnect listener rather than a status word.\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; the table only covers the case\n // where the transport had nothing to forward.\n message:\n description && PLACEHOLDER_MESSAGE.test(message)\n ? `${description} (error_code: ${statusCode})`\n : message,\n // A firmware status word is a result, never a link problem. Client-side\n // status codes came from the framing/pipe layer — EXCEPT the timeout,\n // which is genuinely two-faced (the device may be sitting on a confirm\n // screen waiting for a human, or the pipe may be dead) and stays\n // unlabeled rather than mislabeled.\n origin,\n params: { statusCode, details: (err as { details?: string }).details },\n });\n }\n\n // WebUSB failures are DOMExceptions. The device dropping off the bus\n // mid-call is the common one — every command here is its own\n // open/claim/transfer/release/close cycle, so an unplug or a bus reset lands\n // exactly here — and it deserves a message the user can act on.\n if (domName === 'NotFoundError' || domName === 'NetworkError') {\n return createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message,\n origin: 'transport',\n params: { domExceptionName: domName },\n });\n }\n if (domName === 'SecurityError' || domName === 'NotAllowedError') {\n return createHwkError({\n code: HardwareErrorCode.DevicePermissionDenied,\n message,\n origin: 'host',\n params: { domExceptionName: domName },\n });\n }\n if (domName === 'InvalidStateError' || domName === 'AbortError') {\n return createHwkError({\n code: HardwareErrorCode.DeviceBusy,\n message,\n origin: 'transport',\n params: { domExceptionName: domName },\n });\n }\n\n // Anything else that reached this mapper was thrown by the transport layer\n // (this function only wraps USB transport calls), so 'transport' is a fact\n // about the throw site, not a guess about the cause.\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 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/**\n * Static surface shared by `TransportWebUSB` and `TransportNodeUSB`; the\n * platform-specific transport is injected by `_subpath/*`.\n */\n/**\n * What enumeration can see before the device is opened. WebUSB hands back a\n * `USBDevice`; node-usb's wrapper exposes the same descriptor strings. Every\n * field is optional because a device may simply not publish that string\n * descriptor — read defensively, never assume presence.\n */\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/**\n * Enumeration-time display name. The serial is the only other field readable\n * before a device is opened, but it is not printed on the unit or shown in its\n * UI, so appending it cannot help anyone tell two Keystones apart — it only\n * makes the model harder to read.\n */\nfunction usbDisplayName(device: KeystoneUsbDeviceDescriptor): string {\n return device.productName?.trim() || 'Keystone';\n}\n\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 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\nconst DEFAULT_TIMEOUT_MS = 100_000; // SDK's own raw default is 15s (\"may need users' action on the device\") — too short for real confirmation.\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 // Accept either one complete UR or multiple whitespace-separated parts.\n // The transport owns EAPDU framing; this function only validates and joins\n // the BC-UR text present in that response.\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 * `IConnector` for Keystone over USB. Each transport call is its own\n * open/claim/transfer/close cycle, so `connect()` only caches the transport\n * object. `resolveUr` carries the same UR payloads as the QR channel.\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 // Keystone may re-enumerate on the USB bus between public-data exports,\n // which replaces the physical transport session without starting a new\n // user operation. Keep this UI-only state at connector lifetime scope so\n // an internal recovery does not look like another first connection.\n /** Wallets that already approved a public-data export, keyed by master fingerprint. */\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 throws DOMExceptions whose legacy `.code` collides with the\n // five-digit HWK range, so it needs the same mapping as every other\n // transport call here.\n let devices: ReadonlyArray<KeystoneUsbDeviceDescriptor>;\n try {\n devices = await this.transportClass.getKeystoneDevices();\n } catch (err) {\n throw mapKeystoneUsbError(err);\n }\n // No mfp is available without opening+claiming the device. The target id\n // therefore identifies only this discovery snapshot; wallet identity is\n // learned and verified after connect. WebUSB can reopen the exact cached\n // descriptor. Platforms without that ability fail closed for multi-device\n // selection instead of silently opening a different unit.\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 // Everything enumeration can see, verbatim. Nothing here is normalized\n // or defaulted: a missing key means the device published no such string\n // descriptor. Promote a field onto the typed surface above once\n // something actually consumes 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: Awaited<ReturnType<KeystoneUsbConnectorBase['_readAppConfig']>>;\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: Awaited<ReturnType<KeystoneUsbConnectorBase['_readAppConfig']>>;\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 if (!openedTransport) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'Keystone USB transport was not opened',\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 can keep its USB disconnect listener. Give every\n // descriptor a separate holder so it cannot retire 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 // Whether this particular target is ours is settled by the snapshot\n // lookup in `_connectResolved`, not by anything encoded in the id.\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 (see class doc) — nothing to await\n // here beyond letting the underlying transport's own per-call close\n // run its course, which already happened on the last send().\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 asks for approval once per wallet: internal USB\n // re-enumeration must not reopen the toast, but a different device\n // has not approved anything yet. Signing always confirms.\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 // Naming-only assumption (no positive-case fixture to confirm\n // against) — `checkDeviceLockStatus`'s own name is the only\n // evidence `true` means locked; verify against real hardware.\n return success({ locked: response.payload });\n }\n case 'getAppConfig': {\n const config = await this._readAppConfig(session.transport);\n return success(config);\n }\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 // No protocol-level cancel exists over USB (verified: nothing in the SDK's\n // public surface can interrupt an in-flight transferIn/transferOut) — the\n // best this connector can do is stop waiting on its side; the underlying\n // `send()` promise still settles (or times out) on its own.\n cancel(_sessionId: string): Promise<void> {\n return Promise.resolve();\n }\n\n // Keystone USB never relays PIN/passphrase through the host — entry always\n // happens on the device's own touchscreen — so there is nothing to answer.\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(\n transport: TransportHID\n ): Promise<{ version?: string; mfp?: string }> {\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 (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 // The device publishes its model as a USB string descriptor\n // (`productName`, e.g. \"Keystone 3 Pro\"); `device.model` carries it here.\n // Empty rather than a literal 'unknown' when it says nothing, so the\n // host's own default-name fallback can win instead of a fake model\n // reaching the UI and the persisted device settings.\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"]}
|