@ledgerhq/revault-sdk 0.13.1 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -94,8 +94,8 @@ function createApiDevice(options, logger) {
94
94
  return data;
95
95
  };
96
96
  const finalizePairingHandshake = async (params) => {
97
- const { handshake, ciphertext } = params;
98
- const payload = { seed, handshake, ciphertext };
97
+ const { handshake, partitionId } = params;
98
+ const payload = { seed, handshake, ciphertext: partitionId };
99
99
  const res = await deviceApi.post("/finalize-pairing-handshake", payload);
100
100
  return res.data;
101
101
  };
@@ -294,6 +294,9 @@ function createApiDevice(options, logger) {
294
294
  logger.info("Can't send arbitrary APDU to software device");
295
295
  return Promise.resolve("9000");
296
296
  };
297
+ const getVersion = async () => {
298
+ return "1.2.3";
299
+ };
297
300
  const poll = async () => {
298
301
  await new Promise((r) => setTimeout(r, 1e3));
299
302
  return { isAppOpened: true };
@@ -322,6 +325,7 @@ function createApiDevice(options, logger) {
322
325
  startKKPatternAsResponder,
323
326
  startKPatternAsResponder,
324
327
  validateVaultOperation,
328
+ getVersion,
325
329
  sendAPDU,
326
330
  poll,
327
331
  pollApp
@@ -490,4 +494,4 @@ var withDevicePolling = (deviceId) => (job, acceptError = () => false) => withDe
490
494
 
491
495
 
492
496
  exports.PATHS = PATHS; exports.STATUS_LENGTH = STATUS_LENGTH; exports.SCRIPT_IDS = SCRIPT_IDS; exports.STR_ROLES = STR_ROLES; exports.APPID_VAULT_ADMINISTRATOR = APPID_VAULT_ADMINISTRATOR; exports.PAGINATED_STATUS = PAGINATED_STATUS; exports.STREAMING_RESPONSE = STREAMING_RESPONSE; exports.STREAMING_NEXT_ACTION = STREAMING_NEXT_ACTION; exports.createApiDevice = createApiDevice; exports.isTransportStatusError = isTransportStatusError; exports.isDeviceCancelError = isDeviceCancelError; exports.registerTransportModule = registerTransportModule; exports.withDevicePolling = withDevicePolling;
493
- //# sourceMappingURL=chunk-VCAQTGQE.cjs.map
497
+ //# sourceMappingURL=chunk-R2LW7L74.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/chunk-R2LW7L74.cjs","../src/device/api-device.ts","../src/device/constants.ts","../src/device/utils.ts","../src/device/device-access.ts"],"names":["TransportStatusError"],"mappings":"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","file":"/home/runner/_work/revault/revault/packages/sdk/lib/chunk-R2LW7L74.cjs","sourcesContent":[null,"import type {\n HsmCertificate,\n PsdAuthChallengeResponse,\n PsdPairingData,\n PubKey,\n} from \"@ledgerhq/revault-api\";\nimport axios from \"axios\";\nimport axiosRetry from \"axios-retry\";\n\nimport type { Logger } from \"@/types\";\n\nimport { APPID_VAULT_ADMINISTRATOR, PATHS, SCRIPT_IDS, STR_ROLES } from \"./constants\";\nimport type { Device } from \"./types\";\n\ntype Options = {\n /**\n * device-api URL\n */\n deviceApiUrl: string;\n\n /**\n * salt used by device-api\n */\n salt: string;\n\n /**\n * seed generation function used for device-api device spawn\n */\n genSeed: (p: { salt: string; index: number }) => string;\n};\n\nexport type ApiDevice = {\n /**\n * bind a device to the given device index\n */\n with: (index: number) => Device;\n};\n\nexport function createApiDevice(options: Options, logger: Logger): ApiDevice {\n const { genSeed } = options;\n const sessionId = Date.now().toString();\n const deviceApi = axios.create({ baseURL: options.deviceApiUrl });\n\n axiosRetry(deviceApi, {\n retryDelay: axiosRetry.linearDelay(1000),\n retries: 3,\n /* v8 ignore start */\n retryCondition: () => true,\n onRetry: (retryCount, err) => {\n const formattedErr = `${err.code ?? `UNKNOWN`} on ${err.config?.method?.toUpperCase() ?? \"UNKNOWN_METHOD\"} ${err.config?.url ?? \"UNKNOWN_URL\"}`;\n logger.warning(\n `Retrying request to device-api (attempt ${retryCount}) - Cause: ${formattedErr}`,\n );\n },\n /* v8 ignore stop */\n });\n\n deviceApi.interceptors.request.use(\n (config) => {\n /* v8 ignore start */\n logger.debug(\n `[device-api] ${config.method?.toUpperCase()} ${config.url}${config.data ? ` ${JSON.stringify(config.data)}` : \"\"}`,\n );\n if ([\"post\", \"put\"].includes(config.method!)) {\n // when interceptor is called in combination with axios-retry, config.data can be a string or an object\n // and we should return either a string or an object compatible with the original type\n const isStringMode = typeof config.data === \"string\";\n const data = (isStringMode ? JSON.parse(config.data) : config.data) as Record<\n string,\n unknown\n >;\n const enhancedData = {\n sessionID: sessionId, // Used to ensure dedicated session if someones else uses same seed\n psd_model: \"02\", // Stax\n version: 3, // Used to properly enable noise channel\n ...data,\n };\n config.data = isStringMode ? JSON.stringify(enhancedData) : enhancedData;\n }\n return config;\n },\n /* v8 ignore stop */\n (error: Error) => Promise.reject(error),\n );\n\n return {\n with: (index: number): Device => {\n const seed = genSeed({ salt: options.salt, index });\n\n const authenticate = async ({\n challenge,\n workspaceName,\n }: {\n challenge: PsdAuthChallengeResponse;\n workspaceName: string;\n }): Promise<string> => {\n const role = challenge.role;\n if (role === \"READ_ONLY_API_KEY\")\n throw new Error(\"Invalid role for authenticate: READ_ONLY_API_KEY\");\n const { data } = await deviceApi.post<string>(\"/authenticate\", {\n seed,\n challenge: Buffer.from(challenge.challenge, \"base64\").toString(\"hex\"),\n application: APPID_VAULT_ADMINISTRATOR,\n key_handle: challenge.keyHandle,\n name: challenge.name,\n role: STR_ROLES[role],\n type: \"02\", // Stax\n workspaceName,\n });\n return data;\n };\n\n const finalizePairingHandshake = async (params: {\n handshake: string;\n partitionId: string;\n }): Promise<string> => {\n const { handshake, partitionId } = params;\n const payload = { seed, handshake, ciphertext: partitionId };\n const res = await deviceApi.post<string>(\"/finalize-pairing-handshake\", payload);\n return res.data;\n };\n\n const generateSeedFragment = async (): Promise<string> => {\n const payload = {\n seed,\n path: PATHS.KEY_MATERIAL,\n goal: 0, // seed fragment\n };\n const { data } = await deviceApi.post<string>(\"/generate-key-component\", payload);\n return data;\n };\n\n const generateWrappingKeyFragment = async (): Promise<string> => {\n const goal = 1; // means Wrapping Key\n const payload = { seed, goal, path: PATHS.KEY_MATERIAL };\n const res = await deviceApi.post<string>(\"/generate-key-fragments\", payload);\n return Buffer.from(res.data, \"hex\").toString(\"base64\");\n };\n\n const getAttestation = async (): Promise<{\n attestation: {\n codeHash: string;\n attestationPub: string;\n certificate: string;\n };\n buffer: Buffer;\n }> => {\n const { data: attestationStr } = await deviceApi.post<string>(\"/get-attestation\", { seed });\n const attestationBuffer = Buffer.from(attestationStr, \"hex\");\n const certLen = attestationBuffer.readInt8(32 + 65 + 1);\n return {\n attestation: {\n codeHash: attestationBuffer.slice(0, 32).toString(\"base64\"),\n attestationPub: attestationBuffer.slice(32, 32 + 65).toString(\"base64\"),\n certificate: attestationBuffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString(\"base64\"),\n },\n buffer: attestationBuffer,\n };\n };\n\n const getConfidentialityKey = async (): Promise<{\n confidentialityKeyCurve25519: string;\n confidentialityKeySignature: string;\n }> => {\n const res = await deviceApi.post<{\n confidentiality_key_curve25519: string;\n confidentiality_key_signature: string;\n }>(\"/get-confidentiality-key\", { seed });\n return {\n confidentialityKeyCurve25519: res.data.confidentiality_key_curve25519,\n confidentialityKeySignature: res.data.confidentiality_key_signature,\n };\n };\n\n const getConfidentialityPubKey = async (): Promise<{ pubKey: string; signature: string }> => {\n return getPublicKey({ path: PATHS.CONFIDENTIALITY });\n };\n\n const getDeviceUserId = async (): Promise<string> => {\n const res = await deviceApi.post<{ blue_device_id: string }>(\"/blue-device-id\", { seed });\n return res.data.blue_device_id.toUpperCase();\n };\n\n const getU2FPubKey = async (): Promise<{ pubKey: string; signature: string }> => {\n return getPublicKey({ path: PATHS.U2F });\n };\n\n const getValidationPubKey = async (): Promise<{ pubKey: string; signature: string }> => {\n return getPublicKey({ path: PATHS.VALIDATION });\n };\n\n const hasPairing = async (): Promise<boolean> => {\n const res = await deviceApi.post<string[]>(\"/get-partition-ids\", { seed });\n return res.data.length > 0;\n };\n\n const initPairingHandshake = async (): Promise<{ pubKey: string; signature: string }> => {\n const { data } = await deviceApi.post<{ attestation: string; pubKey: string }>(\n \"/initiate-pairing-handshake\",\n { seed },\n );\n return {\n pubKey: data.pubKey,\n signature: Buffer.from(data.attestation, \"hex\").toString(\"base64\"),\n };\n };\n\n const openSession = async (params: {\n secureChannel: { pubKey: PubKey; certificate: HsmCertificate };\n }): Promise<void> => {\n const { secureChannel } = params;\n const signature = Buffer.from(secureChannel.certificate.signature, \"base64\");\n const attestationPubKey = Buffer.from(secureChannel.certificate.attestationPub, \"base64\");\n const attestationCertificate = Buffer.from(secureChannel.certificate.certificate, \"base64\");\n const attestation = Buffer.concat([\n Buffer.from([signature.length]),\n signature,\n attestationPubKey,\n Buffer.from([attestationCertificate.length]),\n attestationCertificate,\n ]);\n const payload = {\n seed,\n path: PATHS.CONFIDENTIALITY,\n pubKey: secureChannel.pubKey,\n attestation: attestation.toString(\"hex\"),\n scriptId: SCRIPT_IDS.INIT_SESSION,\n };\n const { data: deviceResponse } = await deviceApi.post<string>(\"/open-session\", payload);\n if (deviceResponse !== \"9000\") {\n throw new Error(`device-api device failed with code: ${deviceResponse}`);\n }\n };\n\n const 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, u2fRegisterData, name, role } = params;\n const payload = {\n seed,\n challenge,\n name,\n role: STR_ROLES[role],\n hsm_data: u2fRegisterData,\n type: \"02\", // Stax\n application: APPID_VAULT_ADMINISTRATOR,\n };\n const { data } = await deviceApi.post<string>(\"/register\", payload);\n const response = Buffer.from(data, \"hex\");\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: response.slice(0, response.length - 2),\n keyHandle,\n rfu,\n pubKey,\n };\n };\n\n const registerData = async (params: { challenge: string }): Promise<string> => {\n const { challenge } = params;\n const payload = { seed, challenge };\n const res = await deviceApi.post<string>(\"/u2f-register-data\", payload);\n return res.data;\n };\n\n const setPairing = async ({ pairing }: { pairing: PsdPairingData }): Promise<void> => {\n const payload = {\n seed,\n blob: pairing.blob,\n pairing: {\n bootstrap_enabled: pairing.pairing.bootstrapEnabled,\n partition_key: pairing.pairing.partitionKey,\n workspace_name: pairing.pairing.workspaceName,\n },\n partition_key_attestation: {\n code_hash: pairing.partitionKeyAttestation.codeHash,\n attestation_pub: pairing.partitionKeyAttestation.attestationPub,\n certificate: pairing.partitionKeyAttestation.certificate,\n signature: pairing.partitionKeyAttestation.signature,\n },\n };\n await deviceApi.post(\"/set-partition-key\", payload);\n };\n\n const startKKPatternAsResponder = async (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n }): Promise<{ handshake: string; signature: string }> => {\n const payload = {\n seed,\n script_id: SCRIPT_IDS.ACCOUNT_MANAGER_SESSION,\n handshake: params.handshake,\n // for device-api it's normal to have empty string as handshake_attestation\n handshake_attestation: \"\",\n partition_id: params.partitionId,\n };\n const { data } = await deviceApi.post<string>(\"/start-kk-pattern-as-responder\", payload);\n const buffer = Buffer.from(data, \"hex\");\n const dataLength = buffer.readInt8(0);\n return {\n handshake: buffer.slice(1, dataLength + 1).toString(\"base64\"),\n signature: buffer.slice(dataLength + 1).toString(\"base64\"),\n };\n };\n\n const startKPatternAsResponder = async (params: {\n handshake: string;\n handshakeAttestation: HsmCertificate;\n partitionId: string;\n }): Promise<void> => {\n const { handshake, partitionId } = params;\n const payload = {\n seed,\n script_id: SCRIPT_IDS.ACCOUNT_MANAGER_SESSION,\n handshake,\n // for device-api it's normal to have empty string as handshake_attestation\n handshake_attestation: \"\",\n partition_id: partitionId,\n };\n const { data: deviceResponse } = await deviceApi.post<string>(\n \"/start-k-pattern-as-responder\",\n payload,\n );\n if (deviceResponse !== \"9000\") {\n throw new Error(`device-api device failed with code: ${deviceResponse}`);\n }\n };\n\n const getPublicKey = async (params: {\n path: string;\n }): Promise<{ pubKey: string; signature: string }> => {\n const { path } = params;\n type DeviceApiGetPubKeyResponse = { attestation: string; pubKey: string };\n const payload = { seed, secp256k1: true, path };\n const res = await deviceApi.post<DeviceApiGetPubKeyResponse>(\"/get-public-key\", payload);\n return {\n pubKey: res.data.pubKey,\n signature: Buffer.from(res.data.attestation, \"hex\").toString(\"base64\"),\n };\n };\n\n const validateVaultOperation = async (params: { actions: string[] }): Promise<string> => {\n const { actions } = params;\n const payload = {\n seed,\n path: PATHS.VALIDATION,\n actions,\n };\n const { data: signature } = await deviceApi.post<string>(\"/validate-op\", payload);\n return signature;\n };\n\n const sendAPDU = (_apdu: string): Promise<string> => {\n logger.info(\"Can't send arbitrary APDU to software device\");\n return Promise.resolve(\"9000\");\n };\n\n const getVersion = async (): Promise<string> => {\n return \"1.2.3\";\n };\n\n const poll = async (): Promise<{ isAppOpened: boolean }> => {\n await new Promise((r) => setTimeout(r, 1e3));\n return { isAppOpened: true };\n };\n\n const pollApp = async (): Promise<string> => {\n await new Promise((r) => setTimeout(r, 1e3));\n return \"9000\";\n };\n\n return {\n authenticate,\n finalizePairingHandshake,\n generateSeedFragment,\n generateWrappingKeyFragment,\n getAttestation,\n getConfidentialityKey,\n getConfidentialityPubKey,\n getDeviceUserId,\n getU2FPubKey,\n getValidationPubKey,\n hasPairing,\n initPairingHandshake,\n openSession,\n register,\n registerData,\n setPairing,\n startKKPatternAsResponder,\n startKPatternAsResponder,\n validateVaultOperation,\n getVersion,\n sendAPDU,\n poll,\n pollApp,\n };\n },\n };\n}\n","export const PATHS = {\n U2F: \"5655636'/5583430'\",\n CONFIDENTIALITY: \"5655636'/4410950'\",\n KEY_MATERIAL: \"5655636'/4932953'\",\n VALIDATION: \"5655636'/5652812'\",\n} as const;\n\nexport const STATUS_LENGTH = 2;\n\nexport const SCRIPT_IDS = {\n INIT_SESSION: 3,\n ACCOUNT_MANAGER_SESSION: 2,\n} as const;\n\nexport const STR_ROLES: Record<\"OPERATOR\" | \"ADMIN\" | \"SHARED_OWNER\", string> = {\n OPERATOR: \"00\",\n ADMIN: \"01\",\n SHARED_OWNER: \"02\",\n} as const;\n\nexport const APPID_VAULT_ADMINISTRATOR =\n \"ad5be1a1fe011ce7f53ae081a22ae000a42021f3f94106a3bac9f76e8230e4b9\";\n\nconst all61xxStatus = [];\nfor (let i = 0x6100; i <= 0x61ff; i++) {\n all61xxStatus.push(i);\n}\n\nexport const PAGINATED_STATUS = all61xxStatus;\nexport const STREAMING_RESPONSE = 0x02;\nexport const STREAMING_NEXT_ACTION = 0x01;\n","import { TransportStatusError } from \"@ledgerhq/errors\";\n\nexport const isTransportStatusError = (error: unknown): error is TransportStatusError => {\n return (\n error instanceof TransportStatusError ||\n (error instanceof Error && \"statusCode\" in error && error.message.startsWith(\"Ledger device:\"))\n );\n};\n\nconst CANCEL_STATUS_CODES = [\n 0x6985, // cancel on Ledger Blue\n\n // STAX\n 0xb00c, // cancel collect wk fragment\n 0xb00d, // cancel user registration\n 0xb010, // cancel review\n 0xb012, // cancel master seed generation\n];\n\nexport const isDeviceCancelError = (error: Error): boolean => {\n return isTransportStatusError(error) && CANCEL_STATUS_CODES.includes(error.statusCode);\n};\n","// ------------------------------------------------------------------------------------------------\n// ------------------------------------------------------------------------------------------------\n// THIS IS SOME HORRIBLE CODE IMPORTED JUST\n// FOR THE SAKE OF NOT IMPORTING UGLY, WICKED, AND\n// BROKEN @ledgerhq/live-* LIBRARIES\n//\n// IT'S MEANT TO BE CONSIDERED AS A BLACK BOX\n// ------------------------------------------------------------------------------------------------\n// ------------------------------------------------------------------------------------------------\nimport {\n BluetoothRequired,\n CantOpenDevice,\n DeviceHalted,\n FirmwareOrAppUpdateRequired,\n TransportInterfaceNotAvailable,\n TransportStatusError,\n TransportWebUSBGestureRequired,\n} from \"@ledgerhq/errors\";\nimport type Transport from \"@ledgerhq/hw-transport\";\nimport { Observable, throwError, timer } from \"rxjs\";\nimport { catchError, mergeMap, retryWhen } from \"rxjs/operators\";\n\nconst initialErrorRemapping = (error: Error): Observable<never> =>\n throwError(\n error && error instanceof TransportStatusError && error.statusCode === 0x6faa\n ? new DeviceHalted(error.message)\n : error instanceof TransportStatusError && error.statusCode === 0x6b00\n ? new FirmwareOrAppUpdateRequired(error.message)\n : error,\n );\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst never = new Promise(() => {});\n\ntype Discovery = Observable<{\n type: \"add\" | \"remove\";\n id: string;\n name: string;\n}>;\n\nexport type TransportModule = {\n // unique transport name that identify the transport module\n id: string;\n // open a device by an id, this id must be unique across all modules\n // you can typically prefix it with `something|` that identify it globally\n // returns falsy if the transport module can't handle this id\n // here, open means we want to START doing something with the transport\n open: (id: string) => Promise<Transport> | null | undefined;\n // here, close means we want to STOP doing something with the transport\n close?: (transport: Transport, id: string) => Promise<void> | null | undefined;\n // disconnect/interrupt a device connection globally\n // returns falsy if the transport module can't handle this id\n disconnect: (id: string) => Promise<void> | null | undefined;\n // optional observable that allows to discover a transport\n discovery?: Discovery;\n};\n\nconst modules: TransportModule[] = [];\n\nexport const registerTransportModule = (module: TransportModule): void => {\n modules.push(module);\n};\n\nexport const close = (transport: Transport, deviceId: string): Promise<void> => {\n for (const m of modules) {\n const p = m.close?.(transport, deviceId);\n if (p) return p;\n }\n // fallback on an actual close\n return transport.close();\n};\n\nexport const open = (deviceId: string): Promise<Transport> => {\n for (const m of modules) {\n const p = m.open(deviceId);\n if (p) return p;\n }\n return Promise.reject(new Error(`Can't find handler to open ${deviceId}`));\n};\n\nconst transportFinally =\n (cleanup: () => Promise<void>) =>\n <T>(observable: Observable<T>): Observable<T> =>\n // @ts-expect-error typescript not checking against the instanceof\n Observable.create((o) => {\n let done = false;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const finalize = (): any => {\n if (done) return never;\n done = true;\n return cleanup();\n };\n\n const sub = observable.subscribe({\n next: (e) => o.next(e),\n complete: () => {\n void finalize().then(() => o.complete());\n },\n error: (e) => {\n void finalize().then(() => o.error(e));\n },\n });\n return () => {\n sub.unsubscribe();\n void finalize();\n };\n });\n\ntype AccessHook = () => () => void;\n\nconst accessHooks: AccessHook[] = [];\n\nconst deviceQueues = {};\n\nexport const withDevice =\n (deviceId: string) =>\n <T>(job: (t: Transport) => Observable<T>): Observable<T> =>\n new Observable((o) => {\n // @ts-expect-error typescript not checking against the instanceof\n let unsubscribed;\n // @ts-expect-error typescript not checking against the instanceof\n let sub;\n // @ts-expect-error typescript not checking against the instanceof\n const deviceQueue = deviceQueues[deviceId] ?? Promise.resolve();\n\n // @ts-expect-error typescript not checking against the instanceof\n const finalize = (transport, cleanups): Promise<void> =>\n close(transport, deviceId)\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n .catch(() => {})\n .then(() => {\n // @ts-expect-error typescript not checking against the instanceof\n cleanups.forEach((c) => c());\n });\n\n // when we'll finish all the current job, we'll call finish\n // @ts-expect-error typescript not checking against the instanceof\n let finish;\n // this new promise is the next exec queue\n // @ts-expect-error typescript not checking against the instanceof\n deviceQueues[deviceId] = new Promise((resolve) => {\n finish = resolve;\n });\n // for any new job, we'll now wait the exec queue to be available\n deviceQueue\n .then(() => open(deviceId)) // open the transport\n // @ts-expect-error typescript not checking against the instanceof\n .then(async (transport) => {\n // @ts-expect-error typescript not checking against the instanceof\n if (unsubscribed) {\n // it was unsubscribed prematurely\n // @ts-expect-error typescript not checking against the instanceof\n return finalize(transport, [finish]);\n }\n\n if (\n transport.requestConnectionPriority &&\n typeof transport.requestConnectionPriority === \"function\"\n ) {\n await transport.requestConnectionPriority(\"High\");\n }\n\n return transport;\n })\n // @ts-expect-error typescript not checking against the instanceof\n .catch((e) => {\n // @ts-expect-error typescript not checking against the instanceof\n finish();\n if (e instanceof BluetoothRequired) throw e;\n if (e instanceof TransportWebUSBGestureRequired) throw e;\n if (e instanceof TransportInterfaceNotAvailable) throw e;\n throw new CantOpenDevice(e.message);\n })\n // @ts-expect-error typescript not checking against the instanceof\n .then((transport) => {\n if (!transport) return;\n\n // @ts-expect-error typescript not checking against the instanceof\n if (unsubscribed) {\n // it was unsubscribed prematurely\n // @ts-expect-error typescript not checking against the instanceof\n return finalize(transport, [finish]);\n }\n\n const cleanups = accessHooks.map((hook) => hook());\n sub = job(transport) // $FlowFixMe\n .pipe(\n catchError(initialErrorRemapping),\n // $FlowFixMe\n transportFinally(() =>\n // @ts-expect-error typescript not checking against the instanceof\n finalize(transport, [...cleanups, finish]),\n ),\n )\n .subscribe(o);\n })\n // @ts-expect-error typescript not checking against the instanceof\n .catch((error) => o.error(error));\n return () => {\n unsubscribed = true;\n // @ts-expect-error typescript not checking against the instanceof\n if (sub) sub.unsubscribe();\n };\n });\n\nconst WITH_DEVICE_POLLING_DELAY = 500;\n\nexport const retryWhileErrors =\n (acceptError: (arg0: Error) => boolean) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (attempts: Observable<any>): Observable<any> =>\n attempts.pipe(\n mergeMap((error) => {\n if (!acceptError(error)) {\n return throwError(error);\n }\n\n return timer(WITH_DEVICE_POLLING_DELAY);\n }),\n );\n\nexport const withDevicePolling =\n (deviceId: string) =>\n <T>(\n job: (arg0: Transport) => Observable<T>,\n acceptError: (arg0: Error) => boolean = () => false,\n ): Observable<T> =>\n withDevice(deviceId)(job).pipe(retryWhen(retryWhileErrors(acceptError)));\n"]}
package/lib/device.cjs CHANGED
@@ -3,11 +3,11 @@
3
3
 
4
4
 
5
5
 
6
- var _chunkVCAQTGQEcjs = require('./chunk-VCAQTGQE.cjs');
6
+ var _chunkR2LW7L74cjs = require('./chunk-R2LW7L74.cjs');
7
7
 
8
8
 
9
9
 
10
10
 
11
11
 
12
- exports.createApiDevice = _chunkVCAQTGQEcjs.createApiDevice; exports.isDeviceCancelError = _chunkVCAQTGQEcjs.isDeviceCancelError; exports.isTransportStatusError = _chunkVCAQTGQEcjs.isTransportStatusError; exports.registerTransportModule = _chunkVCAQTGQEcjs.registerTransportModule;
12
+ exports.createApiDevice = _chunkR2LW7L74cjs.createApiDevice; exports.isDeviceCancelError = _chunkR2LW7L74cjs.isDeviceCancelError; exports.isTransportStatusError = _chunkR2LW7L74cjs.isTransportStatusError; exports.registerTransportModule = _chunkR2LW7L74cjs.registerTransportModule;
13
13
  //# sourceMappingURL=device.cjs.map
package/lib/device.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Logger } from './index.cjs';
2
- import { D as Device } from './types-CsvE9Mlb.cjs';
2
+ import { D as Device } from './types-DJfbanPz.cjs';
3
3
  import { TransportStatusError } from '@ledgerhq/errors';
4
4
  import Transport from '@ledgerhq/hw-transport';
5
5
  import { Observable } from 'rxjs';
package/lib/device.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Logger } from './index.js';
2
- import { D as Device } from './types-CsvE9Mlb.js';
2
+ import { D as Device } from './types-DJfbanPz.js';
3
3
  import { TransportStatusError } from '@ledgerhq/errors';
4
4
  import Transport from '@ledgerhq/hw-transport';
5
5
  import { Observable } from 'rxjs';
package/lib/device.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  isDeviceCancelError,
4
4
  isTransportStatusError,
5
5
  registerTransportModule
6
- } from "./chunk-DPHEFR6E.js";
6
+ } from "./chunk-BGVGHXMO.js";
7
7
  export {
8
8
  createApiDevice,
9
9
  isDeviceCancelError,
package/lib/engine.cjs CHANGED
@@ -13,7 +13,7 @@ var _chunkQOP5LA3Ecjs = require('./chunk-QOP5LA3E.cjs');
13
13
 
14
14
 
15
15
 
16
- var _chunkVCAQTGQEcjs = require('./chunk-VCAQTGQE.cjs');
16
+ var _chunkR2LW7L74cjs = require('./chunk-R2LW7L74.cjs');
17
17
 
18
18
  // src/engine/index.ts
19
19
  var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant);
@@ -37,7 +37,7 @@ var splitChunks = (chunk, buffer) => {
37
37
  }
38
38
  return chunks;
39
39
  };
40
- var removeStatus = (result) => result.slice(0, result.length - _chunkVCAQTGQEcjs.STATUS_LENGTH);
40
+ var removeStatus = (result) => result.slice(0, result.length - _chunkR2LW7L74cjs.STATUS_LENGTH);
41
41
  var sendByChunk = async (transport, command, data, chunkSize = MAX_CHUNK_LENGTH) => {
42
42
  const chunks = splitChunks(chunkSize, data);
43
43
  let response = Buffer.from([]);
@@ -47,7 +47,7 @@ var sendByChunk = async (transport, command, data, chunkSize = MAX_CHUNK_LENGTH)
47
47
  apdu[2] = i && 128;
48
48
  response = await transport.send(apdu[0], apdu[1], apdu[2], apdu[3], chunk, [
49
49
  36864,
50
- ..._chunkVCAQTGQEcjs.PAGINATED_STATUS
50
+ ..._chunkR2LW7L74cjs.PAGINATED_STATUS
51
51
  ]);
52
52
  }
53
53
  return response;
@@ -90,7 +90,7 @@ var buildAttestation = (params) => {
90
90
  };
91
91
  var genericRetryOnError = (err) => {
92
92
  if (err instanceof _errors.LockedDeviceError) return true;
93
- if (_chunkVCAQTGQEcjs.isTransportStatusError.call(void 0, err) && err.statusCode === 27913) return true;
93
+ if (_chunkR2LW7L74cjs.isTransportStatusError.call(void 0, err) && err.statusCode === 27913) return true;
94
94
  if (err instanceof _errors.DisconnectedDevice) return true;
95
95
  return false;
96
96
  };
@@ -98,22 +98,23 @@ function createRealDevice(options, logger) {
98
98
  const { transportId } = options;
99
99
  async function run(job, retryOnError = genericRetryOnError) {
100
100
  return _rxjs.lastValueFrom.call(void 0,
101
- _chunkVCAQTGQEcjs.withDevicePolling.call(void 0, transportId)((transport) => _rxjs.from.call(void 0, job(transport)), retryOnError)
101
+ _chunkR2LW7L74cjs.withDevicePolling.call(void 0, transportId)((transport) => _rxjs.from.call(void 0, job(transport)), retryOnError)
102
102
  );
103
103
  }
104
104
  const noRetry = () => false;
105
- const poll = async () => {
105
+ const alwaysRetry = () => true;
106
+ const poll = async (opts = {}) => {
106
107
  await run(
107
108
  // eslint-disable-next-line @typescript-eslint/no-empty-function
108
109
  async (_transport) => {
109
110
  },
110
- () => true
111
+ _nullishCoalesce(opts.retryOnError, () => ( alwaysRetry))
111
112
  );
112
113
  try {
113
- await getPublicKey(_chunkVCAQTGQEcjs.PATHS.U2F, { secp256k1: true, retryOnError: noRetry });
114
+ await getPublicKey(_chunkR2LW7L74cjs.PATHS.U2F, { secp256k1: true, retryOnError: noRetry });
114
115
  return { isAppOpened: true };
115
116
  } catch (err) {
116
- if (_chunkVCAQTGQEcjs.isTransportStatusError.call(void 0, err) && genericRetryOnError(err)) {
117
+ if (_chunkR2LW7L74cjs.isTransportStatusError.call(void 0, err) && genericRetryOnError(err)) {
117
118
  return { isAppOpened: false };
118
119
  }
119
120
  throw err;
@@ -144,18 +145,18 @@ function createRealDevice(options, logger) {
144
145
  );
145
146
  const pubKeyLength = response.readInt8(0);
146
147
  const pubKey = response.slice(1, pubKeyLength + 1).toString("hex").toUpperCase();
147
- const signature = response.slice(pubKeyLength + 1, response.length - _chunkVCAQTGQEcjs.STATUS_LENGTH).toString("base64");
148
+ const signature = response.slice(pubKeyLength + 1, response.length - _chunkR2LW7L74cjs.STATUS_LENGTH).toString("base64");
148
149
  return { pubKey, signature };
149
150
  };
150
151
  const device = {
151
152
  authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {
152
153
  logger.info(`[device] Authenticate`);
153
154
  _invariant2.default.call(void 0, role !== "READ_ONLY_API_KEY", "Invalid role for authenticate: READ_ONLY_API_KEY");
154
- const applicationBuffer = Buffer.from(_chunkVCAQTGQEcjs.APPID_VAULT_ADMINISTRATOR, "hex");
155
+ const applicationBuffer = Buffer.from(_chunkR2LW7L74cjs.APPID_VAULT_ADMINISTRATOR, "hex");
155
156
  const nameBuffer = Buffer.from(name);
156
157
  const workspaceBuffer = Buffer.from(workspaceName);
157
158
  const keyHandleData = Buffer.concat([
158
- Buffer.from(_chunkVCAQTGQEcjs.STR_ROLES[role], "hex"),
159
+ Buffer.from(_chunkR2LW7L74cjs.STR_ROLES[role], "hex"),
159
160
  Buffer.from([nameBuffer.length]),
160
161
  nameBuffer,
161
162
  Buffer.from([workspaceBuffer.length]),
@@ -176,10 +177,27 @@ function createRealDevice(options, logger) {
176
177
  );
177
178
  return removeStatus(authentication).toString("hex");
178
179
  },
179
- finalizePairingHandshake: FIXME_NOT_IMPLEMENTED("finalizePairingHandshake"),
180
+ finalizePairingHandshake: async (params) => {
181
+ const bufWithStatus = await run(
182
+ (transport) => sendByChunk(transport, [224, 71, 0, 2], buildAttestation(params))
183
+ );
184
+ return removeStatus(bufWithStatus).toString("hex");
185
+ },
180
186
  generateSeedFragment: FIXME_NOT_IMPLEMENTED("generateSeedFragment"),
181
187
  generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED("generateWrappingKeyFragment"),
182
- getAttestation: FIXME_NOT_IMPLEMENTED("getAttestation"),
188
+ getAttestation: async () => {
189
+ const bufWithStatus = await run((transport) => transport.send(224, 65, 0, 0));
190
+ const buffer = removeStatus(bufWithStatus);
191
+ const certLen = buffer.readInt8(32 + 65 + 1);
192
+ return {
193
+ attestation: {
194
+ codeHash: buffer.slice(0, 32).toString("base64"),
195
+ attestationPub: buffer.slice(32, 32 + 65).toString("base64"),
196
+ certificate: buffer.slice(32 + 65, 32 + 65 + 2 + certLen).toString("base64")
197
+ },
198
+ buffer
199
+ };
200
+ },
183
201
  getConfidentialityKey: async () => {
184
202
  logger.info(`[device] getConfidentialityKey`);
185
203
  const bufWithStatus = await run((transport) => transport.send(224, 77, 0, 0));
@@ -192,10 +210,10 @@ function createRealDevice(options, logger) {
192
210
  confidentialityKeySignature: sig.toString("hex")
193
211
  };
194
212
  },
195
- getConfidentialityPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.CONFIDENTIALITY, { secp256k1: true }),
213
+ getConfidentialityPubKey: () => getPublicKey(_chunkR2LW7L74cjs.PATHS.CONFIDENTIALITY, { secp256k1: true }),
196
214
  getDeviceUserId: FIXME_NOT_IMPLEMENTED("getDeviceUserId"),
197
- getU2FPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.U2F, { secp256k1: false }),
198
- getValidationPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.VALIDATION, { secp256k1: true }),
215
+ getU2FPubKey: () => getPublicKey(_chunkR2LW7L74cjs.PATHS.U2F, { secp256k1: false }),
216
+ getValidationPubKey: () => getPublicKey(_chunkR2LW7L74cjs.PATHS.VALIDATION, { secp256k1: true }),
199
217
  hasPairing: async () => {
200
218
  logger.info(`[device] hasPairing`);
201
219
  const apdu = [224, 81, 0, 0, 181];
@@ -203,10 +221,51 @@ function createRealDevice(options, logger) {
203
221
  const hex = Buffer.from(res).toString("hex");
204
222
  return hex !== "6f45" && hex !== "6a87";
205
223
  },
206
- initPairingHandshake: FIXME_NOT_IMPLEMENTED("initPairingHandshake"),
224
+ initPairingHandshake: async () => {
225
+ const res = await run((transport) => transport.send(224, 70, 0, 0));
226
+ const pubKeyLength = res.readInt8(0);
227
+ const pubKey = res.slice(1, pubKeyLength + 1).toString("hex").toUpperCase();
228
+ const signature = res.slice(pubKeyLength + 1, res.length - _chunkR2LW7L74cjs.STATUS_LENGTH).toString("base64");
229
+ return { pubKey, signature };
230
+ },
207
231
  openSession: FIXME_NOT_IMPLEMENTED("openSession"),
208
- register: FIXME_NOT_IMPLEMENTED("register"),
209
- registerData: FIXME_NOT_IMPLEMENTED("registerData"),
232
+ register: async (params) => {
233
+ const { challenge: strChallenge, u2fRegisterData: _, name, role } = params;
234
+ const challenge = Buffer.from(strChallenge, "hex");
235
+ _invariant2.default.call(void 0, challenge.length === 32, "challenge hex is expected to have 32 bytes");
236
+ const applicationBuf = Buffer.from(_chunkR2LW7L74cjs.APPID_VAULT_ADMINISTRATOR, "hex");
237
+ _invariant2.default.call(void 0, applicationBuf.length === 32, "application hex is expected to have 32 bytes");
238
+ const userNameBuff = Buffer.from(name);
239
+ const keyHandleData = Buffer.concat([
240
+ Buffer.from(_chunkR2LW7L74cjs.STR_ROLES[role], "hex"),
241
+ Buffer.from([userNameBuff.length]),
242
+ userNameBuff
243
+ ]);
244
+ const keyHandleDataLength = Buffer.alloc(2);
245
+ keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);
246
+ const data = Buffer.concat([challenge, applicationBuf, keyHandleDataLength, keyHandleData]);
247
+ const response = await run(
248
+ (transport) => sendByChunk(transport, [224, 1, 0, 0], data)
249
+ );
250
+ let i = 0;
251
+ const rfu = response.slice(i, i += 1)[0];
252
+ const pubKey = response.slice(i, i += 65).toString("hex");
253
+ const keyHandleLength = response.slice(i, ++i)[0];
254
+ const keyHandle = response.slice(i, i += keyHandleLength);
255
+ return {
256
+ u2fRegister: removeStatus(response),
257
+ keyHandle,
258
+ rfu,
259
+ pubKey
260
+ };
261
+ },
262
+ registerData: async (params) => {
263
+ const { challenge: strChallenge } = params;
264
+ const challenge = Buffer.from(strChallenge, "hex");
265
+ _invariant2.default.call(void 0, challenge.length === 32, "challenge hex is expected to have 32 bytes");
266
+ const response = await run((transport) => transport.send(224, 3, 0, 0, challenge));
267
+ return removeStatus(response).toString("hex");
268
+ },
210
269
  setPairing: async ({ pairing }) => {
211
270
  logger.info(`[device] setPairing`);
212
271
  const psdPayload = Buffer.from(pairing.blob, "base64");
@@ -220,12 +279,12 @@ function createRealDevice(options, logger) {
220
279
  logger.info(`[device] startKPatternAsResponder`);
221
280
  const data = buildAttestation(params);
222
281
  await run(
223
- (transport) => sendByChunk(transport, [224, 73, 0, _chunkVCAQTGQEcjs.SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data)
282
+ (transport) => sendByChunk(transport, [224, 73, 0, _chunkR2LW7L74cjs.SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data)
224
283
  );
225
284
  },
226
285
  validateVaultOperation: async (params) => {
227
286
  logger.info(`[device] validateVaultOperation`);
228
- const path = getPathFromPathString(_chunkVCAQTGQEcjs.PATHS.VALIDATION);
287
+ const path = getPathFromPathString(_chunkR2LW7L74cjs.PATHS.VALIDATION);
229
288
  const paths = Buffer.concat([
230
289
  Buffer.from([path.length]),
231
290
  ...path.map((derivation) => {
@@ -246,9 +305,9 @@ function createRealDevice(options, logger) {
246
305
  );
247
306
  const responseType = response.readInt8(0);
248
307
  let responseStatus = response.readUInt16BE(response.length - 2);
249
- if (responseType === _chunkVCAQTGQEcjs.STREAMING_NEXT_ACTION) {
308
+ if (responseType === _chunkR2LW7L74cjs.STREAMING_NEXT_ACTION) {
250
309
  nextActionId = response.readUIntBE(1, 2);
251
- } else if (responseType === _chunkVCAQTGQEcjs.STREAMING_RESPONSE) {
310
+ } else if (responseType === _chunkR2LW7L74cjs.STREAMING_RESPONSE) {
252
311
  finalResponse = response.slice(3, response.length - 2);
253
312
  while (responseStatus !== 36864) {
254
313
  const resp = await run((transport) => transport.send(0, 192, 0, 0));
@@ -265,6 +324,14 @@ function createRealDevice(options, logger) {
265
324
  const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, "hex")));
266
325
  return Buffer.from(res).toString("hex");
267
326
  },
327
+ getVersion: async () => {
328
+ const res = await run((transport) => transport.send(176, 1, 0, 0));
329
+ const appNameLen = res.readInt8(1);
330
+ const appVersionLen = res.readInt8(2 + appNameLen);
331
+ const appVersionHex = res.slice(2 + 1 + appNameLen, 2 + appNameLen + appVersionLen + 1);
332
+ const appVersion = Buffer.from(appVersionHex).toString();
333
+ return appVersion;
334
+ },
268
335
  poll,
269
336
  pollApp
270
337
  };
@@ -284,7 +351,8 @@ var createClient = (options) => {
284
351
  return {
285
352
  ...options.debugAuthToken ? { "x-revault-debug-auth-token": options.debugAuthToken } : {},
286
353
  ...options.rootAuthToken ? { "x-revault-root-auth-token": options.rootAuthToken } : {},
287
- ...options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}
354
+ ...options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {},
355
+ ...options.apiAccessToken ? { Authorization: `Bearer ${options.apiAccessToken}` } : {}
288
356
  };
289
357
  }
290
358
  })
@@ -321,7 +389,8 @@ async function genericRegister({
321
389
  const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });
322
390
  const pairingPayload = await device.finalizePairingHandshake({
323
391
  handshake: challenge.handshake,
324
- ciphertext: challenge.ciphertext
392
+ partitionId: challenge.ciphertext,
393
+ handshakeAttestation: challenge.handshakeAttestation
325
394
  });
326
395
  const register = await device.register({
327
396
  challenge: challenge.challenge,
@@ -356,7 +425,7 @@ function createEngine(options, logger) {
356
425
  baseUrl: options.baseUrl
357
426
  };
358
427
  const client = createClient(clientOptions);
359
- const apiDevice = _chunkVCAQTGQEcjs.createApiDevice.call(void 0, options, logger);
428
+ const apiDevice = _chunkR2LW7L74cjs.createApiDevice.call(void 0, options, logger);
360
429
  const base = {
361
430
  client,
362
431
  createClient: (overrides) => createClient({ ...clientOptions, ...overrides })
@@ -555,7 +624,7 @@ function createEngine(options, logger) {
555
624
  pubKey,
556
625
  workspaceName: __workspaceName
557
626
  });
558
- _optionalChain([opts, 'optionalAccess', _ => _.onScreenDisplayed, 'optionalCall', _2 => _2()]);
627
+ _optionalChain([opts, 'optionalAccess', _2 => _2.onScreenDisplayed, 'optionalCall', _3 => _3()]);
559
628
  const authentication = await device.authenticate({
560
629
  challenge,
561
630
  workspaceName: __workspaceName
@@ -564,7 +633,7 @@ function createEngine(options, logger) {
564
633
  workspaceName: __workspaceName,
565
634
  pubKey,
566
635
  authentication,
567
- validityDurationSecs: _optionalChain([opts, 'optionalAccess', _3 => _3.validityDurationSecs])
636
+ validityDurationSecs: _optionalChain([opts, 'optionalAccess', _4 => _4.validityDurationSecs])
568
637
  };
569
638
  const { token } = await client2.auth.psd.authenticate.mutate({ ...authPayload });
570
639
  const withPsdAuth = {
@@ -580,14 +649,14 @@ function createEngine(options, logger) {
580
649
  name: registration.name,
581
650
  role: registration.role,
582
651
  getChallenge: async ({ deviceData }) => {
583
- const challenge = await client2.users.generateRegistrationChallenge.mutate({
652
+ const challenge = await client2.userRegistrations.generateChallenge.mutate({
584
653
  id: registration.id,
585
654
  workspaceName: __workspaceName,
586
655
  deviceData
587
656
  });
588
657
  return challenge;
589
658
  },
590
- submitChallenge: ({ challengeResponse }) => client2.users.confirmRegistrationChallenge.mutate({
659
+ submitChallenge: ({ challengeResponse }) => client2.userRegistrations.submitChallenge.mutate({
591
660
  workspaceName: __workspaceName,
592
661
  id: registration.id,
593
662
  challengeResponse
@@ -641,7 +710,7 @@ function createEngine(options, logger) {
641
710
  handshakeAttestation: challenge.handshakeAttestation,
642
711
  partitionId: challenge.partitionId
643
712
  });
644
- _optionalChain([params, 'optionalAccess', _4 => _4.onScreenDisplayed, 'optionalCall', _5 => _5()]);
713
+ _optionalChain([params, 'optionalAccess', _5 => _5.onScreenDisplayed, 'optionalCall', _6 => _6()]);
645
714
  const signature = await device.validateVaultOperation({
646
715
  actions: challenge.wActions
647
716
  });