@bitgo/passkey-crypto 0.2.0 → 0.3.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.
Files changed (59) hide show
  1. package/dist/src/attachPasskeyToWallet.d.ts +11 -0
  2. package/dist/src/attachPasskeyToWallet.d.ts.map +1 -0
  3. package/dist/src/attachPasskeyToWallet.js +63 -0
  4. package/dist/src/base64url.d.ts +16 -0
  5. package/dist/src/base64url.d.ts.map +1 -0
  6. package/dist/src/base64url.js +27 -0
  7. package/dist/src/deriveEnterpriseSalt.d.ts +7 -1
  8. package/dist/src/deriveEnterpriseSalt.d.ts.map +1 -1
  9. package/dist/src/deriveEnterpriseSalt.js +12 -42
  10. package/dist/src/derivePasskeyPrfKey.d.ts +15 -0
  11. package/dist/src/derivePasskeyPrfKey.d.ts.map +1 -0
  12. package/dist/src/derivePasskeyPrfKey.js +68 -0
  13. package/dist/src/index.d.ts +5 -0
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/index.js +12 -2
  16. package/dist/src/prfHelpers.d.ts.map +1 -1
  17. package/dist/src/prfHelpers.js +19 -4
  18. package/dist/src/registerPasskey.d.ts +10 -0
  19. package/dist/src/registerPasskey.d.ts.map +1 -0
  20. package/dist/src/registerPasskey.js +93 -0
  21. package/dist/src/removePasskeyFromAccount.d.ts +11 -0
  22. package/dist/src/removePasskeyFromAccount.d.ts.map +1 -0
  23. package/dist/src/removePasskeyFromAccount.js +15 -0
  24. package/dist/src/removePasskeyFromWallet.d.ts +10 -0
  25. package/dist/src/removePasskeyFromWallet.d.ts.map +1 -0
  26. package/dist/src/removePasskeyFromWallet.js +22 -0
  27. package/dist/test/integration/helpers/fixtures.d.ts +12 -0
  28. package/dist/test/integration/helpers/fixtures.d.ts.map +1 -0
  29. package/dist/test/integration/helpers/fixtures.js +15 -0
  30. package/dist/test/integration/helpers/mockBitGo.d.ts +27 -0
  31. package/dist/test/integration/helpers/mockBitGo.d.ts.map +1 -0
  32. package/dist/test/integration/helpers/mockBitGo.js +148 -0
  33. package/dist/test/integration/helpers/mockProvider.d.ts +5 -0
  34. package/dist/test/integration/helpers/mockProvider.d.ts.map +1 -0
  35. package/dist/test/integration/helpers/mockProvider.js +37 -0
  36. package/dist/test/integration/passkeyLifecycle.test.d.ts +2 -0
  37. package/dist/test/integration/passkeyLifecycle.test.d.ts.map +1 -0
  38. package/dist/test/integration/passkeyLifecycle.test.js +153 -0
  39. package/dist/test/unit/attachPasskeyToWallet.test.d.ts +2 -0
  40. package/dist/test/unit/attachPasskeyToWallet.test.d.ts.map +1 -0
  41. package/dist/test/unit/attachPasskeyToWallet.test.js +205 -0
  42. package/dist/test/unit/base64url.test.d.ts +2 -0
  43. package/dist/test/unit/base64url.test.d.ts.map +1 -0
  44. package/dist/test/unit/base64url.test.js +75 -0
  45. package/dist/test/unit/deriveEnterpriseSalt.test.js +8 -4
  46. package/dist/test/unit/derivePasskeyPrfKey.test.d.ts +2 -0
  47. package/dist/test/unit/derivePasskeyPrfKey.test.d.ts.map +1 -0
  48. package/dist/test/unit/derivePasskeyPrfKey.test.js +152 -0
  49. package/dist/test/unit/registerPasskey.test.d.ts +2 -0
  50. package/dist/test/unit/registerPasskey.test.d.ts.map +1 -0
  51. package/dist/test/unit/registerPasskey.test.js +155 -0
  52. package/dist/test/unit/removePasskeyFromAccount.test.d.ts +2 -0
  53. package/dist/test/unit/removePasskeyFromAccount.test.d.ts.map +1 -0
  54. package/dist/test/unit/removePasskeyFromAccount.test.js +88 -0
  55. package/dist/test/unit/removePasskeyFromWallet.test.d.ts +2 -0
  56. package/dist/test/unit/removePasskeyFromWallet.test.d.ts.map +1 -0
  57. package/dist/test/unit/removePasskeyFromWallet.test.js +170 -0
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +7 -5
@@ -0,0 +1,11 @@
1
+ import { BitGoBase, Keychain } from '@bitgo/sdk-core';
2
+ import { WebAuthnOtpDevice, WebAuthnProvider } from './webAuthnTypes';
3
+ export declare function attachPasskeyToWallet(params: {
4
+ bitgo: BitGoBase;
5
+ coin: string;
6
+ walletId: string;
7
+ device: WebAuthnOtpDevice;
8
+ existingPassphrase: string;
9
+ provider: WebAuthnProvider;
10
+ }): Promise<Keychain>;
11
+ //# sourceMappingURL=attachPasskeyToWallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachPasskeyToWallet.d.ts","sourceRoot":"","sources":["../../src/attachPasskeyToWallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqEpB"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachPasskeyToWallet = attachPasskeyToWallet;
4
+ const base64url_1 = require("./base64url");
5
+ const deriveEnterpriseSalt_1 = require("./deriveEnterpriseSalt");
6
+ const derivePassword_1 = require("./derivePassword");
7
+ async function attachPasskeyToWallet(params) {
8
+ const { bitgo, coin, walletId, device, existingPassphrase, provider } = params;
9
+ // Throw early if PRF extension is not supported
10
+ if (!device.prfSalt) {
11
+ throw new Error('PRF extension not supported by this device. Please use a different passkey.');
12
+ }
13
+ const baseCoin = bitgo.coin(coin);
14
+ // Fetch wallet and validate it is a hot wallet
15
+ const wallet = await baseCoin.wallets().get({ id: walletId });
16
+ if (wallet.type() !== 'hot') {
17
+ throw new Error(`Wallet ${walletId} is not a hot wallet. Only hot wallets support passkey attachment.`);
18
+ }
19
+ const walletData = wallet.toJSON();
20
+ const enterpriseId = walletData.enterprise;
21
+ if (!enterpriseId) {
22
+ throw new Error(`Wallet ${walletId} has no enterprise.`);
23
+ }
24
+ // Fetch the user keychain — iterates keys until it finds one with encryptedPrv
25
+ const keychain = await wallet.getEncryptedUserKeychain();
26
+ const keychainId = keychain.id;
27
+ // Derive enterprise-scoped salt (base64url; same encoding is used as the
28
+ // PRF eval input and as the server-stored prfSalt so the bytes fed to the
29
+ // authenticator match between attach and derive).
30
+ const prfSalt = (0, deriveEnterpriseSalt_1.deriveEnterpriseSalt)(device.prfSalt, enterpriseId);
31
+ // Decrypt private key with existing passphrase
32
+ const privateKey = bitgo.decrypt({ password: existingPassphrase, input: keychain.encryptedPrv });
33
+ // Decode credentialId from base64url to ArrayBuffer for allowCredentials.
34
+ // The WebAuthn spec requires allowCredentials to be non-empty when using evalByCredential,
35
+ // and each entry must correspond to a key in the evalByCredential map.
36
+ const credentialIdBuffer = (0, base64url_1.base64UrlToBuffer)(device.credentialId).buffer;
37
+ // PRF assertion — evalByCredential maps this device's credentialId to the
38
+ // base64url enterprise salt. The provider layer is responsible for decoding
39
+ // base64url to raw bytes before handing it to the WebAuthn PRF extension.
40
+ const authResult = await provider.get({
41
+ publicKey: {
42
+ allowCredentials: [{ type: 'public-key', id: credentialIdBuffer }],
43
+ },
44
+ evalByCredential: { [device.credentialId]: prfSalt },
45
+ });
46
+ if (!authResult.prfResult) {
47
+ throw new Error('PRF assertion did not return a result.');
48
+ }
49
+ const prfPassword = (0, derivePassword_1.derivePassword)(authResult.prfResult);
50
+ const encryptedPrv = bitgo.encrypt({ password: prfPassword, input: privateKey });
51
+ const updatedKeychain = await bitgo
52
+ .put(bitgo.url(`/${coin}/key/${keychainId}`, 2))
53
+ .send({
54
+ webauthnInfo: {
55
+ prfSalt,
56
+ otpDeviceId: device.id,
57
+ encryptedPrv,
58
+ },
59
+ })
60
+ .result();
61
+ return updatedKeychain;
62
+ }
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0YWNoUGFzc2tleVRvV2FsbGV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2F0dGFjaFBhc3NrZXlUb1dhbGxldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU1BLHNEQTRFQztBQWpGRCwyQ0FBZ0Q7QUFDaEQsaUVBQThEO0FBQzlELHFEQUFrRDtBQUczQyxLQUFLLFVBQVUscUJBQXFCLENBQUMsTUFPM0M7SUFDQyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLGtCQUFrQixFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUUvRSxnREFBZ0Q7SUFDaEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNwQixNQUFNLElBQUksS0FBSyxDQUFDLDZFQUE2RSxDQUFDLENBQUM7SUFDakcsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFbEMsK0NBQStDO0lBQy9DLE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTlELElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxRQUFRLG9FQUFvRSxDQUFDLENBQUM7SUFDMUcsQ0FBQztJQUVELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNuQyxNQUFNLFlBQVksR0FBRyxVQUFVLENBQUMsVUFBVSxDQUFDO0lBQzNDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsUUFBUSxxQkFBcUIsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRCwrRUFBK0U7SUFDL0UsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztJQUN6RCxNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDO0lBRS9CLHlFQUF5RTtJQUN6RSwwRUFBMEU7SUFDMUUsa0RBQWtEO0lBQ2xELE1BQU0sT0FBTyxHQUFHLElBQUEsMkNBQW9CLEVBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztJQUVuRSwrQ0FBK0M7SUFDL0MsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLFFBQVEsRUFBRSxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUM7SUFFakcsMEVBQTBFO0lBQzFFLDJGQUEyRjtJQUMzRix1RUFBdUU7SUFDdkUsTUFBTSxrQkFBa0IsR0FBRyxJQUFBLDZCQUFpQixFQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFFekUsMEVBQTBFO0lBQzFFLDRFQUE0RTtJQUM1RSwwRUFBMEU7SUFDMUUsTUFBTSxVQUFVLEdBQUcsTUFBTSxRQUFRLENBQUMsR0FBRyxDQUFDO1FBQ3BDLFNBQVMsRUFBRTtZQUNULGdCQUFnQixFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLEVBQUUsRUFBRSxrQkFBa0IsRUFBRSxDQUFDO1NBQzlCO1FBQ3RDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsT0FBTyxFQUFFO0tBQ3JELENBQUMsQ0FBQztJQUVILElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFBLCtCQUFjLEVBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3pELE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBRWpGLE1BQU0sZUFBZSxHQUFHLE1BQU0sS0FBSztTQUNoQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksUUFBUSxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUMvQyxJQUFJLENBQUM7UUFDSixZQUFZLEVBQUU7WUFDWixPQUFPO1lBQ1AsV0FBVyxFQUFFLE1BQU0sQ0FBQyxFQUFFO1lBQ3RCLFlBQVk7U0FDYjtLQUNGLENBQUM7U0FDRCxNQUFNLEVBQUUsQ0FBQztJQUVaLE9BQU8sZUFBMkIsQ0FBQztBQUNyQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQml0R29CYXNlLCBLZXljaGFpbiB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBiYXNlNjRVcmxUb0J1ZmZlciB9IGZyb20gJy4vYmFzZTY0dXJsJztcbmltcG9ydCB7IGRlcml2ZUVudGVycHJpc2VTYWx0IH0gZnJvbSAnLi9kZXJpdmVFbnRlcnByaXNlU2FsdCc7XG5pbXBvcnQgeyBkZXJpdmVQYXNzd29yZCB9IGZyb20gJy4vZGVyaXZlUGFzc3dvcmQnO1xuaW1wb3J0IHsgV2ViQXV0aG5PdHBEZXZpY2UsIFdlYkF1dGhuUHJvdmlkZXIgfSBmcm9tICcuL3dlYkF1dGhuVHlwZXMnO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXR0YWNoUGFzc2tleVRvV2FsbGV0KHBhcmFtczoge1xuICBiaXRnbzogQml0R29CYXNlO1xuICBjb2luOiBzdHJpbmc7XG4gIHdhbGxldElkOiBzdHJpbmc7XG4gIGRldmljZTogV2ViQXV0aG5PdHBEZXZpY2U7XG4gIGV4aXN0aW5nUGFzc3BocmFzZTogc3RyaW5nO1xuICBwcm92aWRlcjogV2ViQXV0aG5Qcm92aWRlcjtcbn0pOiBQcm9taXNlPEtleWNoYWluPiB7XG4gIGNvbnN0IHsgYml0Z28sIGNvaW4sIHdhbGxldElkLCBkZXZpY2UsIGV4aXN0aW5nUGFzc3BocmFzZSwgcHJvdmlkZXIgfSA9IHBhcmFtcztcblxuICAvLyBUaHJvdyBlYXJseSBpZiBQUkYgZXh0ZW5zaW9uIGlzIG5vdCBzdXBwb3J0ZWRcbiAgaWYgKCFkZXZpY2UucHJmU2FsdCkge1xuICAgIHRocm93IG5ldyBFcnJvcignUFJGIGV4dGVuc2lvbiBub3Qgc3VwcG9ydGVkIGJ5IHRoaXMgZGV2aWNlLiBQbGVhc2UgdXNlIGEgZGlmZmVyZW50IHBhc3NrZXkuJyk7XG4gIH1cblxuICBjb25zdCBiYXNlQ29pbiA9IGJpdGdvLmNvaW4oY29pbik7XG5cbiAgLy8gRmV0Y2ggd2FsbGV0IGFuZCB2YWxpZGF0ZSBpdCBpcyBhIGhvdCB3YWxsZXRcbiAgY29uc3Qgd2FsbGV0ID0gYXdhaXQgYmFzZUNvaW4ud2FsbGV0cygpLmdldCh7IGlkOiB3YWxsZXRJZCB9KTtcblxuICBpZiAod2FsbGV0LnR5cGUoKSAhPT0gJ2hvdCcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFdhbGxldCAke3dhbGxldElkfSBpcyBub3QgYSBob3Qgd2FsbGV0LiBPbmx5IGhvdCB3YWxsZXRzIHN1cHBvcnQgcGFzc2tleSBhdHRhY2htZW50LmApO1xuICB9XG5cbiAgY29uc3Qgd2FsbGV0RGF0YSA9IHdhbGxldC50b0pTT04oKTtcbiAgY29uc3QgZW50ZXJwcmlzZUlkID0gd2FsbGV0RGF0YS5lbnRlcnByaXNlO1xuICBpZiAoIWVudGVycHJpc2VJZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgV2FsbGV0ICR7d2FsbGV0SWR9IGhhcyBubyBlbnRlcnByaXNlLmApO1xuICB9XG5cbiAgLy8gRmV0Y2ggdGhlIHVzZXIga2V5Y2hhaW4g4oCUIGl0ZXJhdGVzIGtleXMgdW50aWwgaXQgZmluZHMgb25lIHdpdGggZW5jcnlwdGVkUHJ2XG4gIGNvbnN0IGtleWNoYWluID0gYXdhaXQgd2FsbGV0LmdldEVuY3J5cHRlZFVzZXJLZXljaGFpbigpO1xuICBjb25zdCBrZXljaGFpbklkID0ga2V5Y2hhaW4uaWQ7XG5cbiAgLy8gRGVyaXZlIGVudGVycHJpc2Utc2NvcGVkIHNhbHQgKGJhc2U2NHVybDsgc2FtZSBlbmNvZGluZyBpcyB1c2VkIGFzIHRoZVxuICAvLyBQUkYgZXZhbCBpbnB1dCBhbmQgYXMgdGhlIHNlcnZlci1zdG9yZWQgcHJmU2FsdCBzbyB0aGUgYnl0ZXMgZmVkIHRvIHRoZVxuICAvLyBhdXRoZW50aWNhdG9yIG1hdGNoIGJldHdlZW4gYXR0YWNoIGFuZCBkZXJpdmUpLlxuICBjb25zdCBwcmZTYWx0ID0gZGVyaXZlRW50ZXJwcmlzZVNhbHQoZGV2aWNlLnByZlNhbHQsIGVudGVycHJpc2VJZCk7XG5cbiAgLy8gRGVjcnlwdCBwcml2YXRlIGtleSB3aXRoIGV4aXN0aW5nIHBhc3NwaHJhc2VcbiAgY29uc3QgcHJpdmF0ZUtleSA9IGJpdGdvLmRlY3J5cHQoeyBwYXNzd29yZDogZXhpc3RpbmdQYXNzcGhyYXNlLCBpbnB1dDoga2V5Y2hhaW4uZW5jcnlwdGVkUHJ2IH0pO1xuXG4gIC8vIERlY29kZSBjcmVkZW50aWFsSWQgZnJvbSBiYXNlNjR1cmwgdG8gQXJyYXlCdWZmZXIgZm9yIGFsbG93Q3JlZGVudGlhbHMuXG4gIC8vIFRoZSBXZWJBdXRobiBzcGVjIHJlcXVpcmVzIGFsbG93Q3JlZGVudGlhbHMgdG8gYmUgbm9uLWVtcHR5IHdoZW4gdXNpbmcgZXZhbEJ5Q3JlZGVudGlhbCxcbiAgLy8gYW5kIGVhY2ggZW50cnkgbXVzdCBjb3JyZXNwb25kIHRvIGEga2V5IGluIHRoZSBldmFsQnlDcmVkZW50aWFsIG1hcC5cbiAgY29uc3QgY3JlZGVudGlhbElkQnVmZmVyID0gYmFzZTY0VXJsVG9CdWZmZXIoZGV2aWNlLmNyZWRlbnRpYWxJZCkuYnVmZmVyO1xuXG4gIC8vIFBSRiBhc3NlcnRpb24g4oCUIGV2YWxCeUNyZWRlbnRpYWwgbWFwcyB0aGlzIGRldmljZSdzIGNyZWRlbnRpYWxJZCB0byB0aGVcbiAgLy8gYmFzZTY0dXJsIGVudGVycHJpc2Ugc2FsdC4gVGhlIHByb3ZpZGVyIGxheWVyIGlzIHJlc3BvbnNpYmxlIGZvciBkZWNvZGluZ1xuICAvLyBiYXNlNjR1cmwgdG8gcmF3IGJ5dGVzIGJlZm9yZSBoYW5kaW5nIGl0IHRvIHRoZSBXZWJBdXRobiBQUkYgZXh0ZW5zaW9uLlxuICBjb25zdCBhdXRoUmVzdWx0ID0gYXdhaXQgcHJvdmlkZXIuZ2V0KHtcbiAgICBwdWJsaWNLZXk6IHtcbiAgICAgIGFsbG93Q3JlZGVudGlhbHM6IFt7IHR5cGU6ICdwdWJsaWMta2V5JywgaWQ6IGNyZWRlbnRpYWxJZEJ1ZmZlciB9XSxcbiAgICB9IGFzIFB1YmxpY0tleUNyZWRlbnRpYWxSZXF1ZXN0T3B0aW9ucyxcbiAgICBldmFsQnlDcmVkZW50aWFsOiB7IFtkZXZpY2UuY3JlZGVudGlhbElkXTogcHJmU2FsdCB9LFxuICB9KTtcblxuICBpZiAoIWF1dGhSZXN1bHQucHJmUmVzdWx0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQUkYgYXNzZXJ0aW9uIGRpZCBub3QgcmV0dXJuIGEgcmVzdWx0LicpO1xuICB9XG5cbiAgY29uc3QgcHJmUGFzc3dvcmQgPSBkZXJpdmVQYXNzd29yZChhdXRoUmVzdWx0LnByZlJlc3VsdCk7XG4gIGNvbnN0IGVuY3J5cHRlZFBydiA9IGJpdGdvLmVuY3J5cHQoeyBwYXNzd29yZDogcHJmUGFzc3dvcmQsIGlucHV0OiBwcml2YXRlS2V5IH0pO1xuXG4gIGNvbnN0IHVwZGF0ZWRLZXljaGFpbiA9IGF3YWl0IGJpdGdvXG4gICAgLnB1dChiaXRnby51cmwoYC8ke2NvaW59L2tleS8ke2tleWNoYWluSWR9YCwgMikpXG4gICAgLnNlbmQoe1xuICAgICAgd2ViYXV0aG5JbmZvOiB7XG4gICAgICAgIHByZlNhbHQsXG4gICAgICAgIG90cERldmljZUlkOiBkZXZpY2UuaWQsXG4gICAgICAgIGVuY3J5cHRlZFBydixcbiAgICAgIH0sXG4gICAgfSlcbiAgICAucmVzdWx0KCk7XG5cbiAgcmV0dXJuIHVwZGF0ZWRLZXljaGFpbiBhcyBLZXljaGFpbjtcbn1cbiJdfQ==
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Base64url encoding helpers.
3
+ *
4
+ * Base64url uses the same alphabet as standard base64 except `+` becomes `-`,
5
+ * `/` becomes `_`, and padding (`=`) is stripped. Browser WebAuthn APIs and
6
+ * the BitGo server both use base64url for credential IDs and PRF salts, so we
7
+ * normalise to it everywhere on the client to avoid mismatches caused by
8
+ * mixing encodings.
9
+ */
10
+ /** Converts a standard base64 string (or already-base64url string) to base64url. */
11
+ export declare function toBase64Url(s: string): string;
12
+ /** Encodes an ArrayBuffer or Buffer as a base64url string (no padding). */
13
+ export declare function bufferToBase64Url(buffer: ArrayBuffer | Buffer): string;
14
+ /** Decodes a base64url string into a Buffer. */
15
+ export declare function base64UrlToBuffer(s: string): Buffer;
16
+ //# sourceMappingURL=base64url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64url.d.ts","sourceRoot":"","sources":["../../src/base64url.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAEtE;AAED,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * Base64url encoding helpers.
4
+ *
5
+ * Base64url uses the same alphabet as standard base64 except `+` becomes `-`,
6
+ * `/` becomes `_`, and padding (`=`) is stripped. Browser WebAuthn APIs and
7
+ * the BitGo server both use base64url for credential IDs and PRF salts, so we
8
+ * normalise to it everywhere on the client to avoid mismatches caused by
9
+ * mixing encodings.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.toBase64Url = toBase64Url;
13
+ exports.bufferToBase64Url = bufferToBase64Url;
14
+ exports.base64UrlToBuffer = base64UrlToBuffer;
15
+ /** Converts a standard base64 string (or already-base64url string) to base64url. */
16
+ function toBase64Url(s) {
17
+ return s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
18
+ }
19
+ /** Encodes an ArrayBuffer or Buffer as a base64url string (no padding). */
20
+ function bufferToBase64Url(buffer) {
21
+ return toBase64Url(Buffer.from(buffer).toString('base64'));
22
+ }
23
+ /** Decodes a base64url string into a Buffer. */
24
+ function base64UrlToBuffer(s) {
25
+ return Buffer.from(s.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
26
+ }
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZTY0dXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Jhc2U2NHVybC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7O0FBR0gsa0NBRUM7QUFHRCw4Q0FFQztBQUdELDhDQUVDO0FBYkQsb0ZBQW9GO0FBQ3BGLFNBQWdCLFdBQVcsQ0FBQyxDQUFTO0lBQ25DLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3RFLENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsU0FBZ0IsaUJBQWlCLENBQUMsTUFBNEI7SUFDNUQsT0FBTyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFxQixDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDNUUsQ0FBQztBQUVELGdEQUFnRDtBQUNoRCxTQUFnQixpQkFBaUIsQ0FBQyxDQUFTO0lBQ3pDLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBQ3hFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJhc2U2NHVybCBlbmNvZGluZyBoZWxwZXJzLlxuICpcbiAqIEJhc2U2NHVybCB1c2VzIHRoZSBzYW1lIGFscGhhYmV0IGFzIHN0YW5kYXJkIGJhc2U2NCBleGNlcHQgYCtgIGJlY29tZXMgYC1gLFxuICogYC9gIGJlY29tZXMgYF9gLCBhbmQgcGFkZGluZyAoYD1gKSBpcyBzdHJpcHBlZC4gQnJvd3NlciBXZWJBdXRobiBBUElzIGFuZFxuICogdGhlIEJpdEdvIHNlcnZlciBib3RoIHVzZSBiYXNlNjR1cmwgZm9yIGNyZWRlbnRpYWwgSURzIGFuZCBQUkYgc2FsdHMsIHNvIHdlXG4gKiBub3JtYWxpc2UgdG8gaXQgZXZlcnl3aGVyZSBvbiB0aGUgY2xpZW50IHRvIGF2b2lkIG1pc21hdGNoZXMgY2F1c2VkIGJ5XG4gKiBtaXhpbmcgZW5jb2RpbmdzLlxuICovXG5cbi8qKiBDb252ZXJ0cyBhIHN0YW5kYXJkIGJhc2U2NCBzdHJpbmcgKG9yIGFscmVhZHktYmFzZTY0dXJsIHN0cmluZykgdG8gYmFzZTY0dXJsLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQmFzZTY0VXJsKHM6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBzLnJlcGxhY2UoL1xcKy9nLCAnLScpLnJlcGxhY2UoL1xcLy9nLCAnXycpLnJlcGxhY2UoLz0rJC8sICcnKTtcbn1cblxuLyoqIEVuY29kZXMgYW4gQXJyYXlCdWZmZXIgb3IgQnVmZmVyIGFzIGEgYmFzZTY0dXJsIHN0cmluZyAobm8gcGFkZGluZykuICovXG5leHBvcnQgZnVuY3Rpb24gYnVmZmVyVG9CYXNlNjRVcmwoYnVmZmVyOiBBcnJheUJ1ZmZlciB8IEJ1ZmZlcik6IHN0cmluZyB7XG4gIHJldHVybiB0b0Jhc2U2NFVybChCdWZmZXIuZnJvbShidWZmZXIgYXMgQXJyYXlCdWZmZXIpLnRvU3RyaW5nKCdiYXNlNjQnKSk7XG59XG5cbi8qKiBEZWNvZGVzIGEgYmFzZTY0dXJsIHN0cmluZyBpbnRvIGEgQnVmZmVyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJhc2U2NFVybFRvQnVmZmVyKHM6IHN0cmluZyk6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShzLnJlcGxhY2UoLy0vZywgJysnKS5yZXBsYWNlKC9fL2csICcvJyksICdiYXNlNjQnKTtcbn1cbiJdfQ==
@@ -4,9 +4,15 @@
4
4
  * Computes HMAC-SHA256(key=prfSalt_base64url_decoded, data=enterpriseId_utf8).
5
5
  * The baseSalt must always come from the server — never generate it client-side.
6
6
  *
7
+ * Returns base64url so the same encoding is used everywhere the salt is handled
8
+ * (server storage, PRF eval input, prfHelpers lookup). Mixing encodings
9
+ * (e.g. hex on the client, base64url on the server) caused the PRF to receive
10
+ * different bytes during attach vs derive in browser environments where
11
+ * `Buffer.toString('hex')` is unreliable.
12
+ *
7
13
  * @param baseSalt - Server-provided base64url-encoded PRF salt
8
14
  * @param enterpriseId - Enterprise identifier
9
- * @returns Base64-encoded HMAC-SHA256 digest
15
+ * @returns Base64url-encoded HMAC-SHA256 digest (no padding)
10
16
  */
11
17
  export declare function deriveEnterpriseSalt(baseSalt: string, enterpriseId: string): string;
12
18
  //# sourceMappingURL=deriveEnterpriseSalt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deriveEnterpriseSalt.d.ts","sourceRoot":"","sources":["../../src/deriveEnterpriseSalt.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAUnF"}
1
+ {"version":3,"file":"deriveEnterpriseSalt.d.ts","sourceRoot":"","sources":["../../src/deriveEnterpriseSalt.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAGnF"}
@@ -1,56 +1,26 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.deriveEnterpriseSalt = deriveEnterpriseSalt;
37
- const sjcl = __importStar(require("@bitgo/sjcl"));
4
+ const crypto_1 = require("crypto");
5
+ const base64url_1 = require("./base64url");
38
6
  /**
39
7
  * Derives an enterprise-scoped PRF salt to prevent cross-enterprise key reuse.
40
8
  *
41
9
  * Computes HMAC-SHA256(key=prfSalt_base64url_decoded, data=enterpriseId_utf8).
42
10
  * The baseSalt must always come from the server — never generate it client-side.
43
11
  *
12
+ * Returns base64url so the same encoding is used everywhere the salt is handled
13
+ * (server storage, PRF eval input, prfHelpers lookup). Mixing encodings
14
+ * (e.g. hex on the client, base64url on the server) caused the PRF to receive
15
+ * different bytes during attach vs derive in browser environments where
16
+ * `Buffer.toString('hex')` is unreliable.
17
+ *
44
18
  * @param baseSalt - Server-provided base64url-encoded PRF salt
45
19
  * @param enterpriseId - Enterprise identifier
46
- * @returns Base64-encoded HMAC-SHA256 digest
20
+ * @returns Base64url-encoded HMAC-SHA256 digest (no padding)
47
21
  */
48
22
  function deriveEnterpriseSalt(baseSalt, enterpriseId) {
49
- const { misc, codec, hash } = sjcl;
50
- const keyBits = codec.base64url.toBits(baseSalt);
51
- const dataBits = codec.utf8String.toBits(enterpriseId);
52
- const hmacInstance = new misc.hmac(keyBits, hash.sha256);
53
- const resultBits = hmacInstance.mac(dataBits);
54
- return codec.base64.fromBits(resultBits);
23
+ const keyBytes = (0, base64url_1.base64UrlToBuffer)(baseSalt);
24
+ return (0, base64url_1.toBase64Url)((0, crypto_1.createHmac)('sha256', keyBytes).update(enterpriseId).digest('base64'));
55
25
  }
56
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVyaXZlRW50ZXJwcmlzZVNhbHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVyaXZlRW50ZXJwcmlzZVNhbHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtQkEsb0RBVUM7QUE3QkQsa0RBQW9DO0FBU3BDOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLFFBQWdCLEVBQUUsWUFBb0I7SUFDekUsTUFBTSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsSUFBMkIsQ0FBQztJQUUxRCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUV2RCxNQUFNLFlBQVksR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6RCxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRTlDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDM0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHNqY2wgZnJvbSAnQGJpdGdvL3NqY2wnO1xuaW1wb3J0IHR5cGUgeyBTamNsQ29kZWNzLCBTamNsSGFzaGVzLCBTamNsTWlzYyB9IGZyb20gJ0BiaXRnby9zamNsJztcblxudHlwZSBTamNsVHlwZSA9IHtcbiAgaGFzaDogU2pjbEhhc2hlcztcbiAgY29kZWM6IFNqY2xDb2RlY3M7XG4gIG1pc2M6IFNqY2xNaXNjO1xufTtcblxuLyoqXG4gKiBEZXJpdmVzIGFuIGVudGVycHJpc2Utc2NvcGVkIFBSRiBzYWx0IHRvIHByZXZlbnQgY3Jvc3MtZW50ZXJwcmlzZSBrZXkgcmV1c2UuXG4gKlxuICogQ29tcHV0ZXMgSE1BQy1TSEEyNTYoa2V5PXByZlNhbHRfYmFzZTY0dXJsX2RlY29kZWQsIGRhdGE9ZW50ZXJwcmlzZUlkX3V0ZjgpLlxuICogVGhlIGJhc2VTYWx0IG11c3QgYWx3YXlzIGNvbWUgZnJvbSB0aGUgc2VydmVyIOKAlCBuZXZlciBnZW5lcmF0ZSBpdCBjbGllbnQtc2lkZS5cbiAqXG4gKiBAcGFyYW0gYmFzZVNhbHQgLSBTZXJ2ZXItcHJvdmlkZWQgYmFzZTY0dXJsLWVuY29kZWQgUFJGIHNhbHRcbiAqIEBwYXJhbSBlbnRlcnByaXNlSWQgLSBFbnRlcnByaXNlIGlkZW50aWZpZXJcbiAqIEByZXR1cm5zIEJhc2U2NC1lbmNvZGVkIEhNQUMtU0hBMjU2IGRpZ2VzdFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVyaXZlRW50ZXJwcmlzZVNhbHQoYmFzZVNhbHQ6IHN0cmluZywgZW50ZXJwcmlzZUlkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCB7IG1pc2MsIGNvZGVjLCBoYXNoIH0gPSBzamNsIGFzIHVua25vd24gYXMgU2pjbFR5cGU7XG5cbiAgY29uc3Qga2V5Qml0cyA9IGNvZGVjLmJhc2U2NHVybC50b0JpdHMoYmFzZVNhbHQpO1xuICBjb25zdCBkYXRhQml0cyA9IGNvZGVjLnV0ZjhTdHJpbmcudG9CaXRzKGVudGVycHJpc2VJZCk7XG5cbiAgY29uc3QgaG1hY0luc3RhbmNlID0gbmV3IG1pc2MuaG1hYyhrZXlCaXRzLCBoYXNoLnNoYTI1Nik7XG4gIGNvbnN0IHJlc3VsdEJpdHMgPSBobWFjSW5zdGFuY2UubWFjKGRhdGFCaXRzKTtcblxuICByZXR1cm4gY29kZWMuYmFzZTY0LmZyb21CaXRzKHJlc3VsdEJpdHMpO1xufVxuIl19
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVyaXZlRW50ZXJwcmlzZVNhbHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVyaXZlRW50ZXJwcmlzZVNhbHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFtQkEsb0RBR0M7QUF0QkQsbUNBQW9DO0FBQ3BDLDJDQUE2RDtBQUU3RDs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxTQUFnQixvQkFBb0IsQ0FBQyxRQUFnQixFQUFFLFlBQW9CO0lBQ3pFLE1BQU0sUUFBUSxHQUFHLElBQUEsNkJBQWlCLEVBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0MsT0FBTyxJQUFBLHVCQUFXLEVBQUMsSUFBQSxtQkFBVSxFQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDM0YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhtYWMgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgYmFzZTY0VXJsVG9CdWZmZXIsIHRvQmFzZTY0VXJsIH0gZnJvbSAnLi9iYXNlNjR1cmwnO1xuXG4vKipcbiAqIERlcml2ZXMgYW4gZW50ZXJwcmlzZS1zY29wZWQgUFJGIHNhbHQgdG8gcHJldmVudCBjcm9zcy1lbnRlcnByaXNlIGtleSByZXVzZS5cbiAqXG4gKiBDb21wdXRlcyBITUFDLVNIQTI1NihrZXk9cHJmU2FsdF9iYXNlNjR1cmxfZGVjb2RlZCwgZGF0YT1lbnRlcnByaXNlSWRfdXRmOCkuXG4gKiBUaGUgYmFzZVNhbHQgbXVzdCBhbHdheXMgY29tZSBmcm9tIHRoZSBzZXJ2ZXIg4oCUIG5ldmVyIGdlbmVyYXRlIGl0IGNsaWVudC1zaWRlLlxuICpcbiAqIFJldHVybnMgYmFzZTY0dXJsIHNvIHRoZSBzYW1lIGVuY29kaW5nIGlzIHVzZWQgZXZlcnl3aGVyZSB0aGUgc2FsdCBpcyBoYW5kbGVkXG4gKiAoc2VydmVyIHN0b3JhZ2UsIFBSRiBldmFsIGlucHV0LCBwcmZIZWxwZXJzIGxvb2t1cCkuIE1peGluZyBlbmNvZGluZ3NcbiAqIChlLmcuIGhleCBvbiB0aGUgY2xpZW50LCBiYXNlNjR1cmwgb24gdGhlIHNlcnZlcikgY2F1c2VkIHRoZSBQUkYgdG8gcmVjZWl2ZVxuICogZGlmZmVyZW50IGJ5dGVzIGR1cmluZyBhdHRhY2ggdnMgZGVyaXZlIGluIGJyb3dzZXIgZW52aXJvbm1lbnRzIHdoZXJlXG4gKiBgQnVmZmVyLnRvU3RyaW5nKCdoZXgnKWAgaXMgdW5yZWxpYWJsZS5cbiAqXG4gKiBAcGFyYW0gYmFzZVNhbHQgLSBTZXJ2ZXItcHJvdmlkZWQgYmFzZTY0dXJsLWVuY29kZWQgUFJGIHNhbHRcbiAqIEBwYXJhbSBlbnRlcnByaXNlSWQgLSBFbnRlcnByaXNlIGlkZW50aWZpZXJcbiAqIEByZXR1cm5zIEJhc2U2NHVybC1lbmNvZGVkIEhNQUMtU0hBMjU2IGRpZ2VzdCAobm8gcGFkZGluZylcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcml2ZUVudGVycHJpc2VTYWx0KGJhc2VTYWx0OiBzdHJpbmcsIGVudGVycHJpc2VJZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qga2V5Qnl0ZXMgPSBiYXNlNjRVcmxUb0J1ZmZlcihiYXNlU2FsdCk7XG4gIHJldHVybiB0b0Jhc2U2NFVybChjcmVhdGVIbWFjKCdzaGEyNTYnLCBrZXlCeXRlcykudXBkYXRlKGVudGVycHJpc2VJZCkuZGlnZXN0KCdiYXNlNjQnKSk7XG59XG4iXX0=
@@ -0,0 +1,15 @@
1
+ import type { BitGoBase, IWallet } from '@bitgo/sdk-core';
2
+ import type { WebAuthnProvider } from './webAuthnTypes';
3
+ /**
4
+ * Derives a wallet passphrase from a passkey PRF output.
5
+ *
6
+ * Fetches the wallet's user keychain, triggers a WebAuthn assertion with PRF
7
+ * evaluation, and returns a hex-encoded passphrase suitable for use as
8
+ * walletPassphrase in signing calls.
9
+ */
10
+ export declare function derivePasskeyPrfKey(params: {
11
+ bitgo: BitGoBase;
12
+ wallet: IWallet;
13
+ provider: WebAuthnProvider;
14
+ }): Promise<string>;
15
+ //# sourceMappingURL=derivePasskeyPrfKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derivePasskeyPrfKey.d.ts","sourceRoot":"","sources":["../../src/derivePasskeyPrfKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAoD,MAAM,iBAAiB,CAAC;AAG5G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA8BxD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,gBAAgB,CAAC;CAC5B,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ClB"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.derivePasskeyPrfKey = derivePasskeyPrfKey;
4
+ const prfHelpers_1 = require("./prfHelpers");
5
+ const derivePassword_1 = require("./derivePassword");
6
+ function webauthnDevicesFromKeychain(keychain) {
7
+ const lower = keychain.webauthnDevices;
8
+ if (lower !== undefined && lower.length > 0) {
9
+ return lower;
10
+ }
11
+ const upper = keychain.webAuthnDevices;
12
+ if (upper !== undefined && upper.length > 0) {
13
+ return upper;
14
+ }
15
+ return undefined;
16
+ }
17
+ function challengeFromAuthResponse(body) {
18
+ if (typeof body !== 'object' || body === null) {
19
+ throw new Error('Invalid assertion challenge response');
20
+ }
21
+ const rec = body;
22
+ if (typeof rec.challenge !== 'string') {
23
+ throw new Error('Invalid assertion challenge response');
24
+ }
25
+ return rec.challenge;
26
+ }
27
+ /**
28
+ * Derives a wallet passphrase from a passkey PRF output.
29
+ *
30
+ * Fetches the wallet's user keychain, triggers a WebAuthn assertion with PRF
31
+ * evaluation, and returns a hex-encoded passphrase suitable for use as
32
+ * walletPassphrase in signing calls.
33
+ */
34
+ async function derivePasskeyPrfKey(params) {
35
+ const { bitgo, wallet, provider } = params;
36
+ const keychain = await wallet.getEncryptedUserKeychain();
37
+ const devices = webauthnDevicesFromKeychain(keychain);
38
+ if (!devices || devices.length === 0) {
39
+ throw new Error('No passkey devices available');
40
+ }
41
+ const { evalByCredential } = (0, prfHelpers_1.buildEvalByCredential)(devices);
42
+ if (Object.keys(evalByCredential).length === 0) {
43
+ throw new Error('No passkey devices available with a valid PRF salt');
44
+ }
45
+ const challenge = challengeFromAuthResponse(await bitgo.get(bitgo.url('/user/otp/webauthn/auth', 2)).result());
46
+ const allowCredentials = Object.keys(evalByCredential).map((credId) => {
47
+ const nodeBuf = Buffer.from(credId.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
48
+ const id = nodeBuf.buffer.slice(nodeBuf.byteOffset, nodeBuf.byteOffset + nodeBuf.byteLength);
49
+ return {
50
+ type: 'public-key',
51
+ id,
52
+ };
53
+ });
54
+ const publicKey = {
55
+ challenge: new Uint8Array(Buffer.from(challenge, 'base64')),
56
+ allowCredentials,
57
+ };
58
+ const result = await provider.get({
59
+ publicKey,
60
+ evalByCredential,
61
+ });
62
+ (0, prfHelpers_1.matchDeviceByCredentialId)(devices, result.credentialId);
63
+ if (!result.prfResult) {
64
+ throw new Error('PRF output was not returned by the authenticator');
65
+ }
66
+ return (0, derivePassword_1.derivePassword)(result.prfResult);
67
+ }
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVyaXZlUGFzc2tleVByZktleS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kZXJpdmVQYXNza2V5UHJmS2V5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBd0NBLGtEQWdEQztBQXZGRCw2Q0FBZ0Y7QUFDaEYscURBQWtEO0FBUWxELFNBQVMsMkJBQTJCLENBQUMsUUFBOEI7SUFDakUsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGVBQWUsQ0FBQztJQUN2QyxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM1QyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsZUFBZSxDQUFDO0lBQ3ZDLElBQUksS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQzVDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRCxTQUFTLHlCQUF5QixDQUFDLElBQWE7SUFDOUMsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQzlDLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBQ0QsTUFBTSxHQUFHLEdBQUcsSUFBK0IsQ0FBQztJQUM1QyxJQUFJLE9BQU8sR0FBRyxDQUFDLFNBQVMsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUN0QyxNQUFNLElBQUksS0FBSyxDQUFDLHNDQUFzQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFDLFNBQVMsQ0FBQztBQUN2QixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0ksS0FBSyxVQUFVLG1CQUFtQixDQUFDLE1BSXpDO0lBQ0MsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBRTNDLE1BQU0sUUFBUSxHQUF5QixNQUFNLE1BQU0sQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO0lBQy9FLE1BQU0sT0FBTyxHQUFHLDJCQUEyQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRXRELElBQUksQ0FBQyxPQUFPLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNyQyxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVELE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLElBQUEsa0NBQXFCLEVBQUMsT0FBTyxDQUFDLENBQUM7SUFFNUQsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxLQUFLLENBQUMsb0RBQW9ELENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQsTUFBTSxTQUFTLEdBQUcseUJBQXlCLENBQUMsTUFBTSxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBRS9HLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO1FBQ3BFLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNwRixNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzdGLE9BQU87WUFDTCxJQUFJLEVBQUUsWUFBcUI7WUFDM0IsRUFBRTtTQUNILENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFzQztRQUNuRCxTQUFTLEVBQUUsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDM0QsZ0JBQWdCO0tBQ2pCLENBQUM7SUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQyxHQUFHLENBQUM7UUFDaEMsU0FBUztRQUNULGdCQUFnQjtLQUNqQixDQUFDLENBQUM7SUFFSCxJQUFBLHNDQUF5QixFQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFFeEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLGtEQUFrRCxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUVELE9BQU8sSUFBQSwrQkFBYyxFQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUMxQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBCaXRHb0Jhc2UsIElXYWxsZXQsIEtleWNoYWluV2ViYXV0aG5EZXZpY2UsIEtleWNoYWluV2l0aEVuY3J5cHRlZFBydiB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBidWlsZEV2YWxCeUNyZWRlbnRpYWwsIG1hdGNoRGV2aWNlQnlDcmVkZW50aWFsSWQgfSBmcm9tICcuL3ByZkhlbHBlcnMnO1xuaW1wb3J0IHsgZGVyaXZlUGFzc3dvcmQgfSBmcm9tICcuL2Rlcml2ZVBhc3N3b3JkJztcbmltcG9ydCB0eXBlIHsgV2ViQXV0aG5Qcm92aWRlciB9IGZyb20gJy4vd2ViQXV0aG5UeXBlcyc7XG5cbi8qKiBBUEkgcGF5bG9hZHMgbWF5IHVzZSBlaXRoZXIgc3BlbGxpbmcgZm9yIHRoZSB3ZWJhdXRobiBkZXZpY2UgbGlzdC4gKi9cbnR5cGUgVXNlcktleWNoYWluUmVzcG9uc2UgPSBLZXljaGFpbldpdGhFbmNyeXB0ZWRQcnYgJiB7XG4gIHdlYkF1dGhuRGV2aWNlcz86IEtleWNoYWluV2ViYXV0aG5EZXZpY2VbXTtcbn07XG5cbmZ1bmN0aW9uIHdlYmF1dGhuRGV2aWNlc0Zyb21LZXljaGFpbihrZXljaGFpbjogVXNlcktleWNoYWluUmVzcG9uc2UpOiBLZXljaGFpbldlYmF1dGhuRGV2aWNlW10gfCB1bmRlZmluZWQge1xuICBjb25zdCBsb3dlciA9IGtleWNoYWluLndlYmF1dGhuRGV2aWNlcztcbiAgaWYgKGxvd2VyICE9PSB1bmRlZmluZWQgJiYgbG93ZXIubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiBsb3dlcjtcbiAgfVxuICBjb25zdCB1cHBlciA9IGtleWNoYWluLndlYkF1dGhuRGV2aWNlcztcbiAgaWYgKHVwcGVyICE9PSB1bmRlZmluZWQgJiYgdXBwZXIubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiB1cHBlcjtcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBjaGFsbGVuZ2VGcm9tQXV0aFJlc3BvbnNlKGJvZHk6IHVua25vd24pOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIGJvZHkgIT09ICdvYmplY3QnIHx8IGJvZHkgPT09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYXNzZXJ0aW9uIGNoYWxsZW5nZSByZXNwb25zZScpO1xuICB9XG4gIGNvbnN0IHJlYyA9IGJvZHkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGlmICh0eXBlb2YgcmVjLmNoYWxsZW5nZSAhPT0gJ3N0cmluZycpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYXNzZXJ0aW9uIGNoYWxsZW5nZSByZXNwb25zZScpO1xuICB9XG4gIHJldHVybiByZWMuY2hhbGxlbmdlO1xufVxuXG4vKipcbiAqIERlcml2ZXMgYSB3YWxsZXQgcGFzc3BocmFzZSBmcm9tIGEgcGFzc2tleSBQUkYgb3V0cHV0LlxuICpcbiAqIEZldGNoZXMgdGhlIHdhbGxldCdzIHVzZXIga2V5Y2hhaW4sIHRyaWdnZXJzIGEgV2ViQXV0aG4gYXNzZXJ0aW9uIHdpdGggUFJGXG4gKiBldmFsdWF0aW9uLCBhbmQgcmV0dXJucyBhIGhleC1lbmNvZGVkIHBhc3NwaHJhc2Ugc3VpdGFibGUgZm9yIHVzZSBhc1xuICogd2FsbGV0UGFzc3BocmFzZSBpbiBzaWduaW5nIGNhbGxzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVyaXZlUGFzc2tleVByZktleShwYXJhbXM6IHtcbiAgYml0Z286IEJpdEdvQmFzZTtcbiAgd2FsbGV0OiBJV2FsbGV0O1xuICBwcm92aWRlcjogV2ViQXV0aG5Qcm92aWRlcjtcbn0pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB7IGJpdGdvLCB3YWxsZXQsIHByb3ZpZGVyIH0gPSBwYXJhbXM7XG5cbiAgY29uc3Qga2V5Y2hhaW46IFVzZXJLZXljaGFpblJlc3BvbnNlID0gYXdhaXQgd2FsbGV0LmdldEVuY3J5cHRlZFVzZXJLZXljaGFpbigpO1xuICBjb25zdCBkZXZpY2VzID0gd2ViYXV0aG5EZXZpY2VzRnJvbUtleWNoYWluKGtleWNoYWluKTtcblxuICBpZiAoIWRldmljZXMgfHwgZGV2aWNlcy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHBhc3NrZXkgZGV2aWNlcyBhdmFpbGFibGUnKTtcbiAgfVxuXG4gIGNvbnN0IHsgZXZhbEJ5Q3JlZGVudGlhbCB9ID0gYnVpbGRFdmFsQnlDcmVkZW50aWFsKGRldmljZXMpO1xuXG4gIGlmIChPYmplY3Qua2V5cyhldmFsQnlDcmVkZW50aWFsKS5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHBhc3NrZXkgZGV2aWNlcyBhdmFpbGFibGUgd2l0aCBhIHZhbGlkIFBSRiBzYWx0Jyk7XG4gIH1cblxuICBjb25zdCBjaGFsbGVuZ2UgPSBjaGFsbGVuZ2VGcm9tQXV0aFJlc3BvbnNlKGF3YWl0IGJpdGdvLmdldChiaXRnby51cmwoJy91c2VyL290cC93ZWJhdXRobi9hdXRoJywgMikpLnJlc3VsdCgpKTtcblxuICBjb25zdCBhbGxvd0NyZWRlbnRpYWxzID0gT2JqZWN0LmtleXMoZXZhbEJ5Q3JlZGVudGlhbCkubWFwKChjcmVkSWQpID0+IHtcbiAgICBjb25zdCBub2RlQnVmID0gQnVmZmVyLmZyb20oY3JlZElkLnJlcGxhY2UoLy0vZywgJysnKS5yZXBsYWNlKC9fL2csICcvJyksICdiYXNlNjQnKTtcbiAgICBjb25zdCBpZCA9IG5vZGVCdWYuYnVmZmVyLnNsaWNlKG5vZGVCdWYuYnl0ZU9mZnNldCwgbm9kZUJ1Zi5ieXRlT2Zmc2V0ICsgbm9kZUJ1Zi5ieXRlTGVuZ3RoKTtcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogJ3B1YmxpYy1rZXknIGFzIGNvbnN0LFxuICAgICAgaWQsXG4gICAgfTtcbiAgfSk7XG5cbiAgY29uc3QgcHVibGljS2V5OiBQdWJsaWNLZXlDcmVkZW50aWFsUmVxdWVzdE9wdGlvbnMgPSB7XG4gICAgY2hhbGxlbmdlOiBuZXcgVWludDhBcnJheShCdWZmZXIuZnJvbShjaGFsbGVuZ2UsICdiYXNlNjQnKSksXG4gICAgYWxsb3dDcmVkZW50aWFscyxcbiAgfTtcblxuICBjb25zdCByZXN1bHQgPSBhd2FpdCBwcm92aWRlci5nZXQoe1xuICAgIHB1YmxpY0tleSxcbiAgICBldmFsQnlDcmVkZW50aWFsLFxuICB9KTtcblxuICBtYXRjaERldmljZUJ5Q3JlZGVudGlhbElkKGRldmljZXMsIHJlc3VsdC5jcmVkZW50aWFsSWQpO1xuXG4gIGlmICghcmVzdWx0LnByZlJlc3VsdCkge1xuICAgIHRocm93IG5ldyBFcnJvcignUFJGIG91dHB1dCB3YXMgbm90IHJldHVybmVkIGJ5IHRoZSBhdXRoZW50aWNhdG9yJyk7XG4gIH1cblxuICByZXR1cm4gZGVyaXZlUGFzc3dvcmQocmVzdWx0LnByZlJlc3VsdCk7XG59XG4iXX0=
@@ -1,5 +1,10 @@
1
1
  export { derivePassword } from './derivePassword';
2
+ export { registerPasskey } from './registerPasskey';
2
3
  export { deriveEnterpriseSalt } from './deriveEnterpriseSalt';
3
4
  export { buildEvalByCredential, matchDeviceByCredentialId } from './prfHelpers';
5
+ export { removePasskeyFromAccount } from './removePasskeyFromAccount';
4
6
  export type { WebAuthnOtpDevice, PasskeyAuthResult, PasskeyGetOptions, WebAuthnProvider } from './webAuthnTypes';
7
+ export { removePasskeyFromWallet } from './removePasskeyFromWallet';
8
+ export { attachPasskeyToWallet } from './attachPasskeyToWallet';
9
+ export { derivePasskeyPrfKey } from './derivePasskeyPrfKey';
5
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,11 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.matchDeviceByCredentialId = exports.buildEvalByCredential = exports.deriveEnterpriseSalt = exports.derivePassword = void 0;
3
+ exports.derivePasskeyPrfKey = exports.attachPasskeyToWallet = exports.removePasskeyFromWallet = exports.removePasskeyFromAccount = exports.matchDeviceByCredentialId = exports.buildEvalByCredential = exports.deriveEnterpriseSalt = exports.registerPasskey = exports.derivePassword = void 0;
4
4
  var derivePassword_1 = require("./derivePassword");
5
5
  Object.defineProperty(exports, "derivePassword", { enumerable: true, get: function () { return derivePassword_1.derivePassword; } });
6
+ var registerPasskey_1 = require("./registerPasskey");
7
+ Object.defineProperty(exports, "registerPasskey", { enumerable: true, get: function () { return registerPasskey_1.registerPasskey; } });
6
8
  var deriveEnterpriseSalt_1 = require("./deriveEnterpriseSalt");
7
9
  Object.defineProperty(exports, "deriveEnterpriseSalt", { enumerable: true, get: function () { return deriveEnterpriseSalt_1.deriveEnterpriseSalt; } });
8
10
  var prfHelpers_1 = require("./prfHelpers");
9
11
  Object.defineProperty(exports, "buildEvalByCredential", { enumerable: true, get: function () { return prfHelpers_1.buildEvalByCredential; } });
10
12
  Object.defineProperty(exports, "matchDeviceByCredentialId", { enumerable: true, get: function () { return prfHelpers_1.matchDeviceByCredentialId; } });
11
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbURBQWtEO0FBQXpDLGdIQUFBLGNBQWMsT0FBQTtBQUN2QiwrREFBOEQ7QUFBckQsNEhBQUEsb0JBQW9CLE9BQUE7QUFDN0IsMkNBQWdGO0FBQXZFLG1IQUFBLHFCQUFxQixPQUFBO0FBQUUsdUhBQUEseUJBQXlCLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgeyBkZXJpdmVQYXNzd29yZCB9IGZyb20gJy4vZGVyaXZlUGFzc3dvcmQnO1xuZXhwb3J0IHsgZGVyaXZlRW50ZXJwcmlzZVNhbHQgfSBmcm9tICcuL2Rlcml2ZUVudGVycHJpc2VTYWx0JztcbmV4cG9ydCB7IGJ1aWxkRXZhbEJ5Q3JlZGVudGlhbCwgbWF0Y2hEZXZpY2VCeUNyZWRlbnRpYWxJZCB9IGZyb20gJy4vcHJmSGVscGVycyc7XG5leHBvcnQgdHlwZSB7IFdlYkF1dGhuT3RwRGV2aWNlLCBQYXNza2V5QXV0aFJlc3VsdCwgUGFzc2tleUdldE9wdGlvbnMsIFdlYkF1dGhuUHJvdmlkZXIgfSBmcm9tICcuL3dlYkF1dGhuVHlwZXMnO1xuIl19
13
+ var removePasskeyFromAccount_1 = require("./removePasskeyFromAccount");
14
+ Object.defineProperty(exports, "removePasskeyFromAccount", { enumerable: true, get: function () { return removePasskeyFromAccount_1.removePasskeyFromAccount; } });
15
+ var removePasskeyFromWallet_1 = require("./removePasskeyFromWallet");
16
+ Object.defineProperty(exports, "removePasskeyFromWallet", { enumerable: true, get: function () { return removePasskeyFromWallet_1.removePasskeyFromWallet; } });
17
+ var attachPasskeyToWallet_1 = require("./attachPasskeyToWallet");
18
+ Object.defineProperty(exports, "attachPasskeyToWallet", { enumerable: true, get: function () { return attachPasskeyToWallet_1.attachPasskeyToWallet; } });
19
+ var derivePasskeyPrfKey_1 = require("./derivePasskeyPrfKey");
20
+ Object.defineProperty(exports, "derivePasskeyPrfKey", { enumerable: true, get: function () { return derivePasskeyPrfKey_1.derivePasskeyPrfKey; } });
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbURBQWtEO0FBQXpDLGdIQUFBLGNBQWMsT0FBQTtBQUN2QixxREFBb0Q7QUFBM0Msa0hBQUEsZUFBZSxPQUFBO0FBQ3hCLCtEQUE4RDtBQUFyRCw0SEFBQSxvQkFBb0IsT0FBQTtBQUM3QiwyQ0FBZ0Y7QUFBdkUsbUhBQUEscUJBQXFCLE9BQUE7QUFBRSx1SEFBQSx5QkFBeUIsT0FBQTtBQUN6RCx1RUFBc0U7QUFBN0Qsb0lBQUEsd0JBQXdCLE9BQUE7QUFFakMscUVBQW9FO0FBQTNELGtJQUFBLHVCQUF1QixPQUFBO0FBQ2hDLGlFQUFnRTtBQUF2RCw4SEFBQSxxQkFBcUIsT0FBQTtBQUM5Qiw2REFBNEQ7QUFBbkQsMEhBQUEsbUJBQW1CLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgeyBkZXJpdmVQYXNzd29yZCB9IGZyb20gJy4vZGVyaXZlUGFzc3dvcmQnO1xuZXhwb3J0IHsgcmVnaXN0ZXJQYXNza2V5IH0gZnJvbSAnLi9yZWdpc3RlclBhc3NrZXknO1xuZXhwb3J0IHsgZGVyaXZlRW50ZXJwcmlzZVNhbHQgfSBmcm9tICcuL2Rlcml2ZUVudGVycHJpc2VTYWx0JztcbmV4cG9ydCB7IGJ1aWxkRXZhbEJ5Q3JlZGVudGlhbCwgbWF0Y2hEZXZpY2VCeUNyZWRlbnRpYWxJZCB9IGZyb20gJy4vcHJmSGVscGVycyc7XG5leHBvcnQgeyByZW1vdmVQYXNza2V5RnJvbUFjY291bnQgfSBmcm9tICcuL3JlbW92ZVBhc3NrZXlGcm9tQWNjb3VudCc7XG5leHBvcnQgdHlwZSB7IFdlYkF1dGhuT3RwRGV2aWNlLCBQYXNza2V5QXV0aFJlc3VsdCwgUGFzc2tleUdldE9wdGlvbnMsIFdlYkF1dGhuUHJvdmlkZXIgfSBmcm9tICcuL3dlYkF1dGhuVHlwZXMnO1xuZXhwb3J0IHsgcmVtb3ZlUGFzc2tleUZyb21XYWxsZXQgfSBmcm9tICcuL3JlbW92ZVBhc3NrZXlGcm9tV2FsbGV0JztcbmV4cG9ydCB7IGF0dGFjaFBhc3NrZXlUb1dhbGxldCB9IGZyb20gJy4vYXR0YWNoUGFzc2tleVRvV2FsbGV0JztcbmV4cG9ydCB7IGRlcml2ZVBhc3NrZXlQcmZLZXkgfSBmcm9tICcuL2Rlcml2ZVBhc3NrZXlQcmZLZXknO1xuIl19
@@ -1 +1 @@
1
- {"version":3,"file":"prfHelpers.d.ts","sourceRoot":"","sources":["../../src/prfHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG;IAChE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC7C,CAYA;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,cAAc,CAMzG"}
1
+ {"version":3,"file":"prfHelpers.d.ts","sourceRoot":"","sources":["../../src/prfHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG;IAChE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC7C,CA0BA;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,cAAc,CAQzG"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildEvalByCredential = buildEvalByCredential;
4
4
  exports.matchDeviceByCredentialId = matchDeviceByCredentialId;
5
+ const base64url_1 = require("./base64url");
5
6
  /**
6
7
  * Builds the PRF eval map and credential-to-device lookup from a wallet
7
8
  * keychain's webauthn devices. Devices without a prfSalt are skipped.
@@ -13,8 +14,20 @@ function buildEvalByCredential(devices) {
13
14
  if (!device.prfSalt)
14
15
  continue;
15
16
  const { credID } = device.authenticatorInfo;
16
- evalByCredential[credID] = device.prfSalt;
17
- credIdToDevice.set(credID, device);
17
+ // Normalise credID to base64url (no padding, URL-safe chars) so it matches
18
+ // the key format used by attachPasskeyToWallet (device.credentialId from the
19
+ // browser, which is already base64url). The WebAuthn PRF extension looks up
20
+ // the selected credential's ID against evalByCredential keys — if the encoding
21
+ // differs (e.g. standard base64 with padding/+/), the lookup silently fails and
22
+ // PRF evaluates with no salt, producing a different output.
23
+ const credIdBase64url = (0, base64url_1.toBase64Url)(credID);
24
+ // Pass prfSalt through as-is (base64url). attachPasskeyToWallet writes the
25
+ // server-stored salt in the same encoding and feeds the same string to
26
+ // the PRF extension at attach time, so both paths produce the same salt
27
+ // bytes — provided the WebAuthn provider layer decodes base64url before
28
+ // handing the bytes to navigator.credentials.get.
29
+ evalByCredential[credIdBase64url] = device.prfSalt;
30
+ credIdToDevice.set(credIdBase64url, device);
18
31
  }
19
32
  return { evalByCredential, credIdToDevice };
20
33
  }
@@ -23,10 +36,12 @@ function buildEvalByCredential(devices) {
23
36
  * @throws if no matching device is found
24
37
  */
25
38
  function matchDeviceByCredentialId(devices, credentialId) {
26
- const device = devices.find((d) => d.authenticatorInfo.credID === credentialId);
39
+ // Normalise both sides to base64url so padding/char differences don't break matching.
40
+ const needle = (0, base64url_1.toBase64Url)(credentialId);
41
+ const device = devices.find((d) => (0, base64url_1.toBase64Url)(d.authenticatorInfo.credID) === needle);
27
42
  if (!device) {
28
43
  throw new Error('Could not identify which passkey device was used');
29
44
  }
30
45
  return device;
31
46
  }
32
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJmSGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcmZIZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBTUEsc0RBZUM7QUFNRCw4REFNQztBQS9CRDs7O0dBR0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxPQUF5QjtJQUk3RCxNQUFNLGdCQUFnQixHQUEyQixFQUFFLENBQUM7SUFDcEQsTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLEVBQTBCLENBQUM7SUFFekQsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU87WUFBRSxTQUFTO1FBQzlCLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUM7UUFDNUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQztRQUMxQyxjQUFjLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxDQUFDO0FBQzlDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQix5QkFBeUIsQ0FBQyxPQUF5QixFQUFFLFlBQW9CO0lBQ3ZGLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEtBQUssWUFBWSxDQUFDLENBQUM7SUFDaEYsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBXZWJhdXRobkRldmljZSB9IGZyb20gJ0BiaXRnby9wdWJsaWMtdHlwZXMnO1xuXG4vKipcbiAqIEJ1aWxkcyB0aGUgUFJGIGV2YWwgbWFwIGFuZCBjcmVkZW50aWFsLXRvLWRldmljZSBsb29rdXAgZnJvbSBhIHdhbGxldFxuICoga2V5Y2hhaW4ncyB3ZWJhdXRobiBkZXZpY2VzLiBEZXZpY2VzIHdpdGhvdXQgYSBwcmZTYWx0IGFyZSBza2lwcGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRFdmFsQnlDcmVkZW50aWFsKGRldmljZXM6IFdlYmF1dGhuRGV2aWNlW10pOiB7XG4gIGV2YWxCeUNyZWRlbnRpYWw6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGNyZWRJZFRvRGV2aWNlOiBNYXA8c3RyaW5nLCBXZWJhdXRobkRldmljZT47XG59IHtcbiAgY29uc3QgZXZhbEJ5Q3JlZGVudGlhbDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBjb25zdCBjcmVkSWRUb0RldmljZSA9IG5ldyBNYXA8c3RyaW5nLCBXZWJhdXRobkRldmljZT4oKTtcblxuICBmb3IgKGNvbnN0IGRldmljZSBvZiBkZXZpY2VzKSB7XG4gICAgaWYgKCFkZXZpY2UucHJmU2FsdCkgY29udGludWU7XG4gICAgY29uc3QgeyBjcmVkSUQgfSA9IGRldmljZS5hdXRoZW50aWNhdG9ySW5mbztcbiAgICBldmFsQnlDcmVkZW50aWFsW2NyZWRJRF0gPSBkZXZpY2UucHJmU2FsdDtcbiAgICBjcmVkSWRUb0RldmljZS5zZXQoY3JlZElELCBkZXZpY2UpO1xuICB9XG5cbiAgcmV0dXJuIHsgZXZhbEJ5Q3JlZGVudGlhbCwgY3JlZElkVG9EZXZpY2UgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBXZWJhdXRobkRldmljZSBtYXRjaGluZyB0aGUgZ2l2ZW4gY3JlZGVudGlhbCBJRC5cbiAqIEB0aHJvd3MgaWYgbm8gbWF0Y2hpbmcgZGV2aWNlIGlzIGZvdW5kXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXRjaERldmljZUJ5Q3JlZGVudGlhbElkKGRldmljZXM6IFdlYmF1dGhuRGV2aWNlW10sIGNyZWRlbnRpYWxJZDogc3RyaW5nKTogV2ViYXV0aG5EZXZpY2Uge1xuICBjb25zdCBkZXZpY2UgPSBkZXZpY2VzLmZpbmQoKGQpID0+IGQuYXV0aGVudGljYXRvckluZm8uY3JlZElEID09PSBjcmVkZW50aWFsSWQpO1xuICBpZiAoIWRldmljZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGlkZW50aWZ5IHdoaWNoIHBhc3NrZXkgZGV2aWNlIHdhcyB1c2VkJyk7XG4gIH1cbiAgcmV0dXJuIGRldmljZTtcbn1cbiJdfQ==
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJmSGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcmZIZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBT0Esc0RBNkJDO0FBTUQsOERBUUM7QUFqREQsMkNBQTBDO0FBRTFDOzs7R0FHRztBQUNILFNBQWdCLHFCQUFxQixDQUFDLE9BQXlCO0lBSTdELE1BQU0sZ0JBQWdCLEdBQTJCLEVBQUUsQ0FBQztJQUNwRCxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBMEIsQ0FBQztJQUV6RCxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTztZQUFFLFNBQVM7UUFDOUIsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQztRQUU1QywyRUFBMkU7UUFDM0UsNkVBQTZFO1FBQzdFLDRFQUE0RTtRQUM1RSwrRUFBK0U7UUFDL0UsZ0ZBQWdGO1FBQ2hGLDREQUE0RDtRQUM1RCxNQUFNLGVBQWUsR0FBRyxJQUFBLHVCQUFXLEVBQUMsTUFBTSxDQUFDLENBQUM7UUFFNUMsMkVBQTJFO1FBQzNFLHVFQUF1RTtRQUN2RSx3RUFBd0U7UUFDeEUsd0VBQXdFO1FBQ3hFLGtEQUFrRDtRQUNsRCxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO1FBQ25ELGNBQWMsQ0FBQyxHQUFHLENBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLENBQUM7QUFDOUMsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLE9BQXlCLEVBQUUsWUFBb0I7SUFDdkYsc0ZBQXNGO0lBQ3RGLE1BQU0sTUFBTSxHQUFHLElBQUEsdUJBQVcsRUFBQyxZQUFZLENBQUMsQ0FBQztJQUN6QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFBLHVCQUFXLEVBQUMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxLQUFLLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZGLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgV2ViYXV0aG5EZXZpY2UgfSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCB7IHRvQmFzZTY0VXJsIH0gZnJvbSAnLi9iYXNlNjR1cmwnO1xuXG4vKipcbiAqIEJ1aWxkcyB0aGUgUFJGIGV2YWwgbWFwIGFuZCBjcmVkZW50aWFsLXRvLWRldmljZSBsb29rdXAgZnJvbSBhIHdhbGxldFxuICoga2V5Y2hhaW4ncyB3ZWJhdXRobiBkZXZpY2VzLiBEZXZpY2VzIHdpdGhvdXQgYSBwcmZTYWx0IGFyZSBza2lwcGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRFdmFsQnlDcmVkZW50aWFsKGRldmljZXM6IFdlYmF1dGhuRGV2aWNlW10pOiB7XG4gIGV2YWxCeUNyZWRlbnRpYWw6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGNyZWRJZFRvRGV2aWNlOiBNYXA8c3RyaW5nLCBXZWJhdXRobkRldmljZT47XG59IHtcbiAgY29uc3QgZXZhbEJ5Q3JlZGVudGlhbDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBjb25zdCBjcmVkSWRUb0RldmljZSA9IG5ldyBNYXA8c3RyaW5nLCBXZWJhdXRobkRldmljZT4oKTtcblxuICBmb3IgKGNvbnN0IGRldmljZSBvZiBkZXZpY2VzKSB7XG4gICAgaWYgKCFkZXZpY2UucHJmU2FsdCkgY29udGludWU7XG4gICAgY29uc3QgeyBjcmVkSUQgfSA9IGRldmljZS5hdXRoZW50aWNhdG9ySW5mbztcblxuICAgIC8vIE5vcm1hbGlzZSBjcmVkSUQgdG8gYmFzZTY0dXJsIChubyBwYWRkaW5nLCBVUkwtc2FmZSBjaGFycykgc28gaXQgbWF0Y2hlc1xuICAgIC8vIHRoZSBrZXkgZm9ybWF0IHVzZWQgYnkgYXR0YWNoUGFzc2tleVRvV2FsbGV0IChkZXZpY2UuY3JlZGVudGlhbElkIGZyb20gdGhlXG4gICAgLy8gYnJvd3Nlciwgd2hpY2ggaXMgYWxyZWFkeSBiYXNlNjR1cmwpLiBUaGUgV2ViQXV0aG4gUFJGIGV4dGVuc2lvbiBsb29rcyB1cFxuICAgIC8vIHRoZSBzZWxlY3RlZCBjcmVkZW50aWFsJ3MgSUQgYWdhaW5zdCBldmFsQnlDcmVkZW50aWFsIGtleXMg4oCUIGlmIHRoZSBlbmNvZGluZ1xuICAgIC8vIGRpZmZlcnMgKGUuZy4gc3RhbmRhcmQgYmFzZTY0IHdpdGggcGFkZGluZy8rLyksIHRoZSBsb29rdXAgc2lsZW50bHkgZmFpbHMgYW5kXG4gICAgLy8gUFJGIGV2YWx1YXRlcyB3aXRoIG5vIHNhbHQsIHByb2R1Y2luZyBhIGRpZmZlcmVudCBvdXRwdXQuXG4gICAgY29uc3QgY3JlZElkQmFzZTY0dXJsID0gdG9CYXNlNjRVcmwoY3JlZElEKTtcblxuICAgIC8vIFBhc3MgcHJmU2FsdCB0aHJvdWdoIGFzLWlzIChiYXNlNjR1cmwpLiBhdHRhY2hQYXNza2V5VG9XYWxsZXQgd3JpdGVzIHRoZVxuICAgIC8vIHNlcnZlci1zdG9yZWQgc2FsdCBpbiB0aGUgc2FtZSBlbmNvZGluZyBhbmQgZmVlZHMgdGhlIHNhbWUgc3RyaW5nIHRvXG4gICAgLy8gdGhlIFBSRiBleHRlbnNpb24gYXQgYXR0YWNoIHRpbWUsIHNvIGJvdGggcGF0aHMgcHJvZHVjZSB0aGUgc2FtZSBzYWx0XG4gICAgLy8gYnl0ZXMg4oCUIHByb3ZpZGVkIHRoZSBXZWJBdXRobiBwcm92aWRlciBsYXllciBkZWNvZGVzIGJhc2U2NHVybCBiZWZvcmVcbiAgICAvLyBoYW5kaW5nIHRoZSBieXRlcyB0byBuYXZpZ2F0b3IuY3JlZGVudGlhbHMuZ2V0LlxuICAgIGV2YWxCeUNyZWRlbnRpYWxbY3JlZElkQmFzZTY0dXJsXSA9IGRldmljZS5wcmZTYWx0O1xuICAgIGNyZWRJZFRvRGV2aWNlLnNldChjcmVkSWRCYXNlNjR1cmwsIGRldmljZSk7XG4gIH1cblxuICByZXR1cm4geyBldmFsQnlDcmVkZW50aWFsLCBjcmVkSWRUb0RldmljZSB9O1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIFdlYmF1dGhuRGV2aWNlIG1hdGNoaW5nIHRoZSBnaXZlbiBjcmVkZW50aWFsIElELlxuICogQHRocm93cyBpZiBubyBtYXRjaGluZyBkZXZpY2UgaXMgZm91bmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hdGNoRGV2aWNlQnlDcmVkZW50aWFsSWQoZGV2aWNlczogV2ViYXV0aG5EZXZpY2VbXSwgY3JlZGVudGlhbElkOiBzdHJpbmcpOiBXZWJhdXRobkRldmljZSB7XG4gIC8vIE5vcm1hbGlzZSBib3RoIHNpZGVzIHRvIGJhc2U2NHVybCBzbyBwYWRkaW5nL2NoYXIgZGlmZmVyZW5jZXMgZG9uJ3QgYnJlYWsgbWF0Y2hpbmcuXG4gIGNvbnN0IG5lZWRsZSA9IHRvQmFzZTY0VXJsKGNyZWRlbnRpYWxJZCk7XG4gIGNvbnN0IGRldmljZSA9IGRldmljZXMuZmluZCgoZCkgPT4gdG9CYXNlNjRVcmwoZC5hdXRoZW50aWNhdG9ySW5mby5jcmVkSUQpID09PSBuZWVkbGUpO1xuICBpZiAoIWRldmljZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGlkZW50aWZ5IHdoaWNoIHBhc3NrZXkgZGV2aWNlIHdhcyB1c2VkJyk7XG4gIH1cbiAgcmV0dXJuIGRldmljZTtcbn1cbiJdfQ==
@@ -0,0 +1,10 @@
1
+ import { BitGoBase } from '@bitgo/sdk-core';
2
+ import { WebAuthnOtpDevice, WebAuthnProvider } from './webAuthnTypes';
3
+ export declare function registerPasskey(params: {
4
+ bitgo: BitGoBase;
5
+ provider: WebAuthnProvider;
6
+ label: string;
7
+ }): Promise<WebAuthnOtpDevice & {
8
+ prfSupported: boolean;
9
+ }>;
10
+ //# sourceMappingURL=registerPasskey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registerPasskey.d.ts","sourceRoot":"","sources":["../../src/registerPasskey.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAoEtE,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,iBAAiB,GAAG;IAAE,YAAY,EAAE,OAAO,CAAA;CAAE,CAAC,CA8DzD"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerPasskey = registerPasskey;
4
+ const base64url_1 = require("./base64url");
5
+ /**
6
+ * Recursively converts a PublicKeyCredential (or any value it contains) to a
7
+ * JSON-serialisable representation, encoding ArrayBuffers as base64url strings.
8
+ */
9
+ function publicKeyCredentialToJSON(value) {
10
+ if (Array.isArray(value)) {
11
+ return value.map(publicKeyCredentialToJSON);
12
+ }
13
+ if (value instanceof ArrayBuffer) {
14
+ return (0, base64url_1.bufferToBase64Url)(value);
15
+ }
16
+ if (ArrayBuffer.isView(value)) {
17
+ return (0, base64url_1.bufferToBase64Url)(value.buffer);
18
+ }
19
+ if (value instanceof Object) {
20
+ const result = {};
21
+ // Use for...in to enumerate DOM object properties (non-enumerable own + inherited)
22
+ for (const key in value) {
23
+ result[key] = publicKeyCredentialToJSON(value[key]);
24
+ }
25
+ return result;
26
+ }
27
+ return value;
28
+ }
29
+ /**
30
+ * Decodes excluded credential IDs from base64 strings to ArrayBuffers.
31
+ * The WebAuthn API requires BufferSource values, not base64 strings.
32
+ */
33
+ function preformatExcludedCredentials(excludeCredentials) {
34
+ if (!excludeCredentials)
35
+ return [];
36
+ return excludeCredentials.map((cred) => ({
37
+ ...cred,
38
+ id: Buffer.from(cred.id, 'base64'),
39
+ }));
40
+ }
41
+ async function registerPasskey(params) {
42
+ const { bitgo, provider, label } = params;
43
+ // Step 1: Fetch server challenge (contains baseSalt)
44
+ const challenge = (await bitgo
45
+ .get(bitgo.url('/user/otp/webauthn/register', 2))
46
+ .result());
47
+ // Step 2: Pass formatted challenge to provider.create() — browser returns attestation
48
+ const attestation = await provider.create({
49
+ challenge: Buffer.from(challenge.challenge, 'base64'),
50
+ rp: challenge.rp,
51
+ user: challenge.user,
52
+ pubKeyCredParams: challenge.pubKeyCredParams,
53
+ timeout: challenge.timeout,
54
+ excludeCredentials: preformatExcludedCredentials(challenge.excludeCredentials),
55
+ authenticatorSelection: challenge.authenticatorSelection,
56
+ attestation: challenge.attestation,
57
+ extensions: challenge.extensions,
58
+ });
59
+ // Step 3: Check if PRF is supported — `prf.enabled` is set during registration
60
+ // (not `prf.results.first`, which is only present during authentication assertions)
61
+ const clientExtensionResults = attestation.getClientExtensionResults();
62
+ const prfEnabled = clientExtensionResults.prf;
63
+ const prfSupported = typeof prfEnabled === 'object' && prfEnabled !== null && prfEnabled.enabled === true;
64
+ // Step 4: Serialize the full credential using recursive base64url encoding
65
+ const otp = JSON.stringify(publicKeyCredentialToJSON(attestation));
66
+ const putBody = {
67
+ otp,
68
+ type: 'webauthn',
69
+ label,
70
+ };
71
+ if (prfSupported) {
72
+ putBody.extensions = ['prf'];
73
+ putBody.scopes = ['wallet_hot'];
74
+ }
75
+ // Step 5: PUT /api/v2/user/otp
76
+ const response = (await bitgo.put(bitgo.url('/user/otp', 2)).send(putBody).result());
77
+ // Step 6: Find the newly registered device by matching credentialId
78
+ const device = response.user.otpDevices.find((d) => d.credentialId === attestation.id);
79
+ if (!device) {
80
+ const available = response.user.otpDevices.map((d) => d.credentialId).join(', ');
81
+ throw new Error(`Registered device not found in response (credentialId: ${attestation.id}). Available: [${available}]`);
82
+ }
83
+ // Step 7: Return WebAuthnOtpDevice + prfSupported
84
+ return {
85
+ id: device.id,
86
+ credentialId: device.credentialId,
87
+ prfSalt: device.prfSalt,
88
+ isPasskey: device.isPasskey,
89
+ extensions: device.extensions,
90
+ prfSupported,
91
+ };
92
+ }
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0ZXJQYXNza2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JlZ2lzdGVyUGFzc2tleS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXNFQSwwQ0FrRUM7QUF2SUQsMkNBQWdEO0FBOEJoRDs7O0dBR0c7QUFDSCxTQUFTLHlCQUF5QixDQUFDLEtBQWM7SUFDL0MsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDekIsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUNELElBQUksS0FBSyxZQUFZLFdBQVcsRUFBRSxDQUFDO1FBQ2pDLE9BQU8sSUFBQSw2QkFBaUIsRUFBQyxLQUFLLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBQ0QsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDOUIsT0FBTyxJQUFBLDZCQUFpQixFQUFDLEtBQUssQ0FBQyxNQUFxQixDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUNELElBQUksS0FBSyxZQUFZLE1BQU0sRUFBRSxDQUFDO1FBQzVCLE1BQU0sTUFBTSxHQUE0QixFQUFFLENBQUM7UUFDM0MsbUZBQW1GO1FBQ25GLEtBQUssTUFBTSxHQUFHLElBQUksS0FBSyxFQUFFLENBQUM7WUFDeEIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLHlCQUF5QixDQUFFLEtBQWlDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuRixDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsNEJBQTRCLENBQ25DLGtCQUErRDtJQUUvRCxJQUFJLENBQUMsa0JBQWtCO1FBQUUsT0FBTyxFQUFFLENBQUM7SUFDbkMsT0FBTyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDdkMsR0FBRyxJQUFJO1FBQ1AsRUFBRSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQXVCLEVBQUUsUUFBUSxDQUEyQjtLQUNsRixDQUFDLENBQUMsQ0FBQztBQUNOLENBQUM7QUFFTSxLQUFLLFVBQVUsZUFBZSxDQUFDLE1BSXJDO0lBQ0MsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBRTFDLHFEQUFxRDtJQUNyRCxNQUFNLFNBQVMsR0FBRyxDQUFDLE1BQU0sS0FBSztTQUMzQixHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUNoRCxNQUFNLEVBQUUsQ0FBOEIsQ0FBQztJQUUxQyxzRkFBc0Y7SUFDdEYsTUFBTSxXQUFXLEdBQUcsTUFBTSxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQ3hDLFNBQVMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDO1FBQ3JELEVBQUUsRUFBRSxTQUFTLENBQUMsRUFBRTtRQUNoQixJQUFJLEVBQUUsU0FBUyxDQUFDLElBQUk7UUFDcEIsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLGdCQUFnQjtRQUM1QyxPQUFPLEVBQUUsU0FBUyxDQUFDLE9BQU87UUFDMUIsa0JBQWtCLEVBQUUsNEJBQTRCLENBQUMsU0FBUyxDQUFDLGtCQUFrQixDQUFDO1FBQzlFLHNCQUFzQixFQUFFLFNBQVMsQ0FBQyxzQkFBc0I7UUFDeEQsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO1FBQ2xDLFVBQVUsRUFBRSxTQUFTLENBQUMsVUFBVTtLQUNqQyxDQUFDLENBQUM7SUFFSCwrRUFBK0U7SUFDL0Usb0ZBQW9GO0lBQ3BGLE1BQU0sc0JBQXNCLEdBQTBDLFdBQVcsQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO0lBQzlHLE1BQU0sVUFBVSxHQUFHLHNCQUFzQixDQUFDLEdBQUcsQ0FBQztJQUM5QyxNQUFNLFlBQVksR0FBRyxPQUFPLFVBQVUsS0FBSyxRQUFRLElBQUksVUFBVSxLQUFLLElBQUksSUFBSSxVQUFVLENBQUMsT0FBTyxLQUFLLElBQUksQ0FBQztJQUUxRywyRUFBMkU7SUFDM0UsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyx5QkFBeUIsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBRW5FLE1BQU0sT0FBTyxHQUE0QjtRQUN2QyxHQUFHO1FBQ0gsSUFBSSxFQUFFLFVBQVU7UUFDaEIsS0FBSztLQUNOLENBQUM7SUFFRixJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pCLE9BQU8sQ0FBQyxVQUFVLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVELCtCQUErQjtJQUMvQixNQUFNLFFBQVEsR0FBRyxDQUFDLE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBd0IsQ0FBQztJQUU1RyxvRUFBb0U7SUFDcEUsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsWUFBWSxLQUFLLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2RixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDakYsTUFBTSxJQUFJLEtBQUssQ0FDYiwwREFBMEQsV0FBVyxDQUFDLEVBQUUsa0JBQWtCLFNBQVMsR0FBRyxDQUN2RyxDQUFDO0lBQ0osQ0FBQztJQUVELGtEQUFrRDtJQUNsRCxPQUFPO1FBQ0wsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFFO1FBQ2IsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZO1FBQ2pDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztRQUN2QixTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVM7UUFDM0IsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO1FBQzdCLFlBQVk7S0FDYixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJpdEdvQmFzZSB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBidWZmZXJUb0Jhc2U2NFVybCB9IGZyb20gJy4vYmFzZTY0dXJsJztcbmltcG9ydCB7IFdlYkF1dGhuT3RwRGV2aWNlLCBXZWJBdXRoblByb3ZpZGVyIH0gZnJvbSAnLi93ZWJBdXRoblR5cGVzJztcblxuaW50ZXJmYWNlIFJlZ2lzdGVyQ2hhbGxlbmdlUmVzcG9uc2Uge1xuICBjaGFsbGVuZ2U6IHN0cmluZztcbiAgYmFzZVNhbHQ6IHN0cmluZztcbiAgcnA6IFB1YmxpY0tleUNyZWRlbnRpYWxScEVudGl0eTtcbiAgdXNlcjogUHVibGljS2V5Q3JlZGVudGlhbFVzZXJFbnRpdHk7XG4gIHB1YktleUNyZWRQYXJhbXM6IFB1YmxpY0tleUNyZWRlbnRpYWxQYXJhbWV0ZXJzW107XG4gIHRpbWVvdXQ/OiBudW1iZXI7XG4gIGV4Y2x1ZGVDcmVkZW50aWFscz86IFB1YmxpY0tleUNyZWRlbnRpYWxEZXNjcmlwdG9yW107XG4gIGF1dGhlbnRpY2F0b3JTZWxlY3Rpb24/OiBBdXRoZW50aWNhdG9yU2VsZWN0aW9uQ3JpdGVyaWE7XG4gIGF0dGVzdGF0aW9uPzogQXR0ZXN0YXRpb25Db252ZXlhbmNlUHJlZmVyZW5jZTtcbiAgZXh0ZW5zaW9ucz86IEF1dGhlbnRpY2F0aW9uRXh0ZW5zaW9uc0NsaWVudElucHV0cztcbn1cblxuaW50ZXJmYWNlIE90cERldmljZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGNyZWRlbnRpYWxJZDogc3RyaW5nO1xuICBwcmZTYWx0Pzogc3RyaW5nO1xuICBpc1Bhc3NrZXk/OiBib29sZWFuO1xuICBleHRlbnNpb25zPzogUmVjb3JkPHN0cmluZywgYm9vbGVhbj47XG59XG5cbmludGVyZmFjZSBSZWdpc3Rlck90cFJlc3BvbnNlIHtcbiAgdXNlcjoge1xuICAgIG90cERldmljZXM6IE90cERldmljZVtdO1xuICB9O1xufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IGNvbnZlcnRzIGEgUHVibGljS2V5Q3JlZGVudGlhbCAob3IgYW55IHZhbHVlIGl0IGNvbnRhaW5zKSB0byBhXG4gKiBKU09OLXNlcmlhbGlzYWJsZSByZXByZXNlbnRhdGlvbiwgZW5jb2RpbmcgQXJyYXlCdWZmZXJzIGFzIGJhc2U2NHVybCBzdHJpbmdzLlxuICovXG5mdW5jdGlvbiBwdWJsaWNLZXlDcmVkZW50aWFsVG9KU09OKHZhbHVlOiB1bmtub3duKTogdW5rbm93biB7XG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXAocHVibGljS2V5Q3JlZGVudGlhbFRvSlNPTik7XG4gIH1cbiAgaWYgKHZhbHVlIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICByZXR1cm4gYnVmZmVyVG9CYXNlNjRVcmwodmFsdWUpO1xuICB9XG4gIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcodmFsdWUpKSB7XG4gICAgcmV0dXJuIGJ1ZmZlclRvQmFzZTY0VXJsKHZhbHVlLmJ1ZmZlciBhcyBBcnJheUJ1ZmZlcik7XG4gIH1cbiAgaWYgKHZhbHVlIGluc3RhbmNlb2YgT2JqZWN0KSB7XG4gICAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgIC8vIFVzZSBmb3IuLi5pbiB0byBlbnVtZXJhdGUgRE9NIG9iamVjdCBwcm9wZXJ0aWVzIChub24tZW51bWVyYWJsZSBvd24gKyBpbmhlcml0ZWQpXG4gICAgZm9yIChjb25zdCBrZXkgaW4gdmFsdWUpIHtcbiAgICAgIHJlc3VsdFtrZXldID0gcHVibGljS2V5Q3JlZGVudGlhbFRvSlNPTigodmFsdWUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2tleV0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIHJldHVybiB2YWx1ZTtcbn1cblxuLyoqXG4gKiBEZWNvZGVzIGV4Y2x1ZGVkIGNyZWRlbnRpYWwgSURzIGZyb20gYmFzZTY0IHN0cmluZ3MgdG8gQXJyYXlCdWZmZXJzLlxuICogVGhlIFdlYkF1dGhuIEFQSSByZXF1aXJlcyBCdWZmZXJTb3VyY2UgdmFsdWVzLCBub3QgYmFzZTY0IHN0cmluZ3MuXG4gKi9cbmZ1bmN0aW9uIHByZWZvcm1hdEV4Y2x1ZGVkQ3JlZGVudGlhbHMoXG4gIGV4Y2x1ZGVDcmVkZW50aWFsczogUHVibGljS2V5Q3JlZGVudGlhbERlc2NyaXB0b3JbXSB8IHVuZGVmaW5lZFxuKTogUHVibGljS2V5Q3JlZGVudGlhbERlc2NyaXB0b3JbXSB7XG4gIGlmICghZXhjbHVkZUNyZWRlbnRpYWxzKSByZXR1cm4gW107XG4gIHJldHVybiBleGNsdWRlQ3JlZGVudGlhbHMubWFwKChjcmVkKSA9PiAoe1xuICAgIC4uLmNyZWQsXG4gICAgaWQ6IEJ1ZmZlci5mcm9tKGNyZWQuaWQgYXMgdW5rbm93biBhcyBzdHJpbmcsICdiYXNlNjQnKSBhcyB1bmtub3duIGFzIEFycmF5QnVmZmVyLFxuICB9KSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWdpc3RlclBhc3NrZXkocGFyYW1zOiB7XG4gIGJpdGdvOiBCaXRHb0Jhc2U7XG4gIHByb3ZpZGVyOiBXZWJBdXRoblByb3ZpZGVyO1xuICBsYWJlbDogc3RyaW5nO1xufSk6IFByb21pc2U8V2ViQXV0aG5PdHBEZXZpY2UgJiB7IHByZlN1cHBvcnRlZDogYm9vbGVhbiB9PiB7XG4gIGNvbnN0IHsgYml0Z28sIHByb3ZpZGVyLCBsYWJlbCB9ID0gcGFyYW1zO1xuXG4gIC8vIFN0ZXAgMTogRmV0Y2ggc2VydmVyIGNoYWxsZW5nZSAoY29udGFpbnMgYmFzZVNhbHQpXG4gIGNvbnN0IGNoYWxsZW5nZSA9IChhd2FpdCBiaXRnb1xuICAgIC5nZXQoYml0Z28udXJsKCcvdXNlci9vdHAvd2ViYXV0aG4vcmVnaXN0ZXInLCAyKSlcbiAgICAucmVzdWx0KCkpIGFzIFJlZ2lzdGVyQ2hhbGxlbmdlUmVzcG9uc2U7XG5cbiAgLy8gU3RlcCAyOiBQYXNzIGZvcm1hdHRlZCBjaGFsbGVuZ2UgdG8gcHJvdmlkZXIuY3JlYXRlKCkg4oCUIGJyb3dzZXIgcmV0dXJucyBhdHRlc3RhdGlvblxuICBjb25zdCBhdHRlc3RhdGlvbiA9IGF3YWl0IHByb3ZpZGVyLmNyZWF0ZSh7XG4gICAgY2hhbGxlbmdlOiBCdWZmZXIuZnJvbShjaGFsbGVuZ2UuY2hhbGxlbmdlLCAnYmFzZTY0JyksXG4gICAgcnA6IGNoYWxsZW5nZS5ycCxcbiAgICB1c2VyOiBjaGFsbGVuZ2UudXNlcixcbiAgICBwdWJLZXlDcmVkUGFyYW1zOiBjaGFsbGVuZ2UucHViS2V5Q3JlZFBhcmFtcyxcbiAgICB0aW1lb3V0OiBjaGFsbGVuZ2UudGltZW91dCxcbiAgICBleGNsdWRlQ3JlZGVudGlhbHM6IHByZWZvcm1hdEV4Y2x1ZGVkQ3JlZGVudGlhbHMoY2hhbGxlbmdlLmV4Y2x1ZGVDcmVkZW50aWFscyksXG4gICAgYXV0aGVudGljYXRvclNlbGVjdGlvbjogY2hhbGxlbmdlLmF1dGhlbnRpY2F0b3JTZWxlY3Rpb24sXG4gICAgYXR0ZXN0YXRpb246IGNoYWxsZW5nZS5hdHRlc3RhdGlvbixcbiAgICBleHRlbnNpb25zOiBjaGFsbGVuZ2UuZXh0ZW5zaW9ucyxcbiAgfSk7XG5cbiAgLy8gU3RlcCAzOiBDaGVjayBpZiBQUkYgaXMgc3VwcG9ydGVkIOKAlCBgcHJmLmVuYWJsZWRgIGlzIHNldCBkdXJpbmcgcmVnaXN0cmF0aW9uXG4gIC8vIChub3QgYHByZi5yZXN1bHRzLmZpcnN0YCwgd2hpY2ggaXMgb25seSBwcmVzZW50IGR1cmluZyBhdXRoZW50aWNhdGlvbiBhc3NlcnRpb25zKVxuICBjb25zdCBjbGllbnRFeHRlbnNpb25SZXN1bHRzOiBBdXRoZW50aWNhdGlvbkV4dGVuc2lvbnNDbGllbnRPdXRwdXRzID0gYXR0ZXN0YXRpb24uZ2V0Q2xpZW50RXh0ZW5zaW9uUmVzdWx0cygpO1xuICBjb25zdCBwcmZFbmFibGVkID0gY2xpZW50RXh0ZW5zaW9uUmVzdWx0cy5wcmY7XG4gIGNvbnN0IHByZlN1cHBvcnRlZCA9IHR5cGVvZiBwcmZFbmFibGVkID09PSAnb2JqZWN0JyAmJiBwcmZFbmFibGVkICE9PSBudWxsICYmIHByZkVuYWJsZWQuZW5hYmxlZCA9PT0gdHJ1ZTtcblxuICAvLyBTdGVwIDQ6IFNlcmlhbGl6ZSB0aGUgZnVsbCBjcmVkZW50aWFsIHVzaW5nIHJlY3Vyc2l2ZSBiYXNlNjR1cmwgZW5jb2RpbmdcbiAgY29uc3Qgb3RwID0gSlNPTi5zdHJpbmdpZnkocHVibGljS2V5Q3JlZGVudGlhbFRvSlNPTihhdHRlc3RhdGlvbikpO1xuXG4gIGNvbnN0IHB1dEJvZHk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge1xuICAgIG90cCxcbiAgICB0eXBlOiAnd2ViYXV0aG4nLFxuICAgIGxhYmVsLFxuICB9O1xuXG4gIGlmIChwcmZTdXBwb3J0ZWQpIHtcbiAgICBwdXRCb2R5LmV4dGVuc2lvbnMgPSBbJ3ByZiddO1xuICAgIHB1dEJvZHkuc2NvcGVzID0gWyd3YWxsZXRfaG90J107XG4gIH1cblxuICAvLyBTdGVwIDU6IFBVVCAvYXBpL3YyL3VzZXIvb3RwXG4gIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IGJpdGdvLnB1dChiaXRnby51cmwoJy91c2VyL290cCcsIDIpKS5zZW5kKHB1dEJvZHkpLnJlc3VsdCgpKSBhcyBSZWdpc3Rlck90cFJlc3BvbnNlO1xuXG4gIC8vIFN0ZXAgNjogRmluZCB0aGUgbmV3bHkgcmVnaXN0ZXJlZCBkZXZpY2UgYnkgbWF0Y2hpbmcgY3JlZGVudGlhbElkXG4gIGNvbnN0IGRldmljZSA9IHJlc3BvbnNlLnVzZXIub3RwRGV2aWNlcy5maW5kKChkKSA9PiBkLmNyZWRlbnRpYWxJZCA9PT0gYXR0ZXN0YXRpb24uaWQpO1xuICBpZiAoIWRldmljZSkge1xuICAgIGNvbnN0IGF2YWlsYWJsZSA9IHJlc3BvbnNlLnVzZXIub3RwRGV2aWNlcy5tYXAoKGQpID0+IGQuY3JlZGVudGlhbElkKS5qb2luKCcsICcpO1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBSZWdpc3RlcmVkIGRldmljZSBub3QgZm91bmQgaW4gcmVzcG9uc2UgKGNyZWRlbnRpYWxJZDogJHthdHRlc3RhdGlvbi5pZH0pLiBBdmFpbGFibGU6IFske2F2YWlsYWJsZX1dYFxuICAgICk7XG4gIH1cblxuICAvLyBTdGVwIDc6IFJldHVybiBXZWJBdXRobk90cERldmljZSArIHByZlN1cHBvcnRlZFxuICByZXR1cm4ge1xuICAgIGlkOiBkZXZpY2UuaWQsXG4gICAgY3JlZGVudGlhbElkOiBkZXZpY2UuY3JlZGVudGlhbElkLFxuICAgIHByZlNhbHQ6IGRldmljZS5wcmZTYWx0LFxuICAgIGlzUGFzc2tleTogZGV2aWNlLmlzUGFzc2tleSxcbiAgICBleHRlbnNpb25zOiBkZXZpY2UuZXh0ZW5zaW9ucyxcbiAgICBwcmZTdXBwb3J0ZWQsXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,11 @@
1
+ import { BitGoBase } from '@bitgo/sdk-core';
2
+ import type { WebAuthnOtpDevice } from '@bitgo/public-types';
3
+ /**
4
+ * Permanently removes a passkey credential from the user's account.
5
+ * Call removePasskeyFromWallet() for all affected wallets before calling this.
6
+ */
7
+ export declare function removePasskeyFromAccount(params: {
8
+ bitgo: BitGoBase;
9
+ device: WebAuthnOtpDevice;
10
+ }): Promise<void>;
11
+ //# sourceMappingURL=removePasskeyFromAccount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removePasskeyFromAccount.d.ts","sourceRoot":"","sources":["../../src/removePasskeyFromAccount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrH"}