@ledgerhq/device-signer-kit-solana 0.0.0-verify-safe-address-20251016105127 → 0.0.0-wrong-error-when-in-experimental-provider-20251021161219

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.
Files changed (22) hide show
  1. package/lib/cjs/internal/app-binder/command/SignOffChainMessageCommand.js +1 -1
  2. package/lib/cjs/internal/app-binder/command/SignOffChainMessageCommand.js.map +3 -3
  3. package/lib/cjs/internal/app-binder/command/SignOffChainMessageCommand.test.js +1 -1
  4. package/lib/cjs/internal/app-binder/command/SignOffChainMessageCommand.test.js.map +3 -3
  5. package/lib/cjs/internal/app-binder/task/SendSignMessageTask.js +1 -1
  6. package/lib/cjs/internal/app-binder/task/SendSignMessageTask.js.map +3 -3
  7. package/lib/cjs/internal/app-binder/task/SendSignMessageTask.test.js +3 -1
  8. package/lib/cjs/internal/app-binder/task/SendSignMessageTask.test.js.map +3 -3
  9. package/lib/esm/internal/app-binder/command/SignOffChainMessageCommand.js +1 -1
  10. package/lib/esm/internal/app-binder/command/SignOffChainMessageCommand.js.map +3 -3
  11. package/lib/esm/internal/app-binder/command/SignOffChainMessageCommand.test.js +1 -1
  12. package/lib/esm/internal/app-binder/command/SignOffChainMessageCommand.test.js.map +3 -3
  13. package/lib/esm/internal/app-binder/task/SendSignMessageTask.js +1 -1
  14. package/lib/esm/internal/app-binder/task/SendSignMessageTask.js.map +3 -3
  15. package/lib/esm/internal/app-binder/task/SendSignMessageTask.test.js +3 -1
  16. package/lib/esm/internal/app-binder/task/SendSignMessageTask.test.js.map +3 -3
  17. package/lib/types/internal/app-binder/command/SignOffChainMessageCommand.d.ts +13 -12
  18. package/lib/types/internal/app-binder/command/SignOffChainMessageCommand.d.ts.map +1 -1
  19. package/lib/types/internal/app-binder/task/SendSignMessageTask.d.ts +19 -5
  20. package/lib/types/internal/app-binder/task/SendSignMessageTask.d.ts.map +1 -1
  21. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  22. package/package.json +5 -5
@@ -1,2 +1,2 @@
1
- "use strict";var m=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var h=(a,e)=>{for(var o in e)m(a,o,{get:e[o],enumerable:!0})},y=(a,e,o,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of A(e))!c.call(a,r)&&r!==o&&m(a,r,{get:()=>e[r],enumerable:!(s=u(e,r))||s.enumerable});return a};var S=a=>y(m({},"__esModule",{value:!0}),a);var R={};h(R,{SignOffChainMessageCommand:()=>E});module.exports=S(R);var n=require("@ledgerhq/device-management-kit"),g=require("@ledgerhq/signer-utils"),l=require("purify-ts"),f=require("../../app-binder/services/bs58Encoder"),p=require("./utils/SolanaApplicationErrors");const d=64;class E{constructor(e,o=f.DefaultBs58Encoder){this.bs58Encoder=o;this.args=e}errorHelper=new g.CommandErrorHelper(p.SOLANA_APP_ERRORS,p.SolanaAppCommandErrorFactory);args;getApdu(){return new n.ApduBuilder({cla:224,ins:7,p1:1,p2:0}).addBufferToData(this.args.message).build()}parseResponse(e){return l.Maybe.fromNullable(this.errorHelper.getError(e)).orDefaultLazy(()=>{const s=new n.ApduParser(e).extractFieldByLength(d);if(!s||s.length!==d)return(0,n.CommandResultFactory)({error:new n.InvalidStatusWordError("Signature extraction failed")});const r=Uint8Array.of(1),i=this.args.message,t=new Uint8Array(r.length+s.length+i.length);t.set(r,0),t.set(s,r.length),t.set(i,r.length+s.length);const C=this.bs58Encoder.encode(t);return(0,n.CommandResultFactory)({data:{signature:C}})})}}0&&(module.exports={SignOffChainMessageCommand});
1
+ "use strict";var p=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var g=(n,e)=>{for(var o in e)p(n,o,{get:e[o],enumerable:!0})},c=(n,e,o,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of l(e))!A.call(n,t)&&t!==o&&p(n,t,{get:()=>e[t],enumerable:!(a=C(e,t))||a.enumerable});return n};var R=n=>c(p({},"__esModule",{value:!0}),n);var x={};g(x,{CLA:()=>m,INS:()=>i,P1:()=>u,SOL_P2:()=>s,SignOffChainMessageCommand:()=>f});module.exports=R(x);var r=require("@ledgerhq/device-management-kit");const m=224,i=7,u=1,d=64,s={INIT:0,EXTEND:1,MORE:2};class f{constructor(e){this.args=e}getApdu(){const e=(this.args.extend?s.EXTEND:s.INIT)|(this.args.more?s.MORE:0);return new r.ApduBuilder({cla:m,ins:i,p1:u,p2:e}).addBufferToData(this.args.chunkedData).build()}parseResponse(e){const a=new r.ApduParser(e).extractFieldByLength(d);return!a||a.length!==d?(0,r.CommandResultFactory)({data:new Uint8Array(0)}):(0,r.CommandResultFactory)({data:a})}}0&&(module.exports={CLA,INS,P1,SOL_P2,SignOffChainMessageCommand});
2
2
  //# sourceMappingURL=SignOffChainMessageCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/SignOffChainMessageCommand.ts"],
4
- "sourcesContent": ["import {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n type Bs58Encoder,\n DefaultBs58Encoder,\n} from \"@internal/app-binder/services/bs58Encoder\";\n\nimport {\n SOLANA_APP_ERRORS,\n SolanaAppCommandErrorFactory,\n type SolanaAppErrorCodes,\n} from \"./utils/SolanaApplicationErrors\";\n\nconst SIGNATURE_LENGTH = 64;\n\nexport type SignOffChainMessageCommandResponse = {\n signature: string;\n};\nexport type SignOffChainMessageCommandArgs = {\n readonly message: Uint8Array;\n};\n\nexport class SignOffChainMessageCommand\n implements\n Command<\n SignOffChainMessageCommandResponse,\n SignOffChainMessageCommandArgs,\n SolanaAppErrorCodes\n >\n{\n private readonly errorHelper = new CommandErrorHelper<\n SignOffChainMessageCommandResponse,\n SolanaAppErrorCodes\n >(SOLANA_APP_ERRORS, SolanaAppCommandErrorFactory);\n\n args: SignOffChainMessageCommandArgs;\n\n constructor(\n args: SignOffChainMessageCommandArgs,\n private readonly bs58Encoder: Bs58Encoder = DefaultBs58Encoder,\n ) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: 0xe0,\n ins: 0x07,\n p1: 0x01,\n p2: 0x00,\n })\n .addBufferToData(this.args.message)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<SignOffChainMessageCommandResponse, SolanaAppErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n const parser = new ApduParser(response);\n\n // extract raw signature from device response\n const signature = parser.extractFieldByLength(SIGNATURE_LENGTH);\n if (!signature || signature.length !== SIGNATURE_LENGTH) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"Signature extraction failed\"),\n });\n }\n\n // build the OCM envelope: [signatureCount=1][signature][signedMessage]\n // signatureCount = 1 (single signer)\n const signatureCount = Uint8Array.of(1);\n\n // this.args.message is the off-chain message that was signed\n const msg = this.args.message;\n\n const envelope = new Uint8Array(\n signatureCount.length + signature.length + msg.length,\n );\n envelope.set(signatureCount, 0);\n envelope.set(signature, signatureCount.length);\n envelope.set(msg, signatureCount.length + signature.length);\n\n // base58-encode the envelope and return { signature: <b58> }\n const encoded = this.bs58Encoder.encode(envelope);\n\n return CommandResultFactory({\n data: { signature: encoded },\n });\n });\n }\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EASO,2CACPC,EAAmC,kCACnCC,EAAsB,qBAEtBC,EAGO,qDAEPC,EAIO,2CAEP,MAAMC,EAAmB,GASlB,MAAMP,CAOb,CAQE,YACEQ,EACiBC,EAA2B,qBAC5C,CADiB,iBAAAA,EAEjB,KAAK,KAAOD,CACd,CAZiB,YAAc,IAAI,qBAGjC,oBAAmB,8BAA4B,EAEjD,KASA,SAAgB,CACd,OAAO,IAAI,cAAY,CACrB,IAAK,IACL,IAAK,EACL,GAAI,EACJ,GAAI,CACN,CAAC,EACE,gBAAgB,KAAK,KAAK,OAAO,EACjC,MAAM,CACX,CAEA,cACEE,EACwE,CACxE,OAAO,QAAM,aACX,KAAK,YAAY,SAASA,CAAQ,CACpC,EAAE,cAAc,IAAM,CAIpB,MAAMC,EAHS,IAAI,aAAWD,CAAQ,EAGb,qBAAqBH,CAAgB,EAC9D,GAAI,CAACI,GAAaA,EAAU,SAAWJ,EACrC,SAAO,wBAAqB,CAC1B,MAAO,IAAI,yBAAuB,6BAA6B,CACjE,CAAC,EAKH,MAAMK,EAAiB,WAAW,GAAG,CAAC,EAGhCC,EAAM,KAAK,KAAK,QAEhBC,EAAW,IAAI,WACnBF,EAAe,OAASD,EAAU,OAASE,EAAI,MACjD,EACAC,EAAS,IAAIF,EAAgB,CAAC,EAC9BE,EAAS,IAAIH,EAAWC,EAAe,MAAM,EAC7CE,EAAS,IAAID,EAAKD,EAAe,OAASD,EAAU,MAAM,EAG1D,MAAMI,EAAU,KAAK,YAAY,OAAOD,CAAQ,EAEhD,SAAO,wBAAqB,CAC1B,KAAM,CAAE,UAAWC,CAAQ,CAC7B,CAAC,CACH,CAAC,CACH,CACF",
6
- "names": ["SignOffChainMessageCommand_exports", "__export", "SignOffChainMessageCommand", "__toCommonJS", "import_device_management_kit", "import_signer_utils", "import_purify_ts", "import_bs58Encoder", "import_SolanaApplicationErrors", "SIGNATURE_LENGTH", "args", "bs58Encoder", "response", "signature", "signatureCount", "msg", "envelope", "encoded"]
4
+ "sourcesContent": ["import {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ChunkableCommandArgs } from \"@internal/app-binder/task/SendCommandInChunksTask\";\n\nimport { type SolanaAppErrorCodes } from \"./utils/SolanaApplicationErrors\";\n\nexport const CLA = 0xe0;\nexport const INS = 0x07;\nexport const P1 = 0x01;\n\nconst SIGNATURE_LENGTH = 64;\n\nexport const SOL_P2 = {\n INIT: 0x00,\n EXTEND: 0x01,\n MORE: 0x02,\n};\n\nexport type SignOffChainRawResponse = Uint8Array;\n\nexport class SignOffChainMessageCommand\n implements\n Command<SignOffChainRawResponse, ChunkableCommandArgs, SolanaAppErrorCodes>\n{\n constructor(readonly args: ChunkableCommandArgs) {}\n\n getApdu(): Apdu {\n const p2 =\n (this.args.extend ? SOL_P2.EXTEND : SOL_P2.INIT) |\n (this.args.more ? SOL_P2.MORE : 0);\n\n return new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2,\n })\n .addBufferToData(this.args.chunkedData)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<SignOffChainRawResponse, SolanaAppErrorCodes> {\n const parser = new ApduParser(response);\n const sig = parser.extractFieldByLength(SIGNATURE_LENGTH);\n\n // for intermediate chunks, the device returns 0 bytes of data with 0x9000.\n // only the last chunk yields the 64-byte signature.\n if (!sig || sig.length !== SIGNATURE_LENGTH) {\n return CommandResultFactory({ data: new Uint8Array(0) });\n }\n\n return CommandResultFactory({ data: sig });\n }\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,SAAAE,EAAA,QAAAC,EAAA,OAAAC,EAAA,WAAAC,EAAA,+BAAAC,IAAA,eAAAC,EAAAP,GAAA,IAAAQ,EAQO,2CAMA,MAAMN,EAAM,IACNC,EAAM,EACNC,EAAK,EAEZK,EAAmB,GAEZJ,EAAS,CACpB,KAAM,EACN,OAAQ,EACR,KAAM,CACR,EAIO,MAAMC,CAGb,CACE,YAAqBI,EAA4B,CAA5B,UAAAA,CAA6B,CAElD,SAAgB,CACd,MAAMC,GACH,KAAK,KAAK,OAASN,EAAO,OAASA,EAAO,OAC1C,KAAK,KAAK,KAAOA,EAAO,KAAO,GAElC,OAAO,IAAI,cAAY,CACrB,IAAKH,EACL,IAAKC,EACL,GAAIC,EACJ,GAAAO,CACF,CAAC,EACE,gBAAgB,KAAK,KAAK,WAAW,EACrC,MAAM,CACX,CAEA,cACEC,EAC6D,CAE7D,MAAMC,EADS,IAAI,aAAWD,CAAQ,EACnB,qBAAqBH,CAAgB,EAIxD,MAAI,CAACI,GAAOA,EAAI,SAAWJ,KAClB,wBAAqB,CAAE,KAAM,IAAI,WAAW,CAAC,CAAE,CAAC,KAGlD,wBAAqB,CAAE,KAAMI,CAAI,CAAC,CAC3C,CACF",
6
+ "names": ["SignOffChainMessageCommand_exports", "__export", "CLA", "INS", "P1", "SOL_P2", "SignOffChainMessageCommand", "__toCommonJS", "import_device_management_kit", "SIGNATURE_LENGTH", "args", "p2", "response", "sig"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("@ledgerhq/device-management-kit"),i=require("../../app-binder/services/bs58Encoder"),c=require("./SignOffChainMessageCommand");describe("SignOffChainMessageCommand",()=>{let t;const a=new TextEncoder().encode("Solana SignOffChainMessage"),n=64;beforeEach(()=>{t=new c.SignOffChainMessageCommand({message:a}),vi.clearAllMocks(),vi.importActual("@ledgerhq/device-management-kit")}),describe("getApdu",()=>{it("should return the correct APDU",()=>{const s=t.getApdu(),r=new e.ApduBuilder({cla:224,ins:7,p1:1,p2:0}).addBufferToData(a).build();expect(s.getRawApdu()).toEqual(r.getRawApdu())})}),describe("parseResponse",()=>{it("should parse the response correctly",()=>{const s=new Uint8Array(n).fill(1),r=t.parseResponse(new e.ApduResponse({data:s,statusCode:new Uint8Array([144,0])}));if(expect((0,e.isSuccessCommandResult)(r)).toBe(!0),(0,e.isSuccessCommandResult)(r)){const o=new Uint8Array(1+n+a.length);o.set(Uint8Array.of(1),0),o.set(s,1),o.set(a,1+n);const d=i.DefaultBs58Encoder.encode(o);expect(r.data).toEqual({signature:d})}else assert.fail("Expected success result")}),describe("error handling",()=>{it("should return error if response is not success",()=>{const s=t.parseResponse(new e.ApduResponse({statusCode:new Uint8Array([106,130]),data:new Uint8Array(0)}));expect((0,e.isSuccessCommandResult)(s)).toBe(!1),(0,e.isSuccessCommandResult)(s)?assert.fail("Expected error"):expect(s.error).toEqual(expect.objectContaining({_tag:"SolanaAppCommandError",errorCode:"6a82",message:"Invalid off-chain message format"}))}),it("should return error if signature is missing or incomplete",()=>{const s=new Uint8Array(n-1).fill(1),r=t.parseResponse(new e.ApduResponse({data:s,statusCode:new Uint8Array([144,0])}));expect((0,e.isSuccessCommandResult)(r)).toBe(!1),(0,e.isSuccessCommandResult)(r)?assert.fail("Expected error"):typeof r.error.originalError=="object"&&r.error.originalError!==null&&"message"in r.error.originalError&&expect(r.error.originalError.message).toBe("Signature extraction failed")})})})});
1
+ "use strict";var a=require("@ledgerhq/device-management-kit"),e=require("./SignOffChainMessageCommand");describe("SignOffChainMessageCommand",()=>{const s=new TextEncoder().encode("Solana SignOffChainMessage"),r=64;describe("getApdu()",()=>{it("builds APDU for a single (final) chunk (p2=INIT)",()=>{const t=new e.SignOffChainMessageCommand({chunkedData:s,extend:!1,more:!1}).getApdu(),n=new a.ApduBuilder({cla:e.CLA,ins:e.INS,p1:e.P1,p2:0}).addBufferToData(s).build();expect(t.getRawApdu()).toEqual(n.getRawApdu())}),it("sets p2 correctly for first of many chunks (INIT|MORE)",()=>{const t=new e.SignOffChainMessageCommand({chunkedData:s,extend:!1,more:!0}).getApdu(),n=new a.ApduBuilder({cla:e.CLA,ins:e.INS,p1:e.P1,p2:2}).addBufferToData(s).build();expect(t.getRawApdu()).toEqual(n.getRawApdu())}),it("sets p2 correctly for middle chunks (EXTEND|MORE)",()=>{const t=new e.SignOffChainMessageCommand({chunkedData:s,extend:!0,more:!0}).getApdu(),n=new a.ApduBuilder({cla:e.CLA,ins:e.INS,p1:e.P1,p2:3}).addBufferToData(s).build();expect(t.getRawApdu()).toEqual(n.getRawApdu())}),it("sets p2 correctly for the final chunk after extends (EXTEND)",()=>{const t=new e.SignOffChainMessageCommand({chunkedData:s,extend:!0,more:!1}).getApdu(),n=new a.ApduBuilder({cla:e.CLA,ins:e.INS,p1:e.P1,p2:1}).addBufferToData(s).build();expect(t.getRawApdu()).toEqual(n.getRawApdu())})}),describe("parseResponse()",()=>{it("returns raw 64-byte signature on the last chunk",()=>{const d=new e.SignOffChainMessageCommand({chunkedData:s,extend:!0,more:!1}),t=new Uint8Array(r).fill(66),n=d.parseResponse(new a.ApduResponse({data:t,statusCode:new Uint8Array([144,0])}));expect((0,a.isSuccessCommandResult)(n)).toBe(!0),(0,a.isSuccessCommandResult)(n)&&expect(n.data).toEqual(t)}),it("returns empty data for intermediate chunks (no signature yet)",()=>{const t=new e.SignOffChainMessageCommand({chunkedData:s,extend:!0,more:!0}).parseResponse(new a.ApduResponse({data:new Uint8Array(0),statusCode:new Uint8Array([144,0])}));expect((0,a.isSuccessCommandResult)(t)).toBe(!0),(0,a.isSuccessCommandResult)(t)&&expect(t.data).toEqual(new Uint8Array(0))}),it("returns empty data if signature is present but not 64 bytes",()=>{const d=new e.SignOffChainMessageCommand({chunkedData:s,extend:!0,more:!1}),t=new Uint8Array(r-1).fill(153),n=d.parseResponse(new a.ApduResponse({data:t,statusCode:new Uint8Array([144,0])}));expect((0,a.isSuccessCommandResult)(n)).toBe(!0),(0,a.isSuccessCommandResult)(n)&&expect(n.data).toEqual(new Uint8Array(0))})})});
2
2
  //# sourceMappingURL=SignOffChainMessageCommand.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/SignOffChainMessageCommand.test.ts"],
4
- "sourcesContent": ["import {\n ApduBuilder,\n ApduResponse,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { DefaultBs58Encoder } from \"@internal/app-binder/services/bs58Encoder\";\n\nimport { SignOffChainMessageCommand } from \"./SignOffChainMessageCommand\";\n\ndescribe(\"SignOffChainMessageCommand\", () => {\n let command: SignOffChainMessageCommand;\n\n const MESSAGE = new TextEncoder().encode(\"Solana SignOffChainMessage\");\n const SIGNATURE_LENGTH = 64;\n\n beforeEach(() => {\n command = new SignOffChainMessageCommand({\n message: MESSAGE,\n });\n vi.clearAllMocks();\n vi.importActual(\"@ledgerhq/device-management-kit\");\n });\n\n describe(\"getApdu\", () => {\n it(\"should return the correct APDU\", () => {\n const apdu = command.getApdu();\n\n const expectedApdu = new ApduBuilder({\n cla: 0xe0,\n ins: 0x07,\n p1: 0x01,\n p2: 0x00,\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expectedApdu.getRawApdu());\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"should parse the response correctly\", () => {\n const signature = new Uint8Array(SIGNATURE_LENGTH).fill(0x01);\n\n const parsed = command.parseResponse(\n new ApduResponse({\n data: signature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n // build expected OCM envelope: [count=1][signature][message]\n const envelope = new Uint8Array(1 + SIGNATURE_LENGTH + MESSAGE.length);\n envelope.set(Uint8Array.of(1), 0);\n envelope.set(signature, 1);\n envelope.set(MESSAGE, 1 + SIGNATURE_LENGTH);\n\n const expectedB58 = DefaultBs58Encoder.encode(envelope);\n expect(parsed.data).toEqual({ signature: expectedB58 });\n } else {\n assert.fail(\"Expected success result\");\n }\n });\n\n describe(\"error handling\", () => {\n it(\"should return error if response is not success\", () => {\n const result = command.parseResponse(\n new ApduResponse({\n statusCode: new Uint8Array([0x6a, 0x82]),\n data: new Uint8Array(0),\n }),\n );\n\n expect(isSuccessCommandResult(result)).toBe(false);\n if (!isSuccessCommandResult(result)) {\n expect(result.error).toEqual(\n expect.objectContaining({\n _tag: \"SolanaAppCommandError\",\n errorCode: \"6a82\",\n message: \"Invalid off-chain message format\",\n }),\n );\n } else {\n assert.fail(\"Expected error\");\n }\n });\n\n it(\"should return error if signature is missing or incomplete\", () => {\n const incompleteSignature = new Uint8Array(SIGNATURE_LENGTH - 1).fill(\n 0x01,\n );\n const result = command.parseResponse(\n new ApduResponse({\n data: incompleteSignature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(result)).toBe(false);\n if (!isSuccessCommandResult(result)) {\n if (\n typeof result.error.originalError === \"object\" &&\n result.error.originalError !== null &&\n \"message\" in result.error.originalError\n ) {\n expect(\n (result.error.originalError as { message: string }).message,\n ).toBe(\"Signature extraction failed\");\n }\n } else {\n assert.fail(\"Expected error\");\n }\n });\n });\n });\n});\n"],
5
- "mappings": "aAAA,IAAAA,EAIO,2CAEPC,EAAmC,qDAEnCC,EAA2C,wCAE3C,SAAS,6BAA8B,IAAM,CAC3C,IAAIC,EAEJ,MAAMC,EAAU,IAAI,YAAY,EAAE,OAAO,4BAA4B,EAC/DC,EAAmB,GAEzB,WAAW,IAAM,CACfF,EAAU,IAAI,6BAA2B,CACvC,QAASC,CACX,CAAC,EACD,GAAG,cAAc,EACjB,GAAG,aAAa,iCAAiC,CACnD,CAAC,EAED,SAAS,UAAW,IAAM,CACxB,GAAG,iCAAkC,IAAM,CACzC,MAAME,EAAOH,EAAQ,QAAQ,EAEvBI,EAAe,IAAI,cAAY,CACnC,IAAK,IACL,IAAK,EACL,GAAI,EACJ,GAAI,CACN,CAAC,EACE,gBAAgBH,CAAO,EACvB,MAAM,EAET,OAAOE,EAAK,WAAW,CAAC,EAAE,QAAQC,EAAa,WAAW,CAAC,CAC7D,CAAC,CACH,CAAC,EAED,SAAS,gBAAiB,IAAM,CAC9B,GAAG,sCAAuC,IAAM,CAC9C,MAAMC,EAAY,IAAI,WAAWH,CAAgB,EAAE,KAAK,CAAI,EAEtDI,EAASN,EAAQ,cACrB,IAAI,eAAa,CACf,KAAMK,EACN,WAAY,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CACzC,CAAC,CACH,EAGA,GADA,UAAO,0BAAuBC,CAAM,CAAC,EAAE,KAAK,EAAI,KAC5C,0BAAuBA,CAAM,EAAG,CAElC,MAAMC,EAAW,IAAI,WAAW,EAAIL,EAAmBD,EAAQ,MAAM,EACrEM,EAAS,IAAI,WAAW,GAAG,CAAC,EAAG,CAAC,EAChCA,EAAS,IAAIF,EAAW,CAAC,EACzBE,EAAS,IAAIN,EAAS,EAAIC,CAAgB,EAE1C,MAAMM,EAAc,qBAAmB,OAAOD,CAAQ,EACtD,OAAOD,EAAO,IAAI,EAAE,QAAQ,CAAE,UAAWE,CAAY,CAAC,CACxD,MACE,OAAO,KAAK,yBAAyB,CAEzC,CAAC,EAED,SAAS,iBAAkB,IAAM,CAC/B,GAAG,iDAAkD,IAAM,CACzD,MAAMC,EAAST,EAAQ,cACrB,IAAI,eAAa,CACf,WAAY,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC,EACvC,KAAM,IAAI,WAAW,CAAC,CACxB,CAAC,CACH,EAEA,UAAO,0BAAuBS,CAAM,CAAC,EAAE,KAAK,EAAK,KAC5C,0BAAuBA,CAAM,EAShC,OAAO,KAAK,gBAAgB,EAR5B,OAAOA,EAAO,KAAK,EAAE,QACnB,OAAO,iBAAiB,CACtB,KAAM,wBACN,UAAW,OACX,QAAS,kCACX,CAAC,CACH,CAIJ,CAAC,EAED,GAAG,4DAA6D,IAAM,CACpE,MAAMC,EAAsB,IAAI,WAAWR,EAAmB,CAAC,EAAE,KAC/D,CACF,EACMO,EAAST,EAAQ,cACrB,IAAI,eAAa,CACf,KAAMU,EACN,WAAY,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CACzC,CAAC,CACH,EAEA,UAAO,0BAAuBD,CAAM,CAAC,EAAE,KAAK,EAAK,KAC5C,0BAAuBA,CAAM,EAWhC,OAAO,KAAK,gBAAgB,EAT1B,OAAOA,EAAO,MAAM,eAAkB,UACtCA,EAAO,MAAM,gBAAkB,MAC/B,YAAaA,EAAO,MAAM,eAE1B,OACGA,EAAO,MAAM,cAAsC,OACtD,EAAE,KAAK,6BAA6B,CAK1C,CAAC,CACH,CAAC,CACH,CAAC,CACH,CAAC",
6
- "names": ["import_device_management_kit", "import_bs58Encoder", "import_SignOffChainMessageCommand", "command", "MESSAGE", "SIGNATURE_LENGTH", "apdu", "expectedApdu", "signature", "parsed", "envelope", "expectedB58", "result", "incompleteSignature"]
4
+ "sourcesContent": ["import {\n ApduBuilder,\n ApduResponse,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CLA,\n INS,\n P1,\n SignOffChainMessageCommand,\n} from \"./SignOffChainMessageCommand\";\n\ndescribe(\"SignOffChainMessageCommand\", () => {\n const MESSAGE = new TextEncoder().encode(\"Solana SignOffChainMessage\");\n const SIGNATURE_LENGTH = 64;\n\n describe(\"getApdu()\", () => {\n it(\"builds APDU for a single (final) chunk (p2=INIT)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: false,\n more: false,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x00, // INIT only\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for first of many chunks (INIT|MORE)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: false,\n more: true,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x02, // INIT|MORE\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for middle chunks (EXTEND|MORE)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: true,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x03, // EXTEND|MORE\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for the final chunk after extends (EXTEND)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x01, // EXTEND only\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n });\n\n describe(\"parseResponse()\", () => {\n it(\"returns raw 64-byte signature on the last chunk\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const signature = new Uint8Array(SIGNATURE_LENGTH).fill(0x42);\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: signature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(signature);\n }\n });\n\n it(\"returns empty data for intermediate chunks (no signature yet)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: true,\n });\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: new Uint8Array(0), // device returns no data mid-stream\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(new Uint8Array(0));\n }\n });\n\n it(\"returns empty data if signature is present but not 64 bytes\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const shortSig = new Uint8Array(SIGNATURE_LENGTH - 1).fill(0x99);\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: shortSig,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(new Uint8Array(0));\n }\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["import_device_management_kit", "import_SignOffChainMessageCommand", "MESSAGE", "SIGNATURE_LENGTH", "apdu", "expected", "cmd", "signature", "parsed", "shortSig"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var u=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var b=(r,e)=>{for(var n in e)u(r,n,{get:e[n],enumerable:!0})},S=(r,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of h(e))!A.call(r,a)&&a!==n&&u(r,a,{get:()=>e[a],enumerable:!(i=y(e,a))||i.enumerable});return r};var D=r=>S(u({},"__esModule",{value:!0}),r);var B={};b(B,{MAX_MESSAGE_LENGTH:()=>c,SendSignMessageTask:()=>T});module.exports=D(B);var t=require("@ledgerhq/device-management-kit"),m=require("@ledgerhq/signer-utils"),g=require("../../app-binder/command/GetPubKeyCommand"),l=require("../../app-binder/command/SignOffChainMessageCommand"),p=require("../../app-binder/services/bs58Encoder");const c=65535;class T{constructor(e,n,i=p.DefaultBs58Encoder){this.api=e;this.args=n;this.bs58Encoder=i}async run(){const{sendingData:e,derivationPath:n}=this.args;if(e.length===0)return(0,t.CommandResultFactory)({error:new t.InvalidStatusWordError("Message cannot be empty")});if(e.length>c)return(0,t.CommandResultFactory)({error:new t.InvalidStatusWordError(`Message too long: ${e.length} bytes (max is 65535)`)});const i=m.DerivationPathUtils.splitPath(n),a=await this.api.sendCommand(new g.GetPubKeyCommand({derivationPath:n,checkOnDevice:!1}));if(!("data"in a))return(0,t.CommandResultFactory)({error:new t.InvalidStatusWordError("Error getting public key from device")});const d=this.bs58Encoder.decode(a.data),o=this._buildFullMessage(e,d),s=this._buildApduCommand(o,i);return s.length>t.APDU_MAX_PAYLOAD?(0,t.CommandResultFactory)({error:new t.InvalidStatusWordError("The APDU command exceeds the maximum allowable size (255 bytes)")}):this.api.sendCommand(new l.SignOffChainMessageCommand({message:s}))}_buildFullMessage(e,n){return new t.ByteArrayBuilder().add8BitUIntToData(255).addAsciiStringToData("solana offchain").add8BitUIntToData(0).addBufferToData(new Uint8Array(32)).add8BitUIntToData(0).add8BitUIntToData(1).addBufferToData(n).add8BitUIntToData(e.length&255).add8BitUIntToData(e.length>>8&255).addBufferToData(e).build()}_buildApduCommand(e,n){const d=n.length*4,o=new t.ByteArrayBuilder(e.length+1+1+d);return o.add8BitUIntToData(1),o.add8BitUIntToData(n.length),n.forEach(s=>{const f=new Uint8Array(4);new DataView(f.buffer).setUint32(0,s,!1),o.addBufferToData(f)}),o.addBufferToData(e),o.build()}}0&&(module.exports={MAX_MESSAGE_LENGTH,SendSignMessageTask});
1
+ "use strict";var u=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var w=(i,t)=>{for(var e in t)u(i,e,{get:t[e],enumerable:!0})},B=(i,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of v(t))!D.call(i,r)&&r!==e&&u(i,r,{get:()=>t[r],enumerable:!(n=R(t,r))||n.enumerable});return i};var M=i=>B(u({},"__esModule",{value:!0}),i);var G={};w(G,{MAX_MESSAGE_LENGTH:()=>g,MessageFormat:()=>S,SendSignMessageTask:()=>N});module.exports=M(G);var a=require("@ledgerhq/device-management-kit"),A=require("@ledgerhq/signer-utils"),m=require("../../app-binder/command/GetPubKeyCommand"),E=require("../../app-binder/command/SignOffChainMessageCommand"),_=require("../../app-binder/services/bs58Encoder"),C=require("./SendCommandInChunksTask");const F=15*1024,k=1280,y=40,I=8,P=F-y-I,p=k-y-I,f=65515,x=126,L=32,O=10;var S=(n=>(n[n.Ascii=0]="Ascii",n[n.Utf8=1]="Utf8",n[n.Utf8LongV0=2]="Utf8LongV0",n))(S||{});const g=f;class N{constructor(t,e,n=_.DefaultBs58Encoder){this.api=t;this.args=e;this.bs58Encoder=n}async run(){const{sendingData:t,derivationPath:e}=this.args;if(t.length===0)return(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError("Message cannot be empty")});if(t.length>g)return(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError(`Message too long: ${t.length} bytes (max is ${g})`)});const n=A.DerivationPathUtils.splitPath(e),r=await this.api.sendCommand(new m.GetPubKeyCommand({derivationPath:e,checkOnDevice:!1}));if(!("data"in r))return(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError("Error getting public key from device")});const o=this.bs58Encoder.decode(r.data),h=this._buildFullMessage(t,o,!1),b=this._buildApduCommand(h,n),d=await this._sendInChunks(b);if((0,a.isSuccessCommandResult)(d))try{const s=this._buildEnvelopeBase58(d.data,h);return(0,a.CommandResultFactory)({data:{signature:s}})}catch(s){return(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError(s instanceof Error?s.message:String(s))})}const U="error"in d?d.error:void 0;if(this._isInvalidOffchainHeaderError(U)){if(t.length>p)return d;const s=this._buildFullMessage(t,o,!0),T=this._buildApduCommand(s,n),c=await this._sendInChunks(T);if((0,a.isSuccessCommandResult)(c))try{const l=this._buildEnvelopeBase58(c.data,s);return(0,a.CommandResultFactory)({data:{signature:l}})}catch(l){return(0,a.CommandResultFactory)({error:new a.InvalidStatusWordError(l instanceof Error?l.message:String(l))})}return c}return d}_isUTF8(t){try{return new TextDecoder("utf-8",{fatal:!0}).decode(t),!0}catch{return!1}}_findMessageFormat(t,e){const n=e?p:P;if(t.length<=n){if(this._isPrintableASCII(t,e))return 0;if(this._isUTF8(t))return 1}else if(t.length<=f){if(this._isUTF8(t))return 2}else throw new a.InvalidStatusWordError(`Message too long: ${t.length} bytes (max is ${f})`);return 0}_isPrintableASCII(t,e){for(let n=0;n<t.length;n++){const r=t[n];if(!(!e&&r===O)&&(r<L||r>x))return!1}return!0}_buildFullMessage(t,e,n){const r=this._findMessageFormat(t,n),o=new a.ByteArrayBuilder;return o.add8BitUIntToData(255).addAsciiStringToData("solana offchain"),o.add8BitUIntToData(0),n||o.addBufferToData(new Uint8Array(32)),o.add8BitUIntToData(r),n||(o.add8BitUIntToData(1),o.addBufferToData(e)),o.add8BitUIntToData(t.length&255),o.add8BitUIntToData(t.length>>8&255),o.addBufferToData(t),o.build()}_isInvalidOffchainHeaderError(t){if(!t||typeof t!="object")return!1;const e=t,n=e._tag,r=e.errorCode;return typeof n=="string"&&typeof r=="string"&&r.toLowerCase()==="6a81"}_buildApduCommand(t,e){const n=new a.ByteArrayBuilder(2+e.length*4+t.length);return n.add8BitUIntToData(1),n.add8BitUIntToData(e.length),e.forEach(r=>n.add32BitUIntToData(r)),n.addBufferToData(t),n.build()}async _sendInChunks(t){const e=n=>new E.SignOffChainMessageCommand(n);return await new C.SendCommandInChunksTask(this.api,{data:t,commandFactory:e}).run()}_buildEnvelopeBase58(t,e){if(t.length!==64)throw new a.InvalidStatusWordError(`Invalid signature length: ${t.length} (expected 64)`);const n=Uint8Array.of(1),r=new Uint8Array(n.length+t.length+e.length);return r.set(n,0),r.set(t,n.length),r.set(e,n.length+t.length),this.bs58Encoder.encode(r)}}0&&(module.exports={MAX_MESSAGE_LENGTH,MessageFormat,SendSignMessageTask});
2
2
  //# sourceMappingURL=SendSignMessageTask.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/task/SendSignMessageTask.ts"],
4
- "sourcesContent": ["import {\n APDU_MAX_PAYLOAD,\n ByteArrayBuilder,\n type CommandResult,\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { DerivationPathUtils } from \"@ledgerhq/signer-utils\";\n\nimport { GetPubKeyCommand } from \"@internal/app-binder/command/GetPubKeyCommand\";\nimport {\n SignOffChainMessageCommand,\n type SignOffChainMessageCommandResponse,\n} from \"@internal/app-binder/command/SignOffChainMessageCommand\";\nimport { type SolanaAppErrorCodes } from \"@internal/app-binder/command/utils/SolanaApplicationErrors\";\nimport {\n type Bs58Encoder,\n DefaultBs58Encoder,\n} from \"@internal/app-binder/services/bs58Encoder\";\n\nexport type SendSignMessageTaskArgs = {\n sendingData: Uint8Array;\n derivationPath: string;\n};\n\nexport type SendSignMessageTaskRunFunctionReturn = Promise<\n CommandResult<SignOffChainMessageCommandResponse, SolanaAppErrorCodes>\n>;\n\nexport const MAX_MESSAGE_LENGTH = 0xffff;\n\nexport class SendSignMessageTask {\n constructor(\n private api: InternalApi,\n private args: SendSignMessageTaskArgs,\n private readonly bs58Encoder: Bs58Encoder = DefaultBs58Encoder,\n ) {}\n\n async run(): SendSignMessageTaskRunFunctionReturn {\n const { sendingData, derivationPath } = this.args;\n\n if (sendingData.length === 0) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"Message cannot be empty\"),\n });\n }\n\n if (sendingData.length > MAX_MESSAGE_LENGTH) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Message too long: ${sendingData.length} bytes (max is 65535)`,\n ),\n });\n }\n\n const pathIndexes = DerivationPathUtils.splitPath(derivationPath);\n\n const pubkeyResult = await this.api.sendCommand(\n new GetPubKeyCommand({ derivationPath, checkOnDevice: false }),\n );\n\n if (!(\"data\" in pubkeyResult)) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"Error getting public key from device\",\n ),\n });\n }\n\n const signerPubkey = this.bs58Encoder.decode(pubkeyResult.data);\n const fullMessage = this._buildFullMessage(sendingData, signerPubkey);\n const commandBuffer = this._buildApduCommand(fullMessage, pathIndexes);\n\n if (commandBuffer.length > APDU_MAX_PAYLOAD) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"The APDU command exceeds the maximum allowable size (255 bytes)\",\n ),\n });\n }\n\n return this.api.sendCommand(\n new SignOffChainMessageCommand({ message: commandBuffer }),\n );\n }\n\n /**\n * builds the serialised off-chain message header and body\n */\n private _buildFullMessage(\n sendingData: Uint8Array,\n signerPubkey: Uint8Array,\n ): Uint8Array {\n return (\n new ByteArrayBuilder()\n // 0xFF + prefix\n .add8BitUIntToData(0xff)\n .addAsciiStringToData(\"solana offchain\")\n // version = 0\n .add8BitUIntToData(0)\n // domain = 32 zeros\n .addBufferToData(new Uint8Array(32))\n // format = 0\n .add8BitUIntToData(0)\n // signer count = 1\n .add8BitUIntToData(1)\n // signer pubkey (32 bytes)\n .addBufferToData(signerPubkey)\n // message length (2 bytes, little endian)\n .add8BitUIntToData(sendingData.length & 0xff)\n .add8BitUIntToData((sendingData.length >> 8) & 0xff)\n // message body\n .addBufferToData(sendingData)\n .build()\n );\n }\n\n /**\n * builds the APDU command to send to the device\n */\n private _buildApduCommand(\n fullMessage: Uint8Array,\n paths: number[],\n ): Uint8Array {\n const numberOfSigners = 1;\n const derivationCount = 1;\n const pathBytes = paths.length * 4;\n const builder = new ByteArrayBuilder(\n fullMessage.length + numberOfSigners + derivationCount + pathBytes,\n );\n\n // number of signers\n builder.add8BitUIntToData(numberOfSigners);\n // number of BIP32 derivations\n builder.add8BitUIntToData(paths.length);\n // each derivation index\n paths.forEach((idx) => {\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, idx, false);\n builder.addBufferToData(buf);\n });\n // serialised off-chain message\n builder.addBufferToData(fullMessage);\n\n return builder.build();\n }\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,wBAAAE,EAAA,wBAAAC,IAAA,eAAAC,EAAAJ,GAAA,IAAAK,EAOO,2CACPC,EAAoC,kCAEpCC,EAAiC,yDACjCC,EAGO,mEAEPC,EAGO,qDAWA,MAAMP,EAAqB,MAE3B,MAAMC,CAAoB,CAC/B,YACUO,EACAC,EACSC,EAA2B,qBAC5C,CAHQ,SAAAF,EACA,UAAAC,EACS,iBAAAC,CAChB,CAEH,MAAM,KAA4C,CAChD,KAAM,CAAE,YAAAC,EAAa,eAAAC,CAAe,EAAI,KAAK,KAE7C,GAAID,EAAY,SAAW,EACzB,SAAO,wBAAqB,CAC1B,MAAO,IAAI,yBAAuB,yBAAyB,CAC7D,CAAC,EAGH,GAAIA,EAAY,OAASX,EACvB,SAAO,wBAAqB,CAC1B,MAAO,IAAI,yBACT,qBAAqBW,EAAY,MAAM,uBACzC,CACF,CAAC,EAGH,MAAME,EAAc,sBAAoB,UAAUD,CAAc,EAE1DE,EAAe,MAAM,KAAK,IAAI,YAClC,IAAI,mBAAiB,CAAE,eAAAF,EAAgB,cAAe,EAAM,CAAC,CAC/D,EAEA,GAAI,EAAE,SAAUE,GACd,SAAO,wBAAqB,CAC1B,MAAO,IAAI,yBACT,sCACF,CACF,CAAC,EAGH,MAAMC,EAAe,KAAK,YAAY,OAAOD,EAAa,IAAI,EACxDE,EAAc,KAAK,kBAAkBL,EAAaI,CAAY,EAC9DE,EAAgB,KAAK,kBAAkBD,EAAaH,CAAW,EAErE,OAAII,EAAc,OAAS,sBAClB,wBAAqB,CAC1B,MAAO,IAAI,yBACT,iEACF,CACF,CAAC,EAGI,KAAK,IAAI,YACd,IAAI,6BAA2B,CAAE,QAASA,CAAc,CAAC,CAC3D,CACF,CAKQ,kBACNN,EACAI,EACY,CACZ,OACE,IAAI,mBAAiB,EAElB,kBAAkB,GAAI,EACtB,qBAAqB,iBAAiB,EAEtC,kBAAkB,CAAC,EAEnB,gBAAgB,IAAI,WAAW,EAAE,CAAC,EAElC,kBAAkB,CAAC,EAEnB,kBAAkB,CAAC,EAEnB,gBAAgBA,CAAY,EAE5B,kBAAkBJ,EAAY,OAAS,GAAI,EAC3C,kBAAmBA,EAAY,QAAU,EAAK,GAAI,EAElD,gBAAgBA,CAAW,EAC3B,MAAM,CAEb,CAKQ,kBACNK,EACAE,EACY,CAGZ,MAAMC,EAAYD,EAAM,OAAS,EAC3BE,EAAU,IAAI,mBAClBJ,EAAY,OAAS,EAAkB,EAAkBG,CAC3D,EAGA,OAAAC,EAAQ,kBAAkB,CAAe,EAEzCA,EAAQ,kBAAkBF,EAAM,MAAM,EAEtCA,EAAM,QAASG,GAAQ,CACrB,MAAMC,EAAM,IAAI,WAAW,CAAC,EAC5B,IAAI,SAASA,EAAI,MAAM,EAAE,UAAU,EAAGD,EAAK,EAAK,EAChDD,EAAQ,gBAAgBE,CAAG,CAC7B,CAAC,EAEDF,EAAQ,gBAAgBJ,CAAW,EAE5BI,EAAQ,MAAM,CACvB,CACF",
6
- "names": ["SendSignMessageTask_exports", "__export", "MAX_MESSAGE_LENGTH", "SendSignMessageTask", "__toCommonJS", "import_device_management_kit", "import_signer_utils", "import_GetPubKeyCommand", "import_SignOffChainMessageCommand", "import_bs58Encoder", "api", "args", "bs58Encoder", "sendingData", "derivationPath", "pathIndexes", "pubkeyResult", "signerPubkey", "fullMessage", "commandBuffer", "paths", "pathBytes", "builder", "idx", "buf"]
4
+ "sourcesContent": ["import {\n ByteArrayBuilder,\n type CommandResult,\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\nimport { DerivationPathUtils } from \"@ledgerhq/signer-utils\";\n\nimport { GetPubKeyCommand } from \"@internal/app-binder/command/GetPubKeyCommand\";\nimport {\n SignOffChainMessageCommand,\n type SignOffChainRawResponse,\n} from \"@internal/app-binder/command/SignOffChainMessageCommand\";\nimport { type SolanaAppErrorCodes } from \"@internal/app-binder/command/utils/SolanaApplicationErrors\";\nimport {\n type Bs58Encoder,\n DefaultBs58Encoder,\n} from \"@internal/app-binder/services/bs58Encoder\";\n\nimport {\n type CommandFactory,\n SendCommandInChunksTask,\n} from \"./SendCommandInChunksTask\";\n\nconst DEVICE_V0_PAYLOAD_CEILING = 15 * 1024; // 15360\nconst DEVICE_LEGACY_PAYLOAD_CEILING = 1280;\n\n// bytes reserved by app/header and transport\nconst RESERVED_HEADER_BYTES = 40;\nconst RESERVED_TRANSPORT_BYTES = 8;\n\n// derived usable body sizes\nconst OFFCHAINMSG_MAX_LEN =\n DEVICE_V0_PAYLOAD_CEILING - RESERVED_HEADER_BYTES - RESERVED_TRANSPORT_BYTES; // 15312\n\nconst LEGACY_OFFCHAINMSG_MAX_LEN =\n DEVICE_LEGACY_PAYLOAD_CEILING -\n RESERVED_HEADER_BYTES -\n RESERVED_TRANSPORT_BYTES; // 1232\n\n// device cap for v0 long UTF-8\nconst OFFCHAINMSG_MAX_V0_LEN = 65515;\n\nconst MAX_PRINTABLE_ASCII = 0x7e;\nconst MIN_PRINTABLE_ASCII = 0x20;\nconst LINE_FEED_ASCII = 0x0a;\n\nexport enum MessageFormat {\n Ascii = 0,\n Utf8 = 1,\n Utf8LongV0 = 2,\n}\n\nexport const MAX_MESSAGE_LENGTH = OFFCHAINMSG_MAX_V0_LEN;\n\nexport type SendSignMessageTaskArgs = {\n sendingData: Uint8Array;\n derivationPath: string;\n};\n\nexport type SendSignMessageTaskRunFunctionReturn = Promise<\n CommandResult<{ signature: string }, SolanaAppErrorCodes>\n>;\n\nexport class SendSignMessageTask {\n constructor(\n private api: InternalApi,\n private args: SendSignMessageTaskArgs,\n private readonly bs58Encoder: Bs58Encoder = DefaultBs58Encoder,\n ) {}\n\n async run(): SendSignMessageTaskRunFunctionReturn {\n const { sendingData, derivationPath } = this.args;\n\n if (sendingData.length === 0) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"Message cannot be empty\"),\n });\n }\n if (sendingData.length > MAX_MESSAGE_LENGTH) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Message too long: ${sendingData.length} bytes (max is ${MAX_MESSAGE_LENGTH})`,\n ),\n });\n }\n\n const paths = DerivationPathUtils.splitPath(derivationPath);\n\n const pubkeyResult = await this.api.sendCommand(\n new GetPubKeyCommand({ derivationPath, checkOnDevice: false }),\n );\n if (!(\"data\" in pubkeyResult)) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"Error getting public key from device\",\n ),\n });\n }\n const signerPubkey = this.bs58Encoder.decode(pubkeyResult.data);\n\n // try v0 first\n const v0OCM = this._buildFullMessage(sendingData, signerPubkey, false);\n const v0Payload = this._buildApduCommand(v0OCM, paths);\n const v0Res = await this._sendInChunks(v0Payload);\n\n if (isSuccessCommandResult(v0Res)) {\n try {\n const sigB58 = this._buildEnvelopeBase58(v0Res.data, v0OCM);\n return CommandResultFactory({ data: { signature: sigB58 } });\n } catch (e) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n e instanceof Error ? e.message : String(e),\n ),\n });\n }\n }\n\n // if the app says header invalid, try legacy\n const v0Error: unknown =\n \"error\" in v0Res ? (v0Res as { error: unknown }).error : undefined;\n\n if (this._isInvalidOffchainHeaderError(v0Error)) {\n if (sendingData.length > LEGACY_OFFCHAINMSG_MAX_LEN) {\n return v0Res;\n }\n\n const legacyOCM = this._buildFullMessage(sendingData, signerPubkey, true);\n const legacyPayload = this._buildApduCommand(legacyOCM, paths);\n const legacyRes = await this._sendInChunks(legacyPayload);\n\n if (isSuccessCommandResult(legacyRes)) {\n try {\n const sigB58 = this._buildEnvelopeBase58(legacyRes.data, legacyOCM);\n return CommandResultFactory({ data: { signature: sigB58 } });\n } catch (e) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n e instanceof Error ? e.message : String(e),\n ),\n });\n }\n }\n return legacyRes;\n }\n\n return v0Res;\n }\n\n private _isUTF8(buf: Uint8Array): boolean {\n try {\n new TextDecoder(\"utf-8\", { fatal: true }).decode(buf);\n return true;\n } catch {\n return false;\n }\n }\n\n private _findMessageFormat(\n message: Uint8Array,\n isLegacy: boolean,\n ): MessageFormat {\n const maxLedgerLen = isLegacy\n ? LEGACY_OFFCHAINMSG_MAX_LEN\n : OFFCHAINMSG_MAX_LEN;\n\n if (message.length <= maxLedgerLen) {\n if (this._isPrintableASCII(message, isLegacy)) return MessageFormat.Ascii;\n if (this._isUTF8(message)) return MessageFormat.Utf8;\n } else if (message.length <= OFFCHAINMSG_MAX_V0_LEN) {\n if (this._isUTF8(message)) return MessageFormat.Utf8LongV0;\n } else {\n // unreachable if run() guards length\n throw new InvalidStatusWordError(\n `Message too long: ${message.length} bytes (max is ${OFFCHAINMSG_MAX_V0_LEN})`,\n );\n }\n // default to ASCII like legacy\n return MessageFormat.Ascii;\n }\n\n private _isPrintableASCII(buf: Uint8Array, isLegacy: boolean): boolean {\n for (let i = 0; i < buf.length; i++) {\n const ch: number = buf[i]!;\n if (!isLegacy && ch === LINE_FEED_ASCII) continue; // newline allowed only for non-legacy\n if (ch < MIN_PRINTABLE_ASCII || ch > MAX_PRINTABLE_ASCII) return false;\n }\n return true;\n }\n\n /**\n * build serialised off-chain message header + body\n * when `isLegacy` is true, build the short legacy header (no app-domain or signers).\n */\n private _buildFullMessage(\n messageBody: Uint8Array,\n signerPubkey: Uint8Array,\n isLegacy: boolean,\n ): Uint8Array {\n const format: MessageFormat = this._findMessageFormat(\n messageBody,\n isLegacy,\n );\n\n const builder = new ByteArrayBuilder();\n\n // signing domain: 0xFF + \"solana offchain\" (16 bytes)\n builder.add8BitUIntToData(0xff).addAsciiStringToData(\"solana offchain\");\n\n // header version = 0\n builder.add8BitUIntToData(0);\n\n if (!isLegacy) {\n // application domain = 32 zeros\n builder.addBufferToData(new Uint8Array(32));\n }\n\n // message format\n builder.add8BitUIntToData(format);\n\n if (!isLegacy) {\n // signer count = 1\n builder.add8BitUIntToData(1);\n // signer pubkey (32 bytes)\n builder.addBufferToData(signerPubkey);\n }\n\n // message length (LE, 2 bytes)\n builder.add8BitUIntToData(messageBody.length & 0xff);\n builder.add8BitUIntToData((messageBody.length >> 8) & 0xff);\n\n // message body\n builder.addBufferToData(messageBody);\n\n return builder.build();\n }\n\n // guard for the device\u2019s 0x6A81 \u201CInvalid off-chain message header\u201D error\n private _isInvalidOffchainHeaderError(\n e: unknown,\n ): e is { _tag: string; errorCode: string } {\n if (!e || typeof e !== \"object\") return false;\n const obj = e as Record<string, unknown>;\n const tag = obj[\"_tag\"];\n const code = obj[\"errorCode\"];\n return (\n typeof tag === \"string\" &&\n typeof code === \"string\" &&\n code.toLowerCase() === \"6a81\"\n );\n }\n\n /**\n * build APDU payload:\n * [signerCount=1][derivationsCount][each 4-byte index][OCM message]\n */\n private _buildApduCommand(\n fullMessage: Uint8Array,\n paths: number[],\n ): Uint8Array {\n const builder = new ByteArrayBuilder(\n 1 + 1 + paths.length * 4 + fullMessage.length,\n );\n\n builder.add8BitUIntToData(1); // number of signers\n builder.add8BitUIntToData(paths.length); // number of derivations\n paths.forEach((idx) => builder.add32BitUIntToData(idx)); // big-endian\n builder.addBufferToData(fullMessage);\n\n return builder.build(); // larger than 255 is ok, SendCommandInChunksTask will chunk it\n }\n\n // send APDU payload using chunk task, return raw 64-byte signature (last chunk)\n private async _sendInChunks(\n apduPayload: Uint8Array,\n ): Promise<CommandResult<SignOffChainRawResponse, SolanaAppErrorCodes>> {\n const commandFactory: CommandFactory<SignOffChainRawResponse> = (\n chunkArgs,\n ) => new SignOffChainMessageCommand(chunkArgs);\n\n return await new SendCommandInChunksTask<SignOffChainRawResponse>(\n this.api,\n {\n data: apduPayload,\n commandFactory,\n },\n ).run();\n }\n\n // build base58 OCM envelope: [signatureCount=1][signature(64)][serialized OCM]\n private _buildEnvelopeBase58(\n rawSignature: Uint8Array,\n serializedOCM: Uint8Array,\n ): string {\n if (rawSignature.length !== 64) {\n throw new InvalidStatusWordError(\n `Invalid signature length: ${rawSignature.length} (expected 64)`,\n );\n }\n const sigCount = Uint8Array.of(1);\n const envelope = new Uint8Array(\n sigCount.length + rawSignature.length + serializedOCM.length,\n );\n envelope.set(sigCount, 0);\n envelope.set(rawSignature, sigCount.length);\n envelope.set(serializedOCM, sigCount.length + rawSignature.length);\n return this.bs58Encoder.encode(envelope);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["SendSignMessageTask_exports", "__export", "MAX_MESSAGE_LENGTH", "MessageFormat", "SendSignMessageTask", "__toCommonJS", "import_device_management_kit", "import_signer_utils", "import_GetPubKeyCommand", "import_SignOffChainMessageCommand", "import_bs58Encoder", "import_SendCommandInChunksTask", "DEVICE_V0_PAYLOAD_CEILING", "DEVICE_LEGACY_PAYLOAD_CEILING", "RESERVED_HEADER_BYTES", "RESERVED_TRANSPORT_BYTES", "OFFCHAINMSG_MAX_LEN", "LEGACY_OFFCHAINMSG_MAX_LEN", "OFFCHAINMSG_MAX_V0_LEN", "MAX_PRINTABLE_ASCII", "MIN_PRINTABLE_ASCII", "LINE_FEED_ASCII", "api", "args", "bs58Encoder", "sendingData", "derivationPath", "paths", "pubkeyResult", "signerPubkey", "v0OCM", "v0Payload", "v0Res", "sigB58", "e", "v0Error", "legacyOCM", "legacyPayload", "legacyRes", "buf", "message", "isLegacy", "maxLedgerLen", "i", "ch", "messageBody", "format", "builder", "obj", "tag", "code", "fullMessage", "idx", "apduPayload", "commandFactory", "chunkArgs", "rawSignature", "serializedOCM", "sigCount", "envelope"]
7
7
  }
@@ -1,2 +1,4 @@
1
- "use strict";var n=require("@ledgerhq/device-management-kit"),m=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),u=require("../../app-binder/services/bs58Encoder"),s=require("../../app-binder/task/SendSignMessageTask");const r="44'/501'/0'/0'",g=new Uint8Array(32).fill(0),l=u.DefaultBs58Encoder.encode(g),c=new Uint8Array([240,202,204,26]);describe("SendSignMessageTask",()=>{const e=(0,m.makeDeviceActionInternalApiMock)();beforeEach(()=>{vi.resetAllMocks()}),describe("run()",()=>{it("should error on empty message before any device call",async()=>{const a={derivationPath:r,sendingData:new Uint8Array([])},t=await new s.SendSignMessageTask(e,a).run();expect(e.sendCommand).toHaveBeenCalledTimes(0),expect(t.error).toEqual(new n.InvalidStatusWordError("Message cannot be empty"))}),it("should return error if GET_PUBKEY fails",async()=>{e.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({error:new n.InvalidStatusWordError("pubkey error")}));const a={derivationPath:r,sendingData:c},t=await new s.SendSignMessageTask(e,a).run();expect(e.sendCommand).toHaveBeenCalledTimes(1),expect(t.error).toEqual(new n.InvalidStatusWordError("Error getting public key from device"))}),it("should return error if SignOffChainMessageCommand fails",async()=>{e.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:l})).mockResolvedValueOnce((0,n.CommandResultFactory)({error:new n.InvalidStatusWordError("no signature returned")}));const a={derivationPath:r,sendingData:c},t=await new s.SendSignMessageTask(e,a).run();expect(e.sendCommand).toHaveBeenCalledTimes(2),expect(t.error).toEqual(new n.InvalidStatusWordError("no signature returned"))}),it("should return success when signing succeeds",async()=>{const a=new Uint8Array([240,202,204,26]);e.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:l})).mockResolvedValueOnce((0,n.CommandResultFactory)({data:a}));const t={derivationPath:r,sendingData:c},o=await new s.SendSignMessageTask(e,t).run();expect(e.sendCommand).toHaveBeenCalledTimes(2),expect(o.data).toEqual(a)}),it("should reject invalid derivation path",async()=>{const a={derivationPath:"not/a/path",sendingData:c};await expect(new s.SendSignMessageTask(e,a).run()).rejects.toThrow()}),it("should correctly build APDU command lengths",()=>{const a=new s.SendSignMessageTask(e,{derivationPath:r,sendingData:c}),t=a._buildFullMessage(c,g),o=[-2147483604,-2147483147,-2147483648,0],i=a._buildApduCommand(t,o),d=2+o.length*4+t.length;expect(i.length).toBe(d)}),it("should handle maximum allowed message length",async()=>{const i=new Uint8Array(152).fill(1),d=new Uint8Array([240,202,204,26]);e.sendCommand.mockResolvedValueOnce((0,n.CommandResultFactory)({data:l})).mockResolvedValueOnce((0,n.CommandResultFactory)({data:d}));const x=await new s.SendSignMessageTask(e,{derivationPath:r,sendingData:i}).run();expect(e.sendCommand).toHaveBeenCalledTimes(2),expect(x.data).toEqual(d)}),it("should error on message exceeding 16-bit length (65535)",async()=>{const a=new Uint8Array(s.MAX_MESSAGE_LENGTH+1).fill(170),t={derivationPath:r,sendingData:a},o=await new s.SendSignMessageTask(e,t).run();expect(e.sendCommand).toHaveBeenCalledTimes(0),expect(o.error).toEqual(new n.InvalidStatusWordError(`Message too long: ${a.length} bytes (max is 65535)`))})})});
1
+ "use strict";var s=require("@ledgerhq/device-management-kit"),y=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),g=require("../../app-binder/services/bs58Encoder"),t=require("../../app-binder/task/SendSignMessageTask");const r="44'/501'/0'/0'",c=new Uint8Array(32).fill(17),m=g.DefaultBs58Encoder.encode(c);function w(){return{_tag:"SolanaAppCommandError",errorCode:"6a81",message:"Invalid off-chain message header"}}describe("SendSignMessageTask",()=>{const n=(0,y.makeDeviceActionInternalApiMock)();beforeEach(()=>{vi.resetAllMocks()}),describe("run()",()=>{it("errors on empty message before any device call",async()=>{const e=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:new Uint8Array([])}).run();expect(n.sendCommand).toHaveBeenCalledTimes(0),expect(e.error).toEqual(new s.InvalidStatusWordError("Message cannot be empty"))}),it("errors when GET_PUBKEY fails",async()=>{n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({error:new s.InvalidStatusWordError("pubkey error")}));const e=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:new Uint8Array([1,2,3])}).run();expect(n.sendCommand).toHaveBeenCalledTimes(1),expect(e.error).toEqual(new s.InvalidStatusWordError("Error getting public key from device"))}),it("surfaces command error when signing fails",async()=>{n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({error:new s.InvalidStatusWordError("no signature returned")}));const e=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:new Uint8Array([170,187])}).run();expect(n.sendCommand).toHaveBeenCalledTimes(2),expect(e.error).toEqual(new s.InvalidStatusWordError("no signature returned"))}),it("returns base58 envelope when signing succeeds",async()=>{const e=new Uint8Array([240,202,204,26]),a=new Uint8Array(64).fill(51);n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({data:a}));const o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}),i=o._buildFullMessage(e,c,!1),d=await o.run();expect(n.sendCommand).toHaveBeenCalledTimes(2),expect("data"in d).toBe(!0);const u=d.data.signature,l=new Uint8Array(1+a.length+i.length);l.set(Uint8Array.of(1),0),l.set(a,1),l.set(i,1+a.length),expect(g.DefaultBs58Encoder.decode(u)).toEqual(l)}),it("rejects invalid derivation path",async()=>{const e={derivationPath:"not/a/path",sendingData:new Uint8Array([1])};await expect(new t.SendSignMessageTask(n,e).run()).rejects.toThrow()}),it("builds APDU command with correct structure (prefix + tail)",()=>{const e=new Uint8Array([1,2,3]),a=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}),o=a._buildFullMessage(e,c,!1),i=[-2147483604,-2147483147,-2147483648,0],d=a._buildApduCommand(o,i);expect(d[0]).toBe(1),expect(d[1]).toBe(i.length),expect(d.slice(d.length-o.length)).toEqual(o)}),it("handles large messages via chunking (no exact call count assertion)",async()=>{const e=new Uint8Array(4e3).fill(1),a=new Uint8Array(64).fill(68);n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValue((0,s.CommandResultFactory)({data:a}));const o=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}).run();expect("data"in o).toBe(!0)}),it("errors on message exceeding v0 max (65515)",async()=>{const e=new Uint8Array(t.MAX_MESSAGE_LENGTH+1).fill(170),a=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}).run();expect(n.sendCommand).toHaveBeenCalledTimes(0),expect(a.error).toEqual(new s.InvalidStatusWordError(`Message too long: ${e.length} bytes (max is ${t.MAX_MESSAGE_LENGTH})`))}),it("falls back to legacy when v0 returns 6a81 (header error)",async()=>{const e=new Uint8Array([97,98,99]),a=new Uint8Array(64).fill(85);n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({error:w()})).mockResolvedValueOnce((0,s.CommandResultFactory)({data:a}));const o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}),i=o._buildFullMessage(e,c,!0),d=await o.run();expect(n.sendCommand).toHaveBeenCalledTimes(3);const u=d.data.signature,l=new Uint8Array(1+a.length+i.length);l.set(Uint8Array.of(1),0),l.set(a,1),l.set(i,1+a.length),expect(g.DefaultBs58Encoder.decode(u)).toEqual(l)}),it("does NOT fallback on non-6a81 errors",async()=>{n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({error:new s.InvalidStatusWordError("oups")}));const e=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:new Uint8Array([1,2])}).run();expect(n.sendCommand).toHaveBeenCalledTimes(2),expect(e.error).toBeInstanceOf(s.InvalidStatusWordError)}),it("propagates 6a81 if body is too large for legacy",async()=>{const e=new Uint8Array(2e3).fill(49);n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({error:w()}));const a=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}).run();expect(n.sendCommand).toHaveBeenCalledTimes(2),expect(a.error).toEqual(w())})}),describe("message format detection (indirect via header byte)",()=>{it("sets format=0 for ASCII \u2264 maxLedgerLen (v0 header)",()=>{const e=new TextEncoder().encode(`hello
2
+ world`),o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e})._buildFullMessage(e,c,!1);expect(o[49]).toBe(t.MessageFormat.Ascii)}),it("sets format=1 for short UTF-8 non-ASCII (v0 header)",()=>{const e=new TextEncoder().encode("h\xE9ll\xF8"),o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e})._buildFullMessage(e,c,!1);expect(o[49]).toBe(t.MessageFormat.Utf8)}),it("sets format=2 for long UTF-8 (v0 header)",()=>{const e=new TextEncoder().encode("x".repeat(15313)),o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e})._buildFullMessage(e,c,!1);expect(o[49]).toBe(t.MessageFormat.Utf8LongV0)}),it("legacy header forbids newline in ASCII (so format becomes UTF-8=1)",()=>{const e=new TextEncoder().encode(`hello
3
+ world`),o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e})._buildFullMessage(e,c,!0);expect(o[17]).toBe(t.MessageFormat.Utf8)}),it("legacy header sets format=0 for plain ASCII (no newline)",()=>{const e=new TextEncoder().encode("HELLO_123"),o=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e})._buildFullMessage(e,c,!0);expect(o[17]).toBe(t.MessageFormat.Ascii)}),it("message length is little-endian in both headers",()=>{const e=new Uint8Array([1,2,3]),a=new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}),o=a._buildFullMessage(e,c,!1);expect(o[83]).toBe(3),expect(o[84]).toBe(0);const i=a._buildFullMessage(e,c,!0);expect(i[18]).toBe(3),expect(i[19]).toBe(0)})}),it("returns error when device returns non-64-byte signature on final chunk",async()=>{const e=new Uint8Array([1,2,3]);n.sendCommand.mockResolvedValueOnce((0,s.CommandResultFactory)({data:m})).mockResolvedValueOnce((0,s.CommandResultFactory)({data:new Uint8Array(0)}));const a=await new t.SendSignMessageTask(n,{derivationPath:r,sendingData:e}).run();expect("error"in a).toBe(!0);const o=a.error;expect(o).toBeInstanceOf(s.InvalidStatusWordError)})});
2
4
  //# sourceMappingURL=SendSignMessageTask.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/task/SendSignMessageTask.test.ts"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { DefaultBs58Encoder } from \"@internal/app-binder/services/bs58Encoder\";\nimport {\n MAX_MESSAGE_LENGTH,\n SendSignMessageTask,\n} from \"@internal/app-binder/task/SendSignMessageTask\";\n\nconst DERIVATION_PATH = \"44'/501'/0'/0'\";\nconst PUBKEY = new Uint8Array(32).fill(0x00);\nconst PUBKEY_BASE58 = DefaultBs58Encoder.encode(PUBKEY);\nconst MESSAGE = new Uint8Array([0xf0, 0xca, 0xcc, 0x1a]);\n\ndescribe(\"SendSignMessageTask\", () => {\n const apiMock = makeDeviceActionInternalApiMock();\n\n beforeEach(() => {\n vi.resetAllMocks();\n });\n\n describe(\"run()\", () => {\n it(\"should error on empty message before any device call\", async () => {\n // given\n const args = {\n derivationPath: DERIVATION_PATH,\n sendingData: new Uint8Array([]),\n };\n\n // when\n const result = await new SendSignMessageTask(apiMock, args).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(0);\n expect((result as any).error).toEqual(\n new InvalidStatusWordError(\"Message cannot be empty\"),\n );\n });\n\n it(\"should return error if GET_PUBKEY fails\", async () => {\n // given\n apiMock.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"pubkey error\"),\n }),\n );\n const args = {\n derivationPath: DERIVATION_PATH,\n sendingData: MESSAGE,\n };\n\n // when\n const result = await new SendSignMessageTask(apiMock, args).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(1);\n expect((result as any).error).toEqual(\n new InvalidStatusWordError(\"Error getting public key from device\"),\n );\n });\n\n it(\"should return error if SignOffChainMessageCommand fails\", async () => {\n // given\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 }))\n .mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"no signature returned\"),\n }),\n );\n const args = {\n derivationPath: DERIVATION_PATH,\n sendingData: MESSAGE,\n };\n\n // when\n const result = await new SendSignMessageTask(apiMock, args).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((result as any).error).toEqual(\n new InvalidStatusWordError(\"no signature returned\"),\n );\n });\n\n it(\"should return success when signing succeeds\", async () => {\n // given\n const mockSig = new Uint8Array([0xf0, 0xca, 0xcc, 0x1a]);\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 }))\n .mockResolvedValueOnce(CommandResultFactory({ data: mockSig }));\n const args = {\n derivationPath: DERIVATION_PATH,\n sendingData: MESSAGE,\n };\n\n // when\n const result = await new SendSignMessageTask(apiMock, args).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((result as any).data).toEqual(mockSig);\n });\n\n it(\"should reject invalid derivation path\", async () => {\n const args = {\n derivationPath: \"not/a/path\",\n sendingData: MESSAGE,\n };\n await expect(\n new SendSignMessageTask(apiMock, args).run(),\n ).rejects.toThrow();\n });\n\n it(\"should correctly build APDU command lengths\", () => {\n // given\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: MESSAGE,\n });\n\n // when\n const fullMsg = task._buildFullMessage(MESSAGE, PUBKEY);\n const paths = [44 | 0x80000000, 501 | 0x80000000, 0 | 0x80000000, 0];\n const apdu = task._buildApduCommand(fullMsg, paths);\n const expectedLen = 1 + 1 + paths.length * 4 + fullMsg.length;\n\n // then\n expect(apdu.length).toBe(expectedLen);\n });\n\n it(\"should handle maximum allowed message length\", async () => {\n // given\n const headerAPDU = 1 + 1 + 4 * 4;\n const fullMsgHeader = 1 + 15 + 1 + 32 + 1 + 1 + 32 + 2;\n const maxBody = 255 - headerAPDU - fullMsgHeader;\n const bigMsg = new Uint8Array(maxBody).fill(0x01);\n const mockSig = new Uint8Array([0xf0, 0xca, 0xcc, 0x1a]);\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 }))\n .mockResolvedValueOnce(CommandResultFactory({ data: mockSig }));\n\n // when\n const result = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: bigMsg,\n }).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((result as any).data).toEqual(mockSig);\n });\n\n it(\"should error on message exceeding 16-bit length (65535)\", async () => {\n // given\n const tooBig = new Uint8Array(MAX_MESSAGE_LENGTH + 1).fill(0xaa);\n const args = {\n derivationPath: DERIVATION_PATH,\n sendingData: tooBig,\n };\n\n // when\n const result = await new SendSignMessageTask(apiMock, args).run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(0);\n expect((result as any).error).toEqual(\n new InvalidStatusWordError(\n `Message too long: ${tooBig.length} bytes (max is 65535)`,\n ),\n );\n });\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_device_management_kit", "import_makeInternalApi", "import_bs58Encoder", "import_SendSignMessageTask", "DERIVATION_PATH", "PUBKEY", "PUBKEY_BASE58", "MESSAGE", "apiMock", "args", "result", "mockSig", "task", "fullMsg", "paths", "apdu", "expectedLen", "bigMsg", "tooBig"]
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { DefaultBs58Encoder } from \"@internal/app-binder/services/bs58Encoder\";\nimport {\n MAX_MESSAGE_LENGTH,\n MessageFormat,\n SendSignMessageTask,\n} from \"@internal/app-binder/task/SendSignMessageTask\";\n\nconst DERIVATION_PATH = \"44'/501'/0'/0'\";\nconst PUBKEY = new Uint8Array(32).fill(0x11);\nconst PUBKEY_BASE58 = DefaultBs58Encoder.encode(PUBKEY);\n\nfunction solanaHeaderErr() {\n return {\n _tag: \"SolanaAppCommandError\",\n errorCode: \"6a81\",\n message: \"Invalid off-chain message header\",\n } as const;\n}\n\ndescribe(\"SendSignMessageTask\", () => {\n const apiMock = makeDeviceActionInternalApiMock();\n\n beforeEach(() => {\n vi.resetAllMocks();\n });\n\n describe(\"run()\", () => {\n it(\"errors on empty message before any device call\", async () => {\n const result = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: new Uint8Array([]),\n }).run();\n\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(0);\n expect((result as any).error).toEqual(\n new InvalidStatusWordError(\"Message cannot be empty\"),\n );\n });\n\n it(\"errors when GET_PUBKEY fails\", async () => {\n apiMock.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"pubkey error\"),\n }),\n );\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: new Uint8Array([1, 2, 3]),\n }).run();\n\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(1);\n expect((res as any).error).toEqual(\n new InvalidStatusWordError(\"Error getting public key from device\"),\n );\n });\n\n it(\"surfaces command error when signing fails\", async () => {\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 })) // pubkey\n .mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"no signature returned\"),\n }),\n );\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: new Uint8Array([0xaa, 0xbb]),\n }).run();\n\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((res as any).error).toEqual(\n new InvalidStatusWordError(\"no signature returned\"),\n );\n });\n\n it(\"returns base58 envelope when signing succeeds\", async () => {\n // given\n const msg = new Uint8Array([0xf0, 0xca, 0xcc, 0x1a]);\n const rawSig = new Uint8Array(64).fill(0x33); // mock 64-byte signature\n\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 })) // pubkey\n .mockResolvedValueOnce(CommandResultFactory({ data: rawSig })); // v0 last chunk\n\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: msg,\n });\n const v0OCM: Uint8Array = task._buildFullMessage(msg, PUBKEY, false);\n\n // when\n const res = await task.run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect(\"data\" in res).toBe(true);\n const b58 = (res as any).data.signature as string;\n\n // expected envelope = [1][rawSig][v0OCM]\n const expected = new Uint8Array(1 + rawSig.length + v0OCM.length);\n expected.set(Uint8Array.of(1), 0);\n expected.set(rawSig, 1);\n expected.set(v0OCM, 1 + rawSig.length);\n\n expect(DefaultBs58Encoder.decode(b58)).toEqual(expected);\n });\n\n it(\"rejects invalid derivation path\", async () => {\n const args = {\n derivationPath: \"not/a/path\",\n sendingData: new Uint8Array([1]),\n };\n await expect(\n new SendSignMessageTask(apiMock, args).run(),\n ).rejects.toThrow();\n });\n\n it(\"builds APDU command with correct structure (prefix + tail)\", () => {\n const msg = new Uint8Array([1, 2, 3]);\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: msg,\n });\n\n const fullMsg = task._buildFullMessage(msg, PUBKEY, false);\n const paths = [44 | 0x80000000, 501 | 0x80000000, 0 | 0x80000000, 0];\n const apdu = task._buildApduCommand(fullMsg, paths);\n\n // first byte: number of signers\n expect(apdu[0]).toBe(1);\n // second byte: number of derivation indices\n expect(apdu[1]).toBe(paths.length);\n // tail equals the serialized OCM\n expect(apdu.slice(apdu.length - fullMsg.length)).toEqual(fullMsg);\n });\n\n it(\"handles large messages via chunking (no exact call count assertion)\", async () => {\n const bigMsg = new Uint8Array(4000).fill(0x01);\n const rawSig = new Uint8Array(64).fill(0x44);\n\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 })) // pubkey\n .mockResolvedValue(CommandResultFactory({ data: rawSig })); // all subsequent chunks\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: bigMsg,\n }).run();\n\n expect(\"data\" in res).toBe(true);\n });\n\n it(\"errors on message exceeding v0 max (65515)\", async () => {\n const tooBig = new Uint8Array(MAX_MESSAGE_LENGTH + 1).fill(0xaa);\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: tooBig,\n }).run();\n\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(0);\n expect((res as any).error).toEqual(\n new InvalidStatusWordError(\n `Message too long: ${tooBig.length} bytes (max is ${MAX_MESSAGE_LENGTH})`,\n ),\n );\n });\n\n it(\"falls back to legacy when v0 returns 6a81 (header error)\", async () => {\n // given\n const msg = new Uint8Array([0x61, 0x62, 0x63]); // \"abc\"\n const rawSig = new Uint8Array(64).fill(0x55);\n\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 })) // pubkey\n .mockResolvedValueOnce(\n CommandResultFactory({ error: solanaHeaderErr() as any }),\n ) // v0 -> 6a81\n .mockResolvedValueOnce(CommandResultFactory({ data: rawSig })); // legacy -> OK\n\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: msg,\n });\n\n // build expected LEGACY OCM to verify envelope\n const legacyOCM: Uint8Array = task._buildFullMessage(msg, PUBKEY, true);\n\n // when\n const res = await task.run();\n\n // then\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(3); // pubkey + v0 + legacy\n const b58 = (res as any).data.signature as string;\n\n const expected = new Uint8Array(1 + rawSig.length + legacyOCM.length);\n expected.set(Uint8Array.of(1), 0);\n expected.set(rawSig, 1);\n expected.set(legacyOCM, 1 + rawSig.length);\n\n expect(DefaultBs58Encoder.decode(b58)).toEqual(expected);\n });\n\n it(\"does NOT fallback on non-6a81 errors\", async () => {\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 }))\n .mockResolvedValueOnce(\n CommandResultFactory({ error: new InvalidStatusWordError(\"oups\") }),\n );\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: new Uint8Array([1, 2]),\n }).run();\n\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((res as any).error).toBeInstanceOf(InvalidStatusWordError);\n });\n\n it(\"propagates 6a81 if body is too large for legacy\", async () => {\n const msg = new Uint8Array(2000).fill(0x31); // > 1232 legacy limit\n\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 })) // pubkey\n .mockResolvedValueOnce(\n CommandResultFactory({ error: solanaHeaderErr() as any }),\n ); // v0 -> 6a81\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: msg,\n }).run();\n\n // no legacy retry\n expect(apiMock.sendCommand).toHaveBeenCalledTimes(2);\n expect((res as any).error).toEqual(solanaHeaderErr());\n });\n });\n\n describe(\"message format detection (indirect via header byte)\", () => {\n it(\"sets format=0 for ASCII \u2264 maxLedgerLen (v0 header)\", () => {\n const ascii = new TextEncoder().encode(\"hello\\nworld\"); // newline allowed in non-legacy\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: ascii,\n });\n const v0 = task._buildFullMessage(ascii, PUBKEY, false);\n // in v0 format byte is at offset: 16 (domain) + 1 (ver) + 32 (app) = 49\n expect(v0[49]).toBe(MessageFormat.Ascii);\n });\n\n it(\"sets format=1 for short UTF-8 non-ASCII (v0 header)\", () => {\n const utf8 = new TextEncoder().encode(\"h\u00E9ll\u00F8\");\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: utf8,\n });\n const v0 = task._buildFullMessage(utf8, PUBKEY, false);\n expect(v0[49]).toBe(MessageFormat.Utf8);\n });\n\n it(\"sets format=2 for long UTF-8 (v0 header)\", () => {\n // must exceed OFFCM_MAX_LEDGER_LEN to get format=2\n const longUtf8 = new TextEncoder().encode(\"x\".repeat(15313));\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: longUtf8,\n });\n const v0 = task._buildFullMessage(longUtf8, PUBKEY, false);\n expect(v0[49]).toBe(MessageFormat.Utf8LongV0);\n });\n\n it(\"legacy header forbids newline in ASCII (so format becomes UTF-8=1)\", () => {\n const asciiWithNl = new TextEncoder().encode(\"hello\\nworld\");\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: asciiWithNl,\n });\n const legacy = task._buildFullMessage(asciiWithNl, PUBKEY, true);\n // in legacy: format byte is at offset 16 (domain) + 1 (ver) = 17\n expect(legacy[17]).toBe(MessageFormat.Utf8);\n });\n\n it(\"legacy header sets format=0 for plain ASCII (no newline)\", () => {\n const ascii = new TextEncoder().encode(\"HELLO_123\");\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: ascii,\n });\n const legacy = task._buildFullMessage(ascii, PUBKEY, true);\n expect(legacy[17]).toBe(MessageFormat.Ascii);\n });\n\n it(\"message length is little-endian in both headers\", () => {\n const body = new Uint8Array([1, 2, 3]); // length = 3\n const task: any = new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: body,\n });\n\n // v0 offsets:\n // length starts at: 16(domain) + 1(ver) + 32(app) + 1(format) + 1(count) + 32(pubkey) = 83\n const v0 = task._buildFullMessage(body, PUBKEY, false);\n expect(v0[83]).toBe(3); // LSB (0x03)\n expect(v0[84]).toBe(0); // MSB (0x00)\n\n // legacy offsets:\n // length starts at: 16(domain) + 1(ver) + 1(format) = 18\n const legacy = task._buildFullMessage(body, PUBKEY, true);\n expect(legacy[18]).toBe(3); // LSB (0x03)\n expect(legacy[19]).toBe(0); // MSB (0x00)\n });\n });\n\n it(\"returns error when device returns non-64-byte signature on final chunk\", async () => {\n const msg = new Uint8Array([1, 2, 3]);\n\n apiMock.sendCommand\n .mockResolvedValueOnce(CommandResultFactory({ data: PUBKEY_BASE58 }))\n .mockResolvedValueOnce(CommandResultFactory({ data: new Uint8Array(0) }));\n\n const res = await new SendSignMessageTask(apiMock, {\n derivationPath: DERIVATION_PATH,\n sendingData: msg,\n }).run();\n\n expect(\"error\" in res).toBe(true);\n\n const err = (res as any).error as unknown;\n expect(err).toBeInstanceOf(InvalidStatusWordError);\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["import_device_management_kit", "import_makeInternalApi", "import_bs58Encoder", "import_SendSignMessageTask", "DERIVATION_PATH", "PUBKEY", "PUBKEY_BASE58", "solanaHeaderErr", "apiMock", "result", "res", "msg", "rawSig", "task", "v0OCM", "b58", "expected", "args", "fullMsg", "paths", "apdu", "bigMsg", "tooBig", "legacyOCM", "ascii", "v0", "utf8", "longUtf8", "asciiWithNl", "legacy", "body", "err"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as i,ApduParser as d,CommandResultFactory as o,InvalidStatusWordError as g}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as l}from"@ledgerhq/signer-utils";import{Maybe as f}from"purify-ts";import{DefaultBs58Encoder as C}from"../../app-binder/services/bs58Encoder";import{SOLANA_APP_ERRORS as u,SolanaAppCommandErrorFactory as A}from"./utils/SolanaApplicationErrors";const t=64;class O{constructor(r,p=C){this.bs58Encoder=p;this.args=r}errorHelper=new l(u,A);args;getApdu(){return new i({cla:224,ins:7,p1:1,p2:0}).addBufferToData(this.args.message).build()}parseResponse(r){return f.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{const e=new d(r).extractFieldByLength(t);if(!e||e.length!==t)return o({error:new g("Signature extraction failed")});const n=Uint8Array.of(1),s=this.args.message,a=new Uint8Array(n.length+e.length+s.length);a.set(n,0),a.set(e,n.length),a.set(s,n.length+e.length);const m=this.bs58Encoder.encode(a);return o({data:{signature:m}})})}}export{O as SignOffChainMessageCommand};
1
+ import{ApduBuilder as t,ApduParser as s,CommandResultFactory as a}from"@ledgerhq/device-management-kit";const p=224,d=7,m=1,o=64,r={INIT:0,EXTEND:1,MORE:2};class l{constructor(e){this.args=e}getApdu(){const e=(this.args.extend?r.EXTEND:r.INIT)|(this.args.more?r.MORE:0);return new t({cla:p,ins:d,p1:m,p2:e}).addBufferToData(this.args.chunkedData).build()}parseResponse(e){const n=new s(e).extractFieldByLength(o);return!n||n.length!==o?a({data:new Uint8Array(0)}):a({data:n})}}export{p as CLA,d as INS,m as P1,r as SOL_P2,l as SignOffChainMessageCommand};
2
2
  //# sourceMappingURL=SignOffChainMessageCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/SignOffChainMessageCommand.ts"],
4
- "sourcesContent": ["import {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n type Bs58Encoder,\n DefaultBs58Encoder,\n} from \"@internal/app-binder/services/bs58Encoder\";\n\nimport {\n SOLANA_APP_ERRORS,\n SolanaAppCommandErrorFactory,\n type SolanaAppErrorCodes,\n} from \"./utils/SolanaApplicationErrors\";\n\nconst SIGNATURE_LENGTH = 64;\n\nexport type SignOffChainMessageCommandResponse = {\n signature: string;\n};\nexport type SignOffChainMessageCommandArgs = {\n readonly message: Uint8Array;\n};\n\nexport class SignOffChainMessageCommand\n implements\n Command<\n SignOffChainMessageCommandResponse,\n SignOffChainMessageCommandArgs,\n SolanaAppErrorCodes\n >\n{\n private readonly errorHelper = new CommandErrorHelper<\n SignOffChainMessageCommandResponse,\n SolanaAppErrorCodes\n >(SOLANA_APP_ERRORS, SolanaAppCommandErrorFactory);\n\n args: SignOffChainMessageCommandArgs;\n\n constructor(\n args: SignOffChainMessageCommandArgs,\n private readonly bs58Encoder: Bs58Encoder = DefaultBs58Encoder,\n ) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: 0xe0,\n ins: 0x07,\n p1: 0x01,\n p2: 0x00,\n })\n .addBufferToData(this.args.message)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<SignOffChainMessageCommandResponse, SolanaAppErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n const parser = new ApduParser(response);\n\n // extract raw signature from device response\n const signature = parser.extractFieldByLength(SIGNATURE_LENGTH);\n if (!signature || signature.length !== SIGNATURE_LENGTH) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"Signature extraction failed\"),\n });\n }\n\n // build the OCM envelope: [signatureCount=1][signature][signedMessage]\n // signatureCount = 1 (single signer)\n const signatureCount = Uint8Array.of(1);\n\n // this.args.message is the off-chain message that was signed\n const msg = this.args.message;\n\n const envelope = new Uint8Array(\n signatureCount.length + signature.length + msg.length,\n );\n envelope.set(signatureCount, 0);\n envelope.set(signature, signatureCount.length);\n envelope.set(msg, signatureCount.length + signature.length);\n\n // base58-encode the envelope and return { signature: <b58> }\n const encoded = this.bs58Encoder.encode(envelope);\n\n return CommandResultFactory({\n data: { signature: encoded },\n });\n });\n }\n}\n"],
5
- "mappings": "AAAA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OAEE,sBAAAC,MACK,4CAEP,OACE,qBAAAC,EACA,gCAAAC,MAEK,kCAEP,MAAMC,EAAmB,GASlB,MAAMC,CAOb,CAQE,YACEC,EACiBC,EAA2BN,EAC5C,CADiB,iBAAAM,EAEjB,KAAK,KAAOD,CACd,CAZiB,YAAc,IAAIP,EAGjCG,EAAmBC,CAA4B,EAEjD,KASA,SAAgB,CACd,OAAO,IAAIR,EAAY,CACrB,IAAK,IACL,IAAK,EACL,GAAI,EACJ,GAAI,CACN,CAAC,EACE,gBAAgB,KAAK,KAAK,OAAO,EACjC,MAAM,CACX,CAEA,cACEa,EACwE,CACxE,OAAOR,EAAM,aACX,KAAK,YAAY,SAASQ,CAAQ,CACpC,EAAE,cAAc,IAAM,CAIpB,MAAMC,EAHS,IAAIb,EAAWY,CAAQ,EAGb,qBAAqBJ,CAAgB,EAC9D,GAAI,CAACK,GAAaA,EAAU,SAAWL,EACrC,OAAOP,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,6BAA6B,CACjE,CAAC,EAKH,MAAMY,EAAiB,WAAW,GAAG,CAAC,EAGhCC,EAAM,KAAK,KAAK,QAEhBC,EAAW,IAAI,WACnBF,EAAe,OAASD,EAAU,OAASE,EAAI,MACjD,EACAC,EAAS,IAAIF,EAAgB,CAAC,EAC9BE,EAAS,IAAIH,EAAWC,EAAe,MAAM,EAC7CE,EAAS,IAAID,EAAKD,EAAe,OAASD,EAAU,MAAM,EAG1D,MAAMI,EAAU,KAAK,YAAY,OAAOD,CAAQ,EAEhD,OAAOf,EAAqB,CAC1B,KAAM,CAAE,UAAWgB,CAAQ,CAC7B,CAAC,CACH,CAAC,CACH,CACF",
6
- "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "DefaultBs58Encoder", "SOLANA_APP_ERRORS", "SolanaAppCommandErrorFactory", "SIGNATURE_LENGTH", "SignOffChainMessageCommand", "args", "bs58Encoder", "response", "signature", "signatureCount", "msg", "envelope", "encoded"]
4
+ "sourcesContent": ["import {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ChunkableCommandArgs } from \"@internal/app-binder/task/SendCommandInChunksTask\";\n\nimport { type SolanaAppErrorCodes } from \"./utils/SolanaApplicationErrors\";\n\nexport const CLA = 0xe0;\nexport const INS = 0x07;\nexport const P1 = 0x01;\n\nconst SIGNATURE_LENGTH = 64;\n\nexport const SOL_P2 = {\n INIT: 0x00,\n EXTEND: 0x01,\n MORE: 0x02,\n};\n\nexport type SignOffChainRawResponse = Uint8Array;\n\nexport class SignOffChainMessageCommand\n implements\n Command<SignOffChainRawResponse, ChunkableCommandArgs, SolanaAppErrorCodes>\n{\n constructor(readonly args: ChunkableCommandArgs) {}\n\n getApdu(): Apdu {\n const p2 =\n (this.args.extend ? SOL_P2.EXTEND : SOL_P2.INIT) |\n (this.args.more ? SOL_P2.MORE : 0);\n\n return new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2,\n })\n .addBufferToData(this.args.chunkedData)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<SignOffChainRawResponse, SolanaAppErrorCodes> {\n const parser = new ApduParser(response);\n const sig = parser.extractFieldByLength(SIGNATURE_LENGTH);\n\n // for intermediate chunks, the device returns 0 bytes of data with 0x9000.\n // only the last chunk yields the 64-byte signature.\n if (!sig || sig.length !== SIGNATURE_LENGTH) {\n return CommandResultFactory({ data: new Uint8Array(0) });\n }\n\n return CommandResultFactory({ data: sig });\n }\n}\n"],
5
+ "mappings": "AAAA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,MACK,kCAMA,MAAMC,EAAM,IACNC,EAAM,EACNC,EAAK,EAEZC,EAAmB,GAEZC,EAAS,CACpB,KAAM,EACN,OAAQ,EACR,KAAM,CACR,EAIO,MAAMC,CAGb,CACE,YAAqBC,EAA4B,CAA5B,UAAAA,CAA6B,CAElD,SAAgB,CACd,MAAMC,GACH,KAAK,KAAK,OAASH,EAAO,OAASA,EAAO,OAC1C,KAAK,KAAK,KAAOA,EAAO,KAAO,GAElC,OAAO,IAAIP,EAAY,CACrB,IAAKG,EACL,IAAKC,EACL,GAAIC,EACJ,GAAAK,CACF,CAAC,EACE,gBAAgB,KAAK,KAAK,WAAW,EACrC,MAAM,CACX,CAEA,cACEC,EAC6D,CAE7D,MAAMC,EADS,IAAIX,EAAWU,CAAQ,EACnB,qBAAqBL,CAAgB,EAIxD,MAAI,CAACM,GAAOA,EAAI,SAAWN,EAClBJ,EAAqB,CAAE,KAAM,IAAI,WAAW,CAAC,CAAE,CAAC,EAGlDA,EAAqB,CAAE,KAAMU,CAAI,CAAC,CAC3C,CACF",
6
+ "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "CLA", "INS", "P1", "SIGNATURE_LENGTH", "SOL_P2", "SignOffChainMessageCommand", "args", "p2", "response", "sig"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as d,ApduResponse as i,isSuccessCommandResult as s}from"@ledgerhq/device-management-kit";import{DefaultBs58Encoder as l}from"../../app-binder/services/bs58Encoder";import{SignOffChainMessageCommand as p}from"./SignOffChainMessageCommand";describe("SignOffChainMessageCommand",()=>{let t;const a=new TextEncoder().encode("Solana SignOffChainMessage"),n=64;beforeEach(()=>{t=new p({message:a}),vi.clearAllMocks(),vi.importActual("@ledgerhq/device-management-kit")}),describe("getApdu",()=>{it("should return the correct APDU",()=>{const r=t.getApdu(),e=new d({cla:224,ins:7,p1:1,p2:0}).addBufferToData(a).build();expect(r.getRawApdu()).toEqual(e.getRawApdu())})}),describe("parseResponse",()=>{it("should parse the response correctly",()=>{const r=new Uint8Array(n).fill(1),e=t.parseResponse(new i({data:r,statusCode:new Uint8Array([144,0])}));if(expect(s(e)).toBe(!0),s(e)){const o=new Uint8Array(1+n+a.length);o.set(Uint8Array.of(1),0),o.set(r,1),o.set(a,1+n);const c=l.encode(o);expect(e.data).toEqual({signature:c})}else assert.fail("Expected success result")}),describe("error handling",()=>{it("should return error if response is not success",()=>{const r=t.parseResponse(new i({statusCode:new Uint8Array([106,130]),data:new Uint8Array(0)}));expect(s(r)).toBe(!1),s(r)?assert.fail("Expected error"):expect(r.error).toEqual(expect.objectContaining({_tag:"SolanaAppCommandError",errorCode:"6a82",message:"Invalid off-chain message format"}))}),it("should return error if signature is missing or incomplete",()=>{const r=new Uint8Array(n-1).fill(1),e=t.parseResponse(new i({data:r,statusCode:new Uint8Array([144,0])}));expect(s(e)).toBe(!1),s(e)?assert.fail("Expected error"):typeof e.error.originalError=="object"&&e.error.originalError!==null&&"message"in e.error.originalError&&expect(e.error.originalError.message).toBe("Signature extraction failed")})})})});
1
+ import{ApduBuilder as r,ApduResponse as p,isSuccessCommandResult as d}from"@ledgerhq/device-management-kit";import{CLA as c,INS as o,P1 as u,SignOffChainMessageCommand as s}from"./SignOffChainMessageCommand";describe("SignOffChainMessageCommand",()=>{const a=new TextEncoder().encode("Solana SignOffChainMessage"),i=64;describe("getApdu()",()=>{it("builds APDU for a single (final) chunk (p2=INIT)",()=>{const e=new s({chunkedData:a,extend:!1,more:!1}).getApdu(),t=new r({cla:c,ins:o,p1:u,p2:0}).addBufferToData(a).build();expect(e.getRawApdu()).toEqual(t.getRawApdu())}),it("sets p2 correctly for first of many chunks (INIT|MORE)",()=>{const e=new s({chunkedData:a,extend:!1,more:!0}).getApdu(),t=new r({cla:c,ins:o,p1:u,p2:2}).addBufferToData(a).build();expect(e.getRawApdu()).toEqual(t.getRawApdu())}),it("sets p2 correctly for middle chunks (EXTEND|MORE)",()=>{const e=new s({chunkedData:a,extend:!0,more:!0}).getApdu(),t=new r({cla:c,ins:o,p1:u,p2:3}).addBufferToData(a).build();expect(e.getRawApdu()).toEqual(t.getRawApdu())}),it("sets p2 correctly for the final chunk after extends (EXTEND)",()=>{const e=new s({chunkedData:a,extend:!0,more:!1}).getApdu(),t=new r({cla:c,ins:o,p1:u,p2:1}).addBufferToData(a).build();expect(e.getRawApdu()).toEqual(t.getRawApdu())})}),describe("parseResponse()",()=>{it("returns raw 64-byte signature on the last chunk",()=>{const n=new s({chunkedData:a,extend:!0,more:!1}),e=new Uint8Array(i).fill(66),t=n.parseResponse(new p({data:e,statusCode:new Uint8Array([144,0])}));expect(d(t)).toBe(!0),d(t)&&expect(t.data).toEqual(e)}),it("returns empty data for intermediate chunks (no signature yet)",()=>{const e=new s({chunkedData:a,extend:!0,more:!0}).parseResponse(new p({data:new Uint8Array(0),statusCode:new Uint8Array([144,0])}));expect(d(e)).toBe(!0),d(e)&&expect(e.data).toEqual(new Uint8Array(0))}),it("returns empty data if signature is present but not 64 bytes",()=>{const n=new s({chunkedData:a,extend:!0,more:!1}),e=new Uint8Array(i-1).fill(153),t=n.parseResponse(new p({data:e,statusCode:new Uint8Array([144,0])}));expect(d(t)).toBe(!0),d(t)&&expect(t.data).toEqual(new Uint8Array(0))})})});
2
2
  //# sourceMappingURL=SignOffChainMessageCommand.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/SignOffChainMessageCommand.test.ts"],
4
- "sourcesContent": ["import {\n ApduBuilder,\n ApduResponse,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { DefaultBs58Encoder } from \"@internal/app-binder/services/bs58Encoder\";\n\nimport { SignOffChainMessageCommand } from \"./SignOffChainMessageCommand\";\n\ndescribe(\"SignOffChainMessageCommand\", () => {\n let command: SignOffChainMessageCommand;\n\n const MESSAGE = new TextEncoder().encode(\"Solana SignOffChainMessage\");\n const SIGNATURE_LENGTH = 64;\n\n beforeEach(() => {\n command = new SignOffChainMessageCommand({\n message: MESSAGE,\n });\n vi.clearAllMocks();\n vi.importActual(\"@ledgerhq/device-management-kit\");\n });\n\n describe(\"getApdu\", () => {\n it(\"should return the correct APDU\", () => {\n const apdu = command.getApdu();\n\n const expectedApdu = new ApduBuilder({\n cla: 0xe0,\n ins: 0x07,\n p1: 0x01,\n p2: 0x00,\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expectedApdu.getRawApdu());\n });\n });\n\n describe(\"parseResponse\", () => {\n it(\"should parse the response correctly\", () => {\n const signature = new Uint8Array(SIGNATURE_LENGTH).fill(0x01);\n\n const parsed = command.parseResponse(\n new ApduResponse({\n data: signature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n // build expected OCM envelope: [count=1][signature][message]\n const envelope = new Uint8Array(1 + SIGNATURE_LENGTH + MESSAGE.length);\n envelope.set(Uint8Array.of(1), 0);\n envelope.set(signature, 1);\n envelope.set(MESSAGE, 1 + SIGNATURE_LENGTH);\n\n const expectedB58 = DefaultBs58Encoder.encode(envelope);\n expect(parsed.data).toEqual({ signature: expectedB58 });\n } else {\n assert.fail(\"Expected success result\");\n }\n });\n\n describe(\"error handling\", () => {\n it(\"should return error if response is not success\", () => {\n const result = command.parseResponse(\n new ApduResponse({\n statusCode: new Uint8Array([0x6a, 0x82]),\n data: new Uint8Array(0),\n }),\n );\n\n expect(isSuccessCommandResult(result)).toBe(false);\n if (!isSuccessCommandResult(result)) {\n expect(result.error).toEqual(\n expect.objectContaining({\n _tag: \"SolanaAppCommandError\",\n errorCode: \"6a82\",\n message: \"Invalid off-chain message format\",\n }),\n );\n } else {\n assert.fail(\"Expected error\");\n }\n });\n\n it(\"should return error if signature is missing or incomplete\", () => {\n const incompleteSignature = new Uint8Array(SIGNATURE_LENGTH - 1).fill(\n 0x01,\n );\n const result = command.parseResponse(\n new ApduResponse({\n data: incompleteSignature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(result)).toBe(false);\n if (!isSuccessCommandResult(result)) {\n if (\n typeof result.error.originalError === \"object\" &&\n result.error.originalError !== null &&\n \"message\" in result.error.originalError\n ) {\n expect(\n (result.error.originalError as { message: string }).message,\n ).toBe(\"Signature extraction failed\");\n }\n } else {\n assert.fail(\"Expected error\");\n }\n });\n });\n });\n});\n"],
5
- "mappings": "AAAA,OACE,eAAAA,EACA,gBAAAC,EACA,0BAAAC,MACK,kCAEP,OAAS,sBAAAC,MAA0B,4CAEnC,OAAS,8BAAAC,MAAkC,+BAE3C,SAAS,6BAA8B,IAAM,CAC3C,IAAIC,EAEJ,MAAMC,EAAU,IAAI,YAAY,EAAE,OAAO,4BAA4B,EAC/DC,EAAmB,GAEzB,WAAW,IAAM,CACfF,EAAU,IAAID,EAA2B,CACvC,QAASE,CACX,CAAC,EACD,GAAG,cAAc,EACjB,GAAG,aAAa,iCAAiC,CACnD,CAAC,EAED,SAAS,UAAW,IAAM,CACxB,GAAG,iCAAkC,IAAM,CACzC,MAAME,EAAOH,EAAQ,QAAQ,EAEvBI,EAAe,IAAIT,EAAY,CACnC,IAAK,IACL,IAAK,EACL,GAAI,EACJ,GAAI,CACN,CAAC,EACE,gBAAgBM,CAAO,EACvB,MAAM,EAET,OAAOE,EAAK,WAAW,CAAC,EAAE,QAAQC,EAAa,WAAW,CAAC,CAC7D,CAAC,CACH,CAAC,EAED,SAAS,gBAAiB,IAAM,CAC9B,GAAG,sCAAuC,IAAM,CAC9C,MAAMC,EAAY,IAAI,WAAWH,CAAgB,EAAE,KAAK,CAAI,EAEtDI,EAASN,EAAQ,cACrB,IAAIJ,EAAa,CACf,KAAMS,EACN,WAAY,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CACzC,CAAC,CACH,EAGA,GADA,OAAOR,EAAuBS,CAAM,CAAC,EAAE,KAAK,EAAI,EAC5CT,EAAuBS,CAAM,EAAG,CAElC,MAAMC,EAAW,IAAI,WAAW,EAAIL,EAAmBD,EAAQ,MAAM,EACrEM,EAAS,IAAI,WAAW,GAAG,CAAC,EAAG,CAAC,EAChCA,EAAS,IAAIF,EAAW,CAAC,EACzBE,EAAS,IAAIN,EAAS,EAAIC,CAAgB,EAE1C,MAAMM,EAAcV,EAAmB,OAAOS,CAAQ,EACtD,OAAOD,EAAO,IAAI,EAAE,QAAQ,CAAE,UAAWE,CAAY,CAAC,CACxD,MACE,OAAO,KAAK,yBAAyB,CAEzC,CAAC,EAED,SAAS,iBAAkB,IAAM,CAC/B,GAAG,iDAAkD,IAAM,CACzD,MAAMC,EAAST,EAAQ,cACrB,IAAIJ,EAAa,CACf,WAAY,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC,EACvC,KAAM,IAAI,WAAW,CAAC,CACxB,CAAC,CACH,EAEA,OAAOC,EAAuBY,CAAM,CAAC,EAAE,KAAK,EAAK,EAC5CZ,EAAuBY,CAAM,EAShC,OAAO,KAAK,gBAAgB,EAR5B,OAAOA,EAAO,KAAK,EAAE,QACnB,OAAO,iBAAiB,CACtB,KAAM,wBACN,UAAW,OACX,QAAS,kCACX,CAAC,CACH,CAIJ,CAAC,EAED,GAAG,4DAA6D,IAAM,CACpE,MAAMC,EAAsB,IAAI,WAAWR,EAAmB,CAAC,EAAE,KAC/D,CACF,EACMO,EAAST,EAAQ,cACrB,IAAIJ,EAAa,CACf,KAAMc,EACN,WAAY,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CACzC,CAAC,CACH,EAEA,OAAOb,EAAuBY,CAAM,CAAC,EAAE,KAAK,EAAK,EAC5CZ,EAAuBY,CAAM,EAWhC,OAAO,KAAK,gBAAgB,EAT1B,OAAOA,EAAO,MAAM,eAAkB,UACtCA,EAAO,MAAM,gBAAkB,MAC/B,YAAaA,EAAO,MAAM,eAE1B,OACGA,EAAO,MAAM,cAAsC,OACtD,EAAE,KAAK,6BAA6B,CAK1C,CAAC,CACH,CAAC,CACH,CAAC,CACH,CAAC",
6
- "names": ["ApduBuilder", "ApduResponse", "isSuccessCommandResult", "DefaultBs58Encoder", "SignOffChainMessageCommand", "command", "MESSAGE", "SIGNATURE_LENGTH", "apdu", "expectedApdu", "signature", "parsed", "envelope", "expectedB58", "result", "incompleteSignature"]
4
+ "sourcesContent": ["import {\n ApduBuilder,\n ApduResponse,\n isSuccessCommandResult,\n} from \"@ledgerhq/device-management-kit\";\n\nimport {\n CLA,\n INS,\n P1,\n SignOffChainMessageCommand,\n} from \"./SignOffChainMessageCommand\";\n\ndescribe(\"SignOffChainMessageCommand\", () => {\n const MESSAGE = new TextEncoder().encode(\"Solana SignOffChainMessage\");\n const SIGNATURE_LENGTH = 64;\n\n describe(\"getApdu()\", () => {\n it(\"builds APDU for a single (final) chunk (p2=INIT)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: false,\n more: false,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x00, // INIT only\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for first of many chunks (INIT|MORE)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: false,\n more: true,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x02, // INIT|MORE\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for middle chunks (EXTEND|MORE)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: true,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x03, // EXTEND|MORE\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n\n it(\"sets p2 correctly for the final chunk after extends (EXTEND)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const apdu = cmd.getApdu();\n\n const expected = new ApduBuilder({\n cla: CLA,\n ins: INS,\n p1: P1,\n p2: 0x01, // EXTEND only\n })\n .addBufferToData(MESSAGE)\n .build();\n\n expect(apdu.getRawApdu()).toEqual(expected.getRawApdu());\n });\n });\n\n describe(\"parseResponse()\", () => {\n it(\"returns raw 64-byte signature on the last chunk\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const signature = new Uint8Array(SIGNATURE_LENGTH).fill(0x42);\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: signature,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(signature);\n }\n });\n\n it(\"returns empty data for intermediate chunks (no signature yet)\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: true,\n });\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: new Uint8Array(0), // device returns no data mid-stream\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(new Uint8Array(0));\n }\n });\n\n it(\"returns empty data if signature is present but not 64 bytes\", () => {\n const cmd = new SignOffChainMessageCommand({\n chunkedData: MESSAGE,\n extend: true,\n more: false,\n });\n\n const shortSig = new Uint8Array(SIGNATURE_LENGTH - 1).fill(0x99);\n\n const parsed = cmd.parseResponse(\n new ApduResponse({\n data: shortSig,\n statusCode: new Uint8Array([0x90, 0x00]),\n }),\n );\n\n expect(isSuccessCommandResult(parsed)).toBe(true);\n if (isSuccessCommandResult(parsed)) {\n expect(parsed.data).toEqual(new Uint8Array(0));\n }\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["ApduBuilder", "ApduResponse", "isSuccessCommandResult", "CLA", "INS", "P1", "SignOffChainMessageCommand", "MESSAGE", "SIGNATURE_LENGTH", "apdu", "expected", "cmd", "signature", "parsed", "shortSig"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{APDU_MAX_PAYLOAD as m,ByteArrayBuilder as f,CommandResultFactory as r,InvalidStatusWordError as o}from"@ledgerhq/device-management-kit";import{DerivationPathUtils as g}from"@ledgerhq/signer-utils";import{GetPubKeyCommand as l}from"../../app-binder/command/GetPubKeyCommand";import{SignOffChainMessageCommand as p}from"../../app-binder/command/SignOffChainMessageCommand";import{DefaultBs58Encoder as c}from"../../app-binder/services/bs58Encoder";const y=65535;class B{constructor(e,t,i=c){this.api=e;this.args=t;this.bs58Encoder=i}async run(){const{sendingData:e,derivationPath:t}=this.args;if(e.length===0)return r({error:new o("Message cannot be empty")});if(e.length>y)return r({error:new o(`Message too long: ${e.length} bytes (max is 65535)`)});const i=g.splitPath(t),s=await this.api.sendCommand(new l({derivationPath:t,checkOnDevice:!1}));if(!("data"in s))return r({error:new o("Error getting public key from device")});const d=this.bs58Encoder.decode(s.data),n=this._buildFullMessage(e,d),a=this._buildApduCommand(n,i);return a.length>m?r({error:new o("The APDU command exceeds the maximum allowable size (255 bytes)")}):this.api.sendCommand(new p({message:a}))}_buildFullMessage(e,t){return new f().add8BitUIntToData(255).addAsciiStringToData("solana offchain").add8BitUIntToData(0).addBufferToData(new Uint8Array(32)).add8BitUIntToData(0).add8BitUIntToData(1).addBufferToData(t).add8BitUIntToData(e.length&255).add8BitUIntToData(e.length>>8&255).addBufferToData(e).build()}_buildApduCommand(e,t){const d=t.length*4,n=new f(e.length+1+1+d);return n.add8BitUIntToData(1),n.add8BitUIntToData(t.length),t.forEach(a=>{const u=new Uint8Array(4);new DataView(u.buffer).setUint32(0,a,!1),n.addBufferToData(u)}),n.addBufferToData(e),n.build()}}export{y as MAX_MESSAGE_LENGTH,B as SendSignMessageTask};
1
+ import{ByteArrayBuilder as g,CommandResultFactory as i,InvalidStatusWordError as s,isSuccessCommandResult as h}from"@ledgerhq/device-management-kit";import{DerivationPathUtils as I}from"@ledgerhq/signer-utils";import{GetPubKeyCommand as S}from"../../app-binder/command/GetPubKeyCommand";import{SignOffChainMessageCommand as b}from"../../app-binder/command/SignOffChainMessageCommand";import{DefaultBs58Encoder as U}from"../../app-binder/services/bs58Encoder";import{SendCommandInChunksTask as T}from"./SendCommandInChunksTask";const R=15*1024,v=1280,m=40,E=8,D=R-m-E,p=v-m-E,u=65515,w=126,B=32,M=10;var F=(n=>(n[n.Ascii=0]="Ascii",n[n.Utf8=1]="Utf8",n[n.Utf8LongV0=2]="Utf8LongV0",n))(F||{});const A=u;class V{constructor(t,e,n=U){this.api=t;this.args=e;this.bs58Encoder=n}async run(){const{sendingData:t,derivationPath:e}=this.args;if(t.length===0)return i({error:new s("Message cannot be empty")});if(t.length>A)return i({error:new s(`Message too long: ${t.length} bytes (max is ${A})`)});const n=I.splitPath(e),r=await this.api.sendCommand(new S({derivationPath:e,checkOnDevice:!1}));if(!("data"in r))return i({error:new s("Error getting public key from device")});const a=this.bs58Encoder.decode(r.data),f=this._buildFullMessage(t,a,!1),_=this._buildApduCommand(f,n),d=await this._sendInChunks(_);if(h(d))try{const o=this._buildEnvelopeBase58(d.data,f);return i({data:{signature:o}})}catch(o){return i({error:new s(o instanceof Error?o.message:String(o))})}const C="error"in d?d.error:void 0;if(this._isInvalidOffchainHeaderError(C)){if(t.length>p)return d;const o=this._buildFullMessage(t,a,!0),y=this._buildApduCommand(o,n),c=await this._sendInChunks(y);if(h(c))try{const l=this._buildEnvelopeBase58(c.data,o);return i({data:{signature:l}})}catch(l){return i({error:new s(l instanceof Error?l.message:String(l))})}return c}return d}_isUTF8(t){try{return new TextDecoder("utf-8",{fatal:!0}).decode(t),!0}catch{return!1}}_findMessageFormat(t,e){const n=e?p:D;if(t.length<=n){if(this._isPrintableASCII(t,e))return 0;if(this._isUTF8(t))return 1}else if(t.length<=u){if(this._isUTF8(t))return 2}else throw new s(`Message too long: ${t.length} bytes (max is ${u})`);return 0}_isPrintableASCII(t,e){for(let n=0;n<t.length;n++){const r=t[n];if(!(!e&&r===M)&&(r<B||r>w))return!1}return!0}_buildFullMessage(t,e,n){const r=this._findMessageFormat(t,n),a=new g;return a.add8BitUIntToData(255).addAsciiStringToData("solana offchain"),a.add8BitUIntToData(0),n||a.addBufferToData(new Uint8Array(32)),a.add8BitUIntToData(r),n||(a.add8BitUIntToData(1),a.addBufferToData(e)),a.add8BitUIntToData(t.length&255),a.add8BitUIntToData(t.length>>8&255),a.addBufferToData(t),a.build()}_isInvalidOffchainHeaderError(t){if(!t||typeof t!="object")return!1;const e=t,n=e._tag,r=e.errorCode;return typeof n=="string"&&typeof r=="string"&&r.toLowerCase()==="6a81"}_buildApduCommand(t,e){const n=new g(2+e.length*4+t.length);return n.add8BitUIntToData(1),n.add8BitUIntToData(e.length),e.forEach(r=>n.add32BitUIntToData(r)),n.addBufferToData(t),n.build()}async _sendInChunks(t){const e=n=>new b(n);return await new T(this.api,{data:t,commandFactory:e}).run()}_buildEnvelopeBase58(t,e){if(t.length!==64)throw new s(`Invalid signature length: ${t.length} (expected 64)`);const n=Uint8Array.of(1),r=new Uint8Array(n.length+t.length+e.length);return r.set(n,0),r.set(t,n.length),r.set(e,n.length+t.length),this.bs58Encoder.encode(r)}}export{A as MAX_MESSAGE_LENGTH,F as MessageFormat,V as SendSignMessageTask};
2
2
  //# sourceMappingURL=SendSignMessageTask.js.map