@ledgerhq/device-contacts-kit 0.0.0-develop-20260827155839 → 0.0.0-develop-20260828024102
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/README.md +30 -2
- package/lib/cjs/api/ContactsManager.js +1 -1
- package/lib/cjs/api/ContactsManager.js.map +1 -1
- package/lib/cjs/api/app-binder/RegisterExternalAddressDeviceActionTypes.js +2 -0
- package/lib/cjs/api/app-binder/RegisterExternalAddressDeviceActionTypes.js.map +7 -0
- package/lib/cjs/api/index.js +1 -1
- package/lib/cjs/api/index.js.map +2 -2
- package/lib/cjs/api/model/RegisterExternalAddress.js +2 -0
- package/lib/cjs/api/model/RegisterExternalAddress.js.map +7 -0
- package/lib/cjs/internal/DefaultContactsManager.js +1 -1
- package/lib/cjs/internal/DefaultContactsManager.js.map +3 -3
- package/lib/cjs/internal/DefaultContactsManager.test.js +2 -0
- package/lib/cjs/internal/DefaultContactsManager.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/ContactsAppBinder.js +1 -1
- package/lib/cjs/internal/app-binder/ContactsAppBinder.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js +2 -0
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js.map +7 -0
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.test.js +2 -0
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/makeInternalApi.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/makeInternalApi.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.js.map +7 -0
- package/lib/cjs/internal/app-binder/isContactsSupportedForSession.js +1 -1
- package/lib/cjs/internal/app-binder/isContactsSupportedForSession.js.map +3 -3
- package/lib/cjs/internal/app-binder/isContactsSupportedForSession.test.js +1 -1
- package/lib/cjs/internal/app-binder/isContactsSupportedForSession.test.js.map +3 -3
- package/lib/cjs/internal/app-binder/model/contactsConstants.js +2 -0
- package/lib/cjs/internal/app-binder/model/contactsConstants.js.map +7 -0
- package/lib/cjs/internal/app-binder/model/contactsErrors.js +2 -0
- package/lib/cjs/internal/app-binder/model/contactsErrors.js.map +7 -0
- package/lib/cjs/internal/app-binder/model/contactsValidation.js +2 -0
- package/lib/cjs/internal/app-binder/model/contactsValidation.js.map +7 -0
- package/lib/cjs/internal/app-binder/model/contactsValidation.test.js +2 -0
- package/lib/cjs/internal/app-binder/model/contactsValidation.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/services/contactsTlvSerializer.js +2 -0
- package/lib/cjs/internal/app-binder/services/contactsTlvSerializer.js.map +7 -0
- package/lib/cjs/internal/app-binder/services/contactsTlvSerializer.test.js +2 -0
- package/lib/cjs/internal/app-binder/services/contactsTlvSerializer.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/services/sendFramedContactsPayload.js +2 -0
- package/lib/cjs/internal/app-binder/services/sendFramedContactsPayload.js.map +7 -0
- package/lib/cjs/internal/app-binder/services/sendFramedContactsPayload.test.js +2 -0
- package/lib/cjs/internal/app-binder/services/sendFramedContactsPayload.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.js +2 -0
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.js.map +7 -0
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.test.js +2 -0
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.test.js.map +7 -0
- package/lib/cjs/internal/di.js +1 -1
- package/lib/cjs/internal/di.js.map +3 -3
- package/lib/cjs/internal/di.test.js +1 -1
- package/lib/cjs/internal/di.test.js.map +3 -3
- package/lib/cjs/internal/use-cases/RegisterExternalAddressUseCase.js +2 -0
- package/lib/cjs/internal/use-cases/RegisterExternalAddressUseCase.js.map +7 -0
- package/lib/cjs/internal/use-cases/RegisterExternalAddressUseCase.test.js +2 -0
- package/lib/cjs/internal/use-cases/RegisterExternalAddressUseCase.test.js.map +7 -0
- package/lib/cjs/internal/use-cases/di/useCaseModule.js +2 -0
- package/lib/cjs/internal/use-cases/di/useCaseModule.js.map +7 -0
- package/lib/cjs/internal/use-cases/di/useCaseTypes.js +2 -0
- package/lib/cjs/internal/use-cases/di/useCaseTypes.js.map +7 -0
- package/lib/cjs/package.json +2 -1
- package/lib/esm/api/app-binder/RegisterExternalAddressDeviceActionTypes.js +1 -0
- package/lib/esm/api/app-binder/RegisterExternalAddressDeviceActionTypes.js.map +7 -0
- package/lib/esm/api/index.js +1 -1
- package/lib/esm/api/index.js.map +2 -2
- package/lib/esm/api/model/RegisterExternalAddress.js +1 -0
- package/lib/esm/api/model/RegisterExternalAddress.js.map +7 -0
- package/lib/esm/internal/DefaultContactsManager.js +1 -1
- package/lib/esm/internal/DefaultContactsManager.js.map +3 -3
- package/lib/esm/internal/DefaultContactsManager.test.js +2 -0
- package/lib/esm/internal/DefaultContactsManager.test.js.map +7 -0
- package/lib/esm/internal/app-binder/ContactsAppBinder.js +1 -1
- package/lib/esm/internal/app-binder/ContactsAppBinder.js.map +3 -3
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js +2 -0
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js.map +7 -0
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.test.js +2 -0
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.test.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/makeInternalApi.js +2 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/makeInternalApi.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.js +2 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.js +2 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.js +2 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.js.map +7 -0
- package/lib/esm/internal/app-binder/isContactsSupportedForSession.js +1 -1
- package/lib/esm/internal/app-binder/isContactsSupportedForSession.js.map +3 -3
- package/lib/esm/internal/app-binder/isContactsSupportedForSession.test.js +1 -1
- package/lib/esm/internal/app-binder/isContactsSupportedForSession.test.js.map +3 -3
- package/lib/esm/internal/app-binder/model/contactsConstants.js +2 -0
- package/lib/esm/internal/app-binder/model/contactsConstants.js.map +7 -0
- package/lib/esm/internal/app-binder/model/contactsErrors.js +2 -0
- package/lib/esm/internal/app-binder/model/contactsErrors.js.map +7 -0
- package/lib/esm/internal/app-binder/model/contactsValidation.js +2 -0
- package/lib/esm/internal/app-binder/model/contactsValidation.js.map +7 -0
- package/lib/esm/internal/app-binder/model/contactsValidation.test.js +2 -0
- package/lib/esm/internal/app-binder/model/contactsValidation.test.js.map +7 -0
- package/lib/esm/internal/app-binder/services/contactsTlvSerializer.js +2 -0
- package/lib/esm/internal/app-binder/services/contactsTlvSerializer.js.map +7 -0
- package/lib/esm/internal/app-binder/services/contactsTlvSerializer.test.js +2 -0
- package/lib/esm/internal/app-binder/services/contactsTlvSerializer.test.js.map +7 -0
- package/lib/esm/internal/app-binder/services/sendFramedContactsPayload.js +2 -0
- package/lib/esm/internal/app-binder/services/sendFramedContactsPayload.js.map +7 -0
- package/lib/esm/internal/app-binder/services/sendFramedContactsPayload.test.js +2 -0
- package/lib/esm/internal/app-binder/services/sendFramedContactsPayload.test.js.map +7 -0
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.js +2 -0
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.js.map +7 -0
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.test.js +2 -0
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.test.js.map +7 -0
- package/lib/esm/internal/di.js +1 -1
- package/lib/esm/internal/di.js.map +3 -3
- package/lib/esm/internal/di.test.js +1 -1
- package/lib/esm/internal/di.test.js.map +3 -3
- package/lib/esm/internal/use-cases/RegisterExternalAddressUseCase.js +2 -0
- package/lib/esm/internal/use-cases/RegisterExternalAddressUseCase.js.map +7 -0
- package/lib/esm/internal/use-cases/RegisterExternalAddressUseCase.test.js +2 -0
- package/lib/esm/internal/use-cases/RegisterExternalAddressUseCase.test.js.map +7 -0
- package/lib/esm/internal/use-cases/di/useCaseModule.js +2 -0
- package/lib/esm/internal/use-cases/di/useCaseModule.js.map +7 -0
- package/lib/esm/internal/use-cases/di/useCaseTypes.js +2 -0
- package/lib/esm/internal/use-cases/di/useCaseTypes.js.map +7 -0
- package/lib/esm/package.json +2 -1
- package/lib/types/api/ContactsManager.d.ts +11 -5
- package/lib/types/api/ContactsManager.d.ts.map +1 -1
- package/lib/types/api/app-binder/RegisterExternalAddressDeviceActionTypes.d.ts +30 -0
- package/lib/types/api/app-binder/RegisterExternalAddressDeviceActionTypes.d.ts.map +1 -0
- package/lib/types/api/index.d.ts +2 -0
- package/lib/types/api/index.d.ts.map +1 -1
- package/lib/types/api/model/RegisterExternalAddress.d.ts +50 -0
- package/lib/types/api/model/RegisterExternalAddress.d.ts.map +1 -0
- package/lib/types/internal/DefaultContactsManager.d.ts +5 -2
- package/lib/types/internal/DefaultContactsManager.d.ts.map +1 -1
- package/lib/types/internal/DefaultContactsManager.test.d.ts +2 -0
- package/lib/types/internal/DefaultContactsManager.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/ContactsAppBinder.d.ts +4 -3
- package/lib/types/internal/app-binder/ContactsAppBinder.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/RegisterIdentityCommand.d.ts +30 -0
- package/lib/types/internal/app-binder/command/RegisterIdentityCommand.d.ts.map +1 -0
- package/lib/types/internal/app-binder/command/RegisterIdentityCommand.test.d.ts +2 -0
- package/lib/types/internal/app-binder/command/RegisterIdentityCommand.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.d.ts +14 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.d.ts +2 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.d.ts +12 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.d.ts +2 -0
- package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/makeInternalApi.d.ts +4 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/makeInternalApi.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.d.ts +2 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.d.ts +17 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.d.ts +15 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/testDeviceActionStates.d.ts.map +1 -0
- package/lib/types/internal/app-binder/isContactsSupportedForSession.d.ts +16 -8
- package/lib/types/internal/app-binder/isContactsSupportedForSession.d.ts.map +1 -1
- package/lib/types/internal/app-binder/model/contactsConstants.d.ts +24 -0
- package/lib/types/internal/app-binder/model/contactsConstants.d.ts.map +1 -0
- package/lib/types/internal/app-binder/model/contactsErrors.d.ts +30 -0
- package/lib/types/internal/app-binder/model/contactsErrors.d.ts.map +1 -0
- package/lib/types/internal/app-binder/model/contactsValidation.d.ts +53 -0
- package/lib/types/internal/app-binder/model/contactsValidation.d.ts.map +1 -0
- package/lib/types/internal/app-binder/model/contactsValidation.test.d.ts +2 -0
- package/lib/types/internal/app-binder/model/contactsValidation.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/services/contactsTlvSerializer.d.ts +33 -0
- package/lib/types/internal/app-binder/services/contactsTlvSerializer.d.ts.map +1 -0
- package/lib/types/internal/app-binder/services/contactsTlvSerializer.test.d.ts +2 -0
- package/lib/types/internal/app-binder/services/contactsTlvSerializer.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/services/sendFramedContactsPayload.d.ts +14 -0
- package/lib/types/internal/app-binder/services/sendFramedContactsPayload.d.ts.map +1 -0
- package/lib/types/internal/app-binder/services/sendFramedContactsPayload.test.d.ts +2 -0
- package/lib/types/internal/app-binder/services/sendFramedContactsPayload.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/task/SendRegisterIdentityTask.d.ts +25 -0
- package/lib/types/internal/app-binder/task/SendRegisterIdentityTask.d.ts.map +1 -0
- package/lib/types/internal/app-binder/task/SendRegisterIdentityTask.test.d.ts +2 -0
- package/lib/types/internal/app-binder/task/SendRegisterIdentityTask.test.d.ts.map +1 -0
- package/lib/types/internal/di.d.ts.map +1 -1
- package/lib/types/internal/use-cases/RegisterExternalAddressUseCase.d.ts +17 -0
- package/lib/types/internal/use-cases/RegisterExternalAddressUseCase.d.ts.map +1 -0
- package/lib/types/internal/use-cases/RegisterExternalAddressUseCase.test.d.ts +2 -0
- package/lib/types/internal/use-cases/RegisterExternalAddressUseCase.test.d.ts.map +1 -0
- package/lib/types/internal/use-cases/di/useCaseModule.d.ts +3 -0
- package/lib/types/internal/use-cases/di/useCaseModule.d.ts.map +1 -0
- package/lib/types/internal/use-cases/di/useCaseTypes.d.ts +4 -0
- package/lib/types/internal/use-cases/di/useCaseTypes.d.ts.map +1 -0
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +8 -7
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var s=Object.defineProperty;var
|
|
1
|
+
"use strict";var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var u=(n,e)=>{for(var i in e)s(n,i,{get:e[i],enumerable:!0})},d=(n,e,i,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of l(e))!m.call(n,r)&&r!==i&&s(n,r,{get:()=>e[r],enumerable:!(o=f(e,r))||o.enumerable});return n};var v=n=>d(s({},"__esModule",{value:!0}),n);var V={};u(V,{isContactsSupportedForSession:()=>A});module.exports=v(V);var a=require("@ledgerhq/device-management-kit"),t=require("../../api/model/ContactsVersionRequirements"),c=require("./ContactsApplicationResolver");function A(n,e){const i=n.getDeviceSessionState(),o=(0,t.resolveContactsVersionRequirements)(i.deviceModelId);if(!o.supported)return!1;const r=o.minAppVersion[e.name];if(r===void 0||!new a.ApplicationChecker(i,{version:e.version},new c.ContactsApplicationResolver).withMinVersionInclusive(r).check())return!1;const p="firmwareVersion"in i?i.firmwareVersion?.os:void 0;return p===void 0?!1:(0,t.isVersionAtLeast)(p,o.minOsVersion)}0&&(module.exports={isContactsSupportedForSession});
|
|
2
2
|
//# sourceMappingURL=isContactsSupportedForSession.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/internal/app-binder/isContactsSupportedForSession.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,
|
|
6
|
-
"names": ["isContactsSupportedForSession_exports", "__export", "isContactsSupportedForSession", "__toCommonJS", "import_device_management_kit", "import_ContactsVersionRequirements", "import_ContactsApplicationResolver", "internalApi", "
|
|
4
|
+
"sourcesContent": ["import {\n ApplicationChecker,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport { ContactsApplicationResolver } from \"./ContactsApplicationResolver\";\n\n/** The running app's identity, read freshly from the device. */\nexport type RunningApp = {\n readonly name: string;\n readonly version: string;\n};\n\n/**\n * Session-aware Contacts support check, for internal consumption by Contacts\n * `DeviceAction`s. Resolves the given running app against the static\n * requirements table:\n * - the device model must be supported;\n * - the running app must be known to Contacts and meet its minimum version;\n * - the device OS must meet its minimum version (a dimension `ApplicationChecker`\n * does not cover, so it is checked separately here).\n *\n * The app `name` and `version` are supplied by the caller so they can come from\n * a fresh `WaitForAppAndVersion` result rather than the (potentially stale)\n * device session state; the model and OS come from the session state, which\n * does not change under the caller's feet the way the running app can.\n *\n * @param internalApi - the DeviceAction's internal API for the current session.\n * @param app - the running app's fresh name and version.\n */\nexport function isContactsSupportedForSession(\n internalApi: InternalApi,\n app: RunningApp,\n): boolean {\n const deviceState = internalApi.getDeviceSessionState();\n const requirement = resolveContactsVersionRequirements(\n deviceState.deviceModelId,\n );\n if (!requirement.supported) return false;\n\n const minAppVersion = requirement.minAppVersion[app.name];\n if (minAppVersion === undefined) return false;\n\n const appCompatible = new ApplicationChecker(\n deviceState,\n { version: app.version },\n new ContactsApplicationResolver(),\n )\n .withMinVersionInclusive(minAppVersion)\n .check();\n if (!appCompatible) return false;\n\n const osVersion =\n \"firmwareVersion\" in deviceState\n ? deviceState.firmwareVersion?.os\n : undefined;\n if (osVersion === undefined) return false;\n\n return isVersionAtLeast(osVersion, requirement.minOsVersion);\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAGO,2CAEPC,EAGO,kDAEPC,EAA4C,yCAyBrC,SAASJ,EACdK,EACAC,EACS,CACT,MAAMC,EAAcF,EAAY,sBAAsB,EAChDG,KAAc,sCAClBD,EAAY,aACd,EACA,GAAI,CAACC,EAAY,UAAW,MAAO,GAEnC,MAAMC,EAAgBD,EAAY,cAAcF,EAAI,IAAI,EAUxD,GATIG,IAAkB,QASlB,CAPkB,IAAI,qBACxBF,EACA,CAAE,QAASD,EAAI,OAAQ,EACvB,IAAI,6BACN,EACG,wBAAwBG,CAAa,EACrC,MAAM,EACW,MAAO,GAE3B,MAAMC,EACJ,oBAAqBH,EACjBA,EAAY,iBAAiB,GAC7B,OACN,OAAIG,IAAc,OAAkB,MAE7B,oBAAiBA,EAAWF,EAAY,YAAY,CAC7D",
|
|
6
|
+
"names": ["isContactsSupportedForSession_exports", "__export", "isContactsSupportedForSession", "__toCommonJS", "import_device_management_kit", "import_ContactsVersionRequirements", "import_ContactsApplicationResolver", "internalApi", "app", "deviceState", "requirement", "minAppVersion", "osVersion"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var t=require("@ledgerhq/device-management-kit"),
|
|
1
|
+
"use strict";var t=require("@ledgerhq/device-management-kit"),o=require("../../api/model/ContactsVersionRequirements"),n=require("./isContactsSupportedForSession");const c=(()=>{const e=(0,o.resolveContactsVersionRequirements)(t.DeviceModelId.FLEX);if(!e.supported)throw new Error("Flex must be supported");return e})(),u=c.minOsVersion,d=(()=>{const e=c.minAppVersion[o.ETHEREUM_APP_NAME];if(e===void 0)throw new Error("Ethereum min version required");return e})(),a="0.0.1";function r({osVersion:e=u,modelId:p=t.DeviceModelId.FLEX}={}){return{sessionStateType:t.DeviceSessionStateType.ReadyWithoutSecureChannel,deviceStatus:t.DeviceStatus.CONNECTED,installedApps:[],currentApp:{name:o.ETHEREUM_APP_NAME,version:"0.0.0"},deviceModelId:p,firmwareVersion:{mcu:"1.0.0",bootloader:"1.0.0",os:e},isSecureConnectionAllowed:!1}}function s(e){return{getDeviceSessionState:()=>e}}function i(e=o.ETHEREUM_APP_NAME,p=d){return{name:e,version:p}}describe("isContactsSupportedForSession",()=>{it("returns true when model, app version and OS version all meet the minimums",()=>{const e=s(r());expect((0,n.isContactsSupportedForSession)(e,i())).toBe(!0)}),it("returns false on an unsupported device model",()=>{const e=s(r({modelId:t.DeviceModelId.NANO_X}));expect((0,n.isContactsSupportedForSession)(e,i())).toBe(!1)}),it("returns false when the app version is below the minimum",()=>{const e=s(r());expect((0,n.isContactsSupportedForSession)(e,i(o.ETHEREUM_APP_NAME,a))).toBe(!1)}),it("returns false when the running app is unknown to Contacts",()=>{const e=s(r());expect((0,n.isContactsSupportedForSession)(e,i("Bitcoin"))).toBe(!1)}),it("returns false when the OS version is below the minimum",()=>{const e=s(r({osVersion:a}));expect((0,n.isContactsSupportedForSession)(e,i())).toBe(!1)}),it("returns false when the device session has no running app",()=>{const e=s({sessionStateType:t.DeviceSessionStateType.Connected,deviceStatus:t.DeviceStatus.CONNECTED,deviceModelId:t.DeviceModelId.FLEX});expect((0,n.isContactsSupportedForSession)(e,i())).toBe(!1)})});
|
|
2
2
|
//# sourceMappingURL=isContactsSupportedForSession.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/internal/app-binder/isContactsSupportedForSession.test.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n
|
|
5
|
-
"mappings": "aAAA,IAAAA,
|
|
6
|
-
"names": ["import_device_management_kit", "import_ContactsVersionRequirements", "import_isContactsSupportedForSession", "flexSupport", "requirement", "MIN_OS_VERSION", "MIN_APP_VERSION", "version", "BELOW_ANY_VERSION", "createReadyState", "
|
|
4
|
+
"sourcesContent": ["import {\n DeviceModelId,\n DeviceSessionStateType,\n DeviceStatus,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n ETHEREUM_APP_NAME,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport {\n isContactsSupportedForSession,\n type RunningApp,\n} from \"./isContactsSupportedForSession\";\n\nconst flexSupport = (() => {\n const requirement = resolveContactsVersionRequirements(DeviceModelId.FLEX);\n if (!requirement.supported) throw new Error(\"Flex must be supported\");\n return requirement;\n})();\n\nconst MIN_OS_VERSION = flexSupport.minOsVersion;\nconst MIN_APP_VERSION = (() => {\n const version = flexSupport.minAppVersion[ETHEREUM_APP_NAME];\n if (version === undefined) throw new Error(\"Ethereum min version required\");\n return version;\n})();\nconst BELOW_ANY_VERSION = \"0.0.1\";\n\ntype ReadyStateOptions = {\n osVersion?: string;\n modelId?: DeviceModelId;\n};\n\nfunction createReadyState({\n osVersion = MIN_OS_VERSION,\n modelId = DeviceModelId.FLEX,\n}: ReadyStateOptions = {}) {\n return {\n sessionStateType: DeviceSessionStateType.ReadyWithoutSecureChannel,\n deviceStatus: DeviceStatus.CONNECTED,\n installedApps: [],\n currentApp: { name: ETHEREUM_APP_NAME, version: \"0.0.0\" },\n deviceModelId: modelId,\n firmwareVersion: { mcu: \"1.0.0\", bootloader: \"1.0.0\", os: osVersion },\n isSecureConnectionAllowed: false,\n };\n}\n\nfunction createInternalApi(deviceState: object): InternalApi {\n return {\n getDeviceSessionState: () => deviceState,\n } as unknown as InternalApi;\n}\n\n// The running app identity now comes from the caller (a fresh\n// WaitForAppAndVersion result), not the device session state.\nfunction runningApp(\n name = ETHEREUM_APP_NAME,\n version = MIN_APP_VERSION,\n): RunningApp {\n return { name, version };\n}\n\ndescribe(\"isContactsSupportedForSession\", () => {\n it(\"returns true when model, app version and OS version all meet the minimums\", () => {\n const api = createInternalApi(createReadyState());\n expect(isContactsSupportedForSession(api, runningApp())).toBe(true);\n });\n\n it(\"returns false on an unsupported device model\", () => {\n const api = createInternalApi(\n createReadyState({ modelId: DeviceModelId.NANO_X }),\n );\n expect(isContactsSupportedForSession(api, runningApp())).toBe(false);\n });\n\n // App-version requirement (evaluated from the fresh app version).\n it(\"returns false when the app version is below the minimum\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsSupportedForSession(\n api,\n runningApp(ETHEREUM_APP_NAME, BELOW_ANY_VERSION),\n ),\n ).toBe(false);\n });\n\n it(\"returns false when the running app is unknown to Contacts\", () => {\n const api = createInternalApi(createReadyState());\n expect(isContactsSupportedForSession(api, runningApp(\"Bitcoin\"))).toBe(\n false,\n );\n });\n\n // OS-version requirement.\n it(\"returns false when the OS version is below the minimum\", () => {\n const api = createInternalApi(\n createReadyState({ osVersion: BELOW_ANY_VERSION }),\n );\n expect(isContactsSupportedForSession(api, runningApp())).toBe(false);\n });\n\n it(\"returns false when the device session has no running app\", () => {\n const api = createInternalApi({\n sessionStateType: DeviceSessionStateType.Connected,\n deviceStatus: DeviceStatus.CONNECTED,\n deviceModelId: DeviceModelId.FLEX,\n });\n expect(isContactsSupportedForSession(api, runningApp())).toBe(false);\n });\n});\n"],
|
|
5
|
+
"mappings": "aAAA,IAAAA,EAKO,2CAEPC,EAGO,kDAEPC,EAGO,2CAEP,MAAMC,GAAe,IAAM,CACzB,MAAMC,KAAc,sCAAmC,gBAAc,IAAI,EACzE,GAAI,CAACA,EAAY,UAAW,MAAM,IAAI,MAAM,wBAAwB,EACpE,OAAOA,CACT,GAAG,EAEGC,EAAiBF,EAAY,aAC7BG,GAAmB,IAAM,CAC7B,MAAMC,EAAUJ,EAAY,cAAc,mBAAiB,EAC3D,GAAII,IAAY,OAAW,MAAM,IAAI,MAAM,+BAA+B,EAC1E,OAAOA,CACT,GAAG,EACGC,EAAoB,QAO1B,SAASC,EAAiB,CACxB,UAAAC,EAAYL,EACZ,QAAAM,EAAU,gBAAc,IAC1B,EAAuB,CAAC,EAAG,CACzB,MAAO,CACL,iBAAkB,yBAAuB,0BACzC,aAAc,eAAa,UAC3B,cAAe,CAAC,EAChB,WAAY,CAAE,KAAM,oBAAmB,QAAS,OAAQ,EACxD,cAAeA,EACf,gBAAiB,CAAE,IAAK,QAAS,WAAY,QAAS,GAAID,CAAU,EACpE,0BAA2B,EAC7B,CACF,CAEA,SAASE,EAAkBC,EAAkC,CAC3D,MAAO,CACL,sBAAuB,IAAMA,CAC/B,CACF,CAIA,SAASC,EACPC,EAAO,oBACPR,EAAUD,EACE,CACZ,MAAO,CAAE,KAAAS,EAAM,QAAAR,CAAQ,CACzB,CAEA,SAAS,gCAAiC,IAAM,CAC9C,GAAG,4EAA6E,IAAM,CACpF,MAAMS,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UAAO,iCAA8BO,EAAKF,EAAW,CAAC,CAAC,EAAE,KAAK,EAAI,CACpE,CAAC,EAED,GAAG,+CAAgD,IAAM,CACvD,MAAME,EAAMJ,EACVH,EAAiB,CAAE,QAAS,gBAAc,MAAO,CAAC,CACpD,EACA,UAAO,iCAA8BO,EAAKF,EAAW,CAAC,CAAC,EAAE,KAAK,EAAK,CACrE,CAAC,EAGD,GAAG,0DAA2D,IAAM,CAClE,MAAME,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UACE,iCACEO,EACAF,EAAW,oBAAmBN,CAAiB,CACjD,CACF,EAAE,KAAK,EAAK,CACd,CAAC,EAED,GAAG,4DAA6D,IAAM,CACpE,MAAMQ,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UAAO,iCAA8BO,EAAKF,EAAW,SAAS,CAAC,CAAC,EAAE,KAChE,EACF,CACF,CAAC,EAGD,GAAG,yDAA0D,IAAM,CACjE,MAAME,EAAMJ,EACVH,EAAiB,CAAE,UAAWD,CAAkB,CAAC,CACnD,EACA,UAAO,iCAA8BQ,EAAKF,EAAW,CAAC,CAAC,EAAE,KAAK,EAAK,CACrE,CAAC,EAED,GAAG,2DAA4D,IAAM,CACnE,MAAME,EAAMJ,EAAkB,CAC5B,iBAAkB,yBAAuB,UACzC,aAAc,eAAa,UAC3B,cAAe,gBAAc,IAC/B,CAAC,EACD,UAAO,iCAA8BI,EAAKF,EAAW,CAAC,CAAC,EAAE,KAAK,EAAK,CACrE,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["import_device_management_kit", "import_ContactsVersionRequirements", "import_isContactsSupportedForSession", "flexSupport", "requirement", "MIN_OS_VERSION", "MIN_APP_VERSION", "version", "BELOW_ANY_VERSION", "createReadyState", "osVersion", "modelId", "createInternalApi", "deviceState", "runningApp", "name", "api"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var s=Object.prototype.hasOwnProperty;var A=(t,o)=>{for(var _ in o)e(t,_,{get:o[_],enumerable:!0})},T=(t,o,_,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let x of c(o))!s.call(t,x)&&x!==_&&e(t,x,{get:()=>o[x],enumerable:!(n=r(o,x))||n.enumerable});return t};var C=t=>T(e({},"__esModule",{value:!0}),t);var I={};A(I,{BLOCKCHAIN_FAMILY_BY_NAME:()=>B,CONTACTS_APDU_CLA:()=>E,CONTACTS_APDU_INS:()=>S,GROUP_HANDLE_BYTES:()=>N,HMAC_PROOF_BYTES:()=>R,HMAC_REST_BYTES:()=>a,SUB_CMD_REGISTER_IDENTITY:()=>p});module.exports=C(I);const E=176,S=16,p=1,N=64,R=32,a=32,B={bitcoin:0,ethereum:1,solana:2,polkadot:3,cosmos:4,cardano:5};0&&(module.exports={BLOCKCHAIN_FAMILY_BY_NAME,CONTACTS_APDU_CLA,CONTACTS_APDU_INS,GROUP_HANDLE_BYTES,HMAC_PROOF_BYTES,HMAC_REST_BYTES,SUB_CMD_REGISTER_IDENTITY});
|
|
2
|
+
//# sourceMappingURL=contactsConstants.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/model/contactsConstants.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Protocol constants shared by the Contacts (Address Book) operations.\n *\n * Wire format and values follow the BOLOS SDK Address Book specification\n * (ledger-secure-sdk/app_features/address_book). Op-specific sub-command bytes\n * and response field sizes live here; TLV tags and struct-type bytes live in\n * {@link ./../services/contactsTlvSerializer}.\n */\n\n/** APDU class/instruction shared by every Address Book sub-command. */\nexport const CONTACTS_APDU_CLA = 0xb0;\nexport const CONTACTS_APDU_INS = 0x10;\n\n/** P1 sub-command selector for REGISTER IDENTITY (register external address). */\nexport const SUB_CMD_REGISTER_IDENTITY = 0x01;\n\n/** Sizes (bytes) of the fields in the REGISTER IDENTITY final-chunk response. */\nexport const GROUP_HANDLE_BYTES = 64;\nexport const HMAC_PROOF_BYTES = 32;\nexport const HMAC_REST_BYTES = 32;\n\n/**\n * Blockchain-family byte encoded in the `BLOCKCHAIN_FAMILY` TLV, keyed by a\n * lowercase family name. v1 ships Ethereum only; the remaining families are\n * listed for completeness and will be enabled as their chains are supported.\n */\nexport const BLOCKCHAIN_FAMILY_BY_NAME: Readonly<Record<string, number>> = {\n bitcoin: 0x00,\n ethereum: 0x01,\n solana: 0x02,\n polkadot: 0x03,\n cosmos: 0x04,\n cardano: 0x05,\n};\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,+BAAAE,EAAA,sBAAAC,EAAA,sBAAAC,EAAA,uBAAAC,EAAA,qBAAAC,EAAA,oBAAAC,EAAA,8BAAAC,IAAA,eAAAC,EAAAT,GAUO,MAAMG,EAAoB,IACpBC,EAAoB,GAGpBI,EAA4B,EAG5BH,EAAqB,GACrBC,EAAmB,GACnBC,EAAkB,GAOlBL,EAA8D,CACzE,QAAS,EACT,SAAU,EACV,OAAQ,EACR,SAAU,EACV,OAAQ,EACR,QAAS,CACX",
|
|
6
|
+
"names": ["contactsConstants_exports", "__export", "BLOCKCHAIN_FAMILY_BY_NAME", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "SUB_CMD_REGISTER_IDENTITY", "__toCommonJS"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var p=(r,e)=>{for(var t in e)s(r,t,{get:e[t],enumerable:!0})},g=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of i(e))!C.call(r,o)&&o!==t&&s(r,o,{get:()=>e[o],enumerable:!(a=m(e,o))||a.enumerable});return r};var E=r=>g(s({},"__esModule",{value:!0}),r);var u={};p(u,{CONTACTS_APP_ERRORS:()=>l,CONTACT_SEED_MISMATCH_ERROR_CODE:()=>d,ContactsCommandError:()=>c,ContactsVersionRequirementError:()=>h,contactsCommandErrorFactory:()=>f});module.exports=E(u);var n=require("@ledgerhq/device-management-kit");const d="6982",l={[d]:{message:"This address-book entry was registered with a different seed. Connect the Ledger device that registered it to modify this contact."},6800:{message:"Internal error (Please report)"},6983:{message:"Wrong data length"},6984:{message:"Unsupported address-book operation for this device or app configuration"},6985:{message:"Condition not satisfied"},"6a80":{message:"Invalid contact data, or operation refused on device"},"6a84":{message:"Insufficient memory: the device address book is full"},"6a88":{message:"Contact data not found"},"6af0":{message:"Invalid value for this contact entry"},"6b00":{message:"The app rejected the contact data"},"6f00":{message:"Technical problem (Internal error, please report)"}};class c extends n.DeviceExchangeError{constructor(e){super({tag:"ContactsCommandError",...e})}}const f=r=>new c(r);class h{constructor(e="The connected device or app does not meet the Contacts version requirements."){this.message=e}_tag="ContactsVersionRequirementError";originalError}0&&(module.exports={CONTACTS_APP_ERRORS,CONTACT_SEED_MISMATCH_ERROR_CODE,ContactsCommandError,ContactsVersionRequirementError,contactsCommandErrorFactory});
|
|
2
|
+
//# sourceMappingURL=contactsErrors.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/model/contactsErrors.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n type CommandErrorArgs,\n type CommandErrors,\n DeviceExchangeError,\n type DmkError,\n} from \"@ledgerhq/device-management-kit\";\n\n/**\n * Status word returned by the app's Address Book *edit* operations when the\n * seed-bound HMAC / group-handle verification fails \u2014 i.e. the entry was\n * registered with a different seed than the one currently on the device.\n *\n * The device runs this check *before* showing any UI and returns 0x6982 *only*\n * for seed-binding failures (user rejection and TLV errors return 0x6a80,\n * address validation returns 0x6af0), so 0x6982 is an unambiguous \"wrong seed\"\n * signal that consumers (e.g. Ledger Wallet) can catch to guide the user.\n */\nexport const CONTACT_SEED_MISMATCH_ERROR_CODE = \"6982\" as const;\n\nexport type ContactsErrorCodes =\n | \"6982\"\n | \"6800\"\n | \"6983\"\n | \"6984\"\n | \"6985\"\n | \"6a80\"\n | \"6a84\"\n | \"6a88\"\n | \"6af0\"\n | \"6b00\"\n | \"6f00\";\n\nexport const CONTACTS_APP_ERRORS: CommandErrors<ContactsErrorCodes> = {\n [CONTACT_SEED_MISMATCH_ERROR_CODE]: {\n message:\n \"This address-book entry was registered with a different seed. Connect the Ledger device that registered it to modify this contact.\",\n },\n \"6800\": { message: \"Internal error (Please report)\" },\n \"6983\": { message: \"Wrong data length\" },\n \"6984\": {\n message:\n \"Unsupported address-book operation for this device or app configuration\",\n },\n \"6985\": { message: \"Condition not satisfied\" },\n \"6a80\": { message: \"Invalid contact data, or operation refused on device\" },\n \"6a84\": { message: \"Insufficient memory: the device address book is full\" },\n \"6a88\": { message: \"Contact data not found\" },\n \"6af0\": { message: \"Invalid value for this contact entry\" },\n \"6b00\": { message: \"The app rejected the contact data\" },\n \"6f00\": { message: \"Technical problem (Internal error, please report)\" },\n};\n\nexport class ContactsCommandError extends DeviceExchangeError<ContactsErrorCodes> {\n constructor(args: CommandErrorArgs<ContactsErrorCodes>) {\n super({ tag: \"ContactsCommandError\", ...args });\n }\n}\n\nexport const contactsCommandErrorFactory = (\n args: CommandErrorArgs<ContactsErrorCodes>,\n) => new ContactsCommandError(args);\n\n/**\n * Raised by a Contacts `DeviceAction` when the connected device model, app\n * version, or OS version does not meet the Contacts requirements \u2014 i.e. the\n * DSDK-1376 support check fails before any APDU is sent.\n */\nexport class ContactsVersionRequirementError implements DmkError {\n readonly _tag = \"ContactsVersionRequirementError\";\n readonly originalError?: unknown;\n constructor(\n readonly message = \"The connected device or app does not meet the Contacts version requirements.\",\n ) {}\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,EAAA,qCAAAC,EAAA,yBAAAC,EAAA,oCAAAC,EAAA,gCAAAC,IAAA,eAAAC,EAAAP,GAAA,IAAAQ,EAKO,2CAYA,MAAML,EAAmC,OAenCD,EAAyD,CACpE,CAACC,CAAgC,EAAG,CAClC,QACE,oIACJ,EACA,KAAQ,CAAE,QAAS,gCAAiC,EACpD,KAAQ,CAAE,QAAS,mBAAoB,EACvC,KAAQ,CACN,QACE,yEACJ,EACA,KAAQ,CAAE,QAAS,yBAA0B,EAC7C,OAAQ,CAAE,QAAS,sDAAuD,EAC1E,OAAQ,CAAE,QAAS,sDAAuD,EAC1E,OAAQ,CAAE,QAAS,wBAAyB,EAC5C,OAAQ,CAAE,QAAS,sCAAuC,EAC1D,OAAQ,CAAE,QAAS,mCAAoC,EACvD,OAAQ,CAAE,QAAS,mDAAoD,CACzE,EAEO,MAAMC,UAA6B,qBAAwC,CAChF,YAAYK,EAA4C,CACtD,MAAM,CAAE,IAAK,uBAAwB,GAAGA,CAAK,CAAC,CAChD,CACF,CAEO,MAAMH,EACXG,GACG,IAAIL,EAAqBK,CAAI,EAO3B,MAAMJ,CAAoD,CAG/D,YACWK,EAAU,+EACnB,CADS,aAAAA,CACR,CAJM,KAAO,kCACP,aAIX",
|
|
6
|
+
"names": ["contactsErrors_exports", "__export", "CONTACTS_APP_ERRORS", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "ContactsVersionRequirementError", "contactsCommandErrorFactory", "__toCommonJS", "import_device_management_kit", "args", "message"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var d=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var b=(t,e)=>{for(var o in e)d(t,o,{get:e[o],enumerable:!0})},x=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of y(e))!w.call(t,n)&&n!==o&&d(t,n,{get:()=>e[n],enumerable:!(i=p(e,n))||i.enumerable});return t};var l=t=>x(d({},"__esModule",{value:!0}),t);var L={};b(L,{CONTACT_NAME_BUFFER_LENGTH:()=>$,ContactsValidationError:()=>r,ETH_ADDRESS_BYTES:()=>I,GROUP_HANDLE_SIZE:()=>N,HMAC_PROOF_LENGTH:()=>u,MAX_BIP32_DEPTH:()=>h,SCOPE_BUFFER_LENGTH:()=>E,validateByteLength:()=>T,validateChainId:()=>O,validateDerivationPath:()=>A,validatePrintableLabel:()=>P});module.exports=l(L);const $=33,E=33,N=64,u=32,h=10,I=20;class r extends Error{_tag="ContactsValidationError";originalError;constructor(e){super(e),this.name="ContactsValidationError"}}const S=32,_=126,B=new TextEncoder;function P(t,e){const{field:o,bufferLength:i}=e;if(!t)throw new r(`${o} must not be empty (firmware rejects empty strings).`);const n=B.encode(t),s=i-1;if(n.length>s)throw new r(`${o} ${JSON.stringify(t)} is too long: ${n.length} bytes encoded (max ${s}). The device buffer is ${i} bytes including the trailing NUL.`);const f=[];for(let c=0;c<n.length;c++){const a=n[c];(a<S||a>_)&&f.push(c)}if(f.length>0){const a=Array.from(new Set(f.map(g=>n[g]))).sort((g,m)=>g-m).map(g=>`0x${g.toString(16).padStart(2,"0")}`).join(", ");throw new r(`${o} ${JSON.stringify(t)} contains ${f.length} non-ASCII byte(s) at position(s) [${f.join(", ")}]: ${a}. The device buffer is byte-level isprint() \u2014 only 0x20-0x7E are accepted, no UTF-8 / accents / emoji.`)}}function T(t,e){const{field:o,expectedBytes:i}=e;if(t.length!==i)throw new r(`${o} is ${t.length} bytes, expected ${i}.`)}function A(t){if(!t)throw new r(`derivationPath must not be empty (e.g. "m/44'/60'/0'/0/0").`);const e=t.split("/"),o=e[0]==="m"||e[0]==="M"?e.slice(1):e;if(o.length===0)throw new r(`derivationPath ${JSON.stringify(t)} has no segments past 'm'.`);if(o.length>h)throw new r(`derivationPath ${JSON.stringify(t)} has ${o.length} segments (max ${h}). Firmware rejects deeper paths.`);for(const i of o){const n=i.endsWith("'")?i.slice(0,-1):i;if(!n||!/^\d+$/.test(n))throw new r(`derivationPath ${JSON.stringify(t)} segment ${JSON.stringify(i)} is not numeric. Use plain integers, optionally suffixed with ' for hardened.`);const s=Number(n);if(!Number.isSafeInteger(s)||s>=2147483648)throw new r(`derivationPath ${JSON.stringify(t)} segment ${JSON.stringify(i)} >= 2^31. Use the ' suffix for hardening rather than overflowing.`)}}function O(t){const e=typeof t=="number";if(!e&&!(typeof t=="bigint"))throw new r(`chainId must be number or bigint, got ${typeof t}.`);if(e&&!Number.isInteger(t))throw new r(`chainId must be an integer, got ${t}.`);const i=typeof t=="bigint"?t:BigInt(t);if(i<=0n)throw new r(`chainId must be positive, got ${t}.`);const n=(1n<<64n)-1n;if(i>n)throw new r(`chainId ${t} exceeds uint64 range (max ${n}).`)}0&&(module.exports={CONTACT_NAME_BUFFER_LENGTH,ContactsValidationError,ETH_ADDRESS_BYTES,GROUP_HANDLE_SIZE,HMAC_PROOF_LENGTH,MAX_BIP32_DEPTH,SCOPE_BUFFER_LENGTH,validateByteLength,validateChainId,validateDerivationPath,validatePrintableLabel});
|
|
2
|
+
//# sourceMappingURL=contactsValidation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/model/contactsValidation.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Pre-APDU input validators for the Contacts operations.\n *\n * Buffer-length constants mirror the Ledger secure SDK `#define` values\n * *including* the trailing NUL terminator (so a 32-printable-char name lives in\n * a 33-byte buffer). Validators subtract 1 internally so the constants remain\n * pure equality checks against the upstream `#define`s. The byte-level\n * `0x20..0x7E` printable check exactly matches firmware `is_printable_string`.\n */\nimport { type DmkError } from \"@ledgerhq/device-management-kit\";\n\n// ---- SDK-mirrored constants -------------------------------------------------\n// Source of truth: ledger-secure-sdk/app_features/address_book/include/\n\nexport const CONTACT_NAME_BUFFER_LENGTH = 33; // identity.h:49 (incl. NUL)\nexport const SCOPE_BUFFER_LENGTH = 33; // identity.h:50 (incl. NUL)\nexport const GROUP_HANDLE_SIZE = 64; // identity.h:47\nexport const HMAC_PROOF_LENGTH = 32; // CX_SHA256_SIZE\nexport const MAX_BIP32_DEPTH = 10; // bip32.h:15 (MAX_BIP32_PATH)\nexport const ETH_ADDRESS_BYTES = 20; // protocol convention, no header\n\n// ---- error type -------------------------------------------------------------\n\n/**\n * Raised when caller input fails a pre-APDU check. Implements `DmkError` (and\n * stays an `Error` subclass) so a Contacts device action can surface it as a\n * typed terminal error state on the observable rather than throwing out of the\n * public, device-action-returning API.\n */\nexport class ContactsValidationError extends Error implements DmkError {\n readonly _tag = \"ContactsValidationError\";\n readonly originalError?: unknown;\n constructor(message: string) {\n super(message);\n this.name = \"ContactsValidationError\";\n }\n}\n\n// ---- printable-string validation -------------------------------------------\n\nconst PRINTABLE_MIN = 0x20;\nconst PRINTABLE_MAX = 0x7e;\n\nconst utf8Encoder = new TextEncoder();\n\n/**\n * Mirror of firmware `is_printable_string` + length cap. `bufferLength` is the\n * firmware's fixed buffer size *including* the trailing NUL, so the maximum\n * payload byte length is `bufferLength - 1`.\n */\nexport function validatePrintableLabel(\n value: string,\n options: { field: string; bufferLength: number },\n): void {\n const { field, bufferLength } = options;\n if (!value) {\n throw new ContactsValidationError(\n `${field} must not be empty (firmware rejects empty strings).`,\n );\n }\n const encoded = utf8Encoder.encode(value);\n const maxBytes = bufferLength - 1;\n if (encoded.length > maxBytes) {\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} is too long: ${encoded.length} bytes ` +\n `encoded (max ${maxBytes}). The device buffer is ${bufferLength} bytes ` +\n `including the trailing NUL.`,\n );\n }\n const badPositions: number[] = [];\n for (let i = 0; i < encoded.length; i++) {\n const byte = encoded[i]!;\n if (byte < PRINTABLE_MIN || byte > PRINTABLE_MAX) {\n badPositions.push(i);\n }\n }\n if (badPositions.length > 0) {\n const offendingBytes = Array.from(\n new Set(badPositions.map((i) => encoded[i]!)),\n ).sort((a, b) => a - b);\n const offendingHex = offendingBytes\n .map((b) => `0x${b.toString(16).padStart(2, \"0\")}`)\n .join(\", \");\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} contains ${badPositions.length} ` +\n `non-ASCII byte(s) at position(s) [${badPositions.join(\", \")}]: ` +\n `${offendingHex}. The device buffer is byte-level isprint() \u2014 only ` +\n `0x20-0x7E are accepted, no UTF-8 / accents / emoji.`,\n );\n }\n}\n\n// ---- byte-buffer validation ------------------------------------------------\n\n/** Assert a byte buffer is exactly `expectedBytes` long and non-empty. */\nexport function validateByteLength(\n value: Uint8Array,\n options: { field: string; expectedBytes: number },\n): void {\n const { field, expectedBytes } = options;\n if (value.length !== expectedBytes) {\n throw new ContactsValidationError(\n `${field} is ${value.length} bytes, expected ${expectedBytes}.`,\n );\n }\n}\n\n// ---- BIP32 path validation -------------------------------------------------\n\n/**\n * Sanity-check a BIP32 path before serialization. Firmware enforces depth <=\n * MAX_BIP32_DEPTH and rejects malformed segments. Accepts `m/44'/60'/0'/0/0`\n * style; segments may end in `'` (hardened).\n */\nexport function validateDerivationPath(path: string): void {\n if (!path) {\n throw new ContactsValidationError(\n `derivationPath must not be empty (e.g. \"m/44'/60'/0'/0/0\").`,\n );\n }\n const parts = path.split(\"/\");\n const segments =\n parts[0] === \"m\" || parts[0] === \"M\" ? parts.slice(1) : parts;\n if (segments.length === 0) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has no segments past 'm'.`,\n );\n }\n if (segments.length > MAX_BIP32_DEPTH) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has ${segments.length} segments ` +\n `(max ${MAX_BIP32_DEPTH}). Firmware rejects deeper paths.`,\n );\n }\n for (const segment of segments) {\n const token = segment.endsWith(\"'\") ? segment.slice(0, -1) : segment;\n if (!token || !/^\\d+$/.test(token)) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `is not numeric. Use plain integers, optionally suffixed with ' for hardened.`,\n );\n }\n const n = Number(token);\n if (!Number.isSafeInteger(n) || n >= 0x80000000) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `>= 2^31. Use the ' suffix for hardening rather than overflowing.`,\n );\n }\n }\n}\n\n// ---- chain id validation ---------------------------------------------------\n\n/**\n * Firmware encodes chain_id as uint64. JS `number` is fine up to 2^53; accept\n * `bigint` for the high range so callers don't silently truncate.\n */\nexport function validateChainId(value: number | bigint): void {\n const isNumber = typeof value === \"number\";\n const isBigInt = typeof value === \"bigint\";\n if (!isNumber && !isBigInt) {\n throw new ContactsValidationError(\n `chainId must be number or bigint, got ${typeof value}.`,\n );\n }\n if (isNumber && !Number.isInteger(value)) {\n throw new ContactsValidationError(\n `chainId must be an integer, got ${value}.`,\n );\n }\n const v = typeof value === \"bigint\" ? value : BigInt(value);\n if (v <= 0n) {\n throw new ContactsValidationError(\n `chainId must be positive, got ${value}.`,\n );\n }\n const UINT64_MAX = (1n << 64n) - 1n;\n if (v > UINT64_MAX) {\n throw new ContactsValidationError(\n `chainId ${value} exceeds uint64 range (max ${UINT64_MAX}).`,\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["contactsValidation_exports", "__export", "CONTACT_NAME_BUFFER_LENGTH", "ContactsValidationError", "ETH_ADDRESS_BYTES", "GROUP_HANDLE_SIZE", "HMAC_PROOF_LENGTH", "MAX_BIP32_DEPTH", "SCOPE_BUFFER_LENGTH", "validateByteLength", "validateChainId", "validateDerivationPath", "validatePrintableLabel", "__toCommonJS", "message", "PRINTABLE_MIN", "PRINTABLE_MAX", "utf8Encoder", "value", "options", "field", "bufferLength", "encoded", "maxBytes", "badPositions", "i", "byte", "offendingHex", "a", "b", "expectedBytes", "path", "parts", "segments", "segment", "token", "n", "isNumber", "v", "UINT64_MAX"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("./contactsValidation");const i="44'/60'/0'/0/0";describe("contactsValidation",()=>{describe("validatePrintableLabel",()=>{const t={field:"name",bufferLength:e.CONTACT_NAME_BUFFER_LENGTH};it("accepts a printable ASCII label within the buffer",()=>{expect(()=>(0,e.validatePrintableLabel)("Alice",t)).not.toThrow()}),it("rejects an empty label",()=>{expect(()=>(0,e.validatePrintableLabel)("",t)).toThrow(e.ContactsValidationError)}),it("rejects a label exceeding bufferLength - 1 bytes",()=>{expect(()=>(0,e.validatePrintableLabel)("x".repeat(e.CONTACT_NAME_BUFFER_LENGTH),t)).toThrow(e.ContactsValidationError)}),it("rejects non-ASCII / accented characters (byte-level isprint)",()=>{expect(()=>(0,e.validatePrintableLabel)("Am\xE9lie",t)).toThrow(e.ContactsValidationError)})}),describe("validateByteLength",()=>{it("accepts an exact-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(20),{field:"identifier",expectedBytes:20})).not.toThrow()}),it("rejects a wrong-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(19),{field:"identifier",expectedBytes:20})).toThrow(e.ContactsValidationError)})}),describe("validateChainId",()=>{it("accepts a positive integer and bigint",()=>{expect(()=>(0,e.validateChainId)(1)).not.toThrow(),expect(()=>(0,e.validateChainId)(56n)).not.toThrow()}),it("rejects zero, negative, and non-integer",()=>{expect(()=>(0,e.validateChainId)(0)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(-1)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(1.5)).toThrow(e.ContactsValidationError)})}),describe("validateDerivationPath",()=>{it("accepts a representative BIP32 path",()=>{expect(()=>(0,e.validateDerivationPath)(i)).not.toThrow()}),it("accepts m-prefixed and hardened paths",()=>{expect(()=>(0,e.validateDerivationPath)("m/44'/60'/0'/0/0")).not.toThrow()}),it("rejects a non-numeric segment",()=>{expect(()=>(0,e.validateDerivationPath)("44'/x/0")).toThrow(e.ContactsValidationError)})})});
|
|
2
|
+
//# sourceMappingURL=contactsValidation.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/model/contactsValidation.test.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n validateByteLength,\n validateChainId,\n validateDerivationPath,\n validatePrintableLabel,\n} from \"./contactsValidation\";\n\n// A representative BIP32 path (used by Ledger-Account ops, not external\n// addresses). Kept here to exercise the shared validator.\nconst SAMPLE_DERIVATION_PATH = \"44'/60'/0'/0/0\";\n\ndescribe(\"contactsValidation\", () => {\n describe(\"validatePrintableLabel\", () => {\n const opts = { field: \"name\", bufferLength: CONTACT_NAME_BUFFER_LENGTH };\n\n it(\"accepts a printable ASCII label within the buffer\", () => {\n expect(() => validatePrintableLabel(\"Alice\", opts)).not.toThrow();\n });\n\n it(\"rejects an empty label\", () => {\n expect(() => validatePrintableLabel(\"\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n\n it(\"rejects a label exceeding bufferLength - 1 bytes\", () => {\n expect(() =>\n validatePrintableLabel(\"x\".repeat(CONTACT_NAME_BUFFER_LENGTH), opts),\n ).toThrow(ContactsValidationError);\n });\n\n it(\"rejects non-ASCII / accented characters (byte-level isprint)\", () => {\n expect(() => validatePrintableLabel(\"Am\u00E9lie\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n });\n\n describe(\"validateByteLength\", () => {\n it(\"accepts an exact-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(20), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).not.toThrow();\n });\n\n it(\"rejects a wrong-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(19), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateChainId\", () => {\n it(\"accepts a positive integer and bigint\", () => {\n expect(() => validateChainId(1)).not.toThrow();\n expect(() => validateChainId(56n)).not.toThrow();\n });\n\n it(\"rejects zero, negative, and non-integer\", () => {\n expect(() => validateChainId(0)).toThrow(ContactsValidationError);\n expect(() => validateChainId(-1)).toThrow(ContactsValidationError);\n expect(() => validateChainId(1.5)).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateDerivationPath\", () => {\n it(\"accepts a representative BIP32 path\", () => {\n expect(() =>\n validateDerivationPath(SAMPLE_DERIVATION_PATH),\n ).not.toThrow();\n });\n\n it(\"accepts m-prefixed and hardened paths\", () => {\n expect(() => validateDerivationPath(\"m/44'/60'/0'/0/0\")).not.toThrow();\n });\n\n it(\"rejects a non-numeric segment\", () => {\n expect(() => validateDerivationPath(\"44'/x/0\")).toThrow(\n ContactsValidationError,\n );\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "aAAA,IAAAA,EAOO,gCAIP,MAAMC,EAAyB,iBAE/B,SAAS,qBAAsB,IAAM,CACnC,SAAS,yBAA0B,IAAM,CACvC,MAAMC,EAAO,CAAE,MAAO,OAAQ,aAAc,4BAA2B,EAEvE,GAAG,oDAAqD,IAAM,CAC5D,OAAO,OAAM,0BAAuB,QAASA,CAAI,CAAC,EAAE,IAAI,QAAQ,CAClE,CAAC,EAED,GAAG,yBAA0B,IAAM,CACjC,OAAO,OAAM,0BAAuB,GAAIA,CAAI,CAAC,EAAE,QAC7C,yBACF,CACF,CAAC,EAED,GAAG,mDAAoD,IAAM,CAC3D,OAAO,OACL,0BAAuB,IAAI,OAAO,4BAA0B,EAAGA,CAAI,CACrE,EAAE,QAAQ,yBAAuB,CACnC,CAAC,EAED,GAAG,+DAAgE,IAAM,CACvE,OAAO,OAAM,0BAAuB,YAAUA,CAAI,CAAC,EAAE,QACnD,yBACF,CACF,CAAC,CACH,CAAC,EAED,SAAS,qBAAsB,IAAM,CACnC,GAAG,iCAAkC,IAAM,CACzC,OAAO,OACL,sBAAmB,IAAI,WAAW,EAAE,EAAG,CACrC,MAAO,aACP,cAAe,EACjB,CAAC,CACH,EAAE,IAAI,QAAQ,CAChB,CAAC,EAED,GAAG,gCAAiC,IAAM,CACxC,OAAO,OACL,sBAAmB,IAAI,WAAW,EAAE,EAAG,CACrC,MAAO,aACP,cAAe,EACjB,CAAC,CACH,EAAE,QAAQ,yBAAuB,CACnC,CAAC,CACH,CAAC,EAED,SAAS,kBAAmB,IAAM,CAChC,GAAG,wCAAyC,IAAM,CAChD,OAAO,OAAM,mBAAgB,CAAC,CAAC,EAAE,IAAI,QAAQ,EAC7C,OAAO,OAAM,mBAAgB,GAAG,CAAC,EAAE,IAAI,QAAQ,CACjD,CAAC,EAED,GAAG,0CAA2C,IAAM,CAClD,OAAO,OAAM,mBAAgB,CAAC,CAAC,EAAE,QAAQ,yBAAuB,EAChE,OAAO,OAAM,mBAAgB,EAAE,CAAC,EAAE,QAAQ,yBAAuB,EACjE,OAAO,OAAM,mBAAgB,GAAG,CAAC,EAAE,QAAQ,yBAAuB,CACpE,CAAC,CACH,CAAC,EAED,SAAS,yBAA0B,IAAM,CACvC,GAAG,sCAAuC,IAAM,CAC9C,OAAO,OACL,0BAAuBD,CAAsB,CAC/C,EAAE,IAAI,QAAQ,CAChB,CAAC,EAED,GAAG,wCAAyC,IAAM,CAChD,OAAO,OAAM,0BAAuB,kBAAkB,CAAC,EAAE,IAAI,QAAQ,CACvE,CAAC,EAED,GAAG,gCAAiC,IAAM,CACxC,OAAO,OAAM,0BAAuB,SAAS,CAAC,EAAE,QAC9C,yBACF,CACF,CAAC,CACH,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["import_contactsValidation", "SAMPLE_DERIVATION_PATH", "opts"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var d=(t,n)=>{for(var e in n)o(t,e,{get:n[e],enumerable:!0})},C=(t,n,e,T)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of _(n))!I.call(t,r)&&r!==e&&o(t,r,{get:()=>n[r],enumerable:!(T=x(n,r))||T.enumerable});return t};var A=t=>C(o({},"__esModule",{value:!0}),t);var V={};d(V,{CONTACTS_TLV_TAG:()=>c,STRUCT_TYPE_EDIT_CONTACT_NAME:()=>R,STRUCT_TYPE_EDIT_IDENTIFIER:()=>u,STRUCT_TYPE_EDIT_LEDGER_ACCOUNT:()=>D,STRUCT_TYPE_EDIT_SCOPE:()=>O,STRUCT_TYPE_PROVIDE_CONTACT:()=>N,STRUCT_TYPE_PROVIDE_LEDGER_ACCOUNT_CONTACT:()=>p,STRUCT_TYPE_REGISTER_IDENTITY:()=>s,STRUCT_TYPE_REGISTER_LEDGER_ACCOUNT:()=>B,STRUCT_VERSION_VALUE:()=>y,encodeTlvAscii:()=>m,encodeTlvBuffer:()=>E,encodeTlvChainId:()=>w,encodeTlvUInt8:()=>P,packDerivationPath:()=>L});module.exports=A(V);var i=require("@ledgerhq/device-management-kit");const U=33024,c={STRUCT_TYPE:1,STRUCT_VERSION:2,DERIVATION_PATH:105,CHAIN_ID:35,HMAC_PROOF:41,BLOCKCHAIN_FAMILY:81,CONTACT_NAME:240,SCOPE:241,ACCOUNT_IDENTIFIER:242,PREVIOUS_CONTACT_NAME:243,PREVIOUS_IDENTIFIER:244,PREVIOUS_SCOPE:245,GROUP_HANDLE:246,HMAC_REST:247},s=45,R=46,B=47,D=48,u=49,O=50,N=51,p=52,y=1;function f(t,n){if(n<128)t.add8BitUIntToData(n);else if(n<=255)t.add16BitUIntToData(U+n);else throw new Error(`TLV tag ${n} exceeds supported single-byte range`)}function a(t,n){if(n<128)t.add8BitUIntToData(n);else if(n<=255)t.add8BitUIntToData(129),t.add8BitUIntToData(n);else if(n<=65535)t.add8BitUIntToData(130),t.add16BitUIntToData(n);else throw new Error(`TLV length ${n} exceeds supported range`)}function S(t){const n=typeof t=="bigint"?t:BigInt(t);if(n<=0n)throw new Error(`chainId must be positive, got ${t}`);if(n>0xffffffffffffffffn)throw new Error(`chainId ${t} exceeds uint64 range`);const e=[];let T=n;for(;T>0n;)e.unshift(Number(T&0xffn)),T>>=8n;return Uint8Array.from(e)}function P(t,n,e){f(t,n),t.add8BitUIntToData(1),t.add8BitUIntToData(e)}function m(t,n,e){f(t,n);const T=new TextEncoder().encode(e);a(t,T.length),t.addBufferToData(T)}function E(t,n,e){f(t,n),a(t,e.length),t.addBufferToData(e)}function w(t,n,e){E(t,n,S(e))}function L(t){const n=new i.ByteArrayBuilder;return n.add8BitUIntToData(t.length),t.forEach(e=>n.add32BitUIntToData(e)),n.build()}0&&(module.exports={CONTACTS_TLV_TAG,STRUCT_TYPE_EDIT_CONTACT_NAME,STRUCT_TYPE_EDIT_IDENTIFIER,STRUCT_TYPE_EDIT_LEDGER_ACCOUNT,STRUCT_TYPE_EDIT_SCOPE,STRUCT_TYPE_PROVIDE_CONTACT,STRUCT_TYPE_PROVIDE_LEDGER_ACCOUNT_CONTACT,STRUCT_TYPE_REGISTER_IDENTITY,STRUCT_TYPE_REGISTER_LEDGER_ACCOUNT,STRUCT_VERSION_VALUE,encodeTlvAscii,encodeTlvBuffer,encodeTlvChainId,encodeTlvUInt8,packDerivationPath});
|
|
2
|
+
//# sourceMappingURL=contactsTlvSerializer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/services/contactsTlvSerializer.ts"],
|
|
4
|
+
"sourcesContent": ["// TLV encoding for the Contacts feature.\n// The SDK's TLV parser (lib_tlv/tlv_library.c, get_der_value_as_uint32) reads\n// tags as DER values: a byte with the high bit set means \"long form, low 7 bits\n// = following byte count\". So tags >= 0x80 (e.g. 0xf0) MUST be sent as the\n// 2-byte form [0x81, tag]; a bare 0xf0 is mis-read as a 112-byte tag. Lengths\n// >= 0x80 likewise use DER long form. (Verified on-device: a raw one-byte tag\n// parses as garbage and the app rejects the payload with 0x6a80.)\nimport { ByteArrayBuilder } from \"@ledgerhq/device-management-kit\";\n\nconst LONG_TAG_PREFIX_HIGH_BYTE = 0x81 << 8;\n\nexport const CONTACTS_TLV_TAG = {\n STRUCT_TYPE: 0x01,\n STRUCT_VERSION: 0x02,\n // Ledger-Account operations only; external-address ops carry no path.\n // TODO(Ledger Account ticket): spec tag registry lists 0x69 but the per-op\n // payload tables list 0x21 \u2014 confirm before the Ledger-Account op ships.\n DERIVATION_PATH: 0x69,\n CHAIN_ID: 0x23,\n HMAC_PROOF: 0x29,\n BLOCKCHAIN_FAMILY: 0x51,\n CONTACT_NAME: 0xf0,\n SCOPE: 0xf1,\n ACCOUNT_IDENTIFIER: 0xf2,\n PREVIOUS_CONTACT_NAME: 0xf3,\n PREVIOUS_IDENTIFIER: 0xf4,\n PREVIOUS_SCOPE: 0xf5,\n GROUP_HANDLE: 0xf6,\n HMAC_REST: 0xf7,\n} as const;\n\nexport const STRUCT_TYPE_REGISTER_IDENTITY = 0x2d;\nexport const STRUCT_TYPE_EDIT_CONTACT_NAME = 0x2e;\nexport const STRUCT_TYPE_REGISTER_LEDGER_ACCOUNT = 0x2f;\nexport const STRUCT_TYPE_EDIT_LEDGER_ACCOUNT = 0x30;\nexport const STRUCT_TYPE_EDIT_IDENTIFIER = 0x31;\nexport const STRUCT_TYPE_EDIT_SCOPE = 0x32;\nexport const STRUCT_TYPE_PROVIDE_CONTACT = 0x33;\nexport const STRUCT_TYPE_PROVIDE_LEDGER_ACCOUNT_CONTACT = 0x34;\nexport const STRUCT_VERSION_VALUE = 0x01;\n\nfunction writeTag(builder: ByteArrayBuilder, tag: number): void {\n if (tag < 0x80) {\n builder.add8BitUIntToData(tag);\n } else if (tag <= 0xff) {\n // DER long-form: 0x81 (1 following byte) then the tag value.\n builder.add16BitUIntToData(LONG_TAG_PREFIX_HIGH_BYTE + tag);\n } else {\n throw new Error(`TLV tag ${tag} exceeds supported single-byte range`);\n }\n}\n\nfunction writeDerLength(builder: ByteArrayBuilder, length: number): void {\n if (length < 0x80) {\n builder.add8BitUIntToData(length);\n } else if (length <= 0xff) {\n builder.add8BitUIntToData(0x81);\n builder.add8BitUIntToData(length);\n } else if (length <= 0xffff) {\n builder.add8BitUIntToData(0x82);\n builder.add16BitUIntToData(length);\n } else {\n throw new Error(`TLV length ${length} exceeds supported range`);\n }\n}\n\nfunction chainIdToMinimalBytes(chainId: number | bigint): Uint8Array {\n const big = typeof chainId === \"bigint\" ? chainId : BigInt(chainId);\n if (big <= 0n) {\n throw new Error(`chainId must be positive, got ${chainId}`);\n }\n if (big > 0xffffffffffffffffn) {\n throw new Error(`chainId ${chainId} exceeds uint64 range`);\n }\n const bytes: number[] = [];\n let n = big;\n while (n > 0n) {\n bytes.unshift(Number(n & 0xffn));\n n >>= 8n;\n }\n return Uint8Array.from(bytes);\n}\n\nexport function encodeTlvUInt8(\n builder: ByteArrayBuilder,\n tag: number,\n value: number,\n): void {\n writeTag(builder, tag);\n builder.add8BitUIntToData(1);\n builder.add8BitUIntToData(value);\n}\n\nexport function encodeTlvAscii(\n builder: ByteArrayBuilder,\n tag: number,\n value: string,\n): void {\n writeTag(builder, tag);\n const bytes = new TextEncoder().encode(value);\n writeDerLength(builder, bytes.length);\n builder.addBufferToData(bytes);\n}\n\nexport function encodeTlvBuffer(\n builder: ByteArrayBuilder,\n tag: number,\n value: Uint8Array,\n): void {\n writeTag(builder, tag);\n writeDerLength(builder, value.length);\n builder.addBufferToData(value);\n}\n\nexport function encodeTlvChainId(\n builder: ByteArrayBuilder,\n tag: number,\n chainId: number | bigint,\n): void {\n encodeTlvBuffer(builder, tag, chainIdToMinimalBytes(chainId));\n}\n\n/** Pack BIP32 segments as `count(1) || segment(4 BE)*count`. */\nexport function packDerivationPath(segments: number[]): Uint8Array {\n const builder = new ByteArrayBuilder();\n builder.add8BitUIntToData(segments.length);\n segments.forEach((segment) => builder.add32BitUIntToData(segment));\n return builder.build();\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sBAAAE,EAAA,kCAAAC,EAAA,gCAAAC,EAAA,oCAAAC,EAAA,2BAAAC,EAAA,gCAAAC,EAAA,+CAAAC,EAAA,kCAAAC,EAAA,wCAAAC,EAAA,yBAAAC,EAAA,mBAAAC,EAAA,oBAAAC,EAAA,qBAAAC,EAAA,mBAAAC,EAAA,uBAAAC,IAAA,eAAAC,EAAAjB,GAOA,IAAAkB,EAAiC,2CAEjC,MAAMC,EAA4B,MAErBjB,EAAmB,CAC9B,YAAa,EACb,eAAgB,EAIhB,gBAAiB,IACjB,SAAU,GACV,WAAY,GACZ,kBAAmB,GACnB,aAAc,IACd,MAAO,IACP,mBAAoB,IACpB,sBAAuB,IACvB,oBAAqB,IACrB,eAAgB,IAChB,aAAc,IACd,UAAW,GACb,EAEaO,EAAgC,GAChCN,EAAgC,GAChCO,EAAsC,GACtCL,EAAkC,GAClCD,EAA8B,GAC9BE,EAAyB,GACzBC,EAA8B,GAC9BC,EAA6C,GAC7CG,EAAuB,EAEpC,SAASS,EAASC,EAA2BC,EAAmB,CAC9D,GAAIA,EAAM,IACRD,EAAQ,kBAAkBC,CAAG,UACpBA,GAAO,IAEhBD,EAAQ,mBAAmBF,EAA4BG,CAAG,MAE1D,OAAM,IAAI,MAAM,WAAWA,CAAG,sCAAsC,CAExE,CAEA,SAASC,EAAeF,EAA2BG,EAAsB,CACvE,GAAIA,EAAS,IACXH,EAAQ,kBAAkBG,CAAM,UACvBA,GAAU,IACnBH,EAAQ,kBAAkB,GAAI,EAC9BA,EAAQ,kBAAkBG,CAAM,UACvBA,GAAU,MACnBH,EAAQ,kBAAkB,GAAI,EAC9BA,EAAQ,mBAAmBG,CAAM,MAEjC,OAAM,IAAI,MAAM,cAAcA,CAAM,0BAA0B,CAElE,CAEA,SAASC,EAAsBC,EAAsC,CACnE,MAAMC,EAAM,OAAOD,GAAY,SAAWA,EAAU,OAAOA,CAAO,EAClE,GAAIC,GAAO,GACT,MAAM,IAAI,MAAM,iCAAiCD,CAAO,EAAE,EAE5D,GAAIC,EAAM,oBACR,MAAM,IAAI,MAAM,WAAWD,CAAO,uBAAuB,EAE3D,MAAME,EAAkB,CAAC,EACzB,IAAIC,EAAIF,EACR,KAAOE,EAAI,IACTD,EAAM,QAAQ,OAAOC,EAAI,KAAK,CAAC,EAC/BA,IAAM,GAER,OAAO,WAAW,KAAKD,CAAK,CAC9B,CAEO,SAASb,EACdM,EACAC,EACAQ,EACM,CACNV,EAASC,EAASC,CAAG,EACrBD,EAAQ,kBAAkB,CAAC,EAC3BA,EAAQ,kBAAkBS,CAAK,CACjC,CAEO,SAASlB,EACdS,EACAC,EACAQ,EACM,CACNV,EAASC,EAASC,CAAG,EACrB,MAAMM,EAAQ,IAAI,YAAY,EAAE,OAAOE,CAAK,EAC5CP,EAAeF,EAASO,EAAM,MAAM,EACpCP,EAAQ,gBAAgBO,CAAK,CAC/B,CAEO,SAASf,EACdQ,EACAC,EACAQ,EACM,CACNV,EAASC,EAASC,CAAG,EACrBC,EAAeF,EAASS,EAAM,MAAM,EACpCT,EAAQ,gBAAgBS,CAAK,CAC/B,CAEO,SAAShB,EACdO,EACAC,EACAI,EACM,CACNb,EAAgBQ,EAASC,EAAKG,EAAsBC,CAAO,CAAC,CAC9D,CAGO,SAASV,EAAmBe,EAAgC,CACjE,MAAMV,EAAU,IAAI,mBACpB,OAAAA,EAAQ,kBAAkBU,EAAS,MAAM,EACzCA,EAAS,QAASC,GAAYX,EAAQ,mBAAmBW,CAAO,CAAC,EAC1DX,EAAQ,MAAM,CACvB",
|
|
6
|
+
"names": ["contactsTlvSerializer_exports", "__export", "CONTACTS_TLV_TAG", "STRUCT_TYPE_EDIT_CONTACT_NAME", "STRUCT_TYPE_EDIT_IDENTIFIER", "STRUCT_TYPE_EDIT_LEDGER_ACCOUNT", "STRUCT_TYPE_EDIT_SCOPE", "STRUCT_TYPE_PROVIDE_CONTACT", "STRUCT_TYPE_PROVIDE_LEDGER_ACCOUNT_CONTACT", "STRUCT_TYPE_REGISTER_IDENTITY", "STRUCT_TYPE_REGISTER_LEDGER_ACCOUNT", "STRUCT_VERSION_VALUE", "encodeTlvAscii", "encodeTlvBuffer", "encodeTlvChainId", "encodeTlvUInt8", "packDerivationPath", "__toCommonJS", "import_device_management_kit", "LONG_TAG_PREFIX_HIGH_BYTE", "writeTag", "builder", "tag", "writeDerLength", "length", "chainIdToMinimalBytes", "chainId", "big", "bytes", "n", "value", "segments", "segment"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var i=require("@ledgerhq/device-management-kit"),e=require("./contactsTlvSerializer");describe("contactsTlvSerializer",()=>{describe("DERIVATION_PATH tag",()=>{it("is 0x69 (not the pre-1.23 value 0x21)",()=>{expect(e.CONTACTS_TLV_TAG.DERIVATION_PATH).toBe(105)}),it("encodes a packed path under tag 0x69",()=>{const t=new i.ByteArrayBuilder,r=(0,e.packDerivationPath)([2147483692,2147483708,2147483648]);(0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.DERIVATION_PATH,r),expect(t.build()).toStrictEqual(Uint8Array.from([105,13,3,128,0,0,44,128,0,0,60,128,0,0,0]))})}),describe("primitive encoders",()=>{it("encodes a single-byte TLV (tag < 0x80, length 1)",()=>{const t=new i.ByteArrayBuilder;(0,e.encodeTlvUInt8)(t,e.CONTACTS_TLV_TAG.STRUCT_TYPE,45),expect(t.build()).toStrictEqual(Uint8Array.from([1,1,45]))}),it("encodes tags >= 0x80 as the 2-byte DER long form [0x81, tag]",()=>{const t=new i.ByteArrayBuilder;(0,e.encodeTlvAscii)(t,e.CONTACTS_TLV_TAG.CONTACT_NAME,"AB"),expect(t.build()).toStrictEqual(Uint8Array.from([129,240,2,65,66]))}),it("encodes chainId as minimal big-endian bytes",()=>{const t=new i.ByteArrayBuilder;(0,e.encodeTlvChainId)(t,e.CONTACTS_TLV_TAG.CHAIN_ID,1n),expect(t.build()).toStrictEqual(Uint8Array.from([35,1,1]));const r=new i.ByteArrayBuilder;(0,e.encodeTlvChainId)(r,e.CONTACTS_TLV_TAG.CHAIN_ID,56),expect(r.build()).toStrictEqual(Uint8Array.from([35,1,56]))}),it("emits DER long-form length for payloads >= 0x80 bytes",()=>{const t=new i.ByteArrayBuilder,r=new Uint8Array(200).fill(171);(0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,r);const x=t.build();expect(Array.from(x.slice(0,4))).toEqual([129,242,129,200]),expect(x.length).toBe(204)}),it("rejects a non-positive chainId",()=>{const t=new i.ByteArrayBuilder;expect(()=>(0,e.encodeTlvChainId)(t,e.CONTACTS_TLV_TAG.CHAIN_ID,0)).toThrow()})})});
|
|
2
|
+
//# sourceMappingURL=contactsTlvSerializer.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/services/contactsTlvSerializer.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { ByteArrayBuilder } from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACTS_TLV_TAG,\n encodeTlvAscii,\n encodeTlvBuffer,\n encodeTlvChainId,\n encodeTlvUInt8,\n packDerivationPath,\n} from \"./contactsTlvSerializer\";\n\ndescribe(\"contactsTlvSerializer\", () => {\n describe(\"DERIVATION_PATH tag\", () => {\n // Pins the ETH-app 1.23 / BOLOS SDK protocol change (commit 963d72b7):\n // the address-book derivation-path tag moved from 0x21 to 0x69. Sending the\n // old tag makes the on-device TLV parser reject with 0x6A80.\n it(\"is 0x69 (not the pre-1.23 value 0x21)\", () => {\n expect(CONTACTS_TLV_TAG.DERIVATION_PATH).toBe(0x69);\n });\n\n it(\"encodes a packed path under tag 0x69\", () => {\n const builder = new ByteArrayBuilder();\n const path = packDerivationPath([0x8000002c, 0x8000003c, 0x80000000]);\n\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.DERIVATION_PATH, path);\n\n expect(builder.build()).toStrictEqual(\n Uint8Array.from([\n 0x69, // DERIVATION_PATH tag\n 0x0d, // length: 1 count byte + 3 * 4-byte segments\n 0x03, // segment count\n 0x80,\n 0x00,\n 0x00,\n 0x2c, // 44'\n 0x80,\n 0x00,\n 0x00,\n 0x3c, // 60'\n 0x80,\n 0x00,\n 0x00,\n 0x00, // 0'\n ]),\n );\n });\n });\n\n describe(\"primitive encoders\", () => {\n it(\"encodes a single-byte TLV (tag < 0x80, length 1)\", () => {\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(builder, CONTACTS_TLV_TAG.STRUCT_TYPE, 0x2d);\n expect(builder.build()).toStrictEqual(\n Uint8Array.from([0x01, 0x01, 0x2d]),\n );\n });\n\n it(\"encodes tags >= 0x80 as the 2-byte DER long form [0x81, tag]\", () => {\n const builder = new ByteArrayBuilder();\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, \"AB\");\n // Tag 0xf0 -> DER long form [0x81, 0xf0], length 2, ASCII \"AB\".\n expect(builder.build()).toStrictEqual(\n Uint8Array.from([0x81, 0xf0, 0x02, 0x41, 0x42]),\n );\n });\n\n it(\"encodes chainId as minimal big-endian bytes\", () => {\n const builder = new ByteArrayBuilder();\n encodeTlvChainId(builder, CONTACTS_TLV_TAG.CHAIN_ID, 1n);\n expect(builder.build()).toStrictEqual(\n Uint8Array.from([0x23, 0x01, 0x01]),\n );\n\n const builder2 = new ByteArrayBuilder();\n encodeTlvChainId(builder2, CONTACTS_TLV_TAG.CHAIN_ID, 56);\n expect(builder2.build()).toStrictEqual(\n Uint8Array.from([0x23, 0x01, 0x38]),\n );\n });\n\n it(\"emits DER long-form length for payloads >= 0x80 bytes\", () => {\n const builder = new ByteArrayBuilder();\n const value = new Uint8Array(200).fill(0xab);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER, value);\n const out = builder.build();\n // tag 0xf2 -> [0x81, 0xf2], then long-form length 0x81 0xc8 (200).\n expect(Array.from(out.slice(0, 4))).toEqual([0x81, 0xf2, 0x81, 0xc8]);\n expect(out.length).toBe(4 + 200);\n });\n\n it(\"rejects a non-positive chainId\", () => {\n const builder = new ByteArrayBuilder();\n expect(() =>\n encodeTlvChainId(builder, CONTACTS_TLV_TAG.CHAIN_ID, 0),\n ).toThrow();\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "aAAA,IAAAA,EAAiC,2CAEjCC,EAOO,mCAEP,SAAS,wBAAyB,IAAM,CACtC,SAAS,sBAAuB,IAAM,CAIpC,GAAG,wCAAyC,IAAM,CAChD,OAAO,mBAAiB,eAAe,EAAE,KAAK,GAAI,CACpD,CAAC,EAED,GAAG,uCAAwC,IAAM,CAC/C,MAAMC,EAAU,IAAI,mBACdC,KAAO,sBAAmB,CAAC,WAAY,WAAY,UAAU,CAAC,KAEpE,mBAAgBD,EAAS,mBAAiB,gBAAiBC,CAAI,EAE/D,OAAOD,EAAQ,MAAM,CAAC,EAAE,cACtB,WAAW,KAAK,CACd,IACA,GACA,EACA,IACA,EACA,EACA,GACA,IACA,EACA,EACA,GACA,IACA,EACA,EACA,CACF,CAAC,CACH,CACF,CAAC,CACH,CAAC,EAED,SAAS,qBAAsB,IAAM,CACnC,GAAG,mDAAoD,IAAM,CAC3D,MAAMA,EAAU,IAAI,sBACpB,kBAAeA,EAAS,mBAAiB,YAAa,EAAI,EAC1D,OAAOA,EAAQ,MAAM,CAAC,EAAE,cACtB,WAAW,KAAK,CAAC,EAAM,EAAM,EAAI,CAAC,CACpC,CACF,CAAC,EAED,GAAG,+DAAgE,IAAM,CACvE,MAAMA,EAAU,IAAI,sBACpB,kBAAeA,EAAS,mBAAiB,aAAc,IAAI,EAE3D,OAAOA,EAAQ,MAAM,CAAC,EAAE,cACtB,WAAW,KAAK,CAAC,IAAM,IAAM,EAAM,GAAM,EAAI,CAAC,CAChD,CACF,CAAC,EAED,GAAG,8CAA+C,IAAM,CACtD,MAAMA,EAAU,IAAI,sBACpB,oBAAiBA,EAAS,mBAAiB,SAAU,EAAE,EACvD,OAAOA,EAAQ,MAAM,CAAC,EAAE,cACtB,WAAW,KAAK,CAAC,GAAM,EAAM,CAAI,CAAC,CACpC,EAEA,MAAME,EAAW,IAAI,sBACrB,oBAAiBA,EAAU,mBAAiB,SAAU,EAAE,EACxD,OAAOA,EAAS,MAAM,CAAC,EAAE,cACvB,WAAW,KAAK,CAAC,GAAM,EAAM,EAAI,CAAC,CACpC,CACF,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,MAAMF,EAAU,IAAI,mBACdG,EAAQ,IAAI,WAAW,GAAG,EAAE,KAAK,GAAI,KAC3C,mBAAgBH,EAAS,mBAAiB,mBAAoBG,CAAK,EACnE,MAAMC,EAAMJ,EAAQ,MAAM,EAE1B,OAAO,MAAM,KAAKI,EAAI,MAAM,EAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAM,IAAM,IAAM,GAAI,CAAC,EACpE,OAAOA,EAAI,MAAM,EAAE,KAAK,GAAO,CACjC,CAAC,EAED,GAAG,iCAAkC,IAAM,CACzC,MAAMJ,EAAU,IAAI,mBACpB,OAAO,OACL,oBAAiBA,EAAS,mBAAiB,SAAU,CAAC,CACxD,EAAE,QAAQ,CACZ,CAAC,CACH,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["import_device_management_kit", "import_contactsTlvSerializer", "builder", "path", "builder2", "value", "out"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var S=(n,e)=>{for(var t in e)l(n,t,{get:e[t],enumerable:!0})},U=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of k(e))!P.call(n,s)&&s!==t&&l(n,s,{get:()=>e[s],enumerable:!(r=R(e,s))||r.enumerable});return n};var b=n=>U(l({},"__esModule",{value:!0}),n);var I={};S(I,{sendFramedContactsPayload:()=>L});module.exports=b(I);var A=require("@ledgerhq/device-management-kit");const F=255,y=0,C=128;async function L(n,{payload:e,makeCommand:t,logger:r,commandTag:s}){const a=w(e),o=x(a,F),m=s??"framed-contacts";for(let u=0;u<o.length-1;u++){const g=u===0?y:C,h=o[u];f(r,m,u,o.length,g,h.length,a.length);const p=await n.sendCommand(t(h,g));if(!(0,A.isSuccessDmkResult)(p))return p}const c=o.length-1,d=c===0?y:C,i=o[c];return f(r,m,c,o.length,d,i.length,a.length),await n.sendCommand(t(i,d))}function f(n,e,t,r,s,a,o){n&&n.debug(`[chunk ${t+1}/${r}] sending`,{tag:e,data:{chunkIndex:t,chunkCount:r,p2:`0x${s.toString(16).padStart(2,"0")}`,chunkLen:a,framedPayloadLen:o,isFirst:t===0,isLast:t===r-1}})}function w(n){const e=n.length,t=new Uint8Array(e+2);return t[0]=e>>8&255,t[1]=e&255,t.set(n,2),t}function x(n,e){if(n.length===0)return[n];const t=[];for(let r=0;r<n.length;r+=e)t.push(n.slice(r,Math.min(r+e,n.length)));return t}0&&(module.exports={sendFramedContactsPayload});
|
|
2
|
+
//# sourceMappingURL=sendFramedContactsPayload.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/services/sendFramedContactsPayload.ts"],
|
|
4
|
+
"sourcesContent": ["// Chunked-framing transport for the Contacts ops. Since the BOLOS SDK\n// \"use uniform chunked transport for all sub-commands\" change, every\n// address-book sub-command frames its TLV this way.\n//\n// First chunk is dispatched with P2=0x00 and carries the 2-byte BE\n// total-payload-length prefix. Subsequent chunks use P2=0x80. The\n// caller-supplied `makeCommand` builds a Command per chunk; the helper\n// returns the final chunk's CommandResult unchanged so the caller can\n// parse the device's structured response off the last exchange.\n// Protocol: ledger-secure-sdk/app_features/address_book/doc/address_book_spec.md \u00A73\nimport {\n type Command,\n type CommandResult,\n type InternalApi,\n isSuccessDmkResult,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nconst MAX_CHUNK_BYTES = 255;\nconst P2_FIRST = 0x00;\nconst P2_NEXT = 0x80;\n\nexport type SendFramedContactsPayloadArgs<Response> = {\n /** TLV payload bytes (without any header or length framing). */\n readonly payload: Uint8Array;\n /** Sub-command byte (e.g. 0x01 for REGISTER IDENTITY). */\n readonly p1: number;\n /** Per-chunk Command factory. The helper passes the chunk bytes and the P2 byte. */\n readonly makeCommand: (\n chunk: Uint8Array,\n p2: number,\n ) => Command<Response, unknown, unknown>;\n /** Optional per-chunk diagnostic logging (one `debug` entry per outgoing chunk). */\n readonly logger?: LoggerPublisherService;\n readonly commandTag?: string;\n};\n\nexport async function sendFramedContactsPayload<Response>(\n api: InternalApi,\n {\n payload,\n makeCommand,\n logger,\n commandTag,\n }: SendFramedContactsPayloadArgs<Response>,\n): Promise<CommandResult<Response>> {\n const framed = prependFrameLength(payload);\n const chunks = sliceChunks(framed, MAX_CHUNK_BYTES);\n const tag = commandTag ?? \"framed-contacts\";\n\n // Intermediate chunks: dispatch and short-circuit on error.\n for (let i = 0; i < chunks.length - 1; i++) {\n const p2 = i === 0 ? P2_FIRST : P2_NEXT;\n const chunk = chunks[i]!;\n logChunk(logger, tag, i, chunks.length, p2, chunk.length, framed.length);\n const result = (await api.sendCommand(\n makeCommand(chunk, p2),\n )) as CommandResult<Response>;\n if (!isSuccessDmkResult(result)) {\n return result;\n }\n }\n\n const lastIndex = chunks.length - 1;\n const lastP2 = lastIndex === 0 ? P2_FIRST : P2_NEXT;\n const lastChunk = chunks[lastIndex]!;\n logChunk(\n logger,\n tag,\n lastIndex,\n chunks.length,\n lastP2,\n lastChunk.length,\n framed.length,\n );\n return (await api.sendCommand(\n makeCommand(lastChunk, lastP2),\n )) as CommandResult<Response>;\n}\n\nfunction logChunk(\n logger: LoggerPublisherService | undefined,\n tag: string,\n index: number,\n total: number,\n p2: number,\n chunkLen: number,\n framedLen: number,\n): void {\n if (!logger) return;\n logger.debug(`[chunk ${index + 1}/${total}] sending`, {\n tag,\n data: {\n chunkIndex: index,\n chunkCount: total,\n p2: `0x${p2.toString(16).padStart(2, \"0\")}`,\n chunkLen,\n framedPayloadLen: framedLen,\n isFirst: index === 0,\n isLast: index === total - 1,\n },\n });\n}\n\nfunction prependFrameLength(payload: Uint8Array): Uint8Array {\n const total = payload.length;\n const framed = new Uint8Array(total + 2);\n framed[0] = (total >> 8) & 0xff;\n framed[1] = total & 0xff;\n framed.set(payload, 2);\n return framed;\n}\n\nfunction sliceChunks(buffer: Uint8Array, max: number): Uint8Array[] {\n if (buffer.length === 0) return [buffer];\n const out: Uint8Array[] = [];\n for (let offset = 0; offset < buffer.length; offset += max) {\n out.push(buffer.slice(offset, Math.min(offset + max, buffer.length)));\n }\n return out;\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,+BAAAE,IAAA,eAAAC,EAAAH,GAUA,IAAAI,EAMO,2CAEP,MAAMC,EAAkB,IAClBC,EAAW,EACXC,EAAU,IAiBhB,eAAsBL,EACpBM,EACA,CACE,QAAAC,EACA,YAAAC,EACA,OAAAC,EACA,WAAAC,CACF,EACkC,CAClC,MAAMC,EAASC,EAAmBL,CAAO,EACnCM,EAASC,EAAYH,EAAQR,CAAe,EAC5CY,EAAML,GAAc,kBAG1B,QAASM,EAAI,EAAGA,EAAIH,EAAO,OAAS,EAAGG,IAAK,CAC1C,MAAMC,EAAKD,IAAM,EAAIZ,EAAWC,EAC1Ba,EAAQL,EAAOG,CAAC,EACtBG,EAASV,EAAQM,EAAKC,EAAGH,EAAO,OAAQI,EAAIC,EAAM,OAAQP,EAAO,MAAM,EACvE,MAAMS,EAAU,MAAMd,EAAI,YACxBE,EAAYU,EAAOD,CAAE,CACvB,EACA,GAAI,IAAC,sBAAmBG,CAAM,EAC5B,OAAOA,CAEX,CAEA,MAAMC,EAAYR,EAAO,OAAS,EAC5BS,EAASD,IAAc,EAAIjB,EAAWC,EACtCkB,EAAYV,EAAOQ,CAAS,EAClC,OAAAF,EACEV,EACAM,EACAM,EACAR,EAAO,OACPS,EACAC,EAAU,OACVZ,EAAO,MACT,EACQ,MAAML,EAAI,YAChBE,EAAYe,EAAWD,CAAM,CAC/B,CACF,CAEA,SAASH,EACPV,EACAM,EACAS,EACAC,EACAR,EACAS,EACAC,EACM,CACDlB,GACLA,EAAO,MAAM,UAAUe,EAAQ,CAAC,IAAIC,CAAK,YAAa,CACpD,IAAAV,EACA,KAAM,CACJ,WAAYS,EACZ,WAAYC,EACZ,GAAI,KAAKR,EAAG,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,GACzC,SAAAS,EACA,iBAAkBC,EAClB,QAASH,IAAU,EACnB,OAAQA,IAAUC,EAAQ,CAC5B,CACF,CAAC,CACH,CAEA,SAASb,EAAmBL,EAAiC,CAC3D,MAAMkB,EAAQlB,EAAQ,OAChBI,EAAS,IAAI,WAAWc,EAAQ,CAAC,EACvC,OAAAd,EAAO,CAAC,EAAKc,GAAS,EAAK,IAC3Bd,EAAO,CAAC,EAAIc,EAAQ,IACpBd,EAAO,IAAIJ,EAAS,CAAC,EACdI,CACT,CAEA,SAASG,EAAYc,EAAoBC,EAA2B,CAClE,GAAID,EAAO,SAAW,EAAG,MAAO,CAACA,CAAM,EACvC,MAAME,EAAoB,CAAC,EAC3B,QAASC,EAAS,EAAGA,EAASH,EAAO,OAAQG,GAAUF,EACrDC,EAAI,KAAKF,EAAO,MAAMG,EAAQ,KAAK,IAAIA,EAASF,EAAKD,EAAO,MAAM,CAAC,CAAC,EAEtE,OAAOE,CACT",
|
|
6
|
+
"names": ["sendFramedContactsPayload_exports", "__export", "sendFramedContactsPayload", "__toCommonJS", "import_device_management_kit", "MAX_CHUNK_BYTES", "P2_FIRST", "P2_NEXT", "api", "payload", "makeCommand", "logger", "commandTag", "framed", "prependFrameLength", "chunks", "sliceChunks", "tag", "i", "p2", "chunk", "logChunk", "result", "lastIndex", "lastP2", "lastChunk", "index", "total", "chunkLen", "framedLen", "buffer", "max", "out", "offset"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var a=require("@ledgerhq/device-management-kit"),m=require("./sendFramedContactsPayload");function l(){return{sendCommand:vi.fn()}}function r(e,n=66){return new Uint8Array(e).fill(n)}const d=()=>vi.fn((e,n)=>({name:"test",args:{chunk:e,p2:n},getApdu:vi.fn(),parseResponse:vi.fn()}));describe("sendFramedContactsPayload",()=>{it("single-chunk: prepends BE length, uses P2=0x00, returns command result",async()=>{const e=l(),n=(0,a.CommandResultFactory)({data:{ok:!0}});e.sendCommand.mockResolvedValueOnce(n);const t=d(),o=await(0,m.sendFramedContactsPayload)(e,{payload:r(100),p1:1,makeCommand:t});expect(t).toHaveBeenCalledTimes(1);const[s,c]=t.mock.calls[0];expect(c).toBe(0),expect(s[0]).toBe(0),expect(s[1]).toBe(100),expect(s.length).toBe(102),expect(o).toBe(n)}),it("multi-chunk: splits into <=255B pieces, P2 0x00 then 0x80, prefix on first only",async()=>{const e=l(),n=(0,a.CommandResultFactory)({data:{}}),t=(0,a.CommandResultFactory)({data:{ok:!0}});e.sendCommand.mockResolvedValueOnce(n).mockResolvedValueOnce(n).mockResolvedValueOnce(t);const o=d(),s=await(0,m.sendFramedContactsPayload)(e,{payload:r(600,85),p1:1,makeCommand:o});expect(o).toHaveBeenCalledTimes(3);const[c,p]=o.mock.calls[0],[i,u]=o.mock.calls[1],[k,x]=o.mock.calls[2];expect([p,u,x]).toEqual([0,128,128]),expect([c.length,i.length,k.length]).toEqual([255,255,92]),expect(c[0]).toBe(2),expect(c[1]).toBe(88),expect(i[0]).toBe(85),expect(s).toBe(t)}),it("short-circuits on intermediate-chunk error without dispatching remaining chunks",async()=>{const e=l(),n=(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError("kaboom")});e.sendCommand.mockResolvedValueOnce(n);const t=d(),o=await(0,m.sendFramedContactsPayload)(e,{payload:r(600),p1:1,makeCommand:t});expect(e.sendCommand).toHaveBeenCalledTimes(1),expect(t).toHaveBeenCalledTimes(1),expect(o).toBe(n)})});
|
|
2
|
+
//# sourceMappingURL=sendFramedContactsPayload.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/services/sendFramedContactsPayload.test.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n type Command,\n type CommandResult,\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { sendFramedContactsPayload } from \"./sendFramedContactsPayload\";\n\nfunction makeApiMock(): InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n} {\n return {\n sendCommand: vi.fn(),\n } as unknown as InternalApi & { sendCommand: ReturnType<typeof vi.fn> };\n}\n\nfunction makePayload(byteCount: number, fillByte = 0x42): Uint8Array {\n return new Uint8Array(byteCount).fill(fillByte);\n}\n\nconst makeCommandFactory = () =>\n vi.fn(\n (chunk: Uint8Array, p2: number) =>\n ({\n name: \"test\",\n args: { chunk, p2 },\n getApdu: vi.fn(),\n parseResponse: vi.fn(),\n }) as unknown as Command<unknown, unknown, unknown>,\n );\n\ndescribe(\"sendFramedContactsPayload\", () => {\n it(\"single-chunk: prepends BE length, uses P2=0x00, returns command result\", async () => {\n const api = makeApiMock();\n const finalResult = CommandResultFactory({ data: { ok: true } });\n api.sendCommand.mockResolvedValueOnce(finalResult);\n const makeCommand = makeCommandFactory();\n\n const result = await sendFramedContactsPayload(api, {\n payload: makePayload(100),\n p1: 0x01,\n makeCommand,\n });\n\n expect(makeCommand).toHaveBeenCalledTimes(1);\n const [chunk, p2] = makeCommand.mock.calls[0]!;\n expect(p2).toBe(0x00);\n // 2-byte BE length prefix = 100 \u2192 0x00, 0x64.\n expect(chunk[0]).toBe(0x00);\n expect(chunk[1]).toBe(0x64);\n expect(chunk.length).toBe(102);\n expect(result).toBe(finalResult);\n });\n\n it(\"multi-chunk: splits into <=255B pieces, P2 0x00 then 0x80, prefix on first only\", async () => {\n const api = makeApiMock();\n const intermediateOk = CommandResultFactory({ data: {} });\n const finalResult = CommandResultFactory({ data: { ok: true } });\n api.sendCommand\n .mockResolvedValueOnce(intermediateOk)\n .mockResolvedValueOnce(intermediateOk)\n .mockResolvedValueOnce(finalResult);\n const makeCommand = makeCommandFactory();\n\n // 600 bytes payload \u2192 602 with frame prefix \u2192 3 chunks (255 + 255 + 92).\n const result = await sendFramedContactsPayload(api, {\n payload: makePayload(600, 0x55),\n p1: 0x01,\n makeCommand,\n });\n\n expect(makeCommand).toHaveBeenCalledTimes(3);\n const [chunk0, p20] = makeCommand.mock.calls[0]!;\n const [chunk1, p21] = makeCommand.mock.calls[1]!;\n const [chunk2, p22] = makeCommand.mock.calls[2]!;\n expect([p20, p21, p22]).toEqual([0x00, 0x80, 0x80]);\n expect([chunk0.length, chunk1.length, chunk2.length]).toEqual([\n 255, 255, 92,\n ]);\n // Frame prefix (600 = 0x0258) only on the first chunk.\n expect(chunk0[0]).toBe(0x02);\n expect(chunk0[1]).toBe(0x58);\n // Continuation chunks begin with raw payload bytes.\n expect(chunk1[0]).toBe(0x55);\n expect(result).toBe(finalResult);\n });\n\n it(\"short-circuits on intermediate-chunk error without dispatching remaining chunks\", async () => {\n const api = makeApiMock();\n const errorResult: CommandResult<unknown> = CommandResultFactory({\n error: new InvalidStatusWordError(\"kaboom\"),\n });\n api.sendCommand.mockResolvedValueOnce(errorResult);\n const makeCommand = makeCommandFactory();\n\n const result = await sendFramedContactsPayload(api, {\n payload: makePayload(600),\n p1: 0x01,\n makeCommand,\n });\n\n expect(api.sendCommand).toHaveBeenCalledTimes(1);\n expect(makeCommand).toHaveBeenCalledTimes(1);\n expect(result).toBe(errorResult);\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_device_management_kit", "import_sendFramedContactsPayload", "makeApiMock", "makePayload", "byteCount", "fillByte", "makeCommandFactory", "chunk", "p2", "api", "finalResult", "makeCommand", "result", "intermediateOk", "chunk0", "p20", "chunk1", "p21", "chunk2", "p22", "errorResult"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var s=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var T=(a,r)=>{for(var o in r)s(a,o,{get:r[o],enumerable:!0})},g=(a,r,o,t)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of u(r))!I.call(a,i)&&i!==o&&s(a,i,{get:()=>r[i],enumerable:!(t=C(r,i))||t.enumerable});return a};var A=a=>g(s({},"__esModule",{value:!0}),a);var f={};T(f,{SendRegisterIdentityTask:()=>R});module.exports=A(f);var n=require("@ledgerhq/device-management-kit"),l=require("../../app-binder/command/RegisterIdentityCommand"),d=require("../../app-binder/model/contactsConstants"),e=require("../../app-binder/services/contactsTlvSerializer"),y=require("../../app-binder/services/sendFramedContactsPayload");class R{constructor(r,o){this.api=r;this.args=o}async run(){const r=this.buildPayload(this.args),o=await(0,y.sendFramedContactsPayload)(this.api,{payload:r,p1:d.SUB_CMD_REGISTER_IDENTITY,makeCommand:(m,p)=>new l.RegisterIdentityCommand({data:m,p2:p}),logger:this.args.logger,commandTag:"SendRegisterIdentityTask"});if(!(0,n.isSuccessCommandResult)(o))return o;const{groupHandle:t,hmacProof:i,hmacRest:c}=o.data;return!t||!i||!c?(0,n.DmkResultFactory)({error:new n.InvalidStatusWordError("RegisterIdentity final-chunk response was incomplete")}):(0,n.DmkResultFactory)({data:{groupHandle:t,hmacProof:i,hmacRest:c}})}buildPayload(r){const o=d.BLOCKCHAIN_FAMILY_BY_NAME[r.blockchainFamily.toLowerCase()];if(o===void 0)throw new Error(`Unsupported blockchain family: ${r.blockchainFamily}`);const t=new n.ByteArrayBuilder;return(0,e.encodeTlvUInt8)(t,e.CONTACTS_TLV_TAG.STRUCT_TYPE,e.STRUCT_TYPE_REGISTER_IDENTITY),(0,e.encodeTlvUInt8)(t,e.CONTACTS_TLV_TAG.STRUCT_VERSION,e.STRUCT_VERSION_VALUE),(0,e.encodeTlvAscii)(t,e.CONTACTS_TLV_TAG.CONTACT_NAME,r.contactName),(0,e.encodeTlvAscii)(t,e.CONTACTS_TLV_TAG.SCOPE,r.scope),(0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,r.identifier),(0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.DERIVATION_PATH,(0,e.packDerivationPath)([2147483692,2147483708,2147483648,0,0])),r.chainId!==void 0&&(0,e.encodeTlvChainId)(t,e.CONTACTS_TLV_TAG.CHAIN_ID,r.chainId),(0,e.encodeTlvUInt8)(t,e.CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY,o),r.existingContactGroup&&((0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.GROUP_HANDLE,r.existingContactGroup.groupHandle),(0,e.encodeTlvBuffer)(t,e.CONTACTS_TLV_TAG.HMAC_PROOF,r.existingContactGroup.hmacProof)),t.build()}}0&&(module.exports={SendRegisterIdentityTask});
|
|
2
|
+
//# sourceMappingURL=SendRegisterIdentityTask.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/task/SendRegisterIdentityTask.ts"],
|
|
4
|
+
"sourcesContent": ["// Builds the TLV payload for op 1 (Register Identity / Register External\n// Address) and dispatches it via the chunked-framing scheme shared with the\n// other address-book ops (2-byte BE total length + <=255B chunks). The device\n// returns the 129-byte register response on the final chunk.\n//\n// Reference: Address Book Final Specifications \u2014 Register Identity. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME, SCOPE, ACCOUNT_IDENTIFIER,\n// DERIVATION_PATH, CHAIN_ID (Ethereum only), BLOCKCHAIN_FAMILY, then optional\n// GROUP_HANDLE + HMAC_PROOF when extending an existing group.\n//\n// DERIVATION_PATH (tag 0x69, default m/44'/60'/0'/0/0): the Ethereum app\n// requires it on Register Identity and rejects the payload with 0x6a80 when it\n// is absent (verified on-device against the deployed dev app).\nimport {\n ByteArrayBuilder,\n type CommandResult,\n DmkResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n isSuccessCommandResult,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ExistingContactGroup } from \"@api/model/RegisterExternalAddress\";\nimport { RegisterIdentityCommand } from \"@internal/app-binder/command/RegisterIdentityCommand\";\nimport {\n BLOCKCHAIN_FAMILY_BY_NAME,\n SUB_CMD_REGISTER_IDENTITY,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport { type ContactsErrorCodes } from \"@internal/app-binder/model/contactsErrors\";\nimport {\n CONTACTS_TLV_TAG,\n encodeTlvAscii,\n encodeTlvBuffer,\n encodeTlvChainId,\n encodeTlvUInt8,\n packDerivationPath,\n STRUCT_TYPE_REGISTER_IDENTITY,\n STRUCT_VERSION_VALUE,\n} from \"@internal/app-binder/services/contactsTlvSerializer\";\nimport { sendFramedContactsPayload } from \"@internal/app-binder/services/sendFramedContactsPayload\";\n\nexport type RegisterIdentityProofs = {\n readonly groupHandle: Uint8Array;\n readonly hmacProof: Uint8Array;\n readonly hmacRest: Uint8Array;\n};\n\nexport type SendRegisterIdentityTaskArgs = {\n readonly contactName: string;\n readonly scope: string;\n readonly identifier: Uint8Array;\n readonly blockchainFamily: string;\n readonly chainId?: bigint;\n readonly existingContactGroup?: ExistingContactGroup;\n readonly logger?: LoggerPublisherService;\n};\n\nexport class SendRegisterIdentityTask {\n constructor(\n private readonly api: InternalApi,\n private readonly args: SendRegisterIdentityTaskArgs,\n ) {}\n\n async run(): Promise<\n CommandResult<RegisterIdentityProofs, ContactsErrorCodes>\n > {\n const payload = this.buildPayload(this.args);\n\n const result = (await sendFramedContactsPayload(this.api, {\n payload,\n p1: SUB_CMD_REGISTER_IDENTITY,\n makeCommand: (chunk, p2) =>\n new RegisterIdentityCommand({ data: chunk, p2 }),\n logger: this.args.logger,\n commandTag: \"SendRegisterIdentityTask\",\n })) as CommandResult<\n {\n readonly groupHandle?: Uint8Array;\n readonly hmacProof?: Uint8Array;\n readonly hmacRest?: Uint8Array;\n },\n ContactsErrorCodes\n >;\n\n if (!isSuccessCommandResult(result)) {\n return result;\n }\n\n const { groupHandle, hmacProof, hmacRest } = result.data;\n if (!groupHandle || !hmacProof || !hmacRest) {\n return DmkResultFactory({\n error: new InvalidStatusWordError(\n \"RegisterIdentity final-chunk response was incomplete\",\n ),\n });\n }\n return DmkResultFactory({ data: { groupHandle, hmacProof, hmacRest } });\n }\n\n private buildPayload(args: SendRegisterIdentityTaskArgs): Uint8Array {\n const family =\n BLOCKCHAIN_FAMILY_BY_NAME[args.blockchainFamily.toLowerCase()];\n if (family === undefined) {\n throw new Error(\n `Unsupported blockchain family: ${args.blockchainFamily}`,\n );\n }\n\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_TYPE,\n STRUCT_TYPE_REGISTER_IDENTITY,\n );\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_VERSION,\n STRUCT_VERSION_VALUE,\n );\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, args.contactName);\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.SCOPE, args.scope);\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,\n args.identifier,\n );\n // The Ethereum app requires DERIVATION_PATH on Register Identity (0x6a80\n // without it). Default m/44'/60'/0'/0/0.\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.DERIVATION_PATH,\n packDerivationPath([0x8000002c, 0x8000003c, 0x80000000, 0, 0]),\n );\n if (args.chainId !== undefined) {\n encodeTlvChainId(builder, CONTACTS_TLV_TAG.CHAIN_ID, args.chainId);\n }\n encodeTlvUInt8(builder, CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY, family);\n\n if (args.existingContactGroup) {\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.GROUP_HANDLE,\n args.existingContactGroup.groupHandle,\n );\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.HMAC_PROOF,\n args.existingContactGroup.hmacProof,\n );\n }\n\n return builder.build();\n }\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,8BAAAE,IAAA,eAAAC,EAAAH,GAaA,IAAAI,EAQO,2CAGPC,EAAwC,gEACxCC,EAGO,wDAEPC,EASO,+DACPC,EAA0C,mEAkBnC,MAAMN,CAAyB,CACpC,YACmBO,EACAC,EACjB,CAFiB,SAAAD,EACA,UAAAC,CAChB,CAEH,MAAM,KAEJ,CACA,MAAMC,EAAU,KAAK,aAAa,KAAK,IAAI,EAErCC,EAAU,QAAM,6BAA0B,KAAK,IAAK,CACxD,QAAAD,EACA,GAAI,4BACJ,YAAa,CAACE,EAAOC,IACnB,IAAI,0BAAwB,CAAE,KAAMD,EAAO,GAAAC,CAAG,CAAC,EACjD,OAAQ,KAAK,KAAK,OAClB,WAAY,0BACd,CAAC,EASD,GAAI,IAAC,0BAAuBF,CAAM,EAChC,OAAOA,EAGT,KAAM,CAAE,YAAAG,EAAa,UAAAC,EAAW,SAAAC,CAAS,EAAIL,EAAO,KACpD,MAAI,CAACG,GAAe,CAACC,GAAa,CAACC,KAC1B,oBAAiB,CACtB,MAAO,IAAI,yBACT,sDACF,CACF,CAAC,KAEI,oBAAiB,CAAE,KAAM,CAAE,YAAAF,EAAa,UAAAC,EAAW,SAAAC,CAAS,CAAE,CAAC,CACxE,CAEQ,aAAaP,EAAgD,CACnE,MAAMQ,EACJ,4BAA0BR,EAAK,iBAAiB,YAAY,CAAC,EAC/D,GAAIQ,IAAW,OACb,MAAM,IAAI,MACR,kCAAkCR,EAAK,gBAAgB,EACzD,EAGF,MAAMS,EAAU,IAAI,mBACpB,2BACEA,EACA,mBAAiB,YACjB,+BACF,KACA,kBACEA,EACA,mBAAiB,eACjB,sBACF,KACA,kBAAeA,EAAS,mBAAiB,aAAcT,EAAK,WAAW,KACvE,kBAAeS,EAAS,mBAAiB,MAAOT,EAAK,KAAK,KAC1D,mBACES,EACA,mBAAiB,mBACjBT,EAAK,UACP,KAGA,mBACES,EACA,mBAAiB,mBACjB,sBAAmB,CAAC,WAAY,WAAY,WAAY,EAAG,CAAC,CAAC,CAC/D,EACIT,EAAK,UAAY,WACnB,oBAAiBS,EAAS,mBAAiB,SAAUT,EAAK,OAAO,KAEnE,kBAAeS,EAAS,mBAAiB,kBAAmBD,CAAM,EAE9DR,EAAK,0BACP,mBACES,EACA,mBAAiB,aACjBT,EAAK,qBAAqB,WAC5B,KACA,mBACES,EACA,mBAAiB,WACjBT,EAAK,qBAAqB,SAC5B,GAGKS,EAAQ,MAAM,CACvB,CACF",
|
|
6
|
+
"names": ["SendRegisterIdentityTask_exports", "__export", "SendRegisterIdentityTask", "__toCommonJS", "import_device_management_kit", "import_RegisterIdentityCommand", "import_contactsConstants", "import_contactsTlvSerializer", "import_sendFramedContactsPayload", "api", "args", "payload", "result", "chunk", "p2", "groupHandle", "hmacProof", "hmacRest", "family", "builder"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var n=require("@ledgerhq/device-management-kit"),r=require("../../app-binder/command/RegisterIdentityCommand"),a=require("./SendRegisterIdentityTask");function e(c){const d=new Uint8Array(c.length/2);for(let t=0;t<c.length;t+=2)d[t/2]=parseInt(c.slice(t,t+2),16);return d}const s=e("004d01012d02010181f005416c69636581f108457468206d61696e81f21400000000000000000000000000000000deadbeef6915058000002c8000003c800000000000000000000000230101510101"),m=e("00b301012d02010181f005416c69636581f108417262206d61696e81f21444444444444444444444444444444444444444446915058000002c8000003c8000000000000000000000002302a4b151010181f640cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc2920dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"),i={groupHandle:e("cc".repeat(64)),hmacProof:e("dd".repeat(32)),hmacRest:e("aa".repeat(32))};function o(){return{sendCommand:vi.fn()}}describe("SendRegisterIdentityTask",()=>{it("assembles a fresh-register framed chunk and dispatches RegisterIdentityCommand",async()=>{const c=o();c.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:i}));const d=await new a.SendRegisterIdentityTask(c,{contactName:"Alice",scope:"Eth main",identifier:e("00000000000000000000000000000000deadbeef"),blockchainFamily:"ethereum",chainId:1n}).run();expect(c.sendCommand.mock.calls).toHaveLength(1),expect(c.sendCommand.mock.calls[0][0]).toStrictEqual(new r.RegisterIdentityCommand({data:s,p2:0})),expect(d).toStrictEqual((0,n.CommandResultFactory)({data:i}))}),it("appends GROUP_HANDLE + HMAC_PROOF on extension and frames the extension payload",async()=>{const c=o();c.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:i})),await new a.SendRegisterIdentityTask(c,{contactName:"Alice",scope:"Arb main",identifier:e("44".repeat(20)),blockchainFamily:"ethereum",chainId:42161n,existingContactGroup:{groupHandle:e("cc".repeat(64)),hmacProof:e("dd".repeat(32))}}).run(),expect(c.sendCommand.mock.calls).toHaveLength(1),expect(c.sendCommand.mock.calls[0][0]).toStrictEqual(new r.RegisterIdentityCommand({data:m,p2:0}))}),it("omits the CHAIN_ID TLV when chainId is not provided",async()=>{const c=o();c.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:i})),await new a.SendRegisterIdentityTask(c,{contactName:"Alice",scope:"Eth main",identifier:e("00000000000000000000000000000000deadbeef"),blockchainFamily:"ethereum"}).run();const d=c.sendCommand.mock.calls[0][0],t=Buffer.from(d.args.data).toString("hex");expect(t).not.toContain("230101"),expect(t.endsWith("510101")).toBe(!0)}),it("propagates command-level errors",async()=>{const c=o();c.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({error:new n.InvalidStatusWordError("user cancelled")}));const d=await new a.SendRegisterIdentityTask(c,{contactName:"Alice",scope:"Eth main",identifier:e("00000000000000000000000000000000deadbeef"),blockchainFamily:"ethereum",chainId:1n}).run();expect(d).toStrictEqual((0,n.CommandResultFactory)({error:new n.InvalidStatusWordError("user cancelled")}))}),it("throws on an unsupported blockchain family",async()=>{const c=o();await expect(new a.SendRegisterIdentityTask(c,{contactName:"Alice",scope:"Eth main",identifier:e("00000000000000000000000000000000deadbeef"),blockchainFamily:"dogecoin",chainId:1n}).run()).rejects.toThrow(/Unsupported blockchain family/),expect(c.sendCommand).not.toHaveBeenCalled()})});
|
|
2
|
+
//# sourceMappingURL=SendRegisterIdentityTask.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/task/SendRegisterIdentityTask.test.ts"],
|
|
4
|
+
"sourcesContent": ["// Validates that the TLV serializer + tag ordering + chunk framing produce the\n// expected wire bytes for op 1 (Register Identity): tags >= 0x80 use the 2-byte\n// DER form [0x81, tag], and Register Identity carries DERIVATION_PATH (tag 0x69,\n// m/44'/60'/0'/0/0) which the Ethereum app requires. The framed chunk = 2-byte\n// BE total length + TLV.\nimport {\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { RegisterIdentityCommand } from \"@internal/app-binder/command/RegisterIdentityCommand\";\n\nimport { SendRegisterIdentityTask } from \"./SendRegisterIdentityTask\";\n\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return out;\n}\n\n// Framed chunk = \"00 <Lc>\" (2-byte BE total TLV length) + TLV. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME, SCOPE, ACCOUNT_IDENTIFIER,\n// DERIVATION_PATH, CHAIN_ID, BLOCKCHAIN_FAMILY, then optional GROUP_HANDLE +\n// HMAC_PROOF. Tags >= 0x80 are encoded as [0x81, tag]; DERIVATION_PATH (0x69)\n// packs m/44'/60'/0'/0/0 as \"05 8000002c 8000003c 80000000 00000000 00000000\".\nconst FRESH_FRAMED_CHUNK = hexToBytes(\n \"004d01012d020101\" +\n \"81f005416c696365\" +\n \"81f108457468206d61696e\" +\n \"81f21400000000000000000000000000000000deadbeef\" +\n \"6915058000002c8000003c800000000000000000000000\" +\n \"230101510101\",\n);\n\nconst EXTENSION_FRAMED_CHUNK = hexToBytes(\n \"00b301012d020101\" +\n \"81f005416c696365\" +\n \"81f108417262206d61696e\" +\n \"81f2144444444444444444444444444444444444444444\" +\n \"6915058000002c8000003c800000000000000000000000\" +\n \"2302a4b1510101\" +\n \"81f640cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\" +\n \"2920dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\",\n);\n\nconst OK_PROOFS = {\n groupHandle: hexToBytes(\"cc\".repeat(64)),\n hmacProof: hexToBytes(\"dd\".repeat(32)),\n hmacRest: hexToBytes(\"aa\".repeat(32)),\n};\n\nfunction makeApiMock(): InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n} {\n return { sendCommand: vi.fn() } as unknown as InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n };\n}\n\ndescribe(\"SendRegisterIdentityTask\", () => {\n it(\"assembles a fresh-register framed chunk and dispatches RegisterIdentityCommand\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: OK_PROOFS }),\n );\n\n const result = await new SendRegisterIdentityTask(api, {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: hexToBytes(\"00000000000000000000000000000000deadbeef\"),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n }).run();\n\n expect(api.sendCommand.mock.calls).toHaveLength(1);\n expect(api.sendCommand.mock.calls[0]![0]).toStrictEqual(\n new RegisterIdentityCommand({ data: FRESH_FRAMED_CHUNK, p2: 0x00 }),\n );\n expect(result).toStrictEqual(CommandResultFactory({ data: OK_PROOFS }));\n });\n\n it(\"appends GROUP_HANDLE + HMAC_PROOF on extension and frames the extension payload\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: OK_PROOFS }),\n );\n\n await new SendRegisterIdentityTask(api, {\n contactName: \"Alice\",\n scope: \"Arb main\",\n identifier: hexToBytes(\"44\".repeat(20)),\n blockchainFamily: \"ethereum\",\n chainId: 42161n,\n existingContactGroup: {\n groupHandle: hexToBytes(\"cc\".repeat(64)),\n hmacProof: hexToBytes(\"dd\".repeat(32)),\n },\n }).run();\n\n expect(api.sendCommand.mock.calls).toHaveLength(1);\n expect(api.sendCommand.mock.calls[0]![0]).toStrictEqual(\n new RegisterIdentityCommand({ data: EXTENSION_FRAMED_CHUNK, p2: 0x00 }),\n );\n });\n\n it(\"omits the CHAIN_ID TLV when chainId is not provided\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: OK_PROOFS }),\n );\n\n await new SendRegisterIdentityTask(api, {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: hexToBytes(\"00000000000000000000000000000000deadbeef\"),\n blockchainFamily: \"ethereum\",\n }).run();\n\n const command = api.sendCommand.mock\n .calls[0]![0] as RegisterIdentityCommand;\n // No `23 01 ..` CHAIN_ID TLV; BLOCKCHAIN_FAMILY 51 01 01 follows the path.\n const framedHex = Buffer.from(command.args.data).toString(\"hex\");\n expect(framedHex).not.toContain(\"230101\");\n expect(framedHex.endsWith(\"510101\")).toBe(true);\n });\n\n it(\"propagates command-level errors\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n\n const result = await new SendRegisterIdentityTask(api, {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: hexToBytes(\"00000000000000000000000000000000deadbeef\"),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n }).run();\n\n expect(result).toStrictEqual(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n });\n\n it(\"throws on an unsupported blockchain family\", async () => {\n const api = makeApiMock();\n\n await expect(\n new SendRegisterIdentityTask(api, {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: hexToBytes(\"00000000000000000000000000000000deadbeef\"),\n blockchainFamily: \"dogecoin\",\n chainId: 1n,\n }).run(),\n ).rejects.toThrow(/Unsupported blockchain family/);\n expect(api.sendCommand).not.toHaveBeenCalled();\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_device_management_kit", "import_RegisterIdentityCommand", "import_SendRegisterIdentityTask", "hexToBytes", "hex", "out", "i", "FRESH_FRAMED_CHUNK", "EXTENSION_FRAMED_CHUNK", "OK_PROOFS", "makeApiMock", "api", "result", "command", "framedHex"]
|
|
7
|
+
}
|
package/lib/cjs/internal/di.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var r=Object.defineProperty;var
|
|
1
|
+
"use strict";var r=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var y=(n,e)=>{for(var t in e)r(n,t,{get:e[t],enumerable:!0})},C=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of c(e))!l.call(n,a)&&a!==t&&r(n,a,{get:()=>e[a],enumerable:!(o=d(e,a))||o.enumerable});return n};var u=n=>C(r({},"__esModule",{value:!0}),n);var M={};y(M,{makeContainer:()=>D});module.exports=u(M);var s=require("inversify"),m=require("./app-binder/di/appBinderModule"),i=require("./externalTypes"),p=require("./use-cases/di/useCaseModule");const D=({dmk:n,sessionId:e,appName:t})=>{const o=new s.Container;return o.bind(i.externalTypes.Dmk).toConstantValue(n),o.bind(i.externalTypes.SessionId).toConstantValue(e),o.bind(i.externalTypes.AppName).toConstantValue(t),o.loadSync((0,m.appBinderModuleFactory)()),o.loadSync((0,p.useCaseModuleFactory)()),o};0&&(module.exports={makeContainer});
|
|
2
2
|
//# sourceMappingURL=di.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/internal/di.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { Container } from \"inversify\";\n\nimport { appBinderModuleFactory } from \"@internal/app-binder/di/appBinderModule\";\nimport { externalTypes } from \"@internal/externalTypes\";\n\ntype MakeContainerProps = {\n dmk: DeviceManagementKit;\n sessionId: DeviceSessionId;\n appName: string;\n};\n\nexport const makeContainer = ({\n dmk,\n sessionId,\n appName,\n}: MakeContainerProps) => {\n const container = new Container();\n\n container.bind<DeviceManagementKit>(externalTypes.Dmk).toConstantValue(dmk);\n container\n .bind<DeviceSessionId>(externalTypes.SessionId)\n .toConstantValue(sessionId);\n container.bind<string>(externalTypes.AppName).toConstantValue(appName);\n\n container.loadSync(appBinderModuleFactory());\n\n return container;\n};\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,IAAA,eAAAC,EAAAH,GAIA,IAAAI,EAA0B,qBAE1BC,EAAuC,mDACvCC,EAA8B,
|
|
6
|
-
"names": ["di_exports", "__export", "makeContainer", "__toCommonJS", "import_inversify", "import_appBinderModule", "import_externalTypes", "dmk", "sessionId", "appName", "container"]
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { Container } from \"inversify\";\n\nimport { appBinderModuleFactory } from \"@internal/app-binder/di/appBinderModule\";\nimport { externalTypes } from \"@internal/externalTypes\";\nimport { useCaseModuleFactory } from \"@internal/use-cases/di/useCaseModule\";\n\ntype MakeContainerProps = {\n dmk: DeviceManagementKit;\n sessionId: DeviceSessionId;\n appName: string;\n};\n\nexport const makeContainer = ({\n dmk,\n sessionId,\n appName,\n}: MakeContainerProps) => {\n const container = new Container();\n\n container.bind<DeviceManagementKit>(externalTypes.Dmk).toConstantValue(dmk);\n container\n .bind<DeviceSessionId>(externalTypes.SessionId)\n .toConstantValue(sessionId);\n container.bind<string>(externalTypes.AppName).toConstantValue(appName);\n\n container.loadSync(appBinderModuleFactory());\n container.loadSync(useCaseModuleFactory());\n\n return container;\n};\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,IAAA,eAAAC,EAAAH,GAIA,IAAAI,EAA0B,qBAE1BC,EAAuC,mDACvCC,EAA8B,mCAC9BC,EAAqC,gDAQ9B,MAAML,EAAgB,CAAC,CAC5B,IAAAM,EACA,UAAAC,EACA,QAAAC,CACF,IAA0B,CACxB,MAAMC,EAAY,IAAI,YAEtB,OAAAA,EAAU,KAA0B,gBAAc,GAAG,EAAE,gBAAgBH,CAAG,EAC1EG,EACG,KAAsB,gBAAc,SAAS,EAC7C,gBAAgBF,CAAS,EAC5BE,EAAU,KAAa,gBAAc,OAAO,EAAE,gBAAgBD,CAAO,EAErEC,EAAU,YAAS,0BAAuB,CAAC,EAC3CA,EAAU,YAAS,wBAAqB,CAAC,EAElCA,CACT",
|
|
6
|
+
"names": ["di_exports", "__export", "makeContainer", "__toCommonJS", "import_inversify", "import_appBinderModule", "import_externalTypes", "import_useCaseModule", "dmk", "sessionId", "appName", "container"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var i=require("./app-binder/ContactsAppBinder"),a=require("./app-binder/di/appBinderTypes"),o=require("./di"),t=require("./externalTypes"),p=require("./use-cases/di/useCaseTypes"),m=require("./use-cases/RegisterExternalAddressUseCase");describe("makeContainer",()=>{const s={},n="session-id",r="Ethereum",e=(0,o.makeContainer)({dmk:s,sessionId:n,appName:r});it("binds dmk, sessionId and appName as external values",()=>{expect(e.get(t.externalTypes.Dmk)).toBe(s),expect(e.get(t.externalTypes.SessionId)).toBe(n),expect(e.get(t.externalTypes.AppName)).toBe(r)}),it("binds the ContactsAppBinder",()=>{expect(e.get(a.appBinderTypes.AppBinder)).toBeInstanceOf(i.ContactsAppBinder)}),it("binds the RegisterExternalAddressUseCase",()=>{expect(e.get(p.useCaseTypes.RegisterExternalAddressUseCase)).toBeInstanceOf(m.RegisterExternalAddressUseCase)})});
|
|
2
2
|
//# sourceMappingURL=di.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/internal/di.test.ts"],
|
|
4
|
-
"sourcesContent": ["import { type DeviceManagementKit } from \"@ledgerhq/device-management-kit\";\n\nimport { ContactsAppBinder } from \"@internal/app-binder/ContactsAppBinder\";\nimport { appBinderTypes } from \"@internal/app-binder/di/appBinderTypes\";\nimport { makeContainer } from \"@internal/di\";\nimport { externalTypes } from \"@internal/externalTypes\";\n\ndescribe(\"makeContainer\", () => {\n const dmk = {} as DeviceManagementKit;\n const sessionId = \"session-id\";\n const appName = \"Ethereum\";\n\n const container = makeContainer({ dmk, sessionId, appName });\n\n it(\"binds dmk, sessionId and appName as external values\", () => {\n expect(container.get(externalTypes.Dmk)).toBe(dmk);\n expect(container.get(externalTypes.SessionId)).toBe(sessionId);\n expect(container.get(externalTypes.AppName)).toBe(appName);\n });\n\n it(\"binds the ContactsAppBinder\", () => {\n expect(container.get(appBinderTypes.AppBinder)).toBeInstanceOf(\n ContactsAppBinder,\n );\n });\n});\n"],
|
|
5
|
-
"mappings": "aAEA,IAAAA,EAAkC,kDAClCC,EAA+B,kDAC/BC,EAA8B,wBAC9BC,EAA8B,
|
|
6
|
-
"names": ["import_ContactsAppBinder", "import_appBinderTypes", "import_di", "import_externalTypes", "dmk", "sessionId", "appName", "container"]
|
|
4
|
+
"sourcesContent": ["import { type DeviceManagementKit } from \"@ledgerhq/device-management-kit\";\n\nimport { ContactsAppBinder } from \"@internal/app-binder/ContactsAppBinder\";\nimport { appBinderTypes } from \"@internal/app-binder/di/appBinderTypes\";\nimport { makeContainer } from \"@internal/di\";\nimport { externalTypes } from \"@internal/externalTypes\";\nimport { useCaseTypes } from \"@internal/use-cases/di/useCaseTypes\";\nimport { RegisterExternalAddressUseCase } from \"@internal/use-cases/RegisterExternalAddressUseCase\";\n\ndescribe(\"makeContainer\", () => {\n const dmk = {} as DeviceManagementKit;\n const sessionId = \"session-id\";\n const appName = \"Ethereum\";\n\n const container = makeContainer({ dmk, sessionId, appName });\n\n it(\"binds dmk, sessionId and appName as external values\", () => {\n expect(container.get(externalTypes.Dmk)).toBe(dmk);\n expect(container.get(externalTypes.SessionId)).toBe(sessionId);\n expect(container.get(externalTypes.AppName)).toBe(appName);\n });\n\n it(\"binds the ContactsAppBinder\", () => {\n expect(container.get(appBinderTypes.AppBinder)).toBeInstanceOf(\n ContactsAppBinder,\n );\n });\n\n it(\"binds the RegisterExternalAddressUseCase\", () => {\n expect(\n container.get(useCaseTypes.RegisterExternalAddressUseCase),\n ).toBeInstanceOf(RegisterExternalAddressUseCase);\n });\n});\n"],
|
|
5
|
+
"mappings": "aAEA,IAAAA,EAAkC,kDAClCC,EAA+B,kDAC/BC,EAA8B,wBAC9BC,EAA8B,mCAC9BC,EAA6B,+CAC7BC,EAA+C,8DAE/C,SAAS,gBAAiB,IAAM,CAC9B,MAAMC,EAAM,CAAC,EACPC,EAAY,aACZC,EAAU,WAEVC,KAAY,iBAAc,CAAE,IAAAH,EAAK,UAAAC,EAAW,QAAAC,CAAQ,CAAC,EAE3D,GAAG,sDAAuD,IAAM,CAC9D,OAAOC,EAAU,IAAI,gBAAc,GAAG,CAAC,EAAE,KAAKH,CAAG,EACjD,OAAOG,EAAU,IAAI,gBAAc,SAAS,CAAC,EAAE,KAAKF,CAAS,EAC7D,OAAOE,EAAU,IAAI,gBAAc,OAAO,CAAC,EAAE,KAAKD,CAAO,CAC3D,CAAC,EAED,GAAG,8BAA+B,IAAM,CACtC,OAAOC,EAAU,IAAI,iBAAe,SAAS,CAAC,EAAE,eAC9C,mBACF,CACF,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,OACEA,EAAU,IAAI,eAAa,8BAA8B,CAC3D,EAAE,eAAe,gCAA8B,CACjD,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["import_ContactsAppBinder", "import_appBinderTypes", "import_di", "import_externalTypes", "import_useCaseTypes", "import_RegisterExternalAddressUseCase", "dmk", "sessionId", "appName", "container"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var o=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var f=(t,r)=>{for(var e in r)o(t,e,{get:r[e],enumerable:!0})},l=(t,r,e,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let p of y(r))!B.call(t,p)&&p!==e&&o(t,p,{get:()=>r[p],enumerable:!(n=c(r,p))||n.enumerable});return t};var x=t=>l(o({},"__esModule",{value:!0}),t),s=(t,r,e,n)=>{for(var p=n>1?void 0:n?c(r,e):r,m=t.length-1,a;m>=0;m--)(a=t[m])&&(p=(n?a(r,e,p):a(p))||p);return n&&p&&o(r,e,p),p},u=(t,r)=>(e,n)=>r(e,n,t);var R={};f(R,{RegisterExternalAddressUseCase:()=>i});module.exports=x(R);var d=require("inversify"),A=require("../app-binder/di/appBinderTypes");let i=class{constructor(r){this.appBinder=r}execute(r){return this.appBinder.registerExternalAddress(r)}};i=s([(0,d.injectable)(),u(0,(0,d.inject)(A.appBinderTypes.AppBinder))],i);0&&(module.exports={RegisterExternalAddressUseCase});
|
|
2
|
+
//# sourceMappingURL=RegisterExternalAddressUseCase.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/internal/use-cases/RegisterExternalAddressUseCase.ts"],
|
|
4
|
+
"sourcesContent": ["import { inject, injectable } from \"inversify\";\n\nimport { type RegisterExternalAddressDAReturnType } from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nimport { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { ContactsAppBinder } from \"@internal/app-binder/ContactsAppBinder\";\nimport { appBinderTypes } from \"@internal/app-binder/di/appBinderTypes\";\n\n/**\n * Delegates to `ContactsAppBinder`, which uses its injected `dmk`, `sessionId`,\n * and `appName` to construct and execute the `RegisterExternalAddressDeviceAction`.\n *\n * Caller-input validation is intentionally NOT done here: the public API returns\n * a device action, so validation lives inside the device action and surfaces as\n * a typed terminal error state on the observable rather than a synchronous throw.\n */\n@injectable()\nexport class RegisterExternalAddressUseCase {\n constructor(\n @inject(appBinderTypes.AppBinder)\n private readonly appBinder: ContactsAppBinder,\n ) {}\n\n execute(\n input: RegisterExternalAddressInput,\n ): RegisterExternalAddressDAReturnType {\n return this.appBinder.registerExternalAddress(input);\n }\n}\n"],
|
|
5
|
+
"mappings": "okBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAmC,qBAKnCC,EAA+B,kDAWxB,IAAMC,EAAN,KAAqC,CAC1C,YAEmBC,EACjB,CADiB,eAAAA,CAChB,CAEH,QACEC,EACqC,CACrC,OAAO,KAAK,UAAU,wBAAwBA,CAAK,CACrD,CACF,EAXaF,EAANG,EAAA,IADN,cAAW,EAGPC,EAAA,eAAO,iBAAe,SAAS,IAFvBJ",
|
|
6
|
+
"names": ["RegisterExternalAddressUseCase_exports", "__export", "RegisterExternalAddressUseCase", "__toCommonJS", "import_inversify", "import_appBinderTypes", "RegisterExternalAddressUseCase", "appBinder", "input", "__decorateClass", "__decorateParam"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var a=require("./RegisterExternalAddressUseCase");function r(){const e=vi.fn().mockReturnValue("DA_RETURN"),t={registerExternalAddress:e};return{useCase:new a.RegisterExternalAddressUseCase(t),registerExternalAddress:e}}const s={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n};describe("RegisterExternalAddressUseCase",()=>{it("delegates to the app binder",()=>{const{useCase:e,registerExternalAddress:t}=r(),n=e.execute(s);expect(t).toHaveBeenCalledWith(s),expect(n).toBe("DA_RETURN")}),it("does not validate \u2014 invalid input is forwarded, not thrown",()=>{const{useCase:e,registerExternalAddress:t}=r(),n={...s,contactName:""};expect(()=>e.execute(n)).not.toThrow(),expect(t).toHaveBeenCalledWith(n)})});
|
|
2
|
+
//# sourceMappingURL=RegisterExternalAddressUseCase.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/internal/use-cases/RegisterExternalAddressUseCase.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { type ContactsAppBinder } from \"@internal/app-binder/ContactsAppBinder\";\n\nimport { RegisterExternalAddressUseCase } from \"./RegisterExternalAddressUseCase\";\n\nfunction makeUseCase() {\n const registerExternalAddress = vi.fn().mockReturnValue(\"DA_RETURN\");\n const appBinder = { registerExternalAddress } as unknown as ContactsAppBinder;\n return {\n useCase: new RegisterExternalAddressUseCase(appBinder),\n registerExternalAddress,\n };\n}\n\nconst VALID_INPUT: RegisterExternalAddressInput = {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\ndescribe(\"RegisterExternalAddressUseCase\", () => {\n it(\"delegates to the app binder\", () => {\n const { useCase, registerExternalAddress } = makeUseCase();\n\n const result = useCase.execute(VALID_INPUT);\n\n expect(registerExternalAddress).toHaveBeenCalledWith(VALID_INPUT);\n expect(result).toBe(\"DA_RETURN\");\n });\n\n it(\"does not validate \u2014 invalid input is forwarded, not thrown\", () => {\n // Validation now lives in the device action and surfaces as a typed DA\n // error state; the use case must never throw for bad input.\n const { useCase, registerExternalAddress } = makeUseCase();\n\n const invalidInput = { ...VALID_INPUT, contactName: \"\" };\n expect(() => useCase.execute(invalidInput)).not.toThrow();\n expect(registerExternalAddress).toHaveBeenCalledWith(invalidInput);\n });\n});\n"],
|
|
5
|
+
"mappings": "aAGA,IAAAA,EAA+C,4CAE/C,SAASC,GAAc,CACrB,MAAMC,EAA0B,GAAG,GAAG,EAAE,gBAAgB,WAAW,EAC7DC,EAAY,CAAE,wBAAAD,CAAwB,EAC5C,MAAO,CACL,QAAS,IAAI,iCAA+BC,CAAS,EACrD,wBAAAD,CACF,CACF,CAEA,MAAME,EAA4C,CAChD,YAAa,QACb,MAAO,WACP,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,EACX,EAEA,SAAS,iCAAkC,IAAM,CAC/C,GAAG,8BAA+B,IAAM,CACtC,KAAM,CAAE,QAAAC,EAAS,wBAAAH,CAAwB,EAAID,EAAY,EAEnDK,EAASD,EAAQ,QAAQD,CAAW,EAE1C,OAAOF,CAAuB,EAAE,qBAAqBE,CAAW,EAChE,OAAOE,CAAM,EAAE,KAAK,WAAW,CACjC,CAAC,EAED,GAAG,kEAA8D,IAAM,CAGrE,KAAM,CAAE,QAAAD,EAAS,wBAAAH,CAAwB,EAAID,EAAY,EAEnDM,EAAe,CAAE,GAAGH,EAAa,YAAa,EAAG,EACvD,OAAO,IAAMC,EAAQ,QAAQE,CAAY,CAAC,EAAE,IAAI,QAAQ,EACxD,OAAOL,CAAuB,EAAE,qBAAqBK,CAAY,CACnE,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["import_RegisterExternalAddressUseCase", "makeUseCase", "registerExternalAddress", "appBinder", "VALID_INPUT", "useCase", "result", "invalidInput"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var t=Object.defineProperty;var n=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var l=(e,s)=>{for(var o in s)t(e,o,{get:s[o],enumerable:!0})},u=(e,s,o,a)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of p(s))!C.call(e,r)&&r!==o&&t(e,r,{get:()=>s[r],enumerable:!(a=n(s,r))||a.enumerable});return e};var f=e=>u(t({},"__esModule",{value:!0}),e);var c={};l(c,{useCaseModuleFactory:()=>x});module.exports=f(c);var d=require("inversify"),i=require("../../use-cases/RegisterExternalAddressUseCase"),m=require("./useCaseTypes");const x=()=>new d.ContainerModule(({bind:e})=>{e(m.useCaseTypes.RegisterExternalAddressUseCase).to(i.RegisterExternalAddressUseCase)});0&&(module.exports={useCaseModuleFactory});
|
|
2
|
+
//# sourceMappingURL=useCaseModule.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/use-cases/di/useCaseModule.ts"],
|
|
4
|
+
"sourcesContent": ["import { ContainerModule } from \"inversify\";\n\nimport { RegisterExternalAddressUseCase } from \"@internal/use-cases/RegisterExternalAddressUseCase\";\n\nimport { useCaseTypes } from \"./useCaseTypes\";\n\nexport const useCaseModuleFactory = () =>\n new ContainerModule(({ bind }) => {\n bind(useCaseTypes.RegisterExternalAddressUseCase).to(\n RegisterExternalAddressUseCase,\n );\n });\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,0BAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAgC,qBAEhCC,EAA+C,8DAE/CC,EAA6B,0BAEtB,MAAMJ,EAAuB,IAClC,IAAI,kBAAgB,CAAC,CAAE,KAAAK,CAAK,IAAM,CAChCA,EAAK,eAAa,8BAA8B,EAAE,GAChD,gCACF,CACF,CAAC",
|
|
6
|
+
"names": ["useCaseModule_exports", "__export", "useCaseModuleFactory", "__toCommonJS", "import_inversify", "import_RegisterExternalAddressUseCase", "import_useCaseTypes", "bind"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var a=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var n=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var x=(s,e)=>{for(var t in e)a(s,t,{get:e[t],enumerable:!0})},C=(s,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of n(e))!l.call(s,r)&&r!==t&&a(s,r,{get:()=>e[r],enumerable:!(o=d(e,r))||o.enumerable});return s};var c=s=>C(a({},"__esModule",{value:!0}),s);var i={};x(i,{useCaseTypes:()=>g});module.exports=c(i);const g={RegisterExternalAddressUseCase:Symbol.for("RegisterExternalAddressUseCase")};0&&(module.exports={useCaseTypes});
|
|
2
|
+
//# sourceMappingURL=useCaseTypes.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/use-cases/di/useCaseTypes.ts"],
|
|
4
|
+
"sourcesContent": ["export const useCaseTypes = {\n RegisterExternalAddressUseCase: Symbol.for(\"RegisterExternalAddressUseCase\"),\n} as const;\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,kBAAAE,IAAA,eAAAC,EAAAH,GAAO,MAAME,EAAe,CAC1B,+BAAgC,OAAO,IAAI,gCAAgC,CAC7E",
|
|
6
|
+
"names": ["useCaseTypes_exports", "__export", "useCaseTypes", "__toCommonJS"]
|
|
7
|
+
}
|
package/lib/cjs/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
+
"@ledgerhq/signer-utils": "workspace:*",
|
|
3
4
|
"inversify": "catalog:",
|
|
4
5
|
"purify-ts": "catalog:",
|
|
5
6
|
"reflect-metadata": "catalog:",
|
|
@@ -57,5 +58,5 @@
|
|
|
57
58
|
"watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
|
|
58
59
|
"watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\""
|
|
59
60
|
},
|
|
60
|
-
"version": "0.0.0-develop-
|
|
61
|
+
"version": "0.0.0-develop-20260828024102"
|
|
61
62
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=RegisterExternalAddressDeviceActionTypes.js.map
|