@onekeyfe/hwk-ledger-adapter 1.2.1 → 1.2.2-alpha.1
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/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +152 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -734,6 +734,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
734
734
|
// The Ledger device itself still requires a per-call confirmation — that's
|
|
735
735
|
// the Ledger app's safety boundary, not ours to bypass.
|
|
736
736
|
this._btcHighIndexConfirmedThisSession = false;
|
|
737
|
+
// Runtime relay configuration mutates connector-wide DMK state. Serialize
|
|
738
|
+
// the complete configure → genuine check → clear lifecycle so concurrent
|
|
739
|
+
// callers cannot reset or overwrite each other's one-shot relay.
|
|
740
|
+
this._deviceAuthenticityQueueTail = Promise.resolve();
|
|
737
741
|
// Shared across concurrent callers — only `cancel()` aborts.
|
|
738
742
|
this._doConnectAbortController = null;
|
|
739
743
|
this._installProgressLastEmittedValue = -Infinity;
|
|
@@ -1284,6 +1288,75 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1284
1288
|
return this.errorToFailure(err);
|
|
1285
1289
|
}
|
|
1286
1290
|
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Runs Ledger's official genuine check (DMK GenuineCheckDeviceAction) over the
|
|
1293
|
+
* SAME secure-channel backend as app install
|
|
1294
|
+
* (wss://scriptrunner.api.live.ledger.com/update/genuine). It returns Ledger's
|
|
1295
|
+
* HSM verdict (`verified`) and a stable per-device id = sha3-256 of the device
|
|
1296
|
+
* attestation public key, which DMK reads inside that session. The id survives
|
|
1297
|
+
* wipe/recovery and cannot be forged from a seed.
|
|
1298
|
+
*
|
|
1299
|
+
* Requires network access to Ledger's backend and an on-device
|
|
1300
|
+
* "Allow secure connection" confirmation the first time.
|
|
1301
|
+
*/
|
|
1302
|
+
async verifyDeviceAuthenticity(connectId, params = {}) {
|
|
1303
|
+
const waitForPrevious = this._deviceAuthenticityQueueTail;
|
|
1304
|
+
let releaseQueue = () => void 0;
|
|
1305
|
+
this._deviceAuthenticityQueueTail = new Promise((resolve) => {
|
|
1306
|
+
releaseQueue = resolve;
|
|
1307
|
+
});
|
|
1308
|
+
await waitForPrevious;
|
|
1309
|
+
try {
|
|
1310
|
+
return await this._verifyDeviceAuthenticityExclusive(connectId, params);
|
|
1311
|
+
} finally {
|
|
1312
|
+
releaseQueue();
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
async _verifyDeviceAuthenticityExclusive(connectId, params) {
|
|
1316
|
+
const relayUrl = params.ledgerGenuineCheckWebSocketUrl;
|
|
1317
|
+
try {
|
|
1318
|
+
if (relayUrl) {
|
|
1319
|
+
if (!this.connector.configure) {
|
|
1320
|
+
return failure2(
|
|
1321
|
+
HardwareErrorCode3.MethodNotSupported,
|
|
1322
|
+
"This Ledger connector does not support genuine-check relay configuration"
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
|
|
1326
|
+
this.resetState();
|
|
1327
|
+
}
|
|
1328
|
+
const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
|
|
1329
|
+
if (!result.isGenuine) {
|
|
1330
|
+
return success({
|
|
1331
|
+
vendor: "ledger",
|
|
1332
|
+
verified: false
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
if (!result.deviceId) {
|
|
1336
|
+
return failure2(
|
|
1337
|
+
HardwareErrorCode3.UnknownError,
|
|
1338
|
+
`Genuine check completed (isGenuine=${result.isGenuine}) but no deviceId was captured`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
return success({
|
|
1342
|
+
vendor: "ledger",
|
|
1343
|
+
verified: result.isGenuine,
|
|
1344
|
+
deviceId: result.deviceId
|
|
1345
|
+
});
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
return this.errorToFailure(err);
|
|
1348
|
+
} finally {
|
|
1349
|
+
if (relayUrl) {
|
|
1350
|
+
try {
|
|
1351
|
+
await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
|
|
1352
|
+
this.resetState();
|
|
1353
|
+
} catch {
|
|
1354
|
+
this.connector.reset();
|
|
1355
|
+
this.resetState();
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1287
1360
|
on(event, listener) {
|
|
1288
1361
|
this.emitter.on(event, listener);
|
|
1289
1362
|
}
|
|
@@ -4035,6 +4108,30 @@ var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
|
4035
4108
|
Object.values(HardwareErrorCode8).filter((value) => typeof value === "number")
|
|
4036
4109
|
);
|
|
4037
4110
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
4111
|
+
var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
|
|
4112
|
+
function isAllowedLedgerRelayHost(hostname) {
|
|
4113
|
+
return LEDGER_RELAY_ALLOWED_ROOT_DOMAINS.some(
|
|
4114
|
+
(root) => hostname === root || hostname.endsWith(`.${root}`)
|
|
4115
|
+
);
|
|
4116
|
+
}
|
|
4117
|
+
var LEDGER_RELAY_PATH_PREFIX = "/v1/ledger/session/";
|
|
4118
|
+
var LEDGER_RELAY_TOKEN_PATTERN = /^[A-Za-z0-9_-]{32,256}$/;
|
|
4119
|
+
var MAX_LEDGER_RELAY_URL_LENGTH = 2048;
|
|
4120
|
+
function assertAllowedLedgerRelayUrl(rawUrl) {
|
|
4121
|
+
if (!rawUrl || rawUrl.length > MAX_LEDGER_RELAY_URL_LENGTH) {
|
|
4122
|
+
throw new Error("Ledger genuine-check relay URL is invalid");
|
|
4123
|
+
}
|
|
4124
|
+
let parsed;
|
|
4125
|
+
try {
|
|
4126
|
+
parsed = new URL(rawUrl);
|
|
4127
|
+
} catch {
|
|
4128
|
+
throw new Error("Ledger genuine-check relay URL is invalid");
|
|
4129
|
+
}
|
|
4130
|
+
const token = parsed.pathname.startsWith(LEDGER_RELAY_PATH_PREFIX) ? parsed.pathname.slice(LEDGER_RELAY_PATH_PREFIX.length) : "";
|
|
4131
|
+
if (parsed.protocol !== "wss:" || !isAllowedLedgerRelayHost(parsed.hostname) || parsed.port !== "" || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || !LEDGER_RELAY_TOKEN_PATTERN.test(token)) {
|
|
4132
|
+
throw new Error("Ledger genuine-check relay URL is not allowed");
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4038
4135
|
async function defaultLedgerKitImporter(pkg) {
|
|
4039
4136
|
switch (pkg) {
|
|
4040
4137
|
case "@ledgerhq/device-management-kit":
|
|
@@ -4556,6 +4653,41 @@ var LedgerConnectorBase = class {
|
|
|
4556
4653
|
ctx.clearCanceller(sessionId);
|
|
4557
4654
|
}
|
|
4558
4655
|
}
|
|
4656
|
+
case "getDeviceGenuineCheck": {
|
|
4657
|
+
try {
|
|
4658
|
+
const dmk = await ctx.getOrCreateDmk();
|
|
4659
|
+
const kit = await ctx.importLedgerKit("@ledgerhq/device-management-kit");
|
|
4660
|
+
const action = dmk.executeDeviceAction({
|
|
4661
|
+
sessionId,
|
|
4662
|
+
deviceAction: new kit.GenuineCheckDeviceAction({ input: {} })
|
|
4663
|
+
});
|
|
4664
|
+
let deviceId;
|
|
4665
|
+
const output = await deviceActionToPromise(
|
|
4666
|
+
action,
|
|
4667
|
+
(interaction) => ctx.emit("ui-event", {
|
|
4668
|
+
type: collapseSignerInteraction(interaction),
|
|
4669
|
+
payload: { sessionId }
|
|
4670
|
+
}),
|
|
4671
|
+
// Generous timeout: covers websocket round-trips + the on-device
|
|
4672
|
+
// "Allow secure connection" tap (the idle watchdog does not pause
|
|
4673
|
+
// for it, only for unlock-device).
|
|
4674
|
+
5 * 6e4,
|
|
4675
|
+
(cancel) => ctx.registerCanceller(sessionId, cancel),
|
|
4676
|
+
(intermediateValue) => {
|
|
4677
|
+
const iv = intermediateValue;
|
|
4678
|
+
if (iv?.deviceId instanceof Uint8Array && iv.deviceId.length === 32 && !deviceId) {
|
|
4679
|
+
deviceId = Buffer.from(iv.deviceId).toString("hex");
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4682
|
+
);
|
|
4683
|
+
return { isGenuine: output.isGenuine, deviceId };
|
|
4684
|
+
} catch (err) {
|
|
4685
|
+
ctx.invalidateSession(sessionId);
|
|
4686
|
+
throw ctx.wrapError(err);
|
|
4687
|
+
} finally {
|
|
4688
|
+
ctx.clearCanceller(sessionId);
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4559
4691
|
default:
|
|
4560
4692
|
throw new Error(`LedgerConnector: unknown method "${method}"`);
|
|
4561
4693
|
}
|
|
@@ -4588,8 +4720,23 @@ var LedgerConnectorBase = class {
|
|
|
4588
4720
|
// IConnector -- Reset
|
|
4589
4721
|
// ---------------------------------------------------------------------------
|
|
4590
4722
|
reset() {
|
|
4723
|
+
this._ledgerGenuineCheckWebSocketUrl = void 0;
|
|
4591
4724
|
this._resetAll();
|
|
4592
4725
|
}
|
|
4726
|
+
async configure(config) {
|
|
4727
|
+
const nextUrl = config.ledgerGenuineCheckWebSocketUrl;
|
|
4728
|
+
if (nextUrl) {
|
|
4729
|
+
assertAllowedLedgerRelayUrl(nextUrl);
|
|
4730
|
+
if (this._providedDmk) {
|
|
4731
|
+
throw new Error("Cannot change Ledger genuine-check relay on a pre-built DMK");
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
if (nextUrl === this._ledgerGenuineCheckWebSocketUrl) {
|
|
4735
|
+
return;
|
|
4736
|
+
}
|
|
4737
|
+
this._resetAll();
|
|
4738
|
+
this._ledgerGenuineCheckWebSocketUrl = nextUrl;
|
|
4739
|
+
}
|
|
4593
4740
|
// ---------------------------------------------------------------------------
|
|
4594
4741
|
// Private -- DMK / Manager lifecycle
|
|
4595
4742
|
// ---------------------------------------------------------------------------
|
|
@@ -4615,7 +4762,11 @@ var LedgerConnectorBase = class {
|
|
|
4615
4762
|
);
|
|
4616
4763
|
const transportFactory = await this._createTransport();
|
|
4617
4764
|
debugLog("[DMK] _getOrCreateDmk: transportFactory type:", typeof transportFactory);
|
|
4618
|
-
const
|
|
4765
|
+
const builder = new DeviceManagementKitBuilder().addTransport(transportFactory);
|
|
4766
|
+
if (this._ledgerGenuineCheckWebSocketUrl) {
|
|
4767
|
+
builder.addConfig({ webSocketUrl: this._ledgerGenuineCheckWebSocketUrl });
|
|
4768
|
+
}
|
|
4769
|
+
const dmk = builder.build();
|
|
4619
4770
|
this._dmk = dmk;
|
|
4620
4771
|
debugLog("[DMK] _getOrCreateDmk: DMK created");
|
|
4621
4772
|
return dmk;
|