@ledgerhq/revault-sdk 0.18.2 → 0.20.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/lib/bake.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 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
3
 
4
- var _chunkQOP5LA3Ecjs = require('./chunk-QOP5LA3E.cjs');
4
+ var _chunkWVCYFF2Zcjs = require('./chunk-WVCYFF2Z.cjs');
5
5
 
6
6
  // src/bake/index.ts
7
7
  var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant);
@@ -51,12 +51,12 @@ var flattenApprovers = (groups) => {
51
51
  };
52
52
  async function bakePledgeAdjustment(options, logger) {
53
53
  const { pledgeAdjustment, engine } = options;
54
- const getDeviceIndex = _chunkQOP5LA3Ecjs.createDeviceIndexResolver.call(void 0, engine);
54
+ const getDeviceIndex = _chunkWVCYFF2Zcjs.createDeviceIndexResolver.call(void 0, engine);
55
55
  logger.info("Logging in with admin...");
56
56
  const admin = await engine.withDeviceIndex(4).login();
57
57
  logger.info("Fetching account, tradelink blueprint and network...");
58
58
  const [matchingAccounts, blueprint, network] = await Promise.all([
59
- _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin.client.accounts.list.query, { name: pledgeAdjustment.account }),
59
+ _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin.client.accounts.list.query, { name: pledgeAdjustment.account }),
60
60
  admin.client.tradelink.getNetworkBlueprint.query(),
61
61
  admin.client.tradelink.getNetwork.query()
62
62
  ]);
@@ -201,7 +201,7 @@ async function bakeWorkspace(options, logger) {
201
201
  const { workspace, engine, workspaceName } = options;
202
202
  const workspaceEngine = engine.withWorkspace(workspaceName);
203
203
  const { logTitle, logStep, logSubStep } = createBakeLogHelpers(logger);
204
- const findDeviceIndex = _chunkQOP5LA3Ecjs.createDeviceIndexResolver.call(void 0, workspaceEngine);
204
+ const findDeviceIndex = _chunkWVCYFF2Zcjs.createDeviceIndexResolver.call(void 0, workspaceEngine);
205
205
  logger.info("Authenticating with two admins...");
206
206
  const [admin1, admin2] = await Promise.all([
207
207
  workspaceEngine.withDeviceIndex(4).login(),
@@ -215,10 +215,10 @@ async function bakeWorkspace(options, logger) {
215
215
  existingAccounts,
216
216
  tradelinkNetworkBlueprint
217
217
  ] = await Promise.all([
218
- _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin1.client.users.list.query, { status: "ACTIVE" }),
219
- _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin1.client.groups.list.query, { status: "ACTIVE" }),
220
- _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin1.client.policies.list.query, { isPrivate: false }),
221
- _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin1.client.accounts.list.query, { status: "ACTIVE" }),
218
+ _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin1.client.users.list.query, { status: "ACTIVE" }),
219
+ _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin1.client.groups.list.query, { status: "ACTIVE" }),
220
+ _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin1.client.policies.list.query, { isPrivate: false }),
221
+ _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin1.client.accounts.list.query, { status: "ACTIVE" }),
222
222
  admin1.client.tradelink.getNetworkBlueprint.query()
223
223
  ]);
224
224
  const tradelinkOrgExchangesByName = _lodash2.default.keyBy(_optionalChain([tradelinkNetworkBlueprint, 'optionalAccess', _3 => _3.exchanges]), "name");
@@ -272,7 +272,7 @@ async function bakeWorkspace(options, logger) {
272
272
  }
273
273
  }
274
274
  async function createWhitelists(whitelists) {
275
- const existingWhitelists = await _chunkQOP5LA3Ecjs.fetchAll.call(void 0, admin1.client.whitelists.list.query, {
275
+ const existingWhitelists = await _chunkWVCYFF2Zcjs.fetchAll.call(void 0, admin1.client.whitelists.list.query, {
276
276
  status: "ACTIVE"
277
277
  });
278
278
  for (const whitelist of whitelists) {
package/lib/bake.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { L as Logger } from './types-DNEewSJL.cjs';
2
2
  import z from 'zod';
3
- import { E as Engine, f as WithWorkspace, c as WithDevice, l as WithPsdAuth } from './types-DcbTP2K6.cjs';
3
+ import { E as Engine, f as WithWorkspace, c as WithDevice, l as WithPsdAuth } from './types-CAKnCFJk.cjs';
4
4
  import { VaultRequestResponse } from '@ledgerhq/revault-api';
5
5
  import { b as RouterInputs } from './index-YRqsGEDY.cjs';
6
6
  import './types-DJfbanPz.cjs';
package/lib/bake.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { L as Logger } from './types-DNEewSJL.js';
2
2
  import z from 'zod';
3
- import { E as Engine, f as WithWorkspace, c as WithDevice, l as WithPsdAuth } from './types-CdSLzGGm.js';
3
+ import { E as Engine, f as WithWorkspace, c as WithDevice, l as WithPsdAuth } from './types-mZnXORz9.js';
4
4
  import { VaultRequestResponse } from '@ledgerhq/revault-api';
5
5
  import { b as RouterInputs } from './index-znHBELBb.js';
6
6
  import './types-DJfbanPz.js';
package/lib/bake.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createDeviceIndexResolver,
3
3
  fetchAll
4
- } from "./chunk-VHZJP75X.js";
4
+ } from "./chunk-PEHCVOGV.js";
5
5
 
6
6
  // src/bake/index.ts
7
7
  import invariant4 from "invariant";
@@ -10,6 +10,16 @@ async function fetchAll(queryFn, query) {
10
10
  }
11
11
  return res;
12
12
  }
13
+ async function fetchAllCursor(queryFn, query) {
14
+ const res = [];
15
+ let cursor = null;
16
+ do {
17
+ const partial = await queryFn({ ...query, ...cursor === null ? {} : { cursor } });
18
+ res.push(...partial.results);
19
+ cursor = partial.next;
20
+ } while (cursor);
21
+ return res;
22
+ }
13
23
  function createDeviceIndexResolver(engine) {
14
24
  const _deviceUserIdByDeviceIndexCache = {};
15
25
  return async function findDeviceIndex(deviceUserId) {
@@ -30,6 +40,7 @@ function createDeviceIndexResolver(engine) {
30
40
 
31
41
  export {
32
42
  fetchAll,
43
+ fetchAllCursor,
33
44
  createDeviceIndexResolver
34
45
  };
35
- //# sourceMappingURL=chunk-VHZJP75X.js.map
46
+ //# sourceMappingURL=chunk-PEHCVOGV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import type { CursorPaginated, Paginated } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"./engine/types\";\n\n/**\n * Utility function that collect results on all pages until there is no more next page\n */\nexport async function fetchAll<TData, TQuery extends { page?: number }>(\n queryFn: (query: TQuery) => Promise<Paginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let page: number | null = 1;\n while (page) {\n const partial = await queryFn({ ...query, page });\n res.push(...partial.results);\n page = partial.next;\n }\n return res;\n}\n\n/**\n * Utility function that collect results on all cursors until cursor is null\n */\nexport async function fetchAllCursor<TData, TQuery extends { cursor?: number }>(\n queryFn: (query: TQuery) => Promise<CursorPaginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let cursor: number | string | null = null;\n do {\n const partial = await queryFn({ ...query, ...(cursor === null ? {} : { cursor }) });\n res.push(...partial.results);\n cursor = partial.next;\n } while (cursor);\n return res;\n}\n\n/**\n * Return a function that retrieve a device index based on a given deviceUserId\n * Holds a cache of found indexes to avoid spamming device-api\n */\nexport function createDeviceIndexResolver(engine: Engine<WithWorkspace>) {\n // Cache to avoid spamming device-api when seeking for same index multiple times\n const _deviceUserIdByDeviceIndexCache: Record<string, Promise<string>> = {};\n\n return async function findDeviceIndex(deviceUserId: string): Promise<number> {\n let deviceIndex: number | null = null;\n for (let i = 4; i < 50; i++) {\n const promise =\n i in _deviceUserIdByDeviceIndexCache\n ? _deviceUserIdByDeviceIndexCache[i]!\n : engine.withDeviceIndex(i).device.getDeviceUserId();\n _deviceUserIdByDeviceIndexCache[i] = promise;\n const candidate = await promise;\n // /!\\ we need to decide in which casing we want this information\n // -> device-api returns it in uppercase\n // -> we save it in lowercase in revault-api DB\n // -> doing \"safe\" comparison here by always user the uppercase version, but hey!\n if (candidate.toUpperCase() === deviceUserId.toUpperCase()) {\n deviceIndex = i;\n break;\n }\n }\n invariant(deviceIndex, `Could not find index for device user id ${deviceUserId}`);\n return deviceIndex;\n };\n}\n"],"mappings":";AACA,OAAO,eAAe;AAOtB,eAAsB,SACpB,SACA,OACkB;AAClB,QAAM,MAAe,CAAC;AACtB,MAAI,OAAsB;AAC1B,SAAO,MAAM;AACX,UAAM,UAAU,MAAM,QAAQ,EAAE,GAAG,OAAO,KAAK,CAAC;AAChD,QAAI,KAAK,GAAG,QAAQ,OAAO;AAC3B,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAKA,eAAsB,eACpB,SACA,OACkB;AAClB,QAAM,MAAe,CAAC;AACtB,MAAI,SAAiC;AACrC,KAAG;AACD,UAAM,UAAU,MAAM,QAAQ,EAAE,GAAG,OAAO,GAAI,WAAW,OAAO,CAAC,IAAI,EAAE,OAAO,EAAG,CAAC;AAClF,QAAI,KAAK,GAAG,QAAQ,OAAO;AAC3B,aAAS,QAAQ;AAAA,EACnB,SAAS;AACT,SAAO;AACT;AAMO,SAAS,0BAA0B,QAA+B;AAEvE,QAAM,kCAAmE,CAAC;AAE1E,SAAO,eAAe,gBAAgB,cAAuC;AAC3E,QAAI,cAA6B;AACjC,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,UACJ,KAAK,kCACD,gCAAgC,CAAC,IACjC,OAAO,gBAAgB,CAAC,EAAE,OAAO,gBAAgB;AACvD,sCAAgC,CAAC,IAAI;AACrC,YAAM,YAAY,MAAM;AAKxB,UAAI,UAAU,YAAY,MAAM,aAAa,YAAY,GAAG;AAC1D,sBAAc;AACd;AAAA,MACF;AAAA,IACF;AACA,cAAU,aAAa,2CAA2C,YAAY,EAAE;AAChF,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -10,6 +10,16 @@ async function fetchAll(queryFn, query) {
10
10
  }
11
11
  return res;
12
12
  }
13
+ async function fetchAllCursor(queryFn, query) {
14
+ const res = [];
15
+ let cursor = null;
16
+ do {
17
+ const partial = await queryFn({ ...query, ...cursor === null ? {} : { cursor } });
18
+ res.push(...partial.results);
19
+ cursor = partial.next;
20
+ } while (cursor);
21
+ return res;
22
+ }
13
23
  function createDeviceIndexResolver(engine) {
14
24
  const _deviceUserIdByDeviceIndexCache = {};
15
25
  return async function findDeviceIndex(deviceUserId) {
@@ -31,5 +41,6 @@ function createDeviceIndexResolver(engine) {
31
41
 
32
42
 
33
43
 
34
- exports.fetchAll = fetchAll; exports.createDeviceIndexResolver = createDeviceIndexResolver;
35
- //# sourceMappingURL=chunk-QOP5LA3E.cjs.map
44
+
45
+ exports.fetchAll = fetchAll; exports.fetchAllCursor = fetchAllCursor; exports.createDeviceIndexResolver = createDeviceIndexResolver;
46
+ //# sourceMappingURL=chunk-WVCYFF2Z.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/chunk-WVCYFF2Z.cjs","../src/utils.ts"],"names":[],"mappings":"AAAA;ACCA,4FAAsB;AAOtB,MAAA,SAAsB,QAAA,CACpB,OAAA,EACA,KAAA,EACkB;AAClB,EAAA,MAAM,IAAA,EAAe,CAAC,CAAA;AACtB,EAAA,IAAI,KAAA,EAAsB,CAAA;AAC1B,EAAA,MAAA,CAAO,IAAA,EAAM;AACX,IAAA,MAAM,QAAA,EAAU,MAAM,OAAA,CAAQ,EAAE,GAAG,KAAA,EAAO,KAAK,CAAC,CAAA;AAChD,IAAA,GAAA,CAAI,IAAA,CAAK,GAAG,OAAA,CAAQ,OAAO,CAAA;AAC3B,IAAA,KAAA,EAAO,OAAA,CAAQ,IAAA;AAAA,EACjB;AACA,EAAA,OAAO,GAAA;AACT;AAKA,MAAA,SAAsB,cAAA,CACpB,OAAA,EACA,KAAA,EACkB;AAClB,EAAA,MAAM,IAAA,EAAe,CAAC,CAAA;AACtB,EAAA,IAAI,OAAA,EAAiC,IAAA;AACrC,EAAA,GAAG;AACD,IAAA,MAAM,QAAA,EAAU,MAAM,OAAA,CAAQ,EAAE,GAAG,KAAA,EAAO,GAAI,OAAA,IAAW,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,OAAO,EAAG,CAAC,CAAA;AAClF,IAAA,GAAA,CAAI,IAAA,CAAK,GAAG,OAAA,CAAQ,OAAO,CAAA;AAC3B,IAAA,OAAA,EAAS,OAAA,CAAQ,IAAA;AAAA,EACnB,EAAA,MAAA,CAAS,MAAA,CAAA;AACT,EAAA,OAAO,GAAA;AACT;AAMO,SAAS,yBAAA,CAA0B,MAAA,EAA+B;AAEvE,EAAA,MAAM,gCAAA,EAAmE,CAAC,CAAA;AAE1E,EAAA,OAAO,MAAA,SAAe,eAAA,CAAgB,YAAA,EAAuC;AAC3E,IAAA,IAAI,YAAA,EAA6B,IAAA;AACjC,IAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AAC3B,MAAA,MAAM,QAAA,EACJ,EAAA,GAAK,gCAAA,EACD,+BAAA,CAAgC,CAAC,EAAA,EACjC,MAAA,CAAO,eAAA,CAAgB,CAAC,CAAA,CAAE,MAAA,CAAO,eAAA,CAAgB,CAAA;AACvD,MAAA,+BAAA,CAAgC,CAAC,EAAA,EAAI,OAAA;AACrC,MAAA,MAAM,UAAA,EAAY,MAAM,OAAA;AAKxB,MAAA,GAAA,CAAI,SAAA,CAAU,WAAA,CAAY,EAAA,IAAM,YAAA,CAAa,WAAA,CAAY,CAAA,EAAG;AAC1D,QAAA,YAAA,EAAc,CAAA;AACd,QAAA,KAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,iCAAA,WAAU,EAAa,CAAA,wCAAA,EAA2C,YAAY,CAAA,CAAA;AACvE,IAAA;AACT,EAAA;AACF;AD7BmF;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/_work/revault/revault/packages/sdk/lib/chunk-WVCYFF2Z.cjs","sourcesContent":[null,"import type { CursorPaginated, Paginated } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"./engine/types\";\n\n/**\n * Utility function that collect results on all pages until there is no more next page\n */\nexport async function fetchAll<TData, TQuery extends { page?: number }>(\n queryFn: (query: TQuery) => Promise<Paginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let page: number | null = 1;\n while (page) {\n const partial = await queryFn({ ...query, page });\n res.push(...partial.results);\n page = partial.next;\n }\n return res;\n}\n\n/**\n * Utility function that collect results on all cursors until cursor is null\n */\nexport async function fetchAllCursor<TData, TQuery extends { cursor?: number }>(\n queryFn: (query: TQuery) => Promise<CursorPaginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let cursor: number | string | null = null;\n do {\n const partial = await queryFn({ ...query, ...(cursor === null ? {} : { cursor }) });\n res.push(...partial.results);\n cursor = partial.next;\n } while (cursor);\n return res;\n}\n\n/**\n * Return a function that retrieve a device index based on a given deviceUserId\n * Holds a cache of found indexes to avoid spamming device-api\n */\nexport function createDeviceIndexResolver(engine: Engine<WithWorkspace>) {\n // Cache to avoid spamming device-api when seeking for same index multiple times\n const _deviceUserIdByDeviceIndexCache: Record<string, Promise<string>> = {};\n\n return async function findDeviceIndex(deviceUserId: string): Promise<number> {\n let deviceIndex: number | null = null;\n for (let i = 4; i < 50; i++) {\n const promise =\n i in _deviceUserIdByDeviceIndexCache\n ? _deviceUserIdByDeviceIndexCache[i]!\n : engine.withDeviceIndex(i).device.getDeviceUserId();\n _deviceUserIdByDeviceIndexCache[i] = promise;\n const candidate = await promise;\n // /!\\ we need to decide in which casing we want this information\n // -> device-api returns it in uppercase\n // -> we save it in lowercase in revault-api DB\n // -> doing \"safe\" comparison here by always user the uppercase version, but hey!\n if (candidate.toUpperCase() === deviceUserId.toUpperCase()) {\n deviceIndex = i;\n break;\n }\n }\n invariant(deviceIndex, `Could not find index for device user id ${deviceUserId}`);\n return deviceIndex;\n };\n}\n"]}
package/lib/engine.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkQOP5LA3Ecjs = require('./chunk-QOP5LA3E.cjs');
3
+
4
+ var _chunkWVCYFF2Zcjs = require('./chunk-WVCYFF2Z.cjs');
4
5
 
5
6
 
6
7
 
@@ -700,25 +701,30 @@ function createEngine(options, logger) {
700
701
  });
701
702
  await device.setPairing({ pairing });
702
703
  }
704
+ const approveChallenge = async (challenge, params) => {
705
+ await enforcePairing();
706
+ await device.startKPatternAsResponder({
707
+ handshake: challenge.handshake,
708
+ handshakeAttestation: challenge.handshakeAttestation,
709
+ partitionId: challenge.partitionId
710
+ });
711
+ _optionalChain([params, 'optionalAccess', _5 => _5.onScreenDisplayed, 'optionalCall', _6 => _6()]);
712
+ const signature = await device.validateVaultOperation({
713
+ actions: challenge.wActions
714
+ });
715
+ return signature;
716
+ };
703
717
  return {
704
718
  approve: async (request, params) => {
705
719
  const { challenge } = await client2.requests.getChallenge.query({ id: request.id });
706
720
  _invariant2.default.call(void 0, challenge.challengeType === "PSD", "Challenge type must be PSD");
707
- await enforcePairing();
708
- await device.startKPatternAsResponder({
709
- handshake: challenge.handshake,
710
- handshakeAttestation: challenge.handshakeAttestation,
711
- partitionId: challenge.partitionId
712
- });
713
- _optionalChain([params, 'optionalAccess', _5 => _5.onScreenDisplayed, 'optionalCall', _6 => _6()]);
714
- const signature = await device.validateVaultOperation({
715
- actions: challenge.wActions
716
- });
721
+ const signature = await approveChallenge(challenge, params);
717
722
  return client2.requests.approve.mutate({
718
723
  id: request.id,
719
724
  data: { challengeType: "PSD", signature }
720
725
  });
721
726
  },
727
+ approveChallenge,
722
728
  reject: (request) => {
723
729
  return client2.requests.reject.mutate({ id: request.id, data: null });
724
730
  }
@@ -763,5 +769,6 @@ function createEngine(options, logger) {
763
769
 
764
770
 
765
771
 
766
- exports.createEngine = createEngine; exports.fetchAll = _chunkQOP5LA3Ecjs.fetchAll;
772
+
773
+ exports.createEngine = createEngine; exports.fetchAll = _chunkWVCYFF2Zcjs.fetchAll; exports.fetchAllCursor = _chunkWVCYFF2Zcjs.fetchAllCursor;
767
774
  //# sourceMappingURL=engine.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/engine.cjs","../src/engine/index.ts","../src/device/real-device.ts","../src/trpc.ts"],"names":["withApiUser","withWorkspace","withOnboarding","client","engine"],"mappings":"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","file":"/home/runner/_work/revault/revault/packages/sdk/lib/engine.cjs","sourcesContent":[null,"import type {\n ApiChallenge,\n ClaimedRole,\n OnboardingSeedChallenge,\n PsdChallenge,\n UserRegistrationChallenge,\n UserRegistrationChallengeResponse,\n UserRegistrationDeviceData,\n UserRegistrationResponse,\n VaultRequestResponse,\n WrappingKeyResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport { type Device, createApiDevice } from \"@/device\";\nimport { createRealDevice } from \"@/device/real-device\";\nimport { type TRPCClientOptions, createClient } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\n\nimport type {\n ApproveRequestParams,\n DecorateWithApiUserAndWorkspaceUnauthenticated,\n DecorateWithDevice,\n DecorateWithDeviceAndOnboarding,\n DecorateWithDeviceAndWorkspaceUnauthenticated,\n DecorateWithWorkspaceApiAuthenticated,\n DecorateWithWorkspacePsdAuthenticated,\n DecorateWithWorkspaceUnauthenticated,\n Engine,\n EngineBase,\n EngineOptions,\n RegisterOnboardingDeviceParams,\n WithApiAuth,\n WithApiUser,\n WithDevice,\n WithOnboarding,\n WithPsdAuth,\n WithWorkspace,\n} from \"./types\";\n\nexport { fetchAll } from \"../utils\";\n\nexport type * from \"./types\";\n\nasync function genericRegister<T>({\n device,\n name,\n role,\n getChallenge,\n submitChallenge,\n}: {\n device: Device;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n getChallenge: (p: {\n pubKey: string;\n deviceData: UserRegistrationDeviceData;\n }) => Promise<UserRegistrationChallenge>;\n submitChallenge: (p: {\n pubKey: string;\n challengeResponse: UserRegistrationChallengeResponse;\n }) => Promise<T>;\n}): Promise<T> {\n const [attestation, u2fPubKey, confidentialityKey] = await Promise.all([\n device.getAttestation(),\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n const ephemeralPubKey = await device.initPairingHandshake();\n const deviceData: UserRegistrationDeviceData = {\n name,\n pubKey: u2fPubKey.pubKey,\n psdModel: \"STAX\",\n confidentialityKey: confidentialityKey.pubKey,\n psdEphemeralKey: ephemeralPubKey.pubKey,\n psdEphemeralKeyAttestation: {\n ...attestation.attestation,\n signature: ephemeralPubKey.signature,\n },\n };\n const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });\n const pairingPayload = await device.finalizePairingHandshake({\n handshake: challenge.handshake,\n partitionId: challenge.ciphertext,\n handshakeAttestation: challenge.handshakeAttestation,\n });\n const register = await device.register({\n challenge: challenge.challenge,\n u2fRegisterData: challenge.u2fRegisterData,\n name,\n role,\n });\n const validationPubKey = await device.getValidationPubKey();\n const registerData = await device.registerData({ challenge: challenge.challenge });\n const attestationOffset = 67 + register.u2fRegister.readInt8(66);\n const u2fRegister = Buffer.concat([\n register.u2fRegister.slice(0, attestationOffset),\n Buffer.from([attestation.buffer.length]),\n attestation.buffer,\n register.u2fRegister.slice(attestationOffset),\n ]).toString(\"hex\");\n const challengeResponse: UserRegistrationChallengeResponse = {\n registerData,\n certificate: {\n ...attestation.attestation,\n signature: validationPubKey.signature,\n },\n u2fRegister,\n u2fKeyHandle: register.keyHandle.toString(\"hex\"),\n validationKey: validationPubKey.pubKey,\n pairingPayload,\n };\n return submitChallenge({ pubKey: u2fPubKey.pubKey, challengeResponse });\n}\n\nexport function createEngine(options: EngineOptions, logger: Logger): Engine {\n const clientOptions: TRPCClientOptions = {\n baseUrl: options.baseUrl,\n };\n const client = createClient(clientOptions);\n const apiDevice = createApiDevice(options, logger);\n\n const base: EngineBase = {\n client,\n createClient: (overrides) => createClient({ ...clientOptions, ...overrides }),\n };\n\n const withDeviceIndex: Engine[\"withDeviceIndex\"] = function <T>(\n this: Engine<T>,\n deviceIndex: number,\n ) {\n const device = apiDevice.with(deviceIndex);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withTransportId: Engine[\"withTransportId\"] = function <T>(\n this: Engine<T>,\n transportId: string,\n ) {\n const device = createRealDevice({ transportId }, logger);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withApiUser: Engine[\"withApiUser\"] = function <T>(this: Engine<T>) {\n const withApiUser: WithApiUser = { __isApiUser: true };\n return decorateEngine({ ...this, ...withApiUser } as Engine<T & WithApiUser>);\n };\n\n const withWorkspace: Engine[\"withWorkspace\"] = function <T>(\n this: Engine<T>,\n workspaceName: string,\n ) {\n const withWorkspace: WithWorkspace = { __workspaceName: workspaceName };\n return decorateEngine({ ...this, ...withWorkspace } as Engine<T & WithWorkspace>);\n };\n\n const withOnboarding: Engine[\"withOnboarding\"] = function <T>(\n this: Engine<T>,\n onboardingId: string,\n ) {\n const withOnboarding: WithOnboarding = { __onboardingId: onboardingId };\n return decorateEngine({ ...this, ...withOnboarding } as Engine<T & WithOnboarding>);\n };\n\n function decorateEngine<T>(\n engine: Engine<\n T &\n Partial<\n WithDevice & WithOnboarding & WithWorkspace & WithPsdAuth & WithApiUser & WithApiAuth\n >\n >,\n ): Engine<T> {\n function decorate<TEnhanced, TDecoration>(\n decorator: (engine: EngineBase & TEnhanced) => TDecoration,\n ): void {\n Object.assign(engine, decorator(engine as EngineBase & TEnhanced));\n }\n\n // DecorateWithDevice\n // -------------------------------------------------------------------------\n if (engine.device) {\n decorate<WithDevice, DecorateWithDevice<T>>(\n (engine) =>\n ({\n getWorkspaces: async (): Promise<string[]> => {\n const { device, client } = engine;\n const { pubKey } = await device.getU2FPubKey();\n const { workspaceNames } = await client.auth.psd.findWorkspaceNames.query({ pubKey });\n return workspaceNames;\n },\n }) satisfies DecorateWithDevice<T>,\n );\n }\n\n // DecorateWithWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && !engine.__psdToken && !engine.__apiAuth) {\n decorate<WithWorkspace, DecorateWithWorkspaceUnauthenticated<T>>((engine) => {\n const { __workspaceName } = engine;\n return {\n withPsdToken: function <T>(this: Engine<T>, token: string): Engine<T & WithPsdAuth> {\n const withPsdAuth: WithPsdAuth = { __psdToken: token };\n const psdAuth = `${__workspaceName}:${token}`;\n const client = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client, ...withPsdAuth } as Engine<T & WithPsdAuth>);\n },\n } satisfies DecorateWithWorkspaceUnauthenticated<T>;\n });\n }\n\n // DecorateWithDeviceAndOnboarding\n // -------------------------------------------------------------------------\n if (engine.device && engine.__onboardingId) {\n decorate<WithDevice & WithOnboarding, DecorateWithDeviceAndOnboarding>((engine) => {\n const { device, client, __onboardingId } = engine;\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityKey(),\n ]);\n const pairing = await client.onboarding.pairDevicePartition.mutate({\n pubKey,\n onboardingId: __onboardingId,\n data: {\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n },\n });\n await device.setPairing({ pairing });\n }\n return {\n claimDevice: async (params: { role: ClaimedRole; deviceName: string }): Promise<void> => {\n const { role, deviceName } = params;\n const [{ pubKey }, { pubKey: confidentialityKey }] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await client.onboarding.claimDevice.mutate({\n onboardingId: __onboardingId,\n claim: { role, pubKey, deviceName, confidentialityKey },\n });\n },\n\n collectWrappingKeyFragment: async (wrappingKey: WrappingKeyResponse): Promise<void> => {\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await device.openSession({\n secureChannel: {\n pubKey: wrappingKey.ephemeralPubKey,\n certificate: wrappingKey.ephemeralCertificate,\n },\n });\n const { attestation } = await device.getAttestation();\n const blob = await device.generateWrappingKeyFragment();\n await client.onboarding.submitWrappingKeyFragment.mutate({\n pubKey,\n onboardingId: __onboardingId,\n fragment: {\n blob,\n ephemeralPubKey: confidentialityKey.pubKey,\n ephemeralCertificate: {\n ...attestation,\n signature: confidentialityKey.signature,\n },\n },\n });\n },\n\n registerDevice: async (params: RegisterOnboardingDeviceParams): Promise<void> => {\n const { role, name } = params;\n const getChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.generateMasterAdminRegistrationChallenge\n : client.onboarding.generateSharedOwnerRegistrationChallenge;\n const submitChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.submitMasterAdminRegistration\n : client.onboarding.submitSharedOwnerRegistration;\n await genericRegister({\n device: device,\n name,\n role,\n getChallenge: ({ pubKey, deviceData }) =>\n getChallengeMutation.mutate({\n onboardingId: __onboardingId,\n pubKey,\n deviceData,\n }),\n submitChallenge: ({ pubKey, challengeResponse }) =>\n submitChallengeMutation.mutate({\n onboardingId: engine.__onboardingId,\n pubKey,\n // FIXME this should be renamed to `challengeResponse` on backend side\n response: challengeResponse,\n }),\n });\n },\n\n reviewSharedOwner: async (challenge: PsdChallenge): Promise<void> => {\n await enforcePairing();\n const { pubKey } = await device.getU2FPubKey();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n await client.onboarding.submitReviewByMasterAdminSignature.mutate({\n onboardingId: __onboardingId,\n pubKey,\n signature,\n });\n },\n\n collectSeedFragment: async (challenge: OnboardingSeedChallenge): Promise<void> => {\n await enforcePairing();\n const [{ pubKey }, { attestation }] = await Promise.all([\n device.getU2FPubKey(),\n device.getAttestation(),\n ]);\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const challengeResponse = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n const kkPattern = await device.startKKPatternAsResponder({\n partitionId: challenge.partitionId,\n handshake: challenge.kkHandshake,\n handshakeAttestation: challenge.kkHandshakeAttestation,\n });\n const approverBlob = await device.generateSeedFragment();\n await client.onboarding.submitSeedFragment.mutate({\n onboardingId: __onboardingId,\n pubKey,\n seedFragment: {\n challengeResponse,\n approverBlob,\n handshake: kkPattern.handshake,\n handshakeAttestation: {\n ...attestation,\n signature: kkPattern.signature,\n },\n },\n });\n },\n } satisfies DecorateWithDeviceAndOnboarding;\n });\n }\n\n // DecorateWithDeviceAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && !engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithDeviceAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { device, client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n opts?: { validityDurationSecs?: number; onScreenDisplayed?: () => void },\n ): Promise<Engine<T & WithPsdAuth>> {\n const { pubKey } = await device.getU2FPubKey();\n const challenge = await client.auth.psd.generateChallenge.mutate({\n pubKey,\n workspaceName: __workspaceName,\n });\n opts?.onScreenDisplayed?.();\n const authentication = await device.authenticate({\n challenge,\n workspaceName: __workspaceName,\n });\n const authPayload = {\n workspaceName: __workspaceName,\n pubKey,\n authentication,\n validityDurationSecs: opts?.validityDurationSecs,\n };\n const { token } = await client.auth.psd.authenticate.mutate({ ...authPayload });\n const withPsdAuth: WithPsdAuth = {\n __psdToken: token,\n };\n const psdAuth = `${engine.__workspaceName}:${token}`;\n const __authClient = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client: __authClient, ...withPsdAuth } as Engine<\n T & WithPsdAuth\n >);\n },\n\n register: (\n registration: UserRegistrationResponse,\n ): Promise<UserRegistrationResponse> => {\n return genericRegister({\n device,\n name: registration.name,\n role: registration.role,\n getChallenge: async ({ deviceData }) => {\n const challenge = await client.userRegistrations.generateChallenge.mutate({\n id: registration.id,\n workspaceName: __workspaceName,\n deviceData,\n });\n return challenge;\n },\n submitChallenge: ({ challengeResponse }) =>\n client.userRegistrations.submitChallenge.mutate({\n workspaceName: __workspaceName,\n id: registration.id,\n challengeResponse,\n }),\n });\n },\n } satisfies DecorateWithDeviceAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithApiUserAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__isApiUser && !engine.__apiAuth) {\n decorate<WithWorkspace & WithApiUser, DecorateWithApiUserAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n credentials: {\n apiKeyId: string;\n apiKeySecret: string;\n },\n ): Promise<Engine<T & WithApiAuth>> {\n const res = await client.auth.authenticate.mutate({\n apiKeyId: credentials.apiKeyId,\n apiKeySecret: credentials.apiKeySecret,\n workspace: __workspaceName,\n });\n const withApiAuth: WithApiAuth = {\n __apiAuth: res,\n };\n const __authClient = engine.createClient({ apiAccessToken: res.accessToken });\n return decorateEngine({ ...this, client: __authClient, ...withApiAuth } as Engine<\n T & WithApiAuth\n >);\n },\n } satisfies DecorateWithApiUserAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithWorkspacePsdAuthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithWorkspacePsdAuthenticated>((engine) => {\n const { client, device } = engine;\n\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const confidentialityKey = await device.getConfidentialityKey();\n const pairing = await client.debug.pairDevicePartition.mutate({\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n });\n await device.setPairing({ pairing });\n }\n\n return {\n approve: async (\n request: VaultRequestResponse,\n params?: ApproveRequestParams,\n ): Promise<VaultRequestResponse> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"PSD\", \"Challenge type must be PSD\");\n await enforcePairing();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n params?.onScreenDisplayed?.();\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"PSD\", signature },\n });\n },\n\n reject: (request: VaultRequestResponse): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({ id: request.id, data: null });\n },\n } satisfies DecorateWithWorkspacePsdAuthenticated;\n });\n }\n\n // DecorateWithWorkspaceApiAuthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__apiAuth) {\n decorate<WithWorkspace & WithApiAuth, DecorateWithWorkspaceApiAuthenticated>((engine) => {\n const { client } = engine;\n return {\n getChallenge: async (request: VaultRequestResponse): Promise<ApiChallenge[\"payload\"]> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"API\", \"Challenge type must be API\");\n return challenge.payload;\n },\n\n approve: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n\n reject: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n } satisfies DecorateWithWorkspaceApiAuthenticated;\n });\n }\n\n return engine;\n }\n\n return {\n ...base,\n withDeviceIndex,\n withTransportId,\n withApiUser,\n withWorkspace,\n withOnboarding,\n };\n}\n","import { DisconnectedDevice, LockedDeviceError } from \"@ledgerhq/errors\";\nimport type Transport from \"@ledgerhq/hw-transport\";\nimport type { HsmCertificate } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport { from, lastValueFrom } from \"rxjs\";\n\nimport type { Logger } from \"@/types\";\n\nimport {\n APPID_VAULT_ADMINISTRATOR,\n PAGINATED_STATUS,\n PATHS,\n SCRIPT_IDS,\n STATUS_LENGTH,\n STREAMING_NEXT_ACTION,\n STREAMING_RESPONSE,\n STR_ROLES,\n} from \"./constants\";\nimport { withDevicePolling } from \"./device-access\";\nimport type { Device } from \"./types\";\nimport { isTransportStatusError } from \"./utils\";\n\nconst MAX_CHUNK_LENGTH = 250;\n\ntype Options = {\n transportId: string;\n};\n\nconst FIXME_NOT_IMPLEMENTED =\n (fnName: string): (() => Promise<never>) =>\n async () => {\n throw new Error(`Not implemented: ${fnName}`);\n };\n\nconst getPathFromPathString = (pathString: string): number[] => {\n const parts = pathString.split(\"'/\").map((part) => parseInt(part, 10));\n return parts.map((part) => (part | 0x80000000) >>> 0);\n};\n\nconst splitChunks = (chunk: number, buffer: Buffer): Buffer[] => {\n const chunks = [];\n for (let i = 0, size = chunk; i < buffer.length; i += size, size = chunk) {\n chunks.push(buffer.slice(i, i + size));\n }\n return chunks;\n};\n\nconst removeStatus = (result: Buffer): Buffer => result.slice(0, result.length - STATUS_LENGTH);\n\nconst sendByChunk = async (\n transport: Transport,\n command: number[], // eg [0xe0, 0x45, 0x00, 0x00]\n data: Buffer,\n chunkSize: number = MAX_CHUNK_LENGTH,\n): Promise<Buffer> => {\n const chunks = splitChunks(chunkSize, data);\n let response = Buffer.from([]);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const apdu = [...command];\n // command is 0xe0,0x45,0x00,0x00 for first chunk, then it's 0xe0,0x45,0x80,0x00\n /* v8 ignore start */\n apdu[2] = i && 0x80;\n /* v8 ignore stop */\n response = await transport.send(apdu[0]!, apdu[1]!, apdu[2], apdu[3]!, chunk, [\n 0x9000,\n ...PAGINATED_STATUS,\n ]);\n }\n return response;\n};\n\nconst buildAttestation = (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n}): Buffer => {\n const sigBuffer = Buffer.from(params.handshakeAttestation.signature, \"base64\");\n const sigLengthBuffer = Buffer.alloc(1);\n sigLengthBuffer.writeUIntBE(sigBuffer.length, 0, 1);\n\n const certBuffer = Buffer.from(params.handshakeAttestation.certificate, \"base64\");\n const certLengthBuffer = Buffer.alloc(1);\n certLengthBuffer.writeUIntBE(certBuffer.length, 0, 1);\n\n const pubBuffer = Buffer.from(params.handshakeAttestation.attestationPub, \"base64\");\n\n const certChainData = Buffer.concat([\n sigLengthBuffer,\n sigBuffer,\n pubBuffer,\n certLengthBuffer,\n certBuffer,\n ]);\n\n const cliMsgBuffer = Buffer.from(params.handshake, \"hex\");\n const cliMsgLengthBuffer = Buffer.alloc(1);\n cliMsgLengthBuffer.writeUIntBE(cliMsgBuffer.length, 0, 1);\n\n const pidBuffer = Buffer.from(params.partitionId, \"hex\");\n const pidLengthBuffer = Buffer.alloc(1);\n pidLengthBuffer.writeUIntBE(pidBuffer.length, 0, 1);\n\n const certChainDataLengthBuff = Buffer.alloc(2);\n certChainDataLengthBuff.writeUInt16BE(certChainData.length, 0);\n\n const data = Buffer.concat([\n cliMsgLengthBuffer,\n cliMsgBuffer,\n certChainDataLengthBuff,\n certChainData,\n pidLengthBuffer,\n pidBuffer,\n ]);\n\n const totalLengthBuffer = Buffer.alloc(2);\n totalLengthBuffer.writeUInt16BE(data.length, 0);\n\n const toSend = Buffer.concat([totalLengthBuffer, data]);\n\n return toSend;\n};\n\ntype RetryOnError = (err: Error) => boolean;\n/* v8 ignore start */\nconst genericRetryOnError: RetryOnError = (err) => {\n // device is locked\n if (err instanceof LockedDeviceError) return true;\n // user is on dashboard when receiving a Vault app apdu\n if (isTransportStatusError(err) && err.statusCode === 0x6d09) return true;\n // VG-24797 error that can happen in BLE in some situations (still unclear)\n if (err instanceof DisconnectedDevice) return true;\n\n // for everything else, we don't want to retry\n return false;\n};\n/* v8 ignore stop */\n\nexport function createRealDevice(options: Options, logger: Logger): Device {\n const { transportId } = options;\n\n async function run<T>(\n job: (transport: Transport) => Promise<T>,\n retryOnError: RetryOnError = genericRetryOnError,\n ): Promise<T> {\n return lastValueFrom(\n withDevicePolling(transportId)<T>((transport) => from(job(transport)), retryOnError),\n );\n }\n\n /* v8 ignore start */\n const noRetry = (): boolean => false;\n const alwaysRetry = (): boolean => true;\n /* v8 ignore stop */\n const poll = async (\n opts: { retryOnError?: RetryOnError } = {},\n ): Promise<{ isAppOpened: boolean }> => {\n // waiting for device to be turned on\n await run(\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n async (_transport) => {},\n opts.retryOnError ?? alwaysRetry,\n );\n // checking if app is opened: should return directly on getPubKey\n try {\n await getPublicKey(PATHS.U2F, { secp256k1: true, retryOnError: noRetry });\n return { isAppOpened: true };\n } catch (err) {\n if (isTransportStatusError(err) && genericRetryOnError(err)) {\n return { isAppOpened: false };\n }\n throw err;\n }\n };\n\n const pollApp = async (appName: string): Promise<string> => {\n const res = await run((transport) =>\n transport.send(0xe0, 0xd8, 0x00, 0x00, Buffer.from(appName, \"utf8\")),\n );\n // little delay to give time to the app to be fully opened\n await new Promise((r) => setTimeout(r, 1e3));\n return res.toString(\"hex\");\n };\n\n const getPublicKey = async (\n pathString: string,\n { secp256k1, retryOnError }: { secp256k1: boolean; retryOnError?: RetryOnError },\n ): Promise<{ pubKey: string; signature: string }> => {\n logger.info(`[device] getPublicKey (${pathString})`);\n const path = getPathFromPathString(pathString);\n const data = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n const curve = secp256k1 ? 0x01 : 0x02;\n const response = await run(\n (transport) => transport.send(0xe0, 0x40, curve, 0x00, data),\n retryOnError ?? genericRetryOnError,\n );\n const pubKeyLength = response.readInt8(0);\n const pubKey = response\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = response\n .slice(pubKeyLength + 1, response.length - STATUS_LENGTH)\n .toString(\"base64\");\n return { pubKey, signature };\n };\n\n const device: Device = {\n authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {\n logger.info(`[device] Authenticate`);\n invariant(role !== \"READ_ONLY_API_KEY\", \"Invalid role for authenticate: READ_ONLY_API_KEY\");\n const applicationBuffer = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n const nameBuffer = Buffer.from(name);\n const workspaceBuffer = Buffer.from(workspaceName);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([nameBuffer.length]),\n nameBuffer,\n Buffer.from([workspaceBuffer.length]),\n workspaceBuffer,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([\n Buffer.from(challenge, \"base64\"),\n applicationBuffer,\n Buffer.from([keyHandle.length]),\n Buffer.from(keyHandle, \"hex\"),\n keyHandleDataLength,\n keyHandleData,\n ]);\n\n const authentication = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x02, 0x00, 0x00], data),\n );\n\n return removeStatus(authentication).toString(\"hex\");\n },\n\n finalizePairingHandshake: async (params: {\n handshake: string;\n partitionId: string;\n handshakeAttestation: HsmCertificate;\n }): Promise<string> => {\n const bufWithStatus = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x47, 0x00, 0x02], buildAttestation(params)),\n );\n return removeStatus(bufWithStatus).toString(\"hex\");\n },\n\n generateSeedFragment: FIXME_NOT_IMPLEMENTED(\"generateSeedFragment\"),\n generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED(\"generateWrappingKeyFragment\"),\n getAttestation: async (): Promise<{\n attestation: {\n codeHash: string;\n attestationPub: string;\n certificate: string;\n };\n buffer: Buffer;\n }> => {\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x41, 0x00, 0x00));\n const buffer = removeStatus(bufWithStatus);\n const certLen = buffer.readInt8(32 + 65 + 1);\n return {\n attestation: {\n codeHash: buffer.slice(0, 32).toString(\"base64\"),\n attestationPub: buffer.slice(32, 32 + 65).toString(\"base64\"),\n certificate: buffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString(\"base64\"),\n },\n buffer,\n };\n },\n getConfidentialityKey: async () => {\n logger.info(`[device] getConfidentialityKey`);\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x4d, 0x00, 0x00));\n const buf = removeStatus(bufWithStatus);\n const keyLength = buf[0]!;\n const key = buf.slice(1, 1 + keyLength);\n const sig = buf.slice(1 + keyLength + 1);\n return {\n confidentialityKeyCurve25519: key.toString(\"hex\"),\n confidentialityKeySignature: sig.toString(\"hex\"),\n };\n },\n getConfidentialityPubKey: () => getPublicKey(PATHS.CONFIDENTIALITY, { secp256k1: true }),\n getDeviceUserId: FIXME_NOT_IMPLEMENTED(\"getDeviceUserId\"),\n getU2FPubKey: () => getPublicKey(PATHS.U2F, { secp256k1: false }),\n getValidationPubKey: () => getPublicKey(PATHS.VALIDATION, { secp256k1: true }),\n hasPairing: async () => {\n logger.info(`[device] hasPairing`);\n const apdu = [0xe0, 0x51, 0x00, 0x00, 0xb5];\n const res = await run((transport) => transport.exchange(Buffer.from(apdu)));\n const hex = Buffer.from(res).toString(\"hex\");\n\n // 6f45 => this error means that there is no partition ID on the device\n // if no error, it means there is (at least) one\n //\n // 6a87 => TEMPORARY hack because Stax apparently does not implement\n // the \"get partition id\" APDU, so it returns \"incorrect length\"\n // easier to just assume that in this case there is no partition,\n // and try to insert one anyway (done on revault onboarding)\n //\n return hex !== \"6f45\" && hex !== \"6a87\";\n },\n\n initPairingHandshake: async (): Promise<{ pubKey: string; signature: string }> => {\n const res = await run((transport) => transport.send(0xe0, 0x46, 0x00, 0x00));\n const pubKeyLength = res.readInt8(0);\n const pubKey = res\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = res.slice(pubKeyLength + 1, res.length - STATUS_LENGTH).toString(\"base64\");\n return { pubKey, signature };\n },\n\n openSession: FIXME_NOT_IMPLEMENTED(\"openSession\"),\n\n register: async (params: {\n challenge: string;\n u2fRegisterData: string;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n }): Promise<{\n u2fRegister: Buffer;\n keyHandle: Buffer;\n rfu: number;\n pubKey: string;\n }> => {\n const { challenge: strChallenge, u2fRegisterData: _, name, role } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const applicationBuf = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n invariant(applicationBuf.length === 32, \"application hex is expected to have 32 bytes\");\n\n const userNameBuff = Buffer.from(name);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([userNameBuff.length]),\n userNameBuff,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([challenge, applicationBuf, keyHandleDataLength, keyHandleData]);\n\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x01, 0x00, 0x00], data),\n );\n\n let i = 0;\n const rfu = response.slice(i, (i += 1))[0]!;\n const pubKey = response.slice(i, (i += 65)).toString(\"hex\");\n const keyHandleLength = response.slice(i, ++i)[0]!;\n const keyHandle = response.slice(i, (i += keyHandleLength));\n return {\n u2fRegister: removeStatus(response),\n keyHandle,\n rfu,\n pubKey,\n };\n },\n registerData: async (params: { challenge: string }): Promise<string> => {\n const { challenge: strChallenge } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const response = await run((transport) => transport.send(0xe0, 0x03, 0x00, 0x00, challenge));\n return removeStatus(response).toString(\"hex\");\n },\n\n setPairing: async ({ pairing }) => {\n logger.info(`[device] setPairing`);\n const psdPayload = Buffer.from(pairing.blob, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(psdPayload.length, 0);\n const final = Buffer.concat([length, psdPayload]);\n await run((transport) => sendByChunk(transport, [0xe0, 0x4e, 0x00, 0x00], final));\n },\n startKKPatternAsResponder: FIXME_NOT_IMPLEMENTED(\"startKKPatternAsResponder\"),\n startKPatternAsResponder: async (params) => {\n logger.info(`[device] startKPatternAsResponder`);\n const data = buildAttestation(params);\n await run((transport) =>\n sendByChunk(transport, [0xe0, 0x49, 0x00, SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data),\n );\n },\n validateVaultOperation: async (params) => {\n logger.info(`[device] validateVaultOperation`);\n const path = getPathFromPathString(PATHS.VALIDATION);\n const paths = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n\n let nextActionId = 1;\n let finalResponse;\n\n while (!finalResponse) {\n const screen = Buffer.from(params.actions[nextActionId - 1]!, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(screen.length, 0);\n const data = Buffer.concat([paths, length, screen]);\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x45, 0x00, 0x00], data),\n );\n const responseType = response.readInt8(0);\n let responseStatus = response.readUInt16BE(response.length - 2);\n if (responseType === STREAMING_NEXT_ACTION) {\n nextActionId = response.readUIntBE(1, 2);\n } else if (responseType === STREAMING_RESPONSE) {\n finalResponse = response.slice(3, response.length - 2);\n /* v8 ignore start */\n while (responseStatus !== 0x9000) {\n const resp = await run((transport) => transport.send(0x00, 0xc0, 0x00, 0x00));\n responseStatus = resp.readUInt16BE(resp.length - 2);\n finalResponse = Buffer.concat([finalResponse, removeStatus(resp)]);\n }\n } else {\n throw Error(`${responseType}`);\n }\n /* v8 ignore stop */\n }\n return finalResponse.toString(\"base64\");\n },\n\n sendAPDU: async (apduCommand: string) => {\n const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, \"hex\")));\n return Buffer.from(res).toString(\"hex\");\n },\n getVersion: async () => {\n const res = await run((transport) => transport.send(0xb0, 0x01, 0x00, 0x00));\n const appNameLen = res.readInt8(1);\n const appVersionLen = res.readInt8(2 + appNameLen);\n const appVersionHex = res.slice(2 + 1 + appNameLen, 2 + appNameLen + appVersionLen + 1);\n\n const appVersion = Buffer.from(appVersionHex).toString();\n\n return appVersion;\n },\n poll,\n pollApp,\n };\n return device;\n}\n","import type { AppRouter } from \"@ledgerhq/revault-api\";\nimport { type TRPCClient, createTRPCClient, httpLink } from \"@trpc/client\";\nimport type { inferRouterInputs, inferRouterOutputs } from \"@trpc/server\";\nimport superjson from \"superjson\";\n\nexport type TRPCClientOptions = {\n baseUrl: string;\n debugAuthToken?: string;\n rootAuthToken?: string;\n apiAccessToken?: string;\n psdAuth?: string;\n};\n\nexport type RevaultApiTRPCClient = TRPCClient<AppRouter>;\n\nexport type RouterInputs = inferRouterInputs<AppRouter>;\nexport type RouterOutputs = inferRouterOutputs<AppRouter>;\n\nexport const createClient = (options: TRPCClientOptions): RevaultApiTRPCClient => {\n const trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: `${options.baseUrl}/trpc`,\n transformer: superjson,\n headers() {\n return {\n ...(options.debugAuthToken\n ? { \"x-revault-debug-auth-token\": options.debugAuthToken }\n : {}),\n ...(options.rootAuthToken\n ? { \"x-revault-root-auth-token\": options.rootAuthToken }\n : {}),\n ...(options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}),\n ...(options.apiAccessToken\n ? { Authorization: `Bearer ${options.apiAccessToken}` }\n : {}),\n };\n },\n }),\n ],\n });\n return trpc;\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/engine.cjs","../src/engine/index.ts","../src/device/real-device.ts","../src/trpc.ts"],"names":["withApiUser","withWorkspace","withOnboarding","client","engine"],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;ACNA,4FAAsB;ADQtB;AACA;AErBA,0CAAsD;AAGtD;AACA,4BAAoC;AAkBpC,IAAM,iBAAA,EAAmB,GAAA;AAMzB,IAAM,sBAAA,EACJ,CAAC,MAAA,EAAA,GACD,MAAA,CAAA,EAAA,GAAY;AACV,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,MAAM,CAAA,CAAA;AAC5C;AAE8D;AACpB,EAAA;AACP,EAAA;AACrC;AAEiE;AAC/C,EAAA;AACyB,EAAA;AACF,IAAA;AACvC,EAAA;AACO,EAAA;AACT;AAE8D;AAK5D;AAG0C,EAAA;AACb,EAAA;AACW,EAAA;AAChB,IAAA;AACE,IAAA;AAGT,IAAA;AAE4B,IAAA;AACzC,MAAA;AACG,MAAA;AACJ,IAAA;AACH,EAAA;AACO,EAAA;AACT;AAMc;AACyB,EAAA;AACC,EAAA;AACA,EAAA;AAEA,EAAA;AACC,EAAA;AACC,EAAA;AAEH,EAAA;AAED,EAAA;AAClC,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AAEuC,EAAA;AACC,EAAA;AACV,EAAA;AAEM,EAAA;AACC,EAAA;AACA,EAAA;AAEC,EAAA;AACD,EAAA;AAEX,EAAA;AACzB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AAEuC,EAAA;AACH,EAAA;AAEP,EAAA;AAEvB,EAAA;AACT;AAImD;AAEX,EAAA;AAEC,EAAA;AAEA,EAAA;AAGhC,EAAA;AACT;AAG2E;AACjD,EAAA;AAIO,EAAA;AAEtB,IAAA;AAC8B,MAAA;AACrC,IAAA;AACF,EAAA;AAG+B,EAAA;AACI,EAAA;AAIK,EAAA;AAEhC,IAAA;AAAA;AAEkB,MAAA;AAAC,MAAA;AACF,uBAAA;AACvB,IAAA;AAEI,IAAA;AAC8B,MAAA;AACL,MAAA;AACf,IAAA;AACuB,MAAA;AACL,QAAA;AAC9B,MAAA;AACM,MAAA;AACR,IAAA;AACF,EAAA;AAE4D,EAAA;AACxC,IAAA;AACK,MAAA;AACvB,IAAA;AAEuC,IAAA;AACd,IAAA;AAC3B,EAAA;AAII,EAAA;AAEoC,IAAA;AACH,IAAA;AACR,IAAA;AACA,MAAA;AACG,MAAA;AACA,QAAA;AACK,QAAA;AACxB,QAAA;AACR,MAAA;AACF,IAAA;AACgC,IAAA;AACV,IAAA;AACqB,MAAA;AAC1B,uBAAA;AAClB,IAAA;AACwC,IAAA;AAE5B,IAAA;AAIH,IAAA;AAEkB,IAAA;AAC7B,EAAA;AAEuB,EAAA;AACe,IAAA;AACC,MAAA;AAChB,MAAA;AACmB,MAAA;AACH,MAAA;AACC,MAAA;AAEA,MAAA;AACA,QAAA;AACH,QAAA;AAC/B,QAAA;AACoC,QAAA;AACpC,QAAA;AACD,MAAA;AAEkC,MAAA;AACD,MAAA;AAEP,MAAA;AACM,QAAA;AAC/B,QAAA;AAC8B,QAAA;AACF,QAAA;AAC5B,QAAA;AACA,QAAA;AACD,MAAA;AAE4B,MAAA;AACf,QAAA;AACd,MAAA;AAEoC,MAAA;AACtC,IAAA;AAEiC,IAAA;AAKH,MAAA;AACd,QAAA;AACd,MAAA;AACmC,MAAA;AACrC,IAAA;AAEsB,IAAA;AACO,IAAA;AAQvB,IAAA;AAC6B,MAAA;AACL,MAAA;AACS,MAAA;AAC9B,MAAA;AACQ,QAAA;AACmB,UAAA;AACG,UAAA;AACE,UAAA;AACrC,QAAA;AACA,QAAA;AACF,MAAA;AACF,IAAA;AACmC,IAAA;AACrB,MAAA;AACqB,MAAA;AACK,MAAA;AACf,MAAA;AACe,MAAA;AACC,MAAA;AAChC,MAAA;AAC6B,QAAA;AACD,QAAA;AACnC,MAAA;AACF,IAAA;AACgC,IAAA;AACO,IAAA;AACA,IAAA;AACC,IAAA;AAChB,IAAA;AACW,MAAA;AACS,MAAA;AACL,MAAA;AACC,MAAA;AAUL,MAAA;AACnC,IAAA;AAEkF,IAAA;AAC3C,MAAA;AACF,MAAA;AAEvB,MAAA;AAGgB,MAAA;AACD,MAAA;AAC7B,IAAA;AAEmC,IAAA;AAY7B,IAAA;AAC6B,MAAA;AACH,MAAA;AAEK,MAAA;AACA,MAAA;AACC,MAAA;AAEC,MAAA;AAED,MAAA;AACA,QAAA;AACD,QAAA;AACjC,QAAA;AACD,MAAA;AAEkC,MAAA;AACD,MAAA;AAEK,MAAA;AAEhB,MAAA;AACT,QAAA;AACd,MAAA;AAEQ,MAAA;AACiC,MAAA;AACF,MAAA;AACA,MAAA;AACF,MAAA;AAC9B,MAAA;AAC6B,QAAA;AAClC,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACF,IAAA;AACwE,IAAA;AAClC,MAAA;AACN,MAAA;AACK,MAAA;AACP,MAAA;AACW,MAAA;AACzC,IAAA;AAEmC,IAAA;AACA,MAAA;AACM,MAAA;AACV,MAAA;AACG,MAAA;AACK,MAAA;AACA,MAAA;AACvC,IAAA;AAC2B,IAAA;AACM,IAAA;AACnB,MAAA;AACwB,MAAA;AAC9B,MAAA;AACQ,QAAA;AACd,MAAA;AACF,IAAA;AAC+B,IAAA;AACjB,MAAA;AACuB,MAAA;AACP,MAAA;AACD,QAAA;AACG,QAAA;AACA,UAAA;AACK,UAAA;AACxB,UAAA;AACR,QAAA;AACF,MAAA;AAEkB,MAAA;AACf,MAAA;AAEmB,MAAA;AACa,QAAA;AACL,QAAA;AACQ,QAAA;AACF,QAAA;AACZ,QAAA;AACT,UAAA;AACd,QAAA;AAC8B,QAAA;AACA,QAAA;AACT,QAAA;AACgB,UAAA;AACT,QAAA;AACQ,UAAA;AAEA,UAAA;AACR,YAAA;AACF,YAAA;AACS,YAAA;AACjC,UAAA;AACK,QAAA;AACwB,UAAA;AAC/B,QAAA;AAEF,MAAA;AACsC,MAAA;AACxC,IAAA;AAEyC,IAAA;AACF,MAAA;AACC,MAAA;AACxC,IAAA;AACwB,IAAA;AACe,MAAA;AACJ,MAAA;AACM,MAAA;AACH,MAAA;AAEL,MAAA;AAExB,MAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACO,EAAA;AACT;AFxH6C;AACA;AGpVe;AAEtC;AAe4D;AACvC,EAAA;AAChC,IAAA;AACI,MAAA;AACgB,QAAA;AACV,QAAA;AACH,QAAA;AACD,UAAA;AAEC,YAAA;AAGA,YAAA;AAEkB,YAAA;AAElB,YAAA;AAER,UAAA;AACF,QAAA;AACD,MAAA;AACH,IAAA;AACD,EAAA;AACM,EAAA;AACT;AHiU6C;AACA;AChUX;AAChC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAaa;AACkB,EAAA;AACP,IAAA;AACF,IAAA;AACY,IAAA;AACjC,EAAA;AACoC,EAAA;AACU,EAAA;AAC7C,IAAA;AACkB,IAAA;AACR,IAAA;AAC6B,IAAA;AACN,IAAA;AACL,IAAA;AACX,MAAA;AACY,MAAA;AAC7B,IAAA;AACF,EAAA;AACuC,EAAA;AACH,EAAA;AACb,IAAA;AACE,IAAA;AACS,IAAA;AACjC,EAAA;AACsC,EAAA;AAChB,IAAA;AACM,IAAA;AAC3B,IAAA;AACA,IAAA;AACD,EAAA;AACqC,EAAA;AACJ,EAAA;AACM,EAAA;AACN,EAAA;AACF,IAAA;AACS,IAAA;AAC3B,IAAA;AACe,IAAA;AACZ,EAAA;AAC4C,EAAA;AAC3D,IAAA;AACa,IAAA;AACI,MAAA;AACa,MAAA;AAC9B,IAAA;AACA,IAAA;AACiC,IAAA;AACD,IAAA;AAChC,IAAA;AACF,EAAA;AAC2C,EAAA;AAC7C;AAE6E;AAClC,EAAA;AACtB,IAAA;AACnB,EAAA;AACyC,EAAA;AACE,EAAA;AAElB,EAAA;AACvB,IAAA;AAC6B,IAAA;AAC/B,EAAA;AAIE,EAAA;AAEyC,IAAA;AACJ,IAAA;AACD,IAAA;AACtC,EAAA;AAIE,EAAA;AAEkC,IAAA;AACG,IAAA;AACD,IAAA;AACtC,EAAA;AAEyE,EAAA;AAClB,IAAA;AACjBA,IAAAA;AACtC,EAAA;AAIE,EAAA;AAEuC,IAAA;AACHC,IAAAA;AACtC,EAAA;AAIE,EAAA;AAEyC,IAAA;AACLC,IAAAA;AACtC,EAAA;AASa,EAAA;AAGH,IAAA;AAC2D,MAAA;AACnE,IAAA;AAImB,IAAA;AACjB,MAAA;AAEK,QAAA;AAC+C,UAAA;AACrB,YAAA;AACS,YAAA;AACCC,YAAAA;AAC1B,YAAA;AACT,UAAA;AACF,QAAA;AACJ,MAAA;AACF,IAAA;AAIsC,IAAA;AACyC,MAAA;AAC/CC,QAAAA;AACrB,QAAA;AAC+E,UAAA;AAC/C,YAAA;AAChB,YAAA;AACG,YAAA;AACW,YAAA;AACnC,UAAA;AACF,QAAA;AACD,MAAA;AACH,IAAA;AAI4B,IAAA;AACyD,MAAA;AACzD,QAAA;AACuB,QAAA;AACd,UAAA;AACZ,UAAA;AACG,YAAA;AACS,YAAA;AAC9B,UAAA;AAC4B,UAAA;AAC3B,YAAA;AACc,YAAA;AACR,YAAA;AAC0B,cAAA;AACD,cAAA;AAC/B,YAAA;AACD,UAAA;AACkC,UAAA;AACrC,QAAA;AACO,QAAA;AACoF,UAAA;AAC1D,YAAA;AACA,YAAA;AACP,cAAA;AACb,cAAA;AACR,YAAA;AACuB,YAAA;AACR,cAAA;AACS,cAAA;AACxB,YAAA;AACH,UAAA;AAEmC,UAAA;AACd,YAAA;AACG,cAAA;AACb,cAAA;AACR,YAAA;AACwB,YAAA;AACR,cAAA;AACO,gBAAA;AACK,gBAAA;AAC3B,cAAA;AACD,YAAA;AAC6B,YAAA;AACJ,YAAA;AACF,YAAA;AACtB,cAAA;AACc,cAAA;AACJ,cAAA;AACR,gBAAA;AACiB,gBAAA;AACK,gBAAA;AACjB,kBAAA;AACQ,kBAAA;AACb,gBAAA;AACF,cAAA;AACD,YAAA;AACH,UAAA;AAEiF,UAAA;AACxD,YAAA;AAErB,YAAA;AAIA,YAAA;AAGoB,YAAA;AACpB,cAAA;AACA,cAAA;AACA,cAAA;AACyB,cAAA;AAEP,gBAAA;AACd,gBAAA;AACA,gBAAA;AACD,cAAA;AACyB,cAAA;AAEH,gBAAA;AACrB,gBAAA;AAAA;AAEU,gBAAA;AACX,cAAA;AACJ,YAAA;AACH,UAAA;AAE0B,UAAA;AACH,YAAA;AACW,YAAA;AACnB,YAAA;AACU,cAAA;AACC,cAAA;AACC,cAAA;AACxB,YAAA;AAC8B,YAAA;AACV,cAAA;AACpB,YAAA;AACuB,YAAA;AACR,cAAA;AACd,cAAA;AACA,cAAA;AACD,YAAA;AACH,UAAA;AAE4B,UAAA;AACL,YAAA;AACY,YAAA;AACX,cAAA;AACE,cAAA;AACvB,YAAA;AACY,YAAA;AACU,cAAA;AACC,cAAA;AACC,cAAA;AACxB,YAAA;AAC+B,YAAA;AACX,cAAA;AACpB,YAAA;AAC8B,YAAA;AACN,cAAA;AACF,cAAA;AACC,cAAA;AACvB,YAAA;AAC0B,YAAA;AACH,YAAA;AACR,cAAA;AACd,cAAA;AACc,cAAA;AACZ,gBAAA;AACA,gBAAA;AACqB,gBAAA;AACC,gBAAA;AACjB,kBAAA;AACkB,kBAAA;AACvB,gBAAA;AACF,cAAA;AACD,YAAA;AACH,UAAA;AACF,QAAA;AACD,MAAA;AACH,IAAA;AAI4B,IAAA;AAC1B,MAAA;AACc,QAAA;AACc,UAAA;AACjB,UAAA;AAI+B,YAAA;AACT,cAAA;AACDD,cAAAA;AACtB,gBAAA;AACe,gBAAA;AAChB,cAAA;AACyB,8BAAA;AACG,cAAA;AAC3B,gBAAA;AACe,gBAAA;AAChB,cAAA;AACmB,cAAA;AACH,gBAAA;AACf,gBAAA;AACA,gBAAA;AAC4B,gBAAA;AAC9B,cAAA;AACwBA,cAAAA;AACS,cAAA;AACnB,gBAAA;AACd,cAAA;AAC0B,cAAA;AACE,cAAA;AACD,cAAA;AAG7B,YAAA;AAIwC,YAAA;AACf,cAAA;AACrB,gBAAA;AACmB,gBAAA;AACA,gBAAA;AACI,gBAAA;AACGA,kBAAAA;AACL,oBAAA;AACF,oBAAA;AACf,oBAAA;AACD,kBAAA;AACM,kBAAA;AACT,gBAAA;AACoB,gBAAA;AAED,kBAAA;AACE,kBAAA;AACjB,kBAAA;AACD,gBAAA;AACJ,cAAA;AACH,YAAA;AACF,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AAIqC,IAAA;AACnC,MAAA;AACc,QAAA;AACM,UAAA;AACT,UAAA;AAGH,YAAA;AAK8B,cAAA;AACN,gBAAA;AACI,gBAAA;AACf,gBAAA;AACZ,cAAA;AACgC,cAAA;AACpB,gBAAA;AACb,cAAA;AAC4B,cAAA;AACD,cAAA;AAG7B,YAAA;AACF,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AAI4B,IAAA;AAC8D,MAAA;AAC3DC,QAAAA;AAEoB,QAAA;AACd,UAAA;AACE,UAAA;AACJ,UAAA;AACG,YAAA;AACD,YAAA;AAC9B,UAAA;AACkC,UAAA;AACrC,QAAA;AAGE,QAAA;AAGqB,UAAA;AACR,UAAA;AACU,YAAA;AACW,YAAA;AACT,YAAA;AACxB,UAAA;AAC2B,0BAAA;AACG,UAAA;AACV,YAAA;AACpB,UAAA;AACM,UAAA;AACT,QAAA;AAEO,QAAA;AAGH,UAAA;AAE4BD,YAAAA;AACR,YAAA;AACI,YAAA;AACO,YAAA;AACjB,cAAA;AACkB,cAAA;AAC/B,YAAA;AACH,UAAA;AAEA,UAAA;AAE0E,UAAA;AAC1C,YAAA;AAChC,UAAA;AACF,QAAA;AACD,MAAA;AACH,IAAA;AAIqC,IAAA;AACsD,MAAA;AACpEC,QAAAA;AACZ,QAAA;AACoF,UAAA;AAC3DD,YAAAA;AACR,YAAA;AACH,YAAA;AACnB,UAAA;AAKoC,UAAA;AACH,YAAA;AACjB,cAAA;AACkB,cAAA;AAC/B,YAAA;AACH,UAAA;AAKoC,UAAA;AACJ,YAAA;AAChB,cAAA;AACkB,cAAA;AAC/B,YAAA;AACH,UAAA;AACF,QAAA;AACD,MAAA;AACH,IAAA;AAEO,IAAA;AACT,EAAA;AAEO,EAAA;AACF,IAAA;AACH,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;ADiN6C;AACA;AACA;AACA;AACA","file":"/home/runner/_work/revault/revault/packages/sdk/lib/engine.cjs","sourcesContent":[null,"import type {\n ApiChallenge,\n ClaimedRole,\n OnboardingSeedChallenge,\n PsdChallenge,\n UserRegistrationChallenge,\n UserRegistrationChallengeResponse,\n UserRegistrationDeviceData,\n UserRegistrationResponse,\n VaultRequestResponse,\n WrappingKeyResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport { type Device, createApiDevice } from \"@/device\";\nimport { createRealDevice } from \"@/device/real-device\";\nimport { type TRPCClientOptions, createClient } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\n\nimport type {\n ApproveRequestParams,\n DecorateWithApiUserAndWorkspaceUnauthenticated,\n DecorateWithDevice,\n DecorateWithDeviceAndOnboarding,\n DecorateWithDeviceAndWorkspaceUnauthenticated,\n DecorateWithWorkspaceApiAuthenticated,\n DecorateWithWorkspacePsdAuthenticated,\n DecorateWithWorkspaceUnauthenticated,\n Engine,\n EngineBase,\n EngineOptions,\n RegisterOnboardingDeviceParams,\n WithApiAuth,\n WithApiUser,\n WithDevice,\n WithOnboarding,\n WithPsdAuth,\n WithWorkspace,\n} from \"./types\";\n\nexport { fetchAll, fetchAllCursor } from \"../utils\";\n\nexport type * from \"./types\";\n\nasync function genericRegister<T>({\n device,\n name,\n role,\n getChallenge,\n submitChallenge,\n}: {\n device: Device;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n getChallenge: (p: {\n pubKey: string;\n deviceData: UserRegistrationDeviceData;\n }) => Promise<UserRegistrationChallenge>;\n submitChallenge: (p: {\n pubKey: string;\n challengeResponse: UserRegistrationChallengeResponse;\n }) => Promise<T>;\n}): Promise<T> {\n const [attestation, u2fPubKey, confidentialityKey] = await Promise.all([\n device.getAttestation(),\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n const ephemeralPubKey = await device.initPairingHandshake();\n const deviceData: UserRegistrationDeviceData = {\n name,\n pubKey: u2fPubKey.pubKey,\n psdModel: \"STAX\",\n confidentialityKey: confidentialityKey.pubKey,\n psdEphemeralKey: ephemeralPubKey.pubKey,\n psdEphemeralKeyAttestation: {\n ...attestation.attestation,\n signature: ephemeralPubKey.signature,\n },\n };\n const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });\n const pairingPayload = await device.finalizePairingHandshake({\n handshake: challenge.handshake,\n partitionId: challenge.ciphertext,\n handshakeAttestation: challenge.handshakeAttestation,\n });\n const register = await device.register({\n challenge: challenge.challenge,\n u2fRegisterData: challenge.u2fRegisterData,\n name,\n role,\n });\n const validationPubKey = await device.getValidationPubKey();\n const registerData = await device.registerData({ challenge: challenge.challenge });\n const attestationOffset = 67 + register.u2fRegister.readInt8(66);\n const u2fRegister = Buffer.concat([\n register.u2fRegister.slice(0, attestationOffset),\n Buffer.from([attestation.buffer.length]),\n attestation.buffer,\n register.u2fRegister.slice(attestationOffset),\n ]).toString(\"hex\");\n const challengeResponse: UserRegistrationChallengeResponse = {\n registerData,\n certificate: {\n ...attestation.attestation,\n signature: validationPubKey.signature,\n },\n u2fRegister,\n u2fKeyHandle: register.keyHandle.toString(\"hex\"),\n validationKey: validationPubKey.pubKey,\n pairingPayload,\n };\n return submitChallenge({ pubKey: u2fPubKey.pubKey, challengeResponse });\n}\n\nexport function createEngine(options: EngineOptions, logger: Logger): Engine {\n const clientOptions: TRPCClientOptions = {\n baseUrl: options.baseUrl,\n };\n const client = createClient(clientOptions);\n const apiDevice = createApiDevice(options, logger);\n\n const base: EngineBase = {\n client,\n createClient: (overrides) => createClient({ ...clientOptions, ...overrides }),\n };\n\n const withDeviceIndex: Engine[\"withDeviceIndex\"] = function <T>(\n this: Engine<T>,\n deviceIndex: number,\n ) {\n const device = apiDevice.with(deviceIndex);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withTransportId: Engine[\"withTransportId\"] = function <T>(\n this: Engine<T>,\n transportId: string,\n ) {\n const device = createRealDevice({ transportId }, logger);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withApiUser: Engine[\"withApiUser\"] = function <T>(this: Engine<T>) {\n const withApiUser: WithApiUser = { __isApiUser: true };\n return decorateEngine({ ...this, ...withApiUser } as Engine<T & WithApiUser>);\n };\n\n const withWorkspace: Engine[\"withWorkspace\"] = function <T>(\n this: Engine<T>,\n workspaceName: string,\n ) {\n const withWorkspace: WithWorkspace = { __workspaceName: workspaceName };\n return decorateEngine({ ...this, ...withWorkspace } as Engine<T & WithWorkspace>);\n };\n\n const withOnboarding: Engine[\"withOnboarding\"] = function <T>(\n this: Engine<T>,\n onboardingId: string,\n ) {\n const withOnboarding: WithOnboarding = { __onboardingId: onboardingId };\n return decorateEngine({ ...this, ...withOnboarding } as Engine<T & WithOnboarding>);\n };\n\n function decorateEngine<T>(\n engine: Engine<\n T &\n Partial<\n WithDevice & WithOnboarding & WithWorkspace & WithPsdAuth & WithApiUser & WithApiAuth\n >\n >,\n ): Engine<T> {\n function decorate<TEnhanced, TDecoration>(\n decorator: (engine: EngineBase & TEnhanced) => TDecoration,\n ): void {\n Object.assign(engine, decorator(engine as EngineBase & TEnhanced));\n }\n\n // DecorateWithDevice\n // -------------------------------------------------------------------------\n if (engine.device) {\n decorate<WithDevice, DecorateWithDevice<T>>(\n (engine) =>\n ({\n getWorkspaces: async (): Promise<string[]> => {\n const { device, client } = engine;\n const { pubKey } = await device.getU2FPubKey();\n const { workspaceNames } = await client.auth.psd.findWorkspaceNames.query({ pubKey });\n return workspaceNames;\n },\n }) satisfies DecorateWithDevice<T>,\n );\n }\n\n // DecorateWithWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && !engine.__psdToken && !engine.__apiAuth) {\n decorate<WithWorkspace, DecorateWithWorkspaceUnauthenticated<T>>((engine) => {\n const { __workspaceName } = engine;\n return {\n withPsdToken: function <T>(this: Engine<T>, token: string): Engine<T & WithPsdAuth> {\n const withPsdAuth: WithPsdAuth = { __psdToken: token };\n const psdAuth = `${__workspaceName}:${token}`;\n const client = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client, ...withPsdAuth } as Engine<T & WithPsdAuth>);\n },\n } satisfies DecorateWithWorkspaceUnauthenticated<T>;\n });\n }\n\n // DecorateWithDeviceAndOnboarding\n // -------------------------------------------------------------------------\n if (engine.device && engine.__onboardingId) {\n decorate<WithDevice & WithOnboarding, DecorateWithDeviceAndOnboarding>((engine) => {\n const { device, client, __onboardingId } = engine;\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityKey(),\n ]);\n const pairing = await client.onboarding.pairDevicePartition.mutate({\n pubKey,\n onboardingId: __onboardingId,\n data: {\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n },\n });\n await device.setPairing({ pairing });\n }\n return {\n claimDevice: async (params: { role: ClaimedRole; deviceName: string }): Promise<void> => {\n const { role, deviceName } = params;\n const [{ pubKey }, { pubKey: confidentialityKey }] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await client.onboarding.claimDevice.mutate({\n onboardingId: __onboardingId,\n claim: { role, pubKey, deviceName, confidentialityKey },\n });\n },\n\n collectWrappingKeyFragment: async (wrappingKey: WrappingKeyResponse): Promise<void> => {\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await device.openSession({\n secureChannel: {\n pubKey: wrappingKey.ephemeralPubKey,\n certificate: wrappingKey.ephemeralCertificate,\n },\n });\n const { attestation } = await device.getAttestation();\n const blob = await device.generateWrappingKeyFragment();\n await client.onboarding.submitWrappingKeyFragment.mutate({\n pubKey,\n onboardingId: __onboardingId,\n fragment: {\n blob,\n ephemeralPubKey: confidentialityKey.pubKey,\n ephemeralCertificate: {\n ...attestation,\n signature: confidentialityKey.signature,\n },\n },\n });\n },\n\n registerDevice: async (params: RegisterOnboardingDeviceParams): Promise<void> => {\n const { role, name } = params;\n const getChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.generateMasterAdminRegistrationChallenge\n : client.onboarding.generateSharedOwnerRegistrationChallenge;\n const submitChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.submitMasterAdminRegistration\n : client.onboarding.submitSharedOwnerRegistration;\n await genericRegister({\n device: device,\n name,\n role,\n getChallenge: ({ pubKey, deviceData }) =>\n getChallengeMutation.mutate({\n onboardingId: __onboardingId,\n pubKey,\n deviceData,\n }),\n submitChallenge: ({ pubKey, challengeResponse }) =>\n submitChallengeMutation.mutate({\n onboardingId: engine.__onboardingId,\n pubKey,\n // FIXME this should be renamed to `challengeResponse` on backend side\n response: challengeResponse,\n }),\n });\n },\n\n reviewSharedOwner: async (challenge: PsdChallenge): Promise<void> => {\n await enforcePairing();\n const { pubKey } = await device.getU2FPubKey();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n await client.onboarding.submitReviewByMasterAdminSignature.mutate({\n onboardingId: __onboardingId,\n pubKey,\n signature,\n });\n },\n\n collectSeedFragment: async (challenge: OnboardingSeedChallenge): Promise<void> => {\n await enforcePairing();\n const [{ pubKey }, { attestation }] = await Promise.all([\n device.getU2FPubKey(),\n device.getAttestation(),\n ]);\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const challengeResponse = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n const kkPattern = await device.startKKPatternAsResponder({\n partitionId: challenge.partitionId,\n handshake: challenge.kkHandshake,\n handshakeAttestation: challenge.kkHandshakeAttestation,\n });\n const approverBlob = await device.generateSeedFragment();\n await client.onboarding.submitSeedFragment.mutate({\n onboardingId: __onboardingId,\n pubKey,\n seedFragment: {\n challengeResponse,\n approverBlob,\n handshake: kkPattern.handshake,\n handshakeAttestation: {\n ...attestation,\n signature: kkPattern.signature,\n },\n },\n });\n },\n } satisfies DecorateWithDeviceAndOnboarding;\n });\n }\n\n // DecorateWithDeviceAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && !engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithDeviceAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { device, client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n opts?: { validityDurationSecs?: number; onScreenDisplayed?: () => void },\n ): Promise<Engine<T & WithPsdAuth>> {\n const { pubKey } = await device.getU2FPubKey();\n const challenge = await client.auth.psd.generateChallenge.mutate({\n pubKey,\n workspaceName: __workspaceName,\n });\n opts?.onScreenDisplayed?.();\n const authentication = await device.authenticate({\n challenge,\n workspaceName: __workspaceName,\n });\n const authPayload = {\n workspaceName: __workspaceName,\n pubKey,\n authentication,\n validityDurationSecs: opts?.validityDurationSecs,\n };\n const { token } = await client.auth.psd.authenticate.mutate({ ...authPayload });\n const withPsdAuth: WithPsdAuth = {\n __psdToken: token,\n };\n const psdAuth = `${engine.__workspaceName}:${token}`;\n const __authClient = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client: __authClient, ...withPsdAuth } as Engine<\n T & WithPsdAuth\n >);\n },\n\n register: (\n registration: UserRegistrationResponse,\n ): Promise<UserRegistrationResponse> => {\n return genericRegister({\n device,\n name: registration.name,\n role: registration.role,\n getChallenge: async ({ deviceData }) => {\n const challenge = await client.userRegistrations.generateChallenge.mutate({\n id: registration.id,\n workspaceName: __workspaceName,\n deviceData,\n });\n return challenge;\n },\n submitChallenge: ({ challengeResponse }) =>\n client.userRegistrations.submitChallenge.mutate({\n workspaceName: __workspaceName,\n id: registration.id,\n challengeResponse,\n }),\n });\n },\n } satisfies DecorateWithDeviceAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithApiUserAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__isApiUser && !engine.__apiAuth) {\n decorate<WithWorkspace & WithApiUser, DecorateWithApiUserAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n credentials: {\n apiKeyId: string;\n apiKeySecret: string;\n },\n ): Promise<Engine<T & WithApiAuth>> {\n const res = await client.auth.authenticate.mutate({\n apiKeyId: credentials.apiKeyId,\n apiKeySecret: credentials.apiKeySecret,\n workspace: __workspaceName,\n });\n const withApiAuth: WithApiAuth = {\n __apiAuth: res,\n };\n const __authClient = engine.createClient({ apiAccessToken: res.accessToken });\n return decorateEngine({ ...this, client: __authClient, ...withApiAuth } as Engine<\n T & WithApiAuth\n >);\n },\n } satisfies DecorateWithApiUserAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithWorkspacePsdAuthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithWorkspacePsdAuthenticated>((engine) => {\n const { client, device } = engine;\n\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const confidentialityKey = await device.getConfidentialityKey();\n const pairing = await client.debug.pairDevicePartition.mutate({\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n });\n await device.setPairing({ pairing });\n }\n\n const approveChallenge = async (\n challenge: PsdChallenge,\n params?: ApproveRequestParams,\n ): Promise<string> => {\n await enforcePairing();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n params?.onScreenDisplayed?.();\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n return signature;\n };\n\n return {\n approve: async (\n request: VaultRequestResponse,\n params?: ApproveRequestParams,\n ): Promise<VaultRequestResponse> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"PSD\", \"Challenge type must be PSD\");\n const signature = await approveChallenge(challenge, params);\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"PSD\", signature },\n });\n },\n\n approveChallenge,\n\n reject: (request: VaultRequestResponse): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({ id: request.id, data: null });\n },\n } satisfies DecorateWithWorkspacePsdAuthenticated;\n });\n }\n\n // DecorateWithWorkspaceApiAuthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__apiAuth) {\n decorate<WithWorkspace & WithApiAuth, DecorateWithWorkspaceApiAuthenticated>((engine) => {\n const { client } = engine;\n return {\n getChallenge: async (request: VaultRequestResponse): Promise<ApiChallenge[\"payload\"]> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"API\", \"Challenge type must be API\");\n return challenge.payload;\n },\n\n approve: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n\n reject: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n } satisfies DecorateWithWorkspaceApiAuthenticated;\n });\n }\n\n return engine;\n }\n\n return {\n ...base,\n withDeviceIndex,\n withTransportId,\n withApiUser,\n withWorkspace,\n withOnboarding,\n };\n}\n","import { DisconnectedDevice, LockedDeviceError } from \"@ledgerhq/errors\";\nimport type Transport from \"@ledgerhq/hw-transport\";\nimport type { HsmCertificate } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport { from, lastValueFrom } from \"rxjs\";\n\nimport type { Logger } from \"@/types\";\n\nimport {\n APPID_VAULT_ADMINISTRATOR,\n PAGINATED_STATUS,\n PATHS,\n SCRIPT_IDS,\n STATUS_LENGTH,\n STREAMING_NEXT_ACTION,\n STREAMING_RESPONSE,\n STR_ROLES,\n} from \"./constants\";\nimport { withDevicePolling } from \"./device-access\";\nimport type { Device } from \"./types\";\nimport { isTransportStatusError } from \"./utils\";\n\nconst MAX_CHUNK_LENGTH = 250;\n\ntype Options = {\n transportId: string;\n};\n\nconst FIXME_NOT_IMPLEMENTED =\n (fnName: string): (() => Promise<never>) =>\n async () => {\n throw new Error(`Not implemented: ${fnName}`);\n };\n\nconst getPathFromPathString = (pathString: string): number[] => {\n const parts = pathString.split(\"'/\").map((part) => parseInt(part, 10));\n return parts.map((part) => (part | 0x80000000) >>> 0);\n};\n\nconst splitChunks = (chunk: number, buffer: Buffer): Buffer[] => {\n const chunks = [];\n for (let i = 0, size = chunk; i < buffer.length; i += size, size = chunk) {\n chunks.push(buffer.slice(i, i + size));\n }\n return chunks;\n};\n\nconst removeStatus = (result: Buffer): Buffer => result.slice(0, result.length - STATUS_LENGTH);\n\nconst sendByChunk = async (\n transport: Transport,\n command: number[], // eg [0xe0, 0x45, 0x00, 0x00]\n data: Buffer,\n chunkSize: number = MAX_CHUNK_LENGTH,\n): Promise<Buffer> => {\n const chunks = splitChunks(chunkSize, data);\n let response = Buffer.from([]);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const apdu = [...command];\n // command is 0xe0,0x45,0x00,0x00 for first chunk, then it's 0xe0,0x45,0x80,0x00\n /* v8 ignore start */\n apdu[2] = i && 0x80;\n /* v8 ignore stop */\n response = (await transport.send(apdu[0]!, apdu[1]!, apdu[2], apdu[3]!, chunk, [\n 0x9000,\n ...PAGINATED_STATUS,\n ])) as Buffer<ArrayBuffer>;\n }\n return response;\n};\n\nconst buildAttestation = (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n}): Buffer => {\n const sigBuffer = Buffer.from(params.handshakeAttestation.signature, \"base64\");\n const sigLengthBuffer = Buffer.alloc(1);\n sigLengthBuffer.writeUIntBE(sigBuffer.length, 0, 1);\n\n const certBuffer = Buffer.from(params.handshakeAttestation.certificate, \"base64\");\n const certLengthBuffer = Buffer.alloc(1);\n certLengthBuffer.writeUIntBE(certBuffer.length, 0, 1);\n\n const pubBuffer = Buffer.from(params.handshakeAttestation.attestationPub, \"base64\");\n\n const certChainData = Buffer.concat([\n sigLengthBuffer,\n sigBuffer,\n pubBuffer,\n certLengthBuffer,\n certBuffer,\n ]);\n\n const cliMsgBuffer = Buffer.from(params.handshake, \"hex\");\n const cliMsgLengthBuffer = Buffer.alloc(1);\n cliMsgLengthBuffer.writeUIntBE(cliMsgBuffer.length, 0, 1);\n\n const pidBuffer = Buffer.from(params.partitionId, \"hex\");\n const pidLengthBuffer = Buffer.alloc(1);\n pidLengthBuffer.writeUIntBE(pidBuffer.length, 0, 1);\n\n const certChainDataLengthBuff = Buffer.alloc(2);\n certChainDataLengthBuff.writeUInt16BE(certChainData.length, 0);\n\n const data = Buffer.concat([\n cliMsgLengthBuffer,\n cliMsgBuffer,\n certChainDataLengthBuff,\n certChainData,\n pidLengthBuffer,\n pidBuffer,\n ]);\n\n const totalLengthBuffer = Buffer.alloc(2);\n totalLengthBuffer.writeUInt16BE(data.length, 0);\n\n const toSend = Buffer.concat([totalLengthBuffer, data]);\n\n return toSend;\n};\n\ntype RetryOnError = (err: Error) => boolean;\n/* v8 ignore start */\nconst genericRetryOnError: RetryOnError = (err) => {\n // device is locked\n if (err instanceof LockedDeviceError) return true;\n // user is on dashboard when receiving a Vault app apdu\n if (isTransportStatusError(err) && err.statusCode === 0x6d09) return true;\n // VG-24797 error that can happen in BLE in some situations (still unclear)\n if (err instanceof DisconnectedDevice) return true;\n\n // for everything else, we don't want to retry\n return false;\n};\n/* v8 ignore stop */\n\nexport function createRealDevice(options: Options, logger: Logger): Device {\n const { transportId } = options;\n\n async function run<T>(\n job: (transport: Transport) => Promise<T>,\n retryOnError: RetryOnError = genericRetryOnError,\n ): Promise<T> {\n return lastValueFrom(\n withDevicePolling(transportId)<T>((transport) => from(job(transport)), retryOnError),\n );\n }\n\n /* v8 ignore start */\n const noRetry = (): boolean => false;\n const alwaysRetry = (): boolean => true;\n /* v8 ignore stop */\n const poll = async (\n opts: { retryOnError?: RetryOnError } = {},\n ): Promise<{ isAppOpened: boolean }> => {\n // waiting for device to be turned on\n await run(\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n async (_transport) => {},\n opts.retryOnError ?? alwaysRetry,\n );\n // checking if app is opened: should return directly on getPubKey\n try {\n await getPublicKey(PATHS.U2F, { secp256k1: true, retryOnError: noRetry });\n return { isAppOpened: true };\n } catch (err) {\n if (isTransportStatusError(err) && genericRetryOnError(err)) {\n return { isAppOpened: false };\n }\n throw err;\n }\n };\n\n const pollApp = async (appName: string): Promise<string> => {\n const res = await run((transport) =>\n transport.send(0xe0, 0xd8, 0x00, 0x00, Buffer.from(appName, \"utf8\")),\n );\n // little delay to give time to the app to be fully opened\n await new Promise((r) => setTimeout(r, 1e3));\n return res.toString(\"hex\");\n };\n\n const getPublicKey = async (\n pathString: string,\n { secp256k1, retryOnError }: { secp256k1: boolean; retryOnError?: RetryOnError },\n ): Promise<{ pubKey: string; signature: string }> => {\n logger.info(`[device] getPublicKey (${pathString})`);\n const path = getPathFromPathString(pathString);\n const data = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n const curve = secp256k1 ? 0x01 : 0x02;\n const response = await run(\n (transport) => transport.send(0xe0, 0x40, curve, 0x00, data),\n retryOnError ?? genericRetryOnError,\n );\n const pubKeyLength = response.readInt8(0);\n const pubKey = response\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = response\n .slice(pubKeyLength + 1, response.length - STATUS_LENGTH)\n .toString(\"base64\");\n return { pubKey, signature };\n };\n\n const device: Device = {\n authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {\n logger.info(`[device] Authenticate`);\n invariant(role !== \"READ_ONLY_API_KEY\", \"Invalid role for authenticate: READ_ONLY_API_KEY\");\n const applicationBuffer = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n const nameBuffer = Buffer.from(name);\n const workspaceBuffer = Buffer.from(workspaceName);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([nameBuffer.length]),\n nameBuffer,\n Buffer.from([workspaceBuffer.length]),\n workspaceBuffer,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([\n Buffer.from(challenge, \"base64\"),\n applicationBuffer,\n Buffer.from([keyHandle.length]),\n Buffer.from(keyHandle, \"hex\"),\n keyHandleDataLength,\n keyHandleData,\n ]);\n\n const authentication = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x02, 0x00, 0x00], data),\n );\n\n return removeStatus(authentication).toString(\"hex\");\n },\n\n finalizePairingHandshake: async (params: {\n handshake: string;\n partitionId: string;\n handshakeAttestation: HsmCertificate;\n }): Promise<string> => {\n const bufWithStatus = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x47, 0x00, 0x02], buildAttestation(params)),\n );\n return removeStatus(bufWithStatus).toString(\"hex\");\n },\n\n generateSeedFragment: FIXME_NOT_IMPLEMENTED(\"generateSeedFragment\"),\n generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED(\"generateWrappingKeyFragment\"),\n getAttestation: async (): Promise<{\n attestation: {\n codeHash: string;\n attestationPub: string;\n certificate: string;\n };\n buffer: Buffer;\n }> => {\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x41, 0x00, 0x00));\n const buffer = removeStatus(bufWithStatus);\n const certLen = buffer.readInt8(32 + 65 + 1);\n return {\n attestation: {\n codeHash: buffer.slice(0, 32).toString(\"base64\"),\n attestationPub: buffer.slice(32, 32 + 65).toString(\"base64\"),\n certificate: buffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString(\"base64\"),\n },\n buffer,\n };\n },\n getConfidentialityKey: async () => {\n logger.info(`[device] getConfidentialityKey`);\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x4d, 0x00, 0x00));\n const buf = removeStatus(bufWithStatus);\n const keyLength = buf[0]!;\n const key = buf.slice(1, 1 + keyLength);\n const sig = buf.slice(1 + keyLength + 1);\n return {\n confidentialityKeyCurve25519: key.toString(\"hex\"),\n confidentialityKeySignature: sig.toString(\"hex\"),\n };\n },\n getConfidentialityPubKey: () => getPublicKey(PATHS.CONFIDENTIALITY, { secp256k1: true }),\n getDeviceUserId: FIXME_NOT_IMPLEMENTED(\"getDeviceUserId\"),\n getU2FPubKey: () => getPublicKey(PATHS.U2F, { secp256k1: false }),\n getValidationPubKey: () => getPublicKey(PATHS.VALIDATION, { secp256k1: true }),\n hasPairing: async () => {\n logger.info(`[device] hasPairing`);\n const apdu = [0xe0, 0x51, 0x00, 0x00, 0xb5];\n const res = await run((transport) => transport.exchange(Buffer.from(apdu)));\n const hex = Buffer.from(res).toString(\"hex\");\n\n // 6f45 => this error means that there is no partition ID on the device\n // if no error, it means there is (at least) one\n //\n // 6a87 => TEMPORARY hack because Stax apparently does not implement\n // the \"get partition id\" APDU, so it returns \"incorrect length\"\n // easier to just assume that in this case there is no partition,\n // and try to insert one anyway (done on revault onboarding)\n //\n return hex !== \"6f45\" && hex !== \"6a87\";\n },\n\n initPairingHandshake: async (): Promise<{ pubKey: string; signature: string }> => {\n const res = await run((transport) => transport.send(0xe0, 0x46, 0x00, 0x00));\n const pubKeyLength = res.readInt8(0);\n const pubKey = res\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = res.slice(pubKeyLength + 1, res.length - STATUS_LENGTH).toString(\"base64\");\n return { pubKey, signature };\n },\n\n openSession: FIXME_NOT_IMPLEMENTED(\"openSession\"),\n\n register: async (params: {\n challenge: string;\n u2fRegisterData: string;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n }): Promise<{\n u2fRegister: Buffer;\n keyHandle: Buffer;\n rfu: number;\n pubKey: string;\n }> => {\n const { challenge: strChallenge, u2fRegisterData: _, name, role } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const applicationBuf = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n invariant(applicationBuf.length === 32, \"application hex is expected to have 32 bytes\");\n\n const userNameBuff = Buffer.from(name);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([userNameBuff.length]),\n userNameBuff,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([challenge, applicationBuf, keyHandleDataLength, keyHandleData]);\n\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x01, 0x00, 0x00], data),\n );\n\n let i = 0;\n const rfu = response.slice(i, (i += 1))[0]!;\n const pubKey = response.slice(i, (i += 65)).toString(\"hex\");\n const keyHandleLength = response.slice(i, ++i)[0]!;\n const keyHandle = response.slice(i, (i += keyHandleLength));\n return {\n u2fRegister: removeStatus(response),\n keyHandle,\n rfu,\n pubKey,\n };\n },\n registerData: async (params: { challenge: string }): Promise<string> => {\n const { challenge: strChallenge } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const response = await run((transport) => transport.send(0xe0, 0x03, 0x00, 0x00, challenge));\n return removeStatus(response).toString(\"hex\");\n },\n\n setPairing: async ({ pairing }) => {\n logger.info(`[device] setPairing`);\n const psdPayload = Buffer.from(pairing.blob, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(psdPayload.length, 0);\n const final = Buffer.concat([length, psdPayload]);\n await run((transport) => sendByChunk(transport, [0xe0, 0x4e, 0x00, 0x00], final));\n },\n startKKPatternAsResponder: FIXME_NOT_IMPLEMENTED(\"startKKPatternAsResponder\"),\n startKPatternAsResponder: async (params) => {\n logger.info(`[device] startKPatternAsResponder`);\n const data = buildAttestation(params);\n await run((transport) =>\n sendByChunk(transport, [0xe0, 0x49, 0x00, SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data),\n );\n },\n validateVaultOperation: async (params) => {\n logger.info(`[device] validateVaultOperation`);\n const path = getPathFromPathString(PATHS.VALIDATION);\n const paths = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n\n let nextActionId = 1;\n let finalResponse;\n\n while (!finalResponse) {\n const screen = Buffer.from(params.actions[nextActionId - 1]!, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(screen.length, 0);\n const data = Buffer.concat([paths, length, screen]);\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x45, 0x00, 0x00], data),\n );\n const responseType = response.readInt8(0);\n let responseStatus = response.readUInt16BE(response.length - 2);\n if (responseType === STREAMING_NEXT_ACTION) {\n nextActionId = response.readUIntBE(1, 2);\n } else if (responseType === STREAMING_RESPONSE) {\n finalResponse = response.slice(3, response.length - 2);\n /* v8 ignore start */\n while (responseStatus !== 0x9000) {\n const resp = await run((transport) => transport.send(0x00, 0xc0, 0x00, 0x00));\n responseStatus = resp.readUInt16BE(resp.length - 2);\n finalResponse = Buffer.concat([finalResponse, removeStatus(resp)]);\n }\n } else {\n throw Error(`${responseType}`);\n }\n /* v8 ignore stop */\n }\n return finalResponse.toString(\"base64\");\n },\n\n sendAPDU: async (apduCommand: string) => {\n const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, \"hex\")));\n return Buffer.from(res).toString(\"hex\");\n },\n getVersion: async () => {\n const res = await run((transport) => transport.send(0xb0, 0x01, 0x00, 0x00));\n const appNameLen = res.readInt8(1);\n const appVersionLen = res.readInt8(2 + appNameLen);\n const appVersionHex = res.slice(2 + 1 + appNameLen, 2 + appNameLen + appVersionLen + 1);\n\n const appVersion = Buffer.from(appVersionHex).toString();\n\n return appVersion;\n },\n poll,\n pollApp,\n };\n return device;\n}\n","import type { AppRouter } from \"@ledgerhq/revault-api\";\nimport { type TRPCClient, createTRPCClient, httpLink } from \"@trpc/client\";\nimport type { inferRouterInputs, inferRouterOutputs } from \"@trpc/server\";\nimport superjson from \"superjson\";\n\nexport type TRPCClientOptions = {\n baseUrl: string;\n debugAuthToken?: string;\n rootAuthToken?: string;\n apiAccessToken?: string;\n psdAuth?: string;\n};\n\nexport type RevaultApiTRPCClient = TRPCClient<AppRouter>;\n\nexport type RouterInputs = inferRouterInputs<AppRouter>;\nexport type RouterOutputs = inferRouterOutputs<AppRouter>;\n\nexport const createClient = (options: TRPCClientOptions): RevaultApiTRPCClient => {\n const trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: `${options.baseUrl}/trpc`,\n transformer: superjson,\n headers() {\n return {\n ...(options.debugAuthToken\n ? { \"x-revault-debug-auth-token\": options.debugAuthToken }\n : {}),\n ...(options.rootAuthToken\n ? { \"x-revault-root-auth-token\": options.rootAuthToken }\n : {}),\n ...(options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}),\n ...(options.apiAccessToken\n ? { Authorization: `Bearer ${options.apiAccessToken}` }\n : {}),\n };\n },\n }),\n ],\n });\n return trpc;\n};\n"]}
package/lib/engine.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { L as Logger } from './types-DNEewSJL.cjs';
2
- import { a as EngineOptions, E as Engine } from './types-DcbTP2K6.cjs';
3
- export { A as ApproveRequestParams, m as DecorateWithApiUserAndWorkspaceUnauthenticated, D as DecorateWithDevice, e as DecorateWithDeviceAndOnboarding, k as DecorateWithDeviceAndWorkspaceUnauthenticated, g as DecorateWithWorkspace, j as DecorateWithWorkspaceApiAuthenticated, i as DecorateWithWorkspacePsdAuthenticated, h as DecorateWithWorkspaceUnauthenticated, b as EngineBase, R as RegisterOnboardingDeviceParams, n as WithApiAuth, d as WithApiUser, c as WithDevice, W as WithOnboarding, l as WithPsdAuth, f as WithWorkspace } from './types-DcbTP2K6.cjs';
4
- import { Paginated } from '@ledgerhq/revault-api';
2
+ import { a as EngineOptions, E as Engine } from './types-CAKnCFJk.cjs';
3
+ export { A as ApproveRequestParams, m as DecorateWithApiUserAndWorkspaceUnauthenticated, D as DecorateWithDevice, e as DecorateWithDeviceAndOnboarding, k as DecorateWithDeviceAndWorkspaceUnauthenticated, g as DecorateWithWorkspace, j as DecorateWithWorkspaceApiAuthenticated, i as DecorateWithWorkspacePsdAuthenticated, h as DecorateWithWorkspaceUnauthenticated, b as EngineBase, R as RegisterOnboardingDeviceParams, n as WithApiAuth, d as WithApiUser, c as WithDevice, W as WithOnboarding, l as WithPsdAuth, f as WithWorkspace } from './types-CAKnCFJk.cjs';
4
+ import { Paginated, CursorPaginated } from '@ledgerhq/revault-api';
5
5
  import './types-DJfbanPz.cjs';
6
6
  import './index-YRqsGEDY.cjs';
7
7
  import '@trpc/client';
@@ -13,7 +13,13 @@ import '@trpc/server';
13
13
  declare function fetchAll<TData, TQuery extends {
14
14
  page?: number;
15
15
  }>(queryFn: (query: TQuery) => Promise<Paginated<TData>>, query: TQuery): Promise<TData[]>;
16
+ /**
17
+ * Utility function that collect results on all cursors until cursor is null
18
+ */
19
+ declare function fetchAllCursor<TData, TQuery extends {
20
+ cursor?: number;
21
+ }>(queryFn: (query: TQuery) => Promise<CursorPaginated<TData>>, query: TQuery): Promise<TData[]>;
16
22
 
17
23
  declare function createEngine(options: EngineOptions, logger: Logger): Engine;
18
24
 
19
- export { Engine, EngineOptions, createEngine, fetchAll };
25
+ export { Engine, EngineOptions, createEngine, fetchAll, fetchAllCursor };
package/lib/engine.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { L as Logger } from './types-DNEewSJL.js';
2
- import { a as EngineOptions, E as Engine } from './types-CdSLzGGm.js';
3
- export { A as ApproveRequestParams, m as DecorateWithApiUserAndWorkspaceUnauthenticated, D as DecorateWithDevice, e as DecorateWithDeviceAndOnboarding, k as DecorateWithDeviceAndWorkspaceUnauthenticated, g as DecorateWithWorkspace, j as DecorateWithWorkspaceApiAuthenticated, i as DecorateWithWorkspacePsdAuthenticated, h as DecorateWithWorkspaceUnauthenticated, b as EngineBase, R as RegisterOnboardingDeviceParams, n as WithApiAuth, d as WithApiUser, c as WithDevice, W as WithOnboarding, l as WithPsdAuth, f as WithWorkspace } from './types-CdSLzGGm.js';
4
- import { Paginated } from '@ledgerhq/revault-api';
2
+ import { a as EngineOptions, E as Engine } from './types-mZnXORz9.js';
3
+ export { A as ApproveRequestParams, m as DecorateWithApiUserAndWorkspaceUnauthenticated, D as DecorateWithDevice, e as DecorateWithDeviceAndOnboarding, k as DecorateWithDeviceAndWorkspaceUnauthenticated, g as DecorateWithWorkspace, j as DecorateWithWorkspaceApiAuthenticated, i as DecorateWithWorkspacePsdAuthenticated, h as DecorateWithWorkspaceUnauthenticated, b as EngineBase, R as RegisterOnboardingDeviceParams, n as WithApiAuth, d as WithApiUser, c as WithDevice, W as WithOnboarding, l as WithPsdAuth, f as WithWorkspace } from './types-mZnXORz9.js';
4
+ import { Paginated, CursorPaginated } from '@ledgerhq/revault-api';
5
5
  import './types-DJfbanPz.js';
6
6
  import './index-znHBELBb.js';
7
7
  import '@trpc/client';
@@ -13,7 +13,13 @@ import '@trpc/server';
13
13
  declare function fetchAll<TData, TQuery extends {
14
14
  page?: number;
15
15
  }>(queryFn: (query: TQuery) => Promise<Paginated<TData>>, query: TQuery): Promise<TData[]>;
16
+ /**
17
+ * Utility function that collect results on all cursors until cursor is null
18
+ */
19
+ declare function fetchAllCursor<TData, TQuery extends {
20
+ cursor?: number;
21
+ }>(queryFn: (query: TQuery) => Promise<CursorPaginated<TData>>, query: TQuery): Promise<TData[]>;
16
22
 
17
23
  declare function createEngine(options: EngineOptions, logger: Logger): Engine;
18
24
 
19
- export { Engine, EngineOptions, createEngine, fetchAll };
25
+ export { Engine, EngineOptions, createEngine, fetchAll, fetchAllCursor };
package/lib/engine.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
- fetchAll
3
- } from "./chunk-VHZJP75X.js";
2
+ fetchAll,
3
+ fetchAllCursor
4
+ } from "./chunk-PEHCVOGV.js";
4
5
  import {
5
6
  APPID_VAULT_ADMINISTRATOR,
6
7
  PAGINATED_STATUS,
@@ -700,25 +701,30 @@ function createEngine(options, logger) {
700
701
  });
701
702
  await device.setPairing({ pairing });
702
703
  }
704
+ const approveChallenge = async (challenge, params) => {
705
+ await enforcePairing();
706
+ await device.startKPatternAsResponder({
707
+ handshake: challenge.handshake,
708
+ handshakeAttestation: challenge.handshakeAttestation,
709
+ partitionId: challenge.partitionId
710
+ });
711
+ params?.onScreenDisplayed?.();
712
+ const signature = await device.validateVaultOperation({
713
+ actions: challenge.wActions
714
+ });
715
+ return signature;
716
+ };
703
717
  return {
704
718
  approve: async (request, params) => {
705
719
  const { challenge } = await client2.requests.getChallenge.query({ id: request.id });
706
720
  invariant2(challenge.challengeType === "PSD", "Challenge type must be PSD");
707
- await enforcePairing();
708
- await device.startKPatternAsResponder({
709
- handshake: challenge.handshake,
710
- handshakeAttestation: challenge.handshakeAttestation,
711
- partitionId: challenge.partitionId
712
- });
713
- params?.onScreenDisplayed?.();
714
- const signature = await device.validateVaultOperation({
715
- actions: challenge.wActions
716
- });
721
+ const signature = await approveChallenge(challenge, params);
717
722
  return client2.requests.approve.mutate({
718
723
  id: request.id,
719
724
  data: { challengeType: "PSD", signature }
720
725
  });
721
726
  },
727
+ approveChallenge,
722
728
  reject: (request) => {
723
729
  return client2.requests.reject.mutate({ id: request.id, data: null });
724
730
  }
@@ -762,6 +768,7 @@ function createEngine(options, logger) {
762
768
  }
763
769
  export {
764
770
  createEngine,
765
- fetchAll
771
+ fetchAll,
772
+ fetchAllCursor
766
773
  };
767
774
  //# sourceMappingURL=engine.js.map
package/lib/engine.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine/index.ts","../src/device/real-device.ts","../src/trpc.ts"],"sourcesContent":["import type {\n ApiChallenge,\n ClaimedRole,\n OnboardingSeedChallenge,\n PsdChallenge,\n UserRegistrationChallenge,\n UserRegistrationChallengeResponse,\n UserRegistrationDeviceData,\n UserRegistrationResponse,\n VaultRequestResponse,\n WrappingKeyResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport { type Device, createApiDevice } from \"@/device\";\nimport { createRealDevice } from \"@/device/real-device\";\nimport { type TRPCClientOptions, createClient } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\n\nimport type {\n ApproveRequestParams,\n DecorateWithApiUserAndWorkspaceUnauthenticated,\n DecorateWithDevice,\n DecorateWithDeviceAndOnboarding,\n DecorateWithDeviceAndWorkspaceUnauthenticated,\n DecorateWithWorkspaceApiAuthenticated,\n DecorateWithWorkspacePsdAuthenticated,\n DecorateWithWorkspaceUnauthenticated,\n Engine,\n EngineBase,\n EngineOptions,\n RegisterOnboardingDeviceParams,\n WithApiAuth,\n WithApiUser,\n WithDevice,\n WithOnboarding,\n WithPsdAuth,\n WithWorkspace,\n} from \"./types\";\n\nexport { fetchAll } from \"../utils\";\n\nexport type * from \"./types\";\n\nasync function genericRegister<T>({\n device,\n name,\n role,\n getChallenge,\n submitChallenge,\n}: {\n device: Device;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n getChallenge: (p: {\n pubKey: string;\n deviceData: UserRegistrationDeviceData;\n }) => Promise<UserRegistrationChallenge>;\n submitChallenge: (p: {\n pubKey: string;\n challengeResponse: UserRegistrationChallengeResponse;\n }) => Promise<T>;\n}): Promise<T> {\n const [attestation, u2fPubKey, confidentialityKey] = await Promise.all([\n device.getAttestation(),\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n const ephemeralPubKey = await device.initPairingHandshake();\n const deviceData: UserRegistrationDeviceData = {\n name,\n pubKey: u2fPubKey.pubKey,\n psdModel: \"STAX\",\n confidentialityKey: confidentialityKey.pubKey,\n psdEphemeralKey: ephemeralPubKey.pubKey,\n psdEphemeralKeyAttestation: {\n ...attestation.attestation,\n signature: ephemeralPubKey.signature,\n },\n };\n const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });\n const pairingPayload = await device.finalizePairingHandshake({\n handshake: challenge.handshake,\n partitionId: challenge.ciphertext,\n handshakeAttestation: challenge.handshakeAttestation,\n });\n const register = await device.register({\n challenge: challenge.challenge,\n u2fRegisterData: challenge.u2fRegisterData,\n name,\n role,\n });\n const validationPubKey = await device.getValidationPubKey();\n const registerData = await device.registerData({ challenge: challenge.challenge });\n const attestationOffset = 67 + register.u2fRegister.readInt8(66);\n const u2fRegister = Buffer.concat([\n register.u2fRegister.slice(0, attestationOffset),\n Buffer.from([attestation.buffer.length]),\n attestation.buffer,\n register.u2fRegister.slice(attestationOffset),\n ]).toString(\"hex\");\n const challengeResponse: UserRegistrationChallengeResponse = {\n registerData,\n certificate: {\n ...attestation.attestation,\n signature: validationPubKey.signature,\n },\n u2fRegister,\n u2fKeyHandle: register.keyHandle.toString(\"hex\"),\n validationKey: validationPubKey.pubKey,\n pairingPayload,\n };\n return submitChallenge({ pubKey: u2fPubKey.pubKey, challengeResponse });\n}\n\nexport function createEngine(options: EngineOptions, logger: Logger): Engine {\n const clientOptions: TRPCClientOptions = {\n baseUrl: options.baseUrl,\n };\n const client = createClient(clientOptions);\n const apiDevice = createApiDevice(options, logger);\n\n const base: EngineBase = {\n client,\n createClient: (overrides) => createClient({ ...clientOptions, ...overrides }),\n };\n\n const withDeviceIndex: Engine[\"withDeviceIndex\"] = function <T>(\n this: Engine<T>,\n deviceIndex: number,\n ) {\n const device = apiDevice.with(deviceIndex);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withTransportId: Engine[\"withTransportId\"] = function <T>(\n this: Engine<T>,\n transportId: string,\n ) {\n const device = createRealDevice({ transportId }, logger);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withApiUser: Engine[\"withApiUser\"] = function <T>(this: Engine<T>) {\n const withApiUser: WithApiUser = { __isApiUser: true };\n return decorateEngine({ ...this, ...withApiUser } as Engine<T & WithApiUser>);\n };\n\n const withWorkspace: Engine[\"withWorkspace\"] = function <T>(\n this: Engine<T>,\n workspaceName: string,\n ) {\n const withWorkspace: WithWorkspace = { __workspaceName: workspaceName };\n return decorateEngine({ ...this, ...withWorkspace } as Engine<T & WithWorkspace>);\n };\n\n const withOnboarding: Engine[\"withOnboarding\"] = function <T>(\n this: Engine<T>,\n onboardingId: string,\n ) {\n const withOnboarding: WithOnboarding = { __onboardingId: onboardingId };\n return decorateEngine({ ...this, ...withOnboarding } as Engine<T & WithOnboarding>);\n };\n\n function decorateEngine<T>(\n engine: Engine<\n T &\n Partial<\n WithDevice & WithOnboarding & WithWorkspace & WithPsdAuth & WithApiUser & WithApiAuth\n >\n >,\n ): Engine<T> {\n function decorate<TEnhanced, TDecoration>(\n decorator: (engine: EngineBase & TEnhanced) => TDecoration,\n ): void {\n Object.assign(engine, decorator(engine as EngineBase & TEnhanced));\n }\n\n // DecorateWithDevice\n // -------------------------------------------------------------------------\n if (engine.device) {\n decorate<WithDevice, DecorateWithDevice<T>>(\n (engine) =>\n ({\n getWorkspaces: async (): Promise<string[]> => {\n const { device, client } = engine;\n const { pubKey } = await device.getU2FPubKey();\n const { workspaceNames } = await client.auth.psd.findWorkspaceNames.query({ pubKey });\n return workspaceNames;\n },\n }) satisfies DecorateWithDevice<T>,\n );\n }\n\n // DecorateWithWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && !engine.__psdToken && !engine.__apiAuth) {\n decorate<WithWorkspace, DecorateWithWorkspaceUnauthenticated<T>>((engine) => {\n const { __workspaceName } = engine;\n return {\n withPsdToken: function <T>(this: Engine<T>, token: string): Engine<T & WithPsdAuth> {\n const withPsdAuth: WithPsdAuth = { __psdToken: token };\n const psdAuth = `${__workspaceName}:${token}`;\n const client = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client, ...withPsdAuth } as Engine<T & WithPsdAuth>);\n },\n } satisfies DecorateWithWorkspaceUnauthenticated<T>;\n });\n }\n\n // DecorateWithDeviceAndOnboarding\n // -------------------------------------------------------------------------\n if (engine.device && engine.__onboardingId) {\n decorate<WithDevice & WithOnboarding, DecorateWithDeviceAndOnboarding>((engine) => {\n const { device, client, __onboardingId } = engine;\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityKey(),\n ]);\n const pairing = await client.onboarding.pairDevicePartition.mutate({\n pubKey,\n onboardingId: __onboardingId,\n data: {\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n },\n });\n await device.setPairing({ pairing });\n }\n return {\n claimDevice: async (params: { role: ClaimedRole; deviceName: string }): Promise<void> => {\n const { role, deviceName } = params;\n const [{ pubKey }, { pubKey: confidentialityKey }] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await client.onboarding.claimDevice.mutate({\n onboardingId: __onboardingId,\n claim: { role, pubKey, deviceName, confidentialityKey },\n });\n },\n\n collectWrappingKeyFragment: async (wrappingKey: WrappingKeyResponse): Promise<void> => {\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await device.openSession({\n secureChannel: {\n pubKey: wrappingKey.ephemeralPubKey,\n certificate: wrappingKey.ephemeralCertificate,\n },\n });\n const { attestation } = await device.getAttestation();\n const blob = await device.generateWrappingKeyFragment();\n await client.onboarding.submitWrappingKeyFragment.mutate({\n pubKey,\n onboardingId: __onboardingId,\n fragment: {\n blob,\n ephemeralPubKey: confidentialityKey.pubKey,\n ephemeralCertificate: {\n ...attestation,\n signature: confidentialityKey.signature,\n },\n },\n });\n },\n\n registerDevice: async (params: RegisterOnboardingDeviceParams): Promise<void> => {\n const { role, name } = params;\n const getChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.generateMasterAdminRegistrationChallenge\n : client.onboarding.generateSharedOwnerRegistrationChallenge;\n const submitChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.submitMasterAdminRegistration\n : client.onboarding.submitSharedOwnerRegistration;\n await genericRegister({\n device: device,\n name,\n role,\n getChallenge: ({ pubKey, deviceData }) =>\n getChallengeMutation.mutate({\n onboardingId: __onboardingId,\n pubKey,\n deviceData,\n }),\n submitChallenge: ({ pubKey, challengeResponse }) =>\n submitChallengeMutation.mutate({\n onboardingId: engine.__onboardingId,\n pubKey,\n // FIXME this should be renamed to `challengeResponse` on backend side\n response: challengeResponse,\n }),\n });\n },\n\n reviewSharedOwner: async (challenge: PsdChallenge): Promise<void> => {\n await enforcePairing();\n const { pubKey } = await device.getU2FPubKey();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n await client.onboarding.submitReviewByMasterAdminSignature.mutate({\n onboardingId: __onboardingId,\n pubKey,\n signature,\n });\n },\n\n collectSeedFragment: async (challenge: OnboardingSeedChallenge): Promise<void> => {\n await enforcePairing();\n const [{ pubKey }, { attestation }] = await Promise.all([\n device.getU2FPubKey(),\n device.getAttestation(),\n ]);\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const challengeResponse = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n const kkPattern = await device.startKKPatternAsResponder({\n partitionId: challenge.partitionId,\n handshake: challenge.kkHandshake,\n handshakeAttestation: challenge.kkHandshakeAttestation,\n });\n const approverBlob = await device.generateSeedFragment();\n await client.onboarding.submitSeedFragment.mutate({\n onboardingId: __onboardingId,\n pubKey,\n seedFragment: {\n challengeResponse,\n approverBlob,\n handshake: kkPattern.handshake,\n handshakeAttestation: {\n ...attestation,\n signature: kkPattern.signature,\n },\n },\n });\n },\n } satisfies DecorateWithDeviceAndOnboarding;\n });\n }\n\n // DecorateWithDeviceAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && !engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithDeviceAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { device, client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n opts?: { validityDurationSecs?: number; onScreenDisplayed?: () => void },\n ): Promise<Engine<T & WithPsdAuth>> {\n const { pubKey } = await device.getU2FPubKey();\n const challenge = await client.auth.psd.generateChallenge.mutate({\n pubKey,\n workspaceName: __workspaceName,\n });\n opts?.onScreenDisplayed?.();\n const authentication = await device.authenticate({\n challenge,\n workspaceName: __workspaceName,\n });\n const authPayload = {\n workspaceName: __workspaceName,\n pubKey,\n authentication,\n validityDurationSecs: opts?.validityDurationSecs,\n };\n const { token } = await client.auth.psd.authenticate.mutate({ ...authPayload });\n const withPsdAuth: WithPsdAuth = {\n __psdToken: token,\n };\n const psdAuth = `${engine.__workspaceName}:${token}`;\n const __authClient = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client: __authClient, ...withPsdAuth } as Engine<\n T & WithPsdAuth\n >);\n },\n\n register: (\n registration: UserRegistrationResponse,\n ): Promise<UserRegistrationResponse> => {\n return genericRegister({\n device,\n name: registration.name,\n role: registration.role,\n getChallenge: async ({ deviceData }) => {\n const challenge = await client.userRegistrations.generateChallenge.mutate({\n id: registration.id,\n workspaceName: __workspaceName,\n deviceData,\n });\n return challenge;\n },\n submitChallenge: ({ challengeResponse }) =>\n client.userRegistrations.submitChallenge.mutate({\n workspaceName: __workspaceName,\n id: registration.id,\n challengeResponse,\n }),\n });\n },\n } satisfies DecorateWithDeviceAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithApiUserAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__isApiUser && !engine.__apiAuth) {\n decorate<WithWorkspace & WithApiUser, DecorateWithApiUserAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n credentials: {\n apiKeyId: string;\n apiKeySecret: string;\n },\n ): Promise<Engine<T & WithApiAuth>> {\n const res = await client.auth.authenticate.mutate({\n apiKeyId: credentials.apiKeyId,\n apiKeySecret: credentials.apiKeySecret,\n workspace: __workspaceName,\n });\n const withApiAuth: WithApiAuth = {\n __apiAuth: res,\n };\n const __authClient = engine.createClient({ apiAccessToken: res.accessToken });\n return decorateEngine({ ...this, client: __authClient, ...withApiAuth } as Engine<\n T & WithApiAuth\n >);\n },\n } satisfies DecorateWithApiUserAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithWorkspacePsdAuthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithWorkspacePsdAuthenticated>((engine) => {\n const { client, device } = engine;\n\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const confidentialityKey = await device.getConfidentialityKey();\n const pairing = await client.debug.pairDevicePartition.mutate({\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n });\n await device.setPairing({ pairing });\n }\n\n return {\n approve: async (\n request: VaultRequestResponse,\n params?: ApproveRequestParams,\n ): Promise<VaultRequestResponse> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"PSD\", \"Challenge type must be PSD\");\n await enforcePairing();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n params?.onScreenDisplayed?.();\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"PSD\", signature },\n });\n },\n\n reject: (request: VaultRequestResponse): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({ id: request.id, data: null });\n },\n } satisfies DecorateWithWorkspacePsdAuthenticated;\n });\n }\n\n // DecorateWithWorkspaceApiAuthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__apiAuth) {\n decorate<WithWorkspace & WithApiAuth, DecorateWithWorkspaceApiAuthenticated>((engine) => {\n const { client } = engine;\n return {\n getChallenge: async (request: VaultRequestResponse): Promise<ApiChallenge[\"payload\"]> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"API\", \"Challenge type must be API\");\n return challenge.payload;\n },\n\n approve: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n\n reject: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n } satisfies DecorateWithWorkspaceApiAuthenticated;\n });\n }\n\n return engine;\n }\n\n return {\n ...base,\n withDeviceIndex,\n withTransportId,\n withApiUser,\n withWorkspace,\n withOnboarding,\n };\n}\n","import { DisconnectedDevice, LockedDeviceError } from \"@ledgerhq/errors\";\nimport type Transport from \"@ledgerhq/hw-transport\";\nimport type { HsmCertificate } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport { from, lastValueFrom } from \"rxjs\";\n\nimport type { Logger } from \"@/types\";\n\nimport {\n APPID_VAULT_ADMINISTRATOR,\n PAGINATED_STATUS,\n PATHS,\n SCRIPT_IDS,\n STATUS_LENGTH,\n STREAMING_NEXT_ACTION,\n STREAMING_RESPONSE,\n STR_ROLES,\n} from \"./constants\";\nimport { withDevicePolling } from \"./device-access\";\nimport type { Device } from \"./types\";\nimport { isTransportStatusError } from \"./utils\";\n\nconst MAX_CHUNK_LENGTH = 250;\n\ntype Options = {\n transportId: string;\n};\n\nconst FIXME_NOT_IMPLEMENTED =\n (fnName: string): (() => Promise<never>) =>\n async () => {\n throw new Error(`Not implemented: ${fnName}`);\n };\n\nconst getPathFromPathString = (pathString: string): number[] => {\n const parts = pathString.split(\"'/\").map((part) => parseInt(part, 10));\n return parts.map((part) => (part | 0x80000000) >>> 0);\n};\n\nconst splitChunks = (chunk: number, buffer: Buffer): Buffer[] => {\n const chunks = [];\n for (let i = 0, size = chunk; i < buffer.length; i += size, size = chunk) {\n chunks.push(buffer.slice(i, i + size));\n }\n return chunks;\n};\n\nconst removeStatus = (result: Buffer): Buffer => result.slice(0, result.length - STATUS_LENGTH);\n\nconst sendByChunk = async (\n transport: Transport,\n command: number[], // eg [0xe0, 0x45, 0x00, 0x00]\n data: Buffer,\n chunkSize: number = MAX_CHUNK_LENGTH,\n): Promise<Buffer> => {\n const chunks = splitChunks(chunkSize, data);\n let response = Buffer.from([]);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const apdu = [...command];\n // command is 0xe0,0x45,0x00,0x00 for first chunk, then it's 0xe0,0x45,0x80,0x00\n /* v8 ignore start */\n apdu[2] = i && 0x80;\n /* v8 ignore stop */\n response = await transport.send(apdu[0]!, apdu[1]!, apdu[2], apdu[3]!, chunk, [\n 0x9000,\n ...PAGINATED_STATUS,\n ]);\n }\n return response;\n};\n\nconst buildAttestation = (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n}): Buffer => {\n const sigBuffer = Buffer.from(params.handshakeAttestation.signature, \"base64\");\n const sigLengthBuffer = Buffer.alloc(1);\n sigLengthBuffer.writeUIntBE(sigBuffer.length, 0, 1);\n\n const certBuffer = Buffer.from(params.handshakeAttestation.certificate, \"base64\");\n const certLengthBuffer = Buffer.alloc(1);\n certLengthBuffer.writeUIntBE(certBuffer.length, 0, 1);\n\n const pubBuffer = Buffer.from(params.handshakeAttestation.attestationPub, \"base64\");\n\n const certChainData = Buffer.concat([\n sigLengthBuffer,\n sigBuffer,\n pubBuffer,\n certLengthBuffer,\n certBuffer,\n ]);\n\n const cliMsgBuffer = Buffer.from(params.handshake, \"hex\");\n const cliMsgLengthBuffer = Buffer.alloc(1);\n cliMsgLengthBuffer.writeUIntBE(cliMsgBuffer.length, 0, 1);\n\n const pidBuffer = Buffer.from(params.partitionId, \"hex\");\n const pidLengthBuffer = Buffer.alloc(1);\n pidLengthBuffer.writeUIntBE(pidBuffer.length, 0, 1);\n\n const certChainDataLengthBuff = Buffer.alloc(2);\n certChainDataLengthBuff.writeUInt16BE(certChainData.length, 0);\n\n const data = Buffer.concat([\n cliMsgLengthBuffer,\n cliMsgBuffer,\n certChainDataLengthBuff,\n certChainData,\n pidLengthBuffer,\n pidBuffer,\n ]);\n\n const totalLengthBuffer = Buffer.alloc(2);\n totalLengthBuffer.writeUInt16BE(data.length, 0);\n\n const toSend = Buffer.concat([totalLengthBuffer, data]);\n\n return toSend;\n};\n\ntype RetryOnError = (err: Error) => boolean;\n/* v8 ignore start */\nconst genericRetryOnError: RetryOnError = (err) => {\n // device is locked\n if (err instanceof LockedDeviceError) return true;\n // user is on dashboard when receiving a Vault app apdu\n if (isTransportStatusError(err) && err.statusCode === 0x6d09) return true;\n // VG-24797 error that can happen in BLE in some situations (still unclear)\n if (err instanceof DisconnectedDevice) return true;\n\n // for everything else, we don't want to retry\n return false;\n};\n/* v8 ignore stop */\n\nexport function createRealDevice(options: Options, logger: Logger): Device {\n const { transportId } = options;\n\n async function run<T>(\n job: (transport: Transport) => Promise<T>,\n retryOnError: RetryOnError = genericRetryOnError,\n ): Promise<T> {\n return lastValueFrom(\n withDevicePolling(transportId)<T>((transport) => from(job(transport)), retryOnError),\n );\n }\n\n /* v8 ignore start */\n const noRetry = (): boolean => false;\n const alwaysRetry = (): boolean => true;\n /* v8 ignore stop */\n const poll = async (\n opts: { retryOnError?: RetryOnError } = {},\n ): Promise<{ isAppOpened: boolean }> => {\n // waiting for device to be turned on\n await run(\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n async (_transport) => {},\n opts.retryOnError ?? alwaysRetry,\n );\n // checking if app is opened: should return directly on getPubKey\n try {\n await getPublicKey(PATHS.U2F, { secp256k1: true, retryOnError: noRetry });\n return { isAppOpened: true };\n } catch (err) {\n if (isTransportStatusError(err) && genericRetryOnError(err)) {\n return { isAppOpened: false };\n }\n throw err;\n }\n };\n\n const pollApp = async (appName: string): Promise<string> => {\n const res = await run((transport) =>\n transport.send(0xe0, 0xd8, 0x00, 0x00, Buffer.from(appName, \"utf8\")),\n );\n // little delay to give time to the app to be fully opened\n await new Promise((r) => setTimeout(r, 1e3));\n return res.toString(\"hex\");\n };\n\n const getPublicKey = async (\n pathString: string,\n { secp256k1, retryOnError }: { secp256k1: boolean; retryOnError?: RetryOnError },\n ): Promise<{ pubKey: string; signature: string }> => {\n logger.info(`[device] getPublicKey (${pathString})`);\n const path = getPathFromPathString(pathString);\n const data = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n const curve = secp256k1 ? 0x01 : 0x02;\n const response = await run(\n (transport) => transport.send(0xe0, 0x40, curve, 0x00, data),\n retryOnError ?? genericRetryOnError,\n );\n const pubKeyLength = response.readInt8(0);\n const pubKey = response\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = response\n .slice(pubKeyLength + 1, response.length - STATUS_LENGTH)\n .toString(\"base64\");\n return { pubKey, signature };\n };\n\n const device: Device = {\n authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {\n logger.info(`[device] Authenticate`);\n invariant(role !== \"READ_ONLY_API_KEY\", \"Invalid role for authenticate: READ_ONLY_API_KEY\");\n const applicationBuffer = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n const nameBuffer = Buffer.from(name);\n const workspaceBuffer = Buffer.from(workspaceName);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([nameBuffer.length]),\n nameBuffer,\n Buffer.from([workspaceBuffer.length]),\n workspaceBuffer,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([\n Buffer.from(challenge, \"base64\"),\n applicationBuffer,\n Buffer.from([keyHandle.length]),\n Buffer.from(keyHandle, \"hex\"),\n keyHandleDataLength,\n keyHandleData,\n ]);\n\n const authentication = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x02, 0x00, 0x00], data),\n );\n\n return removeStatus(authentication).toString(\"hex\");\n },\n\n finalizePairingHandshake: async (params: {\n handshake: string;\n partitionId: string;\n handshakeAttestation: HsmCertificate;\n }): Promise<string> => {\n const bufWithStatus = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x47, 0x00, 0x02], buildAttestation(params)),\n );\n return removeStatus(bufWithStatus).toString(\"hex\");\n },\n\n generateSeedFragment: FIXME_NOT_IMPLEMENTED(\"generateSeedFragment\"),\n generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED(\"generateWrappingKeyFragment\"),\n getAttestation: async (): Promise<{\n attestation: {\n codeHash: string;\n attestationPub: string;\n certificate: string;\n };\n buffer: Buffer;\n }> => {\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x41, 0x00, 0x00));\n const buffer = removeStatus(bufWithStatus);\n const certLen = buffer.readInt8(32 + 65 + 1);\n return {\n attestation: {\n codeHash: buffer.slice(0, 32).toString(\"base64\"),\n attestationPub: buffer.slice(32, 32 + 65).toString(\"base64\"),\n certificate: buffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString(\"base64\"),\n },\n buffer,\n };\n },\n getConfidentialityKey: async () => {\n logger.info(`[device] getConfidentialityKey`);\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x4d, 0x00, 0x00));\n const buf = removeStatus(bufWithStatus);\n const keyLength = buf[0]!;\n const key = buf.slice(1, 1 + keyLength);\n const sig = buf.slice(1 + keyLength + 1);\n return {\n confidentialityKeyCurve25519: key.toString(\"hex\"),\n confidentialityKeySignature: sig.toString(\"hex\"),\n };\n },\n getConfidentialityPubKey: () => getPublicKey(PATHS.CONFIDENTIALITY, { secp256k1: true }),\n getDeviceUserId: FIXME_NOT_IMPLEMENTED(\"getDeviceUserId\"),\n getU2FPubKey: () => getPublicKey(PATHS.U2F, { secp256k1: false }),\n getValidationPubKey: () => getPublicKey(PATHS.VALIDATION, { secp256k1: true }),\n hasPairing: async () => {\n logger.info(`[device] hasPairing`);\n const apdu = [0xe0, 0x51, 0x00, 0x00, 0xb5];\n const res = await run((transport) => transport.exchange(Buffer.from(apdu)));\n const hex = Buffer.from(res).toString(\"hex\");\n\n // 6f45 => this error means that there is no partition ID on the device\n // if no error, it means there is (at least) one\n //\n // 6a87 => TEMPORARY hack because Stax apparently does not implement\n // the \"get partition id\" APDU, so it returns \"incorrect length\"\n // easier to just assume that in this case there is no partition,\n // and try to insert one anyway (done on revault onboarding)\n //\n return hex !== \"6f45\" && hex !== \"6a87\";\n },\n\n initPairingHandshake: async (): Promise<{ pubKey: string; signature: string }> => {\n const res = await run((transport) => transport.send(0xe0, 0x46, 0x00, 0x00));\n const pubKeyLength = res.readInt8(0);\n const pubKey = res\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = res.slice(pubKeyLength + 1, res.length - STATUS_LENGTH).toString(\"base64\");\n return { pubKey, signature };\n },\n\n openSession: FIXME_NOT_IMPLEMENTED(\"openSession\"),\n\n register: async (params: {\n challenge: string;\n u2fRegisterData: string;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n }): Promise<{\n u2fRegister: Buffer;\n keyHandle: Buffer;\n rfu: number;\n pubKey: string;\n }> => {\n const { challenge: strChallenge, u2fRegisterData: _, name, role } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const applicationBuf = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n invariant(applicationBuf.length === 32, \"application hex is expected to have 32 bytes\");\n\n const userNameBuff = Buffer.from(name);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([userNameBuff.length]),\n userNameBuff,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([challenge, applicationBuf, keyHandleDataLength, keyHandleData]);\n\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x01, 0x00, 0x00], data),\n );\n\n let i = 0;\n const rfu = response.slice(i, (i += 1))[0]!;\n const pubKey = response.slice(i, (i += 65)).toString(\"hex\");\n const keyHandleLength = response.slice(i, ++i)[0]!;\n const keyHandle = response.slice(i, (i += keyHandleLength));\n return {\n u2fRegister: removeStatus(response),\n keyHandle,\n rfu,\n pubKey,\n };\n },\n registerData: async (params: { challenge: string }): Promise<string> => {\n const { challenge: strChallenge } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const response = await run((transport) => transport.send(0xe0, 0x03, 0x00, 0x00, challenge));\n return removeStatus(response).toString(\"hex\");\n },\n\n setPairing: async ({ pairing }) => {\n logger.info(`[device] setPairing`);\n const psdPayload = Buffer.from(pairing.blob, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(psdPayload.length, 0);\n const final = Buffer.concat([length, psdPayload]);\n await run((transport) => sendByChunk(transport, [0xe0, 0x4e, 0x00, 0x00], final));\n },\n startKKPatternAsResponder: FIXME_NOT_IMPLEMENTED(\"startKKPatternAsResponder\"),\n startKPatternAsResponder: async (params) => {\n logger.info(`[device] startKPatternAsResponder`);\n const data = buildAttestation(params);\n await run((transport) =>\n sendByChunk(transport, [0xe0, 0x49, 0x00, SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data),\n );\n },\n validateVaultOperation: async (params) => {\n logger.info(`[device] validateVaultOperation`);\n const path = getPathFromPathString(PATHS.VALIDATION);\n const paths = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n\n let nextActionId = 1;\n let finalResponse;\n\n while (!finalResponse) {\n const screen = Buffer.from(params.actions[nextActionId - 1]!, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(screen.length, 0);\n const data = Buffer.concat([paths, length, screen]);\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x45, 0x00, 0x00], data),\n );\n const responseType = response.readInt8(0);\n let responseStatus = response.readUInt16BE(response.length - 2);\n if (responseType === STREAMING_NEXT_ACTION) {\n nextActionId = response.readUIntBE(1, 2);\n } else if (responseType === STREAMING_RESPONSE) {\n finalResponse = response.slice(3, response.length - 2);\n /* v8 ignore start */\n while (responseStatus !== 0x9000) {\n const resp = await run((transport) => transport.send(0x00, 0xc0, 0x00, 0x00));\n responseStatus = resp.readUInt16BE(resp.length - 2);\n finalResponse = Buffer.concat([finalResponse, removeStatus(resp)]);\n }\n } else {\n throw Error(`${responseType}`);\n }\n /* v8 ignore stop */\n }\n return finalResponse.toString(\"base64\");\n },\n\n sendAPDU: async (apduCommand: string) => {\n const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, \"hex\")));\n return Buffer.from(res).toString(\"hex\");\n },\n getVersion: async () => {\n const res = await run((transport) => transport.send(0xb0, 0x01, 0x00, 0x00));\n const appNameLen = res.readInt8(1);\n const appVersionLen = res.readInt8(2 + appNameLen);\n const appVersionHex = res.slice(2 + 1 + appNameLen, 2 + appNameLen + appVersionLen + 1);\n\n const appVersion = Buffer.from(appVersionHex).toString();\n\n return appVersion;\n },\n poll,\n pollApp,\n };\n return device;\n}\n","import type { AppRouter } from \"@ledgerhq/revault-api\";\nimport { type TRPCClient, createTRPCClient, httpLink } from \"@trpc/client\";\nimport type { inferRouterInputs, inferRouterOutputs } from \"@trpc/server\";\nimport superjson from \"superjson\";\n\nexport type TRPCClientOptions = {\n baseUrl: string;\n debugAuthToken?: string;\n rootAuthToken?: string;\n apiAccessToken?: string;\n psdAuth?: string;\n};\n\nexport type RevaultApiTRPCClient = TRPCClient<AppRouter>;\n\nexport type RouterInputs = inferRouterInputs<AppRouter>;\nexport type RouterOutputs = inferRouterOutputs<AppRouter>;\n\nexport const createClient = (options: TRPCClientOptions): RevaultApiTRPCClient => {\n const trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: `${options.baseUrl}/trpc`,\n transformer: superjson,\n headers() {\n return {\n ...(options.debugAuthToken\n ? { \"x-revault-debug-auth-token\": options.debugAuthToken }\n : {}),\n ...(options.rootAuthToken\n ? { \"x-revault-root-auth-token\": options.rootAuthToken }\n : {}),\n ...(options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}),\n ...(options.apiAccessToken\n ? { Authorization: `Bearer ${options.apiAccessToken}` }\n : {}),\n };\n },\n }),\n ],\n });\n return trpc;\n};\n"],"mappings":"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","names":["invariant","withApiUser","withWorkspace","withOnboarding","engine","client","invariant"]}
1
+ {"version":3,"sources":["../src/engine/index.ts","../src/device/real-device.ts","../src/trpc.ts"],"sourcesContent":["import type {\n ApiChallenge,\n ClaimedRole,\n OnboardingSeedChallenge,\n PsdChallenge,\n UserRegistrationChallenge,\n UserRegistrationChallengeResponse,\n UserRegistrationDeviceData,\n UserRegistrationResponse,\n VaultRequestResponse,\n WrappingKeyResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport { type Device, createApiDevice } from \"@/device\";\nimport { createRealDevice } from \"@/device/real-device\";\nimport { type TRPCClientOptions, createClient } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\n\nimport type {\n ApproveRequestParams,\n DecorateWithApiUserAndWorkspaceUnauthenticated,\n DecorateWithDevice,\n DecorateWithDeviceAndOnboarding,\n DecorateWithDeviceAndWorkspaceUnauthenticated,\n DecorateWithWorkspaceApiAuthenticated,\n DecorateWithWorkspacePsdAuthenticated,\n DecorateWithWorkspaceUnauthenticated,\n Engine,\n EngineBase,\n EngineOptions,\n RegisterOnboardingDeviceParams,\n WithApiAuth,\n WithApiUser,\n WithDevice,\n WithOnboarding,\n WithPsdAuth,\n WithWorkspace,\n} from \"./types\";\n\nexport { fetchAll, fetchAllCursor } from \"../utils\";\n\nexport type * from \"./types\";\n\nasync function genericRegister<T>({\n device,\n name,\n role,\n getChallenge,\n submitChallenge,\n}: {\n device: Device;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n getChallenge: (p: {\n pubKey: string;\n deviceData: UserRegistrationDeviceData;\n }) => Promise<UserRegistrationChallenge>;\n submitChallenge: (p: {\n pubKey: string;\n challengeResponse: UserRegistrationChallengeResponse;\n }) => Promise<T>;\n}): Promise<T> {\n const [attestation, u2fPubKey, confidentialityKey] = await Promise.all([\n device.getAttestation(),\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n const ephemeralPubKey = await device.initPairingHandshake();\n const deviceData: UserRegistrationDeviceData = {\n name,\n pubKey: u2fPubKey.pubKey,\n psdModel: \"STAX\",\n confidentialityKey: confidentialityKey.pubKey,\n psdEphemeralKey: ephemeralPubKey.pubKey,\n psdEphemeralKeyAttestation: {\n ...attestation.attestation,\n signature: ephemeralPubKey.signature,\n },\n };\n const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });\n const pairingPayload = await device.finalizePairingHandshake({\n handshake: challenge.handshake,\n partitionId: challenge.ciphertext,\n handshakeAttestation: challenge.handshakeAttestation,\n });\n const register = await device.register({\n challenge: challenge.challenge,\n u2fRegisterData: challenge.u2fRegisterData,\n name,\n role,\n });\n const validationPubKey = await device.getValidationPubKey();\n const registerData = await device.registerData({ challenge: challenge.challenge });\n const attestationOffset = 67 + register.u2fRegister.readInt8(66);\n const u2fRegister = Buffer.concat([\n register.u2fRegister.slice(0, attestationOffset),\n Buffer.from([attestation.buffer.length]),\n attestation.buffer,\n register.u2fRegister.slice(attestationOffset),\n ]).toString(\"hex\");\n const challengeResponse: UserRegistrationChallengeResponse = {\n registerData,\n certificate: {\n ...attestation.attestation,\n signature: validationPubKey.signature,\n },\n u2fRegister,\n u2fKeyHandle: register.keyHandle.toString(\"hex\"),\n validationKey: validationPubKey.pubKey,\n pairingPayload,\n };\n return submitChallenge({ pubKey: u2fPubKey.pubKey, challengeResponse });\n}\n\nexport function createEngine(options: EngineOptions, logger: Logger): Engine {\n const clientOptions: TRPCClientOptions = {\n baseUrl: options.baseUrl,\n };\n const client = createClient(clientOptions);\n const apiDevice = createApiDevice(options, logger);\n\n const base: EngineBase = {\n client,\n createClient: (overrides) => createClient({ ...clientOptions, ...overrides }),\n };\n\n const withDeviceIndex: Engine[\"withDeviceIndex\"] = function <T>(\n this: Engine<T>,\n deviceIndex: number,\n ) {\n const device = apiDevice.with(deviceIndex);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withTransportId: Engine[\"withTransportId\"] = function <T>(\n this: Engine<T>,\n transportId: string,\n ) {\n const device = createRealDevice({ transportId }, logger);\n const withPsd: WithDevice = { device };\n return decorateEngine({ ...this, ...withPsd } as Engine<T & WithDevice>);\n };\n\n const withApiUser: Engine[\"withApiUser\"] = function <T>(this: Engine<T>) {\n const withApiUser: WithApiUser = { __isApiUser: true };\n return decorateEngine({ ...this, ...withApiUser } as Engine<T & WithApiUser>);\n };\n\n const withWorkspace: Engine[\"withWorkspace\"] = function <T>(\n this: Engine<T>,\n workspaceName: string,\n ) {\n const withWorkspace: WithWorkspace = { __workspaceName: workspaceName };\n return decorateEngine({ ...this, ...withWorkspace } as Engine<T & WithWorkspace>);\n };\n\n const withOnboarding: Engine[\"withOnboarding\"] = function <T>(\n this: Engine<T>,\n onboardingId: string,\n ) {\n const withOnboarding: WithOnboarding = { __onboardingId: onboardingId };\n return decorateEngine({ ...this, ...withOnboarding } as Engine<T & WithOnboarding>);\n };\n\n function decorateEngine<T>(\n engine: Engine<\n T &\n Partial<\n WithDevice & WithOnboarding & WithWorkspace & WithPsdAuth & WithApiUser & WithApiAuth\n >\n >,\n ): Engine<T> {\n function decorate<TEnhanced, TDecoration>(\n decorator: (engine: EngineBase & TEnhanced) => TDecoration,\n ): void {\n Object.assign(engine, decorator(engine as EngineBase & TEnhanced));\n }\n\n // DecorateWithDevice\n // -------------------------------------------------------------------------\n if (engine.device) {\n decorate<WithDevice, DecorateWithDevice<T>>(\n (engine) =>\n ({\n getWorkspaces: async (): Promise<string[]> => {\n const { device, client } = engine;\n const { pubKey } = await device.getU2FPubKey();\n const { workspaceNames } = await client.auth.psd.findWorkspaceNames.query({ pubKey });\n return workspaceNames;\n },\n }) satisfies DecorateWithDevice<T>,\n );\n }\n\n // DecorateWithWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && !engine.__psdToken && !engine.__apiAuth) {\n decorate<WithWorkspace, DecorateWithWorkspaceUnauthenticated<T>>((engine) => {\n const { __workspaceName } = engine;\n return {\n withPsdToken: function <T>(this: Engine<T>, token: string): Engine<T & WithPsdAuth> {\n const withPsdAuth: WithPsdAuth = { __psdToken: token };\n const psdAuth = `${__workspaceName}:${token}`;\n const client = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client, ...withPsdAuth } as Engine<T & WithPsdAuth>);\n },\n } satisfies DecorateWithWorkspaceUnauthenticated<T>;\n });\n }\n\n // DecorateWithDeviceAndOnboarding\n // -------------------------------------------------------------------------\n if (engine.device && engine.__onboardingId) {\n decorate<WithDevice & WithOnboarding, DecorateWithDeviceAndOnboarding>((engine) => {\n const { device, client, __onboardingId } = engine;\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityKey(),\n ]);\n const pairing = await client.onboarding.pairDevicePartition.mutate({\n pubKey,\n onboardingId: __onboardingId,\n data: {\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n },\n });\n await device.setPairing({ pairing });\n }\n return {\n claimDevice: async (params: { role: ClaimedRole; deviceName: string }): Promise<void> => {\n const { role, deviceName } = params;\n const [{ pubKey }, { pubKey: confidentialityKey }] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await client.onboarding.claimDevice.mutate({\n onboardingId: __onboardingId,\n claim: { role, pubKey, deviceName, confidentialityKey },\n });\n },\n\n collectWrappingKeyFragment: async (wrappingKey: WrappingKeyResponse): Promise<void> => {\n const [{ pubKey }, confidentialityKey] = await Promise.all([\n device.getU2FPubKey(),\n device.getConfidentialityPubKey(),\n ]);\n await device.openSession({\n secureChannel: {\n pubKey: wrappingKey.ephemeralPubKey,\n certificate: wrappingKey.ephemeralCertificate,\n },\n });\n const { attestation } = await device.getAttestation();\n const blob = await device.generateWrappingKeyFragment();\n await client.onboarding.submitWrappingKeyFragment.mutate({\n pubKey,\n onboardingId: __onboardingId,\n fragment: {\n blob,\n ephemeralPubKey: confidentialityKey.pubKey,\n ephemeralCertificate: {\n ...attestation,\n signature: confidentialityKey.signature,\n },\n },\n });\n },\n\n registerDevice: async (params: RegisterOnboardingDeviceParams): Promise<void> => {\n const { role, name } = params;\n const getChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.generateMasterAdminRegistrationChallenge\n : client.onboarding.generateSharedOwnerRegistrationChallenge;\n const submitChallengeMutation =\n role === \"ADMIN\"\n ? client.onboarding.submitMasterAdminRegistration\n : client.onboarding.submitSharedOwnerRegistration;\n await genericRegister({\n device: device,\n name,\n role,\n getChallenge: ({ pubKey, deviceData }) =>\n getChallengeMutation.mutate({\n onboardingId: __onboardingId,\n pubKey,\n deviceData,\n }),\n submitChallenge: ({ pubKey, challengeResponse }) =>\n submitChallengeMutation.mutate({\n onboardingId: engine.__onboardingId,\n pubKey,\n // FIXME this should be renamed to `challengeResponse` on backend side\n response: challengeResponse,\n }),\n });\n },\n\n reviewSharedOwner: async (challenge: PsdChallenge): Promise<void> => {\n await enforcePairing();\n const { pubKey } = await device.getU2FPubKey();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n await client.onboarding.submitReviewByMasterAdminSignature.mutate({\n onboardingId: __onboardingId,\n pubKey,\n signature,\n });\n },\n\n collectSeedFragment: async (challenge: OnboardingSeedChallenge): Promise<void> => {\n await enforcePairing();\n const [{ pubKey }, { attestation }] = await Promise.all([\n device.getU2FPubKey(),\n device.getAttestation(),\n ]);\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n const challengeResponse = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n const kkPattern = await device.startKKPatternAsResponder({\n partitionId: challenge.partitionId,\n handshake: challenge.kkHandshake,\n handshakeAttestation: challenge.kkHandshakeAttestation,\n });\n const approverBlob = await device.generateSeedFragment();\n await client.onboarding.submitSeedFragment.mutate({\n onboardingId: __onboardingId,\n pubKey,\n seedFragment: {\n challengeResponse,\n approverBlob,\n handshake: kkPattern.handshake,\n handshakeAttestation: {\n ...attestation,\n signature: kkPattern.signature,\n },\n },\n });\n },\n } satisfies DecorateWithDeviceAndOnboarding;\n });\n }\n\n // DecorateWithDeviceAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && !engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithDeviceAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { device, client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n opts?: { validityDurationSecs?: number; onScreenDisplayed?: () => void },\n ): Promise<Engine<T & WithPsdAuth>> {\n const { pubKey } = await device.getU2FPubKey();\n const challenge = await client.auth.psd.generateChallenge.mutate({\n pubKey,\n workspaceName: __workspaceName,\n });\n opts?.onScreenDisplayed?.();\n const authentication = await device.authenticate({\n challenge,\n workspaceName: __workspaceName,\n });\n const authPayload = {\n workspaceName: __workspaceName,\n pubKey,\n authentication,\n validityDurationSecs: opts?.validityDurationSecs,\n };\n const { token } = await client.auth.psd.authenticate.mutate({ ...authPayload });\n const withPsdAuth: WithPsdAuth = {\n __psdToken: token,\n };\n const psdAuth = `${engine.__workspaceName}:${token}`;\n const __authClient = engine.createClient({ psdAuth });\n return decorateEngine({ ...this, client: __authClient, ...withPsdAuth } as Engine<\n T & WithPsdAuth\n >);\n },\n\n register: (\n registration: UserRegistrationResponse,\n ): Promise<UserRegistrationResponse> => {\n return genericRegister({\n device,\n name: registration.name,\n role: registration.role,\n getChallenge: async ({ deviceData }) => {\n const challenge = await client.userRegistrations.generateChallenge.mutate({\n id: registration.id,\n workspaceName: __workspaceName,\n deviceData,\n });\n return challenge;\n },\n submitChallenge: ({ challengeResponse }) =>\n client.userRegistrations.submitChallenge.mutate({\n workspaceName: __workspaceName,\n id: registration.id,\n challengeResponse,\n }),\n });\n },\n } satisfies DecorateWithDeviceAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithApiUserAndWorkspaceUnauthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__isApiUser && !engine.__apiAuth) {\n decorate<WithWorkspace & WithApiUser, DecorateWithApiUserAndWorkspaceUnauthenticated<T>>(\n (engine) => {\n const { client, __workspaceName } = engine;\n return {\n login: async function <T>(\n this: Engine<T>,\n credentials: {\n apiKeyId: string;\n apiKeySecret: string;\n },\n ): Promise<Engine<T & WithApiAuth>> {\n const res = await client.auth.authenticate.mutate({\n apiKeyId: credentials.apiKeyId,\n apiKeySecret: credentials.apiKeySecret,\n workspace: __workspaceName,\n });\n const withApiAuth: WithApiAuth = {\n __apiAuth: res,\n };\n const __authClient = engine.createClient({ apiAccessToken: res.accessToken });\n return decorateEngine({ ...this, client: __authClient, ...withApiAuth } as Engine<\n T & WithApiAuth\n >);\n },\n } satisfies DecorateWithApiUserAndWorkspaceUnauthenticated<T>;\n },\n );\n }\n\n // DecorateWithWorkspacePsdAuthenticated\n // -------------------------------------------------------------------------\n if (engine.device && engine.__workspaceName && engine.__psdToken) {\n decorate<WithDevice & WithWorkspace, DecorateWithWorkspacePsdAuthenticated>((engine) => {\n const { client, device } = engine;\n\n async function enforcePairing(): Promise<void> {\n if (await device.hasPairing()) return;\n const confidentialityKey = await device.getConfidentialityKey();\n const pairing = await client.debug.pairDevicePartition.mutate({\n confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,\n confidentialityKeySignature: confidentialityKey.confidentialityKeySignature,\n });\n await device.setPairing({ pairing });\n }\n\n const approveChallenge = async (\n challenge: PsdChallenge,\n params?: ApproveRequestParams,\n ): Promise<string> => {\n await enforcePairing();\n await device.startKPatternAsResponder({\n handshake: challenge.handshake,\n handshakeAttestation: challenge.handshakeAttestation,\n partitionId: challenge.partitionId,\n });\n params?.onScreenDisplayed?.();\n const signature = await device.validateVaultOperation({\n actions: challenge.wActions,\n });\n return signature;\n };\n\n return {\n approve: async (\n request: VaultRequestResponse,\n params?: ApproveRequestParams,\n ): Promise<VaultRequestResponse> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"PSD\", \"Challenge type must be PSD\");\n const signature = await approveChallenge(challenge, params);\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"PSD\", signature },\n });\n },\n\n approveChallenge,\n\n reject: (request: VaultRequestResponse): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({ id: request.id, data: null });\n },\n } satisfies DecorateWithWorkspacePsdAuthenticated;\n });\n }\n\n // DecorateWithWorkspaceApiAuthenticated\n // -------------------------------------------------------------------------\n if (engine.__workspaceName && engine.__apiAuth) {\n decorate<WithWorkspace & WithApiAuth, DecorateWithWorkspaceApiAuthenticated>((engine) => {\n const { client } = engine;\n return {\n getChallenge: async (request: VaultRequestResponse): Promise<ApiChallenge[\"payload\"]> => {\n const { challenge } = await client.requests.getChallenge.query({ id: request.id });\n invariant(challenge.challengeType === \"API\", \"Challenge type must be API\");\n return challenge.payload;\n },\n\n approve: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.approve.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n\n reject: (\n request: VaultRequestResponse,\n signature: string,\n ): Promise<VaultRequestResponse> => {\n return client.requests.reject.mutate({\n id: request.id,\n data: { challengeType: \"API\", signature },\n });\n },\n } satisfies DecorateWithWorkspaceApiAuthenticated;\n });\n }\n\n return engine;\n }\n\n return {\n ...base,\n withDeviceIndex,\n withTransportId,\n withApiUser,\n withWorkspace,\n withOnboarding,\n };\n}\n","import { DisconnectedDevice, LockedDeviceError } from \"@ledgerhq/errors\";\nimport type Transport from \"@ledgerhq/hw-transport\";\nimport type { HsmCertificate } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport { from, lastValueFrom } from \"rxjs\";\n\nimport type { Logger } from \"@/types\";\n\nimport {\n APPID_VAULT_ADMINISTRATOR,\n PAGINATED_STATUS,\n PATHS,\n SCRIPT_IDS,\n STATUS_LENGTH,\n STREAMING_NEXT_ACTION,\n STREAMING_RESPONSE,\n STR_ROLES,\n} from \"./constants\";\nimport { withDevicePolling } from \"./device-access\";\nimport type { Device } from \"./types\";\nimport { isTransportStatusError } from \"./utils\";\n\nconst MAX_CHUNK_LENGTH = 250;\n\ntype Options = {\n transportId: string;\n};\n\nconst FIXME_NOT_IMPLEMENTED =\n (fnName: string): (() => Promise<never>) =>\n async () => {\n throw new Error(`Not implemented: ${fnName}`);\n };\n\nconst getPathFromPathString = (pathString: string): number[] => {\n const parts = pathString.split(\"'/\").map((part) => parseInt(part, 10));\n return parts.map((part) => (part | 0x80000000) >>> 0);\n};\n\nconst splitChunks = (chunk: number, buffer: Buffer): Buffer[] => {\n const chunks = [];\n for (let i = 0, size = chunk; i < buffer.length; i += size, size = chunk) {\n chunks.push(buffer.slice(i, i + size));\n }\n return chunks;\n};\n\nconst removeStatus = (result: Buffer): Buffer => result.slice(0, result.length - STATUS_LENGTH);\n\nconst sendByChunk = async (\n transport: Transport,\n command: number[], // eg [0xe0, 0x45, 0x00, 0x00]\n data: Buffer,\n chunkSize: number = MAX_CHUNK_LENGTH,\n): Promise<Buffer> => {\n const chunks = splitChunks(chunkSize, data);\n let response = Buffer.from([]);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const apdu = [...command];\n // command is 0xe0,0x45,0x00,0x00 for first chunk, then it's 0xe0,0x45,0x80,0x00\n /* v8 ignore start */\n apdu[2] = i && 0x80;\n /* v8 ignore stop */\n response = (await transport.send(apdu[0]!, apdu[1]!, apdu[2], apdu[3]!, chunk, [\n 0x9000,\n ...PAGINATED_STATUS,\n ])) as Buffer<ArrayBuffer>;\n }\n return response;\n};\n\nconst buildAttestation = (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n}): Buffer => {\n const sigBuffer = Buffer.from(params.handshakeAttestation.signature, \"base64\");\n const sigLengthBuffer = Buffer.alloc(1);\n sigLengthBuffer.writeUIntBE(sigBuffer.length, 0, 1);\n\n const certBuffer = Buffer.from(params.handshakeAttestation.certificate, \"base64\");\n const certLengthBuffer = Buffer.alloc(1);\n certLengthBuffer.writeUIntBE(certBuffer.length, 0, 1);\n\n const pubBuffer = Buffer.from(params.handshakeAttestation.attestationPub, \"base64\");\n\n const certChainData = Buffer.concat([\n sigLengthBuffer,\n sigBuffer,\n pubBuffer,\n certLengthBuffer,\n certBuffer,\n ]);\n\n const cliMsgBuffer = Buffer.from(params.handshake, \"hex\");\n const cliMsgLengthBuffer = Buffer.alloc(1);\n cliMsgLengthBuffer.writeUIntBE(cliMsgBuffer.length, 0, 1);\n\n const pidBuffer = Buffer.from(params.partitionId, \"hex\");\n const pidLengthBuffer = Buffer.alloc(1);\n pidLengthBuffer.writeUIntBE(pidBuffer.length, 0, 1);\n\n const certChainDataLengthBuff = Buffer.alloc(2);\n certChainDataLengthBuff.writeUInt16BE(certChainData.length, 0);\n\n const data = Buffer.concat([\n cliMsgLengthBuffer,\n cliMsgBuffer,\n certChainDataLengthBuff,\n certChainData,\n pidLengthBuffer,\n pidBuffer,\n ]);\n\n const totalLengthBuffer = Buffer.alloc(2);\n totalLengthBuffer.writeUInt16BE(data.length, 0);\n\n const toSend = Buffer.concat([totalLengthBuffer, data]);\n\n return toSend;\n};\n\ntype RetryOnError = (err: Error) => boolean;\n/* v8 ignore start */\nconst genericRetryOnError: RetryOnError = (err) => {\n // device is locked\n if (err instanceof LockedDeviceError) return true;\n // user is on dashboard when receiving a Vault app apdu\n if (isTransportStatusError(err) && err.statusCode === 0x6d09) return true;\n // VG-24797 error that can happen in BLE in some situations (still unclear)\n if (err instanceof DisconnectedDevice) return true;\n\n // for everything else, we don't want to retry\n return false;\n};\n/* v8 ignore stop */\n\nexport function createRealDevice(options: Options, logger: Logger): Device {\n const { transportId } = options;\n\n async function run<T>(\n job: (transport: Transport) => Promise<T>,\n retryOnError: RetryOnError = genericRetryOnError,\n ): Promise<T> {\n return lastValueFrom(\n withDevicePolling(transportId)<T>((transport) => from(job(transport)), retryOnError),\n );\n }\n\n /* v8 ignore start */\n const noRetry = (): boolean => false;\n const alwaysRetry = (): boolean => true;\n /* v8 ignore stop */\n const poll = async (\n opts: { retryOnError?: RetryOnError } = {},\n ): Promise<{ isAppOpened: boolean }> => {\n // waiting for device to be turned on\n await run(\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n async (_transport) => {},\n opts.retryOnError ?? alwaysRetry,\n );\n // checking if app is opened: should return directly on getPubKey\n try {\n await getPublicKey(PATHS.U2F, { secp256k1: true, retryOnError: noRetry });\n return { isAppOpened: true };\n } catch (err) {\n if (isTransportStatusError(err) && genericRetryOnError(err)) {\n return { isAppOpened: false };\n }\n throw err;\n }\n };\n\n const pollApp = async (appName: string): Promise<string> => {\n const res = await run((transport) =>\n transport.send(0xe0, 0xd8, 0x00, 0x00, Buffer.from(appName, \"utf8\")),\n );\n // little delay to give time to the app to be fully opened\n await new Promise((r) => setTimeout(r, 1e3));\n return res.toString(\"hex\");\n };\n\n const getPublicKey = async (\n pathString: string,\n { secp256k1, retryOnError }: { secp256k1: boolean; retryOnError?: RetryOnError },\n ): Promise<{ pubKey: string; signature: string }> => {\n logger.info(`[device] getPublicKey (${pathString})`);\n const path = getPathFromPathString(pathString);\n const data = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n const curve = secp256k1 ? 0x01 : 0x02;\n const response = await run(\n (transport) => transport.send(0xe0, 0x40, curve, 0x00, data),\n retryOnError ?? genericRetryOnError,\n );\n const pubKeyLength = response.readInt8(0);\n const pubKey = response\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = response\n .slice(pubKeyLength + 1, response.length - STATUS_LENGTH)\n .toString(\"base64\");\n return { pubKey, signature };\n };\n\n const device: Device = {\n authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {\n logger.info(`[device] Authenticate`);\n invariant(role !== \"READ_ONLY_API_KEY\", \"Invalid role for authenticate: READ_ONLY_API_KEY\");\n const applicationBuffer = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n const nameBuffer = Buffer.from(name);\n const workspaceBuffer = Buffer.from(workspaceName);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([nameBuffer.length]),\n nameBuffer,\n Buffer.from([workspaceBuffer.length]),\n workspaceBuffer,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([\n Buffer.from(challenge, \"base64\"),\n applicationBuffer,\n Buffer.from([keyHandle.length]),\n Buffer.from(keyHandle, \"hex\"),\n keyHandleDataLength,\n keyHandleData,\n ]);\n\n const authentication = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x02, 0x00, 0x00], data),\n );\n\n return removeStatus(authentication).toString(\"hex\");\n },\n\n finalizePairingHandshake: async (params: {\n handshake: string;\n partitionId: string;\n handshakeAttestation: HsmCertificate;\n }): Promise<string> => {\n const bufWithStatus = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x47, 0x00, 0x02], buildAttestation(params)),\n );\n return removeStatus(bufWithStatus).toString(\"hex\");\n },\n\n generateSeedFragment: FIXME_NOT_IMPLEMENTED(\"generateSeedFragment\"),\n generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED(\"generateWrappingKeyFragment\"),\n getAttestation: async (): Promise<{\n attestation: {\n codeHash: string;\n attestationPub: string;\n certificate: string;\n };\n buffer: Buffer;\n }> => {\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x41, 0x00, 0x00));\n const buffer = removeStatus(bufWithStatus);\n const certLen = buffer.readInt8(32 + 65 + 1);\n return {\n attestation: {\n codeHash: buffer.slice(0, 32).toString(\"base64\"),\n attestationPub: buffer.slice(32, 32 + 65).toString(\"base64\"),\n certificate: buffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString(\"base64\"),\n },\n buffer,\n };\n },\n getConfidentialityKey: async () => {\n logger.info(`[device] getConfidentialityKey`);\n const bufWithStatus = await run((transport) => transport.send(0xe0, 0x4d, 0x00, 0x00));\n const buf = removeStatus(bufWithStatus);\n const keyLength = buf[0]!;\n const key = buf.slice(1, 1 + keyLength);\n const sig = buf.slice(1 + keyLength + 1);\n return {\n confidentialityKeyCurve25519: key.toString(\"hex\"),\n confidentialityKeySignature: sig.toString(\"hex\"),\n };\n },\n getConfidentialityPubKey: () => getPublicKey(PATHS.CONFIDENTIALITY, { secp256k1: true }),\n getDeviceUserId: FIXME_NOT_IMPLEMENTED(\"getDeviceUserId\"),\n getU2FPubKey: () => getPublicKey(PATHS.U2F, { secp256k1: false }),\n getValidationPubKey: () => getPublicKey(PATHS.VALIDATION, { secp256k1: true }),\n hasPairing: async () => {\n logger.info(`[device] hasPairing`);\n const apdu = [0xe0, 0x51, 0x00, 0x00, 0xb5];\n const res = await run((transport) => transport.exchange(Buffer.from(apdu)));\n const hex = Buffer.from(res).toString(\"hex\");\n\n // 6f45 => this error means that there is no partition ID on the device\n // if no error, it means there is (at least) one\n //\n // 6a87 => TEMPORARY hack because Stax apparently does not implement\n // the \"get partition id\" APDU, so it returns \"incorrect length\"\n // easier to just assume that in this case there is no partition,\n // and try to insert one anyway (done on revault onboarding)\n //\n return hex !== \"6f45\" && hex !== \"6a87\";\n },\n\n initPairingHandshake: async (): Promise<{ pubKey: string; signature: string }> => {\n const res = await run((transport) => transport.send(0xe0, 0x46, 0x00, 0x00));\n const pubKeyLength = res.readInt8(0);\n const pubKey = res\n .slice(1, pubKeyLength + 1)\n .toString(\"hex\")\n .toUpperCase();\n const signature = res.slice(pubKeyLength + 1, res.length - STATUS_LENGTH).toString(\"base64\");\n return { pubKey, signature };\n },\n\n openSession: FIXME_NOT_IMPLEMENTED(\"openSession\"),\n\n register: async (params: {\n challenge: string;\n u2fRegisterData: string;\n name: string;\n role: \"ADMIN\" | \"SHARED_OWNER\" | \"OPERATOR\";\n }): Promise<{\n u2fRegister: Buffer;\n keyHandle: Buffer;\n rfu: number;\n pubKey: string;\n }> => {\n const { challenge: strChallenge, u2fRegisterData: _, name, role } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const applicationBuf = Buffer.from(APPID_VAULT_ADMINISTRATOR, \"hex\");\n invariant(applicationBuf.length === 32, \"application hex is expected to have 32 bytes\");\n\n const userNameBuff = Buffer.from(name);\n\n const keyHandleData = Buffer.concat([\n Buffer.from(STR_ROLES[role], \"hex\"),\n Buffer.from([userNameBuff.length]),\n userNameBuff,\n ]);\n\n const keyHandleDataLength = Buffer.alloc(2);\n keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);\n\n const data = Buffer.concat([challenge, applicationBuf, keyHandleDataLength, keyHandleData]);\n\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x01, 0x00, 0x00], data),\n );\n\n let i = 0;\n const rfu = response.slice(i, (i += 1))[0]!;\n const pubKey = response.slice(i, (i += 65)).toString(\"hex\");\n const keyHandleLength = response.slice(i, ++i)[0]!;\n const keyHandle = response.slice(i, (i += keyHandleLength));\n return {\n u2fRegister: removeStatus(response),\n keyHandle,\n rfu,\n pubKey,\n };\n },\n registerData: async (params: { challenge: string }): Promise<string> => {\n const { challenge: strChallenge } = params;\n const challenge = Buffer.from(strChallenge, \"hex\");\n invariant(challenge.length === 32, \"challenge hex is expected to have 32 bytes\");\n const response = await run((transport) => transport.send(0xe0, 0x03, 0x00, 0x00, challenge));\n return removeStatus(response).toString(\"hex\");\n },\n\n setPairing: async ({ pairing }) => {\n logger.info(`[device] setPairing`);\n const psdPayload = Buffer.from(pairing.blob, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(psdPayload.length, 0);\n const final = Buffer.concat([length, psdPayload]);\n await run((transport) => sendByChunk(transport, [0xe0, 0x4e, 0x00, 0x00], final));\n },\n startKKPatternAsResponder: FIXME_NOT_IMPLEMENTED(\"startKKPatternAsResponder\"),\n startKPatternAsResponder: async (params) => {\n logger.info(`[device] startKPatternAsResponder`);\n const data = buildAttestation(params);\n await run((transport) =>\n sendByChunk(transport, [0xe0, 0x49, 0x00, SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data),\n );\n },\n validateVaultOperation: async (params) => {\n logger.info(`[device] validateVaultOperation`);\n const path = getPathFromPathString(PATHS.VALIDATION);\n const paths = Buffer.concat([\n Buffer.from([path.length]),\n ...path.map((derivation) => {\n const buf = Buffer.alloc(4);\n buf.writeUInt32BE(derivation, 0);\n return buf;\n }),\n ]);\n\n let nextActionId = 1;\n let finalResponse;\n\n while (!finalResponse) {\n const screen = Buffer.from(params.actions[nextActionId - 1]!, \"base64\");\n const length = Buffer.alloc(2);\n length.writeUInt16BE(screen.length, 0);\n const data = Buffer.concat([paths, length, screen]);\n const response = await run((transport) =>\n sendByChunk(transport, [0xe0, 0x45, 0x00, 0x00], data),\n );\n const responseType = response.readInt8(0);\n let responseStatus = response.readUInt16BE(response.length - 2);\n if (responseType === STREAMING_NEXT_ACTION) {\n nextActionId = response.readUIntBE(1, 2);\n } else if (responseType === STREAMING_RESPONSE) {\n finalResponse = response.slice(3, response.length - 2);\n /* v8 ignore start */\n while (responseStatus !== 0x9000) {\n const resp = await run((transport) => transport.send(0x00, 0xc0, 0x00, 0x00));\n responseStatus = resp.readUInt16BE(resp.length - 2);\n finalResponse = Buffer.concat([finalResponse, removeStatus(resp)]);\n }\n } else {\n throw Error(`${responseType}`);\n }\n /* v8 ignore stop */\n }\n return finalResponse.toString(\"base64\");\n },\n\n sendAPDU: async (apduCommand: string) => {\n const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, \"hex\")));\n return Buffer.from(res).toString(\"hex\");\n },\n getVersion: async () => {\n const res = await run((transport) => transport.send(0xb0, 0x01, 0x00, 0x00));\n const appNameLen = res.readInt8(1);\n const appVersionLen = res.readInt8(2 + appNameLen);\n const appVersionHex = res.slice(2 + 1 + appNameLen, 2 + appNameLen + appVersionLen + 1);\n\n const appVersion = Buffer.from(appVersionHex).toString();\n\n return appVersion;\n },\n poll,\n pollApp,\n };\n return device;\n}\n","import type { AppRouter } from \"@ledgerhq/revault-api\";\nimport { type TRPCClient, createTRPCClient, httpLink } from \"@trpc/client\";\nimport type { inferRouterInputs, inferRouterOutputs } from \"@trpc/server\";\nimport superjson from \"superjson\";\n\nexport type TRPCClientOptions = {\n baseUrl: string;\n debugAuthToken?: string;\n rootAuthToken?: string;\n apiAccessToken?: string;\n psdAuth?: string;\n};\n\nexport type RevaultApiTRPCClient = TRPCClient<AppRouter>;\n\nexport type RouterInputs = inferRouterInputs<AppRouter>;\nexport type RouterOutputs = inferRouterOutputs<AppRouter>;\n\nexport const createClient = (options: TRPCClientOptions): RevaultApiTRPCClient => {\n const trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: `${options.baseUrl}/trpc`,\n transformer: superjson,\n headers() {\n return {\n ...(options.debugAuthToken\n ? { \"x-revault-debug-auth-token\": options.debugAuthToken }\n : {}),\n ...(options.rootAuthToken\n ? { \"x-revault-root-auth-token\": options.rootAuthToken }\n : {}),\n ...(options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}),\n ...(options.apiAccessToken\n ? { Authorization: `Bearer ${options.apiAccessToken}` }\n : {}),\n };\n },\n }),\n ],\n });\n return trpc;\n};\n"],"mappings":"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","names":["invariant","withApiUser","withWorkspace","withOnboarding","engine","client","invariant"]}
@@ -1,6 +1,6 @@
1
1
  import { OnboardingFullStateResponse, OnboardingStep } from '@ledgerhq/revault-api';
2
2
  import { L as Logger } from './types-DNEewSJL.cjs';
3
- import { E as Engine, W as WithOnboarding } from './types-DcbTP2K6.cjs';
3
+ import { E as Engine, W as WithOnboarding } from './types-CAKnCFJk.cjs';
4
4
  import './types-DJfbanPz.cjs';
5
5
  import './index-YRqsGEDY.cjs';
6
6
  import '@trpc/client';
@@ -1,6 +1,6 @@
1
1
  import { OnboardingFullStateResponse, OnboardingStep } from '@ledgerhq/revault-api';
2
2
  import { L as Logger } from './types-DNEewSJL.js';
3
- import { E as Engine, W as WithOnboarding } from './types-CdSLzGGm.js';
3
+ import { E as Engine, W as WithOnboarding } from './types-mZnXORz9.js';
4
4
  import './types-DJfbanPz.js';
5
5
  import './index-znHBELBb.js';
6
6
  import '@trpc/client';
@@ -1,4 +1,4 @@
1
- import { VaultRequestResponse, ApiChallenge, UserRegistrationResponse, ClaimedRole, WrappingKeyResponse, PsdChallenge, OnboardingSeedChallenge } from '@ledgerhq/revault-api';
1
+ import { VaultRequestResponse, PsdChallenge, ApiChallenge, UserRegistrationResponse, ClaimedRole, WrappingKeyResponse, OnboardingSeedChallenge } from '@ledgerhq/revault-api';
2
2
  import { D as Device } from './types-DJfbanPz.cjs';
3
3
  import { R as RevaultApiTRPCClient, T as TRPCClientOptions, a as RouterOutputs } from './index-YRqsGEDY.cjs';
4
4
 
@@ -132,6 +132,10 @@ type DecorateWithWorkspacePsdAuthenticated = {
132
132
  * Approve the given request
133
133
  */
134
134
  approve: (request: VaultRequestResponse, params?: ApproveRequestParams) => Promise<VaultRequestResponse>;
135
+ /**
136
+ * Approve the given challenge
137
+ */
138
+ approveChallenge: (challenge: PsdChallenge, params?: ApproveRequestParams) => Promise<string>;
135
139
  /**
136
140
  * Reject the given request
137
141
  */
@@ -1,4 +1,4 @@
1
- import { VaultRequestResponse, ApiChallenge, UserRegistrationResponse, ClaimedRole, WrappingKeyResponse, PsdChallenge, OnboardingSeedChallenge } from '@ledgerhq/revault-api';
1
+ import { VaultRequestResponse, PsdChallenge, ApiChallenge, UserRegistrationResponse, ClaimedRole, WrappingKeyResponse, OnboardingSeedChallenge } from '@ledgerhq/revault-api';
2
2
  import { D as Device } from './types-DJfbanPz.js';
3
3
  import { R as RevaultApiTRPCClient, T as TRPCClientOptions, a as RouterOutputs } from './index-znHBELBb.js';
4
4
 
@@ -132,6 +132,10 @@ type DecorateWithWorkspacePsdAuthenticated = {
132
132
  * Approve the given request
133
133
  */
134
134
  approve: (request: VaultRequestResponse, params?: ApproveRequestParams) => Promise<VaultRequestResponse>;
135
+ /**
136
+ * Approve the given challenge
137
+ */
138
+ approveChallenge: (challenge: PsdChallenge, params?: ApproveRequestParams) => Promise<string>;
135
139
  /**
136
140
  * Reject the given request
137
141
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/revault-sdk",
3
- "version": "0.18.2",
3
+ "version": "0.20.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "files": [
@@ -54,23 +54,23 @@
54
54
  "superjson": "^1.13.3",
55
55
  "uuid": "^11.1.0",
56
56
  "zod": "^3.25.76",
57
- "@ledgerhq/revault-api": "1.33.0"
57
+ "@ledgerhq/revault-api": "1.35.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@eslint/js": "^9.32.0",
60
+ "@eslint/js": "^9.34.0",
61
61
  "@types/bn.js": "^5.2.0",
62
62
  "@types/elliptic": "^6.4.18",
63
63
  "@types/invariant": "^2.2.37",
64
64
  "@types/lodash": "^4.17.20",
65
- "@types/node": "^22.17.0",
65
+ "@types/node": "^22.17.2",
66
66
  "@vitest/coverage-v8": "^3.2.4",
67
67
  "@vitest/ui": "^3.2.4",
68
- "eslint": "^9.32.0",
69
- "eslint-plugin-unicorn": "^59.0.1",
68
+ "eslint": "^9.34.0",
69
+ "eslint-plugin-unicorn": "^60.0.0",
70
70
  "tsup": "^8.5.0",
71
- "tsx": "^4.20.4",
72
- "typescript": "^5.8.3",
73
- "typescript-eslint": "^8.38.0",
71
+ "tsx": "^4.20.5",
72
+ "typescript": "^5.9.2",
73
+ "typescript-eslint": "^8.40.0",
74
74
  "vite-plugin-node-polyfills": "^0.24.0",
75
75
  "vitest": "^3.2.4",
76
76
  "vitest-mock-extended": "^3.1.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/chunk-QOP5LA3E.cjs","../src/utils.ts"],"names":[],"mappings":"AAAA;ACCA,4FAAsB;AAOtB,MAAA,SAAsB,QAAA,CACpB,OAAA,EACA,KAAA,EACkB;AAClB,EAAA,MAAM,IAAA,EAAe,CAAC,CAAA;AACtB,EAAA,IAAI,KAAA,EAAsB,CAAA;AAC1B,EAAA,MAAA,CAAO,IAAA,EAAM;AACX,IAAA,MAAM,QAAA,EAAU,MAAM,OAAA,CAAQ,EAAE,GAAG,KAAA,EAAO,KAAK,CAAC,CAAA;AAChD,IAAA,GAAA,CAAI,IAAA,CAAK,GAAG,OAAA,CAAQ,OAAO,CAAA;AAC3B,IAAA,KAAA,EAAO,OAAA,CAAQ,IAAA;AAAA,EACjB;AACA,EAAA,OAAO,GAAA;AACT;AAMO,SAAS,yBAAA,CAA0B,MAAA,EAA+B;AAEvE,EAAA,MAAM,gCAAA,EAAmE,CAAC,CAAA;AAE1E,EAAA,OAAO,MAAA,SAAe,eAAA,CAAgB,YAAA,EAAuC;AAC3E,IAAA,IAAI,YAAA,EAA6B,IAAA;AACjC,IAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AAC3B,MAAA,MAAM,QAAA,EACJ,EAAA,GAAK,gCAAA,EACD,+BAAA,CAAgC,CAAC,EAAA,EACjC,MAAA,CAAO,eAAA,CAAgB,CAAC,CAAA,CAAE,MAAA,CAAO,eAAA,CAAgB,CAAA;AACvD,MAAA,+BAAA,CAAgC,CAAC,EAAA,EAAI,OAAA;AACrC,MAAA,MAAM,UAAA,EAAY,MAAM,OAAA;AAKxB,MAAA,GAAA,CAAI,SAAA,CAAU,WAAA,CAAY,EAAA,IAAM,YAAA,CAAa,WAAA,CAAY,CAAA,EAAG;AAC1D,QAAA,YAAA,EAAc,CAAA;AACd,QAAA,KAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,iCAAA,WAAU,EAAa,CAAA,wCAAA,EAA2C,YAAY,CAAA,CAAA;AACvE,IAAA;AACT,EAAA;AACF;ADtBmF;AACA;AACA;AACA;AACA","file":"/home/runner/_work/revault/revault/packages/sdk/lib/chunk-QOP5LA3E.cjs","sourcesContent":[null,"import type { Paginated } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"./engine/types\";\n\n/**\n * Utility function that collect results on all pages until there is no more next page\n */\nexport async function fetchAll<TData, TQuery extends { page?: number }>(\n queryFn: (query: TQuery) => Promise<Paginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let page: number | null = 1;\n while (page) {\n const partial = await queryFn({ ...query, page });\n res.push(...partial.results);\n page = partial.next;\n }\n return res;\n}\n\n/**\n * Return a function that retrieve a device index based on a given deviceUserId\n * Holds a cache of found indexes to avoid spamming device-api\n */\nexport function createDeviceIndexResolver(engine: Engine<WithWorkspace>) {\n // Cache to avoid spamming device-api when seeking for same index multiple times\n const _deviceUserIdByDeviceIndexCache: Record<string, Promise<string>> = {};\n\n return async function findDeviceIndex(deviceUserId: string): Promise<number> {\n let deviceIndex: number | null = null;\n for (let i = 4; i < 50; i++) {\n const promise =\n i in _deviceUserIdByDeviceIndexCache\n ? _deviceUserIdByDeviceIndexCache[i]!\n : engine.withDeviceIndex(i).device.getDeviceUserId();\n _deviceUserIdByDeviceIndexCache[i] = promise;\n const candidate = await promise;\n // /!\\ we need to decide in which casing we want this information\n // -> device-api returns it in uppercase\n // -> we save it in lowercase in revault-api DB\n // -> doing \"safe\" comparison here by always user the uppercase version, but hey!\n if (candidate.toUpperCase() === deviceUserId.toUpperCase()) {\n deviceIndex = i;\n break;\n }\n }\n invariant(deviceIndex, `Could not find index for device user id ${deviceUserId}`);\n return deviceIndex;\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import type { Paginated } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"./engine/types\";\n\n/**\n * Utility function that collect results on all pages until there is no more next page\n */\nexport async function fetchAll<TData, TQuery extends { page?: number }>(\n queryFn: (query: TQuery) => Promise<Paginated<TData>>,\n query: TQuery,\n): Promise<TData[]> {\n const res: TData[] = [];\n let page: number | null = 1;\n while (page) {\n const partial = await queryFn({ ...query, page });\n res.push(...partial.results);\n page = partial.next;\n }\n return res;\n}\n\n/**\n * Return a function that retrieve a device index based on a given deviceUserId\n * Holds a cache of found indexes to avoid spamming device-api\n */\nexport function createDeviceIndexResolver(engine: Engine<WithWorkspace>) {\n // Cache to avoid spamming device-api when seeking for same index multiple times\n const _deviceUserIdByDeviceIndexCache: Record<string, Promise<string>> = {};\n\n return async function findDeviceIndex(deviceUserId: string): Promise<number> {\n let deviceIndex: number | null = null;\n for (let i = 4; i < 50; i++) {\n const promise =\n i in _deviceUserIdByDeviceIndexCache\n ? _deviceUserIdByDeviceIndexCache[i]!\n : engine.withDeviceIndex(i).device.getDeviceUserId();\n _deviceUserIdByDeviceIndexCache[i] = promise;\n const candidate = await promise;\n // /!\\ we need to decide in which casing we want this information\n // -> device-api returns it in uppercase\n // -> we save it in lowercase in revault-api DB\n // -> doing \"safe\" comparison here by always user the uppercase version, but hey!\n if (candidate.toUpperCase() === deviceUserId.toUpperCase()) {\n deviceIndex = i;\n break;\n }\n }\n invariant(deviceIndex, `Could not find index for device user id ${deviceUserId}`);\n return deviceIndex;\n };\n}\n"],"mappings":";AACA,OAAO,eAAe;AAOtB,eAAsB,SACpB,SACA,OACkB;AAClB,QAAM,MAAe,CAAC;AACtB,MAAI,OAAsB;AAC1B,SAAO,MAAM;AACX,UAAM,UAAU,MAAM,QAAQ,EAAE,GAAG,OAAO,KAAK,CAAC;AAChD,QAAI,KAAK,GAAG,QAAQ,OAAO;AAC3B,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAMO,SAAS,0BAA0B,QAA+B;AAEvE,QAAM,kCAAmE,CAAC;AAE1E,SAAO,eAAe,gBAAgB,cAAuC;AAC3E,QAAI,cAA6B;AACjC,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,UACJ,KAAK,kCACD,gCAAgC,CAAC,IACjC,OAAO,gBAAgB,CAAC,EAAE,OAAO,gBAAgB;AACvD,sCAAgC,CAAC,IAAI;AACrC,YAAM,YAAY,MAAM;AAKxB,UAAI,UAAU,YAAY,MAAM,aAAa,YAAY,GAAG;AAC1D,sBAAc;AACd;AAAA,MACF;AAAA,IACF;AACA,cAAU,aAAa,2CAA2C,YAAY,EAAE;AAChF,WAAO;AAAA,EACT;AACF;","names":[]}