@peerbit/server 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/lib/esm/cli.js +67 -20
  2. package/lib/esm/cli.js.map +1 -1
  3. package/lib/esm/client.d.ts +7 -1
  4. package/lib/esm/client.js +48 -31
  5. package/lib/esm/client.js.map +1 -1
  6. package/lib/esm/config.d.ts +3 -3
  7. package/lib/esm/config.js +18 -16
  8. package/lib/esm/config.js.map +1 -1
  9. package/lib/esm/peerbit.d.ts +2 -0
  10. package/lib/esm/peerbit.js +1 -0
  11. package/lib/esm/peerbit.js.map +1 -1
  12. package/lib/esm/remotes.d.ts +1 -2
  13. package/lib/esm/remotes.js +1 -2
  14. package/lib/esm/remotes.js.map +1 -1
  15. package/lib/esm/routes.d.ts +1 -0
  16. package/lib/esm/routes.js +1 -0
  17. package/lib/esm/routes.js.map +1 -1
  18. package/lib/esm/server.d.ts +2 -6
  19. package/lib/esm/server.js +161 -176
  20. package/lib/esm/server.js.map +1 -1
  21. package/lib/esm/signes-request.d.ts +5 -0
  22. package/lib/esm/signes-request.js +54 -0
  23. package/lib/esm/signes-request.js.map +1 -0
  24. package/lib/esm/trust.browser.d.ts +0 -0
  25. package/lib/esm/trust.browser.js +3 -0
  26. package/lib/esm/trust.browser.js.map +1 -0
  27. package/lib/esm/trust.d.ts +9 -0
  28. package/lib/esm/trust.js +36 -0
  29. package/lib/esm/trust.js.map +1 -0
  30. package/lib/ui/assets/index-cac7195d.js +77 -0
  31. package/lib/ui/index.html +1 -1
  32. package/package.json +4 -4
  33. package/src/cli.ts +81 -25
  34. package/src/client.ts +77 -35
  35. package/src/config.ts +21 -23
  36. package/src/peerbit.ts +3 -0
  37. package/src/remotes.ts +1 -3
  38. package/src/routes.ts +1 -1
  39. package/src/server.ts +205 -241
  40. package/src/signes-request.ts +84 -0
  41. package/src/trust.browser.ts +1 -0
  42. package/src/trust.ts +39 -0
  43. package/lib/ui/assets/index-73eaa3bc.js +0 -53
package/lib/ui/index.html CHANGED
@@ -23,7 +23,7 @@
23
23
  Learn how to configure a non-root public URL by running `npm run build`.
24
24
  -->
25
25
  <title>Peerbit</title>
26
- <script type="module" crossorigin src="/assets/index-73eaa3bc.js"></script>
26
+ <script type="module" crossorigin src="/assets/index-cac7195d.js"></script>
27
27
  <link rel="stylesheet" href="/assets/index-5265c558.css">
28
28
  </head>
29
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/server",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "author": "dao.xyz",
5
5
  "repository": {
6
6
  "type": "git",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@peerbit/test-lib": "^0.0.1",
55
- "@peerbit/test-utils": "1.0.16",
55
+ "@peerbit/test-utils": "1.0.17",
56
56
  "@types/tmp": "^0.2.3",
57
57
  "@types/yargs": "^17.0.24",
58
58
  "aws-sdk": "^2.1259.0",
@@ -63,11 +63,11 @@
63
63
  "@dao-xyz/libp2p-noise": "^12.0.1",
64
64
  "axios": "^1.4.0",
65
65
  "chalk": "^5.3.0",
66
- "peerbit": "1.3.0",
66
+ "peerbit": "1.3.1",
67
67
  "tar-stream": "^3.1.6",
68
68
  "tmp": "^0.2.1",
69
69
  "yargs": "^17.7.2",
70
70
  "zlib": "^1.0.5"
71
71
  },
72
- "gitHead": "8d44d24618ae3aa0e5f2f2d77f0825d59774cce4"
72
+ "gitHead": "06d341c4ea81b70c76018899b029f4419c311500"
73
73
  }
package/src/cli.ts CHANGED
@@ -6,7 +6,12 @@ import {
6
6
  } from "./domain.js";
7
7
  import { startServerWithNode } from "./server.js";
8
8
  import { createRecord } from "./aws.js";
9
- import { getHomeConfigDir, getPackageName, getRemotesPath } from "./config.js";
9
+ import {
10
+ getHomeConfigDir,
11
+ getKeypair,
12
+ getPackageName,
13
+ getRemotesPath,
14
+ } from "./config.js";
10
15
  import chalk from "chalk";
11
16
  import { client } from "./client.js";
12
17
  import { InstallDependency, StartProgram } from "./types.js";
@@ -17,6 +22,7 @@ import fs from "fs";
17
22
  import path from "path";
18
23
  import { toBase64 } from "@peerbit/crypto";
19
24
  import { Remotes } from "./remotes.js";
25
+ import { peerIdFromString } from "@libp2p/peer-id";
20
26
 
21
27
  const padString = function (string: string, padding: number, padChar = " ") {
22
28
  const val = string.valueOf();
@@ -64,14 +70,6 @@ export const cli = async (args?: string[]) => {
64
70
  default: false,
65
71
  alias: "r",
66
72
  })
67
- .option("password", {
68
- describe:
69
- "Setup password so you can interact with the node remotely",
70
- type: "string",
71
- defaultDescription:
72
- "The password from the last session will be used or a password will be generated",
73
- default: undefined,
74
- })
75
73
  .option("port-api", {
76
74
  describe:
77
75
  "Set API server port. Only modify this when testing locally, since NGINX config depends on the default value",
@@ -94,12 +92,28 @@ export const cli = async (args?: string[]) => {
94
92
  ),
95
93
  ports: { api: args["port-api"], node: args["port-node"] },
96
94
  bootstrap: args.bootstrap,
97
- password: args.password,
98
95
  newSession: args.reset,
99
96
  });
100
97
  },
101
98
  })
102
-
99
+ .command({
100
+ command: "id",
101
+ describe: "Get peer id",
102
+ builder: (yargs: yargs.Argv) => {
103
+ yargs.option("directory", {
104
+ describe: "Peerbit directory",
105
+ defaultDescription: "~.peerbit",
106
+ type: "string",
107
+ alias: "d",
108
+ default: getHomeConfigDir(),
109
+ });
110
+ return yargs;
111
+ },
112
+ handler: async (args) => {
113
+ const kp = await getKeypair(args.directory);
114
+ console.log((await kp.toPeerId()).toString());
115
+ },
116
+ })
103
117
  .command(
104
118
  "domain",
105
119
  "Setup a domain and certificate for this node",
@@ -254,7 +268,7 @@ export const cli = async (args?: string[]) => {
254
268
  },
255
269
  })
256
270
  .command({
257
- command: "add <name> <address> <password>",
271
+ command: "add <name> <address>",
258
272
  describe: "Add remote",
259
273
  builder: (yargs: yargs.Argv) => {
260
274
  yargs
@@ -268,11 +282,6 @@ export const cli = async (args?: string[]) => {
268
282
  describe: "Remote address",
269
283
  demandOption: true,
270
284
  })
271
- .positional("password", {
272
- type: "string",
273
- describe: "Password",
274
- demandOption: true,
275
- })
276
285
  .option("directory", {
277
286
  describe: "Peerbit directory",
278
287
  defaultDescription: "~.peerbit",
@@ -287,7 +296,10 @@ export const cli = async (args?: string[]) => {
287
296
  if (args.name === "localhost") {
288
297
  throw new Error("Remote can not be named 'localhost'");
289
298
  }
290
- const api = await client(args.password, args.address);
299
+ const api = await client(
300
+ await getKeypair(args.directory),
301
+ args.address
302
+ );
291
303
  try {
292
304
  await api.program.list();
293
305
  } catch (error) {
@@ -297,7 +309,7 @@ export const cli = async (args?: string[]) => {
297
309
  fs.mkdirSync(args.directory, { recursive: true });
298
310
  }
299
311
  const remotes = new Remotes(getRemotesPath(args.directory));
300
- remotes.add(args.name, args.address, args.password);
312
+ remotes.add(args.name, args.address);
301
313
  },
302
314
  })
303
315
  .command({
@@ -363,20 +375,19 @@ export const cli = async (args?: string[]) => {
363
375
  api: Awaited<ReturnType<typeof client>>;
364
376
  }[] = [];
365
377
  console.log(getRemotesPath(connectArgs.directory));
378
+ const config = await import("./config.js");
379
+ const keypair = await config.getKeypair(connectArgs.directory);
380
+
366
381
  if (names.length > 0) {
367
382
  const remotes = new Remotes(
368
383
  getRemotesPath(connectArgs.directory)
369
384
  );
370
385
  for (const name of names) {
371
386
  if (name === "localhost") {
372
- const config = await import("./config.js");
373
- const adminPassword = await config.loadPassword(
374
- config.getServerConfigPath(connectArgs.directory)
375
- );
376
387
  apis.push({
377
388
  log: (string) => console.log("localhost: " + string),
378
389
  name: "localhost",
379
- api: await client(adminPassword),
390
+ api: await client(keypair),
380
391
  });
381
392
  } else {
382
393
  const remote = remotes.getByName(name);
@@ -389,10 +400,11 @@ export const cli = async (args?: string[]) => {
389
400
  } else {
390
401
  logFn = (string) => console.log(string);
391
402
  }
403
+
392
404
  apis.push({
393
405
  log: logFn,
394
406
  name,
395
- api: await client(remote.password, remote.address),
407
+ api: await client(keypair, remote.address),
396
408
  });
397
409
  }
398
410
  }
@@ -437,6 +449,50 @@ export const cli = async (args?: string[]) => {
437
449
  .demandCommand();
438
450
  return yargs;
439
451
  })
452
+ .command(
453
+ "access",
454
+ "Modify access control for this node",
455
+ (yargs) => {
456
+ yargs
457
+ .command({
458
+ command: "grant <peer-id>",
459
+ describe: "Give a peer-id admin capabilities",
460
+ builder: (yargs: yargs.Argv) => {
461
+ yargs.positional("peer-id", {
462
+ describe: "Peer id",
463
+ type: "string",
464
+ demandOption: true,
465
+ });
466
+ return yargs;
467
+ },
468
+ handler: async (args) => {
469
+ const peerId = peerIdFromString(args["peer-id"]);
470
+ for (const api of apis) {
471
+ await api.api.trust.add(peerId);
472
+ }
473
+ },
474
+ })
475
+ .command({
476
+ command: "deny <peer-id>",
477
+ describe: "Remove admin capabilities from peer-id",
478
+ builder: (yargs: yargs.Argv) => {
479
+ yargs.positional("peer-id", {
480
+ describe: "Peer id",
481
+ demandOption: true,
482
+ });
483
+ return yargs;
484
+ },
485
+ handler: async (args) => {
486
+ const peerId = peerIdFromString(args["peer-id"]);
487
+ for (const api of apis) {
488
+ await api.api.trust.remove(peerId);
489
+ }
490
+ },
491
+ })
492
+ .strict()
493
+ .demandCommand();
494
+ }
495
+ )
440
496
  .command("network", "Manage network", (yargs) => {
441
497
  yargs
442
498
  .command({
package/src/client.ts CHANGED
@@ -9,21 +9,37 @@ import {
9
9
  PROGRAMS_PATH,
10
10
  PROGRAM_PATH,
11
11
  RESTART_PATH,
12
+ TRUST_PATH,
12
13
  } from "./routes.js";
13
14
  import { Address } from "@peerbit/program";
14
15
  import { multiaddr } from "@multiformats/multiaddr";
16
+ import { signRequest } from "./signes-request.js";
17
+ import {
18
+ Ed25519PublicKey,
19
+ Identity,
20
+ PublicSignKey,
21
+ getPublicKeyFromPeerId,
22
+ } from "@peerbit/crypto";
23
+ import { PeerId } from "@libp2p/interface-peer-id";
15
24
 
16
25
  export const client = async (
17
- password: string,
26
+ keypair: Identity<Ed25519PublicKey>,
18
27
  endpoint: string = "http://localhost:" + LOCAL_PORT
19
28
  ) => {
20
29
  const isLocalHost = endpoint.startsWith("http://localhost");
21
-
22
- if (!isLocalHost && password == null) {
23
- throw new Error("Expecting password when starting the client");
24
- }
25
-
26
30
  const { default: axios } = await import("axios");
31
+ const axiosInstance = axios.create();
32
+ axiosInstance.interceptors.request.use(async (config) => {
33
+ const url = new URL(config.url!);
34
+ await signRequest(
35
+ config.headers,
36
+ config.method!,
37
+ url.pathname + url.search,
38
+ config.data,
39
+ keypair
40
+ );
41
+ return config;
42
+ });
27
43
 
28
44
  const validateStatus = (status: number) => {
29
45
  return (status >= 200 && status < 300) || status == 404;
@@ -53,19 +69,12 @@ export const client = async (
53
69
  };
54
70
  const getId = async () =>
55
71
  throwIfNot200(
56
- await axios.get(endpoint + PEER_ID_PATH, {
72
+ await axiosInstance.get(endpoint + PEER_ID_PATH, {
57
73
  validateStatus,
58
74
  timeout: 5000,
59
75
  })
60
76
  ).data;
61
77
 
62
- const getHeaders = async () => {
63
- const headers = {
64
- authorization: "Basic admin:" + password,
65
- };
66
- return headers;
67
- };
68
-
69
78
  return {
70
79
  peer: {
71
80
  id: {
@@ -75,7 +84,7 @@ export const client = async (
75
84
  get: async () => {
76
85
  return (
77
86
  throwIfNot200(
78
- await axios.get(endpoint + ADDRESS_PATH, {
87
+ await axiosInstance.get(endpoint + ADDRESS_PATH, {
79
88
  validateStatus,
80
89
  })
81
90
  ).data as string[]
@@ -83,14 +92,51 @@ export const client = async (
83
92
  },
84
93
  },
85
94
  },
95
+ trust: {
96
+ add: async (key: PublicSignKey | PeerId) => {
97
+ const result = await axiosInstance.put(
98
+ endpoint +
99
+ TRUST_PATH +
100
+ "/" +
101
+ encodeURIComponent(
102
+ key instanceof PublicSignKey
103
+ ? key.hashcode()
104
+ : getPublicKeyFromPeerId(key).hashcode()
105
+ ),
106
+ undefined,
107
+ { validateStatus }
108
+ );
109
+ if (result.status !== 200 && result.status !== 404) {
110
+ throw new Error(result.data);
111
+ }
112
+ return result.status === 200 ? true : false;
113
+ },
114
+ remove: async (key: PublicSignKey | PeerId) => {
115
+ const result = await axiosInstance.delete(
116
+ endpoint +
117
+ TRUST_PATH +
118
+ "/" +
119
+ encodeURIComponent(
120
+ key instanceof PublicSignKey
121
+ ? key.hashcode()
122
+ : getPublicKeyFromPeerId(key).hashcode()
123
+ ),
124
+ { validateStatus }
125
+ );
126
+ if (result.status !== 200 && result.status !== 404) {
127
+ throw new Error(result.data);
128
+ }
129
+ return result.status === 200 ? true : false;
130
+ },
131
+ },
86
132
  program: {
87
133
  has: async (address: Address | string): Promise<boolean> => {
88
- const result = await axios.head(
134
+ const result = await axiosInstance.head(
89
135
  endpoint +
90
136
  PROGRAM_PATH +
91
137
  "/" +
92
138
  encodeURIComponent(address.toString()),
93
- { validateStatus, headers: await getHeaders() }
139
+ { validateStatus }
94
140
  );
95
141
  if (result.status !== 200 && result.status !== 404) {
96
142
  throw new Error(result.data);
@@ -100,24 +146,26 @@ export const client = async (
100
146
 
101
147
  open: async (program: StartProgram): Promise<Address> => {
102
148
  const resp = throwIfNot200(
103
- await axios.put(endpoint + PROGRAM_PATH, JSON.stringify(program), {
104
- validateStatus,
105
- headers: await getHeaders(),
106
- })
149
+ await axiosInstance.put(
150
+ endpoint + PROGRAM_PATH,
151
+ JSON.stringify(program),
152
+ {
153
+ validateStatus,
154
+ }
155
+ )
107
156
  );
108
157
  return resp.data as string;
109
158
  },
110
159
 
111
160
  close: async (address: string): Promise<void> => {
112
161
  throwIfNot200(
113
- await axios.delete(
162
+ await axiosInstance.delete(
114
163
  endpoint +
115
164
  PROGRAM_PATH +
116
165
  "/" +
117
166
  encodeURIComponent(address.toString()),
118
167
  {
119
168
  validateStatus,
120
- headers: await getHeaders(),
121
169
  }
122
170
  )
123
171
  );
@@ -125,7 +173,7 @@ export const client = async (
125
173
 
126
174
  drop: async (address: string): Promise<void> => {
127
175
  throwIfNot200(
128
- await axios.delete(
176
+ await axiosInstance.delete(
129
177
  endpoint +
130
178
  PROGRAM_PATH +
131
179
  "/" +
@@ -133,7 +181,6 @@ export const client = async (
133
181
  "?delete=true",
134
182
  {
135
183
  validateStatus,
136
- headers: await getHeaders(),
137
184
  }
138
185
  )
139
186
  );
@@ -141,9 +188,8 @@ export const client = async (
141
188
 
142
189
  list: async (): Promise<string[]> => {
143
190
  const resp = throwIfNot200(
144
- await axios.get(endpoint + PROGRAMS_PATH, {
191
+ await axiosInstance.get(endpoint + PROGRAMS_PATH, {
145
192
  validateStatus,
146
- headers: await getHeaders(),
147
193
  })
148
194
  );
149
195
  return resp.data as string[];
@@ -151,12 +197,11 @@ export const client = async (
151
197
  },
152
198
  dependency: {
153
199
  install: async (instruction: InstallDependency): Promise<string[]> => {
154
- const resp = await axios.put(
200
+ const resp = await axiosInstance.put(
155
201
  endpoint + INSTALL_PATH,
156
202
  JSON.stringify(instruction),
157
203
  {
158
204
  validateStatus,
159
- headers: await getHeaders(),
160
205
  }
161
206
  );
162
207
  if (resp.status !== 200) {
@@ -170,26 +215,23 @@ export const client = async (
170
215
  network: {
171
216
  bootstrap: async (): Promise<void> => {
172
217
  throwIfNot200(
173
- await axios.post(endpoint + BOOTSTRAP_PATH, undefined, {
218
+ await axiosInstance.post(endpoint + BOOTSTRAP_PATH, undefined, {
174
219
  validateStatus,
175
- headers: await getHeaders(),
176
220
  })
177
221
  );
178
222
  },
179
223
  },
180
224
  restart: async (): Promise<void> => {
181
225
  throwIfNot200(
182
- await axios.post(endpoint + RESTART_PATH, undefined, {
226
+ await axiosInstance.post(endpoint + RESTART_PATH, undefined, {
183
227
  validateStatus,
184
- headers: await getHeaders(),
185
228
  })
186
229
  );
187
230
  },
188
231
  terminate: async (): Promise<void> => {
189
232
  throwIfNot200(
190
- await axios.post(endpoint + TERMINATE_PATH, undefined, {
233
+ await axiosInstance.post(endpoint + TERMINATE_PATH, undefined, {
191
234
  validateStatus,
192
- headers: await getHeaders(),
193
235
  })
194
236
  );
195
237
  },
package/src/config.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import path from "path";
2
2
  import os from "os";
3
3
  import fs from "fs";
4
-
4
+ import { deserialize, serialize } from "@dao-xyz/borsh";
5
5
  import { Duplex } from "stream"; // Native Node Module
6
+ import { Ed25519Keypair, Keypair, fromBase64 } from "@peerbit/crypto";
6
7
 
7
8
  const bufferToStream = (myBuffer) => {
8
9
  const tmp = new Duplex();
@@ -16,10 +17,6 @@ export const getHomeConfigDir = (): string => {
16
17
  return configDir;
17
18
  };
18
19
 
19
- export const getCredentialsPath = (configDir: string): string => {
20
- return path.join(configDir, "credentials.json");
21
- };
22
-
23
20
  export const getServerConfigPath = (configDir: string): string => {
24
21
  return path.join(configDir, "server");
25
22
  };
@@ -32,10 +29,28 @@ export const getNodePath = (directory: string): string => {
32
29
  return path.join(directory, "node");
33
30
  };
34
31
 
35
- export const getKeysPath = async (configDir: string): Promise<string> => {
32
+ export const getTrustPath = (directory: string): string => {
33
+ return path.join(directory, "trust.json");
34
+ };
35
+
36
+ const getKeysPath = (configDir: string): string => {
36
37
  return path.join(configDir, "keys");
37
38
  };
38
39
 
40
+ export const getKeypair = async (
41
+ configDir: string
42
+ ): Promise<Ed25519Keypair> => {
43
+ const keypath = getKeysPath(configDir);
44
+ if (!fs.existsSync(keypath)) {
45
+ const keypair = await Ed25519Keypair.create();
46
+ fs.writeFileSync(keypath, serialize(keypair));
47
+ return keypair;
48
+ } else {
49
+ const keypair = deserialize(fs.readFileSync(keypath), Ed25519Keypair);
50
+ return keypair;
51
+ }
52
+ };
53
+
39
54
  export const checkExistPath = async (path: string) => {
40
55
  try {
41
56
  if (!fs.existsSync(path)) {
@@ -51,23 +66,6 @@ export const checkExistPath = async (path: string) => {
51
66
  }
52
67
  };
53
68
 
54
- export const loadPassword = async (
55
- configDirectory: string
56
- ): Promise<string> => {
57
- const configDir = configDirectory || (await getHomeConfigDir());
58
- const credentialsPath = await getCredentialsPath(configDir);
59
- if (!(await checkExistPath(credentialsPath))) {
60
- throw new NotFoundError("Credentials file does not exist");
61
- }
62
- const password = JSON.parse(
63
- fs.readFileSync(credentialsPath, "utf-8")
64
- ).password;
65
- if (!password || password.length === 0) {
66
- throw new NotFoundError("Password not found");
67
- }
68
- return password;
69
- };
70
-
71
69
  export const getPackageName = async (
72
70
  path: string | Uint8Array
73
71
  ): Promise<string> => {
package/src/peerbit.ts CHANGED
@@ -2,12 +2,14 @@ import { DirectBlock } from "@peerbit/blocks";
2
2
  import { DirectSub } from "@peerbit/pubsub";
3
3
  import { Peerbit } from "peerbit";
4
4
  import path from "path";
5
+ import { PeerId } from "@libp2p/interface-peer-id";
5
6
 
6
7
  export const LIBP2P_LISTEN_PORT = 8001;
7
8
  export const create = (properties: {
8
9
  directory?: string;
9
10
  domain?: string;
10
11
  listenPort?: number;
12
+ peerId: PeerId;
11
13
  }) => {
12
14
  const listenPort = properties.listenPort ?? LIBP2P_LISTEN_PORT;
13
15
  const blocksDirectory =
@@ -17,6 +19,7 @@ export const create = (properties: {
17
19
 
18
20
  return Peerbit.create({
19
21
  libp2p: {
22
+ peerId: properties.peerId,
20
23
  addresses: {
21
24
  announce: properties.domain
22
25
  ? [
package/src/remotes.ts CHANGED
@@ -3,7 +3,6 @@ import fs from "fs";
3
3
  interface RemoteObject {
4
4
  address: string;
5
5
  name: string;
6
- password: string;
7
6
  }
8
7
 
9
8
  interface RemotesObject {
@@ -35,11 +34,10 @@ export class Remotes {
35
34
  getByAddress(address: string) {
36
35
  return this.data.remotes.find((x) => x.address === address);
37
36
  }
38
- add(name: string, address: string, password: string) {
37
+ add(name: string, address: string) {
39
38
  const obj: RemoteObject = {
40
39
  address,
41
40
  name,
42
- password,
43
41
  };
44
42
  const existing = this.data.remotes.findIndex((x) => x.name === name);
45
43
  if (existing >= 0) {
package/src/routes.ts CHANGED
@@ -11,7 +11,7 @@ export const getPort = (protocol: string) => {
11
11
  };
12
12
  export const SSL_PORT = 9002;
13
13
  export const LOCAL_PORT = 8082;
14
-
14
+ export const TRUST_PATH = "/trust";
15
15
  export const PEER_ID_PATH = "/peer/id";
16
16
  export const ADDRESS_PATH = "/peer/address";
17
17
  export const PROGRAM_PATH = "/program";