@ledgerhq/device-core 0.2.1-next.2 → 0.3.0-nightly.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +9 -15
  3. package/lib/commands/entities/AppStorageInfo.d.ts +8 -0
  4. package/lib/commands/entities/AppStorageInfo.d.ts.map +1 -0
  5. package/lib/commands/entities/AppStorageInfo.js +3 -0
  6. package/lib/commands/entities/AppStorageInfo.js.map +1 -0
  7. package/lib/commands/use-cases/app-backup/backupAppStorage.d.ts +18 -0
  8. package/lib/commands/use-cases/app-backup/backupAppStorage.d.ts.map +1 -0
  9. package/lib/commands/use-cases/app-backup/backupAppStorage.js +98 -0
  10. package/lib/commands/use-cases/app-backup/backupAppStorage.js.map +1 -0
  11. package/lib/commands/use-cases/app-backup/backupAppStorage.test.d.ts +2 -0
  12. package/lib/commands/use-cases/app-backup/backupAppStorage.test.d.ts.map +1 -0
  13. package/lib/commands/use-cases/app-backup/backupAppStorage.test.js +56 -0
  14. package/lib/commands/use-cases/app-backup/backupAppStorage.test.js.map +1 -0
  15. package/lib/commands/use-cases/app-backup/getAppStorageInfo.d.ts +20 -0
  16. package/lib/commands/use-cases/app-backup/getAppStorageInfo.d.ts.map +1 -0
  17. package/lib/commands/use-cases/app-backup/getAppStorageInfo.js +104 -0
  18. package/lib/commands/use-cases/app-backup/getAppStorageInfo.js.map +1 -0
  19. package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts +2 -0
  20. package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts.map +1 -0
  21. package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.js +59 -0
  22. package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.js.map +1 -0
  23. package/lib/commands/use-cases/app-backup/restoreAppStorage.d.ts +12 -0
  24. package/lib/commands/use-cases/app-backup/restoreAppStorage.d.ts.map +1 -0
  25. package/lib/commands/use-cases/app-backup/restoreAppStorage.js +93 -0
  26. package/lib/commands/use-cases/app-backup/restoreAppStorage.js.map +1 -0
  27. package/lib/commands/use-cases/app-backup/restoreAppStorage.test.d.ts +2 -0
  28. package/lib/commands/use-cases/app-backup/restoreAppStorage.test.d.ts.map +1 -0
  29. package/lib/commands/use-cases/app-backup/restoreAppStorage.test.js +54 -0
  30. package/lib/commands/use-cases/app-backup/restoreAppStorage.test.js.map +1 -0
  31. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts +11 -0
  32. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts.map +1 -0
  33. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.js +83 -0
  34. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.js.map +1 -0
  35. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts +2 -0
  36. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts.map +1 -0
  37. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.js +49 -0
  38. package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.js.map +1 -0
  39. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.d.ts +13 -0
  40. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.d.ts.map +1 -0
  41. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.js +99 -0
  42. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.js.map +1 -0
  43. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts +2 -0
  44. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts.map +1 -0
  45. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.js +52 -0
  46. package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.js.map +1 -0
  47. package/lib/errors.d.ts +40 -0
  48. package/lib/errors.d.ts.map +1 -0
  49. package/lib/errors.js +30 -0
  50. package/lib/errors.js.map +1 -0
  51. package/lib/index.d.ts +6 -0
  52. package/lib/index.d.ts.map +1 -1
  53. package/lib/index.js +11 -1
  54. package/lib/index.js.map +1 -1
  55. package/lib-es/commands/entities/AppStorageInfo.d.ts +8 -0
  56. package/lib-es/commands/entities/AppStorageInfo.d.ts.map +1 -0
  57. package/lib-es/commands/entities/AppStorageInfo.js +2 -0
  58. package/lib-es/commands/entities/AppStorageInfo.js.map +1 -0
  59. package/lib-es/commands/use-cases/app-backup/backupAppStorage.d.ts +18 -0
  60. package/lib-es/commands/use-cases/app-backup/backupAppStorage.d.ts.map +1 -0
  61. package/lib-es/commands/use-cases/app-backup/backupAppStorage.js +93 -0
  62. package/lib-es/commands/use-cases/app-backup/backupAppStorage.js.map +1 -0
  63. package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.d.ts +2 -0
  64. package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.d.ts.map +1 -0
  65. package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.js +54 -0
  66. package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.js.map +1 -0
  67. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.d.ts +20 -0
  68. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.d.ts.map +1 -0
  69. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.js +99 -0
  70. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.js.map +1 -0
  71. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts +2 -0
  72. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts.map +1 -0
  73. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.js +57 -0
  74. package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.js.map +1 -0
  75. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.d.ts +12 -0
  76. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.d.ts.map +1 -0
  77. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.js +88 -0
  78. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.js.map +1 -0
  79. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.d.ts +2 -0
  80. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.d.ts.map +1 -0
  81. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.js +52 -0
  82. package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.js.map +1 -0
  83. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts +11 -0
  84. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts.map +1 -0
  85. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.js +78 -0
  86. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.js.map +1 -0
  87. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts +2 -0
  88. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts.map +1 -0
  89. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.js +47 -0
  90. package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.js.map +1 -0
  91. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.d.ts +13 -0
  92. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.d.ts.map +1 -0
  93. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.js +94 -0
  94. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.js.map +1 -0
  95. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts +2 -0
  96. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts.map +1 -0
  97. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.js +50 -0
  98. package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.js.map +1 -0
  99. package/lib-es/errors.d.ts +40 -0
  100. package/lib-es/errors.d.ts.map +1 -0
  101. package/lib-es/errors.js +27 -0
  102. package/lib-es/errors.js.map +1 -0
  103. package/lib-es/index.d.ts +6 -0
  104. package/lib-es/index.d.ts.map +1 -1
  105. package/lib-es/index.js +5 -0
  106. package/lib-es/index.js.map +1 -1
  107. package/package.json +6 -6
  108. package/src/commands/entities/AppStorageInfo.ts +7 -0
  109. package/src/commands/use-cases/app-backup/backupAppStorage.test.ts +52 -0
  110. package/src/commands/use-cases/app-backup/backupAppStorage.ts +97 -0
  111. package/src/commands/use-cases/app-backup/getAppStorageInfo.test.ts +63 -0
  112. package/src/commands/use-cases/app-backup/getAppStorageInfo.ts +102 -0
  113. package/src/commands/use-cases/app-backup/restoreAppStorage.test.ts +57 -0
  114. package/src/commands/use-cases/app-backup/restoreAppStorage.ts +93 -0
  115. package/src/commands/use-cases/app-backup/restoreAppStorageCommit.test.ts +45 -0
  116. package/src/commands/use-cases/app-backup/restoreAppStorageCommit.ts +82 -0
  117. package/src/commands/use-cases/app-backup/restoreAppStorageInit.test.ts +55 -0
  118. package/src/commands/use-cases/app-backup/restoreAppStorageInit.ts +96 -0
  119. package/src/errors.ts +29 -0
  120. package/src/index.ts +6 -0
@@ -0,0 +1,78 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { StatusCodes, TransportStatusError } from "@ledgerhq/hw-transport";
11
+ import { LocalTracer } from "@ledgerhq/logs";
12
+ import { GenerateAesKeyFailed, InternalComputeAesCmacFailed, InvalidChunkLength, InvalidContext, } from "../../../errors";
13
+ /**
14
+ * Name in documentation: INS_APP_STORAGE_RESTORE_COMMIT
15
+ * cla: 0xe0
16
+ * ins: 0x6e
17
+ * p1: 0x00
18
+ * p2: 0x00
19
+ * lc: 0x00
20
+ */
21
+ const RESTORE_APP_STORAGE_COMMIT = [0xe0, 0x6e, 0x00, 0x00];
22
+ /**
23
+ * 0x9000: Success.
24
+ * 0x5123: Invalid context, Restore Init must be called first.
25
+ * 0x5419: Internal error, crypto operaiton failed.
26
+ * 0x541B: Failed to verify backup authenticity.
27
+ * 0x662F: Invalid device state, recovery mode.
28
+ * 0x6734: Invalid size of the restored app storage.
29
+ */
30
+ const RESPONSE_STATUS_SET = [
31
+ StatusCodes.OK,
32
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
33
+ StatusCodes.GEN_AES_KEY_FAILED,
34
+ StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
35
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
36
+ StatusCodes.INVALID_CHUNK_LENGTH,
37
+ ];
38
+ /**
39
+ * Restores the application storage commit.
40
+ *
41
+ * @param transport - The transport object used for communication with the device.
42
+ * @returns A promise that resolves to void.
43
+ */
44
+ export function restoreAppStorageCommit(transport) {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ const tracer = new LocalTracer("hw", {
47
+ transport: transport.getTraceContext(),
48
+ function: "restoreAppStorageCommit",
49
+ });
50
+ tracer.trace("Start");
51
+ const apdu = [...RESTORE_APP_STORAGE_COMMIT, Buffer.from([0x00])];
52
+ const response = yield transport.send(...apdu, RESPONSE_STATUS_SET);
53
+ parseResponse(response);
54
+ });
55
+ }
56
+ export function parseResponse(data) {
57
+ const tracer = new LocalTracer("hw", {
58
+ function: "parseResponse@restoreAppStorageCommit",
59
+ });
60
+ const status = data.readUInt16BE(data.length - 2);
61
+ tracer.trace("Result status from 0xe06e0000", { status });
62
+ switch (status) {
63
+ case StatusCodes.OK:
64
+ return;
65
+ case StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
66
+ throw new InvalidContext("Invalid context, restoreAppStorageInit must be called first.");
67
+ case StatusCodes.GEN_AES_KEY_FAILED:
68
+ throw new GenerateAesKeyFailed("Internal error, crypto operation failed.");
69
+ case StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED:
70
+ throw new InternalComputeAesCmacFailed("Failed to verify backup authenticity.");
71
+ case StatusCodes.DEVICE_IN_RECOVERY_MODE:
72
+ break;
73
+ case StatusCodes.INVALID_CHUNK_LENGTH:
74
+ throw new InvalidChunkLength("Invalid size of the restored app storage.");
75
+ }
76
+ throw new TransportStatusError(status);
77
+ }
78
+ //# sourceMappingURL=restoreAppStorageCommit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageCommit.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageCommit.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,kBAAkB,EAClB,cAAc,GACf,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;GAOG;AACH,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAErE;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAa;IACpC,WAAW,CAAC,EAAE;IACd,WAAW,CAAC,gCAAgC;IAC5C,WAAW,CAAC,kBAAkB;IAC9B,WAAW,CAAC,gCAAgC;IAC5C,WAAW,CAAC,uBAAuB;IACnC,WAAW,CAAC,oBAAoB;CACjC,CAAC;AAEF;;;;;GAKG;AAEH,MAAM,UAAgB,uBAAuB,CAAC,SAAoB;;QAChE,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE;YACnC,SAAS,EAAE,SAAS,CAAC,eAAe,EAAE;YACtC,QAAQ,EAAE,yBAAyB;SACpC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEtB,MAAM,IAAI,GAAmB,CAAC,GAAG,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAElF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAEpE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;CAAA;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,uCAAuC;KAClD,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW,CAAC,EAAE;YACjB,OAAO;QACT,KAAK,WAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,cAAc,CAAC,8DAA8D,CAAC,CAAC;QAC3F,KAAK,WAAW,CAAC,kBAAkB;YACjC,MAAM,IAAI,oBAAoB,CAAC,0CAA0C,CAAC,CAAC;QAC7E,KAAK,WAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,4BAA4B,CAAC,uCAAuC,CAAC,CAAC;QAClF,KAAK,WAAW,CAAC,uBAAuB;YACtC,MAAM;QACR,KAAK,WAAW,CAAC,oBAAoB;YACnC,MAAM,IAAI,kBAAkB,CAAC,2CAA2C,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=restoreAppStorageCommit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageCommit.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageCommit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { StatusCodes } from "@ledgerhq/hw-transport";
11
+ import { restoreAppStorageCommit, parseResponse } from "./restoreAppStorageCommit";
12
+ import { InvalidChunkLength } from "../../../errors";
13
+ jest.mock("@ledgerhq/hw-transport");
14
+ describe("restoreAppStorageCommit", () => {
15
+ let transport;
16
+ const response = Buffer.from([0x90, 0x00]);
17
+ beforeEach(() => {
18
+ transport = {
19
+ send: jest.fn().mockResolvedValue(response),
20
+ getTraceContext: jest.fn().mockResolvedValue(undefined),
21
+ };
22
+ });
23
+ afterEach(() => {
24
+ jest.clearAllMocks();
25
+ });
26
+ it("should call the send function with correct parameters", () => __awaiter(void 0, void 0, void 0, function* () {
27
+ yield restoreAppStorageCommit(transport);
28
+ expect(transport.send).toHaveBeenCalledWith(0xe0, 0x6e, 0x00, 0x00, Buffer.from([0x00]), [
29
+ StatusCodes.OK,
30
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
31
+ StatusCodes.GEN_AES_KEY_FAILED,
32
+ StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
33
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
34
+ StatusCodes.INVALID_CHUNK_LENGTH,
35
+ ]);
36
+ }));
37
+ describe("parseResponse", () => {
38
+ it("should parse the response data correctly", () => {
39
+ expect(() => parseResponse(response)).not.toThrow();
40
+ });
41
+ it("should throw TransportStatusError if the response status is invalid", () => {
42
+ const data = Buffer.from([0x67, 0x34]);
43
+ expect(() => parseResponse(data)).toThrow(new InvalidChunkLength("Invalid size of the restored app storage."));
44
+ });
45
+ });
46
+ });
47
+ //# sourceMappingURL=restoreAppStorageCommit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageCommit.test.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageCommit.test.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAEpC,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,SAAoB,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAE3C,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,GAAG;YACV,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC;YAC3C,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;SAChC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAS,EAAE;QACrE,MAAM,uBAAuB,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;YACvF,WAAW,CAAC,EAAE;YACd,WAAW,CAAC,gCAAgC;YAC5C,WAAW,CAAC,kBAAkB;YAC9B,WAAW,CAAC,gCAAgC;YAC5C,WAAW,CAAC,uBAAuB;YACnC,WAAW,CAAC,oBAAoB;SACjC,CAAC,CAAC;IACL,CAAC,CAAA,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;YAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACvC,IAAI,kBAAkB,CAAC,2CAA2C,CAAC,CACpE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" />
2
+ import Transport from "@ledgerhq/hw-transport";
3
+ /**
4
+ * Restores the application storage initialization.
5
+ *
6
+ * @param transport - The transport object used for communication with the device.
7
+ * @param appName - The name of the application to restore the storage for.
8
+ * @param backupSize - The size of the backup to restore.
9
+ * @returns A promise that resolves to void.
10
+ */
11
+ export declare function restoreAppStorageInit(transport: Transport, appName: string, backupSize: number): Promise<void>;
12
+ export declare function parseResponse(data: Buffer): void;
13
+ //# sourceMappingURL=restoreAppStorageInit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageInit.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageInit.ts"],"names":[],"mappings":";AAAA,OAAO,SAAgD,MAAM,wBAAwB,CAAC;AAwCtF;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBhD"}
@@ -0,0 +1,94 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { StatusCodes, TransportStatusError } from "@ledgerhq/hw-transport";
11
+ import { LocalTracer } from "@ledgerhq/logs";
12
+ import { AppNotFound, InvalidAppNameLength, InvalidBackupLength, PinNotSet } from "../../../errors";
13
+ /**
14
+ * Name in documentation: INS_APP_STORAGE_RESTORE_INIT
15
+ * cla: 0xe0
16
+ * ins: 0x6c
17
+ * p1: 0x00
18
+ * p2: 0x00
19
+ * data:
20
+ * - LC: BACKUP_LEN_LEN (=0x04) + APP_NAME_LEN (1 byte)
21
+ * - DATA: BACKUP_LEN + APP_NAME
22
+ *
23
+ * For example, the 'bitcoin' app with backup of length 0x00007000:
24
+ * 1. LC is 0x0b
25
+ * 2. DATA is 0x00007000 0x626974636f696e
26
+ */
27
+ const RESTORE_APP_STORAGE_INIT = [0xe0, 0x6c, 0x00, 0x00];
28
+ /**
29
+ * 0x9000: Success.
30
+ * 0x5123: Application not found.
31
+ * 0x662F: Invalid device state, recovery mode.
32
+ * 0x5501: Invalid consent, user rejected.
33
+ * 0x5502: Invalid consent, pin is not set.
34
+ * 0x670A: Invalid application name length, two chars minimum.
35
+ * 0x6733: Invalid BACKUP_LEN value.
36
+ */
37
+ const RESPONSE_STATUS_SET = [
38
+ StatusCodes.OK,
39
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
40
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
41
+ StatusCodes.USER_REFUSED_ON_DEVICE,
42
+ StatusCodes.PIN_NOT_SET,
43
+ StatusCodes.INVALID_APP_NAME_LENGTH,
44
+ StatusCodes.INVALID_BACKUP_LENGTH,
45
+ ];
46
+ /**
47
+ * Restores the application storage initialization.
48
+ *
49
+ * @param transport - The transport object used for communication with the device.
50
+ * @param appName - The name of the application to restore the storage for.
51
+ * @param backupSize - The size of the backup to restore.
52
+ * @returns A promise that resolves to void.
53
+ */
54
+ export function restoreAppStorageInit(transport, appName, backupSize) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ const tracer = new LocalTracer("hw", {
57
+ transport: transport.getTraceContext(),
58
+ function: "restoreAppStorageInit",
59
+ });
60
+ tracer.trace("Start");
61
+ const params = Buffer.concat([
62
+ Buffer.from([appName.length + 4]), // LC
63
+ Buffer.from(backupSize.toString(16).padStart(8, "0"), "hex"), // BACKUP_LEN
64
+ Buffer.from(appName, "ascii"), // APP_NAME
65
+ ]);
66
+ const apdu = [...RESTORE_APP_STORAGE_INIT, params];
67
+ const response = yield transport.send(...apdu, RESPONSE_STATUS_SET);
68
+ parseResponse(response);
69
+ });
70
+ }
71
+ export function parseResponse(data) {
72
+ const tracer = new LocalTracer("hw", {
73
+ function: "parseResponse@restoreAppStorageInit",
74
+ });
75
+ const status = data.readUInt16BE(data.length - 2);
76
+ tracer.trace("Result status from 0xe06c0000", { status });
77
+ switch (status) {
78
+ case StatusCodes.OK:
79
+ return;
80
+ case StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
81
+ throw new AppNotFound("Application not found.");
82
+ case StatusCodes.DEVICE_IN_RECOVERY_MODE:
83
+ case StatusCodes.USER_REFUSED_ON_DEVICE:
84
+ break;
85
+ case StatusCodes.PIN_NOT_SET:
86
+ throw new PinNotSet("Invalid consent, PIN is not set.");
87
+ case StatusCodes.INVALID_APP_NAME_LENGTH:
88
+ throw new InvalidAppNameLength("Invalid application name length, two chars minimum.");
89
+ case StatusCodes.INVALID_BACKUP_LENGTH:
90
+ throw new InvalidBackupLength("Invalid backup length.");
91
+ }
92
+ throw new TransportStatusError(status);
93
+ }
94
+ //# sourceMappingURL=restoreAppStorageInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageInit.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageInit.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEpG;;;;;;;;;;;;;GAaG;AACH,MAAM,wBAAwB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,mBAAmB,GAAa;IACpC,WAAW,CAAC,EAAE;IACd,WAAW,CAAC,gCAAgC;IAC5C,WAAW,CAAC,uBAAuB;IACnC,WAAW,CAAC,sBAAsB;IAClC,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,uBAAuB;IACnC,WAAW,CAAC,qBAAqB;CAClC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAgB,qBAAqB,CACzC,SAAoB,EACpB,OAAe,EACf,UAAkB;;QAElB,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE;YACnC,SAAS,EAAE,SAAS,CAAC,eAAe,EAAE;YACtC,QAAQ,EAAE,uBAAuB;SAClC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEtB,MAAM,MAAM,GAAW,MAAM,CAAC,MAAM,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK;YACxC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,aAAa;YAC3E,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW;SAC3C,CAAC,CAAC;QACH,MAAM,IAAI,GAAmB,CAAC,GAAG,wBAAwB,EAAE,MAAM,CAAC,CAAC;QAEnE,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAEpE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;CAAA;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,qCAAqC;KAChD,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW,CAAC,EAAE;YACjB,OAAO;QACT,KAAK,WAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,WAAW,CAAC,wBAAwB,CAAC,CAAC;QAClD,KAAK,WAAW,CAAC,uBAAuB,CAAC;QACzC,KAAK,WAAW,CAAC,sBAAsB;YACrC,MAAM;QACR,KAAK,WAAW,CAAC,WAAW;YAC1B,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;QAC1D,KAAK,WAAW,CAAC,uBAAuB;YACtC,MAAM,IAAI,oBAAoB,CAAC,qDAAqD,CAAC,CAAC;QACxF,KAAK,WAAW,CAAC,qBAAqB;YACpC,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=restoreAppStorageInit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageInit.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageInit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { StatusCodes } from "@ledgerhq/hw-transport";
11
+ import { restoreAppStorageInit, parseResponse } from "./restoreAppStorageInit";
12
+ import { InvalidAppNameLength } from "../../../errors";
13
+ jest.mock("@ledgerhq/hw-transport");
14
+ describe("restoreAppStorageInit", () => {
15
+ let transport;
16
+ const response = Buffer.from([0x90, 0x00]);
17
+ beforeEach(() => {
18
+ transport = {
19
+ send: jest.fn().mockResolvedValue(response),
20
+ getTraceContext: jest.fn().mockResolvedValue(undefined),
21
+ };
22
+ });
23
+ afterEach(() => {
24
+ jest.clearAllMocks();
25
+ });
26
+ it("should call the send function with correct parameters", () => __awaiter(void 0, void 0, void 0, function* () {
27
+ const appName = "MyApp";
28
+ const backupSize = 1234;
29
+ yield restoreAppStorageInit(transport, appName, backupSize);
30
+ expect(transport.send).toHaveBeenCalledWith(0xe0, 0x6c, 0x00, 0x00, Buffer.from([0x09, 0x00, 0x00, 0x04, 0xd2, 0x4d, 0x79, 0x41, 0x70, 0x70]), [
31
+ StatusCodes.OK,
32
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
33
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
34
+ StatusCodes.USER_REFUSED_ON_DEVICE,
35
+ StatusCodes.PIN_NOT_SET,
36
+ StatusCodes.INVALID_APP_NAME_LENGTH,
37
+ StatusCodes.INVALID_BACKUP_LENGTH,
38
+ ]);
39
+ }));
40
+ describe("parseResponse", () => {
41
+ it("should parse the response data correctly", () => {
42
+ expect(() => parseResponse(response)).not.toThrow();
43
+ });
44
+ it("should throw TransportStatusError if the response status is invalid", () => {
45
+ const data = Buffer.from([0x67, 0x0a]);
46
+ expect(() => parseResponse(data)).toThrow(new InvalidAppNameLength("Invalid application name length, two chars minimum."));
47
+ });
48
+ });
49
+ });
50
+ //# sourceMappingURL=restoreAppStorageInit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreAppStorageInit.test.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorageInit.test.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAEpC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,SAAoB,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAE3C,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,GAAG;YACV,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC;YAC3C,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;SAChC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAS,EAAE;QACrE,MAAM,OAAO,GAAG,OAAO,CAAC;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC;QACxB,MAAM,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC5D,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,oBAAoB,CACzC,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EACzE;YACE,WAAW,CAAC,EAAE;YACd,WAAW,CAAC,gCAAgC;YAC5C,WAAW,CAAC,uBAAuB;YACnC,WAAW,CAAC,sBAAsB;YAClC,WAAW,CAAC,WAAW;YACvB,WAAW,CAAC,uBAAuB;YACnC,WAAW,CAAC,qBAAqB;SAClC,CACF,CAAC;IACJ,CAAC,CAAA,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;YAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACvC,IAAI,oBAAoB,CAAC,qDAAqD,CAAC,CAChF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,40 @@
1
+ export declare const AppNotFound: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
2
+ [key: string]: unknown;
3
+ }>;
4
+ export declare const InvalidContext: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
5
+ [key: string]: unknown;
6
+ }>;
7
+ export declare const InvalidAppNameLength: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
8
+ [key: string]: unknown;
9
+ }>;
10
+ export declare const GenerateAesKeyFailed: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
11
+ [key: string]: unknown;
12
+ }>;
13
+ export declare const InternalCryptoOperationFailed: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
14
+ [key: string]: unknown;
15
+ }>;
16
+ export declare const InternalComputeAesCmacFailed: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
17
+ [key: string]: unknown;
18
+ }>;
19
+ export declare const EncryptAppStorageFailed: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
20
+ [key: string]: unknown;
21
+ }>;
22
+ export declare const PinNotSet: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
23
+ [key: string]: unknown;
24
+ }>;
25
+ export declare const InvalidBackupHeader: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
26
+ [key: string]: unknown;
27
+ }>;
28
+ export declare const InvalidBackupLength: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
29
+ [key: string]: unknown;
30
+ }>;
31
+ export declare const InvalidBackupState: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
32
+ [key: string]: unknown;
33
+ }>;
34
+ export declare const InvalidRestoreState: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
35
+ [key: string]: unknown;
36
+ }>;
37
+ export declare const InvalidChunkLength: import("@ledgerhq/errors/lib/helpers").LedgerErrorConstructor<{
38
+ [key: string]: unknown;
39
+ }>;
40
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW;;EAAwC,CAAC;AACjE,eAAO,MAAM,cAAc;;EAA2C,CAAC;AAEvE,eAAO,MAAM,oBAAoB;;EAAiD,CAAC;AAEnF,eAAO,MAAM,oBAAoB;;EAAiD,CAAC;AAEnF,eAAO,MAAM,6BAA6B;;EAEzC,CAAC;AAEF,eAAO,MAAM,4BAA4B;;EAAyD,CAAC;AAEnG,eAAO,MAAM,uBAAuB;;EAAoD,CAAC;AAEzF,eAAO,MAAM,SAAS;;EAAsC,CAAC;AAE7D,eAAO,MAAM,mBAAmB;;EAAgD,CAAC;AAEjF,eAAO,MAAM,mBAAmB;;EAAgD,CAAC;AAEjF,eAAO,MAAM,kBAAkB;;EAA+C,CAAC;AAE/E,eAAO,MAAM,mBAAmB;;EAAgD,CAAC;AAEjF,eAAO,MAAM,kBAAkB;;EAA+C,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { createCustomErrorClass } from "@ledgerhq/errors";
2
+ // 0x5123
3
+ export const AppNotFound = createCustomErrorClass("AppNotFound");
4
+ export const InvalidContext = createCustomErrorClass("InvalidContext");
5
+ // 0x670a
6
+ export const InvalidAppNameLength = createCustomErrorClass("InvalidAppNameLength");
7
+ // 0x5419
8
+ export const GenerateAesKeyFailed = createCustomErrorClass("GenerateAesKeyFailed");
9
+ // 0x541a
10
+ export const InternalCryptoOperationFailed = createCustomErrorClass("InternalCryptoOperationFailed");
11
+ // 0x541b
12
+ export const InternalComputeAesCmacFailed = createCustomErrorClass("InternalComputeAesCmacFailed");
13
+ // 0x541c
14
+ export const EncryptAppStorageFailed = createCustomErrorClass("EncryptAppStorageFailed");
15
+ // 0x5502
16
+ export const PinNotSet = createCustomErrorClass("PinNotSet");
17
+ // 0x684a
18
+ export const InvalidBackupHeader = createCustomErrorClass("InvalidBackupHeader");
19
+ // 0x6733
20
+ export const InvalidBackupLength = createCustomErrorClass("InvalidBackupLength");
21
+ // 0x6642
22
+ export const InvalidBackupState = createCustomErrorClass("InvalidBackupState");
23
+ // 0x6643
24
+ export const InvalidRestoreState = createCustomErrorClass("InvalidRestoreState");
25
+ // 0x6734
26
+ export const InvalidChunkLength = createCustomErrorClass("InvalidChunkLength");
27
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,SAAS;AACT,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC,aAAa,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;AACvE,SAAS;AACT,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC,sBAAsB,CAAC,CAAC;AACnF,SAAS;AACT,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC,sBAAsB,CAAC,CAAC;AACnF,SAAS;AACT,MAAM,CAAC,MAAM,6BAA6B,GAAG,sBAAsB,CACjE,+BAA+B,CAChC,CAAC;AACF,SAAS;AACT,MAAM,CAAC,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,8BAA8B,CAAC,CAAC;AACnG,SAAS;AACT,MAAM,CAAC,MAAM,uBAAuB,GAAG,sBAAsB,CAAC,yBAAyB,CAAC,CAAC;AACzF,SAAS;AACT,MAAM,CAAC,MAAM,SAAS,GAAG,sBAAsB,CAAC,WAAW,CAAC,CAAC;AAC7D,SAAS;AACT,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,qBAAqB,CAAC,CAAC;AACjF,SAAS;AACT,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,qBAAqB,CAAC,CAAC;AACjF,SAAS;AACT,MAAM,CAAC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;AAC/E,SAAS;AACT,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,qBAAqB,CAAC,CAAC;AACjF,SAAS;AACT,MAAM,CAAC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,oBAAoB,CAAC,CAAC"}
package/lib-es/index.d.ts CHANGED
@@ -16,6 +16,12 @@ export { getDeviceName } from "./commands/use-cases/getDeviceName";
16
16
  export { isHardwareVersionSupported } from "./commands/use-cases/isHardwareVersionSupported";
17
17
  export { isBootloaderVersionSupported } from "./commands/use-cases/isBootloaderVersionSupported";
18
18
  export { getVersion } from "./commands/use-cases/getVersion";
19
+ export type { AppStorageInfo } from "./commands/entities/AppStorageInfo";
20
+ export { backupAppStorage } from "./commands/use-cases/app-backup/backupAppStorage";
21
+ export { getAppStorageInfo } from "./commands/use-cases/app-backup/getAppStorageInfo";
22
+ export { restoreAppStorage } from "./commands/use-cases/app-backup/restoreAppStorage";
23
+ export { restoreAppStorageCommit } from "./commands/use-cases/app-backup/restoreAppStorageCommit";
24
+ export { restoreAppStorageInit } from "./commands/use-cases/app-backup/restoreAppStorageInit";
19
25
  export { type CLSSupportedDeviceModelId, isCustomLockScreenSupported, } from "./capabilities/isCustomLockScreenSupported";
20
26
  export { isEditDeviceNameSupported } from "./capabilities/isEditDeviceNameSupported";
21
27
  export { isSyncOnboardingSupported } from "./capabilities/isSyncOnboardingSupported";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,YAAY,EACV,aAAa,EACb,WAAW,EACX,2BAA2B,GAC5B,MAAM,mDAAmD,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,mDAAmD,CAAC;AAC/F,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAEzF,YAAY,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EACL,KAAK,yBAAyB,EAC9B,2BAA2B,GAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAErF,cAAc,gCAAgC,CAAC;AAE/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,YAAY,EACV,aAAa,EACb,WAAW,EACX,2BAA2B,GAC5B,MAAM,mDAAmD,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,mDAAmD,CAAC;AAC/F,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAEzF,YAAY,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC;AAClG,OAAO,EAAE,qBAAqB,EAAE,MAAM,uDAAuD,CAAC;AAE9F,OAAO,EACL,KAAK,yBAAyB,EAC9B,2BAA2B,GAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAErF,cAAc,gCAAgC,CAAC;AAE/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC"}
package/lib-es/index.js CHANGED
@@ -12,6 +12,11 @@ export { getDeviceName } from "./commands/use-cases/getDeviceName";
12
12
  export { isHardwareVersionSupported } from "./commands/use-cases/isHardwareVersionSupported";
13
13
  export { isBootloaderVersionSupported } from "./commands/use-cases/isBootloaderVersionSupported";
14
14
  export { getVersion } from "./commands/use-cases/getVersion";
15
+ export { backupAppStorage } from "./commands/use-cases/app-backup/backupAppStorage";
16
+ export { getAppStorageInfo } from "./commands/use-cases/app-backup/getAppStorageInfo";
17
+ export { restoreAppStorage } from "./commands/use-cases/app-backup/restoreAppStorage";
18
+ export { restoreAppStorageCommit } from "./commands/use-cases/app-backup/restoreAppStorageCommit";
19
+ export { restoreAppStorageInit } from "./commands/use-cases/app-backup/restoreAppStorageInit";
15
20
  // src/capabilities/
16
21
  export { isCustomLockScreenSupported, } from "./capabilities/isCustomLockScreenSupported";
17
22
  export { isEditDeviceNameSupported } from "./capabilities/isEditDeviceNameSupported";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,mDAAmD,CAAC;AAC/F,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAGzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,oBAAoB;AACpB,OAAO,EAEL,2BAA2B,GAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AACrF,wBAAwB;AACxB,cAAc,gCAAgC,CAAC;AAC/C,sBAAsB;AACtB,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,mDAAmD,CAAC;AAC/F,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAGzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC;AAClG,OAAO,EAAE,qBAAqB,EAAE,MAAM,uDAAuD,CAAC;AAC9F,oBAAoB;AACpB,OAAO,EAEL,2BAA2B,GAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AACrF,wBAAwB;AACxB,cAAc,gCAAgC,CAAC;AAC/C,sBAAsB;AACtB,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/device-core",
3
- "version": "0.2.1-next.2",
3
+ "version": "0.3.0-nightly.0",
4
4
  "description": "Ledger Live device core module",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -20,12 +20,12 @@
20
20
  "dependencies": {
21
21
  "sha.js": "^2.4.11",
22
22
  "semver": "^7.3.5",
23
- "@ledgerhq/errors": "^6.17.0",
24
- "@ledgerhq/live-network": "^1.3.0",
25
- "@ledgerhq/hw-transport": "^6.31.0",
23
+ "@ledgerhq/errors": "^6.18.0-nightly.0",
24
+ "@ledgerhq/live-network": "^1.3.1-nightly.0",
25
+ "@ledgerhq/hw-transport": "^6.31.1-nightly.0",
26
26
  "@ledgerhq/logs": "^6.12.0",
27
- "@ledgerhq/devices": "^8.4.0",
28
- "@ledgerhq/types-live": "^6.48.1-next.0"
27
+ "@ledgerhq/devices": "^8.4.1-nightly.0",
28
+ "@ledgerhq/types-live": "^6.48.1-nightly.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@testing-library/react": "14",
@@ -0,0 +1,7 @@
1
+ export type AppStorageInfo = {
2
+ size: number;
3
+ dataVersion: string;
4
+ hasSettings: boolean;
5
+ hasData: boolean;
6
+ hash: string;
7
+ };
@@ -0,0 +1,52 @@
1
+ import Transport, { StatusCodes } from "@ledgerhq/hw-transport";
2
+ import { backupAppStorage, parseResponse } from "./backupAppStorage";
3
+ import { InternalComputeAesCmacFailed } from "../../../errors";
4
+
5
+ jest.mock("@ledgerhq/hw-transport");
6
+
7
+ describe("backupAppStorage", () => {
8
+ let transport: Transport;
9
+ const response = Buffer.from([
10
+ 0x31, 0x30, 0x36, 0x52, 0x75, 0x65, 0x64, 0x75, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x65, 0x90, 0x00,
11
+ ]);
12
+
13
+ beforeEach(() => {
14
+ transport = {
15
+ send: jest.fn().mockResolvedValue(response),
16
+ getTraceContext: jest.fn().mockResolvedValue(undefined),
17
+ } as unknown as Transport;
18
+ });
19
+
20
+ afterEach(() => {
21
+ jest.clearAllMocks();
22
+ });
23
+
24
+ it("should call the send function with correct parameters", async () => {
25
+ await backupAppStorage(transport);
26
+ expect(transport.send).toHaveBeenCalledWith(0xe0, 0x6b, 0x00, 0x00, Buffer.from([0x00]), [
27
+ StatusCodes.OK,
28
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
29
+ StatusCodes.GEN_AES_KEY_FAILED,
30
+ StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED,
31
+ StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
32
+ StatusCodes.ENCRYPT_APP_STORAGE_FAILED,
33
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
34
+ StatusCodes.INVALID_BACKUP_STATE,
35
+ ]);
36
+ });
37
+
38
+ describe("parseResponse", () => {
39
+ it("should parse the response data correctly", () => {
40
+ const expected = Buffer.from([
41
+ 0x31, 0x30, 0x36, 0x52, 0x75, 0x65, 0x64, 0x75, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x65,
42
+ ]);
43
+ expect(parseResponse(response)).toStrictEqual(expected);
44
+ });
45
+ it("should throw TransportStatusError if the response status is invalid", () => {
46
+ const data = Buffer.from([0x54, 0x1b]);
47
+ expect(() => parseResponse(data)).toThrow(
48
+ new InternalComputeAesCmacFailed("Internal error, failed to compute AES CMAC."),
49
+ );
50
+ });
51
+ });
52
+ });
@@ -0,0 +1,97 @@
1
+ import Transport, { StatusCodes, TransportStatusError } from "@ledgerhq/hw-transport";
2
+ import { LocalTracer } from "@ledgerhq/logs";
3
+ import type { APDU } from "../../entities/APDU";
4
+ import {
5
+ GenerateAesKeyFailed,
6
+ InternalComputeAesCmacFailed,
7
+ InternalCryptoOperationFailed,
8
+ InvalidBackupState,
9
+ InvalidContext,
10
+ } from "../../../errors";
11
+
12
+ /**
13
+ * Name in documentation: INS_APP_STORAGE_BACKUP
14
+ * cla: 0xe0
15
+ * ins: 0x6b
16
+ * p1: 0x00
17
+ * p2: 0x00
18
+ * lc: 0x00
19
+ */
20
+ const BACKUP_APP_STORAGE = [0xe0, 0x6b, 0x00, 0x00] as const;
21
+
22
+ /**
23
+ * 0x9000: Success.
24
+ * 0x5123: Invalid context, Get Info must be called.
25
+ * 0x5419: Failed to generate AES key.
26
+ * 0x541A: Internal error, crypto operation failed.
27
+ * 0x541B: Internal error, failed to compute AES CMAC.
28
+ * 0x541C: Failed to encrypt the app storage backup.
29
+ * 0x662F: Invalid device state, recovery mode.
30
+ * 0x6642: Invalid backup state, backup already performed.
31
+ */
32
+ const RESPONSE_STATUS_SET: number[] = [
33
+ StatusCodes.OK,
34
+ StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
35
+ StatusCodes.GEN_AES_KEY_FAILED,
36
+ StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED,
37
+ StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
38
+ StatusCodes.ENCRYPT_APP_STORAGE_FAILED,
39
+ StatusCodes.DEVICE_IN_RECOVERY_MODE,
40
+ StatusCodes.INVALID_BACKUP_STATE,
41
+ ];
42
+
43
+ /**
44
+ * Retrieves the app storage information (chunk) from the device and returns it
45
+ * as a buffer.
46
+ *
47
+ * @param transport - The transport object used to communicate with the device.
48
+ * @returns A promise that resolves to the app storage information as a buffer.
49
+ */
50
+ export async function backupAppStorage(transport: Transport): Promise<Buffer> {
51
+ const tracer = new LocalTracer("hw", {
52
+ transport: transport.getTraceContext(),
53
+ function: "backupAppStorage",
54
+ });
55
+ tracer.trace("Start");
56
+
57
+ const apdu: Readonly<APDU> = [...BACKUP_APP_STORAGE, Buffer.from([0x00])];
58
+
59
+ const response = await transport.send(...apdu, RESPONSE_STATUS_SET);
60
+
61
+ return parseResponse(response);
62
+ }
63
+
64
+ /**
65
+ * Parses the response data buffer, check the status code and return the data.
66
+ *
67
+ * @param data - The response data buffer w/ status code.
68
+ * @returns The response data as a buffer w/o status code.
69
+ */
70
+ export function parseResponse(data: Buffer): Buffer {
71
+ const tracer = new LocalTracer("hw", {
72
+ function: "parseResponse@backupAppStorage",
73
+ });
74
+ const status = data.readUInt16BE(data.length - 2);
75
+ tracer.trace("Result status from 0xe06b0000", { status });
76
+
77
+ switch (status) {
78
+ case StatusCodes.OK:
79
+ return data.subarray(0, data.length - 2);
80
+ case StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
81
+ throw new InvalidContext("Invalid context, getAppStorageInfo must be called.");
82
+ case StatusCodes.GEN_AES_KEY_FAILED:
83
+ throw new GenerateAesKeyFailed("Failed to generate AES key.");
84
+ case StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED:
85
+ throw new InternalCryptoOperationFailed("Internal error, crypto operation failed.");
86
+ case StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED:
87
+ throw new InternalComputeAesCmacFailed("Internal error, failed to compute AES CMAC.");
88
+ case StatusCodes.ENCRYPT_APP_STORAGE_FAILED:
89
+ throw new GenerateAesKeyFailed("Failed to encrypt the app storage backup.");
90
+ case StatusCodes.DEVICE_IN_RECOVERY_MODE:
91
+ break;
92
+ case StatusCodes.INVALID_BACKUP_STATE:
93
+ throw new InvalidBackupState("Invalid backup state, backup already performed.");
94
+ }
95
+
96
+ throw new TransportStatusError(status);
97
+ }