@ledgerhq/device-core 0.2.1-next.2 → 0.3.0-nightly.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -11
- package/lib/commands/entities/AppStorageInfo.d.ts +8 -0
- package/lib/commands/entities/AppStorageInfo.d.ts.map +1 -0
- package/lib/commands/entities/AppStorageInfo.js +3 -0
- package/lib/commands/entities/AppStorageInfo.js.map +1 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.d.ts +18 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.js +98 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.js.map +1 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.test.d.ts +2 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.test.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.test.js +56 -0
- package/lib/commands/use-cases/app-backup/backupAppStorage.test.js.map +1 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.d.ts +20 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.js +104 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.js.map +1 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts +2 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.js +59 -0
- package/lib/commands/use-cases/app-backup/getAppStorageInfo.test.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.d.ts +12 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.js +93 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.test.d.ts +2 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.test.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.test.js +54 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorage.test.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts +11 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.js +83 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts +2 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.js +49 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageCommit.test.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.d.ts +13 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.js +99 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.js.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts +2 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts.map +1 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.js +52 -0
- package/lib/commands/use-cases/app-backup/restoreAppStorageInit.test.js.map +1 -0
- package/lib/errors.d.ts +40 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +30 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +11 -1
- package/lib/index.js.map +1 -1
- package/lib-es/commands/entities/AppStorageInfo.d.ts +8 -0
- package/lib-es/commands/entities/AppStorageInfo.d.ts.map +1 -0
- package/lib-es/commands/entities/AppStorageInfo.js +2 -0
- package/lib-es/commands/entities/AppStorageInfo.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.d.ts +18 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.js +93 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.d.ts +2 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.js +54 -0
- package/lib-es/commands/use-cases/app-backup/backupAppStorage.test.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.d.ts +20 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.js +99 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts +2 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.js +57 -0
- package/lib-es/commands/use-cases/app-backup/getAppStorageInfo.test.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.d.ts +12 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.js +88 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.d.ts +2 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.js +52 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorage.test.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts +11 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.js +78 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts +2 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.js +47 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageCommit.test.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.d.ts +13 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.js +94 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.js.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts +2 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.d.ts.map +1 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.js +50 -0
- package/lib-es/commands/use-cases/app-backup/restoreAppStorageInit.test.js.map +1 -0
- package/lib-es/errors.d.ts +40 -0
- package/lib-es/errors.d.ts.map +1 -0
- package/lib-es/errors.js +27 -0
- package/lib-es/errors.js.map +1 -0
- package/lib-es/index.d.ts +6 -0
- package/lib-es/index.d.ts.map +1 -1
- package/lib-es/index.js +5 -0
- package/lib-es/index.js.map +1 -1
- package/package.json +6 -6
- package/src/commands/entities/AppStorageInfo.ts +7 -0
- package/src/commands/use-cases/app-backup/backupAppStorage.test.ts +52 -0
- package/src/commands/use-cases/app-backup/backupAppStorage.ts +97 -0
- package/src/commands/use-cases/app-backup/getAppStorageInfo.test.ts +63 -0
- package/src/commands/use-cases/app-backup/getAppStorageInfo.ts +102 -0
- package/src/commands/use-cases/app-backup/restoreAppStorage.test.ts +57 -0
- package/src/commands/use-cases/app-backup/restoreAppStorage.ts +93 -0
- package/src/commands/use-cases/app-backup/restoreAppStorageCommit.test.ts +45 -0
- package/src/commands/use-cases/app-backup/restoreAppStorageCommit.ts +82 -0
- package/src/commands/use-cases/app-backup/restoreAppStorageInit.test.ts +55 -0
- package/src/commands/use-cases/app-backup/restoreAppStorageInit.ts +96 -0
- package/src/errors.ts +29 -0
- package/src/index.ts +6 -0
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
# @ledgerhq/device-core
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.3.0-nightly.1
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Updated dependencies [[`ef2d53d`](https://github.com/LedgerHQ/ledger-live/commit/ef2d53d514f1f4e6f18fc79fa3423bd9b0208a04)]:
|
|
8
|
+
- @ledgerhq/types-live@6.49.0-nightly.1
|
|
8
9
|
|
|
9
|
-
## 0.
|
|
10
|
+
## 0.3.0-nightly.0
|
|
10
11
|
|
|
11
|
-
###
|
|
12
|
-
|
|
13
|
-
- [#7157](https://github.com/LedgerHQ/ledger-live/pull/7157) [`38a18fd`](https://github.com/LedgerHQ/ledger-live/commit/38a18fdb7233b77dfd631d10d9eec3cd4aeefe9f) Thanks [@jdabbech-ledger](https://github.com/jdabbech-ledger)! - Reload app restauration if device disconnected after firmware update with language pack
|
|
12
|
+
### Minor Changes
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
- [#7124](https://github.com/LedgerHQ/ledger-live/pull/7124) [`e78f3b7`](https://github.com/LedgerHQ/ledger-live/commit/e78f3b75296c7a063f6cddbeae44c36d236055f3) Thanks [@jiyuzhuang](https://github.com/jiyuzhuang)! - Implement App data backup relative commands
|
|
16
15
|
|
|
17
16
|
### Patch Changes
|
|
18
17
|
|
|
19
|
-
- [
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
- @ledgerhq/
|
|
18
|
+
- Updated dependencies [[`1cbf767`](https://github.com/LedgerHQ/ledger-live/commit/1cbf767465d9e1f7bed5de79c5b5a0a5ca06e1b5), [`e78f3b7`](https://github.com/LedgerHQ/ledger-live/commit/e78f3b75296c7a063f6cddbeae44c36d236055f3)]:
|
|
19
|
+
- @ledgerhq/types-live@6.48.1-nightly.0
|
|
20
|
+
- @ledgerhq/errors@6.18.0-nightly.0
|
|
21
|
+
- @ledgerhq/devices@8.4.1-nightly.0
|
|
22
|
+
- @ledgerhq/hw-transport@6.31.1-nightly.0
|
|
23
|
+
- @ledgerhq/live-network@1.3.1-nightly.0
|
|
23
24
|
|
|
24
25
|
## 0.2.0
|
|
25
26
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppStorageInfo.d.ts","sourceRoot":"","sources":["../../../src/commands/entities/AppStorageInfo.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppStorageInfo.js","sourceRoot":"","sources":["../../../src/commands/entities/AppStorageInfo.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves the app storage information (chunk) from the device and returns it
|
|
5
|
+
* as a buffer.
|
|
6
|
+
*
|
|
7
|
+
* @param transport - The transport object used to communicate with the device.
|
|
8
|
+
* @returns A promise that resolves to the app storage information as a buffer.
|
|
9
|
+
*/
|
|
10
|
+
export declare function backupAppStorage(transport: Transport): Promise<Buffer>;
|
|
11
|
+
/**
|
|
12
|
+
* Parses the response data buffer, check the status code and return the data.
|
|
13
|
+
*
|
|
14
|
+
* @param data - The response data buffer w/ status code.
|
|
15
|
+
* @returns The response data as a buffer w/o status code.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseResponse(data: Buffer): Buffer;
|
|
18
|
+
//# sourceMappingURL=backupAppStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupAppStorage.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/backupAppStorage.ts"],"names":[],"mappings":";AAAA,OAAO,SAAgD,MAAM,wBAAwB,CAAC;AA0CtF;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA2BlD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseResponse = exports.backupAppStorage = void 0;
|
|
13
|
+
const hw_transport_1 = require("@ledgerhq/hw-transport");
|
|
14
|
+
const logs_1 = require("@ledgerhq/logs");
|
|
15
|
+
const errors_1 = require("../../../errors");
|
|
16
|
+
/**
|
|
17
|
+
* Name in documentation: INS_APP_STORAGE_BACKUP
|
|
18
|
+
* cla: 0xe0
|
|
19
|
+
* ins: 0x6b
|
|
20
|
+
* p1: 0x00
|
|
21
|
+
* p2: 0x00
|
|
22
|
+
* lc: 0x00
|
|
23
|
+
*/
|
|
24
|
+
const BACKUP_APP_STORAGE = [0xe0, 0x6b, 0x00, 0x00];
|
|
25
|
+
/**
|
|
26
|
+
* 0x9000: Success.
|
|
27
|
+
* 0x5123: Invalid context, Get Info must be called.
|
|
28
|
+
* 0x5419: Failed to generate AES key.
|
|
29
|
+
* 0x541A: Internal error, crypto operation failed.
|
|
30
|
+
* 0x541B: Internal error, failed to compute AES CMAC.
|
|
31
|
+
* 0x541C: Failed to encrypt the app storage backup.
|
|
32
|
+
* 0x662F: Invalid device state, recovery mode.
|
|
33
|
+
* 0x6642: Invalid backup state, backup already performed.
|
|
34
|
+
*/
|
|
35
|
+
const RESPONSE_STATUS_SET = [
|
|
36
|
+
hw_transport_1.StatusCodes.OK,
|
|
37
|
+
hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
|
|
38
|
+
hw_transport_1.StatusCodes.GEN_AES_KEY_FAILED,
|
|
39
|
+
hw_transport_1.StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED,
|
|
40
|
+
hw_transport_1.StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
|
|
41
|
+
hw_transport_1.StatusCodes.ENCRYPT_APP_STORAGE_FAILED,
|
|
42
|
+
hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE,
|
|
43
|
+
hw_transport_1.StatusCodes.INVALID_BACKUP_STATE,
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Retrieves the app storage information (chunk) from the device and returns it
|
|
47
|
+
* as a buffer.
|
|
48
|
+
*
|
|
49
|
+
* @param transport - The transport object used to communicate with the device.
|
|
50
|
+
* @returns A promise that resolves to the app storage information as a buffer.
|
|
51
|
+
*/
|
|
52
|
+
function backupAppStorage(transport) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
55
|
+
transport: transport.getTraceContext(),
|
|
56
|
+
function: "backupAppStorage",
|
|
57
|
+
});
|
|
58
|
+
tracer.trace("Start");
|
|
59
|
+
const apdu = [...BACKUP_APP_STORAGE, Buffer.from([0x00])];
|
|
60
|
+
const response = yield transport.send(...apdu, RESPONSE_STATUS_SET);
|
|
61
|
+
return parseResponse(response);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
exports.backupAppStorage = backupAppStorage;
|
|
65
|
+
/**
|
|
66
|
+
* Parses the response data buffer, check the status code and return the data.
|
|
67
|
+
*
|
|
68
|
+
* @param data - The response data buffer w/ status code.
|
|
69
|
+
* @returns The response data as a buffer w/o status code.
|
|
70
|
+
*/
|
|
71
|
+
function parseResponse(data) {
|
|
72
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
73
|
+
function: "parseResponse@backupAppStorage",
|
|
74
|
+
});
|
|
75
|
+
const status = data.readUInt16BE(data.length - 2);
|
|
76
|
+
tracer.trace("Result status from 0xe06b0000", { status });
|
|
77
|
+
switch (status) {
|
|
78
|
+
case hw_transport_1.StatusCodes.OK:
|
|
79
|
+
return data.subarray(0, data.length - 2);
|
|
80
|
+
case hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
|
|
81
|
+
throw new errors_1.InvalidContext("Invalid context, getAppStorageInfo must be called.");
|
|
82
|
+
case hw_transport_1.StatusCodes.GEN_AES_KEY_FAILED:
|
|
83
|
+
throw new errors_1.GenerateAesKeyFailed("Failed to generate AES key.");
|
|
84
|
+
case hw_transport_1.StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED:
|
|
85
|
+
throw new errors_1.InternalCryptoOperationFailed("Internal error, crypto operation failed.");
|
|
86
|
+
case hw_transport_1.StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED:
|
|
87
|
+
throw new errors_1.InternalComputeAesCmacFailed("Internal error, failed to compute AES CMAC.");
|
|
88
|
+
case hw_transport_1.StatusCodes.ENCRYPT_APP_STORAGE_FAILED:
|
|
89
|
+
throw new errors_1.GenerateAesKeyFailed("Failed to encrypt the app storage backup.");
|
|
90
|
+
case hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE:
|
|
91
|
+
break;
|
|
92
|
+
case hw_transport_1.StatusCodes.INVALID_BACKUP_STATE:
|
|
93
|
+
throw new errors_1.InvalidBackupState("Invalid backup state, backup already performed.");
|
|
94
|
+
}
|
|
95
|
+
throw new hw_transport_1.TransportStatusError(status);
|
|
96
|
+
}
|
|
97
|
+
exports.parseResponse = parseResponse;
|
|
98
|
+
//# sourceMappingURL=backupAppStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupAppStorage.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/backupAppStorage.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yDAAsF;AACtF,yCAA6C;AAE7C,4CAMyB;AAEzB;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAE7D;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAa;IACpC,0BAAW,CAAC,EAAE;IACd,0BAAW,CAAC,gCAAgC;IAC5C,0BAAW,CAAC,kBAAkB;IAC9B,0BAAW,CAAC,gCAAgC;IAC5C,0BAAW,CAAC,gCAAgC;IAC5C,0BAAW,CAAC,0BAA0B;IACtC,0BAAW,CAAC,uBAAuB;IACnC,0BAAW,CAAC,oBAAoB;CACjC,CAAC;AAEF;;;;;;GAMG;AACH,SAAsB,gBAAgB,CAAC,SAAoB;;QACzD,MAAM,MAAM,GAAG,IAAI,kBAAW,CAAC,IAAI,EAAE;YACnC,SAAS,EAAE,SAAS,CAAC,eAAe,EAAE;YACtC,QAAQ,EAAE,kBAAkB;SAC7B,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEtB,MAAM,IAAI,GAAmB,CAAC,GAAG,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE1E,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAEpE,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;CAAA;AAZD,4CAYC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,IAAI,kBAAW,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,gCAAgC;KAC3C,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,0BAAW,CAAC,EAAE;YACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3C,KAAK,0BAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,uBAAc,CAAC,oDAAoD,CAAC,CAAC;QACjF,KAAK,0BAAW,CAAC,kBAAkB;YACjC,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;QAChE,KAAK,0BAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,sCAA6B,CAAC,0CAA0C,CAAC,CAAC;QACtF,KAAK,0BAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,qCAA4B,CAAC,6CAA6C,CAAC,CAAC;QACxF,KAAK,0BAAW,CAAC,0BAA0B;YACzC,MAAM,IAAI,6BAAoB,CAAC,2CAA2C,CAAC,CAAC;QAC9E,KAAK,0BAAW,CAAC,uBAAuB;YACtC,MAAM;QACR,KAAK,0BAAW,CAAC,oBAAoB;YACnC,MAAM,IAAI,2BAAkB,CAAC,iDAAiD,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,IAAI,mCAAoB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AA3BD,sCA2BC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupAppStorage.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/backupAppStorage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const hw_transport_1 = require("@ledgerhq/hw-transport");
|
|
13
|
+
const backupAppStorage_1 = require("./backupAppStorage");
|
|
14
|
+
const errors_1 = require("../../../errors");
|
|
15
|
+
jest.mock("@ledgerhq/hw-transport");
|
|
16
|
+
describe("backupAppStorage", () => {
|
|
17
|
+
let transport;
|
|
18
|
+
const response = Buffer.from([
|
|
19
|
+
0x31, 0x30, 0x36, 0x52, 0x75, 0x65, 0x64, 0x75, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x65, 0x90, 0x00,
|
|
20
|
+
]);
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
transport = {
|
|
23
|
+
send: jest.fn().mockResolvedValue(response),
|
|
24
|
+
getTraceContext: jest.fn().mockResolvedValue(undefined),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
});
|
|
30
|
+
it("should call the send function with correct parameters", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
yield (0, backupAppStorage_1.backupAppStorage)(transport);
|
|
32
|
+
expect(transport.send).toHaveBeenCalledWith(0xe0, 0x6b, 0x00, 0x00, Buffer.from([0x00]), [
|
|
33
|
+
hw_transport_1.StatusCodes.OK,
|
|
34
|
+
hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
|
|
35
|
+
hw_transport_1.StatusCodes.GEN_AES_KEY_FAILED,
|
|
36
|
+
hw_transport_1.StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED,
|
|
37
|
+
hw_transport_1.StatusCodes.INTERNAL_COMPUTE_AES_CMAC_FAILED,
|
|
38
|
+
hw_transport_1.StatusCodes.ENCRYPT_APP_STORAGE_FAILED,
|
|
39
|
+
hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE,
|
|
40
|
+
hw_transport_1.StatusCodes.INVALID_BACKUP_STATE,
|
|
41
|
+
]);
|
|
42
|
+
}));
|
|
43
|
+
describe("parseResponse", () => {
|
|
44
|
+
it("should parse the response data correctly", () => {
|
|
45
|
+
const expected = Buffer.from([
|
|
46
|
+
0x31, 0x30, 0x36, 0x52, 0x75, 0x65, 0x64, 0x75, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x65,
|
|
47
|
+
]);
|
|
48
|
+
expect((0, backupAppStorage_1.parseResponse)(response)).toStrictEqual(expected);
|
|
49
|
+
});
|
|
50
|
+
it("should throw TransportStatusError if the response status is invalid", () => {
|
|
51
|
+
const data = Buffer.from([0x54, 0x1b]);
|
|
52
|
+
expect(() => (0, backupAppStorage_1.parseResponse)(data)).toThrow(new errors_1.InternalComputeAesCmacFailed("Internal error, failed to compute AES CMAC."));
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=backupAppStorage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupAppStorage.test.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/backupAppStorage.test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,yDAAgE;AAChE,yDAAqE;AACrE,4CAA+D;AAE/D,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAEpC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,SAAoB,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;KAC/F,CAAC,CAAC;IAEH,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,IAAA,mCAAgB,EAAC,SAAS,CAAC,CAAC;QAClC,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,0BAAW,CAAC,EAAE;YACd,0BAAW,CAAC,gCAAgC;YAC5C,0BAAW,CAAC,kBAAkB;YAC9B,0BAAW,CAAC,gCAAgC;YAC5C,0BAAW,CAAC,gCAAgC;YAC5C,0BAAW,CAAC,0BAA0B;YACtC,0BAAW,CAAC,uBAAuB;YACnC,0BAAW,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,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;gBAC3B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;aACnF,CAAC,CAAC;YACH,MAAM,CAAC,IAAA,gCAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1D,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,IAAA,gCAAa,EAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACvC,IAAI,qCAA4B,CAAC,6CAA6C,CAAC,CAChF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import type { AppStorageInfo } from "../../entities/AppStorageInfo";
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves the application storage information from the device.
|
|
6
|
+
*
|
|
7
|
+
* @param transport - The transport object used to communicate with the device.
|
|
8
|
+
* @param appName - The name of the application to retrieve the storage information for.
|
|
9
|
+
* @returns A promise that resolves to the application storage information object.
|
|
10
|
+
* @throws {TransportStatusError} If the response status is invalid.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAppStorageInfo(transport: Transport, appName: string): Promise<AppStorageInfo>;
|
|
13
|
+
/**
|
|
14
|
+
* Parses the response data from the device into a string.
|
|
15
|
+
*
|
|
16
|
+
* @param data - The response data received from the device.
|
|
17
|
+
* @returns A string representing the parsed response.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseResponse(data: Buffer): AppStorageInfo;
|
|
20
|
+
//# sourceMappingURL=getAppStorageInfo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAppStorageInfo.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/getAppStorageInfo.ts"],"names":[],"mappings":";AAAA,OAAO,SAAgD,MAAM,wBAAwB,CAAC;AAEtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AA2BpE;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAqC1D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseResponse = exports.getAppStorageInfo = void 0;
|
|
13
|
+
const hw_transport_1 = require("@ledgerhq/hw-transport");
|
|
14
|
+
const logs_1 = require("@ledgerhq/logs");
|
|
15
|
+
const errors_1 = require("../../../errors");
|
|
16
|
+
/**
|
|
17
|
+
* Name in documentation: INS_APP_STORAGE_GET_INFO
|
|
18
|
+
* cla: 0xe0
|
|
19
|
+
* ins: 0x6a
|
|
20
|
+
* p1: 0x00
|
|
21
|
+
* p2: 0x00
|
|
22
|
+
* data: APP_NAME_LEN (1 byte) + APP_NAME (variable) to configure at runtime
|
|
23
|
+
*/
|
|
24
|
+
const GET_APP_STORAGE_INFO = [0xe0, 0x6a, 0x00, 0x00];
|
|
25
|
+
/**
|
|
26
|
+
* 0x9000: Success.
|
|
27
|
+
* 0x5123: Application not found.
|
|
28
|
+
* 0x662F: If the device is in recovery mode.
|
|
29
|
+
* 0x670A: Invalid application name length, two chars minimum.
|
|
30
|
+
*/
|
|
31
|
+
const RESPONSE_STATUS_SET = [
|
|
32
|
+
hw_transport_1.StatusCodes.OK,
|
|
33
|
+
hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
|
|
34
|
+
hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE,
|
|
35
|
+
hw_transport_1.StatusCodes.INVALID_APP_NAME_LENGTH,
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Retrieves the application storage information from the device.
|
|
39
|
+
*
|
|
40
|
+
* @param transport - The transport object used to communicate with the device.
|
|
41
|
+
* @param appName - The name of the application to retrieve the storage information for.
|
|
42
|
+
* @returns A promise that resolves to the application storage information object.
|
|
43
|
+
* @throws {TransportStatusError} If the response status is invalid.
|
|
44
|
+
*/
|
|
45
|
+
function getAppStorageInfo(transport, appName) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
48
|
+
transport: transport.getTraceContext(),
|
|
49
|
+
function: "getAppStorageInfo",
|
|
50
|
+
});
|
|
51
|
+
tracer.trace("Start");
|
|
52
|
+
const params = Buffer.concat([
|
|
53
|
+
Buffer.from([appName.length]),
|
|
54
|
+
Buffer.from(appName, "ascii"),
|
|
55
|
+
]);
|
|
56
|
+
const apdu = [...GET_APP_STORAGE_INFO, params];
|
|
57
|
+
const response = yield transport.send(...apdu, RESPONSE_STATUS_SET);
|
|
58
|
+
return parseResponse(response);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
exports.getAppStorageInfo = getAppStorageInfo;
|
|
62
|
+
/**
|
|
63
|
+
* Parses the response data from the device into a string.
|
|
64
|
+
*
|
|
65
|
+
* @param data - The response data received from the device.
|
|
66
|
+
* @returns A string representing the parsed response.
|
|
67
|
+
*/
|
|
68
|
+
function parseResponse(data) {
|
|
69
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
70
|
+
function: "parseResponse@getAppStorageInfo",
|
|
71
|
+
});
|
|
72
|
+
const status = data.readUInt16BE(data.length - 2);
|
|
73
|
+
tracer.trace("Result status from 0xe06a0000", { status });
|
|
74
|
+
switch (status) {
|
|
75
|
+
case hw_transport_1.StatusCodes.OK: {
|
|
76
|
+
/**
|
|
77
|
+
* The backup size is a 4-byte unsigned integer.
|
|
78
|
+
* The data version is a 4-byte string.
|
|
79
|
+
* The hasSettings and hasData flags are 1-byte booleans.
|
|
80
|
+
* The hash is a 32-byte string.
|
|
81
|
+
*/
|
|
82
|
+
let offset = 0;
|
|
83
|
+
const size = data.readUInt32BE(offset); // Len = 4
|
|
84
|
+
offset += 4;
|
|
85
|
+
const dataVersion = data.subarray(offset, offset + 4).toString(); // Len = 4
|
|
86
|
+
offset += 4;
|
|
87
|
+
const hasSettings = data.readUIntBE(offset, 1) === 1; // Len = 1
|
|
88
|
+
offset += 1;
|
|
89
|
+
const hasData = data.readUIntBE(offset, 1) === 1; // Len = 1
|
|
90
|
+
offset += 1;
|
|
91
|
+
const hash = data.subarray(offset, offset + 32).toString(); // Len = 32
|
|
92
|
+
return { size, dataVersion, hasSettings, hasData, hash };
|
|
93
|
+
}
|
|
94
|
+
case hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
|
|
95
|
+
throw new errors_1.AppNotFound("Application not found.");
|
|
96
|
+
case hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE:
|
|
97
|
+
break;
|
|
98
|
+
case hw_transport_1.StatusCodes.INVALID_APP_NAME_LENGTH:
|
|
99
|
+
throw new errors_1.InvalidAppNameLength("Invalid application name length, two chars minimum.");
|
|
100
|
+
}
|
|
101
|
+
throw new hw_transport_1.TransportStatusError(status);
|
|
102
|
+
}
|
|
103
|
+
exports.parseResponse = parseResponse;
|
|
104
|
+
//# sourceMappingURL=getAppStorageInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAppStorageInfo.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/getAppStorageInfo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAppStorageInfo.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/getAppStorageInfo.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const hw_transport_1 = require("@ledgerhq/hw-transport");
|
|
13
|
+
const getAppStorageInfo_1 = require("./getAppStorageInfo");
|
|
14
|
+
const errors_1 = require("../../../errors");
|
|
15
|
+
jest.mock("@ledgerhq/hw-transport");
|
|
16
|
+
describe("getAppStorageInfo", () => {
|
|
17
|
+
let transport;
|
|
18
|
+
const response = Buffer.from([
|
|
19
|
+
0x00, 0x00, 0x04, 0xd2, 0x31, 0x2e, 0x30, 0x31, 0x01, 0x01, 0x68, 0x61, 0x73, 0x68, 0x68, 0x61,
|
|
20
|
+
0x73, 0x68, 0x31, 0x32, 0x33, 0x34, 0x68, 0x61, 0x73, 0x68, 0x68, 0x61, 0x73, 0x68, 0x68, 0x61,
|
|
21
|
+
0x73, 0x68, 0x68, 0x61, 0x73, 0x68, 0x68, 0x61, 0x73, 0x68, 0x90, 0x00,
|
|
22
|
+
]);
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
transport = {
|
|
25
|
+
send: jest.fn().mockResolvedValue(response),
|
|
26
|
+
getTraceContext: jest.fn().mockResolvedValue(undefined),
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
jest.clearAllMocks();
|
|
31
|
+
});
|
|
32
|
+
it("should call the send function with correct parameters", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
const appName = "MyApp";
|
|
34
|
+
yield (0, getAppStorageInfo_1.getAppStorageInfo)(transport, appName);
|
|
35
|
+
expect(transport.send).toHaveBeenCalledWith(0xe0, 0x6a, 0x00, 0x00, Buffer.from([0x05, 0x4d, 0x79, 0x41, 0x70, 0x70]), [
|
|
36
|
+
hw_transport_1.StatusCodes.OK,
|
|
37
|
+
hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
|
|
38
|
+
hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE,
|
|
39
|
+
hw_transport_1.StatusCodes.INVALID_APP_NAME_LENGTH,
|
|
40
|
+
]);
|
|
41
|
+
}));
|
|
42
|
+
describe("parseResponse", () => {
|
|
43
|
+
it("should parse the response data correctly", () => {
|
|
44
|
+
const expected = {
|
|
45
|
+
size: 1234,
|
|
46
|
+
dataVersion: "1.01",
|
|
47
|
+
hasSettings: true,
|
|
48
|
+
hasData: true,
|
|
49
|
+
hash: "hashhash1234hashhashhashhashhash",
|
|
50
|
+
};
|
|
51
|
+
expect((0, getAppStorageInfo_1.parseResponse)(response)).toStrictEqual(expected);
|
|
52
|
+
});
|
|
53
|
+
it("should throw TransportStatusError if the response status is invalid", () => {
|
|
54
|
+
const data = Buffer.from([0x67, 0x0a]);
|
|
55
|
+
expect(() => (0, getAppStorageInfo_1.parseResponse)(data)).toThrow(new errors_1.InvalidAppNameLength("Invalid application name length, two chars minimum."));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=getAppStorageInfo.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAppStorageInfo.test.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/getAppStorageInfo.test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,yDAAgE;AAChE,2DAAuE;AAEvE,4CAAuD;AAEvD,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAEpC,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,SAAoB,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;QAC9F,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;QAC9F,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;KACvE,CAAC,CAAC;IAEH,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,IAAA,qCAAiB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5C,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,CAAC,CAAC,EACjD;YACE,0BAAW,CAAC,EAAE;YACd,0BAAW,CAAC,gCAAgC;YAC5C,0BAAW,CAAC,uBAAuB;YACnC,0BAAW,CAAC,uBAAuB;SACpC,CACF,CAAC;IACJ,CAAC,CAAA,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,QAAQ,GAAmB;gBAC/B,IAAI,EAAE,IAAI;gBACV,WAAW,EAAE,MAAM;gBACnB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,kCAAkC;aACzC,CAAC;YACF,MAAM,CAAC,IAAA,iCAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1D,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,IAAA,iCAAa,EAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACvC,IAAI,6BAAoB,CAAC,qDAAqD,CAAC,CAChF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
/**
|
|
4
|
+
* Restores the application storage.
|
|
5
|
+
*
|
|
6
|
+
* @param transport - The transport object used for communication with the device.
|
|
7
|
+
* @param chunk - The chunk of data to restore.
|
|
8
|
+
* @returns A promise that resolves to void.
|
|
9
|
+
*/
|
|
10
|
+
export declare function restoreAppStorage(transport: Transport, chunk: Buffer): Promise<void>;
|
|
11
|
+
export declare function parseResponse(data: Buffer): void;
|
|
12
|
+
//# sourceMappingURL=restoreAppStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restoreAppStorage.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorage.ts"],"names":[],"mappings":";AAAA,OAAO,SAAgD,MAAM,wBAAwB,CAAC;AA2CtF;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA2BhD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseResponse = exports.restoreAppStorage = void 0;
|
|
13
|
+
const hw_transport_1 = require("@ledgerhq/hw-transport");
|
|
14
|
+
const logs_1 = require("@ledgerhq/logs");
|
|
15
|
+
const errors_1 = require("../../../errors");
|
|
16
|
+
/**
|
|
17
|
+
* Name in documentation: INS_APP_STORAGE_GET_INFO
|
|
18
|
+
* cla: 0xe0
|
|
19
|
+
* ins: 0x6d
|
|
20
|
+
* p1: 0x00
|
|
21
|
+
* p2: 0x00
|
|
22
|
+
* data: CHUNK_LEN + CHUNK to configure at runtime
|
|
23
|
+
*/
|
|
24
|
+
const RESTORE_APP_STORAGE = [0xe0, 0x6d, 0x00, 0x00];
|
|
25
|
+
/**
|
|
26
|
+
* 0x9000: Success.
|
|
27
|
+
* 0x5123: Invalid context, Restore Init must be called first.
|
|
28
|
+
* 0x5419: Failed to generate AES key.
|
|
29
|
+
* 0x541A: Failed to decrypt the app storage backup.
|
|
30
|
+
* 0x662F: Invalid device state, recovery mode.
|
|
31
|
+
* 0x6643: Invalid restore state, restore already performed.
|
|
32
|
+
* 0x6734: Invalid CHUNK_LEN.
|
|
33
|
+
* 0x684A: Invalid backup, app storage header is not valid.
|
|
34
|
+
*/
|
|
35
|
+
const RESPONSE_STATUS_SET = [
|
|
36
|
+
hw_transport_1.StatusCodes.OK,
|
|
37
|
+
hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT,
|
|
38
|
+
hw_transport_1.StatusCodes.GEN_AES_KEY_FAILED,
|
|
39
|
+
hw_transport_1.StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED,
|
|
40
|
+
hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE,
|
|
41
|
+
hw_transport_1.StatusCodes.INVALID_RESTORE_STATE,
|
|
42
|
+
hw_transport_1.StatusCodes.INVALID_CHUNK_LENGTH,
|
|
43
|
+
hw_transport_1.StatusCodes.INVALID_BACKUP_HEADER,
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Restores the application storage.
|
|
47
|
+
*
|
|
48
|
+
* @param transport - The transport object used for communication with the device.
|
|
49
|
+
* @param chunk - The chunk of data to restore.
|
|
50
|
+
* @returns A promise that resolves to void.
|
|
51
|
+
*/
|
|
52
|
+
function restoreAppStorage(transport, chunk) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
55
|
+
transport: transport.getTraceContext(),
|
|
56
|
+
function: "restoreAppStorage",
|
|
57
|
+
});
|
|
58
|
+
tracer.trace("Start");
|
|
59
|
+
const params = Buffer.concat([Buffer.from([chunk.length]), chunk]);
|
|
60
|
+
const apdu = [...RESTORE_APP_STORAGE, params];
|
|
61
|
+
const response = yield transport.send(...apdu, RESPONSE_STATUS_SET);
|
|
62
|
+
parseResponse(response);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
exports.restoreAppStorage = restoreAppStorage;
|
|
66
|
+
function parseResponse(data) {
|
|
67
|
+
const tracer = new logs_1.LocalTracer("hw", {
|
|
68
|
+
function: "parseResponse@restoreAppStorage",
|
|
69
|
+
});
|
|
70
|
+
const status = data.readUInt16BE(data.length - 2);
|
|
71
|
+
tracer.trace("Result status from 0xe06d0000", { status });
|
|
72
|
+
switch (status) {
|
|
73
|
+
case hw_transport_1.StatusCodes.OK:
|
|
74
|
+
return;
|
|
75
|
+
case hw_transport_1.StatusCodes.APP_NOT_FOUND_OR_INVALID_CONTEXT:
|
|
76
|
+
throw new errors_1.InvalidContext("Invalid context, restoreAppStorageInit must be called first.");
|
|
77
|
+
case hw_transport_1.StatusCodes.GEN_AES_KEY_FAILED:
|
|
78
|
+
throw new errors_1.GenerateAesKeyFailed("Failed to generate AES key.");
|
|
79
|
+
case hw_transport_1.StatusCodes.INTERNAL_CRYPTO_OPERATION_FAILED:
|
|
80
|
+
throw new errors_1.InternalCryptoOperationFailed("Failed to decrypt the app storage backup.");
|
|
81
|
+
case hw_transport_1.StatusCodes.DEVICE_IN_RECOVERY_MODE:
|
|
82
|
+
break;
|
|
83
|
+
case hw_transport_1.StatusCodes.INVALID_RESTORE_STATE:
|
|
84
|
+
throw new errors_1.InvalidRestoreState("Invalid restore state, restore already performed.");
|
|
85
|
+
case hw_transport_1.StatusCodes.INVALID_CHUNK_LENGTH:
|
|
86
|
+
throw new errors_1.InvalidChunkLength("Invalid chunk length.");
|
|
87
|
+
case hw_transport_1.StatusCodes.INVALID_BACKUP_HEADER:
|
|
88
|
+
throw new errors_1.InvalidBackupHeader("Invalid backup, app storage header is not valid.");
|
|
89
|
+
}
|
|
90
|
+
throw new hw_transport_1.TransportStatusError(status);
|
|
91
|
+
}
|
|
92
|
+
exports.parseResponse = parseResponse;
|
|
93
|
+
//# sourceMappingURL=restoreAppStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restoreAppStorage.js","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorage.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yDAAsF;AACtF,yCAA6C;AAE7C,4CAOyB;AAEzB;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAa;IACpC,0BAAW,CAAC,EAAE;IACd,0BAAW,CAAC,gCAAgC;IAC5C,0BAAW,CAAC,kBAAkB;IAC9B,0BAAW,CAAC,gCAAgC;IAC5C,0BAAW,CAAC,uBAAuB;IACnC,0BAAW,CAAC,qBAAqB;IACjC,0BAAW,CAAC,oBAAoB;IAChC,0BAAW,CAAC,qBAAqB;CAClC,CAAC;AAEF;;;;;;GAMG;AACH,SAAsB,iBAAiB,CAAC,SAAoB,EAAE,KAAa;;QACzE,MAAM,MAAM,GAAG,IAAI,kBAAW,CAAC,IAAI,EAAE;YACnC,SAAS,EAAE,SAAS,CAAC,eAAe,EAAE;YACtC,QAAQ,EAAE,mBAAmB;SAC9B,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEtB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACnE,MAAM,IAAI,GAAmB,CAAC,GAAG,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAE9D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAEpE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;CAAA;AAbD,8CAaC;AAED,SAAgB,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,IAAI,kBAAW,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,iCAAiC;KAC5C,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,0BAAW,CAAC,EAAE;YACjB,OAAO;QACT,KAAK,0BAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,uBAAc,CAAC,8DAA8D,CAAC,CAAC;QAC3F,KAAK,0BAAW,CAAC,kBAAkB;YACjC,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;QAChE,KAAK,0BAAW,CAAC,gCAAgC;YAC/C,MAAM,IAAI,sCAA6B,CAAC,2CAA2C,CAAC,CAAC;QACvF,KAAK,0BAAW,CAAC,uBAAuB;YACtC,MAAM;QACR,KAAK,0BAAW,CAAC,qBAAqB;YACpC,MAAM,IAAI,4BAAmB,CAAC,mDAAmD,CAAC,CAAC;QACrF,KAAK,0BAAW,CAAC,oBAAoB;YACnC,MAAM,IAAI,2BAAkB,CAAC,uBAAuB,CAAC,CAAC;QACxD,KAAK,0BAAW,CAAC,qBAAqB;YACpC,MAAM,IAAI,4BAAmB,CAAC,kDAAkD,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,IAAI,mCAAoB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AA3BD,sCA2BC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restoreAppStorage.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/use-cases/app-backup/restoreAppStorage.test.ts"],"names":[],"mappings":""}
|