@ledgerhq/device-contacts-kit 0.0.0-develop-20260827155839 → 0.0.0-develop-20260829001241
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 +57 -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/app-binder/RenameContactDeviceActionTypes.js +2 -0
- package/lib/cjs/api/app-binder/RenameContactDeviceActionTypes.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/api/model/RenameContact.js +2 -0
- package/lib/cjs/api/model/RenameContact.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/command/RenameContactCommand.js +2 -0
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.js.map +7 -0
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.test.js +2 -0
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.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/RenameContact/RenameContactDeviceAction.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/validateRenameContactInput.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/validateRenameContactInput.js.map +7 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/validateRenameContactInput.test.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/RenameContact/validateRenameContactInput.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__/setupGoToDashboardDAMock.js +2 -0
- package/lib/cjs/internal/app-binder/device-action/__test-utils__/setupGoToDashboardDAMock.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/app-binder/task/SendRenameContactTask.js +2 -0
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.js.map +7 -0
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.test.js +2 -0
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.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/RenameContactUseCase.js +2 -0
- package/lib/cjs/internal/use-cases/RenameContactUseCase.js.map +7 -0
- package/lib/cjs/internal/use-cases/RenameContactUseCase.test.js +2 -0
- package/lib/cjs/internal/use-cases/RenameContactUseCase.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/app-binder/RenameContactDeviceActionTypes.js +1 -0
- package/lib/esm/api/app-binder/RenameContactDeviceActionTypes.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/api/model/RenameContact.js +1 -0
- package/lib/esm/api/model/RenameContact.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/command/RenameContactCommand.js +2 -0
- package/lib/esm/internal/app-binder/command/RenameContactCommand.js.map +7 -0
- package/lib/esm/internal/app-binder/command/RenameContactCommand.test.js +2 -0
- package/lib/esm/internal/app-binder/command/RenameContactCommand.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/RenameContact/RenameContactDeviceAction.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.js.map +7 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.test.js +2 -0
- package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.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__/setupGoToDashboardDAMock.js +2 -0
- package/lib/esm/internal/app-binder/device-action/__test-utils__/setupGoToDashboardDAMock.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/app-binder/task/SendRenameContactTask.js +2 -0
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.js.map +7 -0
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.test.js +2 -0
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.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/RenameContactUseCase.js +2 -0
- package/lib/esm/internal/use-cases/RenameContactUseCase.js.map +7 -0
- package/lib/esm/internal/use-cases/RenameContactUseCase.test.js +2 -0
- package/lib/esm/internal/use-cases/RenameContactUseCase.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 +23 -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/app-binder/RenameContactDeviceActionTypes.d.ts +25 -0
- package/lib/types/api/app-binder/RenameContactDeviceActionTypes.d.ts.map +1 -0
- package/lib/types/api/index.d.ts +4 -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/api/model/RenameContact.d.ts +39 -0
- package/lib/types/api/model/RenameContact.d.ts.map +1 -0
- package/lib/types/internal/DefaultContactsManager.d.ts +8 -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 +7 -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/command/RenameContactCommand.d.ts +25 -0
- package/lib/types/internal/app-binder/command/RenameContactCommand.d.ts.map +1 -0
- package/lib/types/internal/app-binder/command/RenameContactCommand.test.d.ts +2 -0
- package/lib/types/internal/app-binder/command/RenameContactCommand.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/RenameContact/RenameContactDeviceAction.d.ts +13 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.d.ts +2 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/validateRenameContactInput.d.ts +12 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/validateRenameContactInput.d.ts.map +1 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/validateRenameContactInput.test.d.ts +2 -0
- package/lib/types/internal/app-binder/device-action/RenameContact/validateRenameContactInput.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__/setupGoToDashboardDAMock.d.ts +12 -0
- package/lib/types/internal/app-binder/device-action/__test-utils__/setupGoToDashboardDAMock.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 +31 -8
- package/lib/types/internal/app-binder/isContactsSupportedForSession.d.ts.map +1 -1
- package/lib/types/internal/app-binder/model/contactsConstants.d.ts +39 -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/app-binder/task/SendRenameContactTask.d.ts +20 -0
- package/lib/types/internal/app-binder/task/SendRenameContactTask.d.ts.map +1 -0
- package/lib/types/internal/app-binder/task/SendRenameContactTask.test.d.ts +2 -0
- package/lib/types/internal/app-binder/task/SendRenameContactTask.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/RenameContactUseCase.d.ts +19 -0
- package/lib/types/internal/use-cases/RenameContactUseCase.d.ts.map +1 -0
- package/lib/types/internal/use-cases/RenameContactUseCase.test.d.ts +2 -0
- package/lib/types/internal/use-cases/RenameContactUseCase.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 +5 -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 +7 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/internal/DefaultContactsManager.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Container } from \"inversify\";\n\nimport { type ContactsManager } from \"@api/ContactsManager\";\nimport { makeContainer } from \"@internal/di\";\n\ntype DefaultContactsManagerConstructorArgs = {\n dmk: DeviceManagementKit;\n sessionId: DeviceSessionId;\n appName: string;\n};\n\nexport class DefaultContactsManager implements ContactsManager {\n private readonly _container: Container;\n\n constructor({\n dmk,\n sessionId,\n appName,\n }: DefaultContactsManagerConstructorArgs) {\n this._container = makeContainer({ dmk, sessionId, appName });\n }\n\n /**\n * Exposes the DI container so operation methods
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["makeContainer", "DefaultContactsManager", "dmk", "sessionId", "appName"]
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Container } from \"inversify\";\n\nimport { type RegisterExternalAddressDAReturnType } from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nimport { type RenameContactDAReturnType } from \"@api/app-binder/RenameContactDeviceActionTypes\";\nimport { type ContactsManager } from \"@api/ContactsManager\";\nimport { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { type RenameContactInput } from \"@api/model/RenameContact\";\nimport { makeContainer } from \"@internal/di\";\nimport { useCaseTypes } from \"@internal/use-cases/di/useCaseTypes\";\nimport { type RegisterExternalAddressUseCase } from \"@internal/use-cases/RegisterExternalAddressUseCase\";\nimport { type RenameContactUseCase } from \"@internal/use-cases/RenameContactUseCase\";\n\ntype DefaultContactsManagerConstructorArgs = {\n dmk: DeviceManagementKit;\n sessionId: DeviceSessionId;\n appName: string;\n};\n\nexport class DefaultContactsManager implements ContactsManager {\n private readonly _container: Container;\n\n constructor({\n dmk,\n sessionId,\n appName,\n }: DefaultContactsManagerConstructorArgs) {\n this._container = makeContainer({ dmk, sessionId, appName });\n }\n\n registerExternalAddress(\n input: RegisterExternalAddressInput,\n ): RegisterExternalAddressDAReturnType {\n return this._container\n .get<RegisterExternalAddressUseCase>(\n useCaseTypes.RegisterExternalAddressUseCase,\n )\n .execute(input);\n }\n\n renameContact(input: RenameContactInput): RenameContactDAReturnType {\n return this._container\n .get<RenameContactUseCase>(useCaseTypes.RenameContactUseCase)\n .execute(input);\n }\n\n /**\n * Exposes the DI container so future operation methods can resolve their\n * `UseCase`. Not part of the public API.\n */\n protected get container(): Container {\n return this._container;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAWA,OAAS,iBAAAA,MAAqB,eAC9B,OAAS,gBAAAC,MAAoB,sCAUtB,MAAMC,CAAkD,CAC5C,WAEjB,YAAY,CACV,IAAAC,EACA,UAAAC,EACA,QAAAC,CACF,EAA0C,CACxC,KAAK,WAAaL,EAAc,CAAE,IAAAG,EAAK,UAAAC,EAAW,QAAAC,CAAQ,CAAC,CAC7D,CAEA,wBACEC,EACqC,CACrC,OAAO,KAAK,WACT,IACCL,EAAa,8BACf,EACC,QAAQK,CAAK,CAClB,CAEA,cAAcA,EAAsD,CAClE,OAAO,KAAK,WACT,IAA0BL,EAAa,oBAAoB,EAC3D,QAAQK,CAAK,CAClB,CAMA,IAAc,WAAuB,CACnC,OAAO,KAAK,UACd,CACF",
|
|
6
|
+
"names": ["makeContainer", "useCaseTypes", "DefaultContactsManager", "dmk", "sessionId", "appName", "input"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{DefaultContactsManager as i}from"./DefaultContactsManager";const o={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n},c={previousContactName:"Alice",newContactName:"Bob",groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221)};describe("DefaultContactsManager",()=>{it("registerExternalAddress flows manager -> use-case -> binder -> dmk.executeDeviceAction",()=>{const e=vi.fn().mockReturnValue("DA_RETURN"),n={executeDeviceAction:e},a=new i({dmk:n,sessionId:"session-id",appName:"Ethereum"}).registerExternalAddress(o);expect(e).toHaveBeenCalledTimes(1);const t=e.mock.calls[0][0];expect(t.sessionId).toBe("session-id"),expect(t.deviceAction).toBeDefined(),expect(a).toBe("DA_RETURN")}),it("does not throw on invalid input \u2014 it dispatches the device action, which surfaces the error",()=>{const e=vi.fn().mockReturnValue("DA_RETURN"),n={executeDeviceAction:e},s=new i({dmk:n,sessionId:"session-id",appName:"Ethereum"});expect(()=>s.registerExternalAddress({...o,contactName:""})).not.toThrow(),expect(e).toHaveBeenCalledTimes(1)}),it("renameContact flows manager -> use-case -> binder -> dmk.executeDeviceAction",()=>{const e=vi.fn().mockReturnValue("DA_RETURN"),n={executeDeviceAction:e},a=new i({dmk:n,sessionId:"session-id",appName:"Ethereum"}).renameContact(c);expect(e).toHaveBeenCalledTimes(1);const t=e.mock.calls[0][0];expect(t.sessionId).toBe("session-id"),expect(t.deviceAction).toBeDefined(),expect(a).toBe("DA_RETURN")})});
|
|
2
|
+
//# sourceMappingURL=DefaultContactsManager.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/internal/DefaultContactsManager.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { type DeviceManagementKit } from \"@ledgerhq/device-management-kit\";\n\nimport { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { type RenameContactInput } from \"@api/model/RenameContact\";\n\nimport { DefaultContactsManager } from \"./DefaultContactsManager\";\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\nconst VALID_RENAME_INPUT: RenameContactInput = {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n};\n\ndescribe(\"DefaultContactsManager\", () => {\n it(\"registerExternalAddress flows manager -> use-case -> binder -> dmk.executeDeviceAction\", () => {\n const executeDeviceAction = vi.fn().mockReturnValue(\"DA_RETURN\");\n const dmk = { executeDeviceAction } as unknown as DeviceManagementKit;\n\n const manager = new DefaultContactsManager({\n dmk,\n sessionId: \"session-id\",\n appName: \"Ethereum\",\n });\n\n const result = manager.registerExternalAddress(VALID_INPUT);\n\n expect(executeDeviceAction).toHaveBeenCalledTimes(1);\n const call = executeDeviceAction.mock.calls[0]![0] as {\n sessionId: string;\n deviceAction: unknown;\n };\n expect(call.sessionId).toBe(\"session-id\");\n expect(call.deviceAction).toBeDefined();\n expect(result).toBe(\"DA_RETURN\");\n });\n\n it(\"does not throw on invalid input \u2014 it dispatches the device action, which surfaces the error\", () => {\n // The public API returns a device action; invalid caller input must reach\n // the observable as a typed error state rather than throwing synchronously.\n const executeDeviceAction = vi.fn().mockReturnValue(\"DA_RETURN\");\n const dmk = { executeDeviceAction } as unknown as DeviceManagementKit;\n\n const manager = new DefaultContactsManager({\n dmk,\n sessionId: \"session-id\",\n appName: \"Ethereum\",\n });\n\n expect(() =>\n manager.registerExternalAddress({\n ...VALID_INPUT,\n contactName: \"\",\n }),\n ).not.toThrow();\n expect(executeDeviceAction).toHaveBeenCalledTimes(1);\n });\n\n it(\"renameContact flows manager -> use-case -> binder -> dmk.executeDeviceAction\", () => {\n const executeDeviceAction = vi.fn().mockReturnValue(\"DA_RETURN\");\n const dmk = { executeDeviceAction } as unknown as DeviceManagementKit;\n\n const manager = new DefaultContactsManager({\n dmk,\n sessionId: \"session-id\",\n appName: \"Ethereum\",\n });\n\n const result = manager.renameContact(VALID_RENAME_INPUT);\n\n expect(executeDeviceAction).toHaveBeenCalledTimes(1);\n const call = executeDeviceAction.mock.calls[0]![0] as {\n sessionId: string;\n deviceAction: unknown;\n };\n expect(call.sessionId).toBe(\"session-id\");\n expect(call.deviceAction).toBeDefined();\n expect(result).toBe(\"DA_RETURN\");\n });\n});\n"],
|
|
5
|
+
"mappings": "AAKA,OAAS,0BAAAA,MAA8B,2BAEvC,MAAMC,EAA4C,CAChD,YAAa,QACb,MAAO,WACP,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,EACX,EAEMC,EAAyC,CAC7C,oBAAqB,QACrB,eAAgB,MAChB,YAAa,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,EACzC,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CACzC,EAEA,SAAS,yBAA0B,IAAM,CACvC,GAAG,yFAA0F,IAAM,CACjG,MAAMC,EAAsB,GAAG,GAAG,EAAE,gBAAgB,WAAW,EACzDC,EAAM,CAAE,oBAAAD,CAAoB,EAQ5BE,EANU,IAAIL,EAAuB,CACzC,IAAAI,EACA,UAAW,aACX,QAAS,UACX,CAAC,EAEsB,wBAAwBH,CAAW,EAE1D,OAAOE,CAAmB,EAAE,sBAAsB,CAAC,EACnD,MAAMG,EAAOH,EAAoB,KAAK,MAAM,CAAC,EAAG,CAAC,EAIjD,OAAOG,EAAK,SAAS,EAAE,KAAK,YAAY,EACxC,OAAOA,EAAK,YAAY,EAAE,YAAY,EACtC,OAAOD,CAAM,EAAE,KAAK,WAAW,CACjC,CAAC,EAED,GAAG,mGAA+F,IAAM,CAGtG,MAAMF,EAAsB,GAAG,GAAG,EAAE,gBAAgB,WAAW,EACzDC,EAAM,CAAE,oBAAAD,CAAoB,EAE5BI,EAAU,IAAIP,EAAuB,CACzC,IAAAI,EACA,UAAW,aACX,QAAS,UACX,CAAC,EAED,OAAO,IACLG,EAAQ,wBAAwB,CAC9B,GAAGN,EACH,YAAa,EACf,CAAC,CACH,EAAE,IAAI,QAAQ,EACd,OAAOE,CAAmB,EAAE,sBAAsB,CAAC,CACrD,CAAC,EAED,GAAG,+EAAgF,IAAM,CACvF,MAAMA,EAAsB,GAAG,GAAG,EAAE,gBAAgB,WAAW,EACzDC,EAAM,CAAE,oBAAAD,CAAoB,EAQ5BE,EANU,IAAIL,EAAuB,CACzC,IAAAI,EACA,UAAW,aACX,QAAS,UACX,CAAC,EAEsB,cAAcF,CAAkB,EAEvD,OAAOC,CAAmB,EAAE,sBAAsB,CAAC,EACnD,MAAMG,EAAOH,EAAoB,KAAK,MAAM,CAAC,EAAG,CAAC,EAIjD,OAAOG,EAAK,SAAS,EAAE,KAAK,YAAY,EACxC,OAAOA,EAAK,YAAY,EAAE,YAAY,EACtC,OAAOD,CAAM,EAAE,KAAK,WAAW,CACjC,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["DefaultContactsManager", "VALID_INPUT", "VALID_RENAME_INPUT", "executeDeviceAction", "dmk", "result", "call", "manager"]
|
|
7
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var d=(i,e,n,t)=>{for(var r=t>1?void 0:t?y(e,n):e,m=i.length-1,a;m>=0;m--)(a=i[m])&&(r=(t?a(e,n,r):a(r))||r);return t&&r&&u(e,n,r),r},s=(i,e)=>(n,t)=>e(n,t,i);import{inject as p,injectable as A}from"inversify";import{RegisterExternalAddressDeviceAction as R}from"../app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction";import{RenameContactDeviceAction as D}from"../app-binder/device-action/RenameContact/RenameContactDeviceAction";import{externalTypes as c}from"../externalTypes";let o=class{constructor(e,n,t){this.dmk=e;this.sessionId=n;this.appName=t}registerExternalAddress(e){return this.dmk.executeDeviceAction({sessionId:this.sessionId,deviceAction:new R({input:{...e,appName:this.appName}})})}renameContact(e){return this.dmk.executeDeviceAction({sessionId:this.sessionId,deviceAction:new D({input:e})})}};o=d([A(),s(0,p(c.Dmk)),s(1,p(c.SessionId)),s(2,p(c.AppName))],o);export{o as ContactsAppBinder};
|
|
2
2
|
//# sourceMappingURL=ContactsAppBinder.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/internal/app-binder/ContactsAppBinder.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { inject, injectable } from \"inversify\";\n\nimport { externalTypes } from \"@internal/externalTypes\";\n\n/**\n * Constructs and executes Contacts `DeviceAction`s using the injected `dmk`,\n * `sessionId`, and `appName`.
|
|
5
|
-
"mappings": "iOAIA,OAAS,UAAAA,EAAQ,cAAAC,MAAkB,
|
|
6
|
-
"names": ["inject", "injectable", "externalTypes", "ContactsAppBinder", "dmk", "sessionId", "appName", "__decorateClass", "injectable", "__decorateParam", "inject", "externalTypes"]
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceManagementKit,\n type DeviceSessionId,\n} from \"@ledgerhq/device-management-kit\";\nimport { inject, injectable } from \"inversify\";\n\nimport { type RegisterExternalAddressDAReturnType } from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nimport { type RenameContactDAReturnType } from \"@api/app-binder/RenameContactDeviceActionTypes\";\nimport { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { type RenameContactInput } from \"@api/model/RenameContact\";\nimport { RegisterExternalAddressDeviceAction } from \"@internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction\";\nimport { RenameContactDeviceAction } from \"@internal/app-binder/device-action/RenameContact/RenameContactDeviceAction\";\nimport { externalTypes } from \"@internal/externalTypes\";\n\n/**\n * Constructs and executes Contacts `DeviceAction`s using the injected `dmk`,\n * `sessionId`, and `appName`. Each Address Book operation gets one method here.\n */\n@injectable()\nexport class ContactsAppBinder {\n constructor(\n @inject(externalTypes.Dmk)\n protected readonly dmk: DeviceManagementKit,\n @inject(externalTypes.SessionId)\n protected readonly sessionId: DeviceSessionId,\n @inject(externalTypes.AppName)\n protected readonly appName: string,\n ) {}\n\n registerExternalAddress(\n input: RegisterExternalAddressInput,\n ): RegisterExternalAddressDAReturnType {\n return this.dmk.executeDeviceAction({\n sessionId: this.sessionId,\n deviceAction: new RegisterExternalAddressDeviceAction({\n input: { ...input, appName: this.appName },\n }),\n });\n }\n\n renameContact(input: RenameContactInput): RenameContactDAReturnType {\n // Rename is a dashboard operation: `appName` is intentionally not passed \u2014\n // the OS serves the command and there is no app to open.\n return this.dmk.executeDeviceAction({\n sessionId: this.sessionId,\n deviceAction: new RenameContactDeviceAction({ input }),\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "iOAIA,OAAS,UAAAA,EAAQ,cAAAC,MAAkB,YAMnC,OAAS,uCAAAC,MAA2C,iGACpD,OAAS,6BAAAC,MAAiC,6EAC1C,OAAS,iBAAAC,MAAqB,0BAOvB,IAAMC,EAAN,KAAwB,CAC7B,YAEqBC,EAEAC,EAEAC,EACnB,CALmB,SAAAF,EAEA,eAAAC,EAEA,aAAAC,CAClB,CAEH,wBACEC,EACqC,CACrC,OAAO,KAAK,IAAI,oBAAoB,CAClC,UAAW,KAAK,UAChB,aAAc,IAAIC,EAAoC,CACpD,MAAO,CAAE,GAAGD,EAAO,QAAS,KAAK,OAAQ,CAC3C,CAAC,CACH,CAAC,CACH,CAEA,cAAcA,EAAsD,CAGlE,OAAO,KAAK,IAAI,oBAAoB,CAClC,UAAW,KAAK,UAChB,aAAc,IAAIE,EAA0B,CAAE,MAAAF,CAAM,CAAC,CACvD,CAAC,CACH,CACF,EA7BaJ,EAANO,EAAA,CADNC,EAAW,EAGPC,EAAA,EAAAC,EAAOC,EAAc,GAAG,GAExBF,EAAA,EAAAC,EAAOC,EAAc,SAAS,GAE9BF,EAAA,EAAAC,EAAOC,EAAc,OAAO,IANpBX",
|
|
6
|
+
"names": ["inject", "injectable", "RegisterExternalAddressDeviceAction", "RenameContactDeviceAction", "externalTypes", "ContactsAppBinder", "dmk", "sessionId", "appName", "input", "RegisterExternalAddressDeviceAction", "RenameContactDeviceAction", "__decorateClass", "injectable", "__decorateParam", "inject", "externalTypes"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ApduBuilder as u,ApduParser as y,CommandResultFactory as t,InvalidStatusWordError as n}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as c}from"@ledgerhq/signer-utils";import{Maybe as C}from"purify-ts";import{CONTACTS_APDU_CLA as g,CONTACTS_APDU_INS as l,GROUP_HANDLE_BYTES as R,HMAC_PROOF_BYTES as A,HMAC_REST_BYTES as f,SUB_CMD_REGISTER_IDENTITY as E}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as _,contactsCommandErrorFactory as T}from"../../app-binder/model/contactsErrors";const p=45;function a(d,r){const e=d.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class x{name="registerIdentity";args;errorHelper=new c(_,T);constructor(r){this.args=r}getApdu(){return new u({cla:g,ins:l,p1:E,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return C.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new y(r),o=e.extract8BitUInt();if(o!==p)return t({error:new n(`Expected struct_type 0x${p.toString(16)}, got ${o===void 0?"undefined":`0x${o.toString(16)}`}`)});const s=a(e,R);if(!s)return t({error:new n("group_handle missing or truncated")});const i=a(e,A);if(!i)return t({error:new n("hmac_name missing or truncated")});const m=a(e,f);return m?t({data:{groupHandle:s,hmacProof:i,hmacRest:m}}):t({error:new n("hmac_rest missing or truncated")})})}}export{x as RegisterIdentityCommand};
|
|
2
|
+
//# sourceMappingURL=RegisterIdentityCommand.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/RegisterIdentityCommand.ts"],
|
|
4
|
+
"sourcesContent": ["// Register Identity (register external address) \u2014 sub-command P1=0x01 of the\n// address-book APDU (CLA 0xB0 / INS 0x10). Caller (SendRegisterIdentityTask +\n// sendFramedContactsPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk and, on\n// the final chunk, parses the 129-byte response: struct_type(0x2d) +\n// group_handle(64) + hmac_proof(32) + hmac_rest(32). Intermediate chunks ack\n// with SW=0x9000 and no data.\n// Protocol: Address Book Final Specifications \u2014 Register Identity.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n GROUP_HANDLE_BYTES,\n HMAC_PROOF_BYTES,\n HMAC_REST_BYTES,\n SUB_CMD_REGISTER_IDENTITY,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type RegisterIdentityCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RegisterIdentityCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2d) +\n * group_handle(64) + hmac_proof(32) + hmac_rest(32) there. Intermediate\n * chunks return SW=0x9000 with no data.\n *\n * `hmacProof` is the device's HMAC_PROOF (binds the contact name);\n * `hmacRest` is the HMAC_REST (binds scope + identifier + family).\n */\n readonly groupHandle?: Uint8Array;\n readonly hmacProof?: Uint8Array;\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = 0x2d;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RegisterIdentityCommand\n implements\n Command<\n RegisterIdentityCommandResponse,\n RegisterIdentityCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"registerIdentity\";\n readonly args: RegisterIdentityCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n RegisterIdentityCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: RegisterIdentityCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_REGISTER_IDENTITY,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RegisterIdentityCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const groupHandle = extractField(parser, GROUP_HANDLE_BYTES);\n if (!groupHandle) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"group_handle missing or truncated\",\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_PROOF_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { groupHandle, hmacProof, hmacRest },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,sBAAAC,EACA,oBAAAC,EACA,mBAAAC,EACA,6BAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CAuBP,MAAMC,EAAuB,GAO7B,SAASC,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,mBACP,KACQ,YAAc,IAAIf,EAGjCQ,EAAqBC,CAA2B,EAElD,YAAYO,EAAmC,CAC7C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIpB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAII,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EACoE,CACpE,OAAOhB,EAAM,aACX,KAAK,YAAY,SAASgB,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOnB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMc,EAAS,IAAIf,EAAWoB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOZ,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BW,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAcR,EAAaC,EAAQR,CAAkB,EAC3D,GAAI,CAACe,EACH,OAAOrB,EAAqB,CAC1B,MAAO,IAAIC,EACT,mCACF,CACF,CAAC,EAGH,MAAMqB,EAAYT,EAAaC,EAAQP,CAAgB,EACvD,GAAI,CAACe,EACH,OAAOtB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,EAGH,MAAMsB,EAAWV,EAAaC,EAAQN,CAAe,EACrD,OAAKe,EAMEvB,EAAqB,CAC1B,KAAM,CAAE,YAAAqB,EAAa,UAAAC,EAAW,SAAAC,CAAS,CAC3C,CAAC,EAPQvB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "SUB_CMD_REGISTER_IDENTITY", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RegisterIdentityCommand", "args", "response", "structType", "groupHandle", "hmacProof", "hmacRest"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CommandResultStatus as a}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as m,ContactsCommandError as n}from"../../app-binder/model/contactsErrors";import{RegisterIdentityCommand as o}from"./RegisterIdentityCommand";function s(e){const t=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)t[r/2]=parseInt(e.slice(r,r+2),16);return t}const p=s("cc".repeat(64)),u=s("dd".repeat(32)),x=s("aa".repeat(32)),c="2d"+"cc".repeat(64)+"dd".repeat(32)+"aa".repeat(32);function d(e){return{data:Buffer.from(s(e)),statusCode:Buffer.from([144,0])}}describe("RegisterIdentityCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under B0 10 01 with P2=0x00 for the first/only chunk",()=>{const e=Uint8Array.from([0,3,170,187,204]),t=new o({data:e,p2:0}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([176,16,1,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const e=Uint8Array.from([170,187]),t=new o({data:e,p2:128}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([176,16,1,128,2,170,187]))})}),describe("parseResponse",()=>{it("returns an empty payload for an intermediate chunk (SW=0x9000, no data)",()=>{const e=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(e).toStrictEqual({status:a.Success,data:{}})}),it("extracts group_handle / hmac_name / hmac_rest from a register response",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse(d(c));expect(t).toStrictEqual({status:a.Success,data:{groupHandle:p,hmacProof:u,hmacRest:x}})}),it("returns InvalidStatusWordError when struct_type is wrong",()=>{const e="ee"+c.slice(2),r=new o({data:new Uint8Array,p2:0}).parseResponse(d(e));expect(r.status).toBe(a.Error)}),it("maps a known SW (0x6985) to a ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,133])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe("6985"))}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe(m))})})});
|
|
2
|
+
//# sourceMappingURL=RegisterIdentityCommand.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/RegisterIdentityCommand.test.ts"],
|
|
4
|
+
"sourcesContent": ["// RegisterIdentityCommand is a thin chunk-framer: it wraps a pre-framed chunk\n// (2-byte BE length prefix + TLV, assembled by SendRegisterIdentityTask +\n// sendFramedContactsPayload) under B0 10 01 <P2>, and parses the 129-byte\n// register response on the final chunk. TLV byte-parity is asserted in\n// SendRegisterIdentityTask.test.ts.\nimport {\n type ApduResponse,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n ContactsCommandError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RegisterIdentityCommand } from \"./RegisterIdentityCommand\";\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// Device response: struct_type(0x2d) + group_handle(64) + hmac_name(32) +\n// hmac_rest(32).\nconst GROUP_HANDLE = hexToBytes(\"cc\".repeat(64));\nconst HMAC_PROOF = hexToBytes(\"dd\".repeat(32));\nconst HMAC_REST = hexToBytes(\"aa\".repeat(32));\nconst RESPONSE_HEX = \"2d\" + \"cc\".repeat(64) + \"dd\".repeat(32) + \"aa\".repeat(32);\n\nfunction makeResponse(hex: string): ApduResponse {\n return {\n data: Buffer.from(hexToBytes(hex)),\n statusCode: Buffer.from([0x90, 0x00]),\n };\n}\n\ndescribe(\"RegisterIdentityCommand\", () => {\n describe(\"getApdu\", () => {\n it(\"wraps the framed chunk under B0 10 01 with P2=0x00 for the first/only chunk\", () => {\n const data = Uint8Array.from([0x00, 0x03, 0xaa, 0xbb, 0xcc]);\n\n const apdu = new RegisterIdentityCommand({ data, p2: 0x00 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([\n 0xb0, 0x10, 0x01, 0x00, 0x05, 0x00, 0x03, 0xaa, 0xbb, 0xcc,\n ]),\n );\n });\n\n it(\"uses P2=0x80 for continuation chunks\", () => {\n const data = Uint8Array.from([0xaa, 0xbb]);\n\n const apdu = new RegisterIdentityCommand({ data, p2: 0x80 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([0xb0, 0x10, 0x01, 0x80, 0x02, 0xaa, 0xbb]),\n );\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"returns an empty payload for an intermediate chunk (SW=0x9000, no data)\", () => {\n const result = new RegisterIdentityCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x90, 0x00]),\n });\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: {},\n });\n });\n\n it(\"extracts group_handle / hmac_name / hmac_rest from a register response\", () => {\n const command = new RegisterIdentityCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(RESPONSE_HEX));\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: {\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF,\n hmacRest: HMAC_REST,\n },\n });\n });\n\n it(\"returns InvalidStatusWordError when struct_type is wrong\", () => {\n const wrongType = \"ee\" + RESPONSE_HEX.slice(2); // replace 0x2d with 0xee\n const command = new RegisterIdentityCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(wrongType));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"maps a known SW (0x6985) to a ContactsCommandError\", () => {\n const command = new RegisterIdentityCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x85]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\"6985\");\n }\n });\n\n it(\"maps SW=0x6982 to a seed-mismatch ContactsCommandError\", () => {\n // Reached when extending an existing contact whose group handle was\n // registered with another seed (once the app verifies before the UI).\n const command = new RegisterIdentityCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x82]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n );\n }\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CommandResultStatus", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "RegisterIdentityCommand", "hexToBytes", "hex", "out", "i", "GROUP_HANDLE", "HMAC_PROOF", "HMAC_REST", "RESPONSE_HEX", "makeResponse", "data", "apdu", "result", "wrongType"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ApduBuilder as s,ApduParser as C,CommandResultFactory as t,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as p}from"@ledgerhq/signer-utils";import{Maybe as c}from"purify-ts";import{HMAC_NAME_BYTES as i,RENAME_CONTACT_APDU_CLA as u,RENAME_CONTACT_APDU_INS as A,RENAME_CONTACT_P1 as R}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as l,contactsCommandErrorFactory as y}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_CONTACT_NAME as E}from"../../app-binder/services/contactsTlvSerializer";const d=E;function f(o,r){const e=o.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class h{name="renameContact";args;errorHelper=new p(l,y);constructor(r){this.args=r}getApdu(){return new s({cla:u,ins:A,p1:R,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return c.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new C(r),n=e.extract8BitUInt();if(n!==d)return t({error:new m(`Expected struct_type 0x${d.toString(16)}, got ${n===void 0?"undefined":`0x${n.toString(16)}`}`)});const a=f(e,i);return a?t({data:{hmacProof:a}}):t({error:new m("hmac_name missing or truncated")})})}}export{h as RenameContactCommand};
|
|
2
|
+
//# sourceMappingURL=RenameContactCommand.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/RenameContactCommand.ts"],
|
|
4
|
+
"sourcesContent": ["// Rename Contact (EDIT CONTACT NAME) \u2014 the blockchain-agnostic address-book\n// rename. It is dispatched as an OS/dashboard command (CLA 0xE0 / INS 0x2E /\n// P1 0x00), NOT through the embedded app: the caller navigates to the dashboard\n// first (GoToDashboardDeviceAction) so the OS handles it directly.\n// SendRenameContactTask + sendFramedContactsPayload assemble the TLV, prepend\n// the 2-byte BE total length and slice into <=255B chunks; this command frames\n// one chunk and, on the final chunk, parses the 33-byte response:\n// struct_type(0x2e) + rotated hmac_name(32). Intermediate chunks ack with\n// SW=0x9000 and no data.\n//\n// The device is stateless: it verifies the supplied group handle + old-name\n// proof against the seed-derived key (SW 0x6982 on a seed mismatch, before any\n// UI) and, on approval, returns a fresh proof for the new name.\n// Protocol: Address Book Final Specifications \u2014 Edit Contact Name.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n HMAC_NAME_BYTES,\n RENAME_CONTACT_APDU_CLA,\n RENAME_CONTACT_APDU_INS,\n RENAME_CONTACT_P1,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_CONTACT_NAME } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type RenameContactCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RenameContactCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2e) +\n * rotated hmac_name(32) there. Intermediate chunks return SW=0x9000 with no\n * data. This is the replacement group-level name proof.\n */\n readonly hmacProof?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_CONTACT_NAME;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RenameContactCommand\n implements\n Command<\n RenameContactCommandResponse,\n RenameContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"renameContact\";\n readonly args: RenameContactCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n RenameContactCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: RenameContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: RENAME_CONTACT_APDU_CLA,\n ins: RENAME_CONTACT_APDU_INS,\n p1: RENAME_CONTACT_P1,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RenameContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_NAME_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacProof },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAcA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,mBAAAC,EACA,2BAAAC,EACA,2BAAAC,EACA,qBAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CACP,OAAS,iCAAAC,MAAqC,sDAkB9C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gBACP,KACQ,YAAc,IAAId,EAGjCM,EAAqBC,CAA2B,EAElD,YAAYQ,EAAgC,CAC1C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAInB,EAAY,CACrB,IAAKO,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEW,EACiE,CACjE,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOlB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMa,EAAS,IAAId,EAAWmB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOX,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BU,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAYR,EAAaC,EAAQT,CAAe,EACtD,OAAKgB,EAMEpB,EAAqB,CAC1B,KAAM,CAAE,UAAAoB,CAAU,CACpB,CAAC,EAPQpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "HMAC_NAME_BYTES", "RENAME_CONTACT_APDU_CLA", "RENAME_CONTACT_APDU_INS", "RENAME_CONTACT_P1", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "STRUCT_TYPE_EDIT_CONTACT_NAME", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RenameContactCommand", "args", "response", "structType", "hmacProof"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CommandResultStatus as a}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as d,ContactsCommandError as s}from"../../app-binder/model/contactsErrors";import{RenameContactCommand as o}from"./RenameContactCommand";function m(e){const t=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)t[r/2]=parseInt(e.slice(r,r+2),16);return t}const u=m("dd".repeat(32)),c="2e"+"dd".repeat(32);function n(e){return{data:Buffer.from(m(e)),statusCode:Buffer.from([144,0])}}describe("RenameContactCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk",()=>{const e=Uint8Array.from([0,3,170,187,204]),t=new o({data:e,p2:0}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const e=Uint8Array.from([170,187]),t=new o({data:e,p2:128}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,128,2,170,187]))})}),describe("parseResponse",()=>{it("returns an empty payload for an intermediate chunk (SW=0x9000, no data)",()=>{const e=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(e).toStrictEqual({status:a.Success,data:{}})}),it("extracts the rotated hmac_name from an edit-contact-name response",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse(n(c));expect(t).toStrictEqual({status:a.Success,data:{hmacProof:u}})}),it("returns InvalidStatusWordError when struct_type is wrong",()=>{const e="ee"+c.slice(2),r=new o({data:new Uint8Array,p2:0}).parseResponse(n(e));expect(r.status).toBe(a.Error)}),it("returns InvalidStatusWordError when hmac_name is truncated",()=>{const e="2e"+"dd".repeat(16),r=new o({data:new Uint8Array,p2:0}).parseResponse(n(e));expect(r.status).toBe(a.Error)}),it("maps a known SW (0x6985) to a ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,133])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(s),expect(t.error.errorCode).toBe("6985"))}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(s),expect(t.error.errorCode).toBe(d))})})});
|
|
2
|
+
//# sourceMappingURL=RenameContactCommand.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/RenameContactCommand.test.ts"],
|
|
4
|
+
"sourcesContent": ["// RenameContactCommand is a thin chunk-framer for the OS/dashboard EDIT CONTACT\n// NAME command: it wraps a pre-framed chunk (2-byte BE length prefix + TLV,\n// assembled by SendRenameContactTask + sendFramedContactsPayload) under\n// E0 2E 00 <P2>, and parses the 33-byte response on the final chunk. TLV\n// byte-parity is asserted in SendRenameContactTask.test.ts.\nimport {\n type ApduResponse,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n ContactsCommandError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RenameContactCommand } from \"./RenameContactCommand\";\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// Device response: struct_type(0x2e) + rotated hmac_name(32).\nconst HMAC_PROOF = hexToBytes(\"dd\".repeat(32));\nconst RESPONSE_HEX = \"2e\" + \"dd\".repeat(32);\n\nfunction makeResponse(hex: string): ApduResponse {\n return {\n data: Buffer.from(hexToBytes(hex)),\n statusCode: Buffer.from([0x90, 0x00]),\n };\n}\n\ndescribe(\"RenameContactCommand\", () => {\n describe(\"getApdu\", () => {\n it(\"wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk\", () => {\n const data = Uint8Array.from([0x00, 0x03, 0xaa, 0xbb, 0xcc]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x00 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([\n 0xe0, 0x2e, 0x00, 0x00, 0x05, 0x00, 0x03, 0xaa, 0xbb, 0xcc,\n ]),\n );\n });\n\n it(\"uses P2=0x80 for continuation chunks\", () => {\n const data = Uint8Array.from([0xaa, 0xbb]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x80 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([0xe0, 0x2e, 0x00, 0x80, 0x02, 0xaa, 0xbb]),\n );\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"returns an empty payload for an intermediate chunk (SW=0x9000, no data)\", () => {\n const result = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x90, 0x00]),\n });\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: {},\n });\n });\n\n it(\"extracts the rotated hmac_name from an edit-contact-name response\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(RESPONSE_HEX));\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: { hmacProof: HMAC_PROOF },\n });\n });\n\n it(\"returns InvalidStatusWordError when struct_type is wrong\", () => {\n const wrongType = \"ee\" + RESPONSE_HEX.slice(2); // replace 0x2e with 0xee\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(wrongType));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"returns InvalidStatusWordError when hmac_name is truncated\", () => {\n const truncated = \"2e\" + \"dd\".repeat(16); // only 16 of 32 bytes\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(truncated));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"maps a known SW (0x6985) to a ContactsCommandError\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x85]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\"6985\");\n }\n });\n\n it(\"maps SW=0x6982 to a seed-mismatch ContactsCommandError\", () => {\n // The device verifies the supplied group handle + old-name proof against\n // the seed-derived key before any UI, and returns 0x6982 on a mismatch.\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x82]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n );\n }\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CommandResultStatus", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "RenameContactCommand", "hexToBytes", "hex", "out", "i", "HMAC_PROOF", "RESPONSE_HEX", "makeResponse", "data", "apdu", "result", "wrongType", "truncated"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{isSuccessCommandResult as c,OpenAppDeviceAction as u,UnknownDAError as l,UserInteractionRequired as o,WaitForAppAndVersionDeviceAction as A,XStateDeviceAction as g}from"@ledgerhq/device-management-kit";import{Left as m,Right as E}from"purify-ts";import{assign as n,fromPromise as S,setup as R}from"xstate";import{isContactsSupportedForSession as I}from"../../../app-binder/isContactsSupportedForSession";import{ContactsVersionRequirementError as y}from"../../../app-binder/model/contactsErrors";import{SendRegisterIdentityTask as h}from"../../../app-binder/task/SendRegisterIdentityTask";import{validateRegisterExternalAddressInput as D}from"./validateRegisterExternalAddressInput";class O extends g{makeStateMachine(i){const{isSupported:p,registerIdentity:d}=this.extractDependencies(i),r=this.input.appName;return R({types:{input:{},context:{},output:{}},actors:{openAppStateMachine:new u({input:{appName:r}}).makeStateMachine(i),waitForAppAndVersionStateMachine:new A({input:{}}).makeStateMachine(i),registerIdentity:S(({input:e})=>d(e))},guards:{skipOpenApp:({context:e})=>e.input.skipOpenApp===!0,noInternalError:({context:e})=>e._internalState.error===null,contactsSupported:({context:e})=>{const{appAndVersion:t}=e._internalState;return t!==null&&p(t)}},actions:{assignValidationError:n({_internalState:({context:e})=>{const t=D(e.input);return t?{...e._internalState,error:t}:e._internalState}}),assignVersionError:n({_internalState:({context:e})=>({...e._internalState,error:new y})}),assignErrorFromEvent:n({_internalState:({context:e,event:t})=>({...e._internalState,error:new l(t.error instanceof Error?t.error.message:String(t.error))})})}}).createMachine({id:"RegisterExternalAddressDeviceAction",initial:"InitialState",context:({input:e})=>({input:e,intermediateValue:{requiredUserInteraction:o.None},_internalState:{error:null,appAndVersion:null,proofs:null}}),states:{InitialState:{always:[{target:"ValidateInput",guard:"skipOpenApp"},{target:"OpenAppDeviceAction"}]},OpenAppDeviceAction:{invoke:{id:"openAppStateMachine",src:"openAppStateMachine",input:()=>({appName:r}),onSnapshot:{actions:n({intermediateValue:({event:e})=>e.snapshot.context.intermediateValue})},onDone:{target:"CheckOpenAppResult",actions:n({_internalState:({event:e,context:t})=>e.output.caseOf({Right:()=>t._internalState,Left:a=>({...t._internalState,error:a})})})}}},CheckOpenAppResult:{always:[{target:"ValidateInput",guard:"noInternalError"},{target:"Error"}]},ValidateInput:{entry:"assignValidationError",always:[{target:"WaitForAppAndVersion",guard:"noInternalError"},{target:"Error"}]},WaitForAppAndVersion:{entry:n({intermediateValue:{requiredUserInteraction:o.None}}),invoke:{id:"waitForAppAndVersion",src:"waitForAppAndVersionStateMachine",input:()=>({}),onSnapshot:{actions:n({intermediateValue:({event:e})=>e.snapshot.context.intermediateValue})},onDone:{target:"CheckAppAndVersion",actions:n({_internalState:({event:e,context:t})=>e.output.caseOf({Right:a=>({...t._internalState,appAndVersion:{name:a.name,version:a.version}}),Left:a=>({...t._internalState,error:a})})})}}},CheckAppAndVersion:{always:[{target:"VersionGuard",guard:"noInternalError"},{target:"Error"}]},VersionGuard:{always:[{target:"RegisterIdentity",guard:"contactsSupported"},{target:"Error",actions:"assignVersionError"}]},RegisterIdentity:{entry:n({intermediateValue:{requiredUserInteraction:o.RegisterWallet}}),exit:n({intermediateValue:{requiredUserInteraction:o.None}}),invoke:{id:"registerIdentity",src:"registerIdentity",input:({context:e})=>e.input,onDone:{target:"RegisterIdentityResultCheck",actions:n({_internalState:({event:e,context:t})=>c(e.output)?{...t._internalState,proofs:e.output.data}:{...t._internalState,error:e.output.error}})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},RegisterIdentityResultCheck:{always:[{target:"Success",guard:"noInternalError"},{target:"Error"}]},Success:{type:"final"},Error:{type:"final"}},output:({context:e})=>{const{proofs:t,error:a}=e._internalState;if(t){const{input:s}=e;return E({mode:s.existingContactGroup?"existingContactGroup":"newContactGroup",contactName:s.contactName,scope:s.scope,identifier:s.identifier,blockchainFamily:s.blockchainFamily,chainId:s.chainId,groupHandle:t.groupHandle,hmacProof:t.hmacProof,hmacRest:t.hmacRest})}return m(a??new l("No error in final state"))}})}extractDependencies(i){return{isSupported:r=>I(i,r),registerIdentity:r=>new h(i,{contactName:r.contactName,scope:r.scope,identifier:r.identifier,blockchainFamily:r.blockchainFamily,chainId:r.chainId,existingContactGroup:r.existingContactGroup}).run()}}}export{O as RegisterExternalAddressDeviceAction};
|
|
2
|
+
//# sourceMappingURL=RegisterExternalAddressDeviceAction.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceActionStateMachine,\n type InternalApi,\n isSuccessCommandResult,\n OpenAppDeviceAction,\n type StateMachineTypes,\n UnknownDAError,\n UserInteractionRequired,\n WaitForAppAndVersionDeviceAction,\n XStateDeviceAction,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { assign, fromPromise, setup } from \"xstate\";\n\nimport {\n type RegisterExternalAddressDAError,\n type RegisterExternalAddressDAInput,\n type RegisterExternalAddressDAIntermediateValue,\n type RegisterExternalAddressDAInternalState,\n type RegisterExternalAddressDAOutput,\n} from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nimport {\n isContactsSupportedForSession,\n type RunningApp,\n} from \"@internal/app-binder/isContactsSupportedForSession\";\nimport { ContactsVersionRequirementError } from \"@internal/app-binder/model/contactsErrors\";\nimport {\n type RegisterIdentityProofs,\n SendRegisterIdentityTask,\n} from \"@internal/app-binder/task/SendRegisterIdentityTask\";\n\nimport { validateRegisterExternalAddressInput } from \"./validateRegisterExternalAddressInput\";\n\nexport type RegisterExternalAddressMachineDependencies = {\n readonly isSupported: (app: RunningApp) => boolean;\n readonly registerIdentity: (\n input: RegisterExternalAddressDAInput,\n ) => Promise<Awaited<ReturnType<SendRegisterIdentityTask[\"run\"]>>>;\n};\n\nexport class RegisterExternalAddressDeviceAction extends XStateDeviceAction<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAInput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue,\n RegisterExternalAddressDAInternalState\n> {\n makeStateMachine(\n internalApi: InternalApi,\n ): DeviceActionStateMachine<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAInput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue,\n RegisterExternalAddressDAInternalState\n > {\n type types = StateMachineTypes<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAInput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue,\n RegisterExternalAddressDAInternalState\n >;\n\n const { isSupported, registerIdentity } =\n this.extractDependencies(internalApi);\n const appName = this.input.appName;\n\n return setup({\n types: {\n input: {} as types[\"input\"],\n context: {} as types[\"context\"],\n output: {} as types[\"output\"],\n },\n actors: {\n openAppStateMachine: new OpenAppDeviceAction({\n input: { appName },\n }).makeStateMachine(internalApi),\n waitForAppAndVersionStateMachine: new WaitForAppAndVersionDeviceAction({\n input: {},\n }).makeStateMachine(internalApi),\n registerIdentity: fromPromise(\n ({ input }: { input: RegisterExternalAddressDAInput }) =>\n registerIdentity(input),\n ),\n },\n guards: {\n skipOpenApp: ({ context }) => context.input.skipOpenApp === true,\n noInternalError: ({ context }) => context._internalState.error === null,\n contactsSupported: ({ context }) => {\n const { appAndVersion } = context._internalState;\n return appAndVersion !== null && isSupported(appAndVersion);\n },\n },\n actions: {\n assignValidationError: assign({\n _internalState: ({ context }) => {\n const error = validateRegisterExternalAddressInput(context.input);\n return error\n ? { ...context._internalState, error }\n : context._internalState;\n },\n }),\n assignVersionError: assign({\n _internalState: ({ context }) => ({\n ...context._internalState,\n error: new ContactsVersionRequirementError(),\n }),\n }),\n assignErrorFromEvent: assign({\n _internalState: ({ context, event }) => ({\n ...context._internalState,\n error: new UnknownDAError(\n event[\"error\"] instanceof Error\n ? event[\"error\"].message\n : String(event[\"error\"]),\n ),\n }),\n }),\n },\n }).createMachine({\n id: \"RegisterExternalAddressDeviceAction\",\n initial: \"InitialState\",\n context: ({ input }) => ({\n input,\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n _internalState: {\n error: null,\n appAndVersion: null,\n proofs: null,\n },\n }),\n states: {\n InitialState: {\n always: [\n { target: \"ValidateInput\", guard: \"skipOpenApp\" },\n { target: \"OpenAppDeviceAction\" },\n ],\n },\n OpenAppDeviceAction: {\n invoke: {\n id: \"openAppStateMachine\",\n src: \"openAppStateMachine\",\n input: () => ({ appName }),\n onSnapshot: {\n actions: assign({\n intermediateValue: ({ event }) =>\n event.snapshot.context.intermediateValue,\n }),\n },\n onDone: {\n target: \"CheckOpenAppResult\",\n actions: assign({\n _internalState: ({ event, context }) =>\n event.output.caseOf<RegisterExternalAddressDAInternalState>({\n Right: () => context._internalState,\n Left: (error) => ({ ...context._internalState, error }),\n }),\n }),\n },\n },\n },\n CheckOpenAppResult: {\n always: [\n { target: \"ValidateInput\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // Input validation runs inside the device action (after the app is\n // opened) so invalid caller input surfaces as a typed terminal error\n // state on the observable instead of a synchronous throw. Runs on both\n // the open-app and skip-open-app paths.\n ValidateInput: {\n entry: \"assignValidationError\",\n always: [\n { target: \"WaitForAppAndVersion\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // Read the running app + version freshly from the device (rather than\n // the possibly-stale session state) so the version guard evaluates the\n // app that is actually running \u2014 e.g. when open-app is skipped and the\n // app was changed outside DMK. Runs on both paths.\n WaitForAppAndVersion: {\n // Start the phase from a clean value, clearing any interaction left\n // over from the OpenApp phase (e.g. ConfirmOpenApp).\n entry: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n }),\n invoke: {\n id: \"waitForAppAndVersion\",\n src: \"waitForAppAndVersionStateMachine\",\n input: () => ({}),\n // Propagate the child DA's intermediate value so a consuming client\n // can render, e.g., a \"please unlock your device\" prompt when the\n // device is locked. Mirrors the OpenAppDeviceAction invoke above.\n onSnapshot: {\n actions: assign({\n intermediateValue: ({ event }) =>\n event.snapshot.context.intermediateValue,\n }),\n },\n onDone: {\n target: \"CheckAppAndVersion\",\n actions: assign({\n _internalState: ({ event, context }) =>\n event.output.caseOf<RegisterExternalAddressDAInternalState>({\n Right: (appAndVersion) => ({\n ...context._internalState,\n appAndVersion: {\n name: appAndVersion.name,\n version: appAndVersion.version,\n },\n }),\n Left: (error) => ({ ...context._internalState, error }),\n }),\n }),\n },\n },\n },\n CheckAppAndVersion: {\n always: [\n { target: \"VersionGuard\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // Version guard evaluates support from the fresh WaitForAppAndVersion\n // result. Runs on both the open-app and skip-open-app paths.\n VersionGuard: {\n always: [\n { target: \"RegisterIdentity\", guard: \"contactsSupported\" },\n { target: \"Error\", actions: \"assignVersionError\" },\n ],\n },\n RegisterIdentity: {\n entry: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n }),\n exit: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n }),\n invoke: {\n id: \"registerIdentity\",\n src: \"registerIdentity\",\n input: ({ context }) => context.input,\n onDone: {\n target: \"RegisterIdentityResultCheck\",\n actions: assign({\n _internalState: ({ event, context }) =>\n isSuccessCommandResult(event.output)\n ? { ...context._internalState, proofs: event.output.data }\n : {\n ...context._internalState,\n error: event.output.error,\n },\n }),\n },\n onError: {\n target: \"Error\",\n actions: \"assignErrorFromEvent\",\n },\n },\n },\n RegisterIdentityResultCheck: {\n always: [\n { target: \"Success\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n Success: { type: \"final\" },\n Error: { type: \"final\" },\n },\n output: ({ context }) => {\n const { proofs, error } = context._internalState;\n if (proofs) {\n const { input } = context;\n return Right({\n mode: input.existingContactGroup\n ? (\"existingContactGroup\" as const)\n : (\"newContactGroup\" as const),\n contactName: input.contactName,\n scope: input.scope,\n identifier: input.identifier,\n blockchainFamily: input.blockchainFamily,\n chainId: input.chainId,\n groupHandle: proofs.groupHandle,\n hmacProof: proofs.hmacProof,\n hmacRest: proofs.hmacRest,\n });\n }\n return Left(error ?? new UnknownDAError(\"No error in final state\"));\n },\n });\n }\n\n extractDependencies(\n internalApi: InternalApi,\n ): RegisterExternalAddressMachineDependencies {\n const isSupported = (app: RunningApp) =>\n isContactsSupportedForSession(internalApi, app);\n\n const registerIdentity = (\n input: RegisterExternalAddressDAInput,\n ): Promise<Awaited<ReturnType<SendRegisterIdentityTask[\"run\"]>>> =>\n new SendRegisterIdentityTask(internalApi, {\n contactName: input.contactName,\n scope: input.scope,\n identifier: input.identifier,\n blockchainFamily: input.blockchainFamily,\n chainId: input.chainId,\n existingContactGroup: input.existingContactGroup,\n }).run();\n\n return { isSupported, registerIdentity };\n }\n}\n\nexport type { RegisterIdentityProofs };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isSuccessCommandResult", "OpenAppDeviceAction", "UnknownDAError", "UserInteractionRequired", "WaitForAppAndVersionDeviceAction", "XStateDeviceAction", "Left", "Right", "assign", "fromPromise", "setup", "isContactsSupportedForSession", "ContactsVersionRequirementError", "SendRegisterIdentityTask", "validateRegisterExternalAddressInput", "RegisterExternalAddressDeviceAction", "internalApi", "isSupported", "registerIdentity", "appName", "input", "context", "appAndVersion", "error", "event", "proofs", "app"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CommandResultFactory as x,DeviceActionStatus as e,DeviceModelId as V,DeviceSessionStateType as k,DeviceStatus as P,UnknownDAError as R,UserInteractionRequired as t}from"@ledgerhq/device-management-kit";import{beforeEach as y,describe as U,it as p,vi as m}from"vitest";import{makeDeviceActionInternalApiMock as O}from"../../../app-binder/device-action/__test-utils__/makeInternalApi";import{setupOpenAppDAMock as u}from"../../../app-binder/device-action/__test-utils__/setupOpenAppDAMock";import{setupWaitForAppAndVersionDAMock as v}from"../../../app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock";import{testDeviceActionStates as l}from"../../../app-binder/device-action/__test-utils__/testDeviceActionStates";import{ContactsCommandError as C,ContactsVersionRequirementError as w}from"../../../app-binder/model/contactsErrors";import{RegisterExternalAddressDeviceAction as q}from"./RegisterExternalAddressDeviceAction";import{validateRegisterExternalAddressInput as f}from"./validateRegisterExternalAddressInput";m.mock("@ledgerhq/device-management-kit",async o=>({...await o(),OpenAppDeviceAction:m.fn(()=>({makeStateMachine:m.fn()})),WaitForAppAndVersionDeviceAction:m.fn(()=>({makeStateMachine:m.fn()}))}));const I={name:"Ethereum",version:"1.15.0"},D={groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221),hmacRest:new Uint8Array(32).fill(170)},s={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n,appName:"Ethereum"};U("RegisterExternalAddressDeviceAction",()=>{let o,A,g;function h(){return{isSupported:A,registerIdentity:g}}y(()=>{o=O(),v(I),A=m.fn().mockReturnValue(!0),g=m.fn().mockResolvedValue(x({data:D})),o.getDeviceSessionState.mockReturnValue({sessionStateType:k.ReadyWithoutSecureChannel,deviceStatus:P.CONNECTED,installedApps:[],currentApp:{name:"Ethereum",version:"1.15.0"},deviceModelId:V.FLEX,isSecureConnectionAllowed:!0})});function c(i){const n=new q({input:i});return m.spyOn(n,"extractDependencies").mockReturnValue(h()),n}p("open-app path, new contact group: OpenApp -> VersionGuard -> RegisterIdentity -> Completed",()=>new Promise((i,n)=>{u();const r=c({...s,skipOpenApp:!1}),a=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.ConfirmOpenApp},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{output:{mode:"newContactGroup",contactName:"Alice",scope:"Eth main",identifier:s.identifier,blockchainFamily:"ethereum",chainId:1n,...D},status:e.Completed}];l(r,a,o,{onDone:i,onError:n})})),p("skip-open-app path, existing contact group: VersionGuard -> RegisterIdentity -> Completed",()=>new Promise((i,n)=>{u();const r={groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221)},a=c({...s,skipOpenApp:!0,existingContactGroup:r}),d=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{output:{mode:"existingContactGroup",contactName:"Alice",scope:"Eth main",identifier:s.identifier,blockchainFamily:"ethereum",chainId:1n,...D},status:e.Completed}];l(a,d,o,{onDone:i,onError:n})})),p("version guard rejects on skip-open-app path without opening the app",()=>new Promise((i,n)=>{u(),A.mockReturnValue(!1);const r=c({...s,skipOpenApp:!0}),a=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{error:new w,status:e.Error}];l(r,a,o,{onDone:i,onError:n}),expect(g).not.toHaveBeenCalled()})),p("surfaces an open-app failure as the device action error",()=>new Promise((i,n)=>{const r=new R("open app failed");u(r);const a=c({...s,skipOpenApp:!1}),d=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.ConfirmOpenApp},status:e.Pending},{error:r,status:e.Error}];l(a,d,o,{onDone:i,onError:n}),expect(A).not.toHaveBeenCalled()})),p("surfaces a Register Identity command error",()=>new Promise((i,n)=>{u();const r=new C({errorCode:"6a80",message:"device rejected"});g.mockResolvedValue(x({error:r}));const a=c({...s,skipOpenApp:!0}),d=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{error:r,status:e.Error}];l(a,d,o,{onDone:i,onError:n})})),p("surfaces invalid input as a typed error state on the skip-open-app path",()=>new Promise((i,n)=>{u();const r={...s,skipOpenApp:!0,contactName:""},a=f(r),d=c(r),E=[{error:a,status:e.Error}];l(d,E,o,{onDone:i,onError:n}),expect(A).not.toHaveBeenCalled(),expect(g).not.toHaveBeenCalled()})),p("validates only after opening the app on the default path",()=>new Promise((i,n)=>{u();const r={...s,skipOpenApp:!1,contactName:""},a=f(r),d=c(r),E=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.ConfirmOpenApp},status:e.Pending},{error:a,status:e.Error}];l(d,E,o,{onDone:i,onError:n}),expect(g).not.toHaveBeenCalled()})),p("evaluates support from the fresh WaitForAppAndVersion result, not stale session state",()=>new Promise((i,n)=>{u();const r={name:"Ethereum",version:"9.9.9"};v(r);const a=c({...s,skipOpenApp:!0}),d=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{output:{mode:"newContactGroup",contactName:"Alice",scope:"Eth main",identifier:s.identifier,blockchainFamily:"ethereum",chainId:1n,...D},status:e.Completed}];l(a,d,o,{onDone:()=>{try{expect(A).toHaveBeenCalledWith(r),i()}catch(E){n(E)}},onError:n})})),p("surfaces a WaitForAppAndVersion failure as the device action error",()=>new Promise((i,n)=>{u();const r=new R("could not read app and version");v({error:r});const a=c({...s,skipOpenApp:!0}),d=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{error:r,status:e.Error}];l(a,d,o,{onDone:i,onError:n}),expect(A).not.toHaveBeenCalled(),expect(g).not.toHaveBeenCalled()})),p("propagates the UnlockDevice interaction emitted by WaitForAppAndVersion",()=>new Promise((i,n)=>{u(),v(I,t.UnlockDevice);const r=c({...s,skipOpenApp:!0}),a=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{output:{mode:"newContactGroup",contactName:"Alice",scope:"Eth main",identifier:s.identifier,blockchainFamily:"ethereum",chainId:1n,...D},status:e.Completed}];l(r,a,o,{onDone:i,onError:n})}))});
|
|
2
|
+
//# sourceMappingURL=RegisterExternalAddressDeviceAction.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/RegisterExternalAddressDeviceAction.test.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n CommandResultFactory,\n type DeviceActionState,\n DeviceActionStatus,\n DeviceModelId,\n DeviceSessionStateType,\n DeviceStatus,\n UnknownDAError,\n UserInteractionRequired,\n} from \"@ledgerhq/device-management-kit\";\nimport { beforeEach, describe, it, vi } from \"vitest\";\n\nimport {\n type RegisterExternalAddressDAError,\n type RegisterExternalAddressDAInput,\n type RegisterExternalAddressDAIntermediateValue,\n type RegisterExternalAddressDAOutput,\n} from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { setupOpenAppDAMock } from \"@internal/app-binder/device-action/__test-utils__/setupOpenAppDAMock\";\nimport { setupWaitForAppAndVersionDAMock } from \"@internal/app-binder/device-action/__test-utils__/setupWaitForAppAndVersionDAMock\";\nimport { testDeviceActionStates } from \"@internal/app-binder/device-action/__test-utils__/testDeviceActionStates\";\nimport {\n ContactsCommandError,\n ContactsVersionRequirementError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RegisterExternalAddressDeviceAction } from \"./RegisterExternalAddressDeviceAction\";\nimport { validateRegisterExternalAddressInput } from \"./validateRegisterExternalAddressInput\";\n\nvi.mock(\"@ledgerhq/device-management-kit\", async (importOriginal) => {\n const original =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n await importOriginal<typeof import(\"@ledgerhq/device-management-kit\")>();\n return {\n ...original,\n OpenAppDeviceAction: vi.fn(() => ({\n makeStateMachine: vi.fn(),\n })),\n WaitForAppAndVersionDeviceAction: vi.fn(() => ({\n makeStateMachine: vi.fn(),\n })),\n };\n});\n\nconst FRESH_APP = { name: \"Ethereum\", version: \"1.15.0\" };\n\nconst OK_PROOFS = {\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n hmacRest: new Uint8Array(32).fill(0xaa),\n};\n\nconst BASE_INPUT = {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n appName: \"Ethereum\",\n};\n\ndescribe(\"RegisterExternalAddressDeviceAction\", () => {\n let apiMock: ReturnType<typeof makeDeviceActionInternalApiMock>;\n let isSupportedMock: ReturnType<typeof vi.fn>;\n let registerIdentityMock: ReturnType<typeof vi.fn>;\n\n function extractDeps() {\n return {\n isSupported: isSupportedMock,\n registerIdentity: registerIdentityMock,\n };\n }\n\n beforeEach(() => {\n apiMock = makeDeviceActionInternalApiMock();\n setupWaitForAppAndVersionDAMock(FRESH_APP);\n isSupportedMock = vi.fn().mockReturnValue(true);\n registerIdentityMock = vi\n .fn()\n .mockResolvedValue(CommandResultFactory({ data: OK_PROOFS }));\n apiMock.getDeviceSessionState.mockReturnValue({\n sessionStateType: DeviceSessionStateType.ReadyWithoutSecureChannel,\n deviceStatus: DeviceStatus.CONNECTED,\n installedApps: [],\n currentApp: { name: \"Ethereum\", version: \"1.15.0\" },\n deviceModelId: DeviceModelId.FLEX,\n isSecureConnectionAllowed: true,\n });\n });\n\n function makeAction(input: RegisterExternalAddressDAInput) {\n const action = new RegisterExternalAddressDeviceAction({ input });\n vi.spyOn(action, \"extractDependencies\").mockReturnValue(extractDeps());\n return action;\n }\n\n it(\"open-app path, new contact group: OpenApp -> VersionGuard -> RegisterIdentity -> Completed\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: false });\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.ConfirmOpenApp,\n },\n status: DeviceActionStatus.Pending,\n },\n // WaitForAppAndVersion phase: entry reset, then the child's silent read\n // re-emits None through onSnapshot propagation.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n output: {\n mode: \"newContactGroup\",\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: BASE_INPUT.identifier,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n ...OK_PROOFS,\n },\n status: DeviceActionStatus.Completed,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n }));\n\n it(\"skip-open-app path, existing contact group: VersionGuard -> RegisterIdentity -> Completed\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const existingContactGroup = {\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n };\n const action = makeAction({\n ...BASE_INPUT,\n skipOpenApp: true,\n existingContactGroup,\n });\n\n const expected = [\n // WaitForAppAndVersion phase: entry reset, then the child's silent read\n // re-emits None through onSnapshot propagation.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n output: {\n mode: \"existingContactGroup\",\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: BASE_INPUT.identifier,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n ...OK_PROOFS,\n },\n status: DeviceActionStatus.Completed,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n }));\n\n it(\"version guard rejects on skip-open-app path without opening the app\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n isSupportedMock.mockReturnValue(false);\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: true });\n\n const expected = [\n // WaitForAppAndVersion phase (entry reset + child read) runs before the\n // guard; both reads emit None.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: new ContactsVersionRequirementError(),\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n expect(registerIdentityMock).not.toHaveBeenCalled();\n }));\n\n it(\"surfaces an open-app failure as the device action error\", () =>\n new Promise<void>((resolve, reject) => {\n const openAppError = new UnknownDAError(\"open app failed\");\n setupOpenAppDAMock(openAppError);\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: false });\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.ConfirmOpenApp,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: openAppError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n expect(isSupportedMock).not.toHaveBeenCalled();\n }));\n\n it(\"surfaces a Register Identity command error\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const commandError = new ContactsCommandError({\n errorCode: \"6a80\",\n message: \"device rejected\",\n });\n registerIdentityMock.mockResolvedValue(\n CommandResultFactory({ error: commandError }),\n );\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: true });\n\n const expected = [\n // WaitForAppAndVersion phase: entry reset, then the child's silent read\n // re-emits None through onSnapshot propagation.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: commandError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n }));\n\n it(\"surfaces invalid input as a typed error state on the skip-open-app path\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const invalidInput = {\n ...BASE_INPUT,\n skipOpenApp: true,\n contactName: \"\",\n };\n const validationError =\n validateRegisterExternalAddressInput(invalidInput);\n const action = makeAction(invalidInput);\n\n const expected = [\n {\n error: validationError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n // Validation fails before the version guard and before any APDU.\n expect(isSupportedMock).not.toHaveBeenCalled();\n expect(registerIdentityMock).not.toHaveBeenCalled();\n }));\n\n it(\"validates only after opening the app on the default path\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const invalidInput = {\n ...BASE_INPUT,\n skipOpenApp: false,\n contactName: \"\",\n };\n const validationError =\n validateRegisterExternalAddressInput(invalidInput);\n const action = makeAction(invalidInput);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.ConfirmOpenApp,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: validationError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n expect(registerIdentityMock).not.toHaveBeenCalled();\n }));\n\n it(\"evaluates support from the fresh WaitForAppAndVersion result, not stale session state\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n // Session state (from beforeEach) reports version 1.15.0; the fresh read\n // reports a different version, which is what the guard must use.\n const freshApp = { name: \"Ethereum\", version: \"9.9.9\" };\n setupWaitForAppAndVersionDAMock(freshApp);\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: true });\n\n const expected = [\n // WaitForAppAndVersion phase: entry reset + child read, both None.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n output: {\n mode: \"newContactGroup\",\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: BASE_INPUT.identifier,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n ...OK_PROOFS,\n },\n status: DeviceActionStatus.Completed,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n try {\n expect(isSupportedMock).toHaveBeenCalledWith(freshApp);\n resolve();\n } catch (e) {\n reject(e as Error);\n }\n },\n onError: reject,\n });\n }));\n\n it(\"surfaces a WaitForAppAndVersion failure as the device action error\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n const waitError = new UnknownDAError(\"could not read app and version\");\n setupWaitForAppAndVersionDAMock({ error: waitError });\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: true });\n\n const expected = [\n // WaitForAppAndVersion phase: entry reset + child read, both None,\n // before the child DA surfaces its failure.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: waitError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n // The version guard and the APDU are never reached.\n expect(isSupportedMock).not.toHaveBeenCalled();\n expect(registerIdentityMock).not.toHaveBeenCalled();\n }));\n\n it(\"propagates the UnlockDevice interaction emitted by WaitForAppAndVersion\", () =>\n new Promise<void>((resolve, reject) => {\n setupOpenAppDAMock();\n // Locked device: the child WaitForAppAndVersion DA requests an unlock\n // before it can read the app/version. The parent must surface it so a\n // consuming client can show a \"please unlock your device\" prompt.\n setupWaitForAppAndVersionDAMock(\n FRESH_APP,\n UserInteractionRequired.UnlockDevice,\n );\n const action = makeAction({ ...BASE_INPUT, skipOpenApp: true });\n\n const expected = [\n // Entry reset before the child DA runs.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n // Propagated from the child DA: the device needs to be unlocked.\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n output: {\n mode: \"newContactGroup\",\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: BASE_INPUT.identifier,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n ...OK_PROOFS,\n },\n status: DeviceActionStatus.Completed,\n },\n ] as DeviceActionState<\n RegisterExternalAddressDAOutput,\n RegisterExternalAddressDAError,\n RegisterExternalAddressDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n }));\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CommandResultFactory", "DeviceActionStatus", "DeviceModelId", "DeviceSessionStateType", "DeviceStatus", "UnknownDAError", "UserInteractionRequired", "beforeEach", "describe", "it", "vi", "makeDeviceActionInternalApiMock", "setupOpenAppDAMock", "setupWaitForAppAndVersionDAMock", "testDeviceActionStates", "ContactsCommandError", "ContactsVersionRequirementError", "RegisterExternalAddressDeviceAction", "validateRegisterExternalAddressInput", "importOriginal", "FRESH_APP", "OK_PROOFS", "BASE_INPUT", "apiMock", "isSupportedMock", "registerIdentityMock", "extractDeps", "makeAction", "input", "action", "resolve", "reject", "expected", "existingContactGroup", "openAppError", "commandError", "invalidInput", "validationError", "freshApp", "e", "waitError"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BLOCKCHAIN_FAMILY_BY_NAME as o}from"../../../app-binder/model/contactsConstants";import{CONTACT_NAME_BUFFER_LENGTH as a,ContactsValidationError as i,ETH_ADDRESS_BYTES as d,GROUP_HANDLE_SIZE as c,HMAC_PROOF_LENGTH as f,SCOPE_BUFFER_LENGTH as l,validateByteLength as r,validateChainId as s,validatePrintableLabel as n}from"../../../app-binder/model/contactsValidation";function E(e){try{n(e.contactName,{field:"contactName",bufferLength:a}),n(e.scope,{field:"scope",bufferLength:l});const t=e.blockchainFamily.toLowerCase();if(!(t in o))throw new i(`Unsupported blockchain family: ${e.blockchainFamily}`);if(t==="ethereum"){if(r(e.identifier,{field:"identifier",expectedBytes:d}),e.chainId===void 0)throw new i("chainId is required for the Ethereum blockchain family.")}else if(e.identifier.length===0)throw new i("identifier must not be empty.");return e.chainId!==void 0&&s(e.chainId),e.existingContactGroup&&(r(e.existingContactGroup.groupHandle,{field:"existingContactGroup.groupHandle",expectedBytes:c}),r(e.existingContactGroup.hmacProof,{field:"existingContactGroup.hmacProof",expectedBytes:f})),null}catch(t){if(t instanceof i)return t;throw t}}export{E as validateRegisterExternalAddressInput};
|
|
2
|
+
//# sourceMappingURL=validateRegisterExternalAddressInput.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.ts"],
|
|
4
|
+
"sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { BLOCKCHAIN_FAMILY_BY_NAME } from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n ETH_ADDRESS_BYTES,\n GROUP_HANDLE_SIZE,\n HMAC_PROOF_LENGTH,\n SCOPE_BUFFER_LENGTH,\n validateByteLength,\n validateChainId,\n validatePrintableLabel,\n} from \"@internal/app-binder/model/contactsValidation\";\n\n/**\n * Validate the caller input for Register External Address. Returns the first\n * `ContactsValidationError` found, or `null` when the input is valid.\n *\n * Non-throwing by design: the device action calls this so an invalid input is\n * surfaced as a typed terminal error state on the observable, keeping the\n * public `ContactsManager.registerExternalAddress` free of synchronous throws.\n */\nexport function validateRegisterExternalAddressInput(\n input: RegisterExternalAddressInput,\n): ContactsValidationError | null {\n try {\n validatePrintableLabel(input.contactName, {\n field: \"contactName\",\n bufferLength: CONTACT_NAME_BUFFER_LENGTH,\n });\n validatePrintableLabel(input.scope, {\n field: \"scope\",\n bufferLength: SCOPE_BUFFER_LENGTH,\n });\n\n const family = input.blockchainFamily.toLowerCase();\n if (!(family in BLOCKCHAIN_FAMILY_BY_NAME)) {\n throw new ContactsValidationError(\n `Unsupported blockchain family: ${input.blockchainFamily}`,\n );\n }\n if (family === \"ethereum\") {\n validateByteLength(input.identifier, {\n field: \"identifier\",\n expectedBytes: ETH_ADDRESS_BYTES,\n });\n // CHAIN_ID is mandatory for the Ethereum family (multiple networks share\n // the same address format).\n if (input.chainId === undefined) {\n throw new ContactsValidationError(\n \"chainId is required for the Ethereum blockchain family.\",\n );\n }\n } else if (input.identifier.length === 0) {\n throw new ContactsValidationError(\"identifier must not be empty.\");\n }\n\n if (input.chainId !== undefined) {\n validateChainId(input.chainId);\n }\n\n if (input.existingContactGroup) {\n validateByteLength(input.existingContactGroup.groupHandle, {\n field: \"existingContactGroup.groupHandle\",\n expectedBytes: GROUP_HANDLE_SIZE,\n });\n validateByteLength(input.existingContactGroup.hmacProof, {\n field: \"existingContactGroup.hmacProof\",\n expectedBytes: HMAC_PROOF_LENGTH,\n });\n }\n\n return null;\n } catch (error) {\n if (error instanceof ContactsValidationError) {\n return error;\n }\n throw error;\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,OAAS,6BAAAA,MAAiC,+CAC1C,OACE,8BAAAC,EACA,2BAAAC,EACA,qBAAAC,EACA,qBAAAC,EACA,qBAAAC,EACA,uBAAAC,EACA,sBAAAC,EACA,mBAAAC,EACA,0BAAAC,MACK,gDAUA,SAASC,EACdC,EACgC,CAChC,GAAI,CACFF,EAAuBE,EAAM,YAAa,CACxC,MAAO,cACP,aAAcV,CAChB,CAAC,EACDQ,EAAuBE,EAAM,MAAO,CAClC,MAAO,QACP,aAAcL,CAChB,CAAC,EAED,MAAMM,EAASD,EAAM,iBAAiB,YAAY,EAClD,GAAI,EAAEC,KAAUZ,GACd,MAAM,IAAIE,EACR,kCAAkCS,EAAM,gBAAgB,EAC1D,EAEF,GAAIC,IAAW,YAOb,GANAL,EAAmBI,EAAM,WAAY,CACnC,MAAO,aACP,cAAeR,CACjB,CAAC,EAGGQ,EAAM,UAAY,OACpB,MAAM,IAAIT,EACR,yDACF,UAEOS,EAAM,WAAW,SAAW,EACrC,MAAM,IAAIT,EAAwB,+BAA+B,EAGnE,OAAIS,EAAM,UAAY,QACpBH,EAAgBG,EAAM,OAAO,EAG3BA,EAAM,uBACRJ,EAAmBI,EAAM,qBAAqB,YAAa,CACzD,MAAO,mCACP,cAAeP,CACjB,CAAC,EACDG,EAAmBI,EAAM,qBAAqB,UAAW,CACvD,MAAO,iCACP,cAAeN,CACjB,CAAC,GAGI,IACT,OAASQ,EAAO,CACd,GAAIA,aAAiBX,EACnB,OAAOW,EAET,MAAMA,CACR,CACF",
|
|
6
|
+
"names": ["BLOCKCHAIN_FAMILY_BY_NAME", "CONTACT_NAME_BUFFER_LENGTH", "ContactsValidationError", "ETH_ADDRESS_BYTES", "GROUP_HANDLE_SIZE", "HMAC_PROOF_LENGTH", "SCOPE_BUFFER_LENGTH", "validateByteLength", "validateChainId", "validatePrintableLabel", "validateRegisterExternalAddressInput", "input", "family", "error"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ContactsValidationError as n}from"../../../app-binder/model/contactsValidation";import{validateRegisterExternalAddressInput as e}from"./validateRegisterExternalAddressInput";const t={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n};describe("validateRegisterExternalAddressInput",()=>{it("returns null for valid input",()=>{expect(e(t)).toBeNull()}),it("returns null for a valid existing-contact-group input",()=>{expect(e({...t,existingContactGroup:{groupHandle:new Uint8Array(64),hmacProof:new Uint8Array(32)}})).toBeNull()}),it("returns a ContactsValidationError for a non-printable contact name",()=>{expect(e({...t,contactName:"Am\xE9lie"})).toBeInstanceOf(n)}),it("returns an error for an Ethereum identifier of the wrong length",()=>{expect(e({...t,identifier:new Uint8Array(19)})).toBeInstanceOf(n)}),it("returns an error for an unsupported blockchain family",()=>{expect(e({...t,blockchainFamily:"dogecoin"})).toBeInstanceOf(n)}),it("returns an error when chainId is missing for the Ethereum family",()=>{expect(e({...t,chainId:void 0})).toBeInstanceOf(n)}),it("returns an error for a wrong-sized existing group handle",()=>{expect(e({...t,existingContactGroup:{groupHandle:new Uint8Array(32),hmacProof:new Uint8Array(32)}})).toBeInstanceOf(n)})});
|
|
2
|
+
//# sourceMappingURL=validateRegisterExternalAddressInput.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { ContactsValidationError } from \"@internal/app-binder/model/contactsValidation\";\n\nimport { validateRegisterExternalAddressInput } from \"./validateRegisterExternalAddressInput\";\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(\"validateRegisterExternalAddressInput\", () => {\n it(\"returns null for valid input\", () => {\n expect(validateRegisterExternalAddressInput(VALID_INPUT)).toBeNull();\n });\n\n it(\"returns null for a valid existing-contact-group input\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(64),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeNull();\n });\n\n it(\"returns a ContactsValidationError for a non-printable contact name\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n contactName: \"Am\u00E9lie\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an Ethereum identifier of the wrong length\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n identifier: new Uint8Array(19),\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an unsupported blockchain family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n blockchainFamily: \"dogecoin\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error when chainId is missing for the Ethereum family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n chainId: undefined,\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for a wrong-sized existing group handle\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(32),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n});\n"],
|
|
5
|
+
"mappings": "AACA,OAAS,2BAAAA,MAA+B,gDAExC,OAAS,wCAAAC,MAA4C,yCAErD,MAAMC,EAA4C,CAChD,YAAa,QACb,MAAO,WACP,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,EACX,EAEA,SAAS,uCAAwC,IAAM,CACrD,GAAG,+BAAgC,IAAM,CACvC,OAAOD,EAAqCC,CAAW,CAAC,EAAE,SAAS,CACrE,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,OACED,EAAqC,CACnC,GAAGC,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,SAAS,CACb,CAAC,EAED,GAAG,qEAAsE,IAAM,CAC7E,OACED,EAAqC,CACnC,GAAGC,EACH,YAAa,WACf,CAAC,CACH,EAAE,eAAeF,CAAuB,CAC1C,CAAC,EAED,GAAG,kEAAmE,IAAM,CAC1E,OACEC,EAAqC,CACnC,GAAGC,EACH,WAAY,IAAI,WAAW,EAAE,CAC/B,CAAC,CACH,EAAE,eAAeF,CAAuB,CAC1C,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,OACEC,EAAqC,CACnC,GAAGC,EACH,iBAAkB,UACpB,CAAC,CACH,EAAE,eAAeF,CAAuB,CAC1C,CAAC,EAED,GAAG,mEAAoE,IAAM,CAC3E,OACEC,EAAqC,CACnC,GAAGC,EACH,QAAS,MACX,CAAC,CACH,EAAE,eAAeF,CAAuB,CAC1C,CAAC,EAED,GAAG,2DAA4D,IAAM,CACnE,OACEC,EAAqC,CACnC,GAAGC,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,eAAeF,CAAuB,CAC1C,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["ContactsValidationError", "validateRegisterExternalAddressInput", "VALID_INPUT"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{GoToDashboardDeviceAction as m,isSuccessCommandResult as p,UnknownDAError as u,UserInteractionRequired as i,XStateDeviceAction as l}from"@ledgerhq/device-management-kit";import{Left as d,Right as C}from"purify-ts";import{assign as a,fromPromise as R,setup as S}from"xstate";import{isContactsOsSupportedForSession as D}from"../../../app-binder/isContactsSupportedForSession";import{ContactsVersionRequirementError as g}from"../../../app-binder/model/contactsErrors";import{SendRenameContactTask as A}from"../../../app-binder/task/SendRenameContactTask";import{validateRenameContactInput as I}from"./validateRenameContactInput";class k extends l{makeStateMachine(n){const{isOsSupported:c,renameContact:s}=this.extractDependencies(n);return S({types:{input:{},context:{},output:{}},actors:{goToDashboardStateMachine:new m({input:{}}).makeStateMachine(n),renameContact:R(({input:t})=>s(t))},guards:{noInternalError:({context:t})=>t._internalState.error===null,contactsOsSupported:()=>c()},actions:{assignValidationError:a({_internalState:({context:t})=>{const e=I(t.input);return e?{...t._internalState,error:e}:t._internalState}}),assignVersionError:a({_internalState:({context:t})=>({...t._internalState,error:new g})}),assignErrorFromEvent:a({_internalState:({context:t,event:e})=>({...t._internalState,error:new u(e.error instanceof Error?e.error.message:String(e.error))})})}}).createMachine({id:"RenameContactDeviceAction",initial:"InitialState",context:({input:t})=>({input:t,intermediateValue:{requiredUserInteraction:i.None},_internalState:{error:null,proof:null}}),states:{InitialState:{always:{target:"GoToDashboard"}},GoToDashboard:{invoke:{id:"goToDashboard",src:"goToDashboardStateMachine",input:()=>({}),onSnapshot:{actions:a({intermediateValue:({event:t})=>({requiredUserInteraction:t.snapshot.context.intermediateValue.requiredUserInteraction})})},onDone:{target:"GoToDashboardCheck",actions:a({_internalState:({event:t,context:e})=>t.output.caseOf({Right:()=>e._internalState,Left:r=>({...e._internalState,error:r})})})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},GoToDashboardCheck:{always:[{target:"ValidateInput",guard:"noInternalError"},{target:"Error"}]},ValidateInput:{entry:"assignValidationError",always:[{target:"VersionGuard",guard:"noInternalError"},{target:"Error"}]},VersionGuard:{always:[{target:"RenameContact",guard:"contactsOsSupported"},{target:"Error",actions:"assignVersionError"}]},RenameContact:{entry:a({intermediateValue:{requiredUserInteraction:i.RegisterWallet}}),exit:a({intermediateValue:{requiredUserInteraction:i.None}}),invoke:{id:"renameContact",src:"renameContact",input:({context:t})=>t.input,onDone:{target:"RenameContactResultCheck",actions:a({_internalState:({event:t,context:e})=>p(t.output)?{...e._internalState,proof:t.output.data}:{...e._internalState,error:t.output.error}})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},RenameContactResultCheck:{always:[{target:"Success",guard:"noInternalError"},{target:"Error"}]},Success:{type:"final"},Error:{type:"final"}},output:({context:t})=>{const{proof:e,error:r}=t._internalState;if(e){const{input:o}=t;return C({previousContactName:o.previousContactName,contactName:o.newContactName,groupHandle:o.groupHandle,hmacProof:e.hmacProof})}return d(r??new u("No error in final state"))}})}extractDependencies(n){return{isOsSupported:()=>D(n),renameContact:t=>new A(n,{previousContactName:t.previousContactName,newContactName:t.newContactName,groupHandle:t.groupHandle,hmacProof:t.hmacProof}).run()}}}export{k as RenameContactDeviceAction};
|
|
2
|
+
//# sourceMappingURL=RenameContactDeviceAction.js.map
|
package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceActionStateMachine,\n GoToDashboardDeviceAction,\n type InternalApi,\n isSuccessCommandResult,\n type StateMachineTypes,\n UnknownDAError,\n UserInteractionRequired,\n XStateDeviceAction,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { assign, fromPromise, setup } from \"xstate\";\n\nimport {\n type RenameContactDAError,\n type RenameContactDAInput,\n type RenameContactDAIntermediateValue,\n type RenameContactDAInternalState,\n type RenameContactDAOutput,\n} from \"@api/app-binder/RenameContactDeviceActionTypes\";\nimport { isContactsOsSupportedForSession } from \"@internal/app-binder/isContactsSupportedForSession\";\nimport { ContactsVersionRequirementError } from \"@internal/app-binder/model/contactsErrors\";\nimport {\n type RenameContactProof,\n SendRenameContactTask,\n} from \"@internal/app-binder/task/SendRenameContactTask\";\n\nimport { validateRenameContactInput } from \"./validateRenameContactInput\";\n\nexport type RenameContactMachineDependencies = {\n readonly isOsSupported: () => boolean;\n readonly renameContact: (\n input: RenameContactDAInput,\n ) => Promise<Awaited<ReturnType<SendRenameContactTask[\"run\"]>>>;\n};\n\nexport class RenameContactDeviceAction extends XStateDeviceAction<\n RenameContactDAOutput,\n RenameContactDAInput,\n RenameContactDAError,\n RenameContactDAIntermediateValue,\n RenameContactDAInternalState\n> {\n makeStateMachine(\n internalApi: InternalApi,\n ): DeviceActionStateMachine<\n RenameContactDAOutput,\n RenameContactDAInput,\n RenameContactDAError,\n RenameContactDAIntermediateValue,\n RenameContactDAInternalState\n > {\n type types = StateMachineTypes<\n RenameContactDAOutput,\n RenameContactDAInput,\n RenameContactDAError,\n RenameContactDAIntermediateValue,\n RenameContactDAInternalState\n >;\n\n const { isOsSupported, renameContact } =\n this.extractDependencies(internalApi);\n\n return setup({\n types: {\n input: {} as types[\"input\"],\n context: {} as types[\"context\"],\n output: {} as types[\"output\"],\n },\n actors: {\n // Rename is an OS/dashboard command: navigate to the dashboard (which\n // closes any running app) instead of opening an embedded app. There is\n // no OpenAppDeviceAction here by design.\n goToDashboardStateMachine: new GoToDashboardDeviceAction({\n input: {},\n }).makeStateMachine(internalApi),\n renameContact: fromPromise(\n ({ input }: { input: RenameContactDAInput }) => renameContact(input),\n ),\n },\n guards: {\n noInternalError: ({ context }) => context._internalState.error === null,\n contactsOsSupported: () => isOsSupported(),\n },\n actions: {\n assignValidationError: assign({\n _internalState: ({ context }) => {\n const error = validateRenameContactInput(context.input);\n return error\n ? { ...context._internalState, error }\n : context._internalState;\n },\n }),\n assignVersionError: assign({\n _internalState: ({ context }) => ({\n ...context._internalState,\n error: new ContactsVersionRequirementError(),\n }),\n }),\n assignErrorFromEvent: assign({\n _internalState: ({ context, event }) => ({\n ...context._internalState,\n error: new UnknownDAError(\n event[\"error\"] instanceof Error\n ? event[\"error\"].message\n : String(event[\"error\"]),\n ),\n }),\n }),\n },\n }).createMachine({\n id: \"RenameContactDeviceAction\",\n initial: \"InitialState\",\n context: ({ input }) => ({\n input,\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n _internalState: {\n error: null,\n proof: null,\n },\n }),\n states: {\n InitialState: {\n always: { target: \"GoToDashboard\" },\n },\n // Always navigate to the dashboard first \u2014 rename is an OS command and\n // must not run inside an app. Closing any running app happens here.\n GoToDashboard: {\n invoke: {\n id: \"goToDashboard\",\n src: \"goToDashboardStateMachine\",\n input: () => ({}),\n onSnapshot: {\n actions: assign({\n // The child surfaces both requiredUserInteraction and a step;\n // only the interaction is part of this action's contract.\n intermediateValue: ({ event }) => ({\n requiredUserInteraction:\n event.snapshot.context.intermediateValue\n .requiredUserInteraction,\n }),\n }),\n },\n onDone: {\n target: \"GoToDashboardCheck\",\n actions: assign({\n _internalState: ({ event, context }) =>\n event.output.caseOf<RenameContactDAInternalState>({\n Right: () => context._internalState,\n Left: (error) => ({ ...context._internalState, error }),\n }),\n }),\n },\n onError: {\n target: \"Error\",\n actions: \"assignErrorFromEvent\",\n },\n },\n },\n GoToDashboardCheck: {\n always: [\n { target: \"ValidateInput\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // Input validation runs inside the device action so invalid caller input\n // surfaces as a typed terminal error state on the observable instead of\n // a synchronous throw.\n ValidateInput: {\n entry: \"assignValidationError\",\n always: [\n { target: \"VersionGuard\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // OS-only version guard: rename is served by the device OS, so only the\n // device model and OS version are checked (no embedded-app version).\n VersionGuard: {\n always: [\n { target: \"RenameContact\", guard: \"contactsOsSupported\" },\n { target: \"Error\", actions: \"assignVersionError\" },\n ],\n },\n RenameContact: {\n entry: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n }),\n exit: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n }),\n invoke: {\n id: \"renameContact\",\n src: \"renameContact\",\n input: ({ context }) => context.input,\n onDone: {\n target: \"RenameContactResultCheck\",\n actions: assign({\n _internalState: ({ event, context }) =>\n isSuccessCommandResult(event.output)\n ? { ...context._internalState, proof: event.output.data }\n : {\n ...context._internalState,\n error: event.output.error,\n },\n }),\n },\n onError: {\n target: \"Error\",\n actions: \"assignErrorFromEvent\",\n },\n },\n },\n RenameContactResultCheck: {\n always: [\n { target: \"Success\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n Success: { type: \"final\" },\n Error: { type: \"final\" },\n },\n output: ({ context }) => {\n const { proof, error } = context._internalState;\n if (proof) {\n const { input } = context;\n return Right({\n previousContactName: input.previousContactName,\n contactName: input.newContactName,\n groupHandle: input.groupHandle,\n hmacProof: proof.hmacProof,\n });\n }\n return Left(error ?? new UnknownDAError(\"No error in final state\"));\n },\n });\n }\n\n extractDependencies(\n internalApi: InternalApi,\n ): RenameContactMachineDependencies {\n const isOsSupported = () => isContactsOsSupportedForSession(internalApi);\n\n const renameContact = (\n input: RenameContactDAInput,\n ): Promise<Awaited<ReturnType<SendRenameContactTask[\"run\"]>>> =>\n new SendRenameContactTask(internalApi, {\n previousContactName: input.previousContactName,\n newContactName: input.newContactName,\n groupHandle: input.groupHandle,\n hmacProof: input.hmacProof,\n }).run();\n\n return { isOsSupported, renameContact };\n }\n}\n\nexport type { RenameContactProof };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["GoToDashboardDeviceAction", "isSuccessCommandResult", "UnknownDAError", "UserInteractionRequired", "XStateDeviceAction", "Left", "Right", "assign", "fromPromise", "setup", "isContactsOsSupportedForSession", "ContactsVersionRequirementError", "SendRenameContactTask", "validateRenameContactInput", "RenameContactDeviceAction", "internalApi", "isOsSupported", "renameContact", "input", "context", "error", "event", "proof"]
|
|
7
|
+
}
|
package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CommandResultFactory as C,DeviceActionStatus as e,DeviceModelId as k,DeviceSessionStateType as g,DeviceStatus as E,GoToDashboardDeviceAction as h,OpenAppDeviceAction as R,UnknownDAError as P,UserInteractionRequired as t}from"@ledgerhq/device-management-kit";import{beforeEach as S,describe as V,expect as s,it as D,vi as c}from"vitest";import{makeDeviceActionInternalApiMock as y}from"../../../app-binder/device-action/__test-utils__/makeInternalApi";import{setupGoToDashboardDAMock as v}from"../../../app-binder/device-action/__test-utils__/setupGoToDashboardDAMock";import{testDeviceActionStates as A}from"../../../app-binder/device-action/__test-utils__/testDeviceActionStates";import{ContactsCommandError as q,ContactsVersionRequirementError as O}from"../../../app-binder/model/contactsErrors";import{RenameContactDeviceAction as w}from"./RenameContactDeviceAction";import{validateRenameContactInput as N}from"./validateRenameContactInput";c.mock("@ledgerhq/device-management-kit",async a=>({...await a(),GoToDashboardDeviceAction:c.fn(()=>({makeStateMachine:c.fn()})),OpenAppDeviceAction:c.fn(()=>({makeStateMachine:c.fn()}))}));const f={hmacProof:new Uint8Array(32).fill(238)},m={previousContactName:"Alice",newContactName:"Bob",groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221)},T={previousContactName:"Alice",contactName:"Bob",groupHandle:m.groupHandle,hmacProof:f.hmacProof};V("RenameContactDeviceAction",()=>{let a,d,u;function U(){return{isOsSupported:d,renameContact:u}}S(()=>{c.clearAllMocks(),a=y(),d=c.fn().mockReturnValue(!0),u=c.fn().mockResolvedValue(C({data:f})),a.getDeviceSessionState.mockReturnValue({sessionStateType:g.ReadyWithoutSecureChannel,deviceStatus:E.CONNECTED,installedApps:[],currentApp:{name:"BOLOS",version:"1.7.0"},deviceModelId:k.FLEX,isSecureConnectionAllowed:!0})});function l(r){const n=new w({input:r});return c.spyOn(n,"extractDependencies").mockReturnValue(U()),n}D("navigates to the dashboard, checks the OS, renames, and completes",()=>new Promise((r,n)=>{v({requiredUserInteraction:t.UnlockDevice});const o=l(m),i=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{output:T,status:e.Completed}];A(o,i,a,{onDone:()=>{s(h).toHaveBeenCalled(),s(R).not.toHaveBeenCalled(),r()},onError:n})})),D("rejects on an unsupported OS version without sending the APDU",()=>new Promise((r,n)=>{v({requiredUserInteraction:t.UnlockDevice}),d.mockReturnValue(!1);const o=l(m),i=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{error:new O,status:e.Error}];A(o,i,a,{onDone:()=>{s(u).not.toHaveBeenCalled(),s(R).not.toHaveBeenCalled(),r()},onError:n})})),D("surfaces a go-to-dashboard failure as the device action error",()=>new Promise((r,n)=>{const o=new P("go to dashboard failed");v({error:o,requiredUserInteraction:t.UnlockDevice});const i=l(m),p=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{error:o,status:e.Error}];A(i,p,a,{onDone:()=>{s(d).not.toHaveBeenCalled(),s(u).not.toHaveBeenCalled(),r()},onError:n})})),D("surfaces a rename command error (e.g. seed mismatch)",()=>new Promise((r,n)=>{v({requiredUserInteraction:t.UnlockDevice});const o=new q({errorCode:"6982",message:"wrong seed"});u.mockResolvedValue(C({error:o}));const i=l(m),p=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.RegisterWallet},status:e.Pending},{error:o,status:e.Error}];A(i,p,a,{onDone:r,onError:n})})),D("surfaces invalid input as a typed error after reaching the dashboard",()=>new Promise((r,n)=>{v({requiredUserInteraction:t.UnlockDevice});const o={...m,newContactName:""},i=N(o),p=l(o),I=[{intermediateValue:{requiredUserInteraction:t.None},status:e.Pending},{intermediateValue:{requiredUserInteraction:t.UnlockDevice},status:e.Pending},{error:i,status:e.Error}];A(p,I,a,{onDone:()=>{s(d).not.toHaveBeenCalled(),s(u).not.toHaveBeenCalled(),r()},onError:n})}))});
|
|
2
|
+
//# sourceMappingURL=RenameContactDeviceAction.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n CommandResultFactory,\n type DeviceActionState,\n DeviceActionStatus,\n DeviceModelId,\n DeviceSessionStateType,\n DeviceStatus,\n GoToDashboardDeviceAction,\n OpenAppDeviceAction,\n UnknownDAError,\n UserInteractionRequired,\n} from \"@ledgerhq/device-management-kit\";\nimport { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n type RenameContactDAError,\n type RenameContactDAInput,\n type RenameContactDAIntermediateValue,\n type RenameContactDAOutput,\n} from \"@api/app-binder/RenameContactDeviceActionTypes\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { setupGoToDashboardDAMock } from \"@internal/app-binder/device-action/__test-utils__/setupGoToDashboardDAMock\";\nimport { testDeviceActionStates } from \"@internal/app-binder/device-action/__test-utils__/testDeviceActionStates\";\nimport {\n ContactsCommandError,\n ContactsVersionRequirementError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RenameContactDeviceAction } from \"./RenameContactDeviceAction\";\nimport { validateRenameContactInput } from \"./validateRenameContactInput\";\n\nvi.mock(\"@ledgerhq/device-management-kit\", async (importOriginal) => {\n const original =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n await importOriginal<typeof import(\"@ledgerhq/device-management-kit\")>();\n return {\n ...original,\n GoToDashboardDeviceAction: vi.fn(() => ({\n makeStateMachine: vi.fn(),\n })),\n OpenAppDeviceAction: vi.fn(() => ({\n makeStateMachine: vi.fn(),\n })),\n };\n});\n\nconst OK_PROOF = { hmacProof: new Uint8Array(32).fill(0xee) };\n\nconst BASE_INPUT: RenameContactDAInput = {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n};\n\nconst EXPECTED_OUTPUT: RenameContactDAOutput = {\n previousContactName: \"Alice\",\n contactName: \"Bob\",\n groupHandle: BASE_INPUT.groupHandle,\n hmacProof: OK_PROOF.hmacProof,\n};\n\ndescribe(\"RenameContactDeviceAction\", () => {\n let apiMock: ReturnType<typeof makeDeviceActionInternalApiMock>;\n let isOsSupportedMock: ReturnType<typeof vi.fn>;\n let renameContactMock: ReturnType<typeof vi.fn>;\n\n function extractDeps() {\n return {\n isOsSupported: isOsSupportedMock,\n renameContact: renameContactMock,\n };\n }\n\n beforeEach(() => {\n vi.clearAllMocks();\n apiMock = makeDeviceActionInternalApiMock();\n isOsSupportedMock = vi.fn().mockReturnValue(true);\n renameContactMock = vi\n .fn()\n .mockResolvedValue(CommandResultFactory({ data: OK_PROOF }));\n apiMock.getDeviceSessionState.mockReturnValue({\n sessionStateType: DeviceSessionStateType.ReadyWithoutSecureChannel,\n deviceStatus: DeviceStatus.CONNECTED,\n installedApps: [],\n currentApp: { name: \"BOLOS\", version: \"1.7.0\" },\n deviceModelId: DeviceModelId.FLEX,\n isSecureConnectionAllowed: true,\n });\n });\n\n function makeAction(input: RenameContactDAInput) {\n const action = new RenameContactDeviceAction({ input });\n vi.spyOn(action, \"extractDependencies\").mockReturnValue(extractDeps());\n return action;\n }\n\n it(\"navigates to the dashboard, checks the OS, renames, and completes\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n const action = makeAction(BASE_INPUT);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n output: EXPECTED_OUTPUT,\n status: DeviceActionStatus.Completed,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n // Rename is a dashboard op: it navigates to the dashboard and never\n // opens an app.\n expect(GoToDashboardDeviceAction).toHaveBeenCalled();\n expect(OpenAppDeviceAction).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"rejects on an unsupported OS version without sending the APDU\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n isOsSupportedMock.mockReturnValue(false);\n const action = makeAction(BASE_INPUT);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: new ContactsVersionRequirementError(),\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n expect(renameContactMock).not.toHaveBeenCalled();\n expect(OpenAppDeviceAction).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"surfaces a go-to-dashboard failure as the device action error\", () =>\n new Promise<void>((resolve, reject) => {\n const dashboardError = new UnknownDAError(\"go to dashboard failed\");\n setupGoToDashboardDAMock({\n error: dashboardError,\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n const action = makeAction(BASE_INPUT);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: dashboardError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n expect(isOsSupportedMock).not.toHaveBeenCalled();\n expect(renameContactMock).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"surfaces a rename command error (e.g. seed mismatch)\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n const commandError = new ContactsCommandError({\n errorCode: \"6982\",\n message: \"wrong seed\",\n });\n renameContactMock.mockResolvedValue(\n CommandResultFactory({ error: commandError }),\n );\n const action = makeAction(BASE_INPUT);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: commandError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: resolve,\n onError: reject,\n });\n }));\n\n it(\"surfaces invalid input as a typed error after reaching the dashboard\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n const invalidInput = { ...BASE_INPUT, newContactName: \"\" };\n const validationError = validateRenameContactInput(invalidInput);\n const action = makeAction(invalidInput);\n\n const expected = [\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: validationError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n // Validation fails before the version guard and before any APDU.\n expect(isOsSupportedMock).not.toHaveBeenCalled();\n expect(renameContactMock).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CommandResultFactory", "DeviceActionStatus", "DeviceModelId", "DeviceSessionStateType", "DeviceStatus", "GoToDashboardDeviceAction", "OpenAppDeviceAction", "UnknownDAError", "UserInteractionRequired", "beforeEach", "describe", "expect", "it", "vi", "makeDeviceActionInternalApiMock", "setupGoToDashboardDAMock", "testDeviceActionStates", "ContactsCommandError", "ContactsVersionRequirementError", "RenameContactDeviceAction", "validateRenameContactInput", "importOriginal", "OK_PROOF", "BASE_INPUT", "EXPECTED_OUTPUT", "apiMock", "isOsSupportedMock", "renameContactMock", "extractDeps", "makeAction", "input", "action", "resolve", "reject", "expected", "dashboardError", "commandError", "invalidInput", "validationError"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CONTACT_NAME_BUFFER_LENGTH as a,ContactsValidationError as r,GROUP_HANDLE_SIZE as c,HMAC_PROOF_LENGTH as l,validateByteLength as n,validatePrintableLabel as o}from"../../../app-binder/model/contactsValidation";function f(e){try{return o(e.newContactName,{field:"newContactName",bufferLength:a}),o(e.previousContactName,{field:"previousContactName",bufferLength:a}),n(e.groupHandle,{field:"groupHandle",expectedBytes:c}),n(e.hmacProof,{field:"hmacProof",expectedBytes:l}),null}catch(t){if(t instanceof r)return t;throw t}}export{f as validateRenameContactInput};
|
|
2
|
+
//# sourceMappingURL=validateRenameContactInput.js.map
|
package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/internal/app-binder/device-action/RenameContact/validateRenameContactInput.ts"],
|
|
4
|
+
"sourcesContent": ["import { type RenameContactInput } from \"@api/model/RenameContact\";\nimport {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n GROUP_HANDLE_SIZE,\n HMAC_PROOF_LENGTH,\n validateByteLength,\n validatePrintableLabel,\n} from \"@internal/app-binder/model/contactsValidation\";\n\n/**\n * Validate the caller input for Rename Contact. Returns the first\n * `ContactsValidationError` found, or `null` when the input is valid.\n *\n * Non-throwing by design: the device action calls this so an invalid input is\n * surfaced as a typed terminal error state on the observable, keeping the public\n * `ContactsManager.renameContact` free of synchronous throws.\n */\nexport function validateRenameContactInput(\n input: RenameContactInput,\n): ContactsValidationError | null {\n try {\n validatePrintableLabel(input.newContactName, {\n field: \"newContactName\",\n bufferLength: CONTACT_NAME_BUFFER_LENGTH,\n });\n validatePrintableLabel(input.previousContactName, {\n field: \"previousContactName\",\n bufferLength: CONTACT_NAME_BUFFER_LENGTH,\n });\n validateByteLength(input.groupHandle, {\n field: \"groupHandle\",\n expectedBytes: GROUP_HANDLE_SIZE,\n });\n validateByteLength(input.hmacProof, {\n field: \"hmacProof\",\n expectedBytes: HMAC_PROOF_LENGTH,\n });\n\n return null;\n } catch (error) {\n if (error instanceof ContactsValidationError) {\n return error;\n }\n throw error;\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,OACE,8BAAAA,EACA,2BAAAC,EACA,qBAAAC,EACA,qBAAAC,EACA,sBAAAC,EACA,0BAAAC,MACK,gDAUA,SAASC,EACdC,EACgC,CAChC,GAAI,CACF,OAAAF,EAAuBE,EAAM,eAAgB,CAC3C,MAAO,iBACP,aAAcP,CAChB,CAAC,EACDK,EAAuBE,EAAM,oBAAqB,CAChD,MAAO,sBACP,aAAcP,CAChB,CAAC,EACDI,EAAmBG,EAAM,YAAa,CACpC,MAAO,cACP,cAAeL,CACjB,CAAC,EACDE,EAAmBG,EAAM,UAAW,CAClC,MAAO,YACP,cAAeJ,CACjB,CAAC,EAEM,IACT,OAASK,EAAO,CACd,GAAIA,aAAiBP,EACnB,OAAOO,EAET,MAAMA,CACR,CACF",
|
|
6
|
+
"names": ["CONTACT_NAME_BUFFER_LENGTH", "ContactsValidationError", "GROUP_HANDLE_SIZE", "HMAC_PROOF_LENGTH", "validateByteLength", "validatePrintableLabel", "validateRenameContactInput", "input", "error"]
|
|
7
|
+
}
|
package/lib/esm/internal/app-binder/device-action/RenameContact/validateRenameContactInput.test.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ContactsValidationError as n}from"../../../app-binder/model/contactsValidation";import{validateRenameContactInput as t}from"./validateRenameContactInput";const e={previousContactName:"Alice",newContactName:"Bob",groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221)};describe("validateRenameContactInput",()=>{it("returns null for valid input",()=>{expect(t(e)).toBeNull()}),it("returns a ContactsValidationError for a non-printable new name",()=>{expect(t({...e,newContactName:"Am\xE9lie"})).toBeInstanceOf(n)}),it("returns a ContactsValidationError for a non-printable previous name",()=>{expect(t({...e,previousContactName:"Am\xE9lie"})).toBeInstanceOf(n)}),it("returns an error for an empty new name",()=>{expect(t({...e,newContactName:""})).toBeInstanceOf(n)}),it("returns an error for a group handle of the wrong length",()=>{expect(t({...e,groupHandle:new Uint8Array(63)})).toBeInstanceOf(n)}),it("returns an error for an hmac proof of the wrong length",()=>{expect(t({...e,hmacProof:new Uint8Array(31)})).toBeInstanceOf(n)})});
|
|
2
|
+
//# sourceMappingURL=validateRenameContactInput.test.js.map
|