@peerbit/server 2.0.0 → 4.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.
- package/lib/esm/aws.browser.d.ts +0 -0
- package/lib/esm/aws.browser.js +3 -0
- package/lib/esm/aws.browser.js.map +1 -0
- package/lib/esm/aws.d.ts +19 -0
- package/lib/esm/aws.js +185 -1
- package/lib/esm/aws.js.map +1 -1
- package/lib/esm/cli.js +614 -299
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/client.d.ts +13 -1
- package/lib/esm/client.js +101 -31
- package/lib/esm/client.js.map +1 -1
- package/lib/esm/config.d.ts +3 -3
- package/lib/esm/config.js +18 -16
- package/lib/esm/config.js.map +1 -1
- package/lib/esm/docker.browser.d.ts +0 -0
- package/lib/esm/docker.browser.js +3 -0
- package/lib/esm/docker.browser.js.map +1 -0
- package/lib/esm/domain.js +1 -1
- package/lib/esm/domain.js.map +1 -1
- package/lib/esm/peerbit.d.ts +2 -0
- package/lib/esm/peerbit.js +1 -0
- package/lib/esm/peerbit.js.map +1 -1
- package/lib/esm/remotes.d.ts +15 -3
- package/lib/esm/remotes.js +8 -9
- package/lib/esm/remotes.js.map +1 -1
- package/lib/esm/routes.d.ts +4 -2
- package/lib/esm/routes.js +6 -4
- package/lib/esm/routes.js.map +1 -1
- package/lib/esm/server.d.ts +5 -7
- package/lib/esm/server.js +183 -185
- package/lib/esm/server.js.map +1 -1
- package/lib/esm/signes-request.d.ts +5 -0
- package/lib/esm/signes-request.js +54 -0
- package/lib/esm/signes-request.js.map +1 -0
- package/lib/esm/trust.browser.d.ts +0 -0
- package/lib/esm/trust.browser.js +3 -0
- package/lib/esm/trust.browser.js.map +1 -0
- package/lib/esm/trust.d.ts +9 -0
- package/lib/esm/trust.js +36 -0
- package/lib/esm/trust.js.map +1 -0
- package/lib/ui/assets/aws.browser-4ed993c7.js +1 -0
- package/lib/ui/assets/index-5ed0229d.js +77 -0
- package/lib/ui/index.html +1 -1
- package/package.json +13 -7
- package/src/aws.browser.ts +1 -0
- package/src/aws.ts +250 -1
- package/src/cli.ts +726 -348
- package/src/client.ts +145 -38
- package/src/config.ts +21 -23
- package/src/docker.browser.ts +1 -0
- package/src/domain.ts +1 -1
- package/src/peerbit.ts +3 -0
- package/src/remotes.ts +24 -12
- package/src/routes.ts +6 -5
- package/src/server.ts +238 -254
- package/src/signes-request.ts +84 -0
- package/src/trust.browser.ts +1 -0
- package/src/trust.ts +39 -0
- package/lib/ui/assets/index-73eaa3bc.js +0 -53
package/src/server.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import http from "http";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
fromBase64,
|
|
4
|
+
getKeypairFromPeerId,
|
|
5
|
+
getPublicKeyFromPeerId,
|
|
6
|
+
} from "@peerbit/crypto";
|
|
3
7
|
import { deserialize } from "@dao-xyz/borsh";
|
|
4
8
|
import {
|
|
5
9
|
Program,
|
|
@@ -10,13 +14,10 @@ import {
|
|
|
10
14
|
import { waitFor } from "@peerbit/time";
|
|
11
15
|
import { v4 as uuid } from "uuid";
|
|
12
16
|
import {
|
|
13
|
-
checkExistPath,
|
|
14
17
|
getHomeConfigDir,
|
|
15
|
-
getCredentialsPath,
|
|
16
|
-
getPackageName,
|
|
17
|
-
loadPassword,
|
|
18
|
-
NotFoundError,
|
|
19
18
|
getNodePath,
|
|
19
|
+
getKeypair,
|
|
20
|
+
getTrustPath,
|
|
20
21
|
} from "./config.js";
|
|
21
22
|
import { setMaxListeners } from "events";
|
|
22
23
|
import { create } from "./peerbit.js";
|
|
@@ -31,13 +32,14 @@ import {
|
|
|
31
32
|
import {
|
|
32
33
|
ADDRESS_PATH,
|
|
33
34
|
BOOTSTRAP_PATH,
|
|
34
|
-
TERMINATE_PATH,
|
|
35
35
|
INSTALL_PATH,
|
|
36
|
-
|
|
36
|
+
LOCAL_API_PORT,
|
|
37
37
|
PEER_ID_PATH,
|
|
38
38
|
PROGRAMS_PATH,
|
|
39
39
|
PROGRAM_PATH,
|
|
40
40
|
RESTART_PATH,
|
|
41
|
+
TRUST_PATH,
|
|
42
|
+
STOP_PATH,
|
|
41
43
|
} from "./routes.js";
|
|
42
44
|
import { Session } from "./session.js";
|
|
43
45
|
import fs from "fs";
|
|
@@ -50,6 +52,10 @@ import { dirname } from "path";
|
|
|
50
52
|
import { fileURLToPath } from "url";
|
|
51
53
|
import { Level } from "level";
|
|
52
54
|
import { MemoryLevel } from "memory-level";
|
|
55
|
+
import { Trust } from "./trust.js";
|
|
56
|
+
import { getBody, verifyRequest } from "./signes-request.js";
|
|
57
|
+
import { cli } from "./cli.js";
|
|
58
|
+
import { peerIdFromString } from "@libp2p/peer-id";
|
|
53
59
|
|
|
54
60
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
55
61
|
|
|
@@ -62,69 +68,34 @@ export const stopAndWait = (server: http.Server) => {
|
|
|
62
68
|
return waitFor(() => closed);
|
|
63
69
|
};
|
|
64
70
|
|
|
65
|
-
export const createPassword = async (
|
|
66
|
-
configDirectory: string,
|
|
67
|
-
password?: string
|
|
68
|
-
): Promise<string> => {
|
|
69
|
-
const configDir = configDirectory ?? (await getHomeConfigDir());
|
|
70
|
-
const credentialsPath = await getCredentialsPath(configDir);
|
|
71
|
-
if (!password && (await checkExistPath(credentialsPath))) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
"Config path for credentials: " + credentialsPath + ", already exist"
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
console.log(`Creating config folder ${configDir}`);
|
|
77
|
-
|
|
78
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
79
|
-
await waitFor(() => fs.existsSync(configDir));
|
|
80
|
-
|
|
81
|
-
console.log(`Created config folder ${configDir}`);
|
|
82
|
-
|
|
83
|
-
password = password || uuid();
|
|
84
|
-
fs.writeFileSync(
|
|
85
|
-
credentialsPath,
|
|
86
|
-
JSON.stringify({ username: "admin", password })
|
|
87
|
-
);
|
|
88
|
-
console.log(`Created credentials at ${credentialsPath}`);
|
|
89
|
-
return password!;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export const loadOrCreatePassword = async (
|
|
93
|
-
configDirectory: string,
|
|
94
|
-
password?: string
|
|
95
|
-
): Promise<string> => {
|
|
96
|
-
if (!password) {
|
|
97
|
-
try {
|
|
98
|
-
return await loadPassword(configDirectory);
|
|
99
|
-
} catch (error) {
|
|
100
|
-
if (error instanceof NotFoundError) {
|
|
101
|
-
return createPassword(configDirectory, password);
|
|
102
|
-
}
|
|
103
|
-
throw error;
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
return createPassword(configDirectory, password);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
71
|
export const startServerWithNode = async (properties: {
|
|
110
|
-
directory
|
|
72
|
+
directory: string;
|
|
111
73
|
domain?: string;
|
|
112
74
|
bootstrap?: boolean;
|
|
113
75
|
newSession?: boolean;
|
|
114
|
-
|
|
76
|
+
grantAccess?: string[];
|
|
115
77
|
ports?: {
|
|
116
78
|
node: number;
|
|
117
79
|
api: number;
|
|
118
80
|
};
|
|
119
81
|
restart?: () => void;
|
|
120
82
|
}) => {
|
|
83
|
+
if (!fs.existsSync(properties.directory)) {
|
|
84
|
+
fs.mkdirSync(properties.directory, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const trustPeerIds =
|
|
88
|
+
properties.grantAccess && properties.grantAccess.length > 0
|
|
89
|
+
? properties.grantAccess.map((x) => peerIdFromString(x))
|
|
90
|
+
: [];
|
|
91
|
+
|
|
92
|
+
const keypair = await getKeypair(properties.directory);
|
|
93
|
+
|
|
121
94
|
const peer = await create({
|
|
122
|
-
directory:
|
|
123
|
-
properties.directory != null
|
|
124
|
-
? getNodePath(properties.directory)
|
|
125
|
-
: undefined,
|
|
95
|
+
directory: getNodePath(properties.directory),
|
|
126
96
|
domain: properties.domain,
|
|
127
97
|
listenPort: properties.ports?.node,
|
|
98
|
+
peerId: await keypair.toPeerId(),
|
|
128
99
|
});
|
|
129
100
|
|
|
130
101
|
if (properties.bootstrap) {
|
|
@@ -134,6 +105,7 @@ export const startServerWithNode = async (properties: {
|
|
|
134
105
|
properties.directory != null
|
|
135
106
|
? path.join(properties.directory, "session")
|
|
136
107
|
: undefined;
|
|
108
|
+
|
|
137
109
|
const session = new Session(
|
|
138
110
|
sessionDirectory
|
|
139
111
|
? new Level<string, Uint8Array>(sessionDirectory, {
|
|
@@ -158,14 +130,11 @@ export const startServerWithNode = async (properties: {
|
|
|
158
130
|
await session.clear();
|
|
159
131
|
}
|
|
160
132
|
|
|
133
|
+
const trust = new Trust(getTrustPath(properties.directory));
|
|
161
134
|
const server = await startApiServer(peer, {
|
|
162
135
|
port: properties.ports?.api,
|
|
163
|
-
|
|
164
|
-
properties.directory != null
|
|
165
|
-
? path.join(properties.directory, "server")
|
|
166
|
-
: undefined || getHomeConfigDir(),
|
|
136
|
+
trust,
|
|
167
137
|
session,
|
|
168
|
-
password: properties.password,
|
|
169
138
|
});
|
|
170
139
|
const printNodeInfo = async () => {
|
|
171
140
|
console.log("Starting node with address(es): ");
|
|
@@ -203,14 +172,16 @@ export const startServerWithNode = async (properties: {
|
|
|
203
172
|
});
|
|
204
173
|
};
|
|
205
174
|
await shutDownHook(peer, server);
|
|
175
|
+
|
|
176
|
+
if (trustPeerIds.length > 0) {
|
|
177
|
+
for (const id of trustPeerIds) {
|
|
178
|
+
trust.add(getPublicKeyFromPeerId(id).hashcode());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
206
181
|
return { server, node: peer };
|
|
207
182
|
};
|
|
208
183
|
|
|
209
|
-
const
|
|
210
|
-
client: Peerbit,
|
|
211
|
-
req: http.IncomingMessage,
|
|
212
|
-
pathIndex: number
|
|
213
|
-
): Program | undefined => {
|
|
184
|
+
const getPathValue = (req: http.IncomingMessage, pathIndex: number): string => {
|
|
214
185
|
if (!req.url) {
|
|
215
186
|
throw new Error("Missing url");
|
|
216
187
|
}
|
|
@@ -222,7 +193,7 @@ const getProgramFromPath = (
|
|
|
222
193
|
throw new Error("Invalid path");
|
|
223
194
|
}
|
|
224
195
|
const address = decodeURIComponent(path[pathIndex]);
|
|
225
|
-
return
|
|
196
|
+
return address;
|
|
226
197
|
};
|
|
227
198
|
function findPeerbitProgramFolder(inputDirectory: string): string | null {
|
|
228
199
|
let currentDir = path.resolve(inputDirectory);
|
|
@@ -254,18 +225,13 @@ function findPeerbitProgramFolder(inputDirectory: string): string | null {
|
|
|
254
225
|
|
|
255
226
|
export const startApiServer = async (
|
|
256
227
|
client: ProgramClient,
|
|
257
|
-
|
|
258
|
-
|
|
228
|
+
properties: {
|
|
229
|
+
trust: Trust;
|
|
259
230
|
session?: Session;
|
|
260
231
|
port?: number;
|
|
261
|
-
password?: string;
|
|
262
232
|
}
|
|
263
233
|
): Promise<http.Server> => {
|
|
264
|
-
const port =
|
|
265
|
-
const password = await loadOrCreatePassword(
|
|
266
|
-
options.configDirectory,
|
|
267
|
-
options?.password
|
|
268
|
-
);
|
|
234
|
+
const port = properties?.port ?? LOCAL_API_PORT;
|
|
269
235
|
|
|
270
236
|
const restart = async () => {
|
|
271
237
|
await client.stop();
|
|
@@ -285,43 +251,27 @@ export const startApiServer = async (
|
|
|
285
251
|
gid: process.getgid!(),
|
|
286
252
|
}
|
|
287
253
|
);
|
|
288
|
-
|
|
289
|
-
/* process.on("exit", async () => {
|
|
290
|
-
child.kill("SIGINT")
|
|
291
|
-
});
|
|
292
|
-
process.on("SIGINT", async () => {
|
|
293
|
-
child.kill("SIGINT")
|
|
294
|
-
}); */
|
|
295
254
|
process.exit(0);
|
|
296
255
|
};
|
|
256
|
+
if (!client.peerId.equals(await client.identity.publicKey.toPeerId())) {
|
|
257
|
+
throw new Error("Expecting node identity to equal peerId");
|
|
258
|
+
}
|
|
297
259
|
|
|
298
|
-
const
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
260
|
+
const getVerifiedBody = async (req: http.IncomingMessage) => {
|
|
261
|
+
const body = await getBody(req);
|
|
262
|
+
const result = await verifyRequest(
|
|
263
|
+
req.headers,
|
|
264
|
+
req.method!,
|
|
265
|
+
req.url!,
|
|
266
|
+
body
|
|
267
|
+
);
|
|
268
|
+
if (result.equals(client.identity.publicKey)) {
|
|
269
|
+
return body;
|
|
307
270
|
}
|
|
308
|
-
if (
|
|
309
|
-
return
|
|
271
|
+
if (properties.trust.isTrusted(result.hashcode())) {
|
|
272
|
+
return body;
|
|
310
273
|
}
|
|
311
|
-
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const getBody = (
|
|
315
|
-
req: http.IncomingMessage,
|
|
316
|
-
callback: (body: string) => Promise<void> | void
|
|
317
|
-
) => {
|
|
318
|
-
let body = "";
|
|
319
|
-
req.on("data", function (d) {
|
|
320
|
-
body += d;
|
|
321
|
-
});
|
|
322
|
-
req.on("end", function () {
|
|
323
|
-
callback(body);
|
|
324
|
-
});
|
|
274
|
+
throw new Error("Not trusted");
|
|
325
275
|
};
|
|
326
276
|
|
|
327
277
|
const e404 = "404";
|
|
@@ -339,15 +289,20 @@ export const startApiServer = async (
|
|
|
339
289
|
|
|
340
290
|
try {
|
|
341
291
|
if (req.url) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
292
|
+
let body: string;
|
|
293
|
+
try {
|
|
294
|
+
body =
|
|
295
|
+
req.url.startsWith(PEER_ID_PATH) ||
|
|
296
|
+
req.url.startsWith(ADDRESS_PATH)
|
|
297
|
+
? await getBody(req)
|
|
298
|
+
: await getVerifiedBody(req);
|
|
299
|
+
} catch (error: any) {
|
|
347
300
|
res.writeHead(401);
|
|
348
|
-
res.end("Not authorized");
|
|
301
|
+
res.end("Not authorized: " + error.toString());
|
|
349
302
|
return;
|
|
350
|
-
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (req.url.startsWith(PROGRAMS_PATH)) {
|
|
351
306
|
if (client instanceof Peerbit === false) {
|
|
352
307
|
res.writeHead(400);
|
|
353
308
|
res.end("Server node is not running a native client");
|
|
@@ -380,7 +335,9 @@ export const startApiServer = async (
|
|
|
380
335
|
switch (req.method) {
|
|
381
336
|
case "HEAD":
|
|
382
337
|
try {
|
|
383
|
-
const program =
|
|
338
|
+
const program = (client as Peerbit).handler?.items.get(
|
|
339
|
+
getPathValue(req, 1)
|
|
340
|
+
);
|
|
384
341
|
if (program) {
|
|
385
342
|
res.writeHead(200);
|
|
386
343
|
res.end();
|
|
@@ -399,7 +356,9 @@ export const startApiServer = async (
|
|
|
399
356
|
const url = new URL(req.url, "http://localhost:" + 1234);
|
|
400
357
|
const queryData = url.searchParams.get("delete");
|
|
401
358
|
|
|
402
|
-
const program =
|
|
359
|
+
const program = (client as Peerbit).handler?.items.get(
|
|
360
|
+
getPathValue(req, 1)
|
|
361
|
+
);
|
|
403
362
|
if (program) {
|
|
404
363
|
let closed = false;
|
|
405
364
|
if (queryData === "true") {
|
|
@@ -408,7 +367,9 @@ export const startApiServer = async (
|
|
|
408
367
|
closed = await program.close();
|
|
409
368
|
}
|
|
410
369
|
if (closed) {
|
|
411
|
-
await
|
|
370
|
+
await properties?.session?.programs.remove(
|
|
371
|
+
program.address
|
|
372
|
+
);
|
|
412
373
|
}
|
|
413
374
|
|
|
414
375
|
res.writeHead(200);
|
|
@@ -423,56 +384,54 @@ export const startApiServer = async (
|
|
|
423
384
|
}
|
|
424
385
|
break;
|
|
425
386
|
case "PUT":
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
(startArguments as StartByVariant).variant
|
|
440
|
-
);
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
program = new P();
|
|
444
|
-
} else {
|
|
445
|
-
program = deserialize(
|
|
446
|
-
fromBase64((startArguments as StartByBase64).base64),
|
|
447
|
-
Program
|
|
387
|
+
try {
|
|
388
|
+
const startArguments: StartProgram = JSON.parse(body);
|
|
389
|
+
|
|
390
|
+
let program: Program;
|
|
391
|
+
if ((startArguments as StartByVariant).variant) {
|
|
392
|
+
const P = getProgramFromVariant(
|
|
393
|
+
(startArguments as StartByVariant).variant
|
|
394
|
+
);
|
|
395
|
+
if (!P) {
|
|
396
|
+
res.writeHead(400);
|
|
397
|
+
res.end(
|
|
398
|
+
"Missing program with variant: " +
|
|
399
|
+
(startArguments as StartByVariant).variant
|
|
448
400
|
);
|
|
401
|
+
return;
|
|
449
402
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
program.address,
|
|
457
|
-
(client as Peerbit).directory,
|
|
458
|
-
await client.services.blocks.has(program.address)
|
|
459
|
-
);
|
|
460
|
-
await options?.session?.programs.add(
|
|
461
|
-
program.address,
|
|
462
|
-
new Uint8Array()
|
|
463
|
-
);
|
|
464
|
-
res.writeHead(200);
|
|
465
|
-
res.end(program.address.toString());
|
|
466
|
-
})
|
|
467
|
-
.catch((error) => {
|
|
468
|
-
res.writeHead(400);
|
|
469
|
-
res.end("Failed to open program: " + error.toString());
|
|
470
|
-
});
|
|
471
|
-
} catch (error: any) {
|
|
472
|
-
res.writeHead(400);
|
|
473
|
-
res.end(error.toString());
|
|
403
|
+
program = new P();
|
|
404
|
+
} else {
|
|
405
|
+
program = deserialize(
|
|
406
|
+
fromBase64((startArguments as StartByBase64).base64),
|
|
407
|
+
Program
|
|
408
|
+
);
|
|
474
409
|
}
|
|
475
|
-
|
|
410
|
+
client
|
|
411
|
+
.open(program) // TODO all users to pass args
|
|
412
|
+
.then(async (program) => {
|
|
413
|
+
// TODO what if this is a reopen?
|
|
414
|
+
console.log(
|
|
415
|
+
"OPEN ADDRESS",
|
|
416
|
+
program.address,
|
|
417
|
+
(client as Peerbit).directory,
|
|
418
|
+
await client.services.blocks.has(program.address)
|
|
419
|
+
);
|
|
420
|
+
await properties?.session?.programs.add(
|
|
421
|
+
program.address,
|
|
422
|
+
new Uint8Array()
|
|
423
|
+
);
|
|
424
|
+
res.writeHead(200);
|
|
425
|
+
res.end(program.address.toString());
|
|
426
|
+
})
|
|
427
|
+
.catch((error) => {
|
|
428
|
+
res.writeHead(400);
|
|
429
|
+
res.end("Failed to open program: " + error.toString());
|
|
430
|
+
});
|
|
431
|
+
} catch (error: any) {
|
|
432
|
+
res.writeHead(400);
|
|
433
|
+
res.end(error.toString());
|
|
434
|
+
}
|
|
476
435
|
break;
|
|
477
436
|
|
|
478
437
|
default:
|
|
@@ -481,105 +440,101 @@ export const startApiServer = async (
|
|
|
481
440
|
}
|
|
482
441
|
} else if (req.url.startsWith(INSTALL_PATH)) {
|
|
483
442
|
switch (req.method) {
|
|
484
|
-
case "PUT":
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (!installName || installName.length === 0) {
|
|
507
|
-
res.writeHead(400);
|
|
508
|
-
res.end("Invalid package: " + packageName);
|
|
509
|
-
} else {
|
|
510
|
-
try {
|
|
511
|
-
// TODO do this without sudo. i.e. for servers provide arguments so that this app folder is writeable by default by the user
|
|
512
|
-
const installDir =
|
|
513
|
-
process.env.PEERBIT_MODULES_PATH ||
|
|
514
|
-
findPeerbitProgramFolder(__dirname);
|
|
515
|
-
let permission = "";
|
|
516
|
-
if (!installDir) {
|
|
517
|
-
res.writeHead(400);
|
|
518
|
-
res.end("Missing installation directory");
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
try {
|
|
522
|
-
fs.accessSync(installDir, fs.constants.W_OK);
|
|
523
|
-
} catch (error) {
|
|
524
|
-
permission = "sudo";
|
|
525
|
-
}
|
|
443
|
+
case "PUT": {
|
|
444
|
+
const installArgs: InstallDependency = JSON.parse(body);
|
|
445
|
+
|
|
446
|
+
const packageName = installArgs.name; // @abc/123
|
|
447
|
+
let installName = installArgs.name; // abc123.tgz or @abc/123 (npm package name)
|
|
448
|
+
let clear: (() => void) | undefined;
|
|
449
|
+
if (installArgs.type === "tgz") {
|
|
450
|
+
const binary = fromBase64(installArgs.base64);
|
|
451
|
+
const tempFile = tmp.fileSync({
|
|
452
|
+
name:
|
|
453
|
+
base58btc.encode(Buffer.from(installName)) +
|
|
454
|
+
uuid() +
|
|
455
|
+
".tgz",
|
|
456
|
+
});
|
|
457
|
+
fs.writeFileSync(tempFile.fd, binary);
|
|
458
|
+
clear = () => tempFile.removeCallback();
|
|
459
|
+
installName = tempFile.name;
|
|
460
|
+
} else {
|
|
461
|
+
clear = undefined;
|
|
462
|
+
}
|
|
526
463
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
464
|
+
if (!installName || installName.length === 0) {
|
|
465
|
+
res.writeHead(400);
|
|
466
|
+
res.end("Invalid package: " + packageName);
|
|
467
|
+
} else {
|
|
468
|
+
try {
|
|
469
|
+
// TODO do this without sudo. i.e. for servers provide arguments so that this app folder is writeable by default by the user
|
|
470
|
+
const installDir =
|
|
471
|
+
process.env.PEERBIT_MODULES_PATH ||
|
|
472
|
+
findPeerbitProgramFolder(__dirname);
|
|
473
|
+
let permission = "";
|
|
474
|
+
if (!installDir) {
|
|
532
475
|
res.writeHead(400);
|
|
533
|
-
res.end(
|
|
534
|
-
"Failed to install library: " +
|
|
535
|
-
packageName +
|
|
536
|
-
". " +
|
|
537
|
-
error.toString()
|
|
538
|
-
);
|
|
539
|
-
clear?.();
|
|
476
|
+
res.end("Missing installation directory");
|
|
540
477
|
return;
|
|
541
478
|
}
|
|
542
|
-
|
|
543
479
|
try {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
);
|
|
480
|
+
fs.accessSync(installDir, fs.constants.W_OK);
|
|
481
|
+
} catch (error) {
|
|
482
|
+
permission = "sudo";
|
|
483
|
+
}
|
|
549
484
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
485
|
+
console.log("Installing package: " + installName);
|
|
486
|
+
execSync(
|
|
487
|
+
`${permission} npm install ${installName} --prefix ${installDir} --no-save --no-package-lock`
|
|
488
|
+
); // TODO omit=dev ? but this makes breaks the tests after running once?
|
|
489
|
+
} catch (error: any) {
|
|
490
|
+
res.writeHead(400);
|
|
491
|
+
res.end(
|
|
492
|
+
"Failed to install library: " +
|
|
493
|
+
packageName +
|
|
494
|
+
". " +
|
|
495
|
+
error.toString()
|
|
496
|
+
);
|
|
497
|
+
clear?.();
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
566
500
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
501
|
+
try {
|
|
502
|
+
const programsPre = new Set(
|
|
503
|
+
getProgramFromVariants().map((x) => getSchema(x).variant)
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
await import(
|
|
507
|
+
/* webpackIgnore: true */ /* @vite-ignore */ packageName
|
|
508
|
+
);
|
|
509
|
+
await properties?.session?.imports.add(
|
|
510
|
+
packageName,
|
|
511
|
+
new Uint8Array()
|
|
512
|
+
);
|
|
513
|
+
const programsPost = getProgramFromVariants()?.map((x) =>
|
|
514
|
+
getSchema(x)
|
|
515
|
+
);
|
|
516
|
+
const newPrograms: { variant: string }[] = [];
|
|
517
|
+
for (const p of programsPost) {
|
|
518
|
+
if (!programsPre.has(p.variant)) {
|
|
519
|
+
newPrograms.push(p as { variant: string });
|
|
520
|
+
}
|
|
575
521
|
}
|
|
522
|
+
|
|
523
|
+
res.writeHead(200);
|
|
524
|
+
res.end(JSON.stringify(newPrograms.map((x) => x.variant)));
|
|
525
|
+
} catch (e: any) {
|
|
526
|
+
res.writeHead(400);
|
|
527
|
+
res.end(e.message.toString?.());
|
|
528
|
+
clear?.();
|
|
576
529
|
}
|
|
577
|
-
}
|
|
530
|
+
}
|
|
578
531
|
break;
|
|
532
|
+
}
|
|
579
533
|
|
|
580
|
-
default:
|
|
534
|
+
default: {
|
|
581
535
|
r404();
|
|
582
536
|
break;
|
|
537
|
+
}
|
|
583
538
|
}
|
|
584
539
|
} else if (req.url.startsWith(BOOTSTRAP_PATH)) {
|
|
585
540
|
switch (req.method) {
|
|
@@ -598,6 +553,24 @@ export const startApiServer = async (
|
|
|
598
553
|
r404();
|
|
599
554
|
break;
|
|
600
555
|
}
|
|
556
|
+
} else if (req.url.startsWith(TRUST_PATH)) {
|
|
557
|
+
switch (req.method) {
|
|
558
|
+
case "PUT": {
|
|
559
|
+
properties.trust.add(getPathValue(req, 1));
|
|
560
|
+
res.writeHead(200);
|
|
561
|
+
res.end();
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
case "DELETE": {
|
|
565
|
+
const removed = properties.trust.remove(getPathValue(req, 1));
|
|
566
|
+
res.writeHead(200);
|
|
567
|
+
res.end(removed);
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
default:
|
|
571
|
+
r404();
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
601
574
|
} else if (req.url.startsWith(RESTART_PATH)) {
|
|
602
575
|
switch (req.method) {
|
|
603
576
|
case "POST":
|
|
@@ -610,7 +583,7 @@ export const startApiServer = async (
|
|
|
610
583
|
r404();
|
|
611
584
|
break;
|
|
612
585
|
}
|
|
613
|
-
} else if (req.url.startsWith(
|
|
586
|
+
} else if (req.url.startsWith(STOP_PATH)) {
|
|
614
587
|
switch (req.method) {
|
|
615
588
|
case "POST":
|
|
616
589
|
res.writeHead(200);
|
|
@@ -622,7 +595,18 @@ export const startApiServer = async (
|
|
|
622
595
|
r404();
|
|
623
596
|
break;
|
|
624
597
|
}
|
|
625
|
-
} else if (req.url.startsWith(
|
|
598
|
+
} /* else if (req.url.startsWith(TERMINATE_PATH)) {
|
|
599
|
+
switch (req.method) {
|
|
600
|
+
case "POST":
|
|
601
|
+
execSync("shutdown -h now")
|
|
602
|
+
process.exit(0);
|
|
603
|
+
break;
|
|
604
|
+
|
|
605
|
+
default:
|
|
606
|
+
r404();
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
} */ else if (req.url.startsWith(PEER_ID_PATH)) {
|
|
626
610
|
res.writeHead(200);
|
|
627
611
|
res.end(client.peerId.toString());
|
|
628
612
|
} else if (req.url.startsWith(ADDRESS_PATH)) {
|