@peerbit/server 1.1.2 → 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 (54) hide show
  1. package/lib/esm/cli.js +518 -144
  2. package/lib/esm/cli.js.map +1 -1
  3. package/lib/esm/client.d.ts +11 -3
  4. package/lib/esm/client.js +61 -27
  5. package/lib/esm/client.js.map +1 -1
  6. package/lib/esm/config.d.ts +8 -5
  7. package/lib/esm/config.js +44 -19
  8. package/lib/esm/config.js.map +1 -1
  9. package/lib/esm/peerbit.d.ts +4 -0
  10. package/lib/esm/peerbit.js +15 -2
  11. package/lib/esm/peerbit.js.map +1 -1
  12. package/lib/esm/remotes.browser.d.ts +0 -0
  13. package/lib/esm/remotes.browser.js +3 -0
  14. package/lib/esm/remotes.browser.js.map +1 -0
  15. package/lib/esm/remotes.d.ts +16 -0
  16. package/lib/esm/remotes.js +51 -0
  17. package/lib/esm/remotes.js.map +1 -0
  18. package/lib/esm/routes.d.ts +3 -0
  19. package/lib/esm/routes.js +3 -0
  20. package/lib/esm/routes.js.map +1 -1
  21. package/lib/esm/server.d.ts +14 -4
  22. package/lib/esm/server.js +297 -144
  23. package/lib/esm/server.js.map +1 -1
  24. package/lib/esm/session.d.ts +19 -0
  25. package/lib/esm/session.js +49 -0
  26. package/lib/esm/session.js.map +1 -0
  27. package/lib/esm/signes-request.d.ts +5 -0
  28. package/lib/esm/signes-request.js +54 -0
  29. package/lib/esm/signes-request.js.map +1 -0
  30. package/lib/esm/trust.browser.d.ts +0 -0
  31. package/lib/esm/trust.browser.js +3 -0
  32. package/lib/esm/trust.browser.js.map +1 -0
  33. package/lib/esm/trust.d.ts +9 -0
  34. package/lib/esm/trust.js +36 -0
  35. package/lib/esm/trust.js.map +1 -0
  36. package/lib/esm/types.d.ts +10 -0
  37. package/lib/ui/assets/index-cac7195d.js +77 -0
  38. package/lib/ui/index.html +1 -1
  39. package/package.json +9 -5
  40. package/src/cli.ts +705 -271
  41. package/src/client.ts +105 -30
  42. package/src/config.ts +52 -25
  43. package/src/peerbit.ts +27 -3
  44. package/src/remotes.browser.ts +1 -0
  45. package/src/remotes.ts +63 -0
  46. package/src/routes.ts +3 -1
  47. package/src/server.ts +381 -190
  48. package/src/session.ts +69 -0
  49. package/src/signes-request.ts +84 -0
  50. package/src/trust.browser.ts +1 -0
  51. package/src/trust.ts +39 -0
  52. package/src/types.ts +13 -0
  53. package/lib/ui/assets/config.browser-4ed993c7.js +0 -1
  54. package/lib/ui/assets/index-a8188422.js +0 -53
package/src/client.ts CHANGED
@@ -1,20 +1,45 @@
1
- import { StartByBase64, StartByVariant, StartProgram } from "./types.js";
1
+ import { InstallDependency, StartProgram } from "./types.js";
2
2
  import {
3
3
  ADDRESS_PATH,
4
4
  BOOTSTRAP_PATH,
5
+ TERMINATE_PATH,
5
6
  INSTALL_PATH,
6
7
  LOCAL_PORT,
7
8
  PEER_ID_PATH,
8
9
  PROGRAMS_PATH,
9
10
  PROGRAM_PATH,
11
+ RESTART_PATH,
12
+ TRUST_PATH,
10
13
  } from "./routes.js";
11
14
  import { Address } from "@peerbit/program";
12
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";
13
24
 
14
25
  export const client = async (
26
+ keypair: Identity<Ed25519PublicKey>,
15
27
  endpoint: string = "http://localhost:" + LOCAL_PORT
16
28
  ) => {
29
+ const isLocalHost = endpoint.startsWith("http://localhost");
17
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
+ });
18
43
 
19
44
  const validateStatus = (status: number) => {
20
45
  return (status >= 200 && status < 300) || status == 404;
@@ -43,16 +68,13 @@ export const client = async (
43
68
  );
44
69
  };
45
70
  const getId = async () =>
46
- throwIfNot200(await axios.get(endpoint + PEER_ID_PATH, { validateStatus }))
47
- .data;
71
+ throwIfNot200(
72
+ await axiosInstance.get(endpoint + PEER_ID_PATH, {
73
+ validateStatus,
74
+ timeout: 5000,
75
+ })
76
+ ).data;
48
77
 
49
- const getHeaders = async () => {
50
- const config = await import("./config.js");
51
- const headers = {
52
- authorization: "Basic admin:" + (await config.loadPassword()),
53
- };
54
- return headers;
55
- };
56
78
  return {
57
79
  peer: {
58
80
  id: {
@@ -62,7 +84,7 @@ export const client = async (
62
84
  get: async () => {
63
85
  return (
64
86
  throwIfNot200(
65
- await axios.get(endpoint + ADDRESS_PATH, {
87
+ await axiosInstance.get(endpoint + ADDRESS_PATH, {
66
88
  validateStatus,
67
89
  })
68
90
  ).data as string[]
@@ -70,14 +92,51 @@ export const client = async (
70
92
  },
71
93
  },
72
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
+ },
73
132
  program: {
74
133
  has: async (address: Address | string): Promise<boolean> => {
75
- const result = await axios.head(
134
+ const result = await axiosInstance.head(
76
135
  endpoint +
77
136
  PROGRAM_PATH +
78
137
  "/" +
79
138
  encodeURIComponent(address.toString()),
80
- { validateStatus, headers: await getHeaders() }
139
+ { validateStatus }
81
140
  );
82
141
  if (result.status !== 200 && result.status !== 404) {
83
142
  throw new Error(result.data);
@@ -87,24 +146,26 @@ export const client = async (
87
146
 
88
147
  open: async (program: StartProgram): Promise<Address> => {
89
148
  const resp = throwIfNot200(
90
- await axios.put(endpoint + PROGRAM_PATH, JSON.stringify(program), {
91
- validateStatus,
92
- headers: await getHeaders(),
93
- })
149
+ await axiosInstance.put(
150
+ endpoint + PROGRAM_PATH,
151
+ JSON.stringify(program),
152
+ {
153
+ validateStatus,
154
+ }
155
+ )
94
156
  );
95
157
  return resp.data as string;
96
158
  },
97
159
 
98
160
  close: async (address: string): Promise<void> => {
99
161
  throwIfNot200(
100
- await axios.delete(
162
+ await axiosInstance.delete(
101
163
  endpoint +
102
164
  PROGRAM_PATH +
103
165
  "/" +
104
166
  encodeURIComponent(address.toString()),
105
167
  {
106
168
  validateStatus,
107
- headers: await getHeaders(),
108
169
  }
109
170
  )
110
171
  );
@@ -112,7 +173,7 @@ export const client = async (
112
173
 
113
174
  drop: async (address: string): Promise<void> => {
114
175
  throwIfNot200(
115
- await axios.delete(
176
+ await axiosInstance.delete(
116
177
  endpoint +
117
178
  PROGRAM_PATH +
118
179
  "/" +
@@ -120,7 +181,6 @@ export const client = async (
120
181
  "?delete=true",
121
182
  {
122
183
  validateStatus,
123
- headers: await getHeaders(),
124
184
  }
125
185
  )
126
186
  );
@@ -128,20 +188,22 @@ export const client = async (
128
188
 
129
189
  list: async (): Promise<string[]> => {
130
190
  const resp = throwIfNot200(
131
- await axios.get(endpoint + PROGRAMS_PATH, {
191
+ await axiosInstance.get(endpoint + PROGRAMS_PATH, {
132
192
  validateStatus,
133
- headers: await getHeaders(),
134
193
  })
135
194
  );
136
195
  return resp.data as string[];
137
196
  },
138
197
  },
139
198
  dependency: {
140
- install: async (name: string): Promise<string[]> => {
141
- const resp = await axios.put(endpoint + INSTALL_PATH, name, {
142
- validateStatus,
143
- headers: await getHeaders(),
144
- });
199
+ install: async (instruction: InstallDependency): Promise<string[]> => {
200
+ const resp = await axiosInstance.put(
201
+ endpoint + INSTALL_PATH,
202
+ JSON.stringify(instruction),
203
+ {
204
+ validateStatus,
205
+ }
206
+ );
145
207
  if (resp.status !== 200) {
146
208
  throw new Error(
147
209
  typeof resp.data === "string" ? resp.data : resp.data.toString()
@@ -153,12 +215,25 @@ export const client = async (
153
215
  network: {
154
216
  bootstrap: async (): Promise<void> => {
155
217
  throwIfNot200(
156
- await axios.post(endpoint + BOOTSTRAP_PATH, undefined, {
218
+ await axiosInstance.post(endpoint + BOOTSTRAP_PATH, undefined, {
157
219
  validateStatus,
158
- headers: await getHeaders(),
159
220
  })
160
221
  );
161
222
  },
162
223
  },
224
+ restart: async (): Promise<void> => {
225
+ throwIfNot200(
226
+ await axiosInstance.post(endpoint + RESTART_PATH, undefined, {
227
+ validateStatus,
228
+ })
229
+ );
230
+ },
231
+ terminate: async (): Promise<void> => {
232
+ throwIfNot200(
233
+ await axiosInstance.post(endpoint + TERMINATE_PATH, undefined, {
234
+ validateStatus,
235
+ })
236
+ );
237
+ },
163
238
  };
164
239
  };
package/src/config.ts CHANGED
@@ -1,22 +1,56 @@
1
1
  import path from "path";
2
2
  import os from "os";
3
3
  import fs from "fs";
4
+ import { deserialize, serialize } from "@dao-xyz/borsh";
5
+ import { Duplex } from "stream"; // Native Node Module
6
+ import { Ed25519Keypair, Keypair, fromBase64 } from "@peerbit/crypto";
4
7
 
5
- export const getHomeConfigDir = async (): Promise<string> => {
8
+ const bufferToStream = (myBuffer) => {
9
+ const tmp = new Duplex();
10
+ tmp.push(myBuffer);
11
+ tmp.push(null);
12
+ return tmp;
13
+ };
14
+
15
+ export const getHomeConfigDir = (): string => {
6
16
  const configDir = path.join(os.homedir(), ".peerbit");
7
17
  return configDir;
8
18
  };
9
19
 
10
- export const getCredentialsPath = async (
11
- configDir: string
12
- ): Promise<string> => {
13
- return path.join(configDir, "credentials");
20
+ export const getServerConfigPath = (configDir: string): string => {
21
+ return path.join(configDir, "server");
22
+ };
23
+
24
+ export const getRemotesPath = (configDir: string): string => {
25
+ return path.join(configDir, "remotes.json");
14
26
  };
15
27
 
16
- export const getKeysPath = async (configDir: string): Promise<string> => {
28
+ export const getNodePath = (directory: string): string => {
29
+ return path.join(directory, "node");
30
+ };
31
+
32
+ export const getTrustPath = (directory: string): string => {
33
+ return path.join(directory, "trust.json");
34
+ };
35
+
36
+ const getKeysPath = (configDir: string): string => {
17
37
  return path.join(configDir, "keys");
18
38
  };
19
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
+
20
54
  export const checkExistPath = async (path: string) => {
21
55
  try {
22
56
  if (!fs.existsSync(path)) {
@@ -32,27 +66,16 @@ export const checkExistPath = async (path: string) => {
32
66
  }
33
67
  };
34
68
 
35
- export const loadPassword = async (): Promise<string> => {
36
- const configDir = await getHomeConfigDir();
37
- const credentialsPath = await getCredentialsPath(configDir);
38
- if (!(await checkExistPath(credentialsPath))) {
39
- throw new NotFoundError("Credentials file does not exist");
40
- }
41
- const password = JSON.parse(
42
- fs.readFileSync(credentialsPath, "utf-8")
43
- ).password;
44
- if (!password || password.length === 0) {
45
- throw new NotFoundError("Password not found");
46
- }
47
- return password;
48
- };
49
-
50
- export const getPackageName = async (path: string): Promise<string> => {
69
+ export const getPackageName = async (
70
+ path: string | Uint8Array
71
+ ): Promise<string> => {
51
72
  const tar = await import("tar-stream");
52
73
  const zlib = await import("zlib");
53
74
 
54
- if (!fs.existsSync(path)) {
55
- throw new Error("File does not exist");
75
+ if (typeof path === "string") {
76
+ if (!fs.existsSync(path)) {
77
+ throw new Error("File does not exist");
78
+ }
56
79
  }
57
80
  return new Promise((resolve, reject) => {
58
81
  try {
@@ -84,7 +107,11 @@ export const getPackageName = async (path: string): Promise<string> => {
84
107
  reject(e);
85
108
  });
86
109
 
87
- fs.createReadStream(path).pipe(zlib.createGunzip()).pipe(extract);
110
+ if (typeof path === "string") {
111
+ fs.createReadStream(path).pipe(zlib.createGunzip()).pipe(extract);
112
+ } else {
113
+ bufferToStream(path).pipe(zlib.createGunzip()).pipe(extract);
114
+ }
88
115
  } catch (error) {
89
116
  reject(error);
90
117
  }
package/src/peerbit.ts CHANGED
@@ -1,10 +1,25 @@
1
1
  import { DirectBlock } from "@peerbit/blocks";
2
2
  import { DirectSub } from "@peerbit/pubsub";
3
3
  import { Peerbit } from "peerbit";
4
+ import path from "path";
5
+ import { PeerId } from "@libp2p/interface-peer-id";
6
+
7
+ export const LIBP2P_LISTEN_PORT = 8001;
8
+ export const create = (properties: {
9
+ directory?: string;
10
+ domain?: string;
11
+ listenPort?: number;
12
+ peerId: PeerId;
13
+ }) => {
14
+ const listenPort = properties.listenPort ?? LIBP2P_LISTEN_PORT;
15
+ const blocksDirectory =
16
+ properties.directory != null
17
+ ? path.join(properties.directory, "/blocks").toString()
18
+ : undefined;
4
19
 
5
- export const create = (properties: { directory?: string; domain?: string }) => {
6
20
  return Peerbit.create({
7
21
  libp2p: {
22
+ peerId: properties.peerId,
8
23
  addresses: {
9
24
  announce: properties.domain
10
25
  ? [
@@ -12,14 +27,23 @@ export const create = (properties: { directory?: string; domain?: string }) => {
12
27
  `/dns4/${properties.domain}/tcp/4003/wss`,
13
28
  ]
14
29
  : undefined,
15
- listen: ["/ip4/127.0.0.1/tcp/8001", "/ip4/127.0.0.1/tcp/8002/ws"],
30
+ listen: [
31
+ `/ip4/127.0.0.1/tcp/${listenPort}`,
32
+ `/ip4/127.0.0.1/tcp/${
33
+ listenPort !== 0 ? listenPort + 1 : listenPort
34
+ }/ws`,
35
+ ],
16
36
  },
17
37
  connectionManager: {
18
38
  maxConnections: Infinity,
19
39
  minConnections: 0,
20
40
  },
21
41
  services: {
22
- blocks: (c) => new DirectBlock(c, { canRelayMessage: true }),
42
+ blocks: (c) =>
43
+ new DirectBlock(c, {
44
+ directory: blocksDirectory,
45
+ canRelayMessage: true,
46
+ }),
23
47
  pubsub: (c) => new DirectSub(c, { canRelayMessage: true }),
24
48
  },
25
49
  },
@@ -0,0 +1 @@
1
+ // Not supported
package/src/remotes.ts ADDED
@@ -0,0 +1,63 @@
1
+ import fs from "fs";
2
+
3
+ interface RemoteObject {
4
+ address: string;
5
+ name: string;
6
+ }
7
+
8
+ interface RemotesObject {
9
+ remotes: RemoteObject[];
10
+ }
11
+
12
+ export class Remotes {
13
+ private data: RemotesObject;
14
+
15
+ constructor(readonly path: string) {
16
+ if (fs.existsSync(path)) {
17
+ this.data = JSON.parse(
18
+ fs.readFileSync(path).toString("utf-8")
19
+ ) as RemotesObject;
20
+ } else {
21
+ this.data = {
22
+ remotes: [],
23
+ };
24
+ }
25
+ }
26
+
27
+ save() {
28
+ fs.writeFileSync(this.path, JSON.stringify(this.data));
29
+ }
30
+
31
+ getByName(name: string) {
32
+ return this.data.remotes.find((x) => x.name === name);
33
+ }
34
+ getByAddress(address: string) {
35
+ return this.data.remotes.find((x) => x.address === address);
36
+ }
37
+ add(name: string, address: string) {
38
+ const obj: RemoteObject = {
39
+ address,
40
+ name,
41
+ };
42
+ const existing = this.data.remotes.findIndex((x) => x.name === name);
43
+ if (existing >= 0) {
44
+ this.data.remotes[existing] = obj;
45
+ } else {
46
+ this.data.remotes.push(obj);
47
+ }
48
+ this.save();
49
+ }
50
+
51
+ remove(name: string) {
52
+ const existing = this.data.remotes.findIndex((x) => x.name === name);
53
+ if (existing >= 0) {
54
+ this.data.remotes.splice(existing, 1);
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+
60
+ async all(): Promise<RemoteObject[]> {
61
+ return this.data.remotes;
62
+ }
63
+ }
package/src/routes.ts CHANGED
@@ -11,10 +11,12 @@ 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";
18
18
  export const PROGRAMS_PATH = "/programs";
19
19
  export const INSTALL_PATH = "/install";
20
20
  export const BOOTSTRAP_PATH = "/network/bootstrap";
21
+ export const RESTART_PATH = "/restart";
22
+ export const TERMINATE_PATH = "/terminate";