@ledgerhq/device-contacts-kit 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -13
- 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 +3 -3
- 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/ProvideContact.js +2 -0
- package/lib/cjs/api/model/ProvideContact.js.map +7 -0
- 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 +2 -0
- package/lib/cjs/internal/app-binder/command/ProvideContactCommand.js.map +7 -0
- package/lib/cjs/internal/app-binder/command/ProvideContactCommand.test.js +2 -0
- package/lib/cjs/internal/app-binder/command/ProvideContactCommand.test.js.map +7 -0
- 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 +3 -3
- 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.js +2 -0
- package/lib/cjs/internal/app-binder/services/provideContact.js.map +7 -0
- package/lib/cjs/internal/app-binder/services/provideContact.test.js +2 -0
- package/lib/cjs/internal/app-binder/services/provideContact.test.js.map +7 -0
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.js.map +2 -2
- package/lib/cjs/internal/app-binder/task/SendRegisterIdentityTask.test.js.map +1 -1
- 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 +2 -2
- 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/api/model/ProvideContact.js +1 -0
- package/lib/esm/api/model/ProvideContact.js.map +7 -0
- 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 +2 -0
- package/lib/esm/internal/app-binder/command/ProvideContactCommand.js.map +7 -0
- package/lib/esm/internal/app-binder/command/ProvideContactCommand.test.js +2 -0
- package/lib/esm/internal/app-binder/command/ProvideContactCommand.test.js.map +7 -0
- 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 +3 -3
- 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.js +2 -0
- package/lib/esm/internal/app-binder/services/provideContact.js.map +7 -0
- package/lib/esm/internal/app-binder/services/provideContact.test.js +2 -0
- package/lib/esm/internal/app-binder/services/provideContact.test.js.map +7 -0
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.js.map +2 -2
- package/lib/esm/internal/app-binder/task/SendRegisterIdentityTask.test.js.map +1 -1
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.js +1 -1
- package/lib/esm/internal/app-binder/task/SendRenameContactTask.js.map +2 -2
- 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 +2 -2
- 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 +4 -1
- package/lib/types/api/index.d.ts.map +1 -1
- package/lib/types/api/model/ContactsVersionRequirements.d.ts +38 -23
- package/lib/types/api/model/ContactsVersionRequirements.d.ts.map +1 -1
- package/lib/types/api/model/ProvideContact.d.ts +20 -0
- package/lib/types/api/model/ProvideContact.d.ts.map +1 -0
- 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 +18 -0
- package/lib/types/internal/app-binder/command/ProvideContactCommand.d.ts.map +1 -0
- package/lib/types/internal/app-binder/command/ProvideContactCommand.test.d.ts +2 -0
- package/lib/types/internal/app-binder/command/ProvideContactCommand.test.d.ts.map +1 -0
- 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 -0
- 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/services/provideContact.d.ts +15 -0
- package/lib/types/internal/app-binder/services/provideContact.d.ts.map +1 -0
- package/lib/types/internal/app-binder/services/provideContact.test.d.ts +2 -0
- package/lib/types/internal/app-binder/services/provideContact.test.d.ts.map +1 -0
- package/lib/types/internal/app-binder/task/SendRegisterIdentityTask.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,2 +1,2 @@
|
|
|
1
|
-
import{ApduBuilder as i,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as
|
|
1
|
+
import{ApduBuilder as i,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as o}from"@ledgerhq/device-management-kit";import{Maybe as p}from"purify-ts";import{CONTACTS_APDU_CLA as E,CONTACTS_APDU_INS as l,HMAC_REST_BYTES as u,SUB_CMD_EDIT_IDENTIFIER as A}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as C}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_IDENTIFIER as f}from"../../app-binder/services/contactsTlvSerializer";const s=f;function c(n,r){const e=n.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class g{name="editExternalAddressIdentifier";args;errorHelper=new C;constructor(r){this.args=r}getApdu(){return new i({cla:E,ins:l,p1:A,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return p.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new m(r),d=e.extract8BitUInt();if(d!==s)return t({error:new o(`Expected struct_type 0x${s.toString(16)}, got ${d===void 0?"undefined":`0x${d.toString(16)}`}`)});const a=c(e,u);return a?t({data:{hmacRest:a}}):t({error:new o("hmac_rest missing or truncated")})})}}export{g as EditExternalAddressIdentifierCommand};
|
|
2
2
|
//# sourceMappingURL=EditExternalAddressIdentifierCommand.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/command/EditExternalAddressIdentifierCommand.ts"],
|
|
4
|
-
"sourcesContent": ["// Edit Identifier \u2014 sub-command P1=0x03 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x31) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Identifier.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport {
|
|
5
|
-
"mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,
|
|
6
|
-
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "
|
|
4
|
+
"sourcesContent": ["// Edit Identifier \u2014 sub-command P1=0x03 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x31) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Identifier.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_IDENTIFIER,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_IDENTIFIER } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressIdentifierCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressIdentifierCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x31) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_IDENTIFIER;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressIdentifierCommand\n implements\n Command<\n EditExternalAddressIdentifierCommandResponse,\n EditExternalAddressIdentifierCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressIdentifier\";\n readonly args: EditExternalAddressIdentifierCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<EditExternalAddressIdentifierCommandResponse>();\n\n constructor(args: EditExternalAddressIdentifierCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_IDENTIFIER,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressIdentifierCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,+BAAAC,MAAmC,sDAkB5C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gCACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAAgD,CAC1D,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EAIA,CACA,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQN,CAAe,EACrD,OAAKa,EAMElB,EAAqB,CAC1B,KAAM,CAAE,SAAAkB,CAAS,CACnB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_IDENTIFIER", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_IDENTIFIER", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressIdentifierCommand", "args", "response", "structType", "hmacRest"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ApduBuilder as
|
|
1
|
+
import{ApduBuilder as p,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as a}from"@ledgerhq/device-management-kit";import{Maybe as i}from"purify-ts";import{CONTACTS_APDU_CLA as l,CONTACTS_APDU_INS as u,HMAC_REST_BYTES as E,SUB_CMD_EDIT_SCOPE as c}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as C}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_SCOPE as A}from"../../app-binder/services/contactsTlvSerializer";const s=A;function S(n,r){const e=n.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class T{name="editExternalAddressScope";args;errorHelper=new C;constructor(r){this.args=r}getApdu(){return new p({cla:l,ins:u,p1:c,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return i.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new m(r),d=e.extract8BitUInt();if(d!==s)return t({error:new a(`Expected struct_type 0x${s.toString(16)}, got ${d===void 0?"undefined":`0x${d.toString(16)}`}`)});const o=S(e,E);return o?t({data:{hmacRest:o}}):t({error:new a("hmac_rest missing or truncated")})})}}export{T as EditExternalAddressScopeCommand};
|
|
2
2
|
//# sourceMappingURL=EditExternalAddressScopeCommand.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/command/EditExternalAddressScopeCommand.ts"],
|
|
4
|
-
"sourcesContent": ["// Edit Scope \u2014 sub-command P1=0x04 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x32) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Scope.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport {
|
|
5
|
-
"mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,
|
|
6
|
-
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "
|
|
4
|
+
"sourcesContent": ["// Edit Scope \u2014 sub-command P1=0x04 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x32) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Scope.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_SCOPE,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_SCOPE } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressScopeCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressScopeCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x32) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_SCOPE;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressScopeCommand\n implements\n Command<\n EditExternalAddressScopeCommandResponse,\n EditExternalAddressScopeCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressScope\";\n readonly args: EditExternalAddressScopeCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<EditExternalAddressScopeCommandResponse>();\n\n constructor(args: EditExternalAddressScopeCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_SCOPE,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressScopeCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,sBAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,0BAAAC,MAA8B,sDAkBvC,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,2BACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAA2C,CACrD,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EAIA,CACA,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQN,CAAe,EACrD,OAAKa,EAMElB,EAAqB,CAC1B,KAAM,CAAE,SAAAkB,CAAS,CACnB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_SCOPE", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_SCOPE", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressScopeCommand", "args", "response", "structType", "hmacRest"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ApduBuilder as r,CommandResultFactory as e}from"@ledgerhq/device-management-kit";import{Maybe as t}from"purify-ts";import{CONTACTS_APDU_CLA as a,CONTACTS_APDU_INS as n,SUB_CMD_PROVIDE_CONTACT as d}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as s}from"../../app-binder/model/contactsErrors";class l{name="provideContact";args;errorHelper=new s;constructor(o){this.args=o}getApdu(){return new r({cla:a,ins:n,p1:d,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(o){return t.fromNullable(this.errorHelper.getError(o)).orDefaultLazy(()=>e({data:void 0}))}}export{l as ProvideContactCommand};
|
|
2
|
+
//# sourceMappingURL=ProvideContactCommand.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/ProvideContactCommand.ts"],
|
|
4
|
+
"sourcesContent": ["// Provide Contact \u2014 sub-command P1=0x20 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Sent before a signing APDU so the device renders a registered\n// contact name in place of the raw recipient address. Caller\n// (sendProvideContactPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk. Every\n// chunk answers with SW=0x9000 and no data \u2014 the outcome is a device-side\n// effect, not a returned value.\n// Protocol: Address Book Final Specifications \u2014 Provide Contact.\nimport {\n type Apdu,\n ApduBuilder,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n SUB_CMD_PROVIDE_CONTACT,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type ProvideContactCommandArgs = {\n /** One framed chunk built by sendProvideContactPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type ProvideContactCommandResponse = void;\n\nexport class ProvideContactCommand\n implements\n Command<\n ProvideContactCommandResponse,\n ProvideContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"provideContact\";\n readonly args: ProvideContactCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<ProvideContactCommandResponse>();\n\n constructor(args: ProvideContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_PROVIDE_CONTACT,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<ProvideContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() =>\n CommandResultFactory<ProvideContactCommandResponse, ContactsErrorCodes>({\n data: undefined,\n }),\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,OAEE,eAAAA,EAIA,wBAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CAWA,MAAMC,CAOb,CACW,KAAO,iBACP,KACQ,YACf,IAAID,EAEN,YAAYE,EAAiC,CAC3C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIR,EAAY,CACrB,IAAKG,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEI,EACkE,CAClE,OAAOP,EAAM,aACX,KAAK,YAAY,SAASO,CAAQ,CACpC,EAAE,cAAc,IACdR,EAAwE,CACtE,KAAM,MACR,CAAC,CACH,CACF,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "CommandResultFactory", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "SUB_CMD_PROVIDE_CONTACT", "ContactsCommandErrorHelper", "ProvideContactCommand", "args", "response"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{CommandResultStatus as r}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as o,ContactsCommandError as s}from"../../app-binder/model/contactsErrors";import{ProvideContactCommand as e}from"./ProvideContactCommand";describe("ProvideContactCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under B0 10 20 with P2=0x00 for the first/only chunk",()=>{const t=Uint8Array.from([0,3,170,187,204]),a=new e({data:t,p2:0}).getApdu();expect(a.getRawApdu()).toStrictEqual(Uint8Array.from([176,16,32,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const t=Uint8Array.from([170,187]),a=new e({data:t,p2:128}).getApdu();expect(a.getRawApdu()).toStrictEqual(Uint8Array.from([176,16,32,128,2,170,187]))})}),describe("parseResponse",()=>{it("succeeds with no data on SW=0x9000",()=>{const t=new e({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(t).toStrictEqual({status:r.Success,data:void 0})}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new e({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(s),expect(t.error.errorCode).toBe(o))}),it("maps SW=0x6a80 to a ContactsCommandError",()=>{const t=new e({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([106,128])});expect(t.status).toBe(r.Error),t.status===r.Error&&expect(t.error.errorCode).toBe("6a80")})})});
|
|
2
|
+
//# sourceMappingURL=ProvideContactCommand.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/internal/app-binder/command/ProvideContactCommand.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { CommandResultStatus } from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n ContactsCommandError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { ProvideContactCommand } from \"./ProvideContactCommand\";\n\ndescribe(\"ProvideContactCommand\", () => {\n describe(\"getApdu\", () => {\n it(\"wraps the framed chunk under B0 10 20 with P2=0x00 for the first/only chunk\", () => {\n const data = Uint8Array.from([0x00, 0x03, 0xaa, 0xbb, 0xcc]);\n\n const apdu = new ProvideContactCommand({ data, p2: 0x00 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([\n 0xb0, 0x10, 0x20, 0x00, 0x05, 0x00, 0x03, 0xaa, 0xbb, 0xcc,\n ]),\n );\n });\n\n it(\"uses P2=0x80 for continuation chunks\", () => {\n const data = Uint8Array.from([0xaa, 0xbb]);\n\n const apdu = new ProvideContactCommand({ data, p2: 0x80 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([0xb0, 0x10, 0x20, 0x80, 0x02, 0xaa, 0xbb]),\n );\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"succeeds with no data on SW=0x9000\", () => {\n const result = new ProvideContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x90, 0x00]),\n });\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: undefined,\n });\n });\n\n it(\"maps SW=0x6982 to a seed-mismatch ContactsCommandError\", () => {\n const result = new ProvideContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x82]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n );\n }\n });\n\n it(\"maps SW=0x6a80 to a ContactsCommandError\", () => {\n const result = new ProvideContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x6a, 0x80]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect((result.error as ContactsCommandError).errorCode).toBe(\"6a80\");\n }\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,uBAAAA,MAA2B,kCAEpC,OACE,oCAAAC,EACA,wBAAAC,MACK,4CAEP,OAAS,yBAAAC,MAA6B,0BAEtC,SAAS,wBAAyB,IAAM,CACtC,SAAS,UAAW,IAAM,CACxB,GAAG,8EAA+E,IAAM,CACtF,MAAMC,EAAO,WAAW,KAAK,CAAC,EAAM,EAAM,IAAM,IAAM,GAAI,CAAC,EAErDC,EAAO,IAAIF,EAAsB,CAAE,KAAAC,EAAM,GAAI,CAAK,CAAC,EAAE,QAAQ,EAEnE,OAAOC,EAAK,WAAW,CAAC,EAAE,cACxB,WAAW,KAAK,CACd,IAAM,GAAM,GAAM,EAAM,EAAM,EAAM,EAAM,IAAM,IAAM,GACxD,CAAC,CACH,CACF,CAAC,EAED,GAAG,uCAAwC,IAAM,CAC/C,MAAMD,EAAO,WAAW,KAAK,CAAC,IAAM,GAAI,CAAC,EAEnCC,EAAO,IAAIF,EAAsB,CAAE,KAAAC,EAAM,GAAI,GAAK,CAAC,EAAE,QAAQ,EAEnE,OAAOC,EAAK,WAAW,CAAC,EAAE,cACxB,WAAW,KAAK,CAAC,IAAM,GAAM,GAAM,IAAM,EAAM,IAAM,GAAI,CAAC,CAC5D,CACF,CAAC,CACH,CAAC,EAED,SAAS,gBAAiB,IAAM,CAC9B,GAAG,qCAAsC,IAAM,CAC7C,MAAMC,EAAS,IAAIH,EAAsB,CACvC,KAAM,IAAI,WACV,GAAI,CACN,CAAC,EAAE,cAAc,CACf,KAAM,OAAO,KAAK,CAAC,CAAC,EACpB,WAAY,OAAO,KAAK,CAAC,IAAM,CAAI,CAAC,CACtC,CAAC,EAED,OAAOG,CAAM,EAAE,cAAc,CAC3B,OAAQN,EAAoB,QAC5B,KAAM,MACR,CAAC,CACH,CAAC,EAED,GAAG,yDAA0D,IAAM,CACjE,MAAMM,EAAS,IAAIH,EAAsB,CACvC,KAAM,IAAI,WACV,GAAI,CACN,CAAC,EAAE,cAAc,CACf,KAAM,OAAO,KAAK,CAAC,CAAC,EACpB,WAAY,OAAO,KAAK,CAAC,IAAM,GAAI,CAAC,CACtC,CAAC,EAED,OAAOG,EAAO,MAAM,EAAE,KAAKN,EAAoB,KAAK,EAChDM,EAAO,SAAWN,EAAoB,QACxC,OAAOM,EAAO,KAAK,EAAE,eAAeJ,CAAoB,EACxD,OAAQI,EAAO,MAA+B,SAAS,EAAE,KACvDL,CACF,EAEJ,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,MAAMK,EAAS,IAAIH,EAAsB,CACvC,KAAM,IAAI,WACV,GAAI,CACN,CAAC,EAAE,cAAc,CACf,KAAM,OAAO,KAAK,CAAC,CAAC,EACpB,WAAY,OAAO,KAAK,CAAC,IAAM,GAAI,CAAC,CACtC,CAAC,EAED,OAAOG,EAAO,MAAM,EAAE,KAAKN,EAAoB,KAAK,EAChDM,EAAO,SAAWN,EAAoB,OACxC,OAAQM,EAAO,MAA+B,SAAS,EAAE,KAAK,MAAM,CAExE,CAAC,CACH,CAAC,CACH,CAAC",
|
|
6
|
+
"names": ["CommandResultStatus", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "ProvideContactCommand", "data", "apdu", "result"]
|
|
7
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ApduBuilder as u,ApduParser as y,CommandResultFactory as t,InvalidStatusWordError as n}from"@ledgerhq/device-management-kit";import{
|
|
1
|
+
import{ApduBuilder as u,ApduParser as y,CommandResultFactory as t,InvalidStatusWordError as n}from"@ledgerhq/device-management-kit";import{Maybe as c}from"purify-ts";import{CONTACTS_APDU_CLA as g,CONTACTS_APDU_INS as l,GROUP_HANDLE_BYTES as C,HMAC_PROOF_BYTES as R,HMAC_REST_BYTES as A,SUB_CMD_REGISTER_IDENTITY as f}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as _}from"../../app-binder/model/contactsErrors";const p=45;function a(d,r){const e=d.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class h{name="registerIdentity";args;errorHelper=new _;constructor(r){this.args=r}getApdu(){return new u({cla:g,ins:l,p1:f,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return c.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new y(r),o=e.extract8BitUInt();if(o!==p)return t({error:new n(`Expected struct_type 0x${p.toString(16)}, got ${o===void 0?"undefined":`0x${o.toString(16)}`}`)});const s=a(e,C);if(!s)return t({error:new n("group_handle missing or truncated")});const i=a(e,R);if(!i)return t({error:new n("hmac_name missing or truncated")});const m=a(e,A);return m?t({data:{groupHandle:s,hmacProof:i,hmacRest:m}}):t({error:new n("hmac_rest missing or truncated")})})}}export{h as RegisterIdentityCommand};
|
|
2
2
|
//# sourceMappingURL=RegisterIdentityCommand.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/command/RegisterIdentityCommand.ts"],
|
|
4
|
-
"sourcesContent": ["// Register Identity (register external address) \u2014 sub-command P1=0x01 of the\n// address-book APDU (CLA 0xB0 / INS 0x10). Caller (SendRegisterIdentityTask +\n// sendFramedContactsPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk and, on\n// the final chunk, parses the 129-byte response: struct_type(0x2d) +\n// group_handle(64) + hmac_proof(32) + hmac_rest(32). Intermediate chunks ack\n// with SW=0x9000 and no data.\n// Protocol: Address Book Final Specifications \u2014 Register Identity.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport {
|
|
5
|
-
"mappings": "AAQA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,
|
|
6
|
-
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "
|
|
4
|
+
"sourcesContent": ["// Register Identity (register external address) \u2014 sub-command P1=0x01 of the\n// address-book APDU (CLA 0xB0 / INS 0x10). Caller (SendRegisterIdentityTask +\n// sendFramedContactsPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk and, on\n// the final chunk, parses the 129-byte response: struct_type(0x2d) +\n// group_handle(64) + hmac_proof(32) + hmac_rest(32). Intermediate chunks ack\n// with SW=0x9000 and no data.\n// Protocol: Address Book Final Specifications \u2014 Register Identity.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n GROUP_HANDLE_BYTES,\n HMAC_PROOF_BYTES,\n HMAC_REST_BYTES,\n SUB_CMD_REGISTER_IDENTITY,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type RegisterIdentityCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RegisterIdentityCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2d) +\n * group_handle(64) + hmac_proof(32) + hmac_rest(32) there. Intermediate\n * chunks return SW=0x9000 with no data.\n *\n * `hmacProof` is the device's HMAC_PROOF (binds the contact name);\n * `hmacRest` is the HMAC_REST (binds scope + identifier + family).\n */\n readonly groupHandle?: Uint8Array;\n readonly hmacProof?: Uint8Array;\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = 0x2d;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RegisterIdentityCommand\n implements\n Command<\n RegisterIdentityCommandResponse,\n RegisterIdentityCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"registerIdentity\";\n readonly args: RegisterIdentityCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<RegisterIdentityCommandResponse>();\n\n constructor(args: RegisterIdentityCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_REGISTER_IDENTITY,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RegisterIdentityCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const groupHandle = extractField(parser, GROUP_HANDLE_BYTES);\n if (!groupHandle) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"group_handle missing or truncated\",\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_PROOF_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { groupHandle, hmacProof, hmacRest },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,sBAAAC,EACA,oBAAAC,EACA,mBAAAC,EACA,6BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CAuBP,MAAMC,EAAuB,GAO7B,SAASC,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,mBACP,KACQ,YACf,IAAIN,EAEN,YAAYO,EAAmC,CAC7C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIlB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAII,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACES,EACoE,CACpE,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOjB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMY,EAAS,IAAIb,EAAWkB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOV,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BS,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAcR,EAAaC,EAAQP,CAAkB,EAC3D,GAAI,CAACc,EACH,OAAOnB,EAAqB,CAC1B,MAAO,IAAIC,EACT,mCACF,CACF,CAAC,EAGH,MAAMmB,EAAYT,EAAaC,EAAQN,CAAgB,EACvD,GAAI,CAACc,EACH,OAAOpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,EAGH,MAAMoB,EAAWV,EAAaC,EAAQL,CAAe,EACrD,OAAKc,EAMErB,EAAqB,CAC1B,KAAM,CAAE,YAAAmB,EAAa,UAAAC,EAAW,SAAAC,CAAS,CAC3C,CAAC,EAPQrB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "SUB_CMD_REGISTER_IDENTITY", "ContactsCommandErrorHelper", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RegisterIdentityCommand", "args", "response", "structType", "groupHandle", "hmacProof", "hmacRest"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ApduBuilder as s,ApduParser as C,CommandResultFactory as t,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{
|
|
1
|
+
import{ApduBuilder as s,ApduParser as C,CommandResultFactory as t,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{Maybe as p}from"purify-ts";import{HMAC_NAME_BYTES as i,RENAME_CONTACT_APDU_CLA as u,RENAME_CONTACT_APDU_INS as c,RENAME_CONTACT_P1 as A}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as l}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_CONTACT_NAME as R}from"../../app-binder/services/contactsTlvSerializer";const d=R;function y(a,e){const r=a.extractFieldByLength(e);if(!(!r||r.length!==e))return Uint8Array.from(r)}class N{name="renameContact";args;errorHelper=new l;constructor(e){this.args=e}getApdu(){return new s({cla:u,ins:c,p1:A,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(e){return p.fromNullable(this.errorHelper.getError(e)).orDefaultLazy(()=>{if(e.data.length===0)return t({data:{}});const r=new C(e),n=r.extract8BitUInt();if(n!==d)return t({error:new m(`Expected struct_type 0x${d.toString(16)}, got ${n===void 0?"undefined":`0x${n.toString(16)}`}`)});const o=y(r,i);return o?t({data:{hmacProof:o}}):t({error:new m("hmac_name missing or truncated")})})}}export{N as RenameContactCommand};
|
|
2
2
|
//# sourceMappingURL=RenameContactCommand.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/command/RenameContactCommand.ts"],
|
|
4
|
-
"sourcesContent": ["// Rename Contact (EDIT CONTACT NAME) \u2014 the blockchain-agnostic address-book\n// rename. It is dispatched as an OS/dashboard command (CLA 0xE0 / INS 0x2E /\n// P1 0x00), NOT through the embedded app: the caller navigates to the dashboard\n// first (GoToDashboardDeviceAction) so the OS handles it directly.\n// SendRenameContactTask + sendFramedContactsPayload assemble the TLV, prepend\n// the 2-byte BE total length and slice into <=255B chunks; this command frames\n// one chunk and, on the final chunk, parses the 33-byte response:\n// struct_type(0x2e) + rotated hmac_name(32). Intermediate chunks ack with\n// SW=0x9000 and no data.\n//\n// The device is stateless: it verifies the supplied group handle + old-name\n// proof against the seed-derived key (SW 0x6982 on a seed mismatch, before any\n// UI) and, on approval, returns a fresh proof for the new name.\n// Protocol: Address Book Final Specifications \u2014 Edit Contact Name.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport {
|
|
5
|
-
"mappings": "AAcA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,
|
|
6
|
-
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "
|
|
4
|
+
"sourcesContent": ["// Rename Contact (EDIT CONTACT NAME) \u2014 the blockchain-agnostic address-book\n// rename. It is dispatched as an OS/dashboard command (CLA 0xE0 / INS 0x2E /\n// P1 0x00), NOT through the embedded app: the caller navigates to the dashboard\n// first (GoToDashboardDeviceAction) so the OS handles it directly.\n// SendRenameContactTask + sendFramedContactsPayload assemble the TLV, prepend\n// the 2-byte BE total length and slice into <=255B chunks; this command frames\n// one chunk and, on the final chunk, parses the 33-byte response:\n// struct_type(0x2e) + rotated hmac_name(32). Intermediate chunks ack with\n// SW=0x9000 and no data.\n//\n// The device is stateless: it verifies the supplied group handle + old-name\n// proof against the seed-derived key (SW 0x6982 on a seed mismatch, before any\n// UI) and, on approval, returns a fresh proof for the new name.\n// Protocol: Address Book Final Specifications \u2014 Edit Contact Name.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n HMAC_NAME_BYTES,\n RENAME_CONTACT_APDU_CLA,\n RENAME_CONTACT_APDU_INS,\n RENAME_CONTACT_P1,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_CONTACT_NAME } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type RenameContactCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RenameContactCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2e) +\n * rotated hmac_name(32) there. Intermediate chunks return SW=0x9000 with no\n * data. This is the replacement group-level name proof.\n */\n readonly hmacProof?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_CONTACT_NAME;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RenameContactCommand\n implements\n Command<\n RenameContactCommandResponse,\n RenameContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"renameContact\";\n readonly args: RenameContactCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<RenameContactCommandResponse>();\n\n constructor(args: RenameContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: RENAME_CONTACT_APDU_CLA,\n ins: RENAME_CONTACT_APDU_INS,\n p1: RENAME_CONTACT_P1,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RenameContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_NAME_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacProof },\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAcA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,mBAAAC,EACA,2BAAAC,EACA,2BAAAC,EACA,qBAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,iCAAAC,MAAqC,sDAkB9C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gBACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAAgC,CAC1C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EACiE,CACjE,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAYR,EAAaC,EAAQR,CAAe,EACtD,OAAKe,EAMElB,EAAqB,CAC1B,KAAM,CAAE,UAAAkB,CAAU,CACpB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
|
|
6
|
+
"names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "HMAC_NAME_BYTES", "RENAME_CONTACT_APDU_CLA", "RENAME_CONTACT_APDU_INS", "RENAME_CONTACT_P1", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_CONTACT_NAME", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RenameContactCommand", "args", "response", "structType", "hmacProof"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{CommandResultStatus as
|
|
1
|
+
import{CommandResultStatus as r,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as u,ContactsCommandError as n}from"../../app-binder/model/contactsErrors";import{RenameContactCommand as a}from"./RenameContactCommand";function d(e){const t=new Uint8Array(e.length/2);for(let o=0;o<e.length;o+=2)t[o/2]=parseInt(e.slice(o,o+2),16);return t}const p=d("dd".repeat(32)),c="2e"+"dd".repeat(32);function s(e){return{data:Buffer.from(d(e)),statusCode:Buffer.from([144,0])}}describe("RenameContactCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk",()=>{const e=Uint8Array.from([0,3,170,187,204]),t=new a({data:e,p2:0}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const e=Uint8Array.from([170,187]),t=new a({data:e,p2:128}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,128,2,170,187]))})}),describe("parseResponse",()=>{it("returns an empty payload for an intermediate chunk (SW=0x9000, no data)",()=>{const e=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(e).toStrictEqual({status:r.Success,data:{}})}),it("extracts the rotated hmac_name from an edit-contact-name response",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse(s(c));expect(t).toStrictEqual({status:r.Success,data:{hmacProof:p}})}),it("returns InvalidStatusWordError when struct_type is wrong",()=>{const e="ee"+c.slice(2),o=new a({data:new Uint8Array,p2:0}).parseResponse(s(e));expect(o.status).toBe(r.Error)}),it("returns InvalidStatusWordError when hmac_name is truncated",()=>{const e="2e"+"dd".repeat(16),o=new a({data:new Uint8Array,p2:0}).parseResponse(s(e));expect(o.status).toBe(r.Error)}),it("maps a known SW (0x6985) to a ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,133])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe("6985"))}),it("maps SW=0x686A (OS still mandates the derivation path) to a ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([104,106])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe("686a"))}),it("gives an unmapped status word an actionable message instead of UnknownDeviceExchangeError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([109,1])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(m),expect(t.error.originalError?.message).toContain("0x6d01"))}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe(u))})})});
|
|
2
2
|
//# sourceMappingURL=RenameContactCommand.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/command/RenameContactCommand.test.ts"],
|
|
4
|
-
"sourcesContent": ["// RenameContactCommand is a thin chunk-framer for the OS/dashboard EDIT CONTACT\n// NAME command: it wraps a pre-framed chunk (2-byte BE length prefix + TLV,\n// assembled by SendRenameContactTask + sendFramedContactsPayload) under\n// E0 2E 00 <P2>, and parses the 33-byte response on the final chunk. TLV\n// byte-parity is asserted in SendRenameContactTask.test.ts.\nimport {\n type ApduResponse,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n ContactsCommandError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RenameContactCommand } from \"./RenameContactCommand\";\n\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return out;\n}\n\n// Device response: struct_type(0x2e) + rotated hmac_name(32).\nconst HMAC_PROOF = hexToBytes(\"dd\".repeat(32));\nconst RESPONSE_HEX = \"2e\" + \"dd\".repeat(32);\n\nfunction makeResponse(hex: string): ApduResponse {\n return {\n data: Buffer.from(hexToBytes(hex)),\n statusCode: Buffer.from([0x90, 0x00]),\n };\n}\n\ndescribe(\"RenameContactCommand\", () => {\n describe(\"getApdu\", () => {\n it(\"wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk\", () => {\n const data = Uint8Array.from([0x00, 0x03, 0xaa, 0xbb, 0xcc]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x00 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([\n 0xe0, 0x2e, 0x00, 0x00, 0x05, 0x00, 0x03, 0xaa, 0xbb, 0xcc,\n ]),\n );\n });\n\n it(\"uses P2=0x80 for continuation chunks\", () => {\n const data = Uint8Array.from([0xaa, 0xbb]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x80 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([0xe0, 0x2e, 0x00, 0x80, 0x02, 0xaa, 0xbb]),\n );\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"returns an empty payload for an intermediate chunk (SW=0x9000, no data)\", () => {\n const result = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x90, 0x00]),\n });\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: {},\n });\n });\n\n it(\"extracts the rotated hmac_name from an edit-contact-name response\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(RESPONSE_HEX));\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: { hmacProof: HMAC_PROOF },\n });\n });\n\n it(\"returns InvalidStatusWordError when struct_type is wrong\", () => {\n const wrongType = \"ee\" + RESPONSE_HEX.slice(2); // replace 0x2e with 0xee\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(wrongType));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"returns InvalidStatusWordError when hmac_name is truncated\", () => {\n const truncated = \"2e\" + \"dd\".repeat(16); // only 16 of 32 bytes\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(truncated));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"maps a known SW (0x6985) to a ContactsCommandError\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x85]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\"6985\");\n }\n });\n\n it(\"maps SW=0x6982 to a seed-mismatch ContactsCommandError\", () => {\n // The device verifies the supplied group handle + old-name proof against\n // the seed-derived key before any UI, and returns 0x6982 on a mismatch.\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x82]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n );\n }\n });\n });\n});\n"],
|
|
5
|
-
"mappings": "AAKA,OAEE,uBAAAA,MACK,kCAEP,OACE,oCAAAC,EACA,wBAAAC,MACK,4CAEP,OAAS,wBAAAC,MAA4B,yBAErC,SAASC,EAAWC,EAAyB,CAC3C,MAAMC,EAAM,IAAI,WAAWD,EAAI,OAAS,CAAC,EACzC,QAASE,EAAI,EAAGA,EAAIF,EAAI,OAAQE,GAAK,EACnCD,EAAIC,EAAI,CAAC,EAAI,SAASF,EAAI,MAAME,EAAGA,EAAI,CAAC,EAAG,EAAE,EAE/C,OAAOD,CACT,CAGA,MAAME,EAAaJ,EAAW,KAAK,OAAO,EAAE,CAAC,EACvCK,EAAe,KAAO,KAAK,OAAO,EAAE,EAE1C,SAASC,EAAaL,EAA2B,CAC/C,MAAO,CACL,KAAM,OAAO,KAAKD,EAAWC,CAAG,CAAC,EACjC,WAAY,OAAO,KAAK,CAAC,IAAM,CAAI,CAAC,CACtC,CACF,CAEA,SAAS,uBAAwB,IAAM,CACrC,SAAS,UAAW,IAAM,CACxB,GAAG,8EAA+E,IAAM,CACtF,MAAMM,EAAO,WAAW,KAAK,CAAC,EAAM,EAAM,IAAM,IAAM,GAAI,CAAC,EAErDC,EAAO,IAAIT,EAAqB,CAAE,KAAAQ,EAAM,GAAI,CAAK,CAAC,EAAE,QAAQ,EAElE,OAAOC,EAAK,WAAW,CAAC,EAAE,cACxB,WAAW,KAAK,CACd,IAAM,GAAM,EAAM,EAAM,EAAM,EAAM,EAAM,IAAM,IAAM,GACxD,CAAC,CACH,CACF,CAAC,EAED,GAAG,uCAAwC,IAAM,CAC/C,MAAMD,EAAO,WAAW,KAAK,CAAC,IAAM,GAAI,CAAC,EAEnCC,EAAO,IAAIT,EAAqB,CAAE,KAAAQ,EAAM,GAAI,GAAK,CAAC,EAAE,QAAQ,EAElE,OAAOC,EAAK,WAAW,CAAC,EAAE,cACxB,WAAW,KAAK,CAAC,IAAM,GAAM,EAAM,IAAM,EAAM,IAAM,GAAI,CAAC,CAC5D,CACF,CAAC,CACH,CAAC,EAED,SAAS,gBAAiB,IAAM,CAC9B,GAAG,0EAA2E,IAAM,CAClF,MAAMC,EAAS,IAAIV,EAAqB,CACtC,KAAM,IAAI,WACV,GAAI,CACN,CAAC,EAAE,cAAc,CACf,KAAM,OAAO,KAAK,CAAC,CAAC,EACpB,WAAY,OAAO,KAAK,CAAC,IAAM,CAAI,CAAC,CACtC,CAAC,EAED,OAAOU,CAAM,EAAE,cAAc,CAC3B,
|
|
6
|
-
"names": ["CommandResultStatus", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "RenameContactCommand", "hexToBytes", "hex", "out", "i", "HMAC_PROOF", "RESPONSE_HEX", "makeResponse", "data", "apdu", "result", "wrongType", "truncated"]
|
|
4
|
+
"sourcesContent": ["// RenameContactCommand is a thin chunk-framer for the OS/dashboard EDIT CONTACT\n// NAME command: it wraps a pre-framed chunk (2-byte BE length prefix + TLV,\n// assembled by SendRenameContactTask + sendFramedContactsPayload) under\n// E0 2E 00 <P2>, and parses the 33-byte response on the final chunk. TLV\n// byte-parity is asserted in SendRenameContactTask.test.ts.\nimport {\n type ApduResponse,\n CommandResultStatus,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n ContactsCommandError,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nimport { RenameContactCommand } from \"./RenameContactCommand\";\n\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return out;\n}\n\n// Device response: struct_type(0x2e) + rotated hmac_name(32).\nconst HMAC_PROOF = hexToBytes(\"dd\".repeat(32));\nconst RESPONSE_HEX = \"2e\" + \"dd\".repeat(32);\n\nfunction makeResponse(hex: string): ApduResponse {\n return {\n data: Buffer.from(hexToBytes(hex)),\n statusCode: Buffer.from([0x90, 0x00]),\n };\n}\n\ndescribe(\"RenameContactCommand\", () => {\n describe(\"getApdu\", () => {\n it(\"wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk\", () => {\n const data = Uint8Array.from([0x00, 0x03, 0xaa, 0xbb, 0xcc]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x00 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([\n 0xe0, 0x2e, 0x00, 0x00, 0x05, 0x00, 0x03, 0xaa, 0xbb, 0xcc,\n ]),\n );\n });\n\n it(\"uses P2=0x80 for continuation chunks\", () => {\n const data = Uint8Array.from([0xaa, 0xbb]);\n\n const apdu = new RenameContactCommand({ data, p2: 0x80 }).getApdu();\n\n expect(apdu.getRawApdu()).toStrictEqual(\n Uint8Array.from([0xe0, 0x2e, 0x00, 0x80, 0x02, 0xaa, 0xbb]),\n );\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"returns an empty payload for an intermediate chunk (SW=0x9000, no data)\", () => {\n const result = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n }).parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x90, 0x00]),\n });\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: {},\n });\n });\n\n it(\"extracts the rotated hmac_name from an edit-contact-name response\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(RESPONSE_HEX));\n\n expect(result).toStrictEqual({\n status: CommandResultStatus.Success,\n data: { hmacProof: HMAC_PROOF },\n });\n });\n\n it(\"returns InvalidStatusWordError when struct_type is wrong\", () => {\n const wrongType = \"ee\" + RESPONSE_HEX.slice(2); // replace 0x2e with 0xee\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(wrongType));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"returns InvalidStatusWordError when hmac_name is truncated\", () => {\n const truncated = \"2e\" + \"dd\".repeat(16); // only 16 of 32 bytes\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse(makeResponse(truncated));\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n\n it(\"maps a known SW (0x6985) to a ContactsCommandError\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x85]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\"6985\");\n }\n });\n\n it(\"maps SW=0x686A (OS still mandates the derivation path) to a ContactsCommandError\", () => {\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x68, 0x6a]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\"686a\");\n }\n });\n\n it(\"gives an unmapped status word an actionable message instead of UnknownDeviceExchangeError\", () => {\n // 0x6D01 is in neither the Contacts nor the global error dictionary, so\n // the base helper would yield a bare UnknownDeviceExchangeError. The\n // Contacts helper upgrades it to an InvalidStatusWordError naming the SW.\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x6d, 0x01]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(InvalidStatusWordError);\n expect(\n (result.error as InvalidStatusWordError).originalError?.message,\n ).toContain(\"0x6d01\");\n }\n });\n\n it(\"maps SW=0x6982 to a seed-mismatch ContactsCommandError\", () => {\n // The device verifies the supplied group handle + old-name proof against\n // the seed-derived key before any UI, and returns 0x6982 on a mismatch.\n const command = new RenameContactCommand({\n data: new Uint8Array(),\n p2: 0x00,\n });\n\n const result = command.parseResponse({\n data: Buffer.from([]),\n statusCode: Buffer.from([0x69, 0x82]),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n if (result.status === CommandResultStatus.Error) {\n expect(result.error).toBeInstanceOf(ContactsCommandError);\n expect((result.error as ContactsCommandError).errorCode).toBe(\n CONTACT_SEED_MISMATCH_ERROR_CODE,\n );\n }\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CommandResultStatus", "InvalidStatusWordError", "CONTACT_SEED_MISMATCH_ERROR_CODE", "ContactsCommandError", "RenameContactCommand", "hexToBytes", "hex", "out", "i", "HMAC_PROOF", "RESPONSE_HEX", "makeResponse", "data", "apdu", "result", "wrongType", "truncated"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ApplicationChecker as p}from"@ledgerhq/device-management-kit";import{isVersionAtLeast as
|
|
1
|
+
import{ApplicationChecker as p}from"@ledgerhq/device-management-kit";import{isVersionAtLeast as c,resolveContactsVersionRequirements as i}from"../../api/model/ContactsVersionRequirements";import{ContactsApplicationResolver as a}from"./ContactsApplicationResolver";function s(e){return e.supported}function m(e,t){const o=e.getDeviceSessionState(),n=i(o.deviceModelId);return s(n)?c(t,n.minOsVersion):!1}function f(e,t){const o=e.getDeviceSessionState(),n=i(o.deviceModelId);if(!s(n))return!1;const r=n.minAppVersion[t.name];return r===void 0?!1:new p(o,{version:t.version},new a).withMinVersionInclusiveAcceptingPrerelease(r).check()}export{f as isContactsAppVersionSupportedForSession,m as isContactsOsVersionSupportedForSession};
|
|
2
2
|
//# sourceMappingURL=contactsVersionGuards.js.map
|
|
@@ -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": "AAAA,OACE,sBAAAA,MAEK,kCAEP,OAGE,oBAAAC,EACA,sCAAAC,MACK,yCAEP,OAAS,+BAAAC,MAAmC,gCAS5C,SAASC,EACPC,EACqC,CACrC,OAAOA,EAAY,SACrB,
|
|
6
|
-
"names": ["ApplicationChecker", "isVersionAtLeast", "resolveContactsVersionRequirements", "ContactsApplicationResolver", "isContactsModelSupported", "requirement", "
|
|
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": "AAAA,OACE,sBAAAA,MAEK,kCAEP,OAGE,oBAAAC,EACA,sCAAAC,MACK,yCAEP,OAAS,+BAAAC,MAAmC,gCAS5C,SAASC,EACPC,EACqC,CACrC,OAAOA,EAAY,SACrB,CAuBO,SAASC,EACdC,EACAC,EACS,CACT,MAAMC,EAAcF,EAAY,sBAAsB,EAChDF,EAAcH,EAClBO,EAAY,aACd,EACA,OAAKL,EAAyBC,CAAW,EAElCJ,EAAiBO,EAAWH,EAAY,YAAY,EAFR,EAGrD,CAkBO,SAASK,EACdH,EACAI,EACS,CACT,MAAMF,EAAcF,EAAY,sBAAsB,EAChDF,EAAcH,EAClBO,EAAY,aACd,EACA,GAAI,CAACL,EAAyBC,CAAW,EAAG,MAAO,GAEnD,MAAMO,EAAgBP,EAAY,cAAcM,EAAI,IAAI,EACxD,OAAIC,IAAkB,OAAkB,GAEjC,IAAIZ,EACTS,EACA,CAAE,QAASE,EAAI,OAAQ,EACvB,IAAIR,CACN,EACG,2CAA2CS,CAAa,EACxD,MAAM,CACX",
|
|
6
|
+
"names": ["ApplicationChecker", "isVersionAtLeast", "resolveContactsVersionRequirements", "ContactsApplicationResolver", "isContactsModelSupported", "requirement", "isContactsOsVersionSupportedForSession", "internalApi", "osVersion", "deviceState", "isContactsAppVersionSupportedForSession", "app", "minAppVersion"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{DeviceModelId as i,DeviceSessionStateType as
|
|
1
|
+
import{DeviceModelId as i,DeviceSessionStateType as d,DeviceStatus as l}from"@ledgerhq/device-management-kit";import{ETHEREUM_APP_NAME as c,resolveContactsVersionRequirements as f}from"../../api/model/ContactsVersionRequirements";import{isContactsAppVersionSupportedForSession as s,isContactsOsVersionSupportedForSession as o}from"./contactsVersionGuards";const m=(()=>{const e=f(i.FLEX);if(!e.supported)throw new Error("Flex must be supported");return e})(),a=m.minOsVersion,S=(()=>{const e=m.minAppVersion[c];if(e===void 0)throw new Error("Ethereum min version required");return e})(),p="0.0.1";function n({osVersion:e=a,modelId:u=i.FLEX}={}){return{sessionStateType:d.ReadyWithoutSecureChannel,deviceStatus:l.CONNECTED,installedApps:[],currentApp:{name:c,version:"0.0.0"},deviceModelId:u,firmwareVersion:{mcu:"1.0.0",bootloader:"1.0.0",os:e},isSecureConnectionAllowed:!1}}function t(e){return{getDeviceSessionState:()=>e}}function r(e=c,u=S){return{name:e,version:u}}describe("isContactsAppVersionSupportedForSession",()=>{it("returns true when the model and app version meet the minimums",()=>{const e=t(n());expect(s(e,r())).toBe(!0)}),it("returns true regardless of OS version, since app-owned operations are not gated by it",()=>{const e=t(n({osVersion:p}));expect(s(e,r())).toBe(!0)}),it("returns false on an unsupported device model",()=>{const e=t(n({modelId:i.NANO_S}));expect(s(e,r())).toBe(!1)}),it("returns false when the app version is below the minimum",()=>{const e=t(n());expect(s(e,r(c,p))).toBe(!1)}),it("returns false when the running app is unknown to Contacts",()=>{const e=t(n());expect(s(e,r("Bitcoin"))).toBe(!1)}),it("returns true for a prerelease build of the minimum app version",()=>{const e=t(n());expect(s(e,r(c,`${S}-rc2`))).toBe(!0)}),it("returns false when the device session has no running app",()=>{const e=t({sessionStateType:d.Connected,deviceStatus:l.CONNECTED,deviceModelId:i.FLEX});expect(s(e,r())).toBe(!1)})});describe("isContactsOsVersionSupportedForSession",()=>{it("returns true when the model and the caller's OS version meet the minimums",()=>{const e=t(n());expect(o(e,a)).toBe(!0)}),it("returns false on an unsupported device model",()=>{const e=t(n({modelId:i.NANO_S}));expect(o(e,a)).toBe(!1)}),it("returns false when the caller's OS version is below the minimum",()=>{const e=t(n());expect(o(e,p)).toBe(!1)}),it("returns true for a release candidate of the minimum OS version",()=>{const e=t(n());expect(o(e,`${a}-rc2`)).toBe(!0)}),it("returns false for a release candidate below the minimum OS version",()=>{const e=t(n());expect(o(e,`${p}-rc2`)).toBe(!1)}),it("never reads the OS version from the device session state",()=>{const e=t({sessionStateType:d.Connected,deviceStatus:l.CONNECTED,deviceModelId:i.FLEX});expect(o(e,a)).toBe(!0),expect(o(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,OACE,iBAAAA,EACA,0BAAAC,EACA,gBAAAC,MAEK,kCAEP,OACE,qBAAAC,EACA,sCAAAC,MACK,yCAEP,OACE,2CAAAC,EACA,
|
|
6
|
-
"names": ["DeviceModelId", "DeviceSessionStateType", "DeviceStatus", "ETHEREUM_APP_NAME", "resolveContactsVersionRequirements", "isContactsAppVersionSupportedForSession", "
|
|
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
|
+
"names": ["DeviceModelId", "DeviceSessionStateType", "DeviceStatus", "ETHEREUM_APP_NAME", "resolveContactsVersionRequirements", "isContactsAppVersionSupportedForSession", "isContactsOsVersionSupportedForSession", "flexSupport", "requirement", "MIN_OS_VERSION", "MIN_APP_VERSION", "version", "BELOW_ANY_VERSION", "createReadyState", "osVersion", "modelId", "createInternalApi", "deviceState", "runningApp", "name", "api"]
|
|
7
7
|
}
|
package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{GoToDashboardDeviceAction as
|
|
1
|
+
import{GetOsVersionCommand as C,GoToDashboardDeviceAction as g,isSuccessCommandResult as p,UnknownDAError as l,UserInteractionRequired as o,XStateDeviceAction as S}from"@ledgerhq/device-management-kit";import{Left as R,Right as D}from"purify-ts";import{assign as n,fromPromise as d,setup as V}from"xstate";import{renameRequiresDerivationPath as h}from"../../../../api/model/ContactsVersionRequirements";import{isContactsOsVersionSupportedForSession as I}from"../../../app-binder/contactsVersionGuards";import{ContactsVersionRequirementError as y}from"../../../app-binder/model/contactsErrors";import{SendRenameContactTask as E}from"../../../app-binder/task/SendRenameContactTask";import{validateRenameContactInput as A}from"./validateRenameContactInput";class b extends S{makeStateMachine(a){const{getOsVersion:c,isOsVersionSupported:u,renameContact:m}=this.extractDependencies(a),{deviceModelId:r}=a.getDeviceSessionState();return V({types:{input:{},context:{},output:{}},actors:{goToDashboardStateMachine:new g({input:{}}).makeStateMachine(a),getOsVersion:d(c),renameContact:d(({input:e})=>m(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:n({_internalState:({context:e})=>{const t=A(e.input);return t?{...e._internalState,error:t}:e._internalState}}),assignVersionError:n({_internalState:({context:e})=>({...e._internalState,error:new y})}),assignErrorFromEvent:n({_internalState:({context:e,event:t})=>({...e._internalState,error:new l(t.error instanceof Error?t.error.message:String(t.error))})})}}).createMachine({id:"RenameContactDeviceAction",initial:"InitialState",context:({input:e})=>({input:e,intermediateValue:{requiredUserInteraction:o.None},_internalState:{error:null,osVersion:null,proof:null}}),states:{InitialState:{always:{target:"GoToDashboard"}},GoToDashboard:{invoke:{id:"goToDashboard",src:"goToDashboardStateMachine",input:()=>({}),onSnapshot:{actions:n({intermediateValue:({event:e})=>({requiredUserInteraction:e.snapshot.context.intermediateValue.requiredUserInteraction})})},onDone:{target:"GoToDashboardCheck",actions:n({_internalState:({event:e,context:t})=>e.output.caseOf({Right:()=>t._internalState,Left:i=>({...t._internalState,error:i})})})},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:n({intermediateValue:{requiredUserInteraction:o.None}}),invoke:{id:"getOsVersion",src:"getOsVersion",onDone:{target:"GetOsVersionResultCheck",actions:n({_internalState:({event:e,context:t})=>p(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:n({intermediateValue:{requiredUserInteraction:o.RegisterWallet}}),exit:n({intermediateValue:{requiredUserInteraction:o.None}}),invoke:{id:"renameContact",src:"renameContact",input:({context:e})=>({args:e.input,includeDerivationPath:h(r,e._internalState.osVersion??"")}),onDone:{target:"RenameContactResultCheck",actions:n({_internalState:({event:e,context:t})=>p(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:i}=e._internalState;if(t){const{input:s}=e;return D({previousContactName:s.previousContactName,contactName:s.newContactName,groupHandle:s.groupHandle,hmacProof:t.hmacProof})}return R(i??new l("No error in final state"))}})}extractDependencies(a){return{getOsVersion:()=>a.sendCommand(new C),isOsVersionSupported:r=>I(a,r),renameContact:(r,e)=>new E(a,{previousContactName:r.previousContactName,newContactName:r.newContactName,groupHandle:r.groupHandle,hmacProof:r.hmacProof,includeDerivationPath:e}).run()}}}export{b as RenameContactDeviceAction};
|
|
2
2
|
//# sourceMappingURL=RenameContactDeviceAction.js.map
|