diodejs 0.0.4 → 0.1.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/README.md CHANGED
@@ -1,20 +1,19 @@
1
- # diode_js
1
+ # DiodeJs
2
2
 
3
3
  ## Overview
4
- `diode_js` is a JavaScript client for interacting with the Diode network. It provides functionalities to bind and publish ports, send RPC commands, and handle responses.
4
+ `diodejs` is 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
 
6
6
  ## Installation
7
7
  ```bash
8
8
  npm install diodejs
9
9
  ```
10
- ## Quick Start
11
10
 
12
- To get started, you need to generate a device certificate using OpenSSL. You can use this command:
11
+ ### Quick Start
13
12
 
14
- ```bash
15
- openssl ecparam -name secp256k1 -out secp256k1_params.pem
16
- openssl req -newkey ec:./secp256k1_params.pem -nodes -keyout device_certificate.pem -x509 -days 365 -out device_certificate.pem -subj "/CN=device"
17
- ```
13
+ If you want to enable logs, set environment variable LOG to true.
14
+ If you want to enable debug logs, set environment variable DEBUG to true.
15
+
16
+ Can also use .env files
18
17
 
19
18
  ### Test RPC
20
19
 
@@ -96,3 +95,65 @@ async function main() {
96
95
  main();
97
96
 
98
97
  ```
98
+
99
+ ## Reference
100
+
101
+ ### Classes and Methods
102
+
103
+ #### `DiodeConnection`
104
+
105
+ - **Constructor**: `new DiodeConnection(host, port, certPath)`
106
+ - `host` (string): The host address of the Diode server.
107
+ - `port` (number): The port number of the Diode server.
108
+ - `certPath` (string)(default: ./cert/device_certificate.pem): The path to the device certificate. If doesn't exist, generates automaticly.
109
+
110
+ - **Methods**:
111
+ - `connect()`: Connects to the Diode server. Returns a promise.
112
+ - `sendCommand(commandArray)`: Sends a command to the Diode server. Returns a promise.
113
+ - `sendCommandWithSessionId(commandArray, sessionId)`: Sends a command with a session ID. Returns a promise.
114
+ - `getEthereumAddress()`: Returns the Ethereum address derived from the device certificate.
115
+ - `getServerEthereumAddress()`: Returns the Ethereum address of the server.
116
+ - `createTicketCommand()`: Creates a ticket command for authentication. Returns a promise.
117
+ - `close()`: Closes the connection to the Diode server.
118
+
119
+ #### `DiodeRPC`
120
+
121
+ - **Constructor**: `new DiodeRPC(connection)`
122
+ - `connection` (DiodeConnection): An instance of `DiodeConnection`.
123
+
124
+ - **Methods**:
125
+ - `getBlockPeak()`: Retrieves the current block peak. Returns a promise.
126
+ - `getBlockHeader(index)`: Retrieves the block header for a given index. Returns a promise.
127
+ - `getBlock(index)`: Retrieves the block for a given index. Returns a promise.
128
+ - `ping()`: Sends a ping command. Returns a promise.
129
+ - `portOpen(deviceId, port, flags)`: Opens a port on the device. Returns a promise.
130
+ - `portSend(ref, data)`: Sends data to the device. Returns a promise.
131
+ - `portClose(ref)`: Closes a port on the device. Returns a promise.
132
+ - `sendError(sessionId, ref, error)`: Sends an error response. Returns a promise.
133
+ - `sendResponse(sessionId, ref, response)`: Sends a response. Returns a promise.
134
+ - `getEpoch()`: Retrieves the current epoch. Returns a promise.
135
+ - `parseTimestamp(blockHeader)`: Parses the timestamp from a block header. Returns a number.
136
+
137
+ #### `BindPort`
138
+
139
+ - **Constructor**: `new BindPort(connection, localPort, targetPort, deviceIdHex)`
140
+ - `connection` (DiodeConnection): An instance of `DiodeConnection`.
141
+ - `localPort` (number): The local port to bind.
142
+ - `targetPort` (number): The target port on the device.
143
+ - `deviceIdHex` (string): The device ID in hexadecimal format.
144
+
145
+ - **Methods**:
146
+ - `bind()`: Binds the local port to the target port on the device.
147
+
148
+ #### `PublishPort`
149
+
150
+ - **Constructor**: `new PublishPort(connection, publishedPorts, certPath)`
151
+ - `connection` (DiodeConnection): An instance of `DiodeConnection`.
152
+ - `publishedPorts` (array): An array of ports to publish.
153
+ - `certPath` (string): The path to the device certificate.
154
+
155
+ - **Methods**:
156
+ - `startListening()`: Starts listening for unsolicited messages.
157
+ - `handlePortOpen(sessionIdRaw, messageContent)`: Handles port open requests.
158
+ - `handlePortSend(sessionIdRaw, messageContent)`: Handles port send requests.
159
+ - `handlePortClose(sessionIdRaw, messageContent)`: Handles port close requests.
package/bindPort.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const net = require('net');
2
2
  const { Buffer } = require('buffer');
3
3
  const DiodeRPC = require('./rpc');
4
+ const logger = require('./logger');
4
5
 
5
6
  class BindPort {
6
7
  constructor(connection, localPort, targetPort,deviceIdHex) {
@@ -12,8 +13,7 @@ class BindPort {
12
13
 
13
14
  bind () {
14
15
  const deviceId = Buffer.from(this.deviceIdHex, 'hex');
15
- const clientSockets = new Map();
16
-
16
+ // Remove local clientSockets map and use the one from connection
17
17
  const rpc = new DiodeRPC(this.connection);
18
18
 
19
19
  // Listen for data events from the device
@@ -30,12 +30,17 @@ class BindPort {
30
30
  const dataRef = Buffer.from(refRaw);
31
31
  const data = Buffer.from(dataRaw);
32
32
 
33
- // Find the associated client socket
34
- const clientSocket = clientSockets.get(dataRef.toString('hex'));
33
+ // Find the associated client socket from connection
34
+ const clientSocket = this.connection.getClientSocket(dataRef);
35
35
  if (clientSocket) {
36
36
  clientSocket.write(data);
37
37
  } else {
38
- console.warn(`No client socket found for ref: ${dataRef.toString('hex')}`);
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
+ }
39
44
  }
40
45
  } else if (messageType === 'portclose') {
41
46
  const refRaw = messageContent[1];
@@ -43,75 +48,88 @@ class BindPort {
43
48
  const dataRef = Buffer.from(refRaw);
44
49
 
45
50
  // Close the associated client socket
46
- const clientSocket = clientSockets.get(dataRef.toString('hex'));
51
+ const clientSocket = this.connection.getClientSocket(dataRef);
47
52
  if (clientSocket) {
48
53
  clientSocket.end();
49
- clientSockets.delete(dataRef.toString('hex'));
50
- console.log(`Port closed for ref: ${dataRef.toString('hex')}`);
54
+ this.connection.deleteClientSocket(dataRef);
55
+ logger.info(`Port closed for ref: ${dataRef.toString('hex')}`);
51
56
  }
52
57
  } else {
53
- console.warn(`Unknown unsolicited message type: ${messageType}`);
58
+ if (messageType != 'portopen') {
59
+ logger.warn(`Unknown unsolicited message type: ${messageType}`);
60
+ }
54
61
  }
55
62
  });
56
63
 
57
64
  // Set up local server
58
65
  const server = net.createServer(async (clientSocket) => {
59
- console.log('Client connected to local server');
66
+ logger.info('Client connected to local server');
60
67
 
61
68
  // Open a new port on the device for this client
62
69
  let ref;
63
70
  try {
64
71
  ref = await rpc.portOpen(deviceId, this.targetPort, 'rw');
65
- console.log(`Port opened on device with ref: ${ref.toString('hex')} for client`);
72
+ if (!ref) {
73
+ logger.error('Error opening port on device');
74
+ clientSocket.destroy();
75
+ return
76
+ } else {
77
+ logger.info(`Port opened on device with ref: ${ref.toString('hex')} for client`);
78
+ }
66
79
  } catch (error) {
67
- console.error('Error opening port on device:', error);
80
+ logger.error(`Error opening port on device: ${error}`);
68
81
  clientSocket.destroy();
69
82
  return;
70
83
  }
71
84
 
72
- // Store the client socket with the ref (using hex string as key)
73
- clientSockets.set(ref.toString('hex'), clientSocket);
85
+ // Store the client socket with the ref using connection's method
86
+ this.connection.addClientSocket(ref, clientSocket);
74
87
 
75
88
  // When data is received from the client, send it to the device
76
89
  clientSocket.on('data', async (data) => {
77
90
  try {
78
91
  await rpc.portSend(ref, data);
79
92
  } catch (error) {
80
- console.error('Error sending data to device:', error);
93
+ logger.error(`Error sending data to device: ${error}`);
81
94
  clientSocket.destroy();
82
95
  }
83
96
  });
84
97
 
85
98
  // Handle client socket closure
86
99
  clientSocket.on('end', async () => {
87
- console.log('Client disconnected');
88
- clientSockets.delete(ref.toString('hex'));
89
- try {
90
- console.log(`Port closed on device for ref: ${ref.toString('hex')}`);
91
- } catch (error) {
92
- console.error('Error closing port on device:', error);
100
+ logger.info('Client disconnected');
101
+ if (ref && this.connection.hasClientSocket(ref)) {
102
+ try {
103
+ await rpc.portClose(ref);
104
+ logger.info(`Port closed on device for ref: ${ref.toString('hex')}`);
105
+ this.connection.deleteClientSocket(ref);
106
+ } catch (error) {
107
+ logger.error(`Error closing port on device: ${error}`);
108
+ }
109
+ } else {
110
+ logger.warn('Ref is invalid or no longer in clientSockets.');
93
111
  }
94
112
  });
95
113
 
96
114
  // Handle client socket errors
97
115
  clientSocket.on('error', (err) => {
98
- console.error('Client socket error:', err);
116
+ logger.error('Client socket error:', err);
99
117
  });
100
118
  });
101
119
 
102
120
  server.listen(this.localPort, () => {
103
- console.log(`Local server listening on port ${this.localPort}`);
121
+ logger.info(`Local server listening on port ${this.localPort}`);
104
122
  });
105
123
 
106
124
  // Handle device disconnect
107
125
  this.connection.on('end', () => {
108
- console.log('Disconnected from Diode.io server');
126
+ logger.info('Disconnected from Diode.io server');
109
127
  server.close();
110
128
  });
111
129
 
112
130
  // Handle connection errors
113
131
  this.connection.on('error', (err) => {
114
- console.error('Connection error:', err);
132
+ logger.error(`Connection error: ${err}`);
115
133
  server.close();
116
134
  });
117
135
  }
package/connection.js CHANGED
@@ -3,7 +3,7 @@ const tls = require('tls');
3
3
  const fs = require('fs');
4
4
  const { RLP } = require('@ethereumjs/rlp');
5
5
  const EventEmitter = require('events');
6
- const { makeReadable, parseRequestId, parseResponseType, parseReason } = require('./utils');
6
+ const { makeReadable, parseRequestId, parseResponseType, parseReason, generateCert } = require('./utils');
7
7
  const { Buffer } = require('buffer'); // Import Buffer
8
8
  const asn1 = require('asn1.js');
9
9
  const secp256k1 = require('secp256k1');
@@ -11,8 +11,9 @@ const ethUtil = require('ethereumjs-util');
11
11
  const crypto = require('crypto');
12
12
  const DiodeRPC = require('./rpc');
13
13
  const abi = require('ethereumjs-abi');
14
+ const logger = require('./logger');
14
15
  class DiodeConnection extends EventEmitter {
15
- constructor(host, port, certPath) {
16
+ constructor(host, port, certPath = './cert/device_certificate.pem') {
16
17
  super();
17
18
  this.host = host;
18
19
  this.port = port;
@@ -25,6 +26,17 @@ class DiodeConnection extends EventEmitter {
25
26
  // Add buffer to handle partial data
26
27
  this.receiveBuffer = Buffer.alloc(0);
27
28
  this.RPC = new DiodeRPC(this);
29
+ this.isReconnecting = false;
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
35
+
36
+ // Check if certPath exists, if not generate the certificate
37
+ if (!fs.existsSync(this.certPath)) {
38
+ generateCert(this.certPath);
39
+ }
28
40
  }
29
41
 
30
42
  connect() {
@@ -40,7 +52,7 @@ class DiodeConnection extends EventEmitter {
40
52
  };
41
53
 
42
54
  this.socket = tls.connect(this.port, this.host, options, async () => {
43
- console.log('Connected to Diode.io server');
55
+ logger.info('Connected to Diode.io server');
44
56
  // Set keep-alive to prevent connection timeout forever
45
57
  this.socket.setKeepAlive(true, 0);
46
58
 
@@ -48,33 +60,55 @@ class DiodeConnection extends EventEmitter {
48
60
  try {
49
61
  const ticketCommand = await this.createTicketCommand();
50
62
  const response = await this.sendCommand(ticketCommand).catch(reject);
51
- console.log('Ticket accepted:', response);
63
+ logger.info(`Ticket accepted: ${makeReadable(response)}`);
52
64
  resolve();
53
65
  } catch (error) {
54
- console.error('Error sending ticket:', error);
66
+ logger.error(`Error sending ticket: ${error}`);
55
67
  reject(error);
56
68
  }
57
69
  });
58
70
 
59
71
  this.socket.on('data', (data) => {
72
+ logger.debug(`Received data: ${data.toString('hex')}`);
60
73
  try {
61
74
  this._handleData(data);
62
75
  } catch (error) {
63
- console.error('Error handling data:', error);
76
+ logger.error(`Error handling data: ${error}`);
64
77
  }
65
78
  });
66
79
  this.socket.on('error', (err) => {
67
- console.error('Connection error:', err);
80
+ logger.error(`Connection error: ${err}`);
68
81
  reject(err);
69
82
  });
70
- this.socket.on('end', () => console.log('Disconnected from server'));
83
+ this.socket.on('end', () => logger.info('Disconnected from server'));
71
84
  });
72
85
  }
73
86
 
87
+ _ensureConnected() {
88
+ if (this.socket && !this.socket.destroyed) {
89
+ return Promise.resolve();
90
+ }
91
+ if (this.connectPromise) {
92
+ return this.connectPromise;
93
+ }
94
+ this.isReconnecting = true;
95
+ this.connectPromise = this.connect()
96
+ .then(() => {
97
+ this.isReconnecting = false;
98
+ this.connectPromise = null;
99
+ })
100
+ .catch((err) => {
101
+ this.isReconnecting = false;
102
+ this.connectPromise = null;
103
+ throw err;
104
+ });
105
+ return this.connectPromise;
106
+ }
107
+
74
108
  _handleData(data) {
75
109
  // Append new data to the receive buffer
76
110
  this.receiveBuffer = Buffer.concat([this.receiveBuffer, data]);
77
- console.log('Received data:', data.toString('hex'));
111
+ logger.debug(`Received data: ${data.toString('hex')}`);
78
112
 
79
113
  let offset = 0;
80
114
  while (offset + 2 <= this.receiveBuffer.length) {
@@ -92,7 +126,7 @@ class DiodeConnection extends EventEmitter {
92
126
 
93
127
  try {
94
128
  const decodedMessage = RLP.decode(Uint8Array.from(messageBuffer));
95
- console.log('Decoded message:', makeReadable(decodedMessage));
129
+ logger.debug(`Decoded message: ${makeReadable(decodedMessage)}`);
96
130
 
97
131
  if (Array.isArray(decodedMessage) && decodedMessage.length > 1) {
98
132
  const requestIdRaw = decodedMessage[0];
@@ -102,8 +136,8 @@ class DiodeConnection extends EventEmitter {
102
136
  const requestId = parseRequestId(requestIdRaw);
103
137
 
104
138
  // Debug statements
105
- console.log('requestIdRaw:', requestIdRaw);
106
- console.log('Parsed requestId:', requestId);
139
+ logger.debug(`requestIdRaw: ${requestIdRaw}`);
140
+ logger.debug(`Parsed requestId: ${requestId}`);
107
141
 
108
142
  if (requestId !== null && this.pendingRequests.has(requestId)) {
109
143
  // This is a response to a pending request
@@ -111,16 +145,14 @@ class DiodeConnection extends EventEmitter {
111
145
  const responseRaw = responseData[0];
112
146
 
113
147
  // Debug statements
114
- console.log('responseTypeRaw:', responseTypeRaw);
115
- console.log('Type of responseTypeRaw:', typeof responseTypeRaw);
116
- console.log('Instance of responseTypeRaw:', responseTypeRaw instanceof Uint8Array);
117
- console.log('Is Array:', Array.isArray(responseTypeRaw));
148
+ logger.debug(`responseTypeRaw: ${responseTypeRaw}`);
149
+ logger.debug(`Type of responseTypeRaw: ${typeof responseTypeRaw}`);
118
150
 
119
151
  // Parse responseType
120
152
  const responseType = parseResponseType(responseTypeRaw);
121
153
 
122
- console.log(`Received response for requestId: ${requestId}`);
123
- console.log(`Response Type: '${responseType}'`);
154
+ logger.debug(`Received response for requestId: ${requestId}`);
155
+ logger.debug(`Response Type: '${responseType}'`);
124
156
 
125
157
  const { resolve, reject } = this.pendingRequests.get(requestId);
126
158
  try{
@@ -146,20 +178,20 @@ class DiodeConnection extends EventEmitter {
146
178
  resolve(responseData);
147
179
  }
148
180
  } catch (error) {
149
- console.error('Error handling response:', error);
181
+ logger.error(`Error handling response: ${error}`);
150
182
  }
151
183
  this.pendingRequests.delete(requestId);
152
184
  } else {
153
185
  // This is an unsolicited message
154
- console.log('Received unsolicited message:', decodedMessage);
186
+ logger.debug(`Received unsolicited message: ${makeReadable(decodedMessage)}`);
155
187
  this.emit('unsolicited', decodedMessage);
156
188
  }
157
189
  } else {
158
190
  // Invalid message format
159
- console.error('Invalid message format:', decodedMessage);
191
+ logger.error(`Invalid message format: ${makeReadable(decodedMessage)}`);
160
192
  }
161
193
  } catch (error) {
162
- console.error('Error decoding message:', error);
194
+ logger.error(`Error decoding message: ${error}`);
163
195
  }
164
196
  }
165
197
 
@@ -190,67 +222,55 @@ class DiodeConnection extends EventEmitter {
190
222
 
191
223
  sendCommand(commandArray) {
192
224
  return new Promise((resolve, reject) => {
193
- //check if connection is alive
194
- if (!this.socket || this.socket.destroyed) {
195
- //reconnect
196
- this.connect().then(() => {
197
- this.sendCommand(commandArray).then(resolve).catch(reject);
198
- }).catch(reject);
199
- return;
200
- }
201
- const requestId = this._getNextRequestId();
202
- // Build the message as [requestId, [commandArray]]
203
- const commandWithId = [requestId, commandArray];
204
-
205
- // Store the promise callbacks to resolve/reject later
206
- this.pendingRequests.set(requestId, { resolve, reject });
207
-
208
- const commandBuffer = RLP.encode(commandWithId);
209
- const byteLength = Buffer.byteLength(commandBuffer);
210
-
211
- // Create a 2-byte length buffer
212
- const lengthBuffer = Buffer.alloc(2);
213
- lengthBuffer.writeUInt16BE(byteLength, 0);
214
-
215
- const message = Buffer.concat([lengthBuffer, commandBuffer]);
216
-
217
- console.log(`Sending command with requestId ${requestId}:`, commandArray);
218
- console.log('Command buffer:', message.toString('hex'));
219
-
220
- this.socket.write(message);
225
+ this._ensureConnected().then(() => {
226
+ const requestId = this._getNextRequestId();
227
+ // Build the message as [requestId, [commandArray]]
228
+ const commandWithId = [requestId, commandArray];
229
+
230
+ // Store the promise callbacks to resolve/reject later
231
+ this.pendingRequests.set(requestId, { resolve, reject });
232
+
233
+ const commandBuffer = RLP.encode(commandWithId);
234
+ const byteLength = Buffer.byteLength(commandBuffer);
235
+
236
+ // Create a 2-byte length buffer
237
+ const lengthBuffer = Buffer.alloc(2);
238
+ lengthBuffer.writeUInt16BE(byteLength, 0);
239
+
240
+ const message = Buffer.concat([lengthBuffer, commandBuffer]);
241
+
242
+ logger.debug(`Sending command with requestId ${requestId}: ${commandArray}`);
243
+ logger.debug(`Command buffer: ${message.toString('hex')}`);
244
+
245
+ this.socket.write(message);
246
+ }).catch(reject);
221
247
  });
222
248
  }
223
249
 
224
250
  sendCommandWithSessionId(commandArray, sessionId) {
225
251
  return new Promise((resolve, reject) => {
226
- //check if connection is alive
227
- if (!this.socket || this.socket.destroyed) {
228
- //reconnect
229
- this.connect().then(() => {
230
- this.sendCommand(commandArray).then(resolve).catch(reject);
231
- }).catch(reject);
232
- return;
233
- }
234
- const requestId = sessionId;
235
- // Build the message as [requestId, [commandArray]]
236
- const commandWithId = [requestId, commandArray];
237
-
238
- // Store the promise callbacks to resolve/reject later
239
- this.pendingRequests.set(requestId, { resolve, reject });
240
-
241
- const commandBuffer = RLP.encode(commandWithId);
242
- const byteLength = Buffer.byteLength(commandBuffer);
243
-
244
- // Create a 2-byte length buffer
245
- const lengthBuffer = Buffer.alloc(2);
246
- lengthBuffer.writeUInt16BE(byteLength, 0);
247
-
248
- const message = Buffer.concat([lengthBuffer, commandBuffer]);
249
-
250
- console.log(`Sending command with requestId ${requestId}:`, commandArray);
251
- console.log('Command buffer:', message.toString('hex'));
252
-
253
- this.socket.write(message);
252
+ this._ensureConnected().then(() => {
253
+ const requestId = sessionId;
254
+ // Build the message as [requestId, [commandArray]]
255
+ const commandWithId = [requestId, commandArray];
256
+
257
+ // Store the promise callbacks to resolve/reject later
258
+ this.pendingRequests.set(requestId, { resolve, reject });
259
+
260
+ const commandBuffer = RLP.encode(commandWithId);
261
+ const byteLength = Buffer.byteLength(commandBuffer);
262
+
263
+ // Create a 2-byte length buffer
264
+ const lengthBuffer = Buffer.alloc(2);
265
+ lengthBuffer.writeUInt16BE(byteLength, 0);
266
+
267
+ const message = Buffer.concat([lengthBuffer, commandBuffer]);
268
+
269
+ logger.debug(`Sending command with requestId ${requestId}: ${commandArray}`);
270
+ logger.debug(`Command buffer: ${message.toString('hex')}`);
271
+
272
+ this.socket.write(message);
273
+ }).catch(reject);
254
274
  });
255
275
  }
256
276
 
@@ -300,7 +320,7 @@ class DiodeConnection extends EventEmitter {
300
320
 
301
321
  const ecPrivateKey = ECPrivateKeyASN.decode(privateKeyOctetString, 'der');
302
322
  privateKeyBytes = ecPrivateKey.privateKey;
303
- console.log('Private key bytes:', privateKeyBytes.toString('hex'));
323
+ logger.debug(`Private key bytes: ${privateKeyBytes.toString('hex')}`);
304
324
  } else {
305
325
  throw new Error('Unsupported key format. Expected EC PRIVATE KEY or PRIVATE KEY in PEM format.');
306
326
  }
@@ -317,10 +337,10 @@ class DiodeConnection extends EventEmitter {
317
337
  const addressBuffer = ethUtil.pubToAddress(publicKeyBuffer, true);
318
338
  const address = '0x' + addressBuffer.toString('hex');
319
339
 
320
- console.log('Ethereum address:', address);
340
+ logger.info(`Ethereum address: ${address}`);
321
341
  return address;
322
342
  } catch (error) {
323
- console.error('Error extracting Ethereum address:', error);
343
+ logger.error(`Error extracting Ethereum address: ${error}`);
324
344
  throw error;
325
345
  }
326
346
  }
@@ -336,15 +356,15 @@ class DiodeConnection extends EventEmitter {
336
356
  ? serverCert.pubkey
337
357
  : Buffer.from(serverCert.pubkey);
338
358
 
339
- console.log('Public key Server:', publicKeyBuffer.toString('hex'));
359
+ logger.debug(`Public key Server: ${publicKeyBuffer.toString('hex')}`);
340
360
 
341
361
  const addressBuffer = ethUtil.pubToAddress(publicKeyBuffer, true);
342
362
  const address = '0x' + addressBuffer.toString('hex');
343
363
 
344
- console.log('Server Ethereum address:', address);
364
+ logger.info(`Server Ethereum address: ${address}`);
345
365
  return address;
346
366
  } catch (error) {
347
- console.error('Error extracting server Ethereum address:', error);
367
+ logger.error(`Error extracting server Ethereum address: ${error}`);
348
368
  throw error;
349
369
  }
350
370
  }
@@ -448,7 +468,7 @@ class DiodeConnection extends EventEmitter {
448
468
 
449
469
  return privateKeyBytes;
450
470
  } catch (error) {
451
- console.error('Error extracting Ethereum address:', error);
471
+ logger.error(`Error extracting Ethereum address: ${error}`);
452
472
  throw error;
453
473
  }
454
474
  }
@@ -475,17 +495,17 @@ class DiodeConnection extends EventEmitter {
475
495
  // Convert each element in dataToSign to bytes32 and concatenate them
476
496
  const encodedData = Buffer.concat(dataToSign.map(item => abi.rawEncode(['bytes32'], [item])));
477
497
 
478
- console.log('Encoded data:', encodedData.toString('hex'));
498
+ logger.debug(`Encoded data: ${encodedData.toString('hex')}`);
479
499
 
480
- console.log('Data to sign:', makeReadable(dataToSign));
500
+ logger.debug(`Data to sign: ${makeReadable(dataToSign)}`);
481
501
 
482
502
 
483
503
  // Sign the data
484
504
  const privateKey = this.getPrivateKey();
485
505
  const msgHash = ethUtil.keccak256(encodedData);
486
- console.log('Message hash:', msgHash.toString('hex'));
506
+ logger.debug(`Message hash: ${msgHash.toString('hex')}`);
487
507
  const signature = secp256k1.ecdsaSign(msgHash, privateKey);
488
- console.log('Signature:', signature);
508
+ logger.debug(`Signature: ${signature.signature.toString('hex')}`);
489
509
 
490
510
  const signatureBuffer = Buffer.concat([
491
511
  ethUtil.toBuffer([signature.recid]),
@@ -519,7 +539,7 @@ class DiodeConnection extends EventEmitter {
519
539
  localAddress,
520
540
  epoch
521
541
  );
522
- console.log('Signature hex:', signature.toString('hex'));
542
+ logger.debug(`Signature hex: ${signature.toString('hex')}`);
523
543
 
524
544
 
525
545
  // Construct the ticket command
@@ -546,6 +566,40 @@ class DiodeConnection extends EventEmitter {
546
566
  close() {
547
567
  this.socket.end();
548
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
+ }
549
603
  }
550
604
 
551
605
 
@@ -8,7 +8,7 @@ async function main() {
8
8
  const connection = new DiodeConnection(host, port, certPath);
9
9
  await connection.connect();
10
10
 
11
- const portForward = new BindPort(connection, 3002, 80, "5365baf29cb7ab58de588dfc448913cb609283e2");
11
+ const portForward = new BindPort(connection, 3002, 8080, "5365baf29cb7ab58de588dfc448913cb609283e2");
12
12
  portForward.bind();
13
13
 
14
14
  }
@@ -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
+
package/index.js CHANGED
@@ -4,4 +4,5 @@ const DiodeRPC = require('./rpc');
4
4
  const BindPort = require('./bindPort');
5
5
  const PublishPort = require('./publishPort');
6
6
  const makeReadable = require('./utils').makeReadable;
7
- module.exports = { DiodeConnection, DiodeRPC, BindPort , PublishPort, makeReadable };
7
+ const logger = require('./logger');
8
+ module.exports = { DiodeConnection, DiodeRPC, BindPort , PublishPort, makeReadable, logger };
package/logger.js ADDED
@@ -0,0 +1,28 @@
1
+ const setupLogger = require('dera-logger');
2
+ require('dotenv').config();
3
+ const isDebug = (process.env.DEBUG === 'true'); // Simple debug flag
4
+ const isLogEnabled = (process.env.LOG === 'true'); // Simple log flag
5
+
6
+ const options = {
7
+ logDirectory: 'logs',
8
+ timestampFormat: 'HH:mm:ss',
9
+ fileDatePattern: 'YYYY-MM-DD',
10
+ zippedArchive: false,
11
+ maxLogFileSize: null,
12
+ maxFiles: '14d',
13
+ addConsoleInNonProduction: true,
14
+ transports: [
15
+ { filename: 'combined', level: 'silly', source: 'app' },
16
+ { filename: 'error', level: 'warn', source: 'app' }
17
+ ]
18
+ };
19
+
20
+ const logger = setupLogger(options);
21
+
22
+ // Wrap logger calls to respect debug mode
23
+ module.exports = {
24
+ debug: (...args) => { if (isDebug && isLogEnabled) logger.debug(...args, 'app'); },
25
+ info: (...args) => { if (isLogEnabled) logger.info(...args, 'app'); },
26
+ warn: (...args) => { if (isLogEnabled) logger.warn(...args, 'app'); },
27
+ error: (...args) => { if (isLogEnabled) logger.error(...args, 'app'); },
28
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diodejs",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
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": {
@@ -11,18 +11,20 @@
11
11
  "dependencies": {
12
12
  "@ethereumjs/rlp": "^5.0.2",
13
13
  "asn1.js": "^5.4.1",
14
- "axios": "^1.6.8",
15
14
  "buffer": "^6.0.3",
16
15
  "crypto": "^1.0.1",
16
+ "dera-logger": "^2.0.0",
17
17
  "dgram": "^1.0.1",
18
+ "dotenv": "^16.4.7",
18
19
  "ethereumjs-abi": "^0.6.8",
19
20
  "ethereumjs-util": "^7.1.5",
20
21
  "ethers": "^6.13.2",
21
22
  "fs": "^0.0.1-security",
23
+ "jsrsasign": "^11.1.0",
22
24
  "net": "^1.0.2",
23
25
  "node-fetch": "^2.7.0",
24
26
  "rlp": "^3.0.0",
25
- "secp256k1": "^5.0.0",
27
+ "secp256k1": "^5.0.1",
26
28
  "tls": "^0.0.1"
27
29
  }
28
30
  }
package/publishPort.js CHANGED
@@ -9,6 +9,8 @@ const EventEmitter = require('events');
9
9
  const { Duplex } = require('stream');
10
10
  const DiodeRPC = require('./rpc');
11
11
  const { makeReadable } = require('./utils');
12
+ const logger = require('./logger');
13
+
12
14
  class DiodeSocket extends Duplex {
13
15
  constructor(ref, rpc) {
14
16
  super();
@@ -37,8 +39,8 @@ class PublishPort extends EventEmitter {
37
39
  constructor(connection, publishedPorts, certPath) {
38
40
  super();
39
41
  this.connection = connection;
40
- this.publishedPorts = publishedPorts; // Array of ports to publish
41
- this.connections = new Map(); // Map to store active connections
42
+ this.publishedPorts = new Set(publishedPorts); // Convert array to a Set
43
+ // Remove local connections map and use the one from connection
42
44
  this.startListening();
43
45
  this.rpc = new DiodeRPC(connection);
44
46
  this.certPath = certPath;
@@ -58,7 +60,9 @@ class PublishPort extends EventEmitter {
58
60
  } else if (messageType === 'portclose') {
59
61
  this.handlePortClose(sessionIdRaw, messageContent);
60
62
  } else {
61
- console.warn(`Unknown unsolicited message type: ${messageType}`);
63
+ if (messageType != 'data') {
64
+ logger.warn(`Unknown unsolicited message type: ${messageType}`);
65
+ }
62
66
  }
63
67
  });
64
68
  }
@@ -74,7 +78,7 @@ class PublishPort extends EventEmitter {
74
78
  const ref = Buffer.from(refRaw);
75
79
  const deviceId = Buffer.from(deviceIdRaw).toString('hex');
76
80
 
77
- console.log(`Received portopen request for portString ${portString} with ref ${ref.toString('hex')} from device ${deviceId}`);
81
+ logger.info(`Received portopen request for portString ${portString} with ref ${ref.toString('hex')} from device ${deviceId}`);
78
82
 
79
83
  // Extract protocol and port number from portString
80
84
  var protocol = 'tcp';
@@ -92,8 +96,8 @@ class PublishPort extends EventEmitter {
92
96
  }
93
97
 
94
98
  // Check if the port is published
95
- if (!this.publishedPorts.includes(port)) {
96
- console.warn(`Port ${port} is not published. Rejecting request.`);
99
+ if (!this.publishedPorts.has(port)) { // Use .has() instead of .includes()
100
+ logger.warn(`Port ${port} is not published. Rejecting request.`);
97
101
  // Send error response
98
102
  this.rpc.sendError(sessionId, ref, 'Port is not published');
99
103
  return;
@@ -107,7 +111,7 @@ class PublishPort extends EventEmitter {
107
111
  } else if (protocol === 'udp') {
108
112
  this.handleUDPConnection(sessionId, ref, port);
109
113
  } else {
110
- console.warn(`Unsupported protocol: ${protocol}`);
114
+ logger.warn(`Unsupported protocol: ${protocol}`);
111
115
  this.rpc.sendError(sessionId, ref, `Unsupported protocol: ${protocol}`);
112
116
  }
113
117
  }
@@ -122,17 +126,17 @@ class PublishPort extends EventEmitter {
122
126
  });
123
127
 
124
128
  localSocket.on('end', () => {
125
- console.log(`Local service disconnected`);
129
+ logger.info(`Local service disconnected`);
126
130
  // Send portclose message to Diode
127
131
  this.rpc.portClose(ref);
128
- this.connections.delete(ref.toString('hex'));
132
+ this.connection.deleteConnection(ref);
129
133
  });
130
134
 
131
135
  localSocket.on('error', (err) => {
132
- console.error(`Error with local service:`, err);
136
+ logger.error(`Error with local service: ${err}`);
133
137
  // Send portclose message to Diode
134
138
  this.rpc.portClose(ref);
135
- this.connections.delete(ref.toString('hex'));
139
+ this.connection.deleteConnection(ref);
136
140
  });
137
141
  }
138
142
  }
@@ -140,7 +144,7 @@ class PublishPort extends EventEmitter {
140
144
  handleTCPConnection(sessionId, ref, port) {
141
145
  // Create a TCP connection to the local service on the specified port
142
146
  const localSocket = net.connect({ port: port }, () => {
143
- console.log(`Connected to local TCP service on port ${port}`);
147
+ logger.info(`Connected to local TCP service on port ${port}`);
144
148
  // Send success response
145
149
  this.rpc.sendResponse(sessionId, ref, 'ok');
146
150
  });
@@ -148,8 +152,8 @@ class PublishPort extends EventEmitter {
148
152
  // Handle data, end, and error events
149
153
  this.setupLocalSocketHandlers(localSocket, ref, 'tcp');
150
154
 
151
- // Store the local socket with the ref
152
- this.connections.set(ref.toString('hex'), { socket: localSocket, protocol: 'tcp' });
155
+ // Store the local socket with the ref using connection's method
156
+ this.connection.addConnection(ref, { socket: localSocket, protocol: 'tcp' });
153
157
  }
154
158
 
155
159
  handleTLSConnection(sessionId, ref, port) {
@@ -175,7 +179,7 @@ class PublishPort extends EventEmitter {
175
179
 
176
180
  // Connect to the local service (TCP or TLS as needed)
177
181
  const localSocket = net.connect({ port: port }, () => {
178
- console.log(`Connected to local TCP service on port ${port}`);
182
+ logger.info(`Connected to local TCP service on port ${port}`);
179
183
  // Send success response
180
184
  this.rpc.sendResponse(sessionId, ref, 'ok');
181
185
  });
@@ -185,18 +189,18 @@ class PublishPort extends EventEmitter {
185
189
 
186
190
  // Handle errors and cleanup
187
191
  tlsSocket.on('error', (err) => {
188
- console.error('TLS Socket error:', err);
192
+ logger.error(`TLS Socket error: ${err}`);
189
193
  this.rpc.portClose(ref);
190
- this.connections.delete(ref.toString('hex'));
194
+ this.connection.deleteConnection(ref);
191
195
  });
192
196
 
193
197
  tlsSocket.on('close', () => {
194
198
  console.log('TLS Socket closed');
195
- this.connections.delete(ref.toString('hex'));
199
+ this.connection.deleteConnection(ref);
196
200
  });
197
201
 
198
- // Store the connection info
199
- this.connections.set(ref.toString('hex'), {
202
+ // Store the connection info using connection's method
203
+ this.connection.addConnection(ref, {
200
204
  diodeSocket,
201
205
  tlsSocket,
202
206
  localSocket,
@@ -214,13 +218,15 @@ class PublishPort extends EventEmitter {
214
218
  // Send success response
215
219
  this.rpc.sendResponse(sessionId, ref, 'ok');
216
220
 
217
- // Store the connection info
218
- this.connections.set(ref.toString('hex'), {
221
+ // Store the connection info using connection's method
222
+ this.connection.addConnection(ref, {
219
223
  socket: localSocket,
220
224
  protocol: 'udp',
221
225
  remoteInfo,
222
226
  });
223
227
 
228
+ logger.info(`UDP connection set up on port ${port}`);
229
+
224
230
  // Handle messages from the local UDP service
225
231
  localSocket.on('message', (msg, rinfo) => {
226
232
  //need to add 4 bytes of data length to the beginning of the message but it's Big Endian
@@ -232,9 +238,9 @@ class PublishPort extends EventEmitter {
232
238
  });
233
239
 
234
240
  localSocket.on('error', (err) => {
235
- console.error(`UDP Socket error:`, err);
241
+ logger.error(`UDP Socket error: ${err}`);
236
242
  this.rpc.portClose(ref);
237
- this.connections.delete(ref.toString('hex'));
243
+ this.connection.deleteConnection(ref);
238
244
  });
239
245
  }
240
246
 
@@ -246,7 +252,7 @@ class PublishPort extends EventEmitter {
246
252
  const ref = Buffer.from(refRaw);
247
253
  const data = Buffer.from(dataRaw)//.slice(4);
248
254
 
249
- const connectionInfo = this.connections.get(ref.toString('hex'));
255
+ const connectionInfo = this.connection.getConnection(ref);
250
256
  if (connectionInfo) {
251
257
  const { socket: localSocket, protocol, remoteInfo } = connectionInfo;
252
258
 
@@ -273,8 +279,13 @@ class PublishPort extends EventEmitter {
273
279
  diodeSocket.pushData(data);
274
280
  }
275
281
  } else {
276
- console.warn(`No local connection found for ref ${ref.toString('hex')}. Sending portclose.`);
277
- this.rpc.sendError(sessionId, ref, 'No local connection found');
282
+ const clientSocket = this.connection.getClientSocket(ref);
283
+ if (clientSocket) {
284
+ logger.debug(`No local connection found for ref: ${ref.toString('hex')}, but client socket exists`);
285
+ } else {
286
+ logger.warn(`No local connection found for ref ${ref.toString('hex')}. Sending portclose.`);
287
+ this.rpc.sendError(sessionId, ref, 'No local connection found');
288
+ }
278
289
  }
279
290
  }
280
291
 
@@ -283,9 +294,9 @@ class PublishPort extends EventEmitter {
283
294
  const sessionId = Buffer.from(sessionIdRaw);
284
295
  const ref = Buffer.from(refRaw);
285
296
 
286
- console.log(`Received portclose for ref ${ref.toString('hex')}`);
297
+ logger.info(`Received portclose for ref ${ref.toString('hex')}`);
287
298
 
288
- const connectionInfo = this.connections.get(ref.toString('hex'));
299
+ const connectionInfo = this.connection.getConnection(ref);
289
300
  if (connectionInfo) {
290
301
  const { diodeSocket, tlsSocket, socket: localSocket } = connectionInfo;
291
302
  // End all sockets
@@ -298,7 +309,7 @@ class PublishPort extends EventEmitter {
298
309
  localSocket.end();
299
310
  }
300
311
  }
301
- this.connections.delete(ref.toString('hex'));
312
+ this.connection.deleteConnection(ref);
302
313
  }
303
314
  }
304
315
  }
package/rpc.js CHANGED
@@ -1,5 +1,6 @@
1
1
  //rpc.js
2
2
  const { makeReadable, parseRequestId, parseResponseType, parseReason } = require('./utils');
3
+ const logger = require('./logger');
3
4
 
4
5
  class DiodeRPC {
5
6
  constructor(connection) {
@@ -24,9 +25,10 @@ class DiodeRPC {
24
25
  } else {
25
26
  throw new Error('Invalid block number format. response:', makeReadable(responseData));
26
27
  }
28
+ logger.debug(`Block number is: ${blockNumber}`);
27
29
  return blockNumber;
28
30
  }).catch((error) => {
29
- console.error('Error during get block peak:', error);
31
+ logger.error(`Error during get block peak: ${error}`);
30
32
  return;
31
33
  });
32
34
  }
@@ -34,7 +36,7 @@ class DiodeRPC {
34
36
  return this.connection.sendCommand(['getblockheader', index]).then((responseData) => {
35
37
  return responseData[0]; // block_header
36
38
  }).catch((error) => {
37
- console.error('Error during get block header:', error);
39
+ logger.error(`Error during get block header: ${error}`);
38
40
  return;
39
41
  });
40
42
  }
@@ -43,7 +45,7 @@ class DiodeRPC {
43
45
  return this.connection.sendCommand(['getblock', index]).then((responseData) => {
44
46
  return responseData[0]; // block
45
47
  }).catch((error) => {
46
- console.error('Error during get block:', error);
48
+ logger.error(`Error during get block: ${error}`);
47
49
  return;
48
50
  });
49
51
  }
@@ -62,7 +64,7 @@ class DiodeRPC {
62
64
  throw new Error(`Unknown status in response: '${status}'`);
63
65
  }
64
66
  }).catch((error) => {
65
- console.error('Error during ping:', error);
67
+ logger.error(`Error during ping: ${error}`);
66
68
  return false;
67
69
  })
68
70
  }
@@ -90,7 +92,7 @@ class DiodeRPC {
90
92
  throw new Error(`Unknown status in response: '${status}'`);
91
93
  }
92
94
  }).catch((error) => {
93
- console.error('Error during port open:', error);
95
+ logger.error(`Error during port open: ${error}`);
94
96
  return;
95
97
  });
96
98
  }
@@ -110,12 +112,12 @@ class DiodeRPC {
110
112
  try {
111
113
  const ticketCommand = await this.connection.createTicketCommand();
112
114
  const ticketResponse = await this.connection.sendCommand(ticketCommand).catch((error) => {
113
- console.error('Error during ticket command:', error);
115
+ logger.error(`Error during ticket command: ${error}`);
114
116
  throw error;
115
117
  });
116
- console.log('Ticket updated:', ticketResponse);
118
+ logger.debug(`Ticket updated: ${makeReadable(ticketResponse)}`);
117
119
  } catch (error) {
118
- console.error('Error updating ticket:', error);
120
+ logger.error(`Error updating ticket: ${error}`);
119
121
  throw error;
120
122
  }
121
123
  return;
@@ -125,7 +127,7 @@ class DiodeRPC {
125
127
  throw new Error(`Unknown status in response: '${status}'`);
126
128
  }
127
129
  }).catch((error) => {
128
- console.error('Error during port send:', error);
130
+ logger.error(`Error during port send: ${error}`);
129
131
  return;
130
132
  });
131
133
  }
@@ -146,21 +148,21 @@ class DiodeRPC {
146
148
  throw new Error(`Unknown status in response: '${status}'`);
147
149
  }
148
150
  }).catch((error) => {
149
- console.error('Error during port close:', error);
151
+ logger.error(`Error during port close: ${error}`);
150
152
  return;
151
153
  });
152
154
  }
153
155
 
154
156
  sendError(sessionId, ref, error) {
155
157
  return this.connection.sendCommandWithSessionId(['response', ref, 'error', error], sessionId).catch((error) => {
156
- console.error('Error during send error:', error);
158
+ logger.error(`Error during send error: ${error}`);
157
159
  return;
158
160
  });
159
161
  }
160
162
 
161
163
  sendResponse(sessionId, ref, response) {
162
164
  return this.connection.sendCommandWithSessionId(['response', ref, response], sessionId).catch((error) => {
163
- console.error('Error during send response:', error);
165
+ logger.error(`Error during send response: ${error}`);
164
166
  return;
165
167
  });
166
168
  }
@@ -168,10 +170,10 @@ class DiodeRPC {
168
170
  async getEpoch() {
169
171
  const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
170
172
  if (this.epochCache.expiry && this.epochCache.expiry > currentTime) {
171
- console.log('Using cached epoch:', this.epochCache.epoch);
173
+ logger.debug(`Using cached epoch: ${this.epochCache.epoch}`);
172
174
  return this.epochCache.epoch;
173
175
  }
174
- console.log('Fetching new epoch. Expiry:', this.epochCache.expiry);
176
+ logger.debug(`Fetching new epoch. Expiry: ${this.epochCache.expiry}, Current time: ${currentTime}`);
175
177
  const blockPeak = await this.getBlockPeak();
176
178
  const blockHeader = await this.getBlockHeader(blockPeak);
177
179
 
@@ -205,4 +207,3 @@ class DiodeRPC {
205
207
  }
206
208
 
207
209
  module.exports = DiodeRPC;
208
-
package/utils.js CHANGED
@@ -1,5 +1,11 @@
1
1
  // utils.js
2
2
  const { Buffer } = require('buffer');
3
+ const logger = require('./logger');
4
+ const { KJUR } = require("jsrsasign");
5
+ const { KEYUTIL } = require("jsrsasign");
6
+ const fs = require('fs');
7
+ var path = require('path');
8
+
3
9
  function makeReadable(decodedMessage) {
4
10
  if (Array.isArray(decodedMessage)) {
5
11
  return decodedMessage.map((item) => makeReadable(item));
@@ -46,10 +52,10 @@ function parseRequestId(requestIdRaw) {
46
52
  }
47
53
 
48
54
  function parseResponseType(responseTypeRaw) {
49
- console.log('responseTypeRaw:', responseTypeRaw);
50
- console.log('Type of responseTypeRaw:', typeof responseTypeRaw);
51
- console.log('Instance of responseTypeRaw:', responseTypeRaw instanceof Uint8Array);
52
- console.log('Is Array:', Array.isArray(responseTypeRaw));
55
+ logger.debug(`responseTypeRaw: ${responseTypeRaw}`);
56
+ logger.debug(`Type of responseTypeRaw: ${typeof responseTypeRaw}`);
57
+ logger.debug(`Instance of responseTypeRaw: ${responseTypeRaw instanceof Uint8Array}`);
58
+ logger.debug(`Is Array: ${Array.isArray(responseTypeRaw)}`);
53
59
  if (responseTypeRaw instanceof Uint8Array || Buffer.isBuffer(responseTypeRaw)) {
54
60
  return Buffer.from(responseTypeRaw).toString('utf8');
55
61
  } else if (Array.isArray(responseTypeRaw)) {
@@ -74,4 +80,45 @@ function parseReason(reasonRaw) {
74
80
  }
75
81
  }
76
82
 
77
- module.exports = { makeReadable, parseRequestId, parseResponseType, parseReason };
83
+ function generateCert(path) {
84
+ var kp = KEYUTIL.generateKeypair("EC", "secp256k1");
85
+
86
+ var priv = KEYUTIL.getPEM(kp.prvKeyObj, "PKCS8PRV");
87
+
88
+ pub = KEYUTIL.getPEM(kp.pubKeyObj, "PKCS8PUB");
89
+
90
+ var x = new KJUR.asn1.x509.Certificate({
91
+ version: 3,
92
+ serial: { int: 4 },
93
+ issuer: { str: "/CN=device" },
94
+ subject: { str: "/CN=device" },
95
+ sbjpubkey: kp.pubKeyObj,
96
+ ext: [
97
+ { extname: "basicConstraints", cA: false },
98
+ { extname: "keyUsage", critical: true, names: ["digitalSignature"] },
99
+ {
100
+ extname: "cRLDistributionPoints",
101
+ array: [{ fulluri: 'https://diode.io/' }]
102
+ }
103
+ ],
104
+ sigalg: "SHA256withECDSA",
105
+ cakey: kp.prvKeyObj
106
+ });
107
+
108
+
109
+ const pemFile = priv + x.getPEM();
110
+ ensureDirectoryExistence(path);
111
+
112
+ fs.writeFileSync(path, pemFile , 'utf8');
113
+ }
114
+
115
+ function ensureDirectoryExistence(filePath) {
116
+ var dirname = path.dirname(filePath);
117
+ if (fs.existsSync(dirname)) {
118
+ return true;
119
+ }
120
+ ensureDirectoryExistence(dirname);
121
+ fs.mkdirSync(dirname);
122
+ }
123
+
124
+ module.exports = { makeReadable, parseRequestId, parseResponseType, parseReason, generateCert };