@ledgerhq/device-contacts-kit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/api/app-binder/RenameContactDeviceActionTypes.js.map +1 -1
- package/lib/cjs/api/index.js +1 -1
- package/lib/cjs/api/index.js.map +2 -2
- package/lib/cjs/api/model/ContactsVersionRequirements.js +1 -1
- package/lib/cjs/api/model/ContactsVersionRequirements.js.map +3 -3
- package/lib/cjs/api/model/ContactsVersionRequirements.test.js +1 -1
- package/lib/cjs/api/model/ContactsVersionRequirements.test.js.map +3 -3
- package/lib/cjs/api/model/RenameContact.js.map +1 -1
- package/lib/cjs/internal/app-binder/command/EditExternalAddressIdentifierCommand.js +1 -1
- package/lib/cjs/internal/app-binder/command/EditExternalAddressIdentifierCommand.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/EditExternalAddressScopeCommand.js +1 -1
- package/lib/cjs/internal/app-binder/command/EditExternalAddressScopeCommand.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/ProvideContactCommand.js +1 -1
- package/lib/cjs/internal/app-binder/command/ProvideContactCommand.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js +1 -1
- package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.js +1 -1
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.js.map +3 -3
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.test.js +1 -1
- package/lib/cjs/internal/app-binder/command/RenameContactCommand.test.js.map +2 -2
- package/lib/cjs/internal/app-binder/contactsVersionGuards.js +1 -1
- package/lib/cjs/internal/app-binder/contactsVersionGuards.js.map +3 -3
- package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js +1 -1
- package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js.map +2 -2
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js +1 -1
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +3 -3
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +1 -1
- package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +3 -3
- package/lib/cjs/internal/app-binder/model/contactsConstants.js +1 -1
- package/lib/cjs/internal/app-binder/model/contactsConstants.js.map +2 -2
- package/lib/cjs/internal/app-binder/model/contactsErrors.js +1 -1
- package/lib/cjs/internal/app-binder/model/contactsErrors.js.map +3 -3
- package/lib/cjs/internal/app-binder/services/provideContact.test.js +1 -1
- package/lib/cjs/internal/app-binder/services/provideContact.test.js.map +2 -2
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.js +1 -1
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.js.map +2 -2
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.test.js +1 -1
- package/lib/cjs/internal/app-binder/task/SendRenameContactTask.test.js.map +3 -3
- package/lib/cjs/package.json +1 -1
- package/lib/esm/api/index.js +1 -1
- package/lib/esm/api/index.js.map +3 -3
- package/lib/esm/api/model/ContactsVersionRequirements.js +1 -1
- package/lib/esm/api/model/ContactsVersionRequirements.js.map +3 -3
- package/lib/esm/api/model/ContactsVersionRequirements.test.js +1 -1
- package/lib/esm/api/model/ContactsVersionRequirements.test.js.map +3 -3
- package/lib/esm/internal/app-binder/command/EditExternalAddressIdentifierCommand.js +1 -1
- package/lib/esm/internal/app-binder/command/EditExternalAddressIdentifierCommand.js.map +3 -3
- package/lib/esm/internal/app-binder/command/EditExternalAddressScopeCommand.js +1 -1
- package/lib/esm/internal/app-binder/command/EditExternalAddressScopeCommand.js.map +3 -3
- package/lib/esm/internal/app-binder/command/ProvideContactCommand.js +1 -1
- package/lib/esm/internal/app-binder/command/ProvideContactCommand.js.map +3 -3
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js +1 -1
- package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js.map +3 -3
- package/lib/esm/internal/app-binder/command/RenameContactCommand.js +1 -1
- package/lib/esm/internal/app-binder/command/RenameContactCommand.js.map +3 -3
- package/lib/esm/internal/app-binder/command/RenameContactCommand.test.js +1 -1
- package/lib/esm/internal/app-binder/command/RenameContactCommand.test.js.map +3 -3
- package/lib/esm/internal/app-binder/contactsVersionGuards.js +1 -1
- package/lib/esm/internal/app-binder/contactsVersionGuards.js.map +3 -3
- package/lib/esm/internal/app-binder/contactsVersionGuards.test.js +1 -1
- package/lib/esm/internal/app-binder/contactsVersionGuards.test.js.map +3 -3
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js +1 -1
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +3 -3
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +1 -1
- package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +3 -3
- package/lib/esm/internal/app-binder/model/contactsConstants.js +1 -1
- package/lib/esm/internal/app-binder/model/contactsConstants.js.map +2 -2
- package/lib/esm/internal/app-binder/model/contactsErrors.js +1 -1
- package/lib/esm/internal/app-binder/model/contactsErrors.js.map +3 -3
- package/lib/esm/internal/app-binder/services/provideContact.test.js +1 -1
- package/lib/esm/internal/app-binder/services/provideContact.test.js.map +2 -2
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.js +1 -1
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.js.map +3 -3
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.test.js +1 -1
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.test.js.map +3 -3
- package/lib/esm/package.json +1 -1
- package/lib/types/api/app-binder/RenameContactDeviceActionTypes.d.ts +2 -1
- package/lib/types/api/app-binder/RenameContactDeviceActionTypes.d.ts.map +1 -1
- package/lib/types/api/index.d.ts +1 -1
- package/lib/types/api/index.d.ts.map +1 -1
- package/lib/types/api/model/ContactsVersionRequirements.d.ts +36 -3
- package/lib/types/api/model/ContactsVersionRequirements.d.ts.map +1 -1
- package/lib/types/api/model/RenameContact.d.ts +5 -3
- package/lib/types/api/model/RenameContact.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/EditExternalAddressIdentifierCommand.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/EditExternalAddressScopeCommand.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/ProvideContactCommand.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/RegisterIdentityCommand.d.ts.map +1 -1
- package/lib/types/internal/app-binder/command/RenameContactCommand.d.ts.map +1 -1
- package/lib/types/internal/app-binder/contactsVersionGuards.d.ts +9 -1
- package/lib/types/internal/app-binder/contactsVersionGuards.d.ts.map +1 -1
- package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.d.ts +4 -3
- package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.d.ts.map +1 -1
- package/lib/types/internal/app-binder/model/contactsConstants.d.ts +2 -2
- package/lib/types/internal/app-binder/model/contactsConstants.d.ts.map +1 -1
- package/lib/types/internal/app-binder/model/contactsErrors.d.ts +21 -2
- package/lib/types/internal/app-binder/model/contactsErrors.d.ts.map +1 -1
- package/lib/types/internal/app-binder/task/SendRenameContactTask.d.ts +8 -0
- package/lib/types/internal/app-binder/task/SendRenameContactTask.d.ts.map +1 -1
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/internal/app-binder/contactsVersionGuards.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n ApplicationChecker,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n type ContactsModelRequirement,\n type ContactsModelSupport,\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport { ContactsApplicationResolver } from \"./ContactsApplicationResolver\";\n\n/** The running app's identity, read freshly from the device. */\nexport type RunningApp = {\n readonly name: string;\n readonly version: string;\n};\n\n/** Narrows a resolved requirement to the case where Contacts is supported at all on this device model. */\nfunction isContactsModelSupported(\n requirement: ContactsModelRequirement,\n): requirement is ContactsModelSupport {\n return requirement.supported;\n}\n\n/**\n * OS-only Contacts support check, for internal consumption by dashboard\n * `DeviceAction`s (e.g. Rename Contact, EDIT CONTACT NAME). Dashboard operations\n * are served by the device OS, not the embedded app, so only two dimensions\n * apply:\n * - the device model must be supported;\n * - the device OS must meet its minimum version.\n *\n * The running-app dimension is intentionally skipped: on the dashboard there is\n * no embedded app to gate on (the running \"app\" is BOLOS).\n *\n * @param internalApi - the DeviceAction's internal API for the current session.\n */\nexport function
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6CAAAE,EAAA,
|
|
6
|
-
"names": ["contactsVersionGuards_exports", "__export", "isContactsAppVersionSupportedForSession", "
|
|
4
|
+
"sourcesContent": ["import {\n ApplicationChecker,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n type ContactsModelRequirement,\n type ContactsModelSupport,\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport { ContactsApplicationResolver } from \"./ContactsApplicationResolver\";\n\n/** The running app's identity, read freshly from the device. */\nexport type RunningApp = {\n readonly name: string;\n readonly version: string;\n};\n\n/** Narrows a resolved requirement to the case where Contacts is supported at all on this device model. */\nfunction isContactsModelSupported(\n requirement: ContactsModelRequirement,\n): requirement is ContactsModelSupport {\n return requirement.supported;\n}\n\n/**\n * OS-only Contacts support check, for internal consumption by dashboard\n * `DeviceAction`s (e.g. Rename Contact, EDIT CONTACT NAME). Dashboard operations\n * are served by the device OS, not the embedded app, so only two dimensions\n * apply:\n * - the device model must be supported;\n * - the device OS must meet its minimum version.\n *\n * The running-app dimension is intentionally skipped: on the dashboard there is\n * no embedded app to gate on (the running \"app\" is BOLOS).\n *\n * The OS `version` is supplied by the caller so it can come from a fresh\n * `GetOsVersion` result rather than the device session state, whose\n * `firmwareVersion` is often absent on the dashboard path (the session\n * refresher and `GoToDashboard` re-read only the running app, never the OS\n * version). The model comes from the session state, which does not change\n * under the caller's feet the way a stale/missing OS version would.\n *\n * @param internalApi - the DeviceAction's internal API for the current session.\n * @param osVersion - the device OS version, read freshly from the device.\n */\nexport function isContactsOsVersionSupportedForSession(\n internalApi: InternalApi,\n osVersion: string,\n): boolean {\n const deviceState = internalApi.getDeviceSessionState();\n const requirement = resolveContactsVersionRequirements(\n deviceState.deviceModelId,\n );\n if (!isContactsModelSupported(requirement)) return false;\n\n return isVersionAtLeast(osVersion, requirement.minOsVersion);\n}\n\n/**\n * Session-aware Contacts support check, for internal consumption by app-owned\n * Contacts `DeviceAction`s (registering / editing external addresses). These\n * operations are served by the embedded app, not the device OS, so only two\n * dimensions apply:\n * - the device model must be supported;\n * - the running app must be known to Contacts and meet its minimum version.\n *\n * The app `name` and `version` are supplied by the caller so they can come from\n * a fresh `WaitForAppAndVersion` result rather than the (potentially stale)\n * device session state; the model comes from the session state, which does\n * not change under the caller's feet the way the running app can.\n *\n * @param internalApi - the DeviceAction's internal API for the current session.\n * @param app - the running app's fresh name and version.\n */\nexport function isContactsAppVersionSupportedForSession(\n internalApi: InternalApi,\n app: RunningApp,\n): boolean {\n const deviceState = internalApi.getDeviceSessionState();\n const requirement = resolveContactsVersionRequirements(\n deviceState.deviceModelId,\n );\n if (!isContactsModelSupported(requirement)) return false;\n\n const minAppVersion = requirement.minAppVersion[app.name];\n if (minAppVersion === undefined) return false;\n\n return new ApplicationChecker(\n deviceState,\n { version: app.version },\n new ContactsApplicationResolver(),\n )\n .withMinVersionInclusiveAcceptingPrerelease(minAppVersion)\n .check();\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6CAAAE,EAAA,2CAAAC,IAAA,eAAAC,EAAAJ,GAAA,IAAAK,EAGO,2CAEPC,EAKO,kDAEPC,EAA4C,yCAS5C,SAASC,EACPC,EACqC,CACrC,OAAOA,EAAY,SACrB,CAuBO,SAASN,EACdO,EACAC,EACS,CACT,MAAMC,EAAcF,EAAY,sBAAsB,EAChDD,KAAc,sCAClBG,EAAY,aACd,EACA,OAAKJ,EAAyBC,CAAW,KAElC,oBAAiBE,EAAWF,EAAY,YAAY,EAFR,EAGrD,CAkBO,SAASP,EACdQ,EACAG,EACS,CACT,MAAMD,EAAcF,EAAY,sBAAsB,EAChDD,KAAc,sCAClBG,EAAY,aACd,EACA,GAAI,CAACJ,EAAyBC,CAAW,EAAG,MAAO,GAEnD,MAAMK,EAAgBL,EAAY,cAAcI,EAAI,IAAI,EACxD,OAAIC,IAAkB,OAAkB,GAEjC,IAAI,qBACTF,EACA,CAAE,QAASC,EAAI,OAAQ,EACvB,IAAI,6BACN,EACG,2CAA2CC,CAAa,EACxD,MAAM,CACX",
|
|
6
|
+
"names": ["contactsVersionGuards_exports", "__export", "isContactsAppVersionSupportedForSession", "isContactsOsVersionSupportedForSession", "__toCommonJS", "import_device_management_kit", "import_ContactsVersionRequirements", "import_ContactsApplicationResolver", "isContactsModelSupported", "requirement", "internalApi", "osVersion", "deviceState", "app", "minAppVersion"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var n=require("@ledgerhq/device-management-kit"),
|
|
1
|
+
"use strict";var n=require("@ledgerhq/device-management-kit"),r=require("../../api/model/ContactsVersionRequirements"),t=require("./contactsVersionGuards");const u=(()=>{const e=(0,r.resolveContactsVersionRequirements)(n.DeviceModelId.FLEX);if(!e.supported)throw new Error("Flex must be supported");return e})(),a=u.minOsVersion,d=(()=>{const e=u.minAppVersion[r.ETHEREUM_APP_NAME];if(e===void 0)throw new Error("Ethereum min version required");return e})(),p="0.0.1";function o({osVersion:e=a,modelId:c=n.DeviceModelId.FLEX}={}){return{sessionStateType:n.DeviceSessionStateType.ReadyWithoutSecureChannel,deviceStatus:n.DeviceStatus.CONNECTED,installedApps:[],currentApp:{name:r.ETHEREUM_APP_NAME,version:"0.0.0"},deviceModelId:c,firmwareVersion:{mcu:"1.0.0",bootloader:"1.0.0",os:e},isSecureConnectionAllowed:!1}}function s(e){return{getDeviceSessionState:()=>e}}function i(e=r.ETHEREUM_APP_NAME,c=d){return{name:e,version:c}}describe("isContactsAppVersionSupportedForSession",()=>{it("returns true when the model and app version meet the minimums",()=>{const e=s(o());expect((0,t.isContactsAppVersionSupportedForSession)(e,i())).toBe(!0)}),it("returns true regardless of OS version, since app-owned operations are not gated by it",()=>{const e=s(o({osVersion:p}));expect((0,t.isContactsAppVersionSupportedForSession)(e,i())).toBe(!0)}),it("returns false on an unsupported device model",()=>{const e=s(o({modelId:n.DeviceModelId.NANO_S}));expect((0,t.isContactsAppVersionSupportedForSession)(e,i())).toBe(!1)}),it("returns false when the app version is below the minimum",()=>{const e=s(o());expect((0,t.isContactsAppVersionSupportedForSession)(e,i(r.ETHEREUM_APP_NAME,p))).toBe(!1)}),it("returns false when the running app is unknown to Contacts",()=>{const e=s(o());expect((0,t.isContactsAppVersionSupportedForSession)(e,i("Bitcoin"))).toBe(!1)}),it("returns true for a prerelease build of the minimum app version",()=>{const e=s(o());expect((0,t.isContactsAppVersionSupportedForSession)(e,i(r.ETHEREUM_APP_NAME,`${d}-rc2`))).toBe(!0)}),it("returns false when the device session has no running app",()=>{const e=s({sessionStateType:n.DeviceSessionStateType.Connected,deviceStatus:n.DeviceStatus.CONNECTED,deviceModelId:n.DeviceModelId.FLEX});expect((0,t.isContactsAppVersionSupportedForSession)(e,i())).toBe(!1)})});describe("isContactsOsVersionSupportedForSession",()=>{it("returns true when the model and the caller's OS version meet the minimums",()=>{const e=s(o());expect((0,t.isContactsOsVersionSupportedForSession)(e,a)).toBe(!0)}),it("returns false on an unsupported device model",()=>{const e=s(o({modelId:n.DeviceModelId.NANO_S}));expect((0,t.isContactsOsVersionSupportedForSession)(e,a)).toBe(!1)}),it("returns false when the caller's OS version is below the minimum",()=>{const e=s(o());expect((0,t.isContactsOsVersionSupportedForSession)(e,p)).toBe(!1)}),it("returns true for a release candidate of the minimum OS version",()=>{const e=s(o());expect((0,t.isContactsOsVersionSupportedForSession)(e,`${a}-rc2`)).toBe(!0)}),it("returns false for a release candidate below the minimum OS version",()=>{const e=s(o());expect((0,t.isContactsOsVersionSupportedForSession)(e,`${p}-rc2`)).toBe(!1)}),it("never reads the OS version from the device session state",()=>{const e=s({sessionStateType:n.DeviceSessionStateType.Connected,deviceStatus:n.DeviceStatus.CONNECTED,deviceModelId:n.DeviceModelId.FLEX});expect((0,t.isContactsOsVersionSupportedForSession)(e,a)).toBe(!0),expect((0,t.isContactsOsVersionSupportedForSession)(e,p)).toBe(!1)})});
|
|
2
2
|
//# sourceMappingURL=contactsVersionGuards.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/internal/app-binder/contactsVersionGuards.test.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n DeviceModelId,\n DeviceSessionStateType,\n DeviceStatus,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n ETHEREUM_APP_NAME,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport {\n isContactsAppVersionSupportedForSession,\n
|
|
5
|
-
"mappings": "aAAA,IAAAA,EAKO,2CAEPC,EAGO,kDAEPC,EAIO,mCAEP,MAAMC,GAAe,IAAM,CACzB,MAAMC,KAAc,sCAAmC,gBAAc,IAAI,EACzE,GAAI,CAACA,EAAY,UAAW,MAAM,IAAI,MAAM,wBAAwB,EACpE,OAAOA,CACT,GAAG,EAEGC,EAAiBF,EAAY,aAC7BG,GAAmB,IAAM,CAC7B,MAAMC,EAAUJ,EAAY,cAAc,mBAAiB,EAC3D,GAAII,IAAY,OAAW,MAAM,IAAI,MAAM,+BAA+B,EAC1E,OAAOA,CACT,GAAG,EACGC,EAAoB,QAO1B,SAASC,EAAiB,CACxB,UAAAC,EAAYL,EACZ,QAAAM,EAAU,gBAAc,IAC1B,EAAuB,CAAC,EAAG,CACzB,MAAO,CACL,iBAAkB,yBAAuB,0BACzC,aAAc,eAAa,UAC3B,cAAe,CAAC,EAChB,WAAY,CAAE,KAAM,oBAAmB,QAAS,OAAQ,EACxD,cAAeA,EACf,gBAAiB,CAAE,IAAK,QAAS,WAAY,QAAS,GAAID,CAAU,EACpE,0BAA2B,EAC7B,CACF,CAEA,SAASE,EAAkBC,EAAkC,CAC3D,MAAO,CACL,sBAAuB,IAAMA,CAC/B,CACF,CAIA,SAASC,EACPC,EAAO,oBACPR,EAAUD,EACE,CACZ,MAAO,CAAE,KAAAS,EAAM,QAAAR,CAAQ,CACzB,CAEA,SAAS,0CAA2C,IAAM,CACxD,GAAG,gEAAiE,IAAM,CACxE,MAAMS,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UAAO,2CAAwCO,EAAKF,EAAW,CAAC,CAAC,EAAE,KACjE,EACF,CACF,CAAC,EAED,GAAG,wFAAyF,IAAM,CAChG,MAAME,EAAMJ,EACVH,EAAiB,CAAE,UAAWD,CAAkB,CAAC,CACnD,EACA,UAAO,2CAAwCQ,EAAKF,EAAW,CAAC,CAAC,EAAE,KACjE,EACF,CACF,CAAC,EAED,GAAG,+CAAgD,IAAM,CACvD,MAAME,EAAMJ,EACVH,EAAiB,CAAE,QAAS,gBAAc,MAAO,CAAC,CACpD,EACA,UAAO,2CAAwCO,EAAKF,EAAW,CAAC,CAAC,EAAE,KACjE,EACF,CACF,CAAC,EAED,GAAG,0DAA2D,IAAM,CAClE,MAAME,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UACE,2CACEO,EACAF,EAAW,oBAAmBN,CAAiB,CACjD,CACF,EAAE,KAAK,EAAK,CACd,CAAC,EAED,GAAG,4DAA6D,IAAM,CACpE,MAAMQ,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UACE,2CAAwCO,EAAKF,EAAW,SAAS,CAAC,CACpE,EAAE,KAAK,EAAK,CACd,CAAC,EAED,GAAG,iEAAkE,IAAM,CACzE,MAAME,EAAMJ,EAAkBH,EAAiB,CAAC,EAChD,UACE,2CACEO,EACAF,EAAW,oBAAmB,GAAGR,CAAe,MAAM,CACxD,CACF,EAAE,KAAK,EAAI,CACb,CAAC,EAED,GAAG,2DAA4D,IAAM,CACnE,MAAMU,EAAMJ,EAAkB,CAC5B,iBAAkB,yBAAuB,UACzC,aAAc,eAAa,UAC3B,cAAe,gBAAc,IAC/B,CAAC,EACD,UAAO,2CAAwCI,EAAKF,EAAW,CAAC,CAAC,EAAE,KACjE,EACF,CACF,CAAC,CACH,CAAC,EAED,SAAS,
|
|
4
|
+
"sourcesContent": ["import {\n DeviceModelId,\n DeviceSessionStateType,\n DeviceStatus,\n type InternalApi,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n ETHEREUM_APP_NAME,\n resolveContactsVersionRequirements,\n} from \"@api/model/ContactsVersionRequirements\";\n\nimport {\n isContactsAppVersionSupportedForSession,\n isContactsOsVersionSupportedForSession,\n type RunningApp,\n} from \"./contactsVersionGuards\";\n\nconst flexSupport = (() => {\n const requirement = resolveContactsVersionRequirements(DeviceModelId.FLEX);\n if (!requirement.supported) throw new Error(\"Flex must be supported\");\n return requirement;\n})();\n\nconst MIN_OS_VERSION = flexSupport.minOsVersion;\nconst MIN_APP_VERSION = (() => {\n const version = flexSupport.minAppVersion[ETHEREUM_APP_NAME];\n if (version === undefined) throw new Error(\"Ethereum min version required\");\n return version;\n})();\nconst BELOW_ANY_VERSION = \"0.0.1\";\n\ntype ReadyStateOptions = {\n osVersion?: string;\n modelId?: DeviceModelId;\n};\n\nfunction createReadyState({\n osVersion = MIN_OS_VERSION,\n modelId = DeviceModelId.FLEX,\n}: ReadyStateOptions = {}) {\n return {\n sessionStateType: DeviceSessionStateType.ReadyWithoutSecureChannel,\n deviceStatus: DeviceStatus.CONNECTED,\n installedApps: [],\n currentApp: { name: ETHEREUM_APP_NAME, version: \"0.0.0\" },\n deviceModelId: modelId,\n firmwareVersion: { mcu: \"1.0.0\", bootloader: \"1.0.0\", os: osVersion },\n isSecureConnectionAllowed: false,\n };\n}\n\nfunction createInternalApi(deviceState: object): InternalApi {\n return {\n getDeviceSessionState: () => deviceState,\n } as unknown as InternalApi;\n}\n\n// The running app identity now comes from the caller (a fresh\n// WaitForAppAndVersion result), not the device session state.\nfunction runningApp(\n name = ETHEREUM_APP_NAME,\n version = MIN_APP_VERSION,\n): RunningApp {\n return { name, version };\n}\n\ndescribe(\"isContactsAppVersionSupportedForSession\", () => {\n it(\"returns true when the model and app version meet the minimums\", () => {\n const api = createInternalApi(createReadyState());\n expect(isContactsAppVersionSupportedForSession(api, runningApp())).toBe(\n true,\n );\n });\n\n it(\"returns true regardless of OS version, since app-owned operations are not gated by it\", () => {\n const api = createInternalApi(\n createReadyState({ osVersion: BELOW_ANY_VERSION }),\n );\n expect(isContactsAppVersionSupportedForSession(api, runningApp())).toBe(\n true,\n );\n });\n\n it(\"returns false on an unsupported device model\", () => {\n const api = createInternalApi(\n createReadyState({ modelId: DeviceModelId.NANO_S }),\n );\n expect(isContactsAppVersionSupportedForSession(api, runningApp())).toBe(\n false,\n );\n });\n\n it(\"returns false when the app version is below the minimum\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsAppVersionSupportedForSession(\n api,\n runningApp(ETHEREUM_APP_NAME, BELOW_ANY_VERSION),\n ),\n ).toBe(false);\n });\n\n it(\"returns false when the running app is unknown to Contacts\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsAppVersionSupportedForSession(api, runningApp(\"Bitcoin\")),\n ).toBe(false);\n });\n\n it(\"returns true for a prerelease build of the minimum app version\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsAppVersionSupportedForSession(\n api,\n runningApp(ETHEREUM_APP_NAME, `${MIN_APP_VERSION}-rc2`),\n ),\n ).toBe(true);\n });\n\n it(\"returns false when the device session has no running app\", () => {\n const api = createInternalApi({\n sessionStateType: DeviceSessionStateType.Connected,\n deviceStatus: DeviceStatus.CONNECTED,\n deviceModelId: DeviceModelId.FLEX,\n });\n expect(isContactsAppVersionSupportedForSession(api, runningApp())).toBe(\n false,\n );\n });\n});\n\ndescribe(\"isContactsOsVersionSupportedForSession\", () => {\n it(\"returns true when the model and the caller's OS version meet the minimums\", () => {\n const api = createInternalApi(createReadyState());\n expect(isContactsOsVersionSupportedForSession(api, MIN_OS_VERSION)).toBe(\n true,\n );\n });\n\n it(\"returns false on an unsupported device model\", () => {\n const api = createInternalApi(\n createReadyState({ modelId: DeviceModelId.NANO_S }),\n );\n expect(isContactsOsVersionSupportedForSession(api, MIN_OS_VERSION)).toBe(\n false,\n );\n });\n\n it(\"returns false when the caller's OS version is below the minimum\", () => {\n const api = createInternalApi(createReadyState());\n expect(isContactsOsVersionSupportedForSession(api, BELOW_ANY_VERSION)).toBe(\n false,\n );\n });\n\n it(\"returns true for a release candidate of the minimum OS version\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsOsVersionSupportedForSession(api, `${MIN_OS_VERSION}-rc2`),\n ).toBe(true);\n });\n\n it(\"returns false for a release candidate below the minimum OS version\", () => {\n const api = createInternalApi(createReadyState());\n expect(\n isContactsOsVersionSupportedForSession(api, `${BELOW_ANY_VERSION}-rc2`),\n ).toBe(false);\n });\n\n it(\"never reads the OS version from the device session state\", () => {\n // A session with no firmwareVersion at all: the guard must rely solely on\n // the caller-supplied version and still resolve support.\n const api = createInternalApi({\n sessionStateType: DeviceSessionStateType.Connected,\n deviceStatus: DeviceStatus.CONNECTED,\n deviceModelId: DeviceModelId.FLEX,\n });\n expect(isContactsOsVersionSupportedForSession(api, MIN_OS_VERSION)).toBe(\n true,\n );\n expect(isContactsOsVersionSupportedForSession(api, BELOW_ANY_VERSION)).toBe(\n false,\n );\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_device_management_kit", "import_ContactsVersionRequirements", "import_contactsVersionGuards", "flexSupport", "requirement", "MIN_OS_VERSION", "MIN_APP_VERSION", "version", "BELOW_ANY_VERSION", "createReadyState", "osVersion", "modelId", "createInternalApi", "deviceState", "runningApp", "name", "api"]
|
|
7
7
|
}
|
package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var y=(o,n)=>{for(var c in n)d(o,c,{get:n[c],enumerable:!0})},E=(o,n,c,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of h(n))!I.call(o,i)&&i!==c&&d(o,i,{get:()=>n[i],enumerable:!(u=V(n,i))||u.enumerable});return o};var A=o=>E(d({},"__esModule",{value:!0}),o);var O={};y(O,{RenameContactDeviceAction:()=>f});module.exports=A(O);var r=require("@ledgerhq/device-management-kit"),m=require("purify-ts"),a=require("xstate"),C=require("../../../../api/model/ContactsVersionRequirements"),g=require("../../../app-binder/contactsVersionGuards"),S=require("../../../app-binder/model/contactsErrors"),R=require("../../../app-binder/task/SendRenameContactTask"),D=require("./validateRenameContactInput");class f extends r.XStateDeviceAction{makeStateMachine(n){const{getOsVersion:c,isOsVersionSupported:u,renameContact:i}=this.extractDependencies(n),{deviceModelId:s}=n.getDeviceSessionState();return(0,a.setup)({types:{input:{},context:{},output:{}},actors:{goToDashboardStateMachine:new r.GoToDashboardDeviceAction({input:{}}).makeStateMachine(n),getOsVersion:(0,a.fromPromise)(c),renameContact:(0,a.fromPromise)(({input:e})=>i(e.args,e.includeDerivationPath))},guards:{noInternalError:({context:e})=>e._internalState.error===null,contactsOsSupported:({context:e})=>{const{osVersion:t}=e._internalState;return t!==null&&u(t)}},actions:{assignValidationError:(0,a.assign)({_internalState:({context:e})=>{const t=(0,D.validateRenameContactInput)(e.input);return t?{...e._internalState,error:t}:e._internalState}}),assignVersionError:(0,a.assign)({_internalState:({context:e})=>({...e._internalState,error:new S.ContactsVersionRequirementError})}),assignErrorFromEvent:(0,a.assign)({_internalState:({context:e,event:t})=>({...e._internalState,error:new r.UnknownDAError(t.error instanceof Error?t.error.message:String(t.error))})})}}).createMachine({id:"RenameContactDeviceAction",initial:"InitialState",context:({input:e})=>({input:e,intermediateValue:{requiredUserInteraction:r.UserInteractionRequired.None},_internalState:{error:null,osVersion:null,proof:null}}),states:{InitialState:{always:{target:"GoToDashboard"}},GoToDashboard:{invoke:{id:"goToDashboard",src:"goToDashboardStateMachine",input:()=>({}),onSnapshot:{actions:(0,a.assign)({intermediateValue:({event:e})=>({requiredUserInteraction:e.snapshot.context.intermediateValue.requiredUserInteraction})})},onDone:{target:"GoToDashboardCheck",actions:(0,a.assign)({_internalState:({event:e,context:t})=>e.output.caseOf({Right:()=>t._internalState,Left:p=>({...t._internalState,error:p})})})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},GoToDashboardCheck:{always:[{target:"ValidateInput",guard:"noInternalError"},{target:"Error"}]},ValidateInput:{entry:"assignValidationError",always:[{target:"GetOsVersion",guard:"noInternalError"},{target:"Error"}]},GetOsVersion:{entry:(0,a.assign)({intermediateValue:{requiredUserInteraction:r.UserInteractionRequired.None}}),invoke:{id:"getOsVersion",src:"getOsVersion",onDone:{target:"GetOsVersionResultCheck",actions:(0,a.assign)({_internalState:({event:e,context:t})=>(0,r.isSuccessCommandResult)(e.output)?{...t._internalState,osVersion:e.output.data.seVersion}:{...t._internalState,error:e.output.error}})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},GetOsVersionResultCheck:{always:[{target:"VersionGuard",guard:"noInternalError"},{target:"Error"}]},VersionGuard:{always:[{target:"RenameContact",guard:"contactsOsSupported"},{target:"Error",actions:"assignVersionError"}]},RenameContact:{entry:(0,a.assign)({intermediateValue:{requiredUserInteraction:r.UserInteractionRequired.RegisterWallet}}),exit:(0,a.assign)({intermediateValue:{requiredUserInteraction:r.UserInteractionRequired.None}}),invoke:{id:"renameContact",src:"renameContact",input:({context:e})=>({args:e.input,includeDerivationPath:(0,C.renameRequiresDerivationPath)(s,e._internalState.osVersion??"")}),onDone:{target:"RenameContactResultCheck",actions:(0,a.assign)({_internalState:({event:e,context:t})=>(0,r.isSuccessCommandResult)(e.output)?{...t._internalState,proof:e.output.data}:{...t._internalState,error:e.output.error}})},onError:{target:"Error",actions:"assignErrorFromEvent"}}},RenameContactResultCheck:{always:[{target:"Success",guard:"noInternalError"},{target:"Error"}]},Success:{type:"final"},Error:{type:"final"}},output:({context:e})=>{const{proof:t,error:p}=e._internalState;if(t){const{input:l}=e;return(0,m.Right)({previousContactName:l.previousContactName,contactName:l.newContactName,groupHandle:l.groupHandle,hmacProof:t.hmacProof})}return(0,m.Left)(p??new r.UnknownDAError("No error in final state"))}})}extractDependencies(n){return{getOsVersion:()=>n.sendCommand(new r.GetOsVersionCommand),isOsVersionSupported:s=>(0,g.isContactsOsVersionSupportedForSession)(n,s),renameContact:(s,e)=>new R.SendRenameContactTask(n,{previousContactName:s.previousContactName,newContactName:s.newContactName,groupHandle:s.groupHandle,hmacProof:s.hmacProof,includeDerivationPath:e}).run()}}}0&&(module.exports={RenameContactDeviceAction});
|
|
2
2
|
//# sourceMappingURL=RenameContactDeviceAction.js.map
|
package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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/contactsVersionGuards\";\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": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,+BAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,
|
|
6
|
-
"names": ["RenameContactDeviceAction_exports", "__export", "RenameContactDeviceAction", "__toCommonJS", "import_device_management_kit", "import_purify_ts", "import_xstate", "import_contactsVersionGuards", "import_contactsErrors", "import_SendRenameContactTask", "import_validateRenameContactInput", "internalApi", "
|
|
4
|
+
"sourcesContent": ["import {\n type DeviceActionStateMachine,\n GetOsVersionCommand,\n type GetOsVersionCommandResult,\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 { renameRequiresDerivationPath } from \"@api/model/ContactsVersionRequirements\";\nimport { isContactsOsVersionSupportedForSession } from \"@internal/app-binder/contactsVersionGuards\";\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 getOsVersion: () => Promise<GetOsVersionCommandResult>;\n readonly isOsVersionSupported: (osVersion: string) => boolean;\n readonly renameContact: (\n input: RenameContactDAInput,\n includeDerivationPath: boolean,\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 { getOsVersion, isOsVersionSupported, renameContact } =\n this.extractDependencies(internalApi);\n // Device model is stable for the session; the fresh OS version comes from\n // the GetOsVersion step. Together they decide whether the rename payload\n // must still carry the DERIVATION_PATH (DSDK-1481).\n const { deviceModelId } = internalApi.getDeviceSessionState();\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 getOsVersion: fromPromise(getOsVersion),\n renameContact: fromPromise(\n ({\n input,\n }: {\n input: {\n args: RenameContactDAInput;\n includeDerivationPath: boolean;\n };\n }) => renameContact(input.args, input.includeDerivationPath),\n ),\n },\n guards: {\n noInternalError: ({ context }) => context._internalState.error === null,\n // Gate on the OS version read freshly via `GetOsVersion`, never the\n // session state. `osVersion` is populated by the GetOsVersion step\n // that precedes this guard; a command failure short-circuits to Error\n // before we get here, so a null here would be a machine-wiring bug.\n contactsOsSupported: ({ context }) => {\n const { osVersion } = context._internalState;\n return osVersion !== null && isOsVersionSupported(osVersion);\n },\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 osVersion: 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: \"GetOsVersion\", guard: \"noInternalError\" },\n { target: \"Error\" },\n ],\n },\n // Read the OS version freshly from the device now that the dashboard\n // (BOLOS) is reached, so the version guard evaluates real firmware\n // rather than the session state \u2014 whose `firmwareVersion` is often\n // absent on this path (GoToDashboard re-reads only the running app).\n GetOsVersion: {\n // Clear the stale interaction GoToDashboard leaves behind (e.g.\n // UnlockDevice) so this internal command step asks the user for\n // nothing. This is the one `pending / none` step of the phase.\n entry: assign({\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.None,\n },\n }),\n invoke: {\n id: \"getOsVersion\",\n src: \"getOsVersion\",\n onDone: {\n target: \"GetOsVersionResultCheck\",\n actions: assign({\n _internalState: ({ event, context }) =>\n isSuccessCommandResult(event.output)\n ? {\n ...context._internalState,\n osVersion: event.output.data.seVersion,\n }\n : // A command failure surfaces as itself, never as a\n // ContactsVersionRequirementError.\n { ...context._internalState, error: event.output.error },\n }),\n },\n onError: {\n target: \"Error\",\n actions: \"assignErrorFromEvent\",\n },\n },\n },\n GetOsVersionResultCheck: {\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 // The OS version comes from the fresh GetOsVersion result above.\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 }) => ({\n args: context.input,\n // Fresh OS version (from GetOsVersion) is guaranteed set here: a\n // null would have failed the VersionGuard before this state. The\n // ?? \"\" is a defensive no-path fallback that can never trigger.\n includeDerivationPath: renameRequiresDerivationPath(\n deviceModelId,\n context._internalState.osVersion ?? \"\",\n ),\n }),\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 getOsVersion = (): Promise<GetOsVersionCommandResult> =>\n internalApi.sendCommand(new GetOsVersionCommand());\n\n const isOsVersionSupported = (osVersion: string) =>\n isContactsOsVersionSupportedForSession(internalApi, osVersion);\n\n const renameContact = (\n input: RenameContactDAInput,\n includeDerivationPath: boolean,\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 includeDerivationPath,\n }).run();\n\n return { getOsVersion, isOsVersionSupported, renameContact };\n }\n}\n\nexport type { RenameContactProof };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["RenameContactDeviceAction_exports", "__export", "RenameContactDeviceAction", "__toCommonJS", "import_device_management_kit", "import_purify_ts", "import_xstate", "import_ContactsVersionRequirements", "import_contactsVersionGuards", "import_contactsErrors", "import_SendRenameContactTask", "import_validateRenameContactInput", "internalApi", "getOsVersion", "isOsVersionSupported", "renameContact", "deviceModelId", "input", "context", "osVersion", "error", "event", "proof", "includeDerivationPath"]
|
|
7
7
|
}
|
package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("@ledgerhq/device-management-kit"),t=require("vitest"),
|
|
1
|
+
"use strict";var e=require("@ledgerhq/device-management-kit"),t=require("vitest"),R=require("../../../app-binder/device-action/__test-utils__/makeInternalApi"),d=require("../../../app-binder/device-action/__test-utils__/setupGoToDashboardDAMock"),u=require("../../../app-binder/device-action/__test-utils__/testDeviceActionStates"),D=require("../../../app-binder/model/contactsErrors"),V=require("./RenameContactDeviceAction"),I=require("./validateRenameContactInput");t.vi.mock("@ledgerhq/device-management-kit",async a=>({...await a(),GoToDashboardDeviceAction:t.vi.fn(()=>({makeStateMachine:t.vi.fn()})),OpenAppDeviceAction:t.vi.fn(()=>({makeStateMachine:t.vi.fn()}))}));const f={hmacProof:new Uint8Array(32).fill(238)},C="1.7.0",c={previousContactName:"Alice",newContactName:"Bob",groupHandle:new Uint8Array(64).fill(204),hmacProof:new Uint8Array(32).fill(221)},A={previousContactName:"Alice",contactName:"Bob",groupHandle:c.groupHandle,hmacProof:f.hmacProof};(0,t.describe)("RenameContactDeviceAction",()=>{let a,s,l,m;function g(){return{getOsVersion:s,isOsVersionSupported:l,renameContact:m}}(0,t.beforeEach)(()=>{t.vi.clearAllMocks(),a=(0,R.makeDeviceActionInternalApiMock)(),s=t.vi.fn().mockResolvedValue((0,e.CommandResultFactory)({data:{seVersion:C}})),l=t.vi.fn().mockReturnValue(!0),m=t.vi.fn().mockResolvedValue((0,e.CommandResultFactory)({data:f})),a.getDeviceSessionState.mockReturnValue({sessionStateType:e.DeviceSessionStateType.ReadyWithoutSecureChannel,deviceStatus:e.DeviceStatus.CONNECTED,installedApps:[],currentApp:{name:"BOLOS",version:"1.7.0"},deviceModelId:e.DeviceModelId.FLEX,isSecureConnectionAllowed:!0})});function v(o){const r=new V.RenameContactDeviceAction({input:o});return t.vi.spyOn(r,"extractDependencies").mockReturnValue(g()),r}(0,t.it)("navigates to the dashboard, reads the OS freshly, renames, and completes",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const n=v(c),i=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.RegisterWallet},status:e.DeviceActionStatus.Pending},{output:A,status:e.DeviceActionStatus.Completed}];(0,u.testDeviceActionStates)(n,i,a,{onDone:()=>{(0,t.expect)(e.GoToDashboardDeviceAction).toHaveBeenCalled(),(0,t.expect)(e.OpenAppDeviceAction).not.toHaveBeenCalled(),(0,t.expect)(s).toHaveBeenCalled(),(0,t.expect)(l).toHaveBeenCalledWith(C),o()},onError:r})})),(0,t.it)("succeeds when an app was open at start, gating on the freshly-read OS",()=>new Promise((o,r)=>{a.getDeviceSessionState.mockReturnValue({sessionStateType:e.DeviceSessionStateType.ReadyWithoutSecureChannel,deviceStatus:e.DeviceStatus.CONNECTED,installedApps:[],currentApp:{name:"Ethereum",version:"1.23.0"},deviceModelId:e.DeviceModelId.FLEX,isSecureConnectionAllowed:!0}),(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const n=v(c),i=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.RegisterWallet},status:e.DeviceActionStatus.Pending},{output:A,status:e.DeviceActionStatus.Completed}];(0,u.testDeviceActionStates)(n,i,a,{onDone:()=>{(0,t.expect)(s).toHaveBeenCalled(),(0,t.expect)(l).toHaveBeenCalledWith(C),o()},onError:r})})),(0,t.it)("rejects on an unsupported OS version without sending the APDU",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice}),l.mockReturnValue(!1);const n=v(c),i=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{error:new D.ContactsVersionRequirementError,status:e.DeviceActionStatus.Error}];(0,u.testDeviceActionStates)(n,i,a,{onDone:()=>{(0,t.expect)(s).toHaveBeenCalled(),(0,t.expect)(l).toHaveBeenCalledWith(C),(0,t.expect)(m).not.toHaveBeenCalled(),(0,t.expect)(e.OpenAppDeviceAction).not.toHaveBeenCalled(),o()},onError:r})})),(0,t.it)("surfaces a go-to-dashboard failure as the device action error",()=>new Promise((o,r)=>{const n=new e.UnknownDAError("go to dashboard failed");(0,d.setupGoToDashboardDAMock)({error:n,requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const i=v(c),p=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{error:n,status:e.DeviceActionStatus.Error}];(0,u.testDeviceActionStates)(i,p,a,{onDone:()=>{(0,t.expect)(s).not.toHaveBeenCalled(),(0,t.expect)(l).not.toHaveBeenCalled(),(0,t.expect)(m).not.toHaveBeenCalled(),o()},onError:r})})),(0,t.it)("surfaces a rename command error (e.g. seed mismatch)",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const n=new D.ContactsCommandError({errorCode:"6982",message:"wrong seed"});m.mockResolvedValue((0,e.CommandResultFactory)({error:n}));const i=v(c),p=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.RegisterWallet},status:e.DeviceActionStatus.Pending},{error:n,status:e.DeviceActionStatus.Error}];(0,u.testDeviceActionStates)(i,p,a,{onDone:o,onError:r})})),(0,t.it)("surfaces invalid input as a typed error after reaching the dashboard",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const n={...c,newContactName:""},i=(0,I.validateRenameContactInput)(n),p=v(n),h=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{error:i,status:e.DeviceActionStatus.Error}];(0,u.testDeviceActionStates)(p,h,a,{onDone:()=>{(0,t.expect)(s).not.toHaveBeenCalled(),(0,t.expect)(l).not.toHaveBeenCalled(),(0,t.expect)(m).not.toHaveBeenCalled(),o()},onError:r})})),(0,t.it)("surfaces a GetOsVersion failure as the command error, not a version error",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice});const n=new D.ContactsCommandError({errorCode:"6f00",message:"GetOsVersion failed"});s.mockResolvedValue((0,e.CommandResultFactory)({error:n}));const i=v(c),p=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{error:n,status:e.DeviceActionStatus.Error}];(0,u.testDeviceActionStates)(i,p,a,{onDone:()=>{(0,t.expect)(l).not.toHaveBeenCalled(),(0,t.expect)(m).not.toHaveBeenCalled(),o()},onError:r})}));const U=[{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.UnlockDevice},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.None},status:e.DeviceActionStatus.Pending},{intermediateValue:{requiredUserInteraction:e.UserInteractionRequired.RegisterWallet},status:e.DeviceActionStatus.Pending},{output:A,status:e.DeviceActionStatus.Completed}];(0,t.it)("sends the derivation path when the fresh OS is below the model cutoff (rc2)",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice}),s.mockResolvedValue((0,e.CommandResultFactory)({data:{seVersion:"1.7.0-rc2"}}));const n=v(c);(0,u.testDeviceActionStates)(n,U,a,{onDone:()=>{(0,t.expect)(m).toHaveBeenCalledWith(c,!0),o()},onError:r})})),(0,t.it)("omits the derivation path when the fresh OS is at/after the cutoff (rc3/GA)",()=>new Promise((o,r)=>{(0,d.setupGoToDashboardDAMock)({requiredUserInteraction:e.UserInteractionRequired.UnlockDevice}),s.mockResolvedValue((0,e.CommandResultFactory)({data:{seVersion:"1.7.0-rc3"}}));const n=v(c);(0,u.testDeviceActionStates)(n,U,a,{onDone:()=>{(0,t.expect)(m).toHaveBeenCalledWith(c,!1),o()},onError:r})}))});
|
|
2
2
|
//# sourceMappingURL=RenameContactDeviceAction.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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": "aAAA,IAAAA,EAWO,2CACPC,EAAqD,kBAQrDC,EAAgD,6EAChDC,EAAyC,sFACzCC,EAAuC,oFACvCC,EAGO,qDAEPC,EAA0C,uCAC1CC,EAA2C,wCAE3C,KAAG,KAAK,kCAAmC,MAAOC,IAIzC,CACL,GAFA,MAAMA,EAAiE,EAGvE,0BAA2B,KAAG,GAAG,KAAO,CACtC,iBAAkB,KAAG,GAAG,CAC1B,EAAE,EACF,oBAAqB,KAAG,GAAG,KAAO,CAChC,iBAAkB,KAAG,GAAG,CAC1B,EAAE,CACJ,EACD,EAED,MAAMC,EAAW,CAAE,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CAAE,
|
|
6
|
-
"names": ["import_device_management_kit", "import_vitest", "import_makeInternalApi", "import_setupGoToDashboardDAMock", "import_testDeviceActionStates", "import_contactsErrors", "import_RenameContactDeviceAction", "import_validateRenameContactInput", "importOriginal", "OK_PROOF", "BASE_INPUT", "EXPECTED_OUTPUT", "apiMock", "
|
|
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\n// The OS version the device returns freshly via GetOsVersion after the\n// dashboard is reached. The version guard must be fed *this*, not session state.\nconst FRESH_OS_VERSION = \"1.7.0\";\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 getOsVersionMock: ReturnType<typeof vi.fn>;\n let isOsVersionSupportedMock: ReturnType<typeof vi.fn>;\n let renameContactMock: ReturnType<typeof vi.fn>;\n\n function extractDeps() {\n return {\n getOsVersion: getOsVersionMock,\n isOsVersionSupported: isOsVersionSupportedMock,\n renameContact: renameContactMock,\n };\n }\n\n beforeEach(() => {\n vi.clearAllMocks();\n apiMock = makeDeviceActionInternalApiMock();\n getOsVersionMock = vi\n .fn()\n .mockResolvedValue(\n CommandResultFactory({ data: { seVersion: FRESH_OS_VERSION } }),\n );\n isOsVersionSupportedMock = 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, reads the OS freshly, 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 // GetOsVersion clears the stale UnlockDevice interaction: one\n // `pending / none` step before the rename prompt.\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: 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 // The OS version is read freshly and fed to the guard \u2014 not the\n // session state.\n expect(getOsVersionMock).toHaveBeenCalled();\n expect(isOsVersionSupportedMock).toHaveBeenCalledWith(\n FRESH_OS_VERSION,\n );\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"succeeds when an app was open at start, gating on the freshly-read OS\", () =>\n new Promise<void>((resolve, reject) => {\n // An app (Ethereum) is running when rename begins \u2014 the scenario that\n // left firmwareVersion absent and made the bug look intermittent. Rename\n // must still succeed by reading the OS version fresh after the dashboard.\n apiMock.getDeviceSessionState.mockReturnValue({\n sessionStateType: DeviceSessionStateType.ReadyWithoutSecureChannel,\n deviceStatus: DeviceStatus.CONNECTED,\n installedApps: [],\n currentApp: { name: \"Ethereum\", version: \"1.23.0\" },\n deviceModelId: DeviceModelId.FLEX,\n isSecureConnectionAllowed: true,\n });\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.None,\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 expect(getOsVersionMock).toHaveBeenCalled();\n expect(isOsVersionSupportedMock).toHaveBeenCalledWith(\n FRESH_OS_VERSION,\n );\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 isOsVersionSupportedMock.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 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 RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n // The fresh OS version was read and gated on.\n expect(getOsVersionMock).toHaveBeenCalled();\n expect(isOsVersionSupportedMock).toHaveBeenCalledWith(\n FRESH_OS_VERSION,\n );\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(getOsVersionMock).not.toHaveBeenCalled();\n expect(isOsVersionSupportedMock).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.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 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 OS is read, the version guard, and any\n // APDU.\n expect(getOsVersionMock).not.toHaveBeenCalled();\n expect(isOsVersionSupportedMock).not.toHaveBeenCalled();\n expect(renameContactMock).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"surfaces a GetOsVersion failure as the command error, not a version error\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n const osVersionError = new ContactsCommandError({\n errorCode: \"6f00\",\n message: \"GetOsVersion failed\",\n });\n getOsVersionMock.mockResolvedValue(\n CommandResultFactory({ error: osVersionError }),\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.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n error: osVersionError,\n status: DeviceActionStatus.Error,\n },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n testDeviceActionStates(action, expected, apiMock, {\n onDone: () => {\n // The version guard is never consulted, and the rename APDU is never\n // sent: the raw command error propagates instead of a\n // ContactsVersionRequirementError.\n expect(isOsVersionSupportedMock).not.toHaveBeenCalled();\n expect(renameContactMock).not.toHaveBeenCalled();\n resolve();\n },\n onError: reject,\n });\n }));\n\n // DSDK-1481: the derivation-path flag is derived from the fresh OS version +\n // the (real) requirements table. deviceModelId is FLEX (cutoff 1.7.0-rc3).\n const SUCCESS_STATES = [\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.None,\n },\n status: DeviceActionStatus.Pending,\n },\n {\n intermediateValue: {\n requiredUserInteraction: UserInteractionRequired.RegisterWallet,\n },\n status: DeviceActionStatus.Pending,\n },\n { output: EXPECTED_OUTPUT, status: DeviceActionStatus.Completed },\n ] as DeviceActionState<\n RenameContactDAOutput,\n RenameContactDAError,\n RenameContactDAIntermediateValue\n >[];\n\n it(\"sends the derivation path when the fresh OS is below the model cutoff (rc2)\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n getOsVersionMock.mockResolvedValue(\n CommandResultFactory({ data: { seVersion: \"1.7.0-rc2\" } }),\n );\n const action = makeAction(BASE_INPUT);\n\n testDeviceActionStates(action, SUCCESS_STATES, apiMock, {\n onDone: () => {\n expect(renameContactMock).toHaveBeenCalledWith(BASE_INPUT, true);\n resolve();\n },\n onError: reject,\n });\n }));\n\n it(\"omits the derivation path when the fresh OS is at/after the cutoff (rc3/GA)\", () =>\n new Promise<void>((resolve, reject) => {\n setupGoToDashboardDAMock({\n requiredUserInteraction: UserInteractionRequired.UnlockDevice,\n });\n getOsVersionMock.mockResolvedValue(\n CommandResultFactory({ data: { seVersion: \"1.7.0-rc3\" } }),\n );\n const action = makeAction(BASE_INPUT);\n\n testDeviceActionStates(action, SUCCESS_STATES, apiMock, {\n onDone: () => {\n expect(renameContactMock).toHaveBeenCalledWith(BASE_INPUT, false);\n resolve();\n },\n onError: reject,\n });\n }));\n});\n"],
|
|
5
|
+
"mappings": "aAAA,IAAAA,EAWO,2CACPC,EAAqD,kBAQrDC,EAAgD,6EAChDC,EAAyC,sFACzCC,EAAuC,oFACvCC,EAGO,qDAEPC,EAA0C,uCAC1CC,EAA2C,wCAE3C,KAAG,KAAK,kCAAmC,MAAOC,IAIzC,CACL,GAFA,MAAMA,EAAiE,EAGvE,0BAA2B,KAAG,GAAG,KAAO,CACtC,iBAAkB,KAAG,GAAG,CAC1B,EAAE,EACF,oBAAqB,KAAG,GAAG,KAAO,CAChC,iBAAkB,KAAG,GAAG,CAC1B,EAAE,CACJ,EACD,EAED,MAAMC,EAAW,CAAE,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CAAE,EAItDC,EAAmB,QAEnBC,EAAmC,CACvC,oBAAqB,QACrB,eAAgB,MAChB,YAAa,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,EACzC,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CACzC,EAEMC,EAAyC,CAC7C,oBAAqB,QACrB,YAAa,MACb,YAAaD,EAAW,YACxB,UAAWF,EAAS,SACtB,KAEA,YAAS,4BAA6B,IAAM,CAC1C,IAAII,EACAC,EACAC,EACAC,EAEJ,SAASC,GAAc,CACrB,MAAO,CACL,aAAcH,EACd,qBAAsBC,EACtB,cAAeC,CACjB,CACF,IAEA,cAAW,IAAM,CACf,KAAG,cAAc,EACjBH,KAAU,mCAAgC,EAC1CC,EAAmB,KAChB,GAAG,EACH,qBACC,wBAAqB,CAAE,KAAM,CAAE,UAAWJ,CAAiB,CAAE,CAAC,CAChE,EACFK,EAA2B,KAAG,GAAG,EAAE,gBAAgB,EAAI,EACvDC,EAAoB,KACjB,GAAG,EACH,qBAAkB,wBAAqB,CAAE,KAAMP,CAAS,CAAC,CAAC,EAC7DI,EAAQ,sBAAsB,gBAAgB,CAC5C,iBAAkB,yBAAuB,0BACzC,aAAc,eAAa,UAC3B,cAAe,CAAC,EAChB,WAAY,CAAE,KAAM,QAAS,QAAS,OAAQ,EAC9C,cAAe,gBAAc,KAC7B,0BAA2B,EAC7B,CAAC,CACH,CAAC,EAED,SAASK,EAAWC,EAA6B,CAC/C,MAAMC,EAAS,IAAI,4BAA0B,CAAE,MAAAD,CAAM,CAAC,EACtD,YAAG,MAAMC,EAAQ,qBAAqB,EAAE,gBAAgBH,EAAY,CAAC,EAC9DG,CACT,IAEA,MAAG,2EAA4E,IAC7E,IAAI,QAAc,CAACC,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMF,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EAGA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,cACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,OAAQX,EACR,OAAQ,qBAAmB,SAC7B,CACF,KAMA,0BAAuBQ,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IAGZ,UAAO,2BAAyB,EAAE,iBAAiB,KACnD,UAAO,qBAAmB,EAAE,IAAI,iBAAiB,KAGjD,UAAOC,CAAgB,EAAE,iBAAiB,KAC1C,UAAOC,CAAwB,EAAE,qBAC/BL,CACF,EACAW,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,wEAAyE,IAC1E,IAAI,QAAc,CAACD,EAASC,IAAW,CAIrCT,EAAQ,sBAAsB,gBAAgB,CAC5C,iBAAkB,yBAAuB,0BACzC,aAAc,eAAa,UAC3B,cAAe,CAAC,EAChB,WAAY,CAAE,KAAM,WAAY,QAAS,QAAS,EAClD,cAAe,gBAAc,KAC7B,0BAA2B,EAC7B,CAAC,KACD,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMO,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,cACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,OAAQX,EACR,OAAQ,qBAAmB,SAC7B,CACF,KAMA,0BAAuBQ,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IACZ,UAAOC,CAAgB,EAAE,iBAAiB,KAC1C,UAAOC,CAAwB,EAAE,qBAC/BL,CACF,EACAW,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,gEAAiE,IAClE,IAAI,QAAc,CAACD,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACDP,EAAyB,gBAAgB,EAAK,EAC9C,MAAMK,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,MAAO,IAAI,kCACX,OAAQ,qBAAmB,KAC7B,CACF,KAMA,0BAAuBH,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IAEZ,UAAOC,CAAgB,EAAE,iBAAiB,KAC1C,UAAOC,CAAwB,EAAE,qBAC/BL,CACF,KACA,UAAOM,CAAiB,EAAE,IAAI,iBAAiB,KAC/C,UAAO,qBAAmB,EAAE,IAAI,iBAAiB,EACjDK,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,gEAAiE,IAClE,IAAI,QAAc,CAACD,EAASC,IAAW,CACrC,MAAME,EAAiB,IAAI,iBAAe,wBAAwB,KAClE,4BAAyB,CACvB,MAAOA,EACP,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMJ,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,MAAOC,EACP,OAAQ,qBAAmB,KAC7B,CACF,KAMA,0BAAuBJ,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IACZ,UAAOC,CAAgB,EAAE,IAAI,iBAAiB,KAC9C,UAAOC,CAAwB,EAAE,IAAI,iBAAiB,KACtD,UAAOC,CAAiB,EAAE,IAAI,iBAAiB,EAC/CK,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,uDAAwD,IACzD,IAAI,QAAc,CAACD,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMG,EAAe,IAAI,uBAAqB,CAC5C,UAAW,OACX,QAAS,YACX,CAAC,EACDT,EAAkB,qBAChB,wBAAqB,CAAE,MAAOS,CAAa,CAAC,CAC9C,EACA,MAAML,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,cACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,MAAOE,EACP,OAAQ,qBAAmB,KAC7B,CACF,KAMA,0BAAuBL,EAAQG,EAAUV,EAAS,CAChD,OAAQQ,EACR,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,uEAAwE,IACzE,IAAI,QAAc,CAACD,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMI,EAAe,CAAE,GAAGf,EAAY,eAAgB,EAAG,EACnDgB,KAAkB,8BAA2BD,CAAY,EACzDN,EAASF,EAAWQ,CAAY,EAEhCH,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,MAAOI,EACP,OAAQ,qBAAmB,KAC7B,CACF,KAMA,0BAAuBP,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IAGZ,UAAOC,CAAgB,EAAE,IAAI,iBAAiB,KAC9C,UAAOC,CAAwB,EAAE,IAAI,iBAAiB,KACtD,UAAOC,CAAiB,EAAE,IAAI,iBAAiB,EAC/CK,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,4EAA6E,IAC9E,IAAI,QAAc,CAACD,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACD,MAAMM,EAAiB,IAAI,uBAAqB,CAC9C,UAAW,OACX,QAAS,qBACX,CAAC,EACDd,EAAiB,qBACf,wBAAqB,CAAE,MAAOc,CAAe,CAAC,CAChD,EACA,MAAMR,EAASF,EAAWP,CAAU,EAE9BY,EAAW,CACf,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,MAAOK,EACP,OAAQ,qBAAmB,KAC7B,CACF,KAMA,0BAAuBR,EAAQG,EAAUV,EAAS,CAChD,OAAQ,IAAM,IAIZ,UAAOE,CAAwB,EAAE,IAAI,iBAAiB,KACtD,UAAOC,CAAiB,EAAE,IAAI,iBAAiB,EAC/CK,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,EAIJ,MAAMO,EAAiB,CACrB,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,YACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,IACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CACE,kBAAmB,CACjB,wBAAyB,0BAAwB,cACnD,EACA,OAAQ,qBAAmB,OAC7B,EACA,CAAE,OAAQjB,EAAiB,OAAQ,qBAAmB,SAAU,CAClE,KAMA,MAAG,8EAA+E,IAChF,IAAI,QAAc,CAACS,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACDR,EAAiB,qBACf,wBAAqB,CAAE,KAAM,CAAE,UAAW,WAAY,CAAE,CAAC,CAC3D,EACA,MAAMM,EAASF,EAAWP,CAAU,KAEpC,0BAAuBS,EAAQS,EAAgBhB,EAAS,CACtD,OAAQ,IAAM,IACZ,UAAOG,CAAiB,EAAE,qBAAqBL,EAAY,EAAI,EAC/DU,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,KAEJ,MAAG,8EAA+E,IAChF,IAAI,QAAc,CAACD,EAASC,IAAW,IACrC,4BAAyB,CACvB,wBAAyB,0BAAwB,YACnD,CAAC,EACDR,EAAiB,qBACf,wBAAqB,CAAE,KAAM,CAAE,UAAW,WAAY,CAAE,CAAC,CAC3D,EACA,MAAMM,EAASF,EAAWP,CAAU,KAEpC,0BAAuBS,EAAQS,EAAgBhB,EAAS,CACtD,OAAQ,IAAM,IACZ,UAAOG,CAAiB,EAAE,qBAAqBL,EAAY,EAAK,EAChEU,EAAQ,CACV,EACA,QAASC,CACX,CAAC,CACH,CAAC,CAAC,CACN,CAAC",
|
|
6
|
+
"names": ["import_device_management_kit", "import_vitest", "import_makeInternalApi", "import_setupGoToDashboardDAMock", "import_testDeviceActionStates", "import_contactsErrors", "import_RenameContactDeviceAction", "import_validateRenameContactInput", "importOriginal", "OK_PROOF", "FRESH_OS_VERSION", "BASE_INPUT", "EXPECTED_OUTPUT", "apiMock", "getOsVersionMock", "isOsVersionSupportedMock", "renameContactMock", "extractDeps", "makeAction", "input", "action", "resolve", "reject", "expected", "dashboardError", "commandError", "invalidInput", "validationError", "osVersionError", "SUCCESS_STATES"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var C=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var e=Object.prototype.hasOwnProperty;var n=(_,o)=>{for(var x in o)C(_,x,{get:o[x],enumerable:!0})},r=(_,o,x,A)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of T(o))!e.call(_,t)&&t!==x&&C(_,t,{get:()=>o[t],enumerable:!(A=E(o,t))||A.enumerable});return _};var c=_=>r(C({},"__esModule",{value:!0}),_);var H={};n(H,{BLOCKCHAIN_FAMILY_BY_NAME:()=>a,CONTACTS_APDU_CLA:()=>s,CONTACTS_APDU_INS:()=>N,GROUP_HANDLE_BYTES:()=>B,HMAC_NAME_BYTES:()=>Y,HMAC_PROOF_BYTES:()=>P,HMAC_REST_BYTES:()=>U,RENAME_CONTACT_APDU_CLA:()=>M,RENAME_CONTACT_APDU_INS:()=>O,RENAME_CONTACT_P1:()=>R,SUB_CMD_EDIT_IDENTIFIER:()=>D,SUB_CMD_EDIT_SCOPE:()=>I,SUB_CMD_PROVIDE_CONTACT:()=>S,SUB_CMD_REGISTER_IDENTITY:()=>p});module.exports=c(H);const s=176,N=16,p=1,S=32,D=3,I=4,M=224,O=46,R=0,B=64,P=32,U=32,Y=32,a={bitcoin:0,ethereum:1,solana:2,polkadot:3,cosmos:4,cardano:5};0&&(module.exports={BLOCKCHAIN_FAMILY_BY_NAME,CONTACTS_APDU_CLA,CONTACTS_APDU_INS,GROUP_HANDLE_BYTES,HMAC_NAME_BYTES,HMAC_PROOF_BYTES,HMAC_REST_BYTES,RENAME_CONTACT_APDU_CLA,RENAME_CONTACT_APDU_INS,RENAME_CONTACT_P1,SUB_CMD_EDIT_IDENTIFIER,SUB_CMD_EDIT_SCOPE,SUB_CMD_PROVIDE_CONTACT,SUB_CMD_REGISTER_IDENTITY});
|
|
1
|
+
"use strict";var C=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var e=Object.prototype.hasOwnProperty;var n=(_,o)=>{for(var x in o)C(_,x,{get:o[x],enumerable:!0})},r=(_,o,x,A)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of T(o))!e.call(_,t)&&t!==x&&C(_,t,{get:()=>o[t],enumerable:!(A=E(o,t))||A.enumerable});return _};var c=_=>r(C({},"__esModule",{value:!0}),_);var H={};n(H,{BLOCKCHAIN_FAMILY_BY_NAME:()=>a,CONTACTS_APDU_CLA:()=>s,CONTACTS_APDU_INS:()=>N,GROUP_HANDLE_BYTES:()=>B,HMAC_NAME_BYTES:()=>Y,HMAC_PROOF_BYTES:()=>P,HMAC_REST_BYTES:()=>U,RENAME_CONTACT_APDU_CLA:()=>M,RENAME_CONTACT_APDU_INS:()=>O,RENAME_CONTACT_P1:()=>R,SUB_CMD_EDIT_IDENTIFIER:()=>D,SUB_CMD_EDIT_SCOPE:()=>I,SUB_CMD_PROVIDE_CONTACT:()=>S,SUB_CMD_REGISTER_IDENTITY:()=>p});module.exports=c(H);const s=176,N=16,p=1,S=32,D=3,I=4,M=224,O=46,R=0,B=64,P=32,U=32,Y=32,a={bitcoin:0,ethereum:1,solana:2,polkadot:3,cosmos:4,cardano:5,tron:6};0&&(module.exports={BLOCKCHAIN_FAMILY_BY_NAME,CONTACTS_APDU_CLA,CONTACTS_APDU_INS,GROUP_HANDLE_BYTES,HMAC_NAME_BYTES,HMAC_PROOF_BYTES,HMAC_REST_BYTES,RENAME_CONTACT_APDU_CLA,RENAME_CONTACT_APDU_INS,RENAME_CONTACT_P1,SUB_CMD_EDIT_IDENTIFIER,SUB_CMD_EDIT_SCOPE,SUB_CMD_PROVIDE_CONTACT,SUB_CMD_REGISTER_IDENTITY});
|
|
2
2
|
//# sourceMappingURL=contactsConstants.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/model/contactsConstants.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Protocol constants shared by the Contacts (Address Book) operations.\n *\n * Wire format and values follow the BOLOS SDK Address Book specification\n * (ledger-secure-sdk/app_features/address_book). Op-specific sub-command bytes\n * and response field sizes live here; TLV tags and struct-type bytes live in\n * {@link ./../services/contactsTlvSerializer}.\n */\n\n/** APDU class/instruction shared by every Address Book sub-command. */\nexport const CONTACTS_APDU_CLA = 0xb0;\nexport const CONTACTS_APDU_INS = 0x10;\n\n/** P1 sub-command selector for REGISTER IDENTITY (register external address). */\nexport const SUB_CMD_REGISTER_IDENTITY = 0x01;\n\n/** P1 sub-command selector for PROVIDE CONTACT (pre-signing decoration). */\nexport const SUB_CMD_PROVIDE_CONTACT = 0x20;\n\n/**\n * P1 sub-command selector for EDIT IDENTIFIER \u2014 an address-book app sub-command\n * (CLA 0xB0 / INS 0x10) served by the coin app, never OS-dispatched.\n */\nexport const SUB_CMD_EDIT_IDENTIFIER = 0x03;\n\n/**\n * P1 sub-command selector for EDIT SCOPE \u2014 an address-book app sub-command\n * (CLA 0xB0 / INS 0x10) served by the coin app, never OS-dispatched. Changes an\n * entry's scope while keeping its contact name and identifier.\n */\nexport const SUB_CMD_EDIT_SCOPE = 0x04;\n\n/**\n * EDIT CONTACT NAME (rename) is a blockchain-agnostic OS/dashboard command with\n * its own CLA/INS \u2014 NOT a sub-command of the address-book app APDU (0xB0/0x10).\n * The OS serves it directly, so it must run on the dashboard. P1 is a fixed\n * 0x00 (there is no sub-command selector for this command); P2 still carries the\n * chunk-continuation flag handled by {@link ./../services/sendFramedContactsPayload}.\n */\nexport const RENAME_CONTACT_APDU_CLA = 0xe0;\nexport const RENAME_CONTACT_APDU_INS = 0x2e;\nexport const RENAME_CONTACT_P1 = 0x00;\n\n/** Sizes (bytes) of the fields in the REGISTER IDENTITY final-chunk response. */\nexport const GROUP_HANDLE_BYTES = 64;\nexport const HMAC_PROOF_BYTES = 32;\nexport const HMAC_REST_BYTES = 32;\n\n/**\n * Size (bytes) of the rotated `hmac_name` returned on the EDIT CONTACT NAME\n * final-chunk response \u2014 the replacement group-level name proof.\n */\nexport const HMAC_NAME_BYTES = 32;\n\n/**\n * Blockchain-family byte encoded in the `BLOCKCHAIN_FAMILY` TLV, keyed by a\n * lowercase family name.
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,+BAAAE,EAAA,sBAAAC,EAAA,sBAAAC,EAAA,uBAAAC,EAAA,oBAAAC,EAAA,qBAAAC,EAAA,oBAAAC,EAAA,4BAAAC,EAAA,4BAAAC,EAAA,sBAAAC,EAAA,4BAAAC,EAAA,uBAAAC,EAAA,4BAAAC,EAAA,8BAAAC,IAAA,eAAAC,EAAAhB,GAUO,MAAMG,EAAoB,IACpBC,EAAoB,GAGpBW,EAA4B,EAG5BD,EAA0B,GAM1BF,EAA0B,EAO1BC,EAAqB,EASrBJ,EAA0B,IAC1BC,EAA0B,GAC1BC,EAAoB,EAGpBN,EAAqB,GACrBE,EAAmB,GACnBC,EAAkB,GAMlBF,EAAkB,GAOlBJ,EAA8D,CACzE,QAAS,EACT,SAAU,EACV,OAAQ,EACR,SAAU,EACV,OAAQ,EACR,QAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Protocol constants shared by the Contacts (Address Book) operations.\n *\n * Wire format and values follow the BOLOS SDK Address Book specification\n * (ledger-secure-sdk/app_features/address_book). Op-specific sub-command bytes\n * and response field sizes live here; TLV tags and struct-type bytes live in\n * {@link ./../services/contactsTlvSerializer}.\n */\n\n/** APDU class/instruction shared by every Address Book sub-command. */\nexport const CONTACTS_APDU_CLA = 0xb0;\nexport const CONTACTS_APDU_INS = 0x10;\n\n/** P1 sub-command selector for REGISTER IDENTITY (register external address). */\nexport const SUB_CMD_REGISTER_IDENTITY = 0x01;\n\n/** P1 sub-command selector for PROVIDE CONTACT (pre-signing decoration). */\nexport const SUB_CMD_PROVIDE_CONTACT = 0x20;\n\n/**\n * P1 sub-command selector for EDIT IDENTIFIER \u2014 an address-book app sub-command\n * (CLA 0xB0 / INS 0x10) served by the coin app, never OS-dispatched.\n */\nexport const SUB_CMD_EDIT_IDENTIFIER = 0x03;\n\n/**\n * P1 sub-command selector for EDIT SCOPE \u2014 an address-book app sub-command\n * (CLA 0xB0 / INS 0x10) served by the coin app, never OS-dispatched. Changes an\n * entry's scope while keeping its contact name and identifier.\n */\nexport const SUB_CMD_EDIT_SCOPE = 0x04;\n\n/**\n * EDIT CONTACT NAME (rename) is a blockchain-agnostic OS/dashboard command with\n * its own CLA/INS \u2014 NOT a sub-command of the address-book app APDU (0xB0/0x10).\n * The OS serves it directly, so it must run on the dashboard. P1 is a fixed\n * 0x00 (there is no sub-command selector for this command); P2 still carries the\n * chunk-continuation flag handled by {@link ./../services/sendFramedContactsPayload}.\n */\nexport const RENAME_CONTACT_APDU_CLA = 0xe0;\nexport const RENAME_CONTACT_APDU_INS = 0x2e;\nexport const RENAME_CONTACT_P1 = 0x00;\n\n/** Sizes (bytes) of the fields in the REGISTER IDENTITY final-chunk response. */\nexport const GROUP_HANDLE_BYTES = 64;\nexport const HMAC_PROOF_BYTES = 32;\nexport const HMAC_REST_BYTES = 32;\n\n/**\n * Size (bytes) of the rotated `hmac_name` returned on the EDIT CONTACT NAME\n * final-chunk response \u2014 the replacement group-level name proof.\n */\nexport const HMAC_NAME_BYTES = 32;\n\n/**\n * Blockchain-family byte encoded in the `BLOCKCHAIN_FAMILY` TLV, keyed by a\n * lowercase family name. Values follow the BOLOS Address Book family enum\n * (`BlockchainFamily` in ragger / ledger-secure-sdk).\n */\nexport const BLOCKCHAIN_FAMILY_BY_NAME: Readonly<Record<string, number>> = {\n bitcoin: 0x00,\n ethereum: 0x01,\n solana: 0x02,\n polkadot: 0x03,\n cosmos: 0x04,\n cardano: 0x05,\n tron: 0x06,\n};\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,+BAAAE,EAAA,sBAAAC,EAAA,sBAAAC,EAAA,uBAAAC,EAAA,oBAAAC,EAAA,qBAAAC,EAAA,oBAAAC,EAAA,4BAAAC,EAAA,4BAAAC,EAAA,sBAAAC,EAAA,4BAAAC,EAAA,uBAAAC,EAAA,4BAAAC,EAAA,8BAAAC,IAAA,eAAAC,EAAAhB,GAUO,MAAMG,EAAoB,IACpBC,EAAoB,GAGpBW,EAA4B,EAG5BD,EAA0B,GAM1BF,EAA0B,EAO1BC,EAAqB,EASrBJ,EAA0B,IAC1BC,EAA0B,GAC1BC,EAAoB,EAGpBN,EAAqB,GACrBE,EAAmB,GACnBC,EAAkB,GAMlBF,EAAkB,GAOlBJ,EAA8D,CACzE,QAAS,EACT,SAAU,EACV,OAAQ,EACR,SAAU,EACV,OAAQ,EACR,QAAS,EACT,KAAM,CACR",
|
|
6
6
|
"names": ["contactsConstants_exports", "__export", "BLOCKCHAIN_FAMILY_BY_NAME", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_NAME_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "RENAME_CONTACT_APDU_CLA", "RENAME_CONTACT_APDU_INS", "RENAME_CONTACT_P1", "SUB_CMD_EDIT_IDENTIFIER", "SUB_CMD_EDIT_SCOPE", "SUB_CMD_PROVIDE_CONTACT", "SUB_CMD_REGISTER_IDENTITY", "__toCommonJS"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var n=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var g=(r,e)=>{for(var t in e)n(r,t,{get:e[t],enumerable:!0})},l=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of u(e))!E.call(r,s)&&s!==t&&n(r,s,{get:()=>e[s],enumerable:!(a=C(e,s))||a.enumerable});return r};var f=r=>l(n({},"__esModule",{value:!0}),r);var v={};g(v,{CONTACTS_APP_ERRORS:()=>m,CONTACT_SEED_MISMATCH_ERROR_CODE:()=>c,ContactsCommandError:()=>i,ContactsCommandErrorHelper:()=>h,ContactsVersionRequirementError:()=>y,contactsCommandErrorFactory:()=>p});module.exports=f(v);var o=require("@ledgerhq/device-management-kit"),d=require("@ledgerhq/signer-utils");const c="6982",m={[c]:{message:"This address-book entry was registered with a different seed. Connect the Ledger device that registered it to modify this contact."},6800:{message:"Internal error (Please report)"},6983:{message:"Wrong data length"},6984:{message:"Unsupported address-book operation for this device or app configuration"},6985:{message:"Condition not satisfied"},"686a":{message:"This device's firmware is out of date for the address book. Update your Ledger device to the latest firmware, then try again."},"6a80":{message:"Invalid contact data, or operation refused on device"},"6a84":{message:"Insufficient memory: the device address book is full"},"6a88":{message:"Contact data not found"},"6af0":{message:"Invalid value for this contact entry"},"6b00":{message:"The app rejected the contact data"},"6f00":{message:"Technical problem (Internal error, please report)"}};class i extends o.DeviceExchangeError{constructor(e){super({tag:"ContactsCommandError",...e})}}const p=r=>new i(r);class h extends d.CommandErrorHelper{constructor(){super(m,p)}getError(e){const t=super.getError(e);if(t===void 0||(0,o.isSuccessCommandResult)(t)||t.error._tag!=="UnknownDeviceExchangeError")return t;const a=new o.ApduParser(e).encodeToHexaString(e.statusCode);return(0,o.DmkResultFactory)({error:new o.InvalidStatusWordError(`The device returned an unexpected status word (0x${a}) for this address-book operation. Update your Ledger device and Ethereum app to the latest version, then try again.`)})}}class y{constructor(e="The connected device or app does not meet the Contacts version requirements."){this.message=e}_tag="ContactsVersionRequirementError";originalError}0&&(module.exports={CONTACTS_APP_ERRORS,CONTACT_SEED_MISMATCH_ERROR_CODE,ContactsCommandError,ContactsCommandErrorHelper,ContactsVersionRequirementError,contactsCommandErrorFactory});
|
|
2
2
|
//# sourceMappingURL=contactsErrors.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/model/contactsErrors.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type CommandErrorArgs,\n type CommandErrors,\n DeviceExchangeError,\n type DmkError,\n} from \"@ledgerhq/device-management-kit\";\n\n/**\n * Status word returned by the app's Address Book *edit* operations when the\n * seed-bound HMAC / group-handle verification fails \u2014 i.e. the entry was\n * registered with a different seed than the one currently on the device.\n *\n * The device runs this check *before* showing any UI and returns 0x6982 *only*\n * for seed-binding failures (user rejection and TLV errors return 0x6a80,\n * address validation returns 0x6af0), so 0x6982 is an unambiguous \"wrong seed\"\n * signal that consumers (e.g. Ledger Wallet) can catch to guide the user.\n */\nexport const CONTACT_SEED_MISMATCH_ERROR_CODE = \"6982\" as const;\n\nexport type ContactsErrorCodes =\n | \"6982\"\n | \"6800\"\n | \"6983\"\n | \"6984\"\n | \"6985\"\n | \"6a80\"\n | \"6a84\"\n | \"6a88\"\n | \"6af0\"\n | \"6b00\"\n | \"6f00\";\n\nexport const CONTACTS_APP_ERRORS: CommandErrors<ContactsErrorCodes> = {\n [CONTACT_SEED_MISMATCH_ERROR_CODE]: {\n message:\n \"This address-book entry was registered with a different seed. Connect the Ledger device that registered it to modify this contact.\",\n },\n \"6800\": { message: \"Internal error (Please report)\" },\n \"6983\": { message: \"Wrong data length\" },\n \"6984\": {\n message:\n \"Unsupported address-book operation for this device or app configuration\",\n },\n \"6985\": { message: \"Condition not satisfied\" },\n \"6a80\": { message: \"Invalid contact data, or operation refused on device\" },\n \"6a84\": { message: \"Insufficient memory: the device address book is full\" },\n \"6a88\": { message: \"Contact data not found\" },\n \"6af0\": { message: \"Invalid value for this contact entry\" },\n \"6b00\": { message: \"The app rejected the contact data\" },\n \"6f00\": { message: \"Technical problem (Internal error, please report)\" },\n};\n\nexport class ContactsCommandError extends DeviceExchangeError<ContactsErrorCodes> {\n constructor(args: CommandErrorArgs<ContactsErrorCodes>) {\n super({ tag: \"ContactsCommandError\", ...args });\n }\n}\n\nexport const contactsCommandErrorFactory = (\n args: CommandErrorArgs<ContactsErrorCodes>,\n) => new ContactsCommandError(args);\n\n/**\n * Raised by a Contacts `DeviceAction` when the connected device model, app\n * version, or OS version does not meet the Contacts requirements \u2014 i.e. the\n * DSDK-1376 support check fails before any APDU is sent.\n */\nexport class ContactsVersionRequirementError implements DmkError {\n readonly _tag = \"ContactsVersionRequirementError\";\n readonly originalError?: unknown;\n constructor(\n readonly message = \"The connected device or app does not meet the Contacts version requirements.\",\n ) {}\n}\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,EAAA,qCAAAC,EAAA,yBAAAC,EAAA,oCAAAC,EAAA,gCAAAC,IAAA,eAAAC,
|
|
6
|
-
"names": ["contactsErrors_exports", "__export", "CONTACTS_APP_ERRORS", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "ContactsVersionRequirementError", "contactsCommandErrorFactory", "__toCommonJS", "import_device_management_kit", "args", "message"]
|
|
4
|
+
"sourcesContent": ["import {\n ApduParser,\n type ApduResponse,\n type CommandErrorArgs,\n type CommandErrorResult,\n type CommandErrors,\n type CommandResult,\n DeviceExchangeError,\n type DmkError,\n DmkResultFactory,\n InvalidStatusWordError,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\n\n/**\n * Status word returned by the app's Address Book *edit* operations when the\n * seed-bound HMAC / group-handle verification fails \u2014 i.e. the entry was\n * registered with a different seed than the one currently on the device.\n *\n * The device runs this check *before* showing any UI and returns 0x6982 *only*\n * for seed-binding failures (user rejection and TLV errors return 0x6a80,\n * address validation returns 0x6af0), so 0x6982 is an unambiguous \"wrong seed\"\n * signal that consumers (e.g. Ledger Wallet) can catch to guide the user.\n */\nexport const CONTACT_SEED_MISMATCH_ERROR_CODE = \"6982\" as const;\n\nexport type ContactsErrorCodes =\n | \"6982\"\n | \"6800\"\n | \"6983\"\n | \"6984\"\n | \"6985\"\n | \"686a\"\n | \"6a80\"\n | \"6a84\"\n | \"6a88\"\n | \"6af0\"\n | \"6b00\"\n | \"6f00\";\n\nexport const CONTACTS_APP_ERRORS: CommandErrors<ContactsErrorCodes> = {\n [CONTACT_SEED_MISMATCH_ERROR_CODE]: {\n message:\n \"This address-book entry was registered with a different seed. Connect the Ledger device that registered it to modify this contact.\",\n },\n \"6800\": { message: \"Internal error (Please report)\" },\n \"6983\": { message: \"Wrong data length\" },\n \"6984\": {\n message:\n \"Unsupported address-book operation for this device or app configuration\",\n },\n \"6985\": { message: \"Condition not satisfied\" },\n // Dashboard EDIT CONTACT NAME on an OS build that still mandates the\n // DERIVATION_PATH (tag 0x69) but received a payload without it. DSDK-1481\n // sends the path conditionally by OS version so this should not occur in\n // practice; mapped here so that, if it ever does, the host gets an actionable\n // message instead of a bare UnknownDeviceExchangeError.\n \"686a\": {\n message:\n \"This device's firmware is out of date for the address book. Update your Ledger device to the latest firmware, then try again.\",\n },\n \"6a80\": { message: \"Invalid contact data, or operation refused on device\" },\n \"6a84\": { message: \"Insufficient memory: the device address book is full\" },\n \"6a88\": { message: \"Contact data not found\" },\n \"6af0\": { message: \"Invalid value for this contact entry\" },\n \"6b00\": { message: \"The app rejected the contact data\" },\n \"6f00\": { message: \"Technical problem (Internal error, please report)\" },\n};\n\nexport class ContactsCommandError extends DeviceExchangeError<ContactsErrorCodes> {\n constructor(args: CommandErrorArgs<ContactsErrorCodes>) {\n super({ tag: \"ContactsCommandError\", ...args });\n }\n}\n\nexport const contactsCommandErrorFactory = (\n args: CommandErrorArgs<ContactsErrorCodes>,\n) => new ContactsCommandError(args);\n\n/**\n * A {@link CommandErrorHelper} preconfigured with the Contacts error map, that\n * additionally guarantees no address-book command ever surfaces a bare\n * `UnknownDeviceExchangeError`.\n *\n * The base helper maps known status words to a {@link ContactsCommandError} and\n * falls back to the global handler for the rest \u2014 which, for a status word in\n * neither the Contacts nor the global dictionary (e.g. 0x686A before it was\n * mapped), yields an `UnknownDeviceExchangeError` whose message is a generic\n * \"Unexpected device exchange error happened.\" with no status word and no\n * guidance. This subclass replaces that specific case with an\n * `InvalidStatusWordError` naming the actual status word and pointing at a\n * firmware/app update, so the host always has something actionable to show.\n */\nexport class ContactsCommandErrorHelper<Response> extends CommandErrorHelper<\n Response,\n ContactsErrorCodes\n> {\n constructor() {\n super(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n }\n\n override getError(\n apduResponse: ApduResponse,\n ): CommandResult<Response, ContactsErrorCodes> | undefined {\n const result = super.getError(apduResponse);\n if (\n result === undefined ||\n isSuccessCommandResult(result) ||\n result.error._tag !== \"UnknownDeviceExchangeError\"\n ) {\n return result;\n }\n const statusWord = new ApduParser(apduResponse).encodeToHexaString(\n apduResponse.statusCode,\n );\n return DmkResultFactory<\n Response,\n CommandErrorResult<ContactsErrorCodes>[\"error\"]\n >({\n error: new InvalidStatusWordError(\n `The device returned an unexpected status word (0x${statusWord}) for this address-book operation. Update your Ledger device and Ethereum app to the latest version, then try again.`,\n ),\n });\n }\n}\n\n/**\n * Raised by a Contacts `DeviceAction` when the connected device model, app\n * version, or OS version does not meet the Contacts requirements \u2014 i.e. the\n * DSDK-1376 support check fails before any APDU is sent.\n */\nexport class ContactsVersionRequirementError implements DmkError {\n readonly _tag = \"ContactsVersionRequirementError\";\n readonly originalError?: unknown;\n constructor(\n readonly message = \"The connected device or app does not meet the Contacts version requirements.\",\n ) {}\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,EAAA,qCAAAC,EAAA,yBAAAC,EAAA,+BAAAC,EAAA,oCAAAC,EAAA,gCAAAC,IAAA,eAAAC,EAAAR,GAAA,IAAAS,EAYO,2CACPC,EAAmC,kCAY5B,MAAMP,EAAmC,OAgBnCD,EAAyD,CACpE,CAACC,CAAgC,EAAG,CAClC,QACE,oIACJ,EACA,KAAQ,CAAE,QAAS,gCAAiC,EACpD,KAAQ,CAAE,QAAS,mBAAoB,EACvC,KAAQ,CACN,QACE,yEACJ,EACA,KAAQ,CAAE,QAAS,yBAA0B,EAM7C,OAAQ,CACN,QACE,+HACJ,EACA,OAAQ,CAAE,QAAS,sDAAuD,EAC1E,OAAQ,CAAE,QAAS,sDAAuD,EAC1E,OAAQ,CAAE,QAAS,wBAAyB,EAC5C,OAAQ,CAAE,QAAS,sCAAuC,EAC1D,OAAQ,CAAE,QAAS,mCAAoC,EACvD,OAAQ,CAAE,QAAS,mDAAoD,CACzE,EAEO,MAAMC,UAA6B,qBAAwC,CAChF,YAAYO,EAA4C,CACtD,MAAM,CAAE,IAAK,uBAAwB,GAAGA,CAAK,CAAC,CAChD,CACF,CAEO,MAAMJ,EACXI,GACG,IAAIP,EAAqBO,CAAI,EAgB3B,MAAMN,UAA6C,oBAGxD,CACA,aAAc,CACZ,MAAMH,EAAqBK,CAA2B,CACxD,CAES,SACPK,EACyD,CACzD,MAAMC,EAAS,MAAM,SAASD,CAAY,EAC1C,GACEC,IAAW,WACX,0BAAuBA,CAAM,GAC7BA,EAAO,MAAM,OAAS,6BAEtB,OAAOA,EAET,MAAMC,EAAa,IAAI,aAAWF,CAAY,EAAE,mBAC9CA,EAAa,UACf,EACA,SAAO,oBAGL,CACA,MAAO,IAAI,yBACT,oDAAoDE,CAAU,sHAChE,CACF,CAAC,CACH,CACF,CAOO,MAAMR,CAAoD,CAG/D,YACWS,EAAU,+EACnB,CADS,aAAAA,CACR,CAJM,KAAO,kCACP,aAIX",
|
|
6
|
+
"names": ["contactsErrors_exports", "__export", "CONTACTS_APP_ERRORS", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "ContactsCommandErrorHelper", "ContactsVersionRequirementError", "contactsCommandErrorFactory", "__toCommonJS", "import_device_management_kit", "import_signer_utils", "args", "apduResponse", "result", "statusWord", "message"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var o=require("@ledgerhq/device-management-kit"),r=require("../../app-binder/command/ProvideContactCommand"),i=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),d=require("../../app-binder/model/contactsErrors"),t=require("./provideContact");const m=new Uint8Array(20).fill(17),p=new Uint8Array(64).fill(34),f=new Uint8Array(32).fill(51),h=new Uint8Array(32).fill(68),n={contactName:"Alice",scope:"Ethereum",identifier:m,groupHandle:p,hmacProof:f,hmacRest:h,blockchainFamily:"ethereum",chainId:1n},C="010133",u="020101",y="81f005416c696365",T="81f108457468657265756d",x="81f214"+"11".repeat(20),s="81f640"+"22".repeat(64),E="230101",P="510101",_="2920"+"33".repeat(32),I="81f720"+"44".repeat(32);describe("buildProvideContactPayload",()=>{it("encodes every tag in the order the spec lists",()=>{const e=(0,t.buildProvideContactPayload)(n);expect((0,o.bufferToHexaString)(e,!1)).toBe(C+u+y+T+x+s+E+P+_+I)}),it("fits an Ethereum contact in a single 255-byte chunk",()=>{expect((0,t.buildProvideContactPayload)(n).length).toBeLessThanOrEqual(253)}),it("omits CHAIN_ID for a family that does not carry one",()=>{const e=(0,t.buildProvideContactPayload)({...n,blockchainFamily:"
|
|
1
|
+
"use strict";var o=require("@ledgerhq/device-management-kit"),r=require("../../app-binder/command/ProvideContactCommand"),i=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),d=require("../../app-binder/model/contactsErrors"),t=require("./provideContact");const m=new Uint8Array(20).fill(17),p=new Uint8Array(64).fill(34),f=new Uint8Array(32).fill(51),h=new Uint8Array(32).fill(68),n={contactName:"Alice",scope:"Ethereum",identifier:m,groupHandle:p,hmacProof:f,hmacRest:h,blockchainFamily:"ethereum",chainId:1n},C="010133",u="020101",y="81f005416c696365",T="81f108457468657265756d",x="81f214"+"11".repeat(20),s="81f640"+"22".repeat(64),E="230101",P="510101",_="2920"+"33".repeat(32),I="81f720"+"44".repeat(32);describe("buildProvideContactPayload",()=>{it("encodes every tag in the order the spec lists",()=>{const e=(0,t.buildProvideContactPayload)(n);expect((0,o.bufferToHexaString)(e,!1)).toBe(C+u+y+T+x+s+E+P+_+I)}),it("fits an Ethereum contact in a single 255-byte chunk",()=>{expect((0,t.buildProvideContactPayload)(n).length).toBeLessThanOrEqual(253)}),it("omits CHAIN_ID for a family that does not carry one",()=>{const e=(0,t.buildProvideContactPayload)({...n,blockchainFamily:"tron",chainId:void 0});expect((0,o.bufferToHexaString)(e,!1)).toContain(s+"510106")}),it("encodes a multi-byte chain id big-endian with no leading zeroes",()=>{const e=(0,t.buildProvideContactPayload)({...n,chainId:8453n});expect((0,o.bufferToHexaString)(e,!1)).toContain("23022105")}),it("accepts the family name case-insensitively",()=>{expect((0,t.buildProvideContactPayload)({...n,blockchainFamily:"Ethereum"})).toStrictEqual((0,t.buildProvideContactPayload)(n))}),it("throws on an unknown blockchain family",()=>{expect(()=>(0,t.buildProvideContactPayload)({...n,blockchainFamily:"dogecoin"})).toThrow("Unsupported blockchain family: dogecoin")})});describe("sendProvideContactPayload",()=>{it("sends one chunk under P2=0x00, prefixed with the 2-byte BE total length",async()=>{const e=(0,i.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,o.CommandResultFactory)({data:void 0}));const a=(0,t.buildProvideContactPayload)(n),l=await(0,t.sendProvideContactPayload)(e,{payload:a});expect(e.sendCommand).toHaveBeenCalledTimes(1);const c=e.sendCommand.mock.calls[0][0];expect(c).toBeInstanceOf(r.ProvideContactCommand),expect(c.args.p2).toBe(0),expect(c.args.data.slice(0,2)).toStrictEqual(Uint8Array.from([a.length>>8&255,a.length&255])),expect(c.args.data.slice(2)).toStrictEqual(a),expect(l.status).toBe(o.CommandResultStatus.Success)}),it("propagates a device rejection instead of throwing",async()=>{const e=(0,i.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,o.CommandResultFactory)({error:new d.ContactsCommandError({errorCode:"6982",message:"wrong seed"})}));const a=await(0,t.sendProvideContactPayload)(e,{payload:(0,t.buildProvideContactPayload)(n)});expect(a.status).toBe(o.CommandResultStatus.Error)})});
|
|
2
2
|
//# sourceMappingURL=provideContact.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/services/provideContact.test.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n bufferToHexaString,\n CommandResultFactory,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { ContactsCommandError } from \"@internal/app-binder/model/contactsErrors\";\n\nimport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n} from \"./provideContact\";\n\nconst IDENTIFIER = new Uint8Array(20).fill(0x11);\nconst GROUP_HANDLE = new Uint8Array(64).fill(0x22);\nconst HMAC_PROOF = new Uint8Array(32).fill(0x33);\nconst HMAC_REST = new Uint8Array(32).fill(0x44);\n\nconst INPUT: ProvideContactInput = {\n contactName: \"Alice\",\n scope: \"Ethereum\",\n identifier: IDENTIFIER,\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF,\n hmacRest: HMAC_REST,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\n// Tags >= 0x80 use the DER long form (0x81 then the tag), hence the \"81\" prefix\n// on CONTACT_NAME (0xf0), SCOPE (0xf1), ACCOUNT_IDENTIFIER (0xf2),\n// GROUP_HANDLE (0xf6) and HMAC_REST (0xf7).\nconst STRUCT_TYPE_TLV = \"010133\";\nconst STRUCT_VERSION_TLV = \"020101\";\nconst CONTACT_NAME_TLV = \"81f005\" + \"416c696365\"; // \"Alice\"\nconst SCOPE_TLV = \"81f108\" + \"457468657265756d\"; // \"Ethereum\"\nconst IDENTIFIER_TLV = \"81f214\" + \"11\".repeat(20);\nconst GROUP_HANDLE_TLV = \"81f640\" + \"22\".repeat(64);\nconst CHAIN_ID_TLV = \"230101\";\nconst FAMILY_TLV = \"510101\";\nconst HMAC_PROOF_TLV = \"2920\" + \"33\".repeat(32);\nconst HMAC_REST_TLV = \"81f720\" + \"44\".repeat(32);\n\ndescribe(\"buildProvideContactPayload\", () => {\n it(\"encodes every tag in the order the spec lists\", () => {\n const payload = buildProvideContactPayload(INPUT);\n\n expect(bufferToHexaString(payload, false)).toBe(\n STRUCT_TYPE_TLV +\n STRUCT_VERSION_TLV +\n CONTACT_NAME_TLV +\n SCOPE_TLV +\n IDENTIFIER_TLV +\n GROUP_HANDLE_TLV +\n CHAIN_ID_TLV +\n FAMILY_TLV +\n HMAC_PROOF_TLV +\n HMAC_REST_TLV,\n );\n });\n\n it(\"fits an Ethereum contact in a single 255-byte chunk\", () => {\n expect(buildProvideContactPayload(INPUT).length).toBeLessThanOrEqual(253);\n });\n\n it(\"omits CHAIN_ID for a family that does not carry one\", () => {\n const payload = buildProvideContactPayload({\n ...INPUT,\n blockchainFamily: \"
|
|
5
|
-
"mappings": "aAAA,IAAAA,EAIO,2CAGPC,EAAsC,8DACtCC,EAAgD,6EAChDC,EAAqC,qDAErCC,EAGO,4BAEP,MAAMC,EAAa,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACzCC,EAAe,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EAC3CC,EAAa,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACzCC,EAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EAExCC,EAA6B,CACjC,YAAa,QACb,MAAO,WACP,WAAYJ,EACZ,YAAaC,EACb,UAAWC,EACX,SAAUC,EACV,iBAAkB,WAClB,QAAS,EACX,EAKME,EAAkB,SAClBC,EAAqB,SACrBC,EAAmB,mBACnBC,EAAY,yBACZC,EAAiB,SAAW,KAAK,OAAO,EAAE,EAC1CC,EAAmB,SAAW,KAAK,OAAO,EAAE,EAC5CC,EAAe,SACfC,EAAa,SACbC,EAAiB,OAAS,KAAK,OAAO,EAAE,EACxCC,EAAgB,SAAW,KAAK,OAAO,EAAE,EAE/C,SAAS,6BAA8B,IAAM,CAC3C,GAAG,gDAAiD,IAAM,CACxD,MAAMC,KAAU,8BAA2BX,CAAK,EAEhD,UAAO,sBAAmBW,EAAS,EAAK,CAAC,EAAE,KACzCV,EACEC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CACJ,CACF,CAAC,EAED,GAAG,sDAAuD,IAAM,CAC9D,UAAO,8BAA2BV,CAAK,EAAE,MAAM,EAAE,oBAAoB,GAAG,CAC1E,CAAC,EAED,GAAG,sDAAuD,IAAM,CAC9D,MAAMW,KAAU,8BAA2B,CACzC,GAAGX,EACH,iBAAkB,
|
|
4
|
+
"sourcesContent": ["import {\n bufferToHexaString,\n CommandResultFactory,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { ContactsCommandError } from \"@internal/app-binder/model/contactsErrors\";\n\nimport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n} from \"./provideContact\";\n\nconst IDENTIFIER = new Uint8Array(20).fill(0x11);\nconst GROUP_HANDLE = new Uint8Array(64).fill(0x22);\nconst HMAC_PROOF = new Uint8Array(32).fill(0x33);\nconst HMAC_REST = new Uint8Array(32).fill(0x44);\n\nconst INPUT: ProvideContactInput = {\n contactName: \"Alice\",\n scope: \"Ethereum\",\n identifier: IDENTIFIER,\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF,\n hmacRest: HMAC_REST,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\n// Tags >= 0x80 use the DER long form (0x81 then the tag), hence the \"81\" prefix\n// on CONTACT_NAME (0xf0), SCOPE (0xf1), ACCOUNT_IDENTIFIER (0xf2),\n// GROUP_HANDLE (0xf6) and HMAC_REST (0xf7).\nconst STRUCT_TYPE_TLV = \"010133\";\nconst STRUCT_VERSION_TLV = \"020101\";\nconst CONTACT_NAME_TLV = \"81f005\" + \"416c696365\"; // \"Alice\"\nconst SCOPE_TLV = \"81f108\" + \"457468657265756d\"; // \"Ethereum\"\nconst IDENTIFIER_TLV = \"81f214\" + \"11\".repeat(20);\nconst GROUP_HANDLE_TLV = \"81f640\" + \"22\".repeat(64);\nconst CHAIN_ID_TLV = \"230101\";\nconst FAMILY_TLV = \"510101\";\nconst HMAC_PROOF_TLV = \"2920\" + \"33\".repeat(32);\nconst HMAC_REST_TLV = \"81f720\" + \"44\".repeat(32);\n\ndescribe(\"buildProvideContactPayload\", () => {\n it(\"encodes every tag in the order the spec lists\", () => {\n const payload = buildProvideContactPayload(INPUT);\n\n expect(bufferToHexaString(payload, false)).toBe(\n STRUCT_TYPE_TLV +\n STRUCT_VERSION_TLV +\n CONTACT_NAME_TLV +\n SCOPE_TLV +\n IDENTIFIER_TLV +\n GROUP_HANDLE_TLV +\n CHAIN_ID_TLV +\n FAMILY_TLV +\n HMAC_PROOF_TLV +\n HMAC_REST_TLV,\n );\n });\n\n it(\"fits an Ethereum contact in a single 255-byte chunk\", () => {\n expect(buildProvideContactPayload(INPUT).length).toBeLessThanOrEqual(253);\n });\n\n it(\"omits CHAIN_ID for a family that does not carry one\", () => {\n const payload = buildProvideContactPayload({\n ...INPUT,\n blockchainFamily: \"tron\",\n chainId: undefined,\n });\n\n expect(bufferToHexaString(payload, false)).toContain(\n GROUP_HANDLE_TLV + \"510106\",\n );\n });\n\n it(\"encodes a multi-byte chain id big-endian with no leading zeroes\", () => {\n const payload = buildProvideContactPayload({ ...INPUT, chainId: 8453n });\n\n expect(bufferToHexaString(payload, false)).toContain(\"2302\" + \"2105\");\n });\n\n it(\"accepts the family name case-insensitively\", () => {\n expect(\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"Ethereum\" }),\n ).toStrictEqual(buildProvideContactPayload(INPUT));\n });\n\n it(\"throws on an unknown blockchain family\", () => {\n expect(() =>\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"dogecoin\" }),\n ).toThrow(\"Unsupported blockchain family: dogecoin\");\n });\n});\n\ndescribe(\"sendProvideContactPayload\", () => {\n it(\"sends one chunk under P2=0x00, prefixed with the 2-byte BE total length\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({ data: undefined }),\n );\n const payload = buildProvideContactPayload(INPUT);\n\n const result = await sendProvideContactPayload(api, { payload });\n\n expect(api.sendCommand).toHaveBeenCalledTimes(1);\n const command = api.sendCommand.mock.calls[0]![0] as ProvideContactCommand;\n expect(command).toBeInstanceOf(ProvideContactCommand);\n expect(command.args.p2).toBe(0x00);\n expect(command.args.data.slice(0, 2)).toStrictEqual(\n Uint8Array.from([(payload.length >> 8) & 0xff, payload.length & 0xff]),\n );\n expect(command.args.data.slice(2)).toStrictEqual(payload);\n expect(result.status).toBe(CommandResultStatus.Success);\n });\n\n it(\"propagates a device rejection instead of throwing\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({\n error: new ContactsCommandError({\n errorCode: \"6982\",\n message: \"wrong seed\",\n }),\n }),\n );\n\n const result = await sendProvideContactPayload(api, {\n payload: buildProvideContactPayload(INPUT),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_device_management_kit", "import_ProvideContactCommand", "import_makeInternalApi", "import_contactsErrors", "import_provideContact", "IDENTIFIER", "GROUP_HANDLE", "HMAC_PROOF", "HMAC_REST", "INPUT", "STRUCT_TYPE_TLV", "STRUCT_VERSION_TLV", "CONTACT_NAME_TLV", "SCOPE_TLV", "IDENTIFIER_TLV", "GROUP_HANDLE_TLV", "CHAIN_ID_TLV", "FAMILY_TLV", "HMAC_PROOF_TLV", "HMAC_REST_TLV", "payload", "api", "result", "command"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var y=(t,a)=>{for(var r in a)d(t,r,{get:a[r],enumerable:!0})},u=(t,a,r,i)=>{if(a&&typeof a=="object"||typeof a=="function")for(let n of T(a))!p.call(t,n)&&n!==r&&d(t,n,{get:()=>a[n],enumerable:!(i=C(a,n))||i.enumerable});return t};var A=t=>u(d({},"__esModule",{value:!0}),t);var P={};y(P,{SendRenameContactTask:()=>R});module.exports=A(P);var o=require("@ledgerhq/device-management-kit"),m=require("../../app-binder/command/RenameContactCommand"),c=require("../../app-binder/model/contactsConstants"),e=require("../../app-binder/services/contactsTlvSerializer"),s=require("../../app-binder/services/sendFramedContactsPayload");class R{constructor(a,r){this.api=a;this.args=r}async run(){const a=this.buildPayload(this.args),r=await(0,s.sendFramedContactsPayload)(this.api,{payload:a,p1:c.RENAME_CONTACT_P1,makeCommand:(n,l)=>new m.RenameContactCommand({data:n,p2:l}),logger:this.args.logger,commandTag:"SendRenameContactTask"});if(!(0,o.isSuccessCommandResult)(r))return r;const{hmacProof:i}=r.data;return i?(0,o.DmkResultFactory)({data:{hmacProof:i}}):(0,o.DmkResultFactory)({error:new o.InvalidStatusWordError("RenameContact final-chunk response did not carry hmac_name")})}buildPayload(a){const r=new o.ByteArrayBuilder;return(0,e.encodeTlvUInt8)(r,e.CONTACTS_TLV_TAG.STRUCT_TYPE,e.STRUCT_TYPE_EDIT_CONTACT_NAME),(0,e.encodeTlvUInt8)(r,e.CONTACTS_TLV_TAG.STRUCT_VERSION,e.STRUCT_VERSION_VALUE),(0,e.encodeTlvAscii)(r,e.CONTACTS_TLV_TAG.CONTACT_NAME,a.newContactName),(0,e.encodeTlvAscii)(r,e.CONTACTS_TLV_TAG.PREVIOUS_CONTACT_NAME,a.previousContactName),(0,e.encodeTlvBuffer)(r,e.CONTACTS_TLV_TAG.GROUP_HANDLE,a.groupHandle),a.includeDerivationPath&&(0,e.encodeTlvBuffer)(r,e.CONTACTS_TLV_TAG.DERIVATION_PATH,(0,e.packDerivationPath)([2147483692,2147483708,2147483648,0,0])),(0,e.encodeTlvBuffer)(r,e.CONTACTS_TLV_TAG.HMAC_PROOF,a.hmacProof),r.build()}}0&&(module.exports={SendRenameContactTask});
|
|
2
2
|
//# sourceMappingURL=SendRenameContactTask.js.map
|