@cef-ebsi/cli 0.0.0-alpha.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/LICENSE +190 -0
- package/README.md +32 -0
- package/bin/cli.js +13 -0
- package/dist/abi/pilot/DidRegistry-old.json +2192 -0
- package/dist/abi/pilot/DidRegistry.json +1081 -0
- package/dist/abi/pilot/DidRegistryV3.json +1081 -0
- package/dist/abi/pilot/SchemaSCRegistry.json +972 -0
- package/dist/abi/pilot/SchemaSCRegistryV2.json +473 -0
- package/dist/abi/pilot/Tar.json +1394 -0
- package/dist/abi/pilot/TarV3.json +1107 -0
- package/dist/abi/pilot/Timestamp.json +1091 -0
- package/dist/abi/pilot/TimestampV2.json +1127 -0
- package/dist/abi/pilot/Tir.json +896 -0
- package/dist/abi/pilot/TirV3.json +495 -0
- package/dist/abi/pilot/Tpr.json +1267 -0
- package/dist/abi/pilot/TprV2.json +888 -0
- package/dist/abi/test/DidRegistry-old.json +2192 -0
- package/dist/abi/test/DidRegistry.json +1081 -0
- package/dist/abi/test/DidRegistryV3.json +1088 -0
- package/dist/abi/test/SchemaSCRegistry.json +972 -0
- package/dist/abi/test/SchemaSCRegistryV2.json +473 -0
- package/dist/abi/test/Tar.json +1394 -0
- package/dist/abi/test/TarV3.json +1107 -0
- package/dist/abi/test/Timestamp.json +1091 -0
- package/dist/abi/test/TimestampV2.json +1127 -0
- package/dist/abi/test/Tir.json +896 -0
- package/dist/abi/test/TirV3.json +495 -0
- package/dist/abi/test/Tpr.json +1267 -0
- package/dist/abi/test/TprV2.json +888 -0
- package/dist/app.js +1205 -0
- package/dist/app.js.map +1 -0
- package/dist/buildParam/did.js +355 -0
- package/dist/buildParam/did.js.map +1 -0
- package/dist/buildParam/didOld.js +275 -0
- package/dist/buildParam/didOld.js.map +1 -0
- package/dist/buildParam/didV3.js +353 -0
- package/dist/buildParam/didV3.js.map +1 -0
- package/dist/buildParam/index.js +54 -0
- package/dist/buildParam/index.js.map +1 -0
- package/dist/buildParam/tar.js +240 -0
- package/dist/buildParam/tar.js.map +1 -0
- package/dist/buildParam/tarV3.js +193 -0
- package/dist/buildParam/tarV3.js.map +1 -0
- package/dist/buildParam/timestamp.js +323 -0
- package/dist/buildParam/timestamp.js.map +1 -0
- package/dist/buildParam/timestampV2.js +317 -0
- package/dist/buildParam/timestampV2.js.map +1 -0
- package/dist/buildParam/tir.js +200 -0
- package/dist/buildParam/tir.js.map +1 -0
- package/dist/buildParam/tirV3.js +104 -0
- package/dist/buildParam/tirV3.js.map +1 -0
- package/dist/buildParam/tpr.js +167 -0
- package/dist/buildParam/tpr.js.map +1 -0
- package/dist/buildParam/tprV2.js +82 -0
- package/dist/buildParam/tprV2.js.map +1 -0
- package/dist/buildParam/tsr.js +149 -0
- package/dist/buildParam/tsr.js.map +1 -0
- package/dist/buildParam/tsrV2.js +110 -0
- package/dist/buildParam/tsrV2.js.map +1 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/authorisation-v3.js +98 -0
- package/dist/commands/authorisation-v3.js.map +1 -0
- package/dist/commands/authorisation-v4.js +221 -0
- package/dist/commands/authorisation-v4.js.map +1 -0
- package/dist/commands/compute.js +374 -0
- package/dist/commands/compute.js.map +1 -0
- package/dist/commands/conformance-v3.js +745 -0
- package/dist/commands/conformance-v3.js.map +1 -0
- package/dist/commands/conformance-v4.js +767 -0
- package/dist/commands/conformance-v4.js.map +1 -0
- package/dist/commands/index.js +9 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/ledger-v3.js +189 -0
- package/dist/commands/ledger-v3.js.map +1 -0
- package/dist/commands/ledger-v4.js +188 -0
- package/dist/commands/ledger-v4.js.map +1 -0
- package/dist/commands/view.js +62 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/config.js +910 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/authorisation/authorisation.interface.js +2 -0
- package/dist/interfaces/authorisation/authorisation.interface.js.map +1 -0
- package/dist/interfaces/authorisation/index.js +2 -0
- package/dist/interfaces/authorisation/index.js.map +1 -0
- package/dist/interfaces/context.js +2 -0
- package/dist/interfaces/context.js.map +1 -0
- package/dist/interfaces/index.js +10 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/ledger/besu.interface.js +2 -0
- package/dist/interfaces/ledger/besu.interface.js.map +1 -0
- package/dist/interfaces/ledger/index.js +2 -0
- package/dist/interfaces/ledger/index.js.map +1 -0
- package/dist/interfaces/notifications/index.js +2 -0
- package/dist/interfaces/notifications/index.js.map +1 -0
- package/dist/interfaces/notifications/notifications.interface.js +2 -0
- package/dist/interfaces/notifications/notifications.interface.js.map +1 -0
- package/dist/interfaces/proxy-data-hub/attributes.interface.js +2 -0
- package/dist/interfaces/proxy-data-hub/attributes.interface.js.map +1 -0
- package/dist/interfaces/proxy-data-hub/index.js +2 -0
- package/dist/interfaces/proxy-data-hub/index.js.map +1 -0
- package/dist/interfaces/shared/index.js +5 -0
- package/dist/interfaces/shared/index.js.map +1 -0
- package/dist/interfaces/shared/jsonrpc.interface.js +2 -0
- package/dist/interfaces/shared/jsonrpc.interface.js.map +1 -0
- package/dist/interfaces/shared/paginated-list.interface.js +2 -0
- package/dist/interfaces/shared/paginated-list.interface.js.map +1 -0
- package/dist/interfaces/shared/unsigned-transaction.interface.js +2 -0
- package/dist/interfaces/shared/unsigned-transaction.interface.js.map +1 -0
- package/dist/interfaces/shared/utils.interface.js +2 -0
- package/dist/interfaces/shared/utils.interface.js.map +1 -0
- package/dist/interfaces/timestamp/hash-algorithms.interface.js +2 -0
- package/dist/interfaces/timestamp/hash-algorithms.interface.js.map +1 -0
- package/dist/interfaces/timestamp/index.js +4 -0
- package/dist/interfaces/timestamp/index.js.map +1 -0
- package/dist/interfaces/timestamp/records.interface.js +2 -0
- package/dist/interfaces/timestamp/records.interface.js.map +1 -0
- package/dist/interfaces/timestamp/timestamps.interface.js +2 -0
- package/dist/interfaces/timestamp/timestamps.interface.js.map +1 -0
- package/dist/interfaces/trusted-apps-registry/apps.interface.js +2 -0
- package/dist/interfaces/trusted-apps-registry/apps.interface.js.map +1 -0
- package/dist/interfaces/trusted-apps-registry/index.js +3 -0
- package/dist/interfaces/trusted-apps-registry/index.js.map +1 -0
- package/dist/interfaces/trusted-apps-registry/policies.interface.js +2 -0
- package/dist/interfaces/trusted-apps-registry/policies.interface.js.map +1 -0
- package/dist/interfaces/trusted-issuers-registry/index.js +2 -0
- package/dist/interfaces/trusted-issuers-registry/index.js.map +1 -0
- package/dist/interfaces/trusted-issuers-registry/issuers.interface.js +2 -0
- package/dist/interfaces/trusted-issuers-registry/issuers.interface.js.map +1 -0
- package/dist/interfaces/users-onboarding/authentication.js +2 -0
- package/dist/interfaces/users-onboarding/authentication.js.map +1 -0
- package/dist/interfaces/users-onboarding/index.js +2 -0
- package/dist/interfaces/users-onboarding/index.js.map +1 -0
- package/dist/programs/appRegistration.js +65 -0
- package/dist/programs/appRegistration.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/Client.js +176 -0
- package/dist/utils/Client.js.map +1 -0
- package/dist/utils/authorisation.js +118 -0
- package/dist/utils/authorisation.js.map +1 -0
- package/dist/utils/http.js +128 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/jsonrpc.js +33 -0
- package/dist/utils/jsonrpc.js.map +1 -0
- package/dist/utils/notification.js +51 -0
- package/dist/utils/notification.js.map +1 -0
- package/dist/utils/print.js +57 -0
- package/dist/utils/print.js.map +1 -0
- package/dist/utils/storage.js +97 -0
- package/dist/utils/storage.js.map +1 -0
- package/dist/utils/utils.js +161 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/utils/verifiablePresentation.js +43 -0
- package/dist/utils/verifiablePresentation.js.map +1 -0
- package/package.json +113 -0
package/dist/app.js
ADDED
|
@@ -0,0 +1,1205 @@
|
|
|
1
|
+
/* eslint-disable no-use-before-define, @typescript-eslint/no-use-before-define */
|
|
2
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
3
|
+
import { URL, URLSearchParams } from "node:url";
|
|
4
|
+
import { ethers } from "ethers";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import qs from "qs";
|
|
7
|
+
import { EbsiWallet } from "@cef-ebsi/wallet-lib";
|
|
8
|
+
import lodashSet from "lodash.set";
|
|
9
|
+
import { calculateJwkThumbprint, importJWK, SignJWT, base64url, } from "jose";
|
|
10
|
+
import fs, { createWriteStream } from "fs";
|
|
11
|
+
import Joi from "joi";
|
|
12
|
+
import { Agent as SiopAgent } from "@cef-ebsi/siop-auth";
|
|
13
|
+
import readline from "readline";
|
|
14
|
+
import { loadConfig } from "./config.js";
|
|
15
|
+
import * as utils from "./utils/index.js";
|
|
16
|
+
import { buildParam } from "./buildParam/index.js";
|
|
17
|
+
import { isResponseFile, jsonrpcBody, paramSignedTransaction, parseLine, prefixWith0x, getPrivateKeyHex, } from "./utils/index.js";
|
|
18
|
+
import { Client, getPrivateKeyJwk } from "./utils/Client.js";
|
|
19
|
+
import { authorisationV3, authorisationV4, compute, view, conformanceV3, conformanceV4, ledgerV4, ledgerV3, waitToBeMined, } from "./commands/index.js";
|
|
20
|
+
let config = loadConfig();
|
|
21
|
+
if (!fs.existsSync("./downloads")) {
|
|
22
|
+
fs.mkdirSync("./downloads");
|
|
23
|
+
}
|
|
24
|
+
let client = new Client();
|
|
25
|
+
let transactionInfo;
|
|
26
|
+
let trustedApp;
|
|
27
|
+
let token;
|
|
28
|
+
let oauth2token;
|
|
29
|
+
let httpOpts = {
|
|
30
|
+
headers: {},
|
|
31
|
+
};
|
|
32
|
+
let httpOptsUrlencoded = {
|
|
33
|
+
headers: {},
|
|
34
|
+
};
|
|
35
|
+
const rtVars = {}; // runtime variables
|
|
36
|
+
const algSchema = Joi.string()
|
|
37
|
+
.valid("ES256K", "ES256", "RS256", "EdDSA")
|
|
38
|
+
.required();
|
|
39
|
+
async function setVar(key, value, printVar = true) {
|
|
40
|
+
lodashSet(rtVars, key, value);
|
|
41
|
+
if (key.startsWith("user.")) {
|
|
42
|
+
await execCommand("using user user");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!printVar)
|
|
46
|
+
return;
|
|
47
|
+
utils.cyanBold(`Value saved in '${key}':`);
|
|
48
|
+
utils.cyan(value);
|
|
49
|
+
}
|
|
50
|
+
function updateHttpOpts() {
|
|
51
|
+
const conformanceId = readValue("conformanceId", true);
|
|
52
|
+
httpOpts = {
|
|
53
|
+
headers: {
|
|
54
|
+
...((token || oauth2token) && {
|
|
55
|
+
authorization: `Bearer ${token || oauth2token}`,
|
|
56
|
+
}),
|
|
57
|
+
...(conformanceId && { conformance: conformanceId }),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
httpOptsUrlencoded = {
|
|
61
|
+
headers: {
|
|
62
|
+
...((token || oauth2token) && {
|
|
63
|
+
authorization: `Bearer ${token || oauth2token}`,
|
|
64
|
+
}),
|
|
65
|
+
...(conformanceId && { conformance: conformanceId }),
|
|
66
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function readValue(input, required = false) {
|
|
71
|
+
if (!input || typeof input !== "string")
|
|
72
|
+
return input;
|
|
73
|
+
const parts = input.split(".");
|
|
74
|
+
let fieldName = parts[0];
|
|
75
|
+
if (typeof rtVars[fieldName] === "undefined") {
|
|
76
|
+
if (required)
|
|
77
|
+
return undefined;
|
|
78
|
+
return input;
|
|
79
|
+
}
|
|
80
|
+
let i = 0;
|
|
81
|
+
let obj = rtVars;
|
|
82
|
+
while (i < parts.length - 1) {
|
|
83
|
+
obj = obj[fieldName];
|
|
84
|
+
i += 1;
|
|
85
|
+
fieldName = parts[i];
|
|
86
|
+
}
|
|
87
|
+
return obj[fieldName];
|
|
88
|
+
}
|
|
89
|
+
function urlPath(inputs) {
|
|
90
|
+
return inputs.map((input) => readValue(input)).join("");
|
|
91
|
+
}
|
|
92
|
+
async function using(method, ...params) {
|
|
93
|
+
switch (method) {
|
|
94
|
+
case "token": {
|
|
95
|
+
token = params[0] === "empty" ? null : readValue(params[0]);
|
|
96
|
+
updateHttpOpts();
|
|
97
|
+
utils.yellow(token);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
case "oauth2token": {
|
|
101
|
+
oauth2token = params[0] === "empty" ? null : readValue(params[0]);
|
|
102
|
+
updateHttpOpts();
|
|
103
|
+
utils.yellow(oauth2token);
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
case "user": {
|
|
107
|
+
const existingUser = readValue(params[0]);
|
|
108
|
+
if (existingUser && typeof existingUser !== "string") {
|
|
109
|
+
// load the existing user
|
|
110
|
+
client = new Client();
|
|
111
|
+
client.did = existingUser.did;
|
|
112
|
+
client.didVersion = existingUser.didVersion;
|
|
113
|
+
client.privateKeyHex = existingUser.privateKeyHex;
|
|
114
|
+
client.clientId = existingUser.clientId;
|
|
115
|
+
client.accreditationUrl = existingUser.accreditationUrl;
|
|
116
|
+
client.proxyId = existingUser.proxyId;
|
|
117
|
+
client.issuerState = existingUser.issuerState;
|
|
118
|
+
if (existingUser.privateKeyHex) {
|
|
119
|
+
client.ethWallet = new ethers.Wallet(existingUser.privateKeyHex);
|
|
120
|
+
}
|
|
121
|
+
client.keys = existingUser.keys;
|
|
122
|
+
await setVar("user", client.toJSON(), false);
|
|
123
|
+
await execCommand("view user", false);
|
|
124
|
+
return client;
|
|
125
|
+
}
|
|
126
|
+
if (params[0] === "null") {
|
|
127
|
+
client = new Client();
|
|
128
|
+
await setVar("user", client.toJSON(), false);
|
|
129
|
+
utils.yellow("User removed");
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
const alg = readValue(params[0]) || "ES256K";
|
|
133
|
+
const didMethod = readValue(params[1]) || "did1";
|
|
134
|
+
const privateKey = readValue(params[2]);
|
|
135
|
+
client.did = readValue(params[3]) || client.did;
|
|
136
|
+
let verificationMethodId = readValue(params[4]);
|
|
137
|
+
Joi.assert(alg, algSchema);
|
|
138
|
+
if (client.keys[alg] && !privateKey) {
|
|
139
|
+
throw new Error([
|
|
140
|
+
`Private key can not be generated randomly for alg '${alg}' `,
|
|
141
|
+
"because it is already defined. If you want to update it ",
|
|
142
|
+
"set a specific private key. If you want to create a new ",
|
|
143
|
+
"random user remove the existing one first with the command ",
|
|
144
|
+
"'using user null'.",
|
|
145
|
+
].join(""));
|
|
146
|
+
}
|
|
147
|
+
if (alg === "ES256K") {
|
|
148
|
+
if (!privateKey) {
|
|
149
|
+
client.ethWallet = ethers.Wallet.createRandom();
|
|
150
|
+
}
|
|
151
|
+
else if (typeof privateKey === "string") {
|
|
152
|
+
client.ethWallet = new ethers.Wallet(prefixWith0x(privateKey));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
client.ethWallet = new ethers.Wallet(getPrivateKeyHex(privateKey));
|
|
156
|
+
}
|
|
157
|
+
client.privateKeyHex = client.ethWallet.privateKey;
|
|
158
|
+
const privateKeyJwk = getPrivateKeyJwk(client.ethWallet.privateKey);
|
|
159
|
+
await client.setJwk(alg, privateKeyJwk);
|
|
160
|
+
}
|
|
161
|
+
else if (alg === "ES256" && typeof privateKey === "string") {
|
|
162
|
+
const privateKeyJwk = utils.getPrivateKeyJwkES256(privateKey);
|
|
163
|
+
await client.setJwk(alg, privateKeyJwk);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const privateKeyJwk = privateKey;
|
|
167
|
+
if (privateKeyJwk) {
|
|
168
|
+
await client.setJwk(alg, privateKeyJwk);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
await client.createRandom(alg);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
switch (didMethod) {
|
|
175
|
+
case "did1": {
|
|
176
|
+
client.didVersion = 1;
|
|
177
|
+
if (!client.did) {
|
|
178
|
+
client.did = EbsiWallet.createDid();
|
|
179
|
+
}
|
|
180
|
+
if (!verificationMethodId) {
|
|
181
|
+
verificationMethodId = await calculateJwkThumbprint(client.keys[alg].publicKeyJwk, "sha256");
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case "did2": {
|
|
186
|
+
client.didVersion = 2;
|
|
187
|
+
client.did = EbsiWallet.createDid("NATURAL_PERSON", client.keys[alg].publicKeyJwk);
|
|
188
|
+
if (!verificationMethodId) {
|
|
189
|
+
verificationMethodId = client.did.slice(8);
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
default:
|
|
194
|
+
throw new Error("did method must be 'did1' or 'did2'");
|
|
195
|
+
}
|
|
196
|
+
client.keys[alg].id = verificationMethodId;
|
|
197
|
+
client.keys[alg].kid = `${client.did}#${verificationMethodId}`;
|
|
198
|
+
await setVar("user", client.toJSON(), false);
|
|
199
|
+
await execCommand("view user", false);
|
|
200
|
+
return client;
|
|
201
|
+
}
|
|
202
|
+
case "ethuser": {
|
|
203
|
+
if (params[0] === "null") {
|
|
204
|
+
client = new Client();
|
|
205
|
+
await setVar("user", client.toJSON(), false);
|
|
206
|
+
utils.yellow("User removed");
|
|
207
|
+
return client;
|
|
208
|
+
}
|
|
209
|
+
await execCommand(`using user ES256K ${params.join(" ")}`, true);
|
|
210
|
+
return client;
|
|
211
|
+
}
|
|
212
|
+
case "app":
|
|
213
|
+
case "app-new": {
|
|
214
|
+
const name = params[0];
|
|
215
|
+
const privateKey = params[1];
|
|
216
|
+
const publicKeyPem = new EbsiWallet(privateKey).getPublicKey({
|
|
217
|
+
format: "pem",
|
|
218
|
+
});
|
|
219
|
+
const publicKeyPemBase64 = Buffer.from(publicKeyPem).toString("base64");
|
|
220
|
+
trustedApp = {
|
|
221
|
+
name,
|
|
222
|
+
privateKey,
|
|
223
|
+
publicKeyPem,
|
|
224
|
+
publicKeyPemBase64,
|
|
225
|
+
kid: `${method === "app" ? config.api.tar.url : config.api["tar-new"].url}/apps/${name}`,
|
|
226
|
+
};
|
|
227
|
+
utils.yellow(trustedApp);
|
|
228
|
+
return trustedApp;
|
|
229
|
+
}
|
|
230
|
+
default:
|
|
231
|
+
utils.red(`Invalid subject '${method}'`);
|
|
232
|
+
return 0;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async function authorisationV2(method, inputs) {
|
|
236
|
+
const apiUrl = config.api.authorisationV2.url;
|
|
237
|
+
switch (method) {
|
|
238
|
+
case "get": {
|
|
239
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(inputs)}`, httpOpts);
|
|
240
|
+
return response.data;
|
|
241
|
+
}
|
|
242
|
+
case "siopRequest": {
|
|
243
|
+
return utils.siopRequestV2(config, httpOpts);
|
|
244
|
+
}
|
|
245
|
+
case "siopSession": {
|
|
246
|
+
const callbackUrl = readValue(inputs[0]);
|
|
247
|
+
const alg = readValue(inputs[1]) || "ES256K";
|
|
248
|
+
const verifiedClaims = readValue(inputs[2]);
|
|
249
|
+
Joi.assert(callbackUrl, Joi.string());
|
|
250
|
+
Joi.assert(alg, algSchema);
|
|
251
|
+
Joi.assert(verifiedClaims, Joi.string().optional());
|
|
252
|
+
return utils.siopSessionV2(client, callbackUrl, alg, httpOpts, verifiedClaims);
|
|
253
|
+
}
|
|
254
|
+
case "siop": {
|
|
255
|
+
const alg = readValue(inputs[0]) || "ES256K";
|
|
256
|
+
const vcJwtEOS = readValue(inputs[1]);
|
|
257
|
+
let vpJwt = "";
|
|
258
|
+
if (vcJwtEOS) {
|
|
259
|
+
vpJwt = await execCommand(`compute createPresentationJwt ${vcJwtEOS} ${alg} authorisation-api`, true);
|
|
260
|
+
}
|
|
261
|
+
const request = await execCommand("authorisation-old siopRequest", true);
|
|
262
|
+
const callbackUrl = await execCommand(`compute verifyAuthenticationRequest ${JSON.stringify(request)}`, true);
|
|
263
|
+
const sessionResponse = await execCommand(`authorisation-old siopSession ${callbackUrl} ${alg} ${vpJwt}`, true);
|
|
264
|
+
const accessToken = await execCommand(`compute verifySessionResponse ${JSON.stringify(sessionResponse)}`, true);
|
|
265
|
+
return accessToken;
|
|
266
|
+
}
|
|
267
|
+
case "oauth2":
|
|
268
|
+
case "oauth2Session": {
|
|
269
|
+
return utils.oauth2SessionV2(trustedApp, inputs[0], config);
|
|
270
|
+
}
|
|
271
|
+
default:
|
|
272
|
+
utils.red(`Invalid method '${method}'`);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
async function proxydatahub(method, inputs) {
|
|
278
|
+
const apiUrl = config.api.datahub.url;
|
|
279
|
+
const storageApiUrl = config.api.storage.url;
|
|
280
|
+
switch (method) {
|
|
281
|
+
case "get": {
|
|
282
|
+
Joi.assert(inputs[0], Joi.string());
|
|
283
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(inputs)}`, httpOpts);
|
|
284
|
+
return response.data;
|
|
285
|
+
}
|
|
286
|
+
case "insert": {
|
|
287
|
+
Joi.assert(inputs[0], Joi.object().optional());
|
|
288
|
+
Joi.assert(inputs[1], Joi.string().optional());
|
|
289
|
+
Joi.assert(inputs[2], Joi.string().optional());
|
|
290
|
+
const data = typeof inputs[0] === "object"
|
|
291
|
+
? base64url.encode(Buffer.from(JSON.stringify(inputs[0])))
|
|
292
|
+
: base64url.encode(randomBytes(20));
|
|
293
|
+
const visibility = inputs[1] || "private";
|
|
294
|
+
const did = inputs[2] || "";
|
|
295
|
+
const url = `${apiUrl}/attributes`;
|
|
296
|
+
const body = {
|
|
297
|
+
storageUri: `${storageApiUrl}/stores/distributed`,
|
|
298
|
+
visibility,
|
|
299
|
+
...(did && { sharedWith: did }),
|
|
300
|
+
did: client.did,
|
|
301
|
+
contentType: "application/ld+json",
|
|
302
|
+
dataLabel: "document",
|
|
303
|
+
data,
|
|
304
|
+
proof: {},
|
|
305
|
+
};
|
|
306
|
+
return utils.httpCall.post(url, body, httpOpts);
|
|
307
|
+
}
|
|
308
|
+
case "patch": {
|
|
309
|
+
Joi.assert(inputs[0], Joi.string());
|
|
310
|
+
Joi.assert(inputs[1], Joi.array().optional());
|
|
311
|
+
const attributeId = inputs[0];
|
|
312
|
+
const patchOps = Array.isArray(inputs[1])
|
|
313
|
+
? inputs[1]
|
|
314
|
+
: [
|
|
315
|
+
{
|
|
316
|
+
op: "replace",
|
|
317
|
+
path: "/contentType",
|
|
318
|
+
value: "application/ld+json",
|
|
319
|
+
},
|
|
320
|
+
];
|
|
321
|
+
const url = `${apiUrl}/attributes/${attributeId}`;
|
|
322
|
+
return utils.httpCall.patch(url, patchOps, httpOpts);
|
|
323
|
+
}
|
|
324
|
+
case "delete": {
|
|
325
|
+
Joi.assert(inputs[0], Joi.string());
|
|
326
|
+
const attributeId = inputs[0];
|
|
327
|
+
const url = `${apiUrl}/attributes/${attributeId}`;
|
|
328
|
+
return utils.httpCall.delete(url, httpOpts);
|
|
329
|
+
}
|
|
330
|
+
default:
|
|
331
|
+
utils.red(`Invalid method '${method}'`);
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
return 0;
|
|
335
|
+
}
|
|
336
|
+
async function notifications(method, ...inputs) {
|
|
337
|
+
const apiUrl = config.api.notifications.url;
|
|
338
|
+
switch (method) {
|
|
339
|
+
case "get": {
|
|
340
|
+
Joi.assert(inputs[0], Joi.string());
|
|
341
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(inputs)}`, httpOpts);
|
|
342
|
+
return response.data;
|
|
343
|
+
}
|
|
344
|
+
case "insert": {
|
|
345
|
+
Joi.assert(inputs[0], Joi.string());
|
|
346
|
+
Joi.assert(inputs[1], Joi.object().optional());
|
|
347
|
+
Joi.assert(inputs[2], Joi.string().optional());
|
|
348
|
+
const to = inputs[0];
|
|
349
|
+
const payload = typeof inputs[1] === "object"
|
|
350
|
+
? inputs[1]
|
|
351
|
+
: {
|
|
352
|
+
"@context": "ebsi.eu",
|
|
353
|
+
data: randomBytes(32).toString("hex"),
|
|
354
|
+
};
|
|
355
|
+
const type = inputs[2] || "StoreVerifiableCredential";
|
|
356
|
+
const url = `${apiUrl}/notifications`;
|
|
357
|
+
const data = await utils.createNotification(client, to, payload, type);
|
|
358
|
+
const response = await utils.httpCall.post(url, data, httpOpts);
|
|
359
|
+
const { location } = response.headers;
|
|
360
|
+
const notificationId = location.substring(location.lastIndexOf("/") + 1);
|
|
361
|
+
utils.yellow("Notification Id:");
|
|
362
|
+
utils.yellow(notificationId);
|
|
363
|
+
return response.data;
|
|
364
|
+
}
|
|
365
|
+
case "delete": {
|
|
366
|
+
Joi.assert(inputs[0], Joi.string());
|
|
367
|
+
Joi.assert(inputs[1], Joi.object().optional());
|
|
368
|
+
if (inputs[0] === "all") {
|
|
369
|
+
const response = await utils.httpCall.get(`${apiUrl}/notifications?page[size]=50`, httpOpts);
|
|
370
|
+
const { items } = response.data;
|
|
371
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
372
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
373
|
+
const { href } = items[i]._links.self;
|
|
374
|
+
const notificationId = href.substring(href.lastIndexOf("/") + 1);
|
|
375
|
+
const url = `${apiUrl}/notifications/${notificationId}`;
|
|
376
|
+
await utils.httpCall.delete(url, httpOpts);
|
|
377
|
+
}
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
380
|
+
const notificationId = inputs[0];
|
|
381
|
+
const url = `${apiUrl}/notifications/${notificationId}`;
|
|
382
|
+
return utils.httpCall.delete(url, httpOpts);
|
|
383
|
+
}
|
|
384
|
+
default:
|
|
385
|
+
utils.red(`Invalid method '${method}'`);
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
return 0;
|
|
389
|
+
}
|
|
390
|
+
async function storage(method, inputs) {
|
|
391
|
+
const apiUrl = config.api.storage.url;
|
|
392
|
+
switch (method) {
|
|
393
|
+
case "get": {
|
|
394
|
+
Joi.assert(inputs[0], Joi.string());
|
|
395
|
+
const storageUrlPath = urlPath(inputs);
|
|
396
|
+
const isDownloadingFile = /stores\/distributed\/files\/0x([a-zA-Z0-9]){64}$/.exec(storageUrlPath);
|
|
397
|
+
if (!isDownloadingFile) {
|
|
398
|
+
const response = await utils.httpCall.get(`${apiUrl}${storageUrlPath}`, httpOpts);
|
|
399
|
+
return response.data;
|
|
400
|
+
}
|
|
401
|
+
const response = await utils.httpCall.get(`${apiUrl}${storageUrlPath}`, {
|
|
402
|
+
...httpOpts,
|
|
403
|
+
responseType: "stream",
|
|
404
|
+
});
|
|
405
|
+
let filename;
|
|
406
|
+
if (isResponseFile(response)) {
|
|
407
|
+
filename = response.headers["content-disposition"].replace("attachment; filename=", "");
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
filename = `error-${randomBytes(12).toString("hex")}.txt`;
|
|
411
|
+
}
|
|
412
|
+
const filepath = `./downloads/${filename}`;
|
|
413
|
+
const writer = createWriteStream(filepath);
|
|
414
|
+
await new Promise((resolve, reject) => {
|
|
415
|
+
response.data.pipe(writer);
|
|
416
|
+
let error = null;
|
|
417
|
+
writer.on("error", (err) => {
|
|
418
|
+
error = err;
|
|
419
|
+
writer.close();
|
|
420
|
+
reject(err);
|
|
421
|
+
});
|
|
422
|
+
writer.on("close", () => {
|
|
423
|
+
if (!error) {
|
|
424
|
+
resolve(true);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
if (!isResponseFile(response)) {
|
|
429
|
+
// there is an error
|
|
430
|
+
const dataString = fs.readFileSync(filepath, "utf8");
|
|
431
|
+
fs.unlinkSync(filepath);
|
|
432
|
+
try {
|
|
433
|
+
const jsonData = JSON.parse(dataString);
|
|
434
|
+
utils.red(jsonData);
|
|
435
|
+
}
|
|
436
|
+
catch (e) {
|
|
437
|
+
utils.red(dataString);
|
|
438
|
+
}
|
|
439
|
+
throw new Error(`Requests failed with status code ${response.status}: ${dataString}`);
|
|
440
|
+
}
|
|
441
|
+
utils.green(`Binary data: ${filename}`);
|
|
442
|
+
return 0;
|
|
443
|
+
}
|
|
444
|
+
case "file": {
|
|
445
|
+
Joi.assert(inputs[0], Joi.string());
|
|
446
|
+
const methodFile = inputs[0];
|
|
447
|
+
return utils.fileController(httpOpts, apiUrl, methodFile, inputs.slice(1));
|
|
448
|
+
}
|
|
449
|
+
case "keyvalue": {
|
|
450
|
+
Joi.assert(inputs[0], Joi.string());
|
|
451
|
+
const methodKeyValue = inputs[0];
|
|
452
|
+
return utils.keyValueController(httpOpts, apiUrl, methodKeyValue, inputs.slice(1));
|
|
453
|
+
}
|
|
454
|
+
case "jsonrpc": {
|
|
455
|
+
Joi.assert(inputs[0], Joi.array());
|
|
456
|
+
return utils.jsonrpcStorage(httpOpts, apiUrl, inputs[0]);
|
|
457
|
+
}
|
|
458
|
+
default:
|
|
459
|
+
utils.red(`Invalid method '${method}'`);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
return 0;
|
|
463
|
+
}
|
|
464
|
+
async function cassandra(method, inputs) {
|
|
465
|
+
switch (method) {
|
|
466
|
+
case "query": {
|
|
467
|
+
Joi.assert(inputs[0], Joi.array().items(Joi.string()));
|
|
468
|
+
const [query, ...params] = inputs[0];
|
|
469
|
+
const options = {
|
|
470
|
+
consistency: query.trim().startsWith("select")
|
|
471
|
+
? config.cassandra.consistency.read
|
|
472
|
+
: config.cassandra.consistency.write,
|
|
473
|
+
prepare: true,
|
|
474
|
+
};
|
|
475
|
+
if (params.length > 0 && typeof params[params.length - 1] === "object") {
|
|
476
|
+
Object.assign(options, params.pop());
|
|
477
|
+
}
|
|
478
|
+
const { rows, pageState } = await config.cassandra.client.execute(query, params, options);
|
|
479
|
+
return {
|
|
480
|
+
rows,
|
|
481
|
+
pageState,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
default:
|
|
485
|
+
utils.red(`Invalid method '${method}'`);
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
return 0;
|
|
489
|
+
}
|
|
490
|
+
async function onboarding(method, ...params) {
|
|
491
|
+
const apiUrl = config.api.onboarding.url;
|
|
492
|
+
switch (method) {
|
|
493
|
+
case "get": {
|
|
494
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(params)}`, httpOpts);
|
|
495
|
+
return response.data;
|
|
496
|
+
}
|
|
497
|
+
case "session": {
|
|
498
|
+
return utils.httpCall.post(`${apiUrl}/sessions`, {
|
|
499
|
+
onboarding: "eu-login",
|
|
500
|
+
info: {
|
|
501
|
+
"eul-ticket": readValue(params[0]),
|
|
502
|
+
},
|
|
503
|
+
}, httpOpts);
|
|
504
|
+
}
|
|
505
|
+
case "authenticationRequests": {
|
|
506
|
+
const response = await utils.httpCall.post(`${apiUrl}/authentication-requests`, {
|
|
507
|
+
scope: "ebsi users onboarding",
|
|
508
|
+
}, httpOpts);
|
|
509
|
+
return response.data;
|
|
510
|
+
}
|
|
511
|
+
case "sendAuthResponse": {
|
|
512
|
+
const alg = readValue(params[0]) || "ES256K";
|
|
513
|
+
Joi.assert(alg, algSchema);
|
|
514
|
+
const nonce = randomUUID();
|
|
515
|
+
const key = client.keys[alg];
|
|
516
|
+
if (!key)
|
|
517
|
+
throw new Error(`There is no key defined for alg ${alg}`);
|
|
518
|
+
const callbackUrl = `${apiUrl}/authentication-responses`;
|
|
519
|
+
const agent = new SiopAgent({
|
|
520
|
+
privateKey: await importJWK(key.privateKeyJwk, alg),
|
|
521
|
+
alg,
|
|
522
|
+
kid: key.kid,
|
|
523
|
+
siopV2: true,
|
|
524
|
+
});
|
|
525
|
+
const { idToken } = await agent.createResponse({
|
|
526
|
+
nonce,
|
|
527
|
+
redirectUri: callbackUrl,
|
|
528
|
+
claims: {
|
|
529
|
+
encryption_key: key.publicKeyEncryptionJwk,
|
|
530
|
+
},
|
|
531
|
+
responseMode: "form_post",
|
|
532
|
+
}, {
|
|
533
|
+
syntaxType: client.didVersion === 1 ? "jwk_thumbprint_subject" : "did_subject",
|
|
534
|
+
});
|
|
535
|
+
const data = `id_token=${idToken}`;
|
|
536
|
+
const response = await utils.httpCall.post(callbackUrl, data, {
|
|
537
|
+
headers: {
|
|
538
|
+
...httpOpts.headers,
|
|
539
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
540
|
+
},
|
|
541
|
+
});
|
|
542
|
+
return response.data.verifiableCredential;
|
|
543
|
+
}
|
|
544
|
+
case "authentication": {
|
|
545
|
+
const alg = params[0] || "ES256K";
|
|
546
|
+
const vc = await execCommand(`onboarding sendAuthResponse ${alg}`, true);
|
|
547
|
+
const vp = await execCommand(`compute createPresentationJwt ${vc} ${alg} authorisation-api`, true);
|
|
548
|
+
const request = await execCommand(`authorisation-old siopRequest`, true);
|
|
549
|
+
const callbackUrl = await execCommand(`compute verifyAuthenticationRequest ${JSON.stringify(request)}`, true);
|
|
550
|
+
const sessionResponse = await execCommand(`authorisation-old siopSession ${callbackUrl} ${alg} ${vp}`, true);
|
|
551
|
+
const accessToken = await execCommand(`compute verifySessionResponse ${JSON.stringify(sessionResponse)}`, true);
|
|
552
|
+
return accessToken;
|
|
553
|
+
}
|
|
554
|
+
default:
|
|
555
|
+
utils.red(`Invalid method '${method}'`);
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
return 0;
|
|
559
|
+
}
|
|
560
|
+
async function conformanceOld(method, inputs) {
|
|
561
|
+
const apiUrl = config.api.conformanceV2.url;
|
|
562
|
+
switch (method) {
|
|
563
|
+
case "get": {
|
|
564
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(inputs)}`, httpOpts);
|
|
565
|
+
return response.data;
|
|
566
|
+
}
|
|
567
|
+
case "setId": {
|
|
568
|
+
const id = readValue(inputs[0]);
|
|
569
|
+
let conformanceId;
|
|
570
|
+
if (id === "null")
|
|
571
|
+
conformanceId = undefined;
|
|
572
|
+
else if (!id)
|
|
573
|
+
conformanceId = randomUUID();
|
|
574
|
+
else
|
|
575
|
+
conformanceId = id;
|
|
576
|
+
await setVar("conformanceId", conformanceId);
|
|
577
|
+
updateHttpOpts();
|
|
578
|
+
return execCommand("view conformanceId", false);
|
|
579
|
+
}
|
|
580
|
+
case "issuerInitiate": {
|
|
581
|
+
const flowType = readValue(inputs[0]) || "same-device";
|
|
582
|
+
const redirect = readValue(inputs[1]) || "false";
|
|
583
|
+
const urlParams = { redirect, flow_type: flowType };
|
|
584
|
+
const response = await utils.httpCall.get(`${apiUrl}/issuer-mock/initiate?${qs.stringify(urlParams)}`, httpOpts);
|
|
585
|
+
const openid = response.data;
|
|
586
|
+
return qs.parse(openid.split("?")[1]);
|
|
587
|
+
}
|
|
588
|
+
case "issuerAuthorize": {
|
|
589
|
+
const redirectUri = readValue(inputs[0]) || "http://localhost:3000";
|
|
590
|
+
const credentialType = readValue(inputs[1]);
|
|
591
|
+
Joi.assert(redirectUri, Joi.string());
|
|
592
|
+
Joi.assert(credentialType, Joi.string().optional());
|
|
593
|
+
const urlparams = {
|
|
594
|
+
scope: "openid conformance_testing",
|
|
595
|
+
response_type: "code",
|
|
596
|
+
redirect_uri: redirectUri,
|
|
597
|
+
client_id: client.did,
|
|
598
|
+
response_mode: "post",
|
|
599
|
+
state: randomBytes(6).toString("hex"),
|
|
600
|
+
authorization_details: JSON.stringify([
|
|
601
|
+
{
|
|
602
|
+
type: "openid_credential",
|
|
603
|
+
credential_type: credentialType,
|
|
604
|
+
format: "jwt_vc",
|
|
605
|
+
},
|
|
606
|
+
]),
|
|
607
|
+
};
|
|
608
|
+
const urlParamsString = qs.stringify(urlparams);
|
|
609
|
+
const response = await utils.httpCall.get(`${apiUrl}/issuer-mock/authorize?${urlParamsString}`, httpOpts);
|
|
610
|
+
const urlResponse = response.headers
|
|
611
|
+
.location;
|
|
612
|
+
const location = new URL(urlResponse).searchParams;
|
|
613
|
+
if (location.get("error"))
|
|
614
|
+
throw new Error(location.toString());
|
|
615
|
+
return {
|
|
616
|
+
code: location.get("code"),
|
|
617
|
+
state: location.get("state"),
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
case "issuerToken": {
|
|
621
|
+
const code = readValue(inputs[0]);
|
|
622
|
+
const redirectUri = readValue(inputs[1]) || "http://localhost:3000";
|
|
623
|
+
Joi.assert(code, Joi.string());
|
|
624
|
+
Joi.assert(redirectUri, Joi.string());
|
|
625
|
+
const body = {
|
|
626
|
+
code,
|
|
627
|
+
grant_type: "authorization_code",
|
|
628
|
+
redirect_uri: redirectUri,
|
|
629
|
+
};
|
|
630
|
+
const response = await utils.httpCall.post(`${apiUrl}/issuer-mock/token`, new URLSearchParams(body).toString(), httpOptsUrlencoded);
|
|
631
|
+
return response.data;
|
|
632
|
+
}
|
|
633
|
+
case "issuerCredential": {
|
|
634
|
+
const cNonce = readValue(inputs[0]);
|
|
635
|
+
const accessToken = readValue(inputs[1]) || token;
|
|
636
|
+
const alg = readValue(inputs[2]) || "ES256K";
|
|
637
|
+
const credentialType = readValue(inputs[3]);
|
|
638
|
+
const issuerUrl = readValue(inputs[4]);
|
|
639
|
+
Joi.assert(cNonce, Joi.string());
|
|
640
|
+
if (!client.keys[alg])
|
|
641
|
+
throw new Error(`There is no key defined for alg ${alg}`);
|
|
642
|
+
const privateKey = await importJWK(client.keys[alg].privateKeyJwk, alg);
|
|
643
|
+
const jwt = await new SignJWT({
|
|
644
|
+
nonce: cNonce,
|
|
645
|
+
aud: issuerUrl,
|
|
646
|
+
})
|
|
647
|
+
.setProtectedHeader({
|
|
648
|
+
alg,
|
|
649
|
+
typ: "JWT",
|
|
650
|
+
kid: client.keys[alg].kid,
|
|
651
|
+
...(client.didVersion === 2 && {
|
|
652
|
+
jwk: client.keys[alg].publicKeyJwk,
|
|
653
|
+
}),
|
|
654
|
+
})
|
|
655
|
+
.setIssuedAt()
|
|
656
|
+
.setIssuer(client.did)
|
|
657
|
+
.sign(privateKey);
|
|
658
|
+
const endpoint = "/issuer-mock/credential";
|
|
659
|
+
const headers = {
|
|
660
|
+
authorization: `Bearer ${accessToken}`,
|
|
661
|
+
};
|
|
662
|
+
const body = {
|
|
663
|
+
type: credentialType,
|
|
664
|
+
proof: {
|
|
665
|
+
proof_type: "jwt",
|
|
666
|
+
jwt,
|
|
667
|
+
},
|
|
668
|
+
};
|
|
669
|
+
const response = await utils.httpCall.post(`${apiUrl}${endpoint}`, qs.stringify(body), {
|
|
670
|
+
headers: { ...httpOpts.headers, ...headers },
|
|
671
|
+
});
|
|
672
|
+
return response.data;
|
|
673
|
+
}
|
|
674
|
+
case "verifierAuthRequest": {
|
|
675
|
+
const flowType = readValue(inputs[0]) || "same-device";
|
|
676
|
+
const redirect = readValue(inputs[1]) || "false";
|
|
677
|
+
const urlparams = { redirect, flow_type: flowType };
|
|
678
|
+
let dataResponse;
|
|
679
|
+
{
|
|
680
|
+
const response = await utils.httpCall.get(`${apiUrl}/verifier-mock/authentication-requests?${qs.stringify(urlparams)}`, httpOpts);
|
|
681
|
+
dataResponse = response.data;
|
|
682
|
+
}
|
|
683
|
+
const uriDecoded = qs.parse(dataResponse.replace("openid://?", ""));
|
|
684
|
+
return uriDecoded;
|
|
685
|
+
}
|
|
686
|
+
case "verifierAuthResponse": {
|
|
687
|
+
const jwtVp = readValue(inputs[0]);
|
|
688
|
+
const alg = readValue(inputs[1]) || "ES256K";
|
|
689
|
+
Joi.assert(jwtVp, Joi.string());
|
|
690
|
+
if (!client.keys[alg])
|
|
691
|
+
throw new Error(`There is no key defined for alg ${alg}`);
|
|
692
|
+
const privateKey = await importJWK(client.keys[alg].privateKeyJwk, alg);
|
|
693
|
+
const idToken = await new SignJWT({
|
|
694
|
+
_vp_token: {
|
|
695
|
+
presentation_submission: {
|
|
696
|
+
id: randomUUID(),
|
|
697
|
+
definition_id: "conformance_mock_vp_request",
|
|
698
|
+
descriptor_map: [
|
|
699
|
+
{
|
|
700
|
+
id: "conformance_mock_vp",
|
|
701
|
+
format: "jwt_vp",
|
|
702
|
+
path: "$",
|
|
703
|
+
},
|
|
704
|
+
],
|
|
705
|
+
},
|
|
706
|
+
},
|
|
707
|
+
})
|
|
708
|
+
.setProtectedHeader({
|
|
709
|
+
alg,
|
|
710
|
+
typ: "JWT",
|
|
711
|
+
kid: client.keys[alg].kid,
|
|
712
|
+
...(client.didVersion === 2 && {
|
|
713
|
+
jwk: client.keys[alg].publicKeyJwk,
|
|
714
|
+
}),
|
|
715
|
+
})
|
|
716
|
+
.setIssuedAt()
|
|
717
|
+
.setIssuer("https://self-issued.me/v2")
|
|
718
|
+
.sign(privateKey);
|
|
719
|
+
const body = {
|
|
720
|
+
id_token: idToken,
|
|
721
|
+
vp_token: jwtVp,
|
|
722
|
+
};
|
|
723
|
+
const response = await utils.httpCall.post(`${apiUrl}/verifier-mock/authentication-responses`, qs.stringify(body), httpOptsUrlencoded);
|
|
724
|
+
return response.data;
|
|
725
|
+
}
|
|
726
|
+
case "issuer": {
|
|
727
|
+
let response = await execCommand("conformance-old issuerInitiate", true);
|
|
728
|
+
const { credential_type: credentialType, issuer: issuerUrl } = response;
|
|
729
|
+
response = await execCommand(`conformance-old issuerAuthorize http://localhost:3000 ${credentialType}`, true);
|
|
730
|
+
const { code } = response;
|
|
731
|
+
response = await execCommand(`conformance-old issuerToken ${code}`, true);
|
|
732
|
+
const { access_token: accessToken, c_nonce: cNonce } = response;
|
|
733
|
+
response = await execCommand(`conformance-old issuerCredential ${cNonce} ${accessToken} ES256K ${credentialType} ${issuerUrl}`, true);
|
|
734
|
+
return response;
|
|
735
|
+
}
|
|
736
|
+
case "verifier": {
|
|
737
|
+
const { credential: jwtVc } = await execCommand(`conformance-old issuer`, true);
|
|
738
|
+
await execCommand(`conformance-old verifierAuthRequest`, true);
|
|
739
|
+
const vcDecoded = await execCommand(`compute decodeJWT ${jwtVc}`, true);
|
|
740
|
+
const audience = vcDecoded.payload.iss;
|
|
741
|
+
const jwtVp = await execCommand(`compute createPresentationJwt ${jwtVc} ES256K ${audience}`, true);
|
|
742
|
+
const response = await execCommand(`conformance-old verifierAuthResponse ${jwtVp}`, true);
|
|
743
|
+
return response;
|
|
744
|
+
}
|
|
745
|
+
default:
|
|
746
|
+
utils.red(`Invalid method '${method}'`);
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
return 0;
|
|
750
|
+
}
|
|
751
|
+
async function smartContractApi(contract, method, ...inputs) {
|
|
752
|
+
const apiUrl = config.api[contract].url;
|
|
753
|
+
if (method === "get") {
|
|
754
|
+
const response = await utils.httpCall.get(`${apiUrl}${urlPath(inputs)}`, httpOpts);
|
|
755
|
+
return response.data;
|
|
756
|
+
}
|
|
757
|
+
const url = `${apiUrl}/jsonrpc`;
|
|
758
|
+
if (method === "sendSignedTransaction") {
|
|
759
|
+
const unsignedTransaction = readValue(inputs[0]);
|
|
760
|
+
const sgnTx = readValue(inputs[1]);
|
|
761
|
+
Joi.assert(unsignedTransaction, Joi.object());
|
|
762
|
+
Joi.assert(sgnTx, Joi.string());
|
|
763
|
+
const bodySend = jsonrpcBody(method, [
|
|
764
|
+
paramSignedTransaction(unsignedTransaction, sgnTx),
|
|
765
|
+
]);
|
|
766
|
+
const response = await utils.httpCall.post(url, bodySend, httpOpts);
|
|
767
|
+
// use ledger proxy is besu provider is defined
|
|
768
|
+
const context = {
|
|
769
|
+
config,
|
|
770
|
+
httpOpts,
|
|
771
|
+
client,
|
|
772
|
+
trustedApp,
|
|
773
|
+
rtVars,
|
|
774
|
+
transactionInfo,
|
|
775
|
+
token,
|
|
776
|
+
oauth2token,
|
|
777
|
+
};
|
|
778
|
+
const useProxy = !!config.besuProvider;
|
|
779
|
+
transactionInfo.txId = response.data.result;
|
|
780
|
+
transactionInfo.receipt = await waitToBeMined(response.data.result, useProxy, context);
|
|
781
|
+
return transactionInfo.receipt;
|
|
782
|
+
}
|
|
783
|
+
if (!method.startsWith("build-")) {
|
|
784
|
+
const inputsStr = inputs
|
|
785
|
+
.map((input) => typeof input === "string" ? input : JSON.stringify(input))
|
|
786
|
+
.join(" ");
|
|
787
|
+
const uTx = await execCommand(`${contract} build-${method} ${inputsStr}`, true);
|
|
788
|
+
const sgnTx = await execCommand(`compute signTransaction ${JSON.stringify(uTx)}`, true);
|
|
789
|
+
const receipt = await execCommand(`${contract} sendSignedTransaction ${JSON.stringify(uTx)} ${sgnTx}`, true);
|
|
790
|
+
await execCommand("view transactionInfo", true);
|
|
791
|
+
return receipt;
|
|
792
|
+
}
|
|
793
|
+
let m = method.replace("build-", "");
|
|
794
|
+
const build = await buildParam(contract, m, client, inputs.map((input) => readValue(input)));
|
|
795
|
+
if (build.method)
|
|
796
|
+
m = build.method.substring(0, build.method.indexOf("("));
|
|
797
|
+
const param = {
|
|
798
|
+
from: client.ethWallet.address,
|
|
799
|
+
...build.param,
|
|
800
|
+
};
|
|
801
|
+
const body = jsonrpcBody(m, [param]);
|
|
802
|
+
const response = await utils.httpCall.post(url, body, httpOpts);
|
|
803
|
+
utils.yellow(build.info.title);
|
|
804
|
+
utils.yellow(build.info.data);
|
|
805
|
+
transactionInfo = {
|
|
806
|
+
contract,
|
|
807
|
+
method: m,
|
|
808
|
+
build,
|
|
809
|
+
};
|
|
810
|
+
return response.data.result;
|
|
811
|
+
}
|
|
812
|
+
function environment(env) {
|
|
813
|
+
if (env) {
|
|
814
|
+
config = loadConfig(env);
|
|
815
|
+
utils.yellow(`Environment ${env} loaded`);
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
utils.yellow(`Current environment: ${config.env}`);
|
|
819
|
+
}
|
|
820
|
+
const { domain, contractAddresses, api, env: envConfig } = config;
|
|
821
|
+
utils.yellow({
|
|
822
|
+
domain,
|
|
823
|
+
contractAddresses,
|
|
824
|
+
urls: Object.keys(api).map((name) => api[name].url),
|
|
825
|
+
env: envConfig,
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
function setDomain(dom) {
|
|
829
|
+
if (dom) {
|
|
830
|
+
Object.keys(config.api).forEach((apiName) => {
|
|
831
|
+
config.api[apiName].url = config.api[apiName].url.replace(config.domain, dom);
|
|
832
|
+
});
|
|
833
|
+
config.domain = dom;
|
|
834
|
+
}
|
|
835
|
+
utils.yellow(`Current domain: ${config.domain}`);
|
|
836
|
+
}
|
|
837
|
+
function wctOld(method, inputs) {
|
|
838
|
+
switch (method) {
|
|
839
|
+
case "loadReport": {
|
|
840
|
+
const filename = readValue(inputs[0]);
|
|
841
|
+
Joi.assert(filename, Joi.string());
|
|
842
|
+
const data = fs.readFileSync(filename, "utf8");
|
|
843
|
+
const book = JSON.parse(data);
|
|
844
|
+
utils.yellow(`Report loaded: ${filename}`);
|
|
845
|
+
return book;
|
|
846
|
+
}
|
|
847
|
+
case "check": {
|
|
848
|
+
const logs = readValue(inputs[0]);
|
|
849
|
+
if (!logs || logs.length === 0)
|
|
850
|
+
throw new Error("No logs found");
|
|
851
|
+
const iniTime = new Date(logs[0].created).toISOString();
|
|
852
|
+
const endTime = new Date(logs[logs.length - 1].created).toISOString();
|
|
853
|
+
const conformanceId = logs[0].data.request.headers.conformance;
|
|
854
|
+
console.log([
|
|
855
|
+
"",
|
|
856
|
+
chalk.yellow("----------------------------------------------------"),
|
|
857
|
+
chalk.yellow("Wallet Conformance Testing Report"),
|
|
858
|
+
chalk.yellow("----------------------------------------------------"),
|
|
859
|
+
"",
|
|
860
|
+
`conformance id: ${chalk.magenta(conformanceId)}`,
|
|
861
|
+
"",
|
|
862
|
+
"timestamp:",
|
|
863
|
+
` from: ${chalk.magenta(iniTime)}`,
|
|
864
|
+
` to: ${chalk.magenta(endTime)}`,
|
|
865
|
+
"",
|
|
866
|
+
].join("\n"));
|
|
867
|
+
const missingUrls = [
|
|
868
|
+
"/conformance/v2/issuer-mock/initiate",
|
|
869
|
+
"/conformance/v2/issuer-mock/authorize",
|
|
870
|
+
"/conformance/v2/issuer-mock/token",
|
|
871
|
+
"/conformance/v2/issuer-mock/credential",
|
|
872
|
+
"/conformance/v2/verifier-mock/authentication-requests",
|
|
873
|
+
"/conformance/v2/verifier-mock/authentication-responses",
|
|
874
|
+
];
|
|
875
|
+
let numberErrors = 0;
|
|
876
|
+
logs.forEach((log) => {
|
|
877
|
+
const testOk = log.data.response.statusCode < 400;
|
|
878
|
+
const url = log.data.request.url.split("?")[0];
|
|
879
|
+
const result = testOk ? chalk.green("OK") : chalk.red("FAIL");
|
|
880
|
+
console.log(url + ".".repeat(70 - url.length) + result);
|
|
881
|
+
if (!testOk)
|
|
882
|
+
numberErrors += 1;
|
|
883
|
+
const id = missingUrls.findIndex((u) => u === url);
|
|
884
|
+
if (id >= 0)
|
|
885
|
+
missingUrls.splice(id, 1);
|
|
886
|
+
});
|
|
887
|
+
missingUrls.forEach((url) => {
|
|
888
|
+
console.log(url + ".".repeat(70 - url.length) + chalk.red("NO LOGS"));
|
|
889
|
+
});
|
|
890
|
+
numberErrors += missingUrls.length;
|
|
891
|
+
console.log("");
|
|
892
|
+
const numberSuccess = logs.length + missingUrls.length - numberErrors;
|
|
893
|
+
if (numberSuccess)
|
|
894
|
+
console.log(chalk.green.bold(numberSuccess) + chalk.green(" test passed"));
|
|
895
|
+
if (numberErrors)
|
|
896
|
+
console.log(chalk.red.bold(numberErrors) + chalk.red(" test failed"));
|
|
897
|
+
return 0;
|
|
898
|
+
}
|
|
899
|
+
default:
|
|
900
|
+
utils.red(`Invalid method '${method}'`);
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
return 0;
|
|
904
|
+
}
|
|
905
|
+
function fileSystem(method, ...params) {
|
|
906
|
+
switch (method) {
|
|
907
|
+
case "readBinaryFile": {
|
|
908
|
+
const [filename] = params;
|
|
909
|
+
Joi.assert(filename, Joi.string());
|
|
910
|
+
return fs.readFileSync(filename);
|
|
911
|
+
}
|
|
912
|
+
case "writeBinaryFile": {
|
|
913
|
+
const filename = readValue(params[0]);
|
|
914
|
+
const data = readValue(params[1]);
|
|
915
|
+
Joi.assert(filename, Joi.string());
|
|
916
|
+
fs.writeFileSync(filename, data);
|
|
917
|
+
return 0;
|
|
918
|
+
}
|
|
919
|
+
default:
|
|
920
|
+
utils.red(`Invalid method '${method}'`);
|
|
921
|
+
return 0;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
async function run(filename, inputs = []) {
|
|
925
|
+
const lines = fs.readFileSync(`scripts/${filename}`, "utf8").split(/\r?\n/);
|
|
926
|
+
let response;
|
|
927
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
928
|
+
let line = lines[i].trim();
|
|
929
|
+
inputs.forEach((input, j) => {
|
|
930
|
+
const param = typeof input === "string" ? input : JSON.stringify(input);
|
|
931
|
+
line = line.replace(new RegExp(`\\$${j + 1}`, "g"), param);
|
|
932
|
+
});
|
|
933
|
+
try {
|
|
934
|
+
if (line.length > 0 && !line.startsWith("#")) {
|
|
935
|
+
response = await execCommand(line, true);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
catch (error) {
|
|
939
|
+
utils.red(error.stack);
|
|
940
|
+
throw new Error(`Error in line ${i + 1}: ${error.message}`);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return response;
|
|
944
|
+
}
|
|
945
|
+
export async function execCommand(command, printCommand = false) {
|
|
946
|
+
if (printCommand)
|
|
947
|
+
console.log(`==> ${command}`);
|
|
948
|
+
const parts = parseLine(command);
|
|
949
|
+
let varName = "";
|
|
950
|
+
if (parts.length === 0)
|
|
951
|
+
return 0;
|
|
952
|
+
if (typeof parts[0] === "string" && parts[0].includes(":")) {
|
|
953
|
+
varName = parts[0].replace(":", "");
|
|
954
|
+
parts.shift();
|
|
955
|
+
}
|
|
956
|
+
const [part0, part1] = parts;
|
|
957
|
+
const parts2 = parts.slice(2);
|
|
958
|
+
const method = part0;
|
|
959
|
+
const word1 = part1;
|
|
960
|
+
Joi.assert(method, Joi.string());
|
|
961
|
+
// APIs linked to smart contracts
|
|
962
|
+
if ([
|
|
963
|
+
"timestamp",
|
|
964
|
+
"timestamp-new",
|
|
965
|
+
"did",
|
|
966
|
+
"did-old",
|
|
967
|
+
"did-new",
|
|
968
|
+
"tar",
|
|
969
|
+
"tar-new",
|
|
970
|
+
"tir",
|
|
971
|
+
"tir-old",
|
|
972
|
+
"tir-new",
|
|
973
|
+
"tsr",
|
|
974
|
+
"tsr-new",
|
|
975
|
+
"tpr",
|
|
976
|
+
"tpr-new",
|
|
977
|
+
].includes(method)) {
|
|
978
|
+
Joi.assert(word1, Joi.string());
|
|
979
|
+
const response = await smartContractApi(method, word1, ...parts2);
|
|
980
|
+
if (varName)
|
|
981
|
+
await setVar(varName, response);
|
|
982
|
+
return response;
|
|
983
|
+
}
|
|
984
|
+
const schemaStrings = Joi.array().items(Joi.string());
|
|
985
|
+
const context = {
|
|
986
|
+
config,
|
|
987
|
+
httpOpts,
|
|
988
|
+
client,
|
|
989
|
+
trustedApp,
|
|
990
|
+
rtVars,
|
|
991
|
+
transactionInfo,
|
|
992
|
+
token,
|
|
993
|
+
oauth2token,
|
|
994
|
+
};
|
|
995
|
+
// Other APIs and configurations
|
|
996
|
+
switch (method) {
|
|
997
|
+
case "fs": {
|
|
998
|
+
Joi.assert(word1, Joi.string());
|
|
999
|
+
const response = fileSystem(word1, ...parts2);
|
|
1000
|
+
console.log(response);
|
|
1001
|
+
if (varName)
|
|
1002
|
+
await setVar(varName, response);
|
|
1003
|
+
return response;
|
|
1004
|
+
}
|
|
1005
|
+
case "set": {
|
|
1006
|
+
Joi.assert(word1, Joi.string());
|
|
1007
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1008
|
+
let value = inputs[0];
|
|
1009
|
+
if (inputs.length > 1) {
|
|
1010
|
+
Joi.assert(inputs, schemaStrings);
|
|
1011
|
+
value = inputs.join("");
|
|
1012
|
+
}
|
|
1013
|
+
await setVar(word1, value);
|
|
1014
|
+
return value;
|
|
1015
|
+
}
|
|
1016
|
+
case "view": {
|
|
1017
|
+
Joi.assert(word1, Joi.string());
|
|
1018
|
+
return view([readValue(word1)], context);
|
|
1019
|
+
}
|
|
1020
|
+
case "using": {
|
|
1021
|
+
Joi.assert(word1, Joi.string());
|
|
1022
|
+
const user = await using(word1, ...parts2);
|
|
1023
|
+
return user;
|
|
1024
|
+
}
|
|
1025
|
+
case "env": {
|
|
1026
|
+
Joi.assert(word1, Joi.string().optional());
|
|
1027
|
+
const input = readValue(word1);
|
|
1028
|
+
environment(input);
|
|
1029
|
+
return 0;
|
|
1030
|
+
}
|
|
1031
|
+
case "domain": {
|
|
1032
|
+
Joi.assert(word1, Joi.string());
|
|
1033
|
+
setDomain(word1);
|
|
1034
|
+
return 0;
|
|
1035
|
+
}
|
|
1036
|
+
case "authorisation": {
|
|
1037
|
+
Joi.assert(word1, Joi.string());
|
|
1038
|
+
Joi.assert(parts2, schemaStrings);
|
|
1039
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1040
|
+
const response = await authorisationV3(word1, inputs, context);
|
|
1041
|
+
if (varName)
|
|
1042
|
+
await setVar(varName, response);
|
|
1043
|
+
return response;
|
|
1044
|
+
}
|
|
1045
|
+
case "authorisation-new": {
|
|
1046
|
+
Joi.assert(word1, Joi.string());
|
|
1047
|
+
Joi.assert(parts2, schemaStrings);
|
|
1048
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1049
|
+
const response = await authorisationV4(word1, inputs, context);
|
|
1050
|
+
if (varName)
|
|
1051
|
+
await setVar(varName, response);
|
|
1052
|
+
return response;
|
|
1053
|
+
}
|
|
1054
|
+
case "authorisation-old": {
|
|
1055
|
+
Joi.assert(word1, Joi.string());
|
|
1056
|
+
Joi.assert(parts2, schemaStrings);
|
|
1057
|
+
const response = await authorisationV2(word1, parts2);
|
|
1058
|
+
if (varName)
|
|
1059
|
+
await setVar(varName, response);
|
|
1060
|
+
return response;
|
|
1061
|
+
}
|
|
1062
|
+
case "notifications": {
|
|
1063
|
+
Joi.assert(word1, Joi.string());
|
|
1064
|
+
const response = await notifications(word1, ...parts2);
|
|
1065
|
+
if (varName)
|
|
1066
|
+
await setVar(varName, response);
|
|
1067
|
+
return response;
|
|
1068
|
+
}
|
|
1069
|
+
case "datahub": {
|
|
1070
|
+
Joi.assert(word1, Joi.string());
|
|
1071
|
+
const response = await proxydatahub(word1, parts2);
|
|
1072
|
+
if (varName)
|
|
1073
|
+
await setVar(varName, response);
|
|
1074
|
+
return response;
|
|
1075
|
+
}
|
|
1076
|
+
case "storage": {
|
|
1077
|
+
Joi.assert(word1, Joi.string());
|
|
1078
|
+
const response = await storage(word1, parts2);
|
|
1079
|
+
if (varName)
|
|
1080
|
+
await setVar(varName, response);
|
|
1081
|
+
return response;
|
|
1082
|
+
}
|
|
1083
|
+
case "cassandra": {
|
|
1084
|
+
Joi.assert(word1, Joi.string());
|
|
1085
|
+
const response = await cassandra(word1, parts2);
|
|
1086
|
+
if (varName)
|
|
1087
|
+
await setVar(varName, response);
|
|
1088
|
+
return response;
|
|
1089
|
+
}
|
|
1090
|
+
case "proxyledger": {
|
|
1091
|
+
Joi.assert(word1, Joi.string());
|
|
1092
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1093
|
+
const response = await ledgerV4(word1, inputs, true, context);
|
|
1094
|
+
if (varName)
|
|
1095
|
+
await setVar(varName, response);
|
|
1096
|
+
return response;
|
|
1097
|
+
}
|
|
1098
|
+
case "ledger": {
|
|
1099
|
+
Joi.assert(word1, Joi.string());
|
|
1100
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1101
|
+
const response = await ledgerV3(word1, inputs, false, context);
|
|
1102
|
+
if (varName)
|
|
1103
|
+
await setVar(varName, response);
|
|
1104
|
+
return response;
|
|
1105
|
+
}
|
|
1106
|
+
case "ledger-new": {
|
|
1107
|
+
Joi.assert(word1, Joi.string());
|
|
1108
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1109
|
+
const response = await ledgerV4(word1, inputs, false, context);
|
|
1110
|
+
if (varName)
|
|
1111
|
+
await setVar(varName, response);
|
|
1112
|
+
return response;
|
|
1113
|
+
}
|
|
1114
|
+
case "onboarding": {
|
|
1115
|
+
Joi.assert(word1, Joi.string());
|
|
1116
|
+
Joi.assert(parts2, schemaStrings);
|
|
1117
|
+
const response = await onboarding(word1, ...parts2);
|
|
1118
|
+
if (varName)
|
|
1119
|
+
await setVar(varName, response);
|
|
1120
|
+
return response;
|
|
1121
|
+
}
|
|
1122
|
+
case "conformance": {
|
|
1123
|
+
Joi.assert(word1, Joi.string());
|
|
1124
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1125
|
+
const response = await conformanceV3(word1, inputs, context);
|
|
1126
|
+
if (varName)
|
|
1127
|
+
await setVar(varName, response);
|
|
1128
|
+
return response;
|
|
1129
|
+
}
|
|
1130
|
+
case "conformance-new": {
|
|
1131
|
+
Joi.assert(word1, Joi.string());
|
|
1132
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1133
|
+
const response = await conformanceV4(word1, inputs, context);
|
|
1134
|
+
if (varName)
|
|
1135
|
+
await setVar(varName, response);
|
|
1136
|
+
return response;
|
|
1137
|
+
}
|
|
1138
|
+
case "conformance-old": {
|
|
1139
|
+
Joi.assert(word1, Joi.string());
|
|
1140
|
+
const response = await conformanceOld(word1, parts2);
|
|
1141
|
+
if (varName)
|
|
1142
|
+
await setVar(varName, response);
|
|
1143
|
+
return response;
|
|
1144
|
+
}
|
|
1145
|
+
case "compute": {
|
|
1146
|
+
Joi.assert(word1, Joi.string());
|
|
1147
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1148
|
+
const response = await compute(word1, inputs, context);
|
|
1149
|
+
if (varName)
|
|
1150
|
+
await setVar(varName, response);
|
|
1151
|
+
return response;
|
|
1152
|
+
}
|
|
1153
|
+
case "load": {
|
|
1154
|
+
const filename = readValue(word1);
|
|
1155
|
+
const data = fs.readFileSync(filename, "utf8");
|
|
1156
|
+
const response = JSON.parse(data);
|
|
1157
|
+
if (varName)
|
|
1158
|
+
await setVar(varName, response);
|
|
1159
|
+
return response;
|
|
1160
|
+
}
|
|
1161
|
+
case "wct-old": {
|
|
1162
|
+
Joi.assert(word1, Joi.string());
|
|
1163
|
+
const response = wctOld(word1, parts2);
|
|
1164
|
+
if (varName)
|
|
1165
|
+
await setVar(varName, response, false);
|
|
1166
|
+
return response;
|
|
1167
|
+
}
|
|
1168
|
+
case "run": {
|
|
1169
|
+
Joi.assert(word1, Joi.string());
|
|
1170
|
+
const inputs = parts2.map((p) => readValue(p));
|
|
1171
|
+
const response = await run(word1, inputs);
|
|
1172
|
+
if (varName)
|
|
1173
|
+
await setVar(varName, response);
|
|
1174
|
+
return response;
|
|
1175
|
+
}
|
|
1176
|
+
case "exit": {
|
|
1177
|
+
process.exit(0);
|
|
1178
|
+
return 0;
|
|
1179
|
+
}
|
|
1180
|
+
default:
|
|
1181
|
+
utils.red(`Invalid method '${method}'`);
|
|
1182
|
+
return 0;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
export async function main() {
|
|
1186
|
+
const rl = readline.createInterface({
|
|
1187
|
+
input: process.stdin,
|
|
1188
|
+
output: process.stdout,
|
|
1189
|
+
});
|
|
1190
|
+
// eslint-disable-next-line no-constant-condition
|
|
1191
|
+
while (true) {
|
|
1192
|
+
const command = await new Promise((resolve) => {
|
|
1193
|
+
rl.question("==> ", (input) => {
|
|
1194
|
+
resolve(input);
|
|
1195
|
+
});
|
|
1196
|
+
});
|
|
1197
|
+
try {
|
|
1198
|
+
await execCommand(command);
|
|
1199
|
+
}
|
|
1200
|
+
catch (error) {
|
|
1201
|
+
utils.red(error.stack);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
//# sourceMappingURL=app.js.map
|