@peers-app/peers-sdk 0.14.0 → 0.15.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/dist/context/data-context.d.ts +4 -4
- package/dist/context/data-context.js +1 -1
- package/dist/context/index.d.ts +3 -3
- package/dist/context/index.js +4 -0
- package/dist/context/user-context-singleton.js +13 -14
- package/dist/context/user-context.d.ts +4 -4
- package/dist/context/user-context.js +48 -31
- package/dist/data/assistants.d.ts +1 -1
- package/dist/data/assistants.js +35 -24
- package/dist/data/change-tracking.d.ts +8 -8
- package/dist/data/change-tracking.js +45 -39
- package/dist/data/channels.js +5 -5
- package/dist/data/data-locks.d.ts +2 -2
- package/dist/data/data-locks.js +21 -23
- package/dist/data/data-locks.test.js +73 -75
- package/dist/data/device-sync-info.d.ts +1 -1
- package/dist/data/device-sync-info.js +4 -4
- package/dist/data/devices.d.ts +1 -1
- package/dist/data/devices.js +9 -12
- package/dist/data/embeddings.js +14 -11
- package/dist/data/files/file-read-stream.d.ts +2 -2
- package/dist/data/files/file-read-stream.js +23 -14
- package/dist/data/files/file-write-stream.d.ts +2 -2
- package/dist/data/files/file-write-stream.js +8 -8
- package/dist/data/files/file.types.d.ts +2 -2
- package/dist/data/files/file.types.js +17 -11
- package/dist/data/files/files.d.ts +6 -6
- package/dist/data/files/files.js +17 -19
- package/dist/data/files/files.test.js +213 -214
- package/dist/data/files/index.d.ts +4 -4
- package/dist/data/files/index.js +4 -4
- package/dist/data/group-member-roles.js +2 -2
- package/dist/data/group-members.d.ts +5 -5
- package/dist/data/group-members.js +27 -18
- package/dist/data/group-members.test.js +73 -73
- package/dist/data/group-permissions.d.ts +3 -3
- package/dist/data/group-permissions.js +13 -11
- package/dist/data/group-share.d.ts +2 -2
- package/dist/data/group-share.js +29 -24
- package/dist/data/groups.d.ts +4 -4
- package/dist/data/groups.js +27 -19
- package/dist/data/groups.test.js +44 -44
- package/dist/data/index.d.ts +6 -6
- package/dist/data/index.js +6 -6
- package/dist/data/knowledge/peer-types.js +9 -9
- package/dist/data/messages.d.ts +5 -5
- package/dist/data/messages.js +43 -30
- package/dist/data/orm/client-proxy.data-source.d.ts +4 -4
- package/dist/data/orm/client-proxy.data-source.js +10 -12
- package/dist/data/orm/cursor.d.ts +1 -1
- package/dist/data/orm/cursor.js +2 -2
- package/dist/data/orm/cursor.test.js +92 -93
- package/dist/data/orm/data-query.d.ts +3 -3
- package/dist/data/orm/data-query.js +24 -18
- package/dist/data/orm/data-query.mongo.d.ts +1 -1
- package/dist/data/orm/data-query.mongo.js +49 -51
- package/dist/data/orm/data-query.mongo.test.js +173 -204
- package/dist/data/orm/data-query.sqlite.d.ts +1 -1
- package/dist/data/orm/data-query.sqlite.js +84 -73
- package/dist/data/orm/data-query.sqlite.test.js +164 -176
- package/dist/data/orm/data-query.test.js +216 -224
- package/dist/data/orm/decorators.js +3 -3
- package/dist/data/orm/dependency-injection.test.js +53 -56
- package/dist/data/orm/doc.d.ts +4 -4
- package/dist/data/orm/doc.js +17 -21
- package/dist/data/orm/event-registry.d.ts +1 -1
- package/dist/data/orm/event-registry.test.js +16 -16
- package/dist/data/orm/factory.d.ts +2 -2
- package/dist/data/orm/factory.js +33 -33
- package/dist/data/orm/index.d.ts +10 -10
- package/dist/data/orm/index.js +10 -10
- package/dist/data/orm/multi-cursors.d.ts +1 -1
- package/dist/data/orm/multi-cursors.js +6 -6
- package/dist/data/orm/multi-cursors.test.js +152 -144
- package/dist/data/orm/sql.data-source.d.ts +7 -7
- package/dist/data/orm/sql.data-source.js +88 -93
- package/dist/data/orm/sql.data-source.test.js +109 -101
- package/dist/data/orm/subscribable.data-source.d.ts +4 -4
- package/dist/data/orm/subscribable.data-source.js +5 -5
- package/dist/data/orm/table-container-events.test.js +34 -26
- package/dist/data/orm/table-container.d.ts +6 -6
- package/dist/data/orm/table-container.js +33 -21
- package/dist/data/orm/table-container.test.js +64 -53
- package/dist/data/orm/table-definitions.system.d.ts +3 -3
- package/dist/data/orm/table-definitions.system.js +3 -3
- package/dist/data/orm/table-definitions.type.d.ts +5 -5
- package/dist/data/orm/table-dependencies.d.ts +2 -2
- package/dist/data/orm/table.d.ts +5 -5
- package/dist/data/orm/table.event-source.test.js +105 -115
- package/dist/data/orm/table.js +35 -34
- package/dist/data/orm/types.d.ts +3 -3
- package/dist/data/orm/types.js +26 -25
- package/dist/data/orm/types.test.js +166 -92
- package/dist/data/package-permissions.d.ts +1 -1
- package/dist/data/package-permissions.js +2 -2
- package/dist/data/package-version-permissions.d.ts +1 -1
- package/dist/data/package-version-permissions.js +2 -2
- package/dist/data/package-versions.d.ts +9 -9
- package/dist/data/package-versions.js +47 -33
- package/dist/data/packages.d.ts +2 -2
- package/dist/data/packages.js +36 -18
- package/dist/data/packages.utils.d.ts +2 -2
- package/dist/data/packages.utils.js +4 -4
- package/dist/data/persistent-vars.d.ts +15 -15
- package/dist/data/persistent-vars.js +165 -154
- package/dist/data/table-definitions-table.d.ts +5 -5
- package/dist/data/table-definitions-table.js +13 -12
- package/dist/data/tool-tests.js +6 -6
- package/dist/data/tools.js +29 -19
- package/dist/data/user-permissions.d.ts +1 -1
- package/dist/data/user-permissions.js +5 -5
- package/dist/data/user-permissions.test.js +90 -88
- package/dist/data/user-trust-levels.js +10 -10
- package/dist/data/users.d.ts +4 -4
- package/dist/data/users.js +16 -15
- package/dist/data/voice-messages.d.ts +2 -2
- package/dist/data/voice-messages.js +13 -13
- package/dist/data/welcome-modal.pvar.js +3 -1
- package/dist/data/workflow-logs.js +26 -18
- package/dist/data/workflow-runs.d.ts +6 -6
- package/dist/data/workflow-runs.js +70 -44
- package/dist/data/workflows.d.ts +2 -2
- package/dist/data/workflows.js +7 -9
- package/dist/device/binary-peer-connection-v2.d.ts +7 -7
- package/dist/device/binary-peer-connection-v2.js +32 -28
- package/dist/device/binary-peer-connection-v2.test.js +80 -67
- package/dist/device/binary-peer-connection.d.ts +7 -7
- package/dist/device/binary-peer-connection.js +29 -28
- package/dist/device/binary-peer-connection.test.js +35 -31
- package/dist/device/connection.d.ts +5 -5
- package/dist/device/connection.js +59 -48
- package/dist/device/connection.test.js +74 -68
- package/dist/device/device-election.d.ts +2 -2
- package/dist/device/device-election.js +25 -20
- package/dist/device/device-election.test.js +35 -36
- package/dist/device/device.d.ts +2 -2
- package/dist/device/device.js +10 -4
- package/dist/device/device.test.js +16 -17
- package/dist/device/get-trust-level-fn.d.ts +2 -2
- package/dist/device/get-trust-level-fn.js +22 -11
- package/dist/device/get-trust-level-fn.test.js +58 -58
- package/dist/device/socket-io-binary-peer.d.ts +1 -1
- package/dist/device/socket-io-binary-peer.js +16 -13
- package/dist/device/socket.type.d.ts +2 -2
- package/dist/device/streamed-socket.d.ts +2 -2
- package/dist/device/streamed-socket.js +8 -8
- package/dist/device/streamed-socket.test.js +40 -40
- package/dist/device/tx-encoding.test.js +77 -77
- package/dist/events.d.ts +1 -1
- package/dist/events.js +5 -2
- package/dist/group-invite/group-invite.js +110 -19
- package/dist/group-invite/group-invite.pvars.d.ts +2 -2
- package/dist/group-invite/group-invite.pvars.js +21 -13
- package/dist/group-invite/group-invite.types.d.ts +1 -1
- package/dist/group-invite/index.d.ts +3 -3
- package/dist/group-invite/index.js +1 -1
- package/dist/index.d.ts +25 -24
- package/dist/index.js +30 -25
- package/dist/keys.d.ts +3 -3
- package/dist/keys.js +31 -30
- package/dist/keys.test.js +69 -61
- package/dist/logging/console-logger.d.ts +1 -1
- package/dist/logging/console-logger.js +35 -40
- package/dist/logging/console-logger.test.js +115 -115
- package/dist/logging/console-logs.table.d.ts +3 -3
- package/dist/logging/console-logs.table.js +28 -23
- package/dist/mentions.js +16 -12
- package/dist/observable.d.ts +2 -2
- package/dist/observable.js +15 -9
- package/dist/observable.test.js +47 -47
- package/dist/package-loader/get-require.js +3 -4
- package/dist/package-loader/package-loader.d.ts +2 -2
- package/dist/package-loader/package-loader.js +52 -34
- package/dist/peers-ui/peers-ui.d.ts +2 -2
- package/dist/peers-ui/peers-ui.js +2 -4
- package/dist/peers-ui/peers-ui.types.d.ts +3 -3
- package/dist/peers-ui/peers-ui.types.js +0 -1
- package/dist/rpc-types.d.ts +61 -59
- package/dist/rpc-types.js +61 -55
- package/dist/serial-json.d.ts +1 -1
- package/dist/serial-json.js +50 -43
- package/dist/serial-json.test.js +22 -22
- package/dist/system-ids.js +8 -8
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/tools-factory.d.ts +1 -1
- package/dist/tools/tools-factory.js +2 -2
- package/dist/types/assistant-runner-args.d.ts +3 -3
- package/dist/types/peer-device.d.ts +1 -1
- package/dist/types/peers-package.d.ts +3 -3
- package/dist/types/workflow-logger.d.ts +1 -1
- package/dist/types/workflow-run-context.d.ts +4 -4
- package/dist/types/workflow.d.ts +4 -4
- package/dist/types/workflow.js +27 -14
- package/dist/types/zod-types.d.ts +2 -1
- package/dist/types/zod-types.js +9 -3
- package/dist/user-connect/connection-code.d.ts +1 -1
- package/dist/user-connect/connection-code.js +7 -7
- package/dist/user-connect/connection-code.test.js +106 -106
- package/dist/user-connect/index.d.ts +3 -3
- package/dist/user-connect/index.js +1 -1
- package/dist/user-connect/user-connect.pvars.js +13 -11
- package/dist/user-connect/user-connect.types.d.ts +3 -3
- package/dist/users.query.d.ts +2 -2
- package/dist/users.query.js +40 -30
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +34 -32
- package/dist/utils.test.js +12 -8
- package/dist/workflow-log-formatter.d.ts +1 -1
- package/dist/workflow-log-formatter.js +17 -18
- package/package.json +14 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const utils_1 = require("../utils");
|
|
4
3
|
const keys_1 = require("../keys");
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
const connection_1 = require("./connection");
|
|
6
6
|
const device_1 = require("./device");
|
|
7
7
|
function createTestSocket(localHandlers, remoteHandlers) {
|
|
@@ -17,7 +17,7 @@ function createTestSocket(localHandlers, remoteHandlers) {
|
|
|
17
17
|
on(eventName, handler) {
|
|
18
18
|
localHandlers.push({
|
|
19
19
|
eventName,
|
|
20
|
-
handler: async (...args) => handler(...args)
|
|
20
|
+
handler: async (...args) => handler(...args),
|
|
21
21
|
});
|
|
22
22
|
},
|
|
23
23
|
removeAllListeners(eventName) {
|
|
@@ -28,7 +28,7 @@ function createTestSocket(localHandlers, remoteHandlers) {
|
|
|
28
28
|
},
|
|
29
29
|
disconnect() {
|
|
30
30
|
// Simulate disconnection logic if needed
|
|
31
|
-
}
|
|
31
|
+
},
|
|
32
32
|
};
|
|
33
33
|
return socket;
|
|
34
34
|
}
|
|
@@ -51,35 +51,35 @@ describe(connection_1.Connection, () => {
|
|
|
51
51
|
const clientDevice = new device_1.Device();
|
|
52
52
|
const serverDevice = new device_1.Device();
|
|
53
53
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
54
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
54
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["localhost"]);
|
|
55
55
|
expect(clientConnection.connectionId).toBe(serverConnection.connectionId);
|
|
56
|
-
const response = await clientConnection.doHandshake(
|
|
56
|
+
const response = await clientConnection.doHandshake("localhost");
|
|
57
57
|
expect(response.userId).toBe(serverDevice.userId);
|
|
58
58
|
expect(response.deviceId).toBe(serverDevice.deviceId);
|
|
59
59
|
expect(response.publicKey).toBe(serverDevice.publicKey);
|
|
60
60
|
expect(response.publicBoxKey).toBe(serverDevice.publicBoxKey);
|
|
61
|
-
expect(response.serverAddress).toBe(
|
|
61
|
+
expect(response.serverAddress).toBe("localhost");
|
|
62
62
|
expect(response.connectionId).toBe(serverConnection.connectionId);
|
|
63
|
-
serverConnection.removeAllListeners(
|
|
64
|
-
serverConnection.exposeRPC(
|
|
65
|
-
const pong = await clientConnection.emit(
|
|
66
|
-
expect(pong).toBe(
|
|
63
|
+
serverConnection.removeAllListeners("ping");
|
|
64
|
+
serverConnection.exposeRPC("ping", async (n, s) => `pong - ${n}, ${s}`);
|
|
65
|
+
const pong = await clientConnection.emit("ping", 1, "hello");
|
|
66
|
+
expect(pong).toBe("pong - 1, hello");
|
|
67
67
|
});
|
|
68
68
|
it("should create a new id if socket doesn't have one", async () => {
|
|
69
69
|
const socket = {
|
|
70
70
|
id: (0, utils_1.newid)(),
|
|
71
|
-
emit(
|
|
71
|
+
emit(_eventName, _args, _callback) {
|
|
72
72
|
// do nothing
|
|
73
73
|
},
|
|
74
|
-
on(
|
|
74
|
+
on(_eventName, _handler) {
|
|
75
75
|
// do nothing
|
|
76
76
|
},
|
|
77
|
-
removeAllListeners(
|
|
77
|
+
removeAllListeners(_eventName) {
|
|
78
78
|
// do nothing
|
|
79
79
|
},
|
|
80
80
|
disconnect() {
|
|
81
81
|
// do nothing
|
|
82
|
-
}
|
|
82
|
+
},
|
|
83
83
|
};
|
|
84
84
|
const connection = new connection_1.Connection(socket, new device_1.Device());
|
|
85
85
|
expect(connection.connectionId).toBeTruthy();
|
|
@@ -89,11 +89,11 @@ describe(connection_1.Connection, () => {
|
|
|
89
89
|
const clientDevice = new device_1.Device();
|
|
90
90
|
const serverDevice = new device_1.Device();
|
|
91
91
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
92
|
-
const
|
|
93
|
-
await clientConnection.doHandshake(
|
|
92
|
+
const _serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["https://localhost"]);
|
|
93
|
+
await clientConnection.doHandshake("https://localhost");
|
|
94
94
|
expect(clientConnection.encryptTraffic).toBe(false);
|
|
95
95
|
// and allow forcing insecure
|
|
96
|
-
clientConnection.overrideEncryption =
|
|
96
|
+
clientConnection.overrideEncryption = "encrypt-traffic-regardless-of-protocol";
|
|
97
97
|
expect(clientConnection.encryptTraffic).toBe(true);
|
|
98
98
|
// and only return a copy of the remoteDeviceInfo
|
|
99
99
|
expect(clientConnection.remoteDeviceInfo).not.toBe(clientConnection.remoteDeviceInfo);
|
|
@@ -103,13 +103,15 @@ describe(connection_1.Connection, () => {
|
|
|
103
103
|
const clientDevice = new device_1.Device();
|
|
104
104
|
const serverDevice = new device_1.Device();
|
|
105
105
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
106
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
107
|
-
await clientConnection.doHandshake(
|
|
106
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["https://localhost"]);
|
|
107
|
+
await clientConnection.doHandshake("https://localhost");
|
|
108
108
|
expect(clientConnection.encryptTraffic).toBe(false);
|
|
109
109
|
expect(serverConnection.encryptTraffic).toBe(false);
|
|
110
|
-
serverConnection.removeAllListeners(
|
|
111
|
-
serverConnection.exposeRPC(
|
|
112
|
-
|
|
110
|
+
serverConnection.removeAllListeners("ping");
|
|
111
|
+
serverConnection.exposeRPC("ping", async () => {
|
|
112
|
+
throw new Error("fake error");
|
|
113
|
+
});
|
|
114
|
+
const response = await clientConnection.emit("ping").catch((err) => err);
|
|
113
115
|
expect(response).toEqual({
|
|
114
116
|
errorType: "RPC_ERROR",
|
|
115
117
|
error: "fake error",
|
|
@@ -120,13 +122,15 @@ describe(connection_1.Connection, () => {
|
|
|
120
122
|
const clientDevice = new device_1.Device();
|
|
121
123
|
const serverDevice = new device_1.Device();
|
|
122
124
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
123
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
124
|
-
await clientConnection.doHandshake(
|
|
125
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["http://localhost"]);
|
|
126
|
+
await clientConnection.doHandshake("http://localhost");
|
|
125
127
|
expect(clientConnection.encryptTraffic).toBe(true);
|
|
126
128
|
expect(serverConnection.encryptTraffic).toBe(true);
|
|
127
|
-
serverConnection.removeAllListeners(
|
|
128
|
-
serverConnection.exposeRPC(
|
|
129
|
-
|
|
129
|
+
serverConnection.removeAllListeners("ping");
|
|
130
|
+
serverConnection.exposeRPC("ping", async () => {
|
|
131
|
+
throw new Error("fake error");
|
|
132
|
+
});
|
|
133
|
+
const response = await clientConnection.emit("ping").catch((err) => err);
|
|
130
134
|
expect(response).toEqual({
|
|
131
135
|
errorType: "RPC_ERROR",
|
|
132
136
|
error: "fake error",
|
|
@@ -137,74 +141,74 @@ describe(connection_1.Connection, () => {
|
|
|
137
141
|
const clientDevice = new device_1.Device();
|
|
138
142
|
const serverDevice = new device_1.Device();
|
|
139
143
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
140
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
141
|
-
serverConnection.exposeRPC(
|
|
144
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["https://localhost"]);
|
|
145
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
142
146
|
expect(serverConnection.verified).toBe(false);
|
|
143
147
|
expect(clientConnection.verified).toBe(false);
|
|
144
|
-
const response = await clientConnection.emit(
|
|
148
|
+
const response = await clientConnection.emit("ping").catch((err) => err);
|
|
145
149
|
expect(response).toMatch(/Connection not verified/);
|
|
146
150
|
});
|
|
147
151
|
it("client should detect different connection ids during handshake", async () => {
|
|
148
|
-
const serverAddress =
|
|
152
|
+
const serverAddress = "http://localhost";
|
|
149
153
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
150
154
|
const clientDevice = new device_1.Device();
|
|
151
155
|
const serverDevice = new device_1.Device();
|
|
152
156
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
153
157
|
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
154
|
-
serverConnection.exposeRPC(
|
|
155
|
-
serverConnection.socket.removeAllListeners(
|
|
156
|
-
serverConnection.exposeRPC(
|
|
158
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
159
|
+
serverConnection.socket.removeAllListeners("completeHandshake");
|
|
160
|
+
serverConnection.exposeRPC("completeHandshake", async (handshakeBox) => {
|
|
157
161
|
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
158
|
-
handshake.connectionId =
|
|
162
|
+
handshake.connectionId = "fake";
|
|
159
163
|
return handshake;
|
|
160
164
|
});
|
|
161
165
|
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
162
166
|
expect(result).toMatch(/Invalid connectionId/);
|
|
163
167
|
});
|
|
164
168
|
it("client should detect different device ids during handshake", async () => {
|
|
165
|
-
const serverAddress =
|
|
169
|
+
const serverAddress = "http://localhost";
|
|
166
170
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
167
171
|
const clientDevice = new device_1.Device();
|
|
168
172
|
const serverDevice = new device_1.Device();
|
|
169
173
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
170
174
|
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
171
|
-
serverConnection.exposeRPC(
|
|
172
|
-
serverConnection.socket.removeAllListeners(
|
|
173
|
-
serverConnection.exposeRPC(
|
|
175
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
176
|
+
serverConnection.socket.removeAllListeners("completeHandshake");
|
|
177
|
+
serverConnection.exposeRPC("completeHandshake", async (handshakeBox) => {
|
|
174
178
|
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
175
|
-
handshake.deviceId =
|
|
179
|
+
handshake.deviceId = "fake";
|
|
176
180
|
return handshake;
|
|
177
181
|
});
|
|
178
182
|
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
179
183
|
expect(result).toMatch(/Inconsistent device info/);
|
|
180
184
|
});
|
|
181
185
|
it("client should detect different device ids during handshake", async () => {
|
|
182
|
-
const serverAddress =
|
|
186
|
+
const serverAddress = "http://localhost";
|
|
183
187
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
184
188
|
const clientDevice = new device_1.Device();
|
|
185
189
|
const serverDevice = new device_1.Device();
|
|
186
190
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
187
191
|
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
188
|
-
serverConnection.exposeRPC(
|
|
189
|
-
serverConnection.socket.removeAllListeners(
|
|
190
|
-
serverConnection.exposeRPC(
|
|
192
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
193
|
+
serverConnection.socket.removeAllListeners("completeHandshake");
|
|
194
|
+
serverConnection.exposeRPC("completeHandshake", async (handshakeBox) => {
|
|
191
195
|
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
192
|
-
handshake.userId =
|
|
196
|
+
handshake.userId = "fake";
|
|
193
197
|
return handshake;
|
|
194
198
|
});
|
|
195
199
|
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
196
200
|
expect(result).toMatch(/Inconsistent device info/);
|
|
197
201
|
});
|
|
198
202
|
it("client should detect different box key during handshake", async () => {
|
|
199
|
-
const serverAddress =
|
|
203
|
+
const serverAddress = "http://localhost";
|
|
200
204
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
201
205
|
const clientDevice = new device_1.Device();
|
|
202
206
|
const serverDevice = new device_1.Device();
|
|
203
207
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
204
208
|
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
205
|
-
serverConnection.exposeRPC(
|
|
206
|
-
serverConnection.socket.removeAllListeners(
|
|
207
|
-
serverConnection.exposeRPC(
|
|
209
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
210
|
+
serverConnection.socket.removeAllListeners("completeHandshake");
|
|
211
|
+
serverConnection.exposeRPC("completeHandshake", async (handshakeBox) => {
|
|
208
212
|
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
209
213
|
const _keys = (0, keys_1.newKeys)();
|
|
210
214
|
handshake.publicBoxKey = _keys.publicBoxKey;
|
|
@@ -214,15 +218,15 @@ describe(connection_1.Connection, () => {
|
|
|
214
218
|
expect(result).toMatch(/Inconsistent public keys/);
|
|
215
219
|
});
|
|
216
220
|
it("client should detect different public key during handshake", async () => {
|
|
217
|
-
const serverAddress =
|
|
221
|
+
const serverAddress = "http://localhost";
|
|
218
222
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
219
223
|
const clientDevice = new device_1.Device();
|
|
220
224
|
const serverDevice = new device_1.Device();
|
|
221
225
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
222
226
|
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
223
|
-
serverConnection.exposeRPC(
|
|
224
|
-
serverConnection.socket.removeAllListeners(
|
|
225
|
-
serverConnection.exposeRPC(
|
|
227
|
+
serverConnection.exposeRPC("ping", async () => "pong");
|
|
228
|
+
serverConnection.socket.removeAllListeners("completeHandshake");
|
|
229
|
+
serverConnection.exposeRPC("completeHandshake", async (handshakeBox) => {
|
|
226
230
|
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
227
231
|
const _keys = (0, keys_1.newKeys)();
|
|
228
232
|
handshake.publicKey = _keys.publicKey;
|
|
@@ -236,21 +240,21 @@ describe(connection_1.Connection, () => {
|
|
|
236
240
|
const clientDevice = new device_1.Device();
|
|
237
241
|
const serverDevice = new device_1.Device();
|
|
238
242
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
239
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
240
|
-
await clientConnection.doHandshake(
|
|
243
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["localhost"]);
|
|
244
|
+
await clientConnection.doHandshake("localhost");
|
|
241
245
|
// Create large data
|
|
242
246
|
const largeData = {
|
|
243
247
|
message: "A".repeat(500),
|
|
244
248
|
metadata: "B".repeat(300),
|
|
245
|
-
payload: "C".repeat(400)
|
|
249
|
+
payload: "C".repeat(400),
|
|
246
250
|
};
|
|
247
|
-
serverConnection.exposeRPC(
|
|
251
|
+
serverConnection.exposeRPC("processLargeData", async (data) => {
|
|
248
252
|
return {
|
|
249
253
|
received: data,
|
|
250
|
-
processedSize: JSON.stringify(data).length
|
|
254
|
+
processedSize: JSON.stringify(data).length,
|
|
251
255
|
};
|
|
252
256
|
});
|
|
253
|
-
const result = await clientConnection.emit(
|
|
257
|
+
const result = await clientConnection.emit("processLargeData", largeData);
|
|
254
258
|
expect(result.received.message).toBe("A".repeat(500));
|
|
255
259
|
expect(result.received.metadata).toBe("B".repeat(300));
|
|
256
260
|
expect(result.received.payload).toBe("C".repeat(400));
|
|
@@ -261,18 +265,20 @@ describe(connection_1.Connection, () => {
|
|
|
261
265
|
const clientDevice = new device_1.Device();
|
|
262
266
|
const serverDevice = new device_1.Device();
|
|
263
267
|
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
264
|
-
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [
|
|
268
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ["localhost"]);
|
|
265
269
|
// Set a very strict timestamp tolerance (1 second) to make test reliable
|
|
266
270
|
serverConnection.handshakeTimestampToleranceMs = 1000;
|
|
267
271
|
// Mock the client device to send an old timestamp
|
|
268
272
|
const originalGetHandshake = clientDevice.getHandshake.bind(clientDevice);
|
|
269
|
-
clientDevice.getHandshake =
|
|
273
|
+
clientDevice.getHandshake = (connectionId, serverAddress) => {
|
|
270
274
|
const handshake = originalGetHandshake(connectionId, serverAddress);
|
|
271
275
|
// Make timestamp 2 seconds in the past (beyond tolerance)
|
|
272
276
|
handshake.contents.timestamp = Date.now() - 2000;
|
|
273
277
|
return handshake;
|
|
274
278
|
};
|
|
275
|
-
const result = await clientConnection
|
|
279
|
+
const result = await clientConnection
|
|
280
|
+
.doHandshake("localhost")
|
|
281
|
+
.catch((err) => err.message || err.error || String(err));
|
|
276
282
|
expect(result).toMatch(/Remote device's system clock is too far out of sync/);
|
|
277
283
|
});
|
|
278
284
|
it.todo("should handle RPC calls that return undefined");
|
|
@@ -289,9 +295,9 @@ describe(connection_1.Connection, () => {
|
|
|
289
295
|
// Fix: after openSignedObject succeeds, assert
|
|
290
296
|
// signedHandshake.publicKey === signedHandshake.contents.publicKey
|
|
291
297
|
//
|
|
292
|
-
describe(
|
|
293
|
-
it(
|
|
294
|
-
const serverAddress =
|
|
298
|
+
describe("Security: key confusion — signing key vs claimed identity key", () => {
|
|
299
|
+
it("rejects handshake where signing key (KA) differs from claimed identity key in contents (KV)", async () => {
|
|
300
|
+
const serverAddress = "http://localhost";
|
|
295
301
|
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
296
302
|
const attackerDevice = new device_1.Device();
|
|
297
303
|
const victimDevice = new device_1.Device(); // identity the attacker wants to impersonate
|
|
@@ -307,7 +313,7 @@ describe(connection_1.Connection, () => {
|
|
|
307
313
|
// the attacker can decrypt it to finish the
|
|
308
314
|
// handshake — making the whole flow succeed)
|
|
309
315
|
const originalGetHandshake = attackerDevice.getHandshake.bind(attackerDevice);
|
|
310
|
-
attackerDevice.getHandshake =
|
|
316
|
+
attackerDevice.getHandshake = (connectionId, addr) => {
|
|
311
317
|
const real = originalGetHandshake(connectionId, addr);
|
|
312
318
|
const maliciousContents = {
|
|
313
319
|
...real.contents, // keep connectionId, timestamp, serverAddress
|
|
@@ -325,8 +331,8 @@ describe(connection_1.Connection, () => {
|
|
|
325
331
|
// claimed identity key in the payload contents (KV).
|
|
326
332
|
// Server-side errors travel back through the RPC layer as plain objects
|
|
327
333
|
// { error: '...', errorType: 'RPC_ERROR' } rather than Error instances.
|
|
328
|
-
const result = await attackerConnection.doHandshake(serverAddress).catch(err => err);
|
|
329
|
-
const errorMessage = result instanceof Error ? result.message : result?.error ?? String(result);
|
|
334
|
+
const result = await attackerConnection.doHandshake(serverAddress).catch((err) => err);
|
|
335
|
+
const errorMessage = result instanceof Error ? result.message : (result?.error ?? String(result));
|
|
330
336
|
expect(errorMessage).toMatch(/signing key does not match claimed identity key/i);
|
|
331
337
|
// Neither side should be left in a verified state
|
|
332
338
|
expect(attackerConnection.verified).toBe(false);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { IDeviceConnection, INetworkInfo } from "../types/peer-device";
|
|
1
|
+
import type { IDeviceConnection, INetworkInfo } from "../types/peer-device";
|
|
2
2
|
export interface IElectionData {
|
|
3
3
|
deviceId: string;
|
|
4
4
|
myConnections: IDeviceConnection[];
|
|
5
5
|
allNetworkInfo: INetworkInfo[];
|
|
6
6
|
}
|
|
7
|
-
export declare function electDevices({ deviceId, myConnections, allNetworkInfo
|
|
7
|
+
export declare function electDevices({ deviceId, myConnections, allNetworkInfo }: IElectionData): {
|
|
8
8
|
preferredDeviceIds: string[];
|
|
9
9
|
preferredByDeviceIds: string[];
|
|
10
10
|
};
|
|
@@ -3,19 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.electDevices = electDevices;
|
|
4
4
|
exports.getLeastPreferredConnection = getLeastPreferredConnection;
|
|
5
5
|
const lodash_1 = require("lodash");
|
|
6
|
-
function electDevices({ deviceId, myConnections, allNetworkInfo
|
|
6
|
+
function electDevices({ deviceId, myConnections, allNetworkInfo }) {
|
|
7
7
|
const allDeviceIdsSet = new Set();
|
|
8
8
|
const _preferredByDeviceIdsSet = new Set();
|
|
9
|
-
const allConnectionInfos = allNetworkInfo.map(networkInfo => {
|
|
10
|
-
const deviceIds = [networkInfo.deviceId, ...networkInfo.connections.map(c => c.deviceId)];
|
|
11
|
-
deviceIds.forEach(id =>
|
|
9
|
+
const allConnectionInfos = allNetworkInfo.map((networkInfo) => {
|
|
10
|
+
const deviceIds = [networkInfo.deviceId, ...networkInfo.connections.map((c) => c.deviceId)];
|
|
11
|
+
deviceIds.forEach((id) => {
|
|
12
|
+
allDeviceIdsSet.add(id);
|
|
13
|
+
});
|
|
12
14
|
allDeviceIdsSet.add(networkInfo.deviceId);
|
|
13
15
|
if (networkInfo.preferredDeviceIds.includes(deviceId)) {
|
|
14
16
|
_preferredByDeviceIdsSet.add(networkInfo.deviceId);
|
|
15
17
|
}
|
|
16
|
-
const preferredByDeviceIds = allNetworkInfo
|
|
17
|
-
.
|
|
18
|
-
|
|
18
|
+
const preferredByDeviceIds = allNetworkInfo
|
|
19
|
+
.filter((n) => n.preferredDeviceIds.includes(networkInfo.deviceId))
|
|
20
|
+
.map((n) => n.deviceId);
|
|
21
|
+
const myConnection = myConnections.find((c) => c.deviceId === networkInfo.deviceId);
|
|
19
22
|
return {
|
|
20
23
|
...networkInfo,
|
|
21
24
|
myConnection,
|
|
@@ -25,25 +28,27 @@ function electDevices({ deviceId, myConnections, allNetworkInfo, }) {
|
|
|
25
28
|
});
|
|
26
29
|
allDeviceIdsSet.delete(deviceId);
|
|
27
30
|
const preferredConnections = [];
|
|
28
|
-
let sortedConnections = allConnectionInfos.filter(c => c.myConnection);
|
|
31
|
+
let sortedConnections = allConnectionInfos.filter((c) => c.myConnection);
|
|
29
32
|
while (allDeviceIdsSet.size && sortedConnections.length) {
|
|
30
33
|
// sort connections (best will be first)
|
|
31
34
|
sortedConnections = sortConnections({
|
|
32
35
|
myDeviceId: deviceId,
|
|
33
36
|
connections: sortedConnections,
|
|
34
|
-
unconnectedDeviceIds: allDeviceIdsSet
|
|
37
|
+
unconnectedDeviceIds: allDeviceIdsSet,
|
|
35
38
|
});
|
|
36
39
|
const connection = sortedConnections.shift();
|
|
37
40
|
if (connection) {
|
|
38
41
|
preferredConnections.push(connection.myConnection);
|
|
39
|
-
connection.connectedDeviceIds.forEach(id =>
|
|
42
|
+
connection.connectedDeviceIds.forEach((id) => {
|
|
43
|
+
allDeviceIdsSet.delete(id);
|
|
44
|
+
});
|
|
40
45
|
}
|
|
41
46
|
else {
|
|
42
47
|
break;
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
return {
|
|
46
|
-
preferredDeviceIds: preferredConnections.map(c => c.deviceId),
|
|
51
|
+
preferredDeviceIds: preferredConnections.map((c) => c.deviceId),
|
|
47
52
|
preferredByDeviceIds: Array.from(_preferredByDeviceIdsSet),
|
|
48
53
|
};
|
|
49
54
|
}
|
|
@@ -57,8 +62,8 @@ function electDevices({ deviceId, myConnections, allNetworkInfo, }) {
|
|
|
57
62
|
function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
58
63
|
// sort by latency * error rate (smaller is better)
|
|
59
64
|
connections.sort((a, b) => {
|
|
60
|
-
const aLatency = (a.myConnection
|
|
61
|
-
const bLatency = (b.myConnection
|
|
65
|
+
const aLatency = (a.myConnection?.latencyMs || 1) * (a.myConnection?.errorRate || 0.00001);
|
|
66
|
+
const bLatency = (b.myConnection?.latencyMs || 1) * (b.myConnection?.errorRate || 0.00001);
|
|
62
67
|
return aLatency - bLatency;
|
|
63
68
|
});
|
|
64
69
|
// sort by preferred by other devices count (higher is better)
|
|
@@ -69,8 +74,8 @@ function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
|
69
74
|
});
|
|
70
75
|
// sort by links to new devices - in general, this is most important except for the later edge-cases
|
|
71
76
|
connections.sort((a, b) => {
|
|
72
|
-
const linksToDeviceA = a.connectedDeviceIds.filter(id => unconnectedDeviceIds.has(id)).length;
|
|
73
|
-
const linksToDeviceB = b.connectedDeviceIds.filter(id => unconnectedDeviceIds.has(id)).length;
|
|
77
|
+
const linksToDeviceA = a.connectedDeviceIds.filter((id) => unconnectedDeviceIds.has(id)).length;
|
|
78
|
+
const linksToDeviceB = b.connectedDeviceIds.filter((id) => unconnectedDeviceIds.has(id)).length;
|
|
74
79
|
return linksToDeviceB - linksToDeviceA;
|
|
75
80
|
});
|
|
76
81
|
//=============================================
|
|
@@ -89,8 +94,8 @@ function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
|
89
94
|
// prefer devices that have a connection back to me
|
|
90
95
|
// I think this is an artifact of testing and in the real world this should be a no-op (connections should be bidirectional)
|
|
91
96
|
connections.sort((a, b) => {
|
|
92
|
-
const aHasConn = a.connections.some(c => c.deviceId === myDeviceId);
|
|
93
|
-
const bHasConn = b.connections.some(c => c.deviceId === myDeviceId);
|
|
97
|
+
const aHasConn = a.connections.some((c) => c.deviceId === myDeviceId);
|
|
98
|
+
const bHasConn = b.connections.some((c) => c.deviceId === myDeviceId);
|
|
94
99
|
if (aHasConn && !bHasConn)
|
|
95
100
|
return -1;
|
|
96
101
|
if (!aHasConn && bHasConn)
|
|
@@ -101,14 +106,14 @@ function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
|
101
106
|
}
|
|
102
107
|
function getLeastPreferredConnection({ connections, preferredDeviceIds, preferredByDeviceIds, }) {
|
|
103
108
|
// first consider connections that are not critical to me and I'm not critical to them
|
|
104
|
-
let candidates = connections.filter(c => !(preferredByDeviceIds.includes(c.deviceId) || preferredDeviceIds.includes(c.deviceId)));
|
|
109
|
+
let candidates = connections.filter((c) => !(preferredByDeviceIds.includes(c.deviceId) || preferredDeviceIds.includes(c.deviceId)));
|
|
105
110
|
if (!candidates.length) {
|
|
106
111
|
// if none, next consider connections that are not critical to me
|
|
107
|
-
candidates = connections.filter(c => !preferredDeviceIds.includes(c.deviceId));
|
|
112
|
+
candidates = connections.filter((c) => !preferredDeviceIds.includes(c.deviceId));
|
|
108
113
|
}
|
|
109
114
|
if (!candidates.length) {
|
|
110
115
|
// if none, next consider connections that I am not critical to
|
|
111
|
-
candidates = connections.filter(c => !preferredByDeviceIds.includes(c.deviceId));
|
|
116
|
+
candidates = connections.filter((c) => !preferredByDeviceIds.includes(c.deviceId));
|
|
112
117
|
}
|
|
113
118
|
if (!candidates.length) {
|
|
114
119
|
// if none, then just consider all connections
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const device_election_1 = require("./device-election");
|
|
4
|
-
const utils_1 = require("../utils");
|
|
5
3
|
const lodash_1 = require("lodash");
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const device_election_1 = require("./device-election");
|
|
6
6
|
describe("device-election", () => {
|
|
7
7
|
const createConnection = (deviceId, latencyMs = 10, errorRate = 0.001) => ({
|
|
8
8
|
deviceId,
|
|
@@ -41,9 +41,7 @@ describe("device-election", () => {
|
|
|
41
41
|
createConnection(device2),
|
|
42
42
|
createConnection(device3),
|
|
43
43
|
]);
|
|
44
|
-
const networkInfo2 = createNetworkInfo(device2, [
|
|
45
|
-
createConnection(device1),
|
|
46
|
-
]);
|
|
44
|
+
const networkInfo2 = createNetworkInfo(device2, [createConnection(device1)]);
|
|
47
45
|
const result = (0, device_election_1.electDevices)({
|
|
48
46
|
deviceId: myDeviceId,
|
|
49
47
|
myConnections: [myConnection1, myConnection2],
|
|
@@ -120,9 +118,7 @@ describe("device-election", () => {
|
|
|
120
118
|
createConnection(device4),
|
|
121
119
|
]);
|
|
122
120
|
// device2 only connects to device3
|
|
123
|
-
const networkInfo2 = createNetworkInfo(device2, [
|
|
124
|
-
createConnection(device3),
|
|
125
|
-
]);
|
|
121
|
+
const networkInfo2 = createNetworkInfo(device2, [createConnection(device3)]);
|
|
126
122
|
const result = (0, device_election_1.electDevices)({
|
|
127
123
|
deviceId: myDeviceId,
|
|
128
124
|
myConnections: [myConnection1, myConnection2],
|
|
@@ -170,9 +166,7 @@ describe("device-election", () => {
|
|
|
170
166
|
const myConnection1 = createConnection(device1);
|
|
171
167
|
const myConnection2 = createConnection(device2);
|
|
172
168
|
// device1 has a connection back to me
|
|
173
|
-
const networkInfo1 = createNetworkInfo(device1, [
|
|
174
|
-
createConnection(myDeviceId),
|
|
175
|
-
]);
|
|
169
|
+
const networkInfo1 = createNetworkInfo(device1, [createConnection(myDeviceId)]);
|
|
176
170
|
// device2 doesn't have a connection back to me
|
|
177
171
|
const networkInfo2 = createNetworkInfo(device2, []);
|
|
178
172
|
const result = (0, device_election_1.electDevices)({
|
|
@@ -316,7 +310,7 @@ describe("device-election", () => {
|
|
|
316
310
|
});
|
|
317
311
|
});
|
|
318
312
|
describe("Network simulations", () => {
|
|
319
|
-
it.skip(
|
|
313
|
+
it.skip("should work as connections grow", () => {
|
|
320
314
|
const MAX_CONNECTIONS = 100;
|
|
321
315
|
const groupId = (0, utils_1.newid)();
|
|
322
316
|
const deviceInfos = [];
|
|
@@ -329,10 +323,10 @@ describe("device-election", () => {
|
|
|
329
323
|
};
|
|
330
324
|
deviceInfos.push(newDevice);
|
|
331
325
|
}
|
|
332
|
-
function
|
|
326
|
+
function _removeDevice(d) {
|
|
333
327
|
deviceInfos.splice(deviceInfos.indexOf(d), 1);
|
|
334
|
-
d.connections.forEach(c => {
|
|
335
|
-
const d2 = deviceInfos.find(d2 => d2.deviceId === c.deviceId);
|
|
328
|
+
d.connections.forEach((c) => {
|
|
329
|
+
const d2 = deviceInfos.find((d2) => d2.deviceId === c.deviceId);
|
|
336
330
|
if (d2) {
|
|
337
331
|
disconnectDevices(d, d2);
|
|
338
332
|
}
|
|
@@ -344,7 +338,7 @@ describe("device-election", () => {
|
|
|
344
338
|
return;
|
|
345
339
|
}
|
|
346
340
|
// already connected
|
|
347
|
-
if (d1.connections.some(c => c.deviceId === d2.deviceId)) {
|
|
341
|
+
if (d1.connections.some((c) => c.deviceId === d2.deviceId)) {
|
|
348
342
|
return;
|
|
349
343
|
}
|
|
350
344
|
d1.connections.push({
|
|
@@ -361,15 +355,19 @@ describe("device-election", () => {
|
|
|
361
355
|
});
|
|
362
356
|
}
|
|
363
357
|
function disconnectDevices(d1, d2) {
|
|
364
|
-
d1.connections = d1.connections.filter(c => c.deviceId !== d2.deviceId);
|
|
365
|
-
d2.connections = d2.connections.filter(c => c.deviceId !== d1.deviceId);
|
|
366
|
-
d1.preferredByDeviceIds = d1.preferredByDeviceIds.filter(id => id !== d2.deviceId);
|
|
367
|
-
d2.preferredByDeviceIds = d2.preferredByDeviceIds.filter(id => id !== d1.deviceId);
|
|
368
|
-
d1.preferredDeviceIds = d1.preferredDeviceIds.filter(id => id !== d2.deviceId);
|
|
369
|
-
d2.preferredDeviceIds = d2.preferredDeviceIds.filter(id => id !== d1.deviceId);
|
|
358
|
+
d1.connections = d1.connections.filter((c) => c.deviceId !== d2.deviceId);
|
|
359
|
+
d2.connections = d2.connections.filter((c) => c.deviceId !== d1.deviceId);
|
|
360
|
+
d1.preferredByDeviceIds = d1.preferredByDeviceIds.filter((id) => id !== d2.deviceId);
|
|
361
|
+
d2.preferredByDeviceIds = d2.preferredByDeviceIds.filter((id) => id !== d1.deviceId);
|
|
362
|
+
d1.preferredDeviceIds = d1.preferredDeviceIds.filter((id) => id !== d2.deviceId);
|
|
363
|
+
d2.preferredDeviceIds = d2.preferredDeviceIds.filter((id) => id !== d1.deviceId);
|
|
370
364
|
}
|
|
371
365
|
// pre-populate with devices
|
|
372
|
-
Array(25)
|
|
366
|
+
Array(25)
|
|
367
|
+
.fill(undefined)
|
|
368
|
+
.forEach(() => {
|
|
369
|
+
addDevice();
|
|
370
|
+
});
|
|
373
371
|
const totalTicks = 200;
|
|
374
372
|
for (let tick = 0; tick < totalTicks; tick++) {
|
|
375
373
|
addDevice();
|
|
@@ -381,28 +379,29 @@ describe("device-election", () => {
|
|
|
381
379
|
// }
|
|
382
380
|
// // randomly disconnect
|
|
383
381
|
// if (Math.random() < 0.1) {
|
|
384
|
-
// const disconnect =
|
|
385
|
-
// disconnectDevices()
|
|
382
|
+
// const disconnect =
|
|
383
|
+
// disconnectDevices()
|
|
386
384
|
// }
|
|
387
385
|
// simulate a device wanting to maintain a "well connected" network
|
|
388
386
|
while (device.connections.length < 25) {
|
|
389
|
-
const otherPreferredIds = device.connections.
|
|
390
|
-
const newDeviceId = otherPreferredIds.find(deviceId => !device.connections.some(c => c.deviceId
|
|
391
|
-
|
|
387
|
+
const otherPreferredIds = device.connections.flatMap((c) => deviceInfos.find((d) => d.deviceId === c.deviceId)?.preferredDeviceIds ?? []);
|
|
388
|
+
const newDeviceId = otherPreferredIds.find((deviceId) => !device.connections.some((c) => c.deviceId === deviceId) &&
|
|
389
|
+
deviceId !== device.deviceId);
|
|
390
|
+
const newDevice = deviceInfos.find((d) => d.deviceId === newDeviceId);
|
|
392
391
|
if (newDevice) {
|
|
393
392
|
connectDevices(device, newDevice);
|
|
394
393
|
}
|
|
395
394
|
else {
|
|
396
|
-
const unconnectedDevices = deviceInfos.filter(d => !device.connections.some(c => c.deviceId === d.deviceId));
|
|
395
|
+
const unconnectedDevices = deviceInfos.filter((d) => !device.connections.some((c) => c.deviceId === d.deviceId));
|
|
397
396
|
connectDevices(device, (0, lodash_1.shuffle)(unconnectedDevices)[0]);
|
|
398
397
|
}
|
|
399
398
|
}
|
|
400
399
|
// do elections
|
|
401
|
-
const networkInfo = device.connections.map(c => {
|
|
402
|
-
const remoteDevice = deviceInfos.find(d => d.deviceId === c.deviceId);
|
|
400
|
+
const networkInfo = device.connections.map((c) => {
|
|
401
|
+
const remoteDevice = deviceInfos.find((d) => d.deviceId === c.deviceId);
|
|
403
402
|
return {
|
|
404
403
|
deviceId: remoteDevice.deviceId,
|
|
405
|
-
connections: [...remoteDevice
|
|
404
|
+
connections: [...remoteDevice.connections],
|
|
406
405
|
connectionSlotsAvailable: MAX_CONNECTIONS - remoteDevice.connections.length,
|
|
407
406
|
cpuPercent: 0.1,
|
|
408
407
|
memPercent: 0.2,
|
|
@@ -413,23 +412,23 @@ describe("device-election", () => {
|
|
|
413
412
|
const result = (0, device_election_1.electDevices)({
|
|
414
413
|
deviceId: device.deviceId,
|
|
415
414
|
myConnections: [...device.connections],
|
|
416
|
-
allNetworkInfo: networkInfo
|
|
415
|
+
allNetworkInfo: networkInfo,
|
|
417
416
|
});
|
|
418
417
|
device.preferredDeviceIds = result.preferredDeviceIds;
|
|
419
418
|
device.preferredByDeviceIds = result.preferredByDeviceIds;
|
|
420
419
|
// now that we've done elections, remove connections if we have too many (note this is slightly unrealistic as this usually happens before elections in the real code)
|
|
421
420
|
while (device.connections.length >= MAX_CONNECTIONS) {
|
|
422
421
|
const removeConn = (0, device_election_1.getLeastPreferredConnection)({
|
|
423
|
-
connections: device.connections.map(c => ({ ...c, groups: [groupId] })),
|
|
422
|
+
connections: device.connections.map((c) => ({ ...c, groups: [groupId] })),
|
|
424
423
|
preferredDeviceIds: [...device.preferredDeviceIds],
|
|
425
424
|
preferredByDeviceIds: [...device.preferredByDeviceIds],
|
|
426
425
|
});
|
|
427
|
-
const disconnectDevice = deviceInfos.find(d => d.deviceId === removeConn?.deviceId);
|
|
426
|
+
const disconnectDevice = deviceInfos.find((d) => d.deviceId === removeConn?.deviceId);
|
|
428
427
|
disconnectDevices(device, disconnectDevice);
|
|
429
428
|
}
|
|
430
429
|
}
|
|
431
430
|
}
|
|
432
|
-
const output = (0, lodash_1.sortBy)(deviceInfos, d => -d.preferredByDeviceIds.length).map(d => {
|
|
431
|
+
const output = (0, lodash_1.sortBy)(deviceInfos, (d) => -d.preferredByDeviceIds.length).map((d) => {
|
|
433
432
|
return {
|
|
434
433
|
preferredBy: d.preferredByDeviceIds.length,
|
|
435
434
|
preferred: d.preferredDeviceIds.length,
|
package/dist/device/device.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { IDeviceHandshake, IDeviceInfo } from "../data";
|
|
2
|
+
import { type IDataBox, type ISignedObject } from "../keys";
|
|
3
3
|
export declare class Device implements IDeviceInfo {
|
|
4
4
|
readonly userId: string;
|
|
5
5
|
readonly deviceId: string;
|