@peers-app/peers-sdk 0.1.4
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/README.md +1 -0
- package/dist/context/data-context.d.ts +31 -0
- package/dist/context/data-context.js +56 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.js +19 -0
- package/dist/context/user-context-singleton.d.ts +11 -0
- package/dist/context/user-context-singleton.js +121 -0
- package/dist/context/user-context.d.ts +55 -0
- package/dist/context/user-context.js +205 -0
- package/dist/data/assistants.d.ts +68 -0
- package/dist/data/assistants.js +64 -0
- package/dist/data/change-tracking.d.ts +219 -0
- package/dist/data/change-tracking.js +119 -0
- package/dist/data/channels.d.ts +29 -0
- package/dist/data/channels.js +25 -0
- package/dist/data/data-locks.d.ts +37 -0
- package/dist/data/data-locks.js +180 -0
- package/dist/data/data-locks.test.d.ts +1 -0
- package/dist/data/data-locks.test.js +456 -0
- package/dist/data/device-sync-info.d.ts +19 -0
- package/dist/data/device-sync-info.js +24 -0
- package/dist/data/devices.d.ts +51 -0
- package/dist/data/devices.js +36 -0
- package/dist/data/embeddings.d.ts +47 -0
- package/dist/data/embeddings.js +36 -0
- package/dist/data/files/file-read-stream.d.ts +27 -0
- package/dist/data/files/file-read-stream.js +195 -0
- package/dist/data/files/file-write-stream.d.ts +20 -0
- package/dist/data/files/file-write-stream.js +113 -0
- package/dist/data/files/file.types.d.ts +47 -0
- package/dist/data/files/file.types.js +55 -0
- package/dist/data/files/files.d.ts +28 -0
- package/dist/data/files/files.js +127 -0
- package/dist/data/files/files.test.d.ts +1 -0
- package/dist/data/files/files.test.js +728 -0
- package/dist/data/files/index.d.ts +4 -0
- package/dist/data/files/index.js +23 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +25 -0
- package/dist/data/group-members.d.ts +39 -0
- package/dist/data/group-members.js +68 -0
- package/dist/data/group-members.test.d.ts +1 -0
- package/dist/data/group-members.test.js +287 -0
- package/dist/data/group-permissions.d.ts +8 -0
- package/dist/data/group-permissions.js +73 -0
- package/dist/data/group-share.d.ts +50 -0
- package/dist/data/group-share.js +196 -0
- package/dist/data/groups.d.ts +50 -0
- package/dist/data/groups.js +73 -0
- package/dist/data/groups.test.d.ts +1 -0
- package/dist/data/groups.test.js +153 -0
- package/dist/data/index.d.ts +31 -0
- package/dist/data/index.js +47 -0
- package/dist/data/knowledge/knowledge-frames.d.ts +34 -0
- package/dist/data/knowledge/knowledge-frames.js +34 -0
- package/dist/data/knowledge/knowledge-links.d.ts +30 -0
- package/dist/data/knowledge/knowledge-links.js +25 -0
- package/dist/data/knowledge/knowledge-values.d.ts +35 -0
- package/dist/data/knowledge/knowledge-values.js +35 -0
- package/dist/data/knowledge/peer-types.d.ts +112 -0
- package/dist/data/knowledge/peer-types.js +27 -0
- package/dist/data/knowledge/predicates.d.ts +34 -0
- package/dist/data/knowledge/predicates.js +27 -0
- package/dist/data/messages.d.ts +57 -0
- package/dist/data/messages.js +97 -0
- package/dist/data/orm/client-proxy.data-source.d.ts +27 -0
- package/dist/data/orm/client-proxy.data-source.js +65 -0
- package/dist/data/orm/cursor.d.ts +25 -0
- package/dist/data/orm/cursor.js +47 -0
- package/dist/data/orm/cursor.test.d.ts +1 -0
- package/dist/data/orm/cursor.test.js +315 -0
- package/dist/data/orm/data-query.d.ts +96 -0
- package/dist/data/orm/data-query.js +208 -0
- package/dist/data/orm/data-query.mongo.d.ts +17 -0
- package/dist/data/orm/data-query.mongo.js +267 -0
- package/dist/data/orm/data-query.mongo.test.d.ts +1 -0
- package/dist/data/orm/data-query.mongo.test.js +398 -0
- package/dist/data/orm/data-query.sqlite.d.ts +14 -0
- package/dist/data/orm/data-query.sqlite.js +297 -0
- package/dist/data/orm/data-query.sqlite.test.d.ts +1 -0
- package/dist/data/orm/data-query.sqlite.test.js +377 -0
- package/dist/data/orm/data-query.test.d.ts +1 -0
- package/dist/data/orm/data-query.test.js +553 -0
- package/dist/data/orm/decorators.d.ts +6 -0
- package/dist/data/orm/decorators.js +21 -0
- package/dist/data/orm/dependency-injection.test.d.ts +1 -0
- package/dist/data/orm/dependency-injection.test.js +171 -0
- package/dist/data/orm/doc.d.ts +26 -0
- package/dist/data/orm/doc.js +124 -0
- package/dist/data/orm/event-registry.d.ts +24 -0
- package/dist/data/orm/event-registry.js +40 -0
- package/dist/data/orm/event-registry.test.d.ts +1 -0
- package/dist/data/orm/event-registry.test.js +44 -0
- package/dist/data/orm/factory.d.ts +8 -0
- package/dist/data/orm/factory.js +147 -0
- package/dist/data/orm/index.d.ts +16 -0
- package/dist/data/orm/index.js +32 -0
- package/dist/data/orm/multi-cursors.d.ts +11 -0
- package/dist/data/orm/multi-cursors.js +146 -0
- package/dist/data/orm/multi-cursors.test.d.ts +1 -0
- package/dist/data/orm/multi-cursors.test.js +455 -0
- package/dist/data/orm/sql-db.d.ts +6 -0
- package/dist/data/orm/sql-db.js +2 -0
- package/dist/data/orm/sql.data-source.d.ts +38 -0
- package/dist/data/orm/sql.data-source.js +379 -0
- package/dist/data/orm/sql.data-source.test.d.ts +1 -0
- package/dist/data/orm/sql.data-source.test.js +406 -0
- package/dist/data/orm/subscribable.data-source.d.ts +25 -0
- package/dist/data/orm/subscribable.data-source.js +72 -0
- package/dist/data/orm/table-container-events.test.d.ts +1 -0
- package/dist/data/orm/table-container-events.test.js +93 -0
- package/dist/data/orm/table-container.d.ts +39 -0
- package/dist/data/orm/table-container.js +96 -0
- package/dist/data/orm/table-definitions.system.d.ts +9 -0
- package/dist/data/orm/table-definitions.system.js +29 -0
- package/dist/data/orm/table-definitions.type.d.ts +19 -0
- package/dist/data/orm/table-definitions.type.js +2 -0
- package/dist/data/orm/table-dependencies.d.ts +32 -0
- package/dist/data/orm/table-dependencies.js +2 -0
- package/dist/data/orm/table.d.ts +42 -0
- package/dist/data/orm/table.event-source.test.d.ts +1 -0
- package/dist/data/orm/table.event-source.test.js +341 -0
- package/dist/data/orm/table.js +244 -0
- package/dist/data/orm/types.d.ts +20 -0
- package/dist/data/orm/types.js +115 -0
- package/dist/data/orm/types.test.d.ts +1 -0
- package/dist/data/orm/types.test.js +71 -0
- package/dist/data/package-permissions.d.ts +7 -0
- package/dist/data/package-permissions.js +18 -0
- package/dist/data/packages.d.ts +92 -0
- package/dist/data/packages.js +90 -0
- package/dist/data/peer-events/peer-event-handlers.d.ts +21 -0
- package/dist/data/peer-events/peer-event-handlers.js +28 -0
- package/dist/data/peer-events/peer-event-types.d.ts +119 -0
- package/dist/data/peer-events/peer-event-types.js +29 -0
- package/dist/data/peer-events/peer-events.d.ts +41 -0
- package/dist/data/peer-events/peer-events.js +102 -0
- package/dist/data/persistent-vars.d.ts +87 -0
- package/dist/data/persistent-vars.js +230 -0
- package/dist/data/tool-tests.d.ts +37 -0
- package/dist/data/tool-tests.js +27 -0
- package/dist/data/tools.d.ts +358 -0
- package/dist/data/tools.js +48 -0
- package/dist/data/user-permissions.d.ts +15 -0
- package/dist/data/user-permissions.js +39 -0
- package/dist/data/user-permissions.test.d.ts +1 -0
- package/dist/data/user-permissions.test.js +252 -0
- package/dist/data/users.d.ts +38 -0
- package/dist/data/users.js +73 -0
- package/dist/data/workflow-logs.d.ts +106 -0
- package/dist/data/workflow-logs.js +67 -0
- package/dist/data/workflow-runs.d.ts +103 -0
- package/dist/data/workflow-runs.js +313 -0
- package/dist/data/workflows.d.ts +16 -0
- package/dist/data/workflows.js +21 -0
- package/dist/device/connection.d.ts +41 -0
- package/dist/device/connection.js +249 -0
- package/dist/device/connection.test.d.ts +1 -0
- package/dist/device/connection.test.js +292 -0
- package/dist/device/device-election.d.ts +36 -0
- package/dist/device/device-election.js +137 -0
- package/dist/device/device.d.ts +22 -0
- package/dist/device/device.js +110 -0
- package/dist/device/device.test.d.ts +1 -0
- package/dist/device/device.test.js +203 -0
- package/dist/device/get-trust-level.d.ts +3 -0
- package/dist/device/get-trust-level.js +87 -0
- package/dist/device/socket.type.d.ts +20 -0
- package/dist/device/socket.type.js +15 -0
- package/dist/device/streamed-socket.d.ts +27 -0
- package/dist/device/streamed-socket.js +154 -0
- package/dist/device/streamed-socket.test.d.ts +1 -0
- package/dist/device/streamed-socket.test.js +44 -0
- package/dist/events.d.ts +35 -0
- package/dist/events.js +128 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +50 -0
- package/dist/keys.d.ts +51 -0
- package/dist/keys.js +234 -0
- package/dist/keys.test.d.ts +1 -0
- package/dist/keys.test.js +215 -0
- package/dist/mentions.d.ts +9 -0
- package/dist/mentions.js +46 -0
- package/dist/observable.d.ts +19 -0
- package/dist/observable.js +112 -0
- package/dist/observable.test.d.ts +1 -0
- package/dist/observable.test.js +183 -0
- package/dist/package-loader/get-require.d.ts +10 -0
- package/dist/package-loader/get-require.js +31 -0
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +17 -0
- package/dist/package-loader/package-loader.d.ts +16 -0
- package/dist/package-loader/package-loader.js +102 -0
- package/dist/peers-ui/peers-ui.d.ts +15 -0
- package/dist/peers-ui/peers-ui.js +23 -0
- package/dist/peers-ui/peers-ui.types.d.ts +35 -0
- package/dist/peers-ui/peers-ui.types.js +3 -0
- package/dist/rpc-types.d.ts +45 -0
- package/dist/rpc-types.js +47 -0
- package/dist/serial-json.d.ts +5 -0
- package/dist/serial-json.js +186 -0
- package/dist/serial-json.test.d.ts +1 -0
- package/dist/serial-json.test.js +86 -0
- package/dist/system-ids.d.ts +6 -0
- package/dist/system-ids.js +10 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/tools-factory.d.ts +5 -0
- package/dist/tools/tools-factory.js +34 -0
- package/dist/types/app-nav.d.ts +18 -0
- package/dist/types/app-nav.js +10 -0
- package/dist/types/assistant-runner-args.d.ts +9 -0
- package/dist/types/assistant-runner-args.js +2 -0
- package/dist/types/field-type.d.ts +37 -0
- package/dist/types/field-type.js +26 -0
- package/dist/types/peer-device.d.ts +40 -0
- package/dist/types/peer-device.js +14 -0
- package/dist/types/peers-package.d.ts +23 -0
- package/dist/types/peers-package.js +2 -0
- package/dist/types/workflow-logger.d.ts +2 -0
- package/dist/types/workflow-logger.js +2 -0
- package/dist/types/workflow-run-context.d.ts +12 -0
- package/dist/types/workflow-run-context.js +2 -0
- package/dist/types/workflow.d.ts +72 -0
- package/dist/types/workflow.js +24 -0
- package/dist/types/zod-types.d.ts +7 -0
- package/dist/types/zod-types.js +12 -0
- package/dist/users.query.d.ts +13 -0
- package/dist/users.query.js +134 -0
- package/dist/utils.d.ts +39 -0
- package/dist/utils.js +240 -0
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +140 -0
- package/package.json +50 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const keys_1 = require("../keys");
|
|
5
|
+
const connection_1 = require("./connection");
|
|
6
|
+
const device_1 = require("./device");
|
|
7
|
+
function createTestSocket(localHandlers, remoteHandlers) {
|
|
8
|
+
const socket = {
|
|
9
|
+
id: (0, utils_1.newid)(),
|
|
10
|
+
emit(eventName, args, callback) {
|
|
11
|
+
remoteHandlers.forEach(async ({ eventName: _eventName, handler }) => {
|
|
12
|
+
if (eventName === _eventName) {
|
|
13
|
+
handler(args, callback);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
on(eventName, handler) {
|
|
18
|
+
localHandlers.push({
|
|
19
|
+
eventName,
|
|
20
|
+
handler: async (...args) => handler(...args)
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
removeAllListeners(eventName) {
|
|
24
|
+
while (localHandlers.find(({ eventName: _eventName }) => eventName === _eventName)) {
|
|
25
|
+
const index = localHandlers.findIndex(({ eventName: _eventName }) => eventName === _eventName);
|
|
26
|
+
localHandlers.splice(index, 1);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
disconnect() {
|
|
30
|
+
// Simulate disconnection logic if needed
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return socket;
|
|
34
|
+
}
|
|
35
|
+
function createTestSocketPair() {
|
|
36
|
+
const clientHandlers = [];
|
|
37
|
+
const serverHandlers = [];
|
|
38
|
+
const clientSocket = createTestSocket(clientHandlers, serverHandlers);
|
|
39
|
+
const serverSocket = createTestSocket(serverHandlers, clientHandlers);
|
|
40
|
+
const connectionId = (0, utils_1.newid)();
|
|
41
|
+
clientSocket.id = connectionId;
|
|
42
|
+
serverSocket.id = connectionId;
|
|
43
|
+
return {
|
|
44
|
+
clientSocket,
|
|
45
|
+
serverSocket,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
describe(connection_1.Connection, () => {
|
|
49
|
+
it("should allow simulating a client and server connection handshake", async () => {
|
|
50
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
51
|
+
const clientDevice = new device_1.Device();
|
|
52
|
+
const serverDevice = new device_1.Device();
|
|
53
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
54
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['localhost']);
|
|
55
|
+
expect(clientConnection.connectionId).toBe(serverConnection.connectionId);
|
|
56
|
+
const response = await clientConnection.doHandshake('localhost');
|
|
57
|
+
expect(response.userId).toBe(serverDevice.userId);
|
|
58
|
+
expect(response.deviceId).toBe(serverDevice.deviceId);
|
|
59
|
+
expect(response.publicKey).toBe(serverDevice.publicKey);
|
|
60
|
+
expect(response.publicBoxKey).toBe(serverDevice.publicBoxKey);
|
|
61
|
+
expect(response.serverAddress).toBe('localhost');
|
|
62
|
+
expect(response.connectionId).toBe(serverConnection.connectionId);
|
|
63
|
+
serverConnection.exposeRPC('ping', async (n, s) => `pong - ${n}, ${s}`);
|
|
64
|
+
const pong = await clientConnection.emit('ping', 1, "hello");
|
|
65
|
+
expect(pong).toBe('pong - 1, hello');
|
|
66
|
+
});
|
|
67
|
+
it("should create a new id if socket doesn't have one", async () => {
|
|
68
|
+
const socket = {
|
|
69
|
+
id: (0, utils_1.newid)(),
|
|
70
|
+
emit(eventName, args, callback) {
|
|
71
|
+
// do nothing
|
|
72
|
+
},
|
|
73
|
+
on(eventName, handler) {
|
|
74
|
+
// do nothing
|
|
75
|
+
},
|
|
76
|
+
removeAllListeners(eventName) {
|
|
77
|
+
// do nothing
|
|
78
|
+
},
|
|
79
|
+
disconnect() {
|
|
80
|
+
// do nothing
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const connection = new connection_1.Connection(socket, new device_1.Device());
|
|
84
|
+
expect(connection.connectionId).toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
it("client should requestSecure if both are using https", async () => {
|
|
87
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
88
|
+
const clientDevice = new device_1.Device();
|
|
89
|
+
const serverDevice = new device_1.Device();
|
|
90
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
91
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['https://localhost']);
|
|
92
|
+
await clientConnection.doHandshake('https://localhost');
|
|
93
|
+
expect(clientConnection.secure).toBe(true);
|
|
94
|
+
// and allow forcing insecure
|
|
95
|
+
clientConnection.forceInsecure = true;
|
|
96
|
+
expect(clientConnection.secure).toBe(false);
|
|
97
|
+
// and only return a copy of the remoteDeviceInfo
|
|
98
|
+
expect(clientConnection.remoteDeviceInfo).not.toBe(clientConnection.remoteDeviceInfo);
|
|
99
|
+
});
|
|
100
|
+
it("should gracefully handle remote errors for secure connections", async () => {
|
|
101
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
102
|
+
const clientDevice = new device_1.Device();
|
|
103
|
+
const serverDevice = new device_1.Device();
|
|
104
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
105
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['https://localhost']);
|
|
106
|
+
await clientConnection.doHandshake('https://localhost');
|
|
107
|
+
// for secure connections
|
|
108
|
+
expect(clientConnection.secure).toBe(true);
|
|
109
|
+
expect(serverConnection.secure).toBe(true);
|
|
110
|
+
serverConnection.exposeRPC('ping', async () => { throw new Error("fake error"); });
|
|
111
|
+
const response = await clientConnection.emit('ping').catch((err) => err);
|
|
112
|
+
expect(response).toEqual({
|
|
113
|
+
errorType: "RPC_ERROR",
|
|
114
|
+
error: "fake error",
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
it("should gracefully handle remote errors for unsecure connections", async () => {
|
|
118
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
119
|
+
const clientDevice = new device_1.Device();
|
|
120
|
+
const serverDevice = new device_1.Device();
|
|
121
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
122
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['http://localhost']);
|
|
123
|
+
await clientConnection.doHandshake('http://localhost');
|
|
124
|
+
// for secure connections
|
|
125
|
+
expect(clientConnection.secure).toBe(false);
|
|
126
|
+
expect(serverConnection.secure).toBe(false);
|
|
127
|
+
serverConnection.exposeRPC('ping', async () => { throw new Error("fake error"); });
|
|
128
|
+
const response = await clientConnection.emit('ping').catch((err) => err);
|
|
129
|
+
expect(response).toEqual({
|
|
130
|
+
errorType: "RPC_ERROR",
|
|
131
|
+
error: "fake error",
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
it("should ignore other events before the handshake is finished", async () => {
|
|
135
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
136
|
+
const clientDevice = new device_1.Device();
|
|
137
|
+
const serverDevice = new device_1.Device();
|
|
138
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
139
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['https://localhost']);
|
|
140
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
141
|
+
expect(serverConnection.verified).toBe(false);
|
|
142
|
+
expect(clientConnection.verified).toBe(false);
|
|
143
|
+
const response = await clientConnection.emit('ping').catch((err) => err);
|
|
144
|
+
expect(response).toMatch(/Connection not verified/);
|
|
145
|
+
});
|
|
146
|
+
it("client should detect different connection ids during handshake", async () => {
|
|
147
|
+
const serverAddress = 'http://localhost';
|
|
148
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
149
|
+
const clientDevice = new device_1.Device();
|
|
150
|
+
const serverDevice = new device_1.Device();
|
|
151
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
152
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
153
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
154
|
+
serverConnection.socket.removeAllListeners('completeHandshake');
|
|
155
|
+
serverConnection.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
156
|
+
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
157
|
+
handshake.connectionId = 'fake';
|
|
158
|
+
return handshake;
|
|
159
|
+
});
|
|
160
|
+
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
161
|
+
expect(result).toMatch(/Invalid connectionId/);
|
|
162
|
+
});
|
|
163
|
+
it("client should detect different device ids during handshake", async () => {
|
|
164
|
+
const serverAddress = 'http://localhost';
|
|
165
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
166
|
+
const clientDevice = new device_1.Device();
|
|
167
|
+
const serverDevice = new device_1.Device();
|
|
168
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
169
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
170
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
171
|
+
serverConnection.socket.removeAllListeners('completeHandshake');
|
|
172
|
+
serverConnection.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
173
|
+
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
174
|
+
handshake.deviceId = 'fake';
|
|
175
|
+
return handshake;
|
|
176
|
+
});
|
|
177
|
+
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
178
|
+
expect(result).toMatch(/Inconsistent device info/);
|
|
179
|
+
});
|
|
180
|
+
it("client should detect different device ids during handshake", async () => {
|
|
181
|
+
const serverAddress = 'http://localhost';
|
|
182
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
183
|
+
const clientDevice = new device_1.Device();
|
|
184
|
+
const serverDevice = new device_1.Device();
|
|
185
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
186
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
187
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
188
|
+
serverConnection.socket.removeAllListeners('completeHandshake');
|
|
189
|
+
serverConnection.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
190
|
+
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
191
|
+
handshake.userId = 'fake';
|
|
192
|
+
return handshake;
|
|
193
|
+
});
|
|
194
|
+
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
195
|
+
expect(result).toMatch(/Inconsistent device info/);
|
|
196
|
+
});
|
|
197
|
+
it("client should detect different box key during handshake", async () => {
|
|
198
|
+
const serverAddress = 'http://localhost';
|
|
199
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
200
|
+
const clientDevice = new device_1.Device();
|
|
201
|
+
const serverDevice = new device_1.Device();
|
|
202
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
203
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
204
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
205
|
+
serverConnection.socket.removeAllListeners('completeHandshake');
|
|
206
|
+
serverConnection.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
207
|
+
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
208
|
+
const _keys = (0, keys_1.newKeys)();
|
|
209
|
+
handshake.publicBoxKey = _keys.publicBoxKey;
|
|
210
|
+
return handshake;
|
|
211
|
+
});
|
|
212
|
+
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
213
|
+
expect(result).toMatch(/Inconsistent public keys/);
|
|
214
|
+
});
|
|
215
|
+
it("client should detect different public key during handshake", async () => {
|
|
216
|
+
const serverAddress = 'http://localhost';
|
|
217
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
218
|
+
const clientDevice = new device_1.Device();
|
|
219
|
+
const serverDevice = new device_1.Device();
|
|
220
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
221
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, [serverAddress]);
|
|
222
|
+
serverConnection.exposeRPC('ping', async () => 'pong');
|
|
223
|
+
serverConnection.socket.removeAllListeners('completeHandshake');
|
|
224
|
+
serverConnection.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
225
|
+
const handshake = await serverConnection.completeHandshake(handshakeBox);
|
|
226
|
+
const _keys = (0, keys_1.newKeys)();
|
|
227
|
+
handshake.publicKey = _keys.publicKey;
|
|
228
|
+
return handshake;
|
|
229
|
+
});
|
|
230
|
+
const result = await clientConnection.doHandshake(serverAddress).catch((err) => String(err));
|
|
231
|
+
expect(result).toMatch(/Inconsistent public keys/);
|
|
232
|
+
});
|
|
233
|
+
it("should handle RPC calls with large arguments through chunking", async () => {
|
|
234
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
235
|
+
const clientDevice = new device_1.Device();
|
|
236
|
+
const serverDevice = new device_1.Device();
|
|
237
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
238
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['localhost']);
|
|
239
|
+
clientConnection.maxChunkSize = 50;
|
|
240
|
+
serverConnection.maxChunkSize = 50;
|
|
241
|
+
clientConnection.socket.maxChunkSize = 50;
|
|
242
|
+
serverConnection.socket.maxChunkSize = 50;
|
|
243
|
+
await clientConnection.doHandshake('localhost');
|
|
244
|
+
const clientEmitSpy = jest.spyOn(clientConnection.socket.socket, 'emit');
|
|
245
|
+
const serverEmitSpy = jest.spyOn(serverConnection.socket.socket, 'emit');
|
|
246
|
+
// Create large data that will definitely need chunking
|
|
247
|
+
const largeData = {
|
|
248
|
+
message: "A".repeat(500), // 500 characters
|
|
249
|
+
metadata: "B".repeat(300), // 300 characters
|
|
250
|
+
payload: "C".repeat(400) // 400 characters
|
|
251
|
+
};
|
|
252
|
+
serverConnection.exposeRPC('processLargeData', async (data) => {
|
|
253
|
+
return {
|
|
254
|
+
received: data,
|
|
255
|
+
processedSize: JSON.stringify(data).length
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
const result = await clientConnection.emit('processLargeData', largeData);
|
|
259
|
+
expect(result.received.message).toBe("A".repeat(500));
|
|
260
|
+
expect(result.received.metadata).toBe("B".repeat(300));
|
|
261
|
+
expect(result.received.payload).toBe("C".repeat(400));
|
|
262
|
+
expect(result.processedSize).toBeGreaterThan(1000); // Should be large
|
|
263
|
+
// Count chunk emissions
|
|
264
|
+
const clientChunkCalls = clientEmitSpy.mock.calls.filter((call) => call[0] === clientConnection.socket.safeSocketChunkEventName);
|
|
265
|
+
const serverChunkCalls = serverEmitSpy.mock.calls.filter((call) => call[0] === serverConnection.socket.safeSocketChunkEventName);
|
|
266
|
+
// The data gets wrapped by Connection layer (encryption/signing), making it larger
|
|
267
|
+
// 41 chunks at 50 bytes each = ~2050 bytes (41 * 50)
|
|
268
|
+
// 43 chunks at 50 bytes each = ~2150 bytes (43 * 50)
|
|
269
|
+
expect(clientChunkCalls.length).toBe(41); // ~2050 bytes wrapped data / 50 bytes per chunk
|
|
270
|
+
expect(serverChunkCalls.length).toBe(43); // ~2150 bytes wrapped data / 50 bytes per chunk
|
|
271
|
+
});
|
|
272
|
+
it("should reject handshake if device timestamps are too far apart", async () => {
|
|
273
|
+
const { clientSocket, serverSocket } = createTestSocketPair();
|
|
274
|
+
const clientDevice = new device_1.Device();
|
|
275
|
+
const serverDevice = new device_1.Device();
|
|
276
|
+
const clientConnection = new connection_1.Connection(clientSocket, clientDevice);
|
|
277
|
+
const serverConnection = new connection_1.Connection(serverSocket, serverDevice, ['localhost']);
|
|
278
|
+
// Set a very strict timestamp tolerance (1 second) to make test reliable
|
|
279
|
+
serverConnection.handshakeTimestampToleranceMs = 1000;
|
|
280
|
+
// Mock the client device to send an old timestamp
|
|
281
|
+
const originalGetHandshake = clientDevice.getHandshake.bind(clientDevice);
|
|
282
|
+
clientDevice.getHandshake = function (connectionId, serverAddress) {
|
|
283
|
+
const handshake = originalGetHandshake(connectionId, serverAddress);
|
|
284
|
+
// Make timestamp 2 seconds in the past (beyond tolerance)
|
|
285
|
+
handshake.contents.timestamp = Date.now() - 2000;
|
|
286
|
+
return handshake;
|
|
287
|
+
};
|
|
288
|
+
const result = await clientConnection.doHandshake('localhost').catch((err) => err.message || err.error || String(err));
|
|
289
|
+
expect(result).toMatch(/Remote device's system clock is too far out of sync/);
|
|
290
|
+
});
|
|
291
|
+
it.todo("should handle RPC calls that return undefined");
|
|
292
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IDeviceConnection, INetworkInfo } from "../types/peer-device";
|
|
2
|
+
export interface IElectionData {
|
|
3
|
+
deviceId: string;
|
|
4
|
+
myConnections: IDeviceConnection[];
|
|
5
|
+
allNetworkInfo: INetworkInfo[];
|
|
6
|
+
}
|
|
7
|
+
export declare function electDevices({ deviceId, myConnections, allNetworkInfo, }: IElectionData): {
|
|
8
|
+
preferredDeviceIds: string[];
|
|
9
|
+
preferredByDeviceIds: string[];
|
|
10
|
+
};
|
|
11
|
+
export interface ISortableConnection extends INetworkInfo {
|
|
12
|
+
connectedDeviceIds: string[];
|
|
13
|
+
preferredByDeviceIds: string[];
|
|
14
|
+
myConnection: IDeviceConnection | undefined;
|
|
15
|
+
}
|
|
16
|
+
export interface ISortConnectionsArgs {
|
|
17
|
+
myDeviceId: string;
|
|
18
|
+
unconnectedDeviceIds: Set<string>;
|
|
19
|
+
connections: ISortableConnection[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sort connections from most preferred to least preferred
|
|
23
|
+
* The most preferred connections are ones that link us to the most new devices
|
|
24
|
+
* (i.e. not already connected to by other preferred connections).
|
|
25
|
+
* Ties go to connections that are most preferred by other devices.
|
|
26
|
+
* Further ties go to connections with the lowest latency * error rate
|
|
27
|
+
*/
|
|
28
|
+
export declare function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }: ISortConnectionsArgs): ISortableConnection[];
|
|
29
|
+
export interface IGetLeastPreferredConnectionArgs {
|
|
30
|
+
connections: (IDeviceConnection & {
|
|
31
|
+
groups: string[];
|
|
32
|
+
})[];
|
|
33
|
+
preferredDeviceIds: string[];
|
|
34
|
+
preferredByDeviceIds: string[];
|
|
35
|
+
}
|
|
36
|
+
export declare function getLeastPreferredConnection({ connections, preferredDeviceIds, preferredByDeviceIds, }: IGetLeastPreferredConnectionArgs): IDeviceConnection | undefined;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.electDevices = electDevices;
|
|
4
|
+
exports.sortConnections = sortConnections;
|
|
5
|
+
exports.getLeastPreferredConnection = getLeastPreferredConnection;
|
|
6
|
+
const lodash_1 = require("lodash");
|
|
7
|
+
const peer_device_1 = require("../types/peer-device");
|
|
8
|
+
function electDevices({ deviceId, myConnections, allNetworkInfo, }) {
|
|
9
|
+
const allDeviceIdsSet = new Set();
|
|
10
|
+
const _preferredByDeviceIdsSet = new Set();
|
|
11
|
+
const allConnectionInfos = allNetworkInfo.map(networkInfo => {
|
|
12
|
+
const deviceIds = [networkInfo.deviceId, ...networkInfo.connections.map(c => c.deviceId)];
|
|
13
|
+
deviceIds.forEach(id => allDeviceIdsSet.add(id));
|
|
14
|
+
allDeviceIdsSet.add(networkInfo.deviceId);
|
|
15
|
+
if (networkInfo.preferredDeviceIds.includes(deviceId)) {
|
|
16
|
+
_preferredByDeviceIdsSet.add(networkInfo.deviceId);
|
|
17
|
+
}
|
|
18
|
+
const preferredByDeviceIds = allNetworkInfo.filter(n => n.preferredDeviceIds.includes(networkInfo.deviceId))
|
|
19
|
+
.map(n => n.deviceId);
|
|
20
|
+
const myConnection = myConnections.find(c => c.deviceId === networkInfo.deviceId);
|
|
21
|
+
return {
|
|
22
|
+
...networkInfo,
|
|
23
|
+
myConnection,
|
|
24
|
+
connectedDeviceIds: deviceIds,
|
|
25
|
+
preferredByDeviceIds,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
allDeviceIdsSet.delete(deviceId);
|
|
29
|
+
const preferredConnections = [];
|
|
30
|
+
let sortedConnections = allConnectionInfos.filter(c => c.myConnection);
|
|
31
|
+
while (allDeviceIdsSet.size && sortedConnections.length) {
|
|
32
|
+
// sort connections (best will be first)
|
|
33
|
+
sortedConnections = sortConnections({
|
|
34
|
+
myDeviceId: deviceId,
|
|
35
|
+
connections: sortedConnections,
|
|
36
|
+
unconnectedDeviceIds: allDeviceIdsSet
|
|
37
|
+
});
|
|
38
|
+
const connection = sortedConnections.shift();
|
|
39
|
+
if (connection) {
|
|
40
|
+
preferredConnections.push(connection.myConnection);
|
|
41
|
+
connection.connectedDeviceIds.forEach(id => allDeviceIdsSet.delete(id));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
preferredDeviceIds: preferredConnections.map(c => c.deviceId),
|
|
49
|
+
preferredByDeviceIds: Array.from(_preferredByDeviceIdsSet),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Sort connections from most preferred to least preferred
|
|
54
|
+
* The most preferred connections are ones that link us to the most new devices
|
|
55
|
+
* (i.e. not already connected to by other preferred connections).
|
|
56
|
+
* Ties go to connections that are most preferred by other devices.
|
|
57
|
+
* Further ties go to connections with the lowest latency * error rate
|
|
58
|
+
*/
|
|
59
|
+
function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
60
|
+
// sort by latency * error rate (smaller is better)
|
|
61
|
+
connections.sort((a, b) => {
|
|
62
|
+
const aLatency = (a.myConnection.latencyMs || 1) * (a.myConnection.errorRate || 0.00001);
|
|
63
|
+
const bLatency = (b.myConnection.latencyMs || 1) * (b.myConnection.errorRate || 0.00001);
|
|
64
|
+
return aLatency - bLatency;
|
|
65
|
+
});
|
|
66
|
+
// sort by preferred by other devices count (higher is better)
|
|
67
|
+
connections.sort((a, b) => {
|
|
68
|
+
const aPreferredCount = a.preferredDeviceIds.length;
|
|
69
|
+
const bPreferredCount = b.preferredDeviceIds.length;
|
|
70
|
+
return bPreferredCount - aPreferredCount;
|
|
71
|
+
});
|
|
72
|
+
// sort by links to new devices - in general, this is most important except for the later edge-cases
|
|
73
|
+
connections.sort((a, b) => {
|
|
74
|
+
const linksToDeviceA = a.connectedDeviceIds.filter(id => unconnectedDeviceIds.has(id)).length;
|
|
75
|
+
const linksToDeviceB = b.connectedDeviceIds.filter(id => unconnectedDeviceIds.has(id)).length;
|
|
76
|
+
return linksToDeviceB - linksToDeviceA;
|
|
77
|
+
});
|
|
78
|
+
//=============================================
|
|
79
|
+
// Edge Cases - these should _usually_ return 0
|
|
80
|
+
//=============================================
|
|
81
|
+
const MAX_CONNECTIONS = peer_device_1.PeerDeviceConsts.MAX_CONNECTIONS;
|
|
82
|
+
// deprioritize devices that are close to max connections
|
|
83
|
+
connections.sort((a, b) => {
|
|
84
|
+
const aConnCnt = a.preferredByDeviceIds.length + a.preferredDeviceIds.length;
|
|
85
|
+
const bConnCnt = b.preferredByDeviceIds.length + b.preferredDeviceIds.length;
|
|
86
|
+
const nearingMaxA = aConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
87
|
+
const nearingMaxB = bConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
88
|
+
if (nearingMaxA && !nearingMaxB)
|
|
89
|
+
return 1;
|
|
90
|
+
if (!nearingMaxA && nearingMaxB)
|
|
91
|
+
return -1;
|
|
92
|
+
return 0;
|
|
93
|
+
});
|
|
94
|
+
// prefer devices that have a connection back to me
|
|
95
|
+
// I think this is an artifact of testing and in the real world this should be a no-op (connections should be bidirectional)
|
|
96
|
+
connections.sort((a, b) => {
|
|
97
|
+
const aHasConn = a.connections.some(c => c.deviceId === myDeviceId);
|
|
98
|
+
const bHasConn = b.connections.some(c => c.deviceId === myDeviceId);
|
|
99
|
+
if (aHasConn && !bHasConn)
|
|
100
|
+
return -1;
|
|
101
|
+
if (!aHasConn && bHasConn)
|
|
102
|
+
return 1;
|
|
103
|
+
return 0;
|
|
104
|
+
});
|
|
105
|
+
return connections;
|
|
106
|
+
}
|
|
107
|
+
function getLeastPreferredConnection({ connections, preferredDeviceIds, preferredByDeviceIds, }) {
|
|
108
|
+
// first consider connections that are not critical to me and I'm not critical to them
|
|
109
|
+
let candidates = connections.filter(c => !(preferredByDeviceIds.includes(c.deviceId) || preferredDeviceIds.includes(c.deviceId)));
|
|
110
|
+
if (!candidates.length) {
|
|
111
|
+
// if none, next consider connections that are not critical to me
|
|
112
|
+
candidates = connections.filter(c => !preferredDeviceIds.includes(c.deviceId));
|
|
113
|
+
}
|
|
114
|
+
if (!candidates.length) {
|
|
115
|
+
// if none, next consider connections that I am not critical to
|
|
116
|
+
candidates = connections.filter(c => !preferredByDeviceIds.includes(c.deviceId));
|
|
117
|
+
}
|
|
118
|
+
if (!candidates.length) {
|
|
119
|
+
// if none, then just consider all connections
|
|
120
|
+
candidates = [...connections];
|
|
121
|
+
}
|
|
122
|
+
// start with random order to avoid biasing the selection to newer connections
|
|
123
|
+
candidates = (0, lodash_1.shuffle)(candidates);
|
|
124
|
+
// sort by latency * error rate (smaller is better)
|
|
125
|
+
candidates.sort((a, b) => {
|
|
126
|
+
const aLatency = (a.latencyMs || 1) * (a.errorRate || 0.00001);
|
|
127
|
+
const bLatency = (b.latencyMs || 1) * (b.errorRate || 0.00001);
|
|
128
|
+
return aLatency - bLatency;
|
|
129
|
+
});
|
|
130
|
+
// sort by least number of groups (higher is better)
|
|
131
|
+
candidates.sort((a, b) => {
|
|
132
|
+
const aGroupCount = a.groups.length;
|
|
133
|
+
const bGroupCount = b.groups.length;
|
|
134
|
+
return bGroupCount - aGroupCount;
|
|
135
|
+
});
|
|
136
|
+
return candidates[candidates.length - 1];
|
|
137
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IDataBox, ISignedObject } from "../keys";
|
|
2
|
+
import { IDeviceHandshake, IDeviceInfo } from "../data";
|
|
3
|
+
export declare class Device implements IDeviceInfo {
|
|
4
|
+
readonly userId: string;
|
|
5
|
+
readonly deviceId: string;
|
|
6
|
+
private readonly keys;
|
|
7
|
+
constructor(userId?: string, deviceId?: string, keys?: import("../keys").IPublicPrivateKeys);
|
|
8
|
+
get publicKey(): string;
|
|
9
|
+
get publicBoxKey(): string;
|
|
10
|
+
signMessageWithSecretKey(msg: string): string;
|
|
11
|
+
signObjectWithSecretKey<T>(obj: T): ISignedObject<T>;
|
|
12
|
+
boxDataWithKeys(data: any, toPublicKey: string): IDataBox;
|
|
13
|
+
boxDataForDevice(data: any, device: IDeviceInfo): IDataBox;
|
|
14
|
+
openBoxWithSecretKey(data: IDataBox): any;
|
|
15
|
+
signAndBoxDataForDevice<T>(data: T, device: IDeviceInfo): IDataBox;
|
|
16
|
+
unwrapResponse<T>(response: T | ISignedObject<T> | IDataBox): T;
|
|
17
|
+
openBoxedAndSignedData<T>(response: IDataBox): T;
|
|
18
|
+
getHandshake(connectionId: string, serverAddress: string): ISignedObject<IDeviceHandshake>;
|
|
19
|
+
handshakeResponse(remoteHandshake: ISignedObject<IDeviceHandshake>, connectionId: string, thisServerAddress: string): IDeviceHandshake;
|
|
20
|
+
private deviceInfoSigned;
|
|
21
|
+
getDeviceInfo(): ISignedObject<IDeviceInfo>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Device = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const keys_1 = require("../keys");
|
|
6
|
+
class Device {
|
|
7
|
+
userId;
|
|
8
|
+
deviceId;
|
|
9
|
+
keys;
|
|
10
|
+
constructor(userId = (0, utils_1.newid)(), deviceId = (0, utils_1.newid)(), keys = (0, keys_1.newKeys)()) {
|
|
11
|
+
this.userId = userId;
|
|
12
|
+
this.deviceId = deviceId;
|
|
13
|
+
this.keys = keys;
|
|
14
|
+
}
|
|
15
|
+
get publicKey() {
|
|
16
|
+
return this.keys.publicKey;
|
|
17
|
+
}
|
|
18
|
+
get publicBoxKey() {
|
|
19
|
+
return this.keys.publicBoxKey;
|
|
20
|
+
}
|
|
21
|
+
signMessageWithSecretKey(msg) {
|
|
22
|
+
return (0, keys_1.signMessageWithSecretKey)(msg, this.keys.secretKey);
|
|
23
|
+
}
|
|
24
|
+
signObjectWithSecretKey(obj) {
|
|
25
|
+
return (0, keys_1.signObjectWithSecretKey)(obj, this.keys.secretKey);
|
|
26
|
+
}
|
|
27
|
+
boxDataWithKeys(data, toPublicKey) {
|
|
28
|
+
return (0, keys_1.boxDataWithKeys)(data, toPublicKey, this.keys.secretKey);
|
|
29
|
+
}
|
|
30
|
+
boxDataForDevice(data, device) {
|
|
31
|
+
return this.boxDataWithKeys(data, device.publicBoxKey);
|
|
32
|
+
}
|
|
33
|
+
openBoxWithSecretKey(data) {
|
|
34
|
+
return (0, keys_1.openBoxWithSecretKey)(data, this.keys.secretKey);
|
|
35
|
+
}
|
|
36
|
+
signAndBoxDataForDevice(data, device) {
|
|
37
|
+
const signedData = this.signObjectWithSecretKey(data);
|
|
38
|
+
return this.boxDataForDevice(signedData, device);
|
|
39
|
+
}
|
|
40
|
+
unwrapResponse(response) {
|
|
41
|
+
if (!response) {
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
if (typeof response === 'object' && 'contents' in response && 'nonce' in response && 'fromPublicKey' in response) {
|
|
45
|
+
const signedResponse = this.openBoxWithSecretKey(response);
|
|
46
|
+
return this.unwrapResponse(signedResponse);
|
|
47
|
+
}
|
|
48
|
+
if (typeof response === 'object' && 'contents' in response && 'signature' in response && 'publicKey' in response) {
|
|
49
|
+
const signedResponse = response;
|
|
50
|
+
return (0, keys_1.openSignedObject)(signedResponse);
|
|
51
|
+
}
|
|
52
|
+
return response;
|
|
53
|
+
}
|
|
54
|
+
openBoxedAndSignedData(response) {
|
|
55
|
+
const signedResponse = this.openBoxWithSecretKey(response);
|
|
56
|
+
return (0, keys_1.openSignedObject)(signedResponse);
|
|
57
|
+
}
|
|
58
|
+
getHandshake(connectionId, serverAddress) {
|
|
59
|
+
try {
|
|
60
|
+
const localDeviceInfo = {
|
|
61
|
+
connectionId,
|
|
62
|
+
userId: this.userId,
|
|
63
|
+
deviceId: this.deviceId,
|
|
64
|
+
publicKey: this.publicKey,
|
|
65
|
+
publicBoxKey: this.publicBoxKey,
|
|
66
|
+
serverAddress,
|
|
67
|
+
timestamp: Date.now(),
|
|
68
|
+
};
|
|
69
|
+
const localDeviceInfoSigned = this.signObjectWithSecretKey(localDeviceInfo);
|
|
70
|
+
return localDeviceInfoSigned;
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
throw new Error(`Failed to handshake: ${e.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
handshakeResponse(remoteHandshake, connectionId, thisServerAddress) {
|
|
77
|
+
try {
|
|
78
|
+
const deviceInfo = (0, keys_1.openSignedObject)(remoteHandshake);
|
|
79
|
+
if (deviceInfo.connectionId !== connectionId) {
|
|
80
|
+
throw new Error(`Invalid connectionId ${deviceInfo.connectionId}, expected ${connectionId}`);
|
|
81
|
+
}
|
|
82
|
+
const handshakeResponse = {
|
|
83
|
+
connectionId,
|
|
84
|
+
userId: this.userId,
|
|
85
|
+
deviceId: this.deviceId,
|
|
86
|
+
publicKey: this.publicKey,
|
|
87
|
+
publicBoxKey: this.publicBoxKey,
|
|
88
|
+
serverAddress: thisServerAddress,
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
};
|
|
91
|
+
return handshakeResponse;
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
throw new Error(`Failed to handshake: ${e.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
deviceInfoSigned;
|
|
98
|
+
getDeviceInfo() {
|
|
99
|
+
if (!this.deviceInfoSigned) {
|
|
100
|
+
this.deviceInfoSigned = this.signObjectWithSecretKey({
|
|
101
|
+
userId: this.userId,
|
|
102
|
+
deviceId: this.deviceId,
|
|
103
|
+
publicKey: this.publicKey,
|
|
104
|
+
publicBoxKey: this.publicBoxKey,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return this.deviceInfoSigned;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.Device = Device;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|