@ledgerhq/coin-tester 0.2.0 → 0.2.1-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.
- package/.eslintrc.js +13 -4
- package/CHANGELOG.md +7 -0
- package/README.md +63 -12
- package/docker-compose.yml +2 -4
- package/lib/main.d.ts +16 -8
- package/lib/main.d.ts.map +1 -1
- package/lib/main.js +36 -30
- package/lib/main.js.map +1 -1
- package/lib/signers/speculos.d.ts +3 -4
- package/lib/signers/speculos.d.ts.map +1 -1
- package/lib/signers/speculos.js +108 -53
- package/lib/signers/speculos.js.map +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib-es/main.d.ts +16 -8
- package/lib-es/main.d.ts.map +1 -1
- package/lib-es/main.js +36 -30
- package/lib-es/main.js.map +1 -1
- package/lib-es/signers/speculos.d.ts +3 -4
- package/lib-es/signers/speculos.d.ts.map +1 -1
- package/lib-es/signers/speculos.js +84 -52
- package/lib-es/signers/speculos.js.map +1 -1
- package/lib-es/types.d.ts +1 -1
- package/lib-es/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/main.ts +33 -17
- package/src/signers/speculos.ts +70 -39
- package/src/types.ts +1 -1
package/src/signers/speculos.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import axios from "axios";
|
|
2
|
+
import axios, { AxiosError } from "axios";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import { v2 as compose } from "docker-compose";
|
|
5
5
|
import SpeculosTransportHttp from "@ledgerhq/hw-transport-node-speculos-http";
|
|
@@ -7,30 +7,56 @@ import { ENV } from "../types";
|
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import { SignOperationEvent } from "@ledgerhq/types-live";
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const { SPECULOS_API_PORT } = process.env as ENV;
|
|
11
11
|
const cwd = path.join(__dirname);
|
|
12
12
|
|
|
13
13
|
const delay = (timing: number) => new Promise(resolve => setTimeout(resolve, timing));
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
function ensureEnv() {
|
|
16
|
+
const mandatory_env_variables = ["SEED", "SPECULOS_API_PORT", "GH_TOKEN"];
|
|
17
|
+
const optional_env_variables = ["SPECULOS_IMAGE"];
|
|
18
|
+
|
|
19
|
+
if (!mandatory_env_variables.every(variable => !!process.env[variable])) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Missing env variables. Make sure that ${mandatory_env_variables.join(",")} are in your .env`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
optional_env_variables.forEach(envVariable => {
|
|
26
|
+
if (!process.env[envVariable]) {
|
|
27
|
+
console.warn(`Variable ${envVariable} missing from .env. Using default value.`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function spawnSpeculos(nanoAppEndpoint: `/${string}`): Promise<{
|
|
18
33
|
transport: SpeculosTransportHttp;
|
|
19
|
-
|
|
20
|
-
}>
|
|
34
|
+
getOnSpeculosConfirmation: (approvalText?: string) => () => Promise<void>;
|
|
35
|
+
}> {
|
|
36
|
+
ensureEnv();
|
|
21
37
|
console.log(`Starting speculos...`);
|
|
22
38
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
try {
|
|
40
|
+
const { data: blob } = await axios({
|
|
41
|
+
url: `https://raw.githubusercontent.com/LedgerHQ/coin-apps/master/nanox${nanoAppEndpoint}`,
|
|
42
|
+
method: "GET",
|
|
43
|
+
responseType: "stream",
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${process.env.GH_TOKEN}`,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
await fs.mkdir(path.resolve(cwd, "tmp"), { recursive: true });
|
|
50
|
+
await fs.writeFile(path.resolve(cwd, "tmp/app.elf"), blob, "binary");
|
|
51
|
+
} catch (err) {
|
|
52
|
+
if (err instanceof AxiosError) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`${err.status}: Failed to download the app.elf file from ${nanoAppEndpoint}\nMake sure that your GH_TOKEN is correct and has the right permissions.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
34
60
|
|
|
35
61
|
await compose.upOne("speculos", {
|
|
36
62
|
cwd,
|
|
@@ -38,55 +64,60 @@ export const spawnSpeculos = async (
|
|
|
38
64
|
env: process.env,
|
|
39
65
|
});
|
|
40
66
|
|
|
41
|
-
|
|
67
|
+
async function checkSpeculosLogs(): Promise<SpeculosTransportHttp> {
|
|
42
68
|
const { out } = await compose.logs("speculos", { cwd, env: process.env });
|
|
43
69
|
|
|
44
70
|
if (out.includes("Running on all addresses (0.0.0.0)")) {
|
|
45
71
|
console.log(chalk.bgYellowBright.black(" - SPECULOS READY ✅ - "));
|
|
46
72
|
return SpeculosTransportHttp.open({
|
|
47
|
-
apiPort:
|
|
73
|
+
apiPort: SPECULOS_API_PORT,
|
|
48
74
|
});
|
|
49
75
|
}
|
|
50
76
|
|
|
51
77
|
await delay(200);
|
|
52
78
|
return checkSpeculosLogs();
|
|
53
|
-
}
|
|
79
|
+
}
|
|
54
80
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
function getOnSpeculosConfirmation(approvalText = "Accept") {
|
|
82
|
+
async function onSpeculosConfirmation(e?: SignOperationEvent): Promise<void> {
|
|
83
|
+
if (e?.type === "device-signature-requested") {
|
|
84
|
+
const { data } = await axios.get(
|
|
85
|
+
`http://localhost:${SPECULOS_API_PORT}/events?currentscreenonly=true`,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (data.events[0].text !== approvalText) {
|
|
89
|
+
await axios.post(`http://localhost:${SPECULOS_API_PORT}/button/right`, {
|
|
90
|
+
action: "press-and-release",
|
|
91
|
+
});
|
|
60
92
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await axios.post(`http://localhost:${process.env.API_PORT}/button/both`, {
|
|
68
|
-
action: "press-and-release",
|
|
69
|
-
});
|
|
93
|
+
onSpeculosConfirmation(e);
|
|
94
|
+
} else {
|
|
95
|
+
await axios.post(`http://localhost:${SPECULOS_API_PORT}/button/both`, {
|
|
96
|
+
action: "press-and-release",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
|
-
|
|
101
|
+
|
|
102
|
+
return onSpeculosConfirmation;
|
|
103
|
+
}
|
|
73
104
|
|
|
74
105
|
return checkSpeculosLogs().then(transport => {
|
|
75
106
|
return {
|
|
76
107
|
transport,
|
|
77
|
-
|
|
108
|
+
getOnSpeculosConfirmation,
|
|
78
109
|
};
|
|
79
110
|
});
|
|
80
|
-
}
|
|
111
|
+
}
|
|
81
112
|
|
|
82
|
-
export
|
|
113
|
+
export async function killSpeculos() {
|
|
83
114
|
console.log("Stopping speculos...");
|
|
84
115
|
await compose.down({
|
|
85
116
|
cwd,
|
|
86
117
|
log: true,
|
|
87
118
|
env: process.env,
|
|
88
119
|
});
|
|
89
|
-
}
|
|
120
|
+
}
|
|
90
121
|
|
|
91
122
|
["exit", "SIGINT", "SIGQUIT", "SIGTERM", "SIGUSR1", "SIGUSR2", "uncaughtException"].map(e =>
|
|
92
123
|
process.on(e, async () => {
|
package/src/types.ts
CHANGED