diodejs 0.0.5 → 0.1.1
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 +16 -5
- package/bindPort.js +18 -12
- package/connection.js +38 -0
- package/examples/publishAndBind.js +23 -0
- package/examples/publishPortTest.js +1 -1
- package/package.json +1 -1
- package/publishPort.js +64 -21
package/README.md
CHANGED
|
@@ -87,13 +87,22 @@ async function main() {
|
|
|
87
87
|
const connection = new DiodeConnection(host, port, certPath);
|
|
88
88
|
await connection.connect();
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
90
|
+
// Option 1: Simple array of ports (all public)
|
|
91
|
+
const publishedPorts = [8080, 3000];
|
|
92
|
+
|
|
93
|
+
// Option 2: Object with port configurations for public/private access control
|
|
94
|
+
const publishedPortsWithConfig = {
|
|
95
|
+
8080: { mode: 'public' }, // Public port, accessible by any device
|
|
96
|
+
3000: {
|
|
97
|
+
mode: 'private',
|
|
98
|
+
whitelist: ['0x1234abcd5678...', '0x9876fedc5432...'] // Only these devices can connect
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const publishPort = new PublishPort(connection, publishedPortsWithConfig, certPath);
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
main();
|
|
96
|
-
|
|
97
106
|
```
|
|
98
107
|
|
|
99
108
|
## Reference
|
|
@@ -149,7 +158,9 @@ main();
|
|
|
149
158
|
|
|
150
159
|
- **Constructor**: `new PublishPort(connection, publishedPorts, certPath)`
|
|
151
160
|
- `connection` (DiodeConnection): An instance of `DiodeConnection`.
|
|
152
|
-
- `publishedPorts` (array):
|
|
161
|
+
- `publishedPorts` (array|object): Either:
|
|
162
|
+
- An array of ports to publish (all public mode)
|
|
163
|
+
- An object mapping ports to their configuration: `{ port: { mode: 'public'|'private', whitelist: ['0x123...'] } }`
|
|
153
164
|
- `certPath` (string): The path to the device certificate.
|
|
154
165
|
|
|
155
166
|
- **Methods**:
|
package/bindPort.js
CHANGED
|
@@ -13,8 +13,7 @@ class BindPort {
|
|
|
13
13
|
|
|
14
14
|
bind () {
|
|
15
15
|
const deviceId = Buffer.from(this.deviceIdHex, 'hex');
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// Remove local clientSockets map and use the one from connection
|
|
18
17
|
const rpc = new DiodeRPC(this.connection);
|
|
19
18
|
|
|
20
19
|
// Listen for data events from the device
|
|
@@ -31,12 +30,17 @@ class BindPort {
|
|
|
31
30
|
const dataRef = Buffer.from(refRaw);
|
|
32
31
|
const data = Buffer.from(dataRaw);
|
|
33
32
|
|
|
34
|
-
// Find the associated client socket
|
|
35
|
-
const clientSocket =
|
|
33
|
+
// Find the associated client socket from connection
|
|
34
|
+
const clientSocket = this.connection.getClientSocket(dataRef);
|
|
36
35
|
if (clientSocket) {
|
|
37
36
|
clientSocket.write(data);
|
|
38
37
|
} else {
|
|
39
|
-
|
|
38
|
+
const connectionInfo = this.connection.getConnection(dataRef);
|
|
39
|
+
if (connectionInfo) {
|
|
40
|
+
logger.debug(`No client socket found for ref: ${dataRef.toString('hex')}, but connection exists for ${connectionInfo.host}:${connectionInfo.port}`);
|
|
41
|
+
} else {
|
|
42
|
+
logger.warn(`No client socket found for ref: ${dataRef.toString('hex')}`);
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
} else if (messageType === 'portclose') {
|
|
42
46
|
const refRaw = messageContent[1];
|
|
@@ -44,14 +48,16 @@ class BindPort {
|
|
|
44
48
|
const dataRef = Buffer.from(refRaw);
|
|
45
49
|
|
|
46
50
|
// Close the associated client socket
|
|
47
|
-
const clientSocket =
|
|
51
|
+
const clientSocket = this.connection.getClientSocket(dataRef);
|
|
48
52
|
if (clientSocket) {
|
|
49
53
|
clientSocket.end();
|
|
50
|
-
|
|
54
|
+
this.connection.deleteClientSocket(dataRef);
|
|
51
55
|
logger.info(`Port closed for ref: ${dataRef.toString('hex')}`);
|
|
52
56
|
}
|
|
53
57
|
} else {
|
|
54
|
-
|
|
58
|
+
if (messageType != 'portopen') {
|
|
59
|
+
logger.warn(`Unknown unsolicited message type: ${messageType}`);
|
|
60
|
+
}
|
|
55
61
|
}
|
|
56
62
|
});
|
|
57
63
|
|
|
@@ -76,8 +82,8 @@ class BindPort {
|
|
|
76
82
|
return;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
// Store the client socket with the ref
|
|
80
|
-
|
|
85
|
+
// Store the client socket with the ref using connection's method
|
|
86
|
+
this.connection.addClientSocket(ref, clientSocket);
|
|
81
87
|
|
|
82
88
|
// When data is received from the client, send it to the device
|
|
83
89
|
clientSocket.on('data', async (data) => {
|
|
@@ -92,11 +98,11 @@ class BindPort {
|
|
|
92
98
|
// Handle client socket closure
|
|
93
99
|
clientSocket.on('end', async () => {
|
|
94
100
|
logger.info('Client disconnected');
|
|
95
|
-
if (ref &&
|
|
101
|
+
if (ref && this.connection.hasClientSocket(ref)) {
|
|
96
102
|
try {
|
|
97
103
|
await rpc.portClose(ref);
|
|
98
104
|
logger.info(`Port closed on device for ref: ${ref.toString('hex')}`);
|
|
99
|
-
|
|
105
|
+
this.connection.deleteClientSocket(ref);
|
|
100
106
|
} catch (error) {
|
|
101
107
|
logger.error(`Error closing port on device: ${error}`);
|
|
102
108
|
}
|
package/connection.js
CHANGED
|
@@ -28,6 +28,10 @@ class DiodeConnection extends EventEmitter {
|
|
|
28
28
|
this.RPC = new DiodeRPC(this);
|
|
29
29
|
this.isReconnecting = false;
|
|
30
30
|
this.connectPromise = null;
|
|
31
|
+
|
|
32
|
+
// Add maps for storing client sockets and connections
|
|
33
|
+
this.clientSockets = new Map(); // For BindPort
|
|
34
|
+
this.connections = new Map(); // For PublishPort
|
|
31
35
|
|
|
32
36
|
// Check if certPath exists, if not generate the certificate
|
|
33
37
|
if (!fs.existsSync(this.certPath)) {
|
|
@@ -562,6 +566,40 @@ class DiodeConnection extends EventEmitter {
|
|
|
562
566
|
close() {
|
|
563
567
|
this.socket.end();
|
|
564
568
|
}
|
|
569
|
+
|
|
570
|
+
// Client sockets management methods (for BindPort)
|
|
571
|
+
addClientSocket(ref, socket) {
|
|
572
|
+
this.clientSockets.set(ref.toString('hex'), socket);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
getClientSocket(ref) {
|
|
576
|
+
return this.clientSockets.get(ref.toString('hex'));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
deleteClientSocket(ref) {
|
|
580
|
+
return this.clientSockets.delete(ref.toString('hex'));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
hasClientSocket(ref) {
|
|
584
|
+
return this.clientSockets.has(ref.toString('hex'));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Connections management methods (for PublishPort)
|
|
588
|
+
addConnection(ref, connectionInfo) {
|
|
589
|
+
this.connections.set(ref.toString('hex'), connectionInfo);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
getConnection(ref) {
|
|
593
|
+
return this.connections.get(ref.toString('hex'));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
deleteConnection(ref) {
|
|
597
|
+
return this.connections.delete(ref.toString('hex'));
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
hasConnection(ref) {
|
|
601
|
+
return this.connections.has(ref.toString('hex'));
|
|
602
|
+
}
|
|
565
603
|
}
|
|
566
604
|
|
|
567
605
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const DiodeConnection = require('../connection')
|
|
2
|
+
const PublishPort = require('../publishPort')
|
|
3
|
+
const BindPort = require('../bindPort')
|
|
4
|
+
|
|
5
|
+
const host = 'us2.prenet.diode.io';
|
|
6
|
+
const port = 41046;
|
|
7
|
+
const certPath = 'device_certificate.pem';
|
|
8
|
+
|
|
9
|
+
const connection = new DiodeConnection(host, port, certPath);
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
await connection.connect();
|
|
13
|
+
const publishedPorts = [8080]; // Ports you want to publish
|
|
14
|
+
const publishPort = new PublishPort(connection, publishedPorts, certPath);
|
|
15
|
+
|
|
16
|
+
const portForward = new BindPort(connection, 3002, 8080, "5365baf29cb7ab58de588dfc448913cb609283e2");
|
|
17
|
+
portForward.bind();
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main();
|
|
22
|
+
|
|
23
|
+
|
|
@@ -11,7 +11,7 @@ async function startPublishing() {
|
|
|
11
11
|
const connection = new DiodeConnection(host, port, certPath);
|
|
12
12
|
await connection.connect();
|
|
13
13
|
|
|
14
|
-
const publishedPorts =
|
|
14
|
+
const publishedPorts = {8080: {mode: 'private', whitelist: ['0xca1e71d8105a598810578fb6042fa8cbc1e7f039']}}
|
|
15
15
|
const publishPort = new PublishPort(connection, publishedPorts, certPath);
|
|
16
16
|
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diodejs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A JavaScript client for interacting with the Diode network. It provides functionalities to bind and publish ports, send RPC commands, and handle responses.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/publishPort.js
CHANGED
|
@@ -39,9 +39,34 @@ class PublishPort extends EventEmitter {
|
|
|
39
39
|
constructor(connection, publishedPorts, certPath) {
|
|
40
40
|
super();
|
|
41
41
|
this.connection = connection;
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
|
|
43
|
+
// Convert publishedPorts to a Map with configurations
|
|
44
|
+
this.publishedPorts = new Map();
|
|
45
|
+
|
|
46
|
+
// Handle both array format and object format
|
|
47
|
+
if (Array.isArray(publishedPorts)) {
|
|
48
|
+
// Legacy array format - treat all ports as public
|
|
49
|
+
publishedPorts.forEach(port => {
|
|
50
|
+
this.publishedPorts.set(port, { mode: 'public', whitelist: [] });
|
|
51
|
+
});
|
|
52
|
+
} else if (typeof publishedPorts === 'object' && publishedPorts !== null) {
|
|
53
|
+
// New object format with configurations
|
|
54
|
+
Object.entries(publishedPorts).forEach(([port, config]) => {
|
|
55
|
+
const portNum = parseInt(port, 10);
|
|
56
|
+
// Ensure config is properly structured
|
|
57
|
+
const portConfig = typeof config === 'object' && config !== null
|
|
58
|
+
? {
|
|
59
|
+
mode: config.mode || 'public',
|
|
60
|
+
whitelist: Array.isArray(config.whitelist) ? config.whitelist : []
|
|
61
|
+
}
|
|
62
|
+
: { mode: 'public', whitelist: [] };
|
|
63
|
+
|
|
64
|
+
this.publishedPorts.set(portNum, portConfig);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
44
68
|
this.startListening();
|
|
69
|
+
logger.info(`Publishing ports: ${Array.from(this.publishedPorts.keys())}`);
|
|
45
70
|
this.rpc = new DiodeRPC(connection);
|
|
46
71
|
this.certPath = certPath;
|
|
47
72
|
}
|
|
@@ -60,7 +85,9 @@ class PublishPort extends EventEmitter {
|
|
|
60
85
|
} else if (messageType === 'portclose') {
|
|
61
86
|
this.handlePortClose(sessionIdRaw, messageContent);
|
|
62
87
|
} else {
|
|
63
|
-
|
|
88
|
+
if (messageType != 'data') {
|
|
89
|
+
logger.warn(`Unknown unsolicited message type: ${messageType}`);
|
|
90
|
+
}
|
|
64
91
|
}
|
|
65
92
|
});
|
|
66
93
|
}
|
|
@@ -74,7 +101,7 @@ class PublishPort extends EventEmitter {
|
|
|
74
101
|
const sessionId = Buffer.from(sessionIdRaw);
|
|
75
102
|
const portString = makeReadable(portStringRaw);
|
|
76
103
|
const ref = Buffer.from(refRaw);
|
|
77
|
-
const deviceId = Buffer.from(deviceIdRaw).toString('hex')
|
|
104
|
+
const deviceId = `0x${Buffer.from(deviceIdRaw).toString('hex')}`;
|
|
78
105
|
|
|
79
106
|
logger.info(`Received portopen request for portString ${portString} with ref ${ref.toString('hex')} from device ${deviceId}`);
|
|
80
107
|
|
|
@@ -94,13 +121,24 @@ class PublishPort extends EventEmitter {
|
|
|
94
121
|
}
|
|
95
122
|
|
|
96
123
|
// Check if the port is published
|
|
97
|
-
if (!this.publishedPorts.has(port)) {
|
|
124
|
+
if (!this.publishedPorts.has(port)) {
|
|
98
125
|
logger.warn(`Port ${port} is not published. Rejecting request.`);
|
|
99
126
|
// Send error response
|
|
100
127
|
this.rpc.sendError(sessionId, ref, 'Port is not published');
|
|
101
128
|
return;
|
|
102
129
|
}
|
|
103
130
|
|
|
131
|
+
// Get port configuration and check whitelist if in private mode
|
|
132
|
+
const portConfig = this.publishedPorts.get(port);
|
|
133
|
+
if (portConfig.mode === 'private' && Array.isArray(portConfig.whitelist)) {
|
|
134
|
+
if (!portConfig.whitelist.includes(deviceId)) {
|
|
135
|
+
logger.warn(`Device ${deviceId} is not whitelisted for port ${port}. Rejecting request.`);
|
|
136
|
+
this.rpc.sendError(sessionId, ref, 'Device not whitelisted');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
logger.info(`Device ${deviceId} is whitelisted for port ${port}. Accepting request.`);
|
|
140
|
+
}
|
|
141
|
+
|
|
104
142
|
// Handle based on protocol
|
|
105
143
|
if (protocol === 'tcp') {
|
|
106
144
|
this.handleTCPConnection(sessionId, ref, port);
|
|
@@ -127,14 +165,14 @@ class PublishPort extends EventEmitter {
|
|
|
127
165
|
logger.info(`Local service disconnected`);
|
|
128
166
|
// Send portclose message to Diode
|
|
129
167
|
this.rpc.portClose(ref);
|
|
130
|
-
this.
|
|
168
|
+
this.connection.deleteConnection(ref);
|
|
131
169
|
});
|
|
132
170
|
|
|
133
171
|
localSocket.on('error', (err) => {
|
|
134
172
|
logger.error(`Error with local service: ${err}`);
|
|
135
173
|
// Send portclose message to Diode
|
|
136
174
|
this.rpc.portClose(ref);
|
|
137
|
-
this.
|
|
175
|
+
this.connection.deleteConnection(ref);
|
|
138
176
|
});
|
|
139
177
|
}
|
|
140
178
|
}
|
|
@@ -150,8 +188,8 @@ class PublishPort extends EventEmitter {
|
|
|
150
188
|
// Handle data, end, and error events
|
|
151
189
|
this.setupLocalSocketHandlers(localSocket, ref, 'tcp');
|
|
152
190
|
|
|
153
|
-
// Store the local socket with the ref
|
|
154
|
-
this.
|
|
191
|
+
// Store the local socket with the ref using connection's method
|
|
192
|
+
this.connection.addConnection(ref, { socket: localSocket, protocol: 'tcp' });
|
|
155
193
|
}
|
|
156
194
|
|
|
157
195
|
handleTLSConnection(sessionId, ref, port) {
|
|
@@ -189,16 +227,16 @@ class PublishPort extends EventEmitter {
|
|
|
189
227
|
tlsSocket.on('error', (err) => {
|
|
190
228
|
logger.error(`TLS Socket error: ${err}`);
|
|
191
229
|
this.rpc.portClose(ref);
|
|
192
|
-
this.
|
|
230
|
+
this.connection.deleteConnection(ref);
|
|
193
231
|
});
|
|
194
232
|
|
|
195
233
|
tlsSocket.on('close', () => {
|
|
196
234
|
console.log('TLS Socket closed');
|
|
197
|
-
this.
|
|
235
|
+
this.connection.deleteConnection(ref);
|
|
198
236
|
});
|
|
199
237
|
|
|
200
|
-
// Store the connection info
|
|
201
|
-
this.
|
|
238
|
+
// Store the connection info using connection's method
|
|
239
|
+
this.connection.addConnection(ref, {
|
|
202
240
|
diodeSocket,
|
|
203
241
|
tlsSocket,
|
|
204
242
|
localSocket,
|
|
@@ -216,8 +254,8 @@ class PublishPort extends EventEmitter {
|
|
|
216
254
|
// Send success response
|
|
217
255
|
this.rpc.sendResponse(sessionId, ref, 'ok');
|
|
218
256
|
|
|
219
|
-
// Store the connection info
|
|
220
|
-
this.
|
|
257
|
+
// Store the connection info using connection's method
|
|
258
|
+
this.connection.addConnection(ref, {
|
|
221
259
|
socket: localSocket,
|
|
222
260
|
protocol: 'udp',
|
|
223
261
|
remoteInfo,
|
|
@@ -238,7 +276,7 @@ class PublishPort extends EventEmitter {
|
|
|
238
276
|
localSocket.on('error', (err) => {
|
|
239
277
|
logger.error(`UDP Socket error: ${err}`);
|
|
240
278
|
this.rpc.portClose(ref);
|
|
241
|
-
this.
|
|
279
|
+
this.connection.deleteConnection(ref);
|
|
242
280
|
});
|
|
243
281
|
}
|
|
244
282
|
|
|
@@ -250,7 +288,7 @@ class PublishPort extends EventEmitter {
|
|
|
250
288
|
const ref = Buffer.from(refRaw);
|
|
251
289
|
const data = Buffer.from(dataRaw)//.slice(4);
|
|
252
290
|
|
|
253
|
-
const connectionInfo = this.
|
|
291
|
+
const connectionInfo = this.connection.getConnection(ref);
|
|
254
292
|
if (connectionInfo) {
|
|
255
293
|
const { socket: localSocket, protocol, remoteInfo } = connectionInfo;
|
|
256
294
|
|
|
@@ -277,8 +315,13 @@ class PublishPort extends EventEmitter {
|
|
|
277
315
|
diodeSocket.pushData(data);
|
|
278
316
|
}
|
|
279
317
|
} else {
|
|
280
|
-
|
|
281
|
-
|
|
318
|
+
const clientSocket = this.connection.getClientSocket(ref);
|
|
319
|
+
if (clientSocket) {
|
|
320
|
+
logger.debug(`No local connection found for ref: ${ref.toString('hex')}, but client socket exists`);
|
|
321
|
+
} else {
|
|
322
|
+
logger.warn(`No local connection found for ref ${ref.toString('hex')}. Sending portclose.`);
|
|
323
|
+
this.rpc.sendError(sessionId, ref, 'No local connection found');
|
|
324
|
+
}
|
|
282
325
|
}
|
|
283
326
|
}
|
|
284
327
|
|
|
@@ -289,7 +332,7 @@ class PublishPort extends EventEmitter {
|
|
|
289
332
|
|
|
290
333
|
logger.info(`Received portclose for ref ${ref.toString('hex')}`);
|
|
291
334
|
|
|
292
|
-
const connectionInfo = this.
|
|
335
|
+
const connectionInfo = this.connection.getConnection(ref);
|
|
293
336
|
if (connectionInfo) {
|
|
294
337
|
const { diodeSocket, tlsSocket, socket: localSocket } = connectionInfo;
|
|
295
338
|
// End all sockets
|
|
@@ -302,7 +345,7 @@ class PublishPort extends EventEmitter {
|
|
|
302
345
|
localSocket.end();
|
|
303
346
|
}
|
|
304
347
|
}
|
|
305
|
-
this.
|
|
348
|
+
this.connection.deleteConnection(ref);
|
|
306
349
|
}
|
|
307
350
|
}
|
|
308
351
|
}
|