diodejs 0.0.3 → 0.0.5
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 +69 -8
- package/bindPort.js +29 -17
- package/connection.js +109 -93
- package/examples/portForwardTest.js +1 -1
- package/index.js +2 -1
- package/logger.js +28 -0
- package/package.json +5 -3
- package/publishPort.js +33 -18
- package/rpc.js +52 -21
- package/utils.js +52 -5
package/README.md
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DiodeJs
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
`
|
|
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
|
-
|
|
11
|
+
### Quick Start
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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) {
|
|
@@ -35,7 +36,7 @@ class BindPort {
|
|
|
35
36
|
if (clientSocket) {
|
|
36
37
|
clientSocket.write(data);
|
|
37
38
|
} else {
|
|
38
|
-
|
|
39
|
+
logger.warn(`No client socket found for ref: ${dataRef.toString('hex')}`);
|
|
39
40
|
}
|
|
40
41
|
} else if (messageType === 'portclose') {
|
|
41
42
|
const refRaw = messageContent[1];
|
|
@@ -47,24 +48,30 @@ class BindPort {
|
|
|
47
48
|
if (clientSocket) {
|
|
48
49
|
clientSocket.end();
|
|
49
50
|
clientSockets.delete(dataRef.toString('hex'));
|
|
50
|
-
|
|
51
|
+
logger.info(`Port closed for ref: ${dataRef.toString('hex')}`);
|
|
51
52
|
}
|
|
52
53
|
} else {
|
|
53
|
-
|
|
54
|
+
logger.warn(`Unknown unsolicited message type: ${messageType}`);
|
|
54
55
|
}
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
// Set up local server
|
|
58
59
|
const server = net.createServer(async (clientSocket) => {
|
|
59
|
-
|
|
60
|
+
logger.info('Client connected to local server');
|
|
60
61
|
|
|
61
62
|
// Open a new port on the device for this client
|
|
62
63
|
let ref;
|
|
63
64
|
try {
|
|
64
65
|
ref = await rpc.portOpen(deviceId, this.targetPort, 'rw');
|
|
65
|
-
|
|
66
|
+
if (!ref) {
|
|
67
|
+
logger.error('Error opening port on device');
|
|
68
|
+
clientSocket.destroy();
|
|
69
|
+
return
|
|
70
|
+
} else {
|
|
71
|
+
logger.info(`Port opened on device with ref: ${ref.toString('hex')} for client`);
|
|
72
|
+
}
|
|
66
73
|
} catch (error) {
|
|
67
|
-
|
|
74
|
+
logger.error(`Error opening port on device: ${error}`);
|
|
68
75
|
clientSocket.destroy();
|
|
69
76
|
return;
|
|
70
77
|
}
|
|
@@ -77,41 +84,46 @@ class BindPort {
|
|
|
77
84
|
try {
|
|
78
85
|
await rpc.portSend(ref, data);
|
|
79
86
|
} catch (error) {
|
|
80
|
-
|
|
87
|
+
logger.error(`Error sending data to device: ${error}`);
|
|
81
88
|
clientSocket.destroy();
|
|
82
89
|
}
|
|
83
90
|
});
|
|
84
91
|
|
|
85
92
|
// Handle client socket closure
|
|
86
93
|
clientSocket.on('end', async () => {
|
|
87
|
-
|
|
88
|
-
clientSockets.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
logger.info('Client disconnected');
|
|
95
|
+
if (ref && clientSockets.has(ref.toString('hex'))) {
|
|
96
|
+
try {
|
|
97
|
+
await rpc.portClose(ref);
|
|
98
|
+
logger.info(`Port closed on device for ref: ${ref.toString('hex')}`);
|
|
99
|
+
clientSockets.delete(ref.toString('hex'));
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.error(`Error closing port on device: ${error}`);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
logger.warn('Ref is invalid or no longer in clientSockets.');
|
|
93
105
|
}
|
|
94
106
|
});
|
|
95
107
|
|
|
96
108
|
// Handle client socket errors
|
|
97
109
|
clientSocket.on('error', (err) => {
|
|
98
|
-
|
|
110
|
+
logger.error('Client socket error:', err);
|
|
99
111
|
});
|
|
100
112
|
});
|
|
101
113
|
|
|
102
114
|
server.listen(this.localPort, () => {
|
|
103
|
-
|
|
115
|
+
logger.info(`Local server listening on port ${this.localPort}`);
|
|
104
116
|
});
|
|
105
117
|
|
|
106
118
|
// Handle device disconnect
|
|
107
119
|
this.connection.on('end', () => {
|
|
108
|
-
|
|
120
|
+
logger.info('Disconnected from Diode.io server');
|
|
109
121
|
server.close();
|
|
110
122
|
});
|
|
111
123
|
|
|
112
124
|
// Handle connection errors
|
|
113
125
|
this.connection.on('error', (err) => {
|
|
114
|
-
|
|
126
|
+
logger.error(`Connection error: ${err}`);
|
|
115
127
|
server.close();
|
|
116
128
|
});
|
|
117
129
|
}
|
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,13 @@ 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
|
+
// Check if certPath exists, if not generate the certificate
|
|
33
|
+
if (!fs.existsSync(this.certPath)) {
|
|
34
|
+
generateCert(this.certPath);
|
|
35
|
+
}
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
connect() {
|
|
@@ -40,41 +48,63 @@ class DiodeConnection extends EventEmitter {
|
|
|
40
48
|
};
|
|
41
49
|
|
|
42
50
|
this.socket = tls.connect(this.port, this.host, options, async () => {
|
|
43
|
-
|
|
51
|
+
logger.info('Connected to Diode.io server');
|
|
44
52
|
// Set keep-alive to prevent connection timeout forever
|
|
45
53
|
this.socket.setKeepAlive(true, 0);
|
|
46
54
|
|
|
47
55
|
// Send the ticketv2 command
|
|
48
56
|
try {
|
|
49
57
|
const ticketCommand = await this.createTicketCommand();
|
|
50
|
-
const response = await this.sendCommand(ticketCommand);
|
|
51
|
-
|
|
58
|
+
const response = await this.sendCommand(ticketCommand).catch(reject);
|
|
59
|
+
logger.info(`Ticket accepted: ${makeReadable(response)}`);
|
|
52
60
|
resolve();
|
|
53
61
|
} catch (error) {
|
|
54
|
-
|
|
62
|
+
logger.error(`Error sending ticket: ${error}`);
|
|
55
63
|
reject(error);
|
|
56
64
|
}
|
|
57
65
|
});
|
|
58
66
|
|
|
59
67
|
this.socket.on('data', (data) => {
|
|
68
|
+
logger.debug(`Received data: ${data.toString('hex')}`);
|
|
60
69
|
try {
|
|
61
70
|
this._handleData(data);
|
|
62
71
|
} catch (error) {
|
|
63
|
-
|
|
72
|
+
logger.error(`Error handling data: ${error}`);
|
|
64
73
|
}
|
|
65
74
|
});
|
|
66
75
|
this.socket.on('error', (err) => {
|
|
67
|
-
|
|
76
|
+
logger.error(`Connection error: ${err}`);
|
|
68
77
|
reject(err);
|
|
69
78
|
});
|
|
70
|
-
this.socket.on('end', () =>
|
|
79
|
+
this.socket.on('end', () => logger.info('Disconnected from server'));
|
|
71
80
|
});
|
|
72
81
|
}
|
|
73
82
|
|
|
83
|
+
_ensureConnected() {
|
|
84
|
+
if (this.socket && !this.socket.destroyed) {
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
}
|
|
87
|
+
if (this.connectPromise) {
|
|
88
|
+
return this.connectPromise;
|
|
89
|
+
}
|
|
90
|
+
this.isReconnecting = true;
|
|
91
|
+
this.connectPromise = this.connect()
|
|
92
|
+
.then(() => {
|
|
93
|
+
this.isReconnecting = false;
|
|
94
|
+
this.connectPromise = null;
|
|
95
|
+
})
|
|
96
|
+
.catch((err) => {
|
|
97
|
+
this.isReconnecting = false;
|
|
98
|
+
this.connectPromise = null;
|
|
99
|
+
throw err;
|
|
100
|
+
});
|
|
101
|
+
return this.connectPromise;
|
|
102
|
+
}
|
|
103
|
+
|
|
74
104
|
_handleData(data) {
|
|
75
105
|
// Append new data to the receive buffer
|
|
76
106
|
this.receiveBuffer = Buffer.concat([this.receiveBuffer, data]);
|
|
77
|
-
|
|
107
|
+
logger.debug(`Received data: ${data.toString('hex')}`);
|
|
78
108
|
|
|
79
109
|
let offset = 0;
|
|
80
110
|
while (offset + 2 <= this.receiveBuffer.length) {
|
|
@@ -92,7 +122,7 @@ class DiodeConnection extends EventEmitter {
|
|
|
92
122
|
|
|
93
123
|
try {
|
|
94
124
|
const decodedMessage = RLP.decode(Uint8Array.from(messageBuffer));
|
|
95
|
-
|
|
125
|
+
logger.debug(`Decoded message: ${makeReadable(decodedMessage)}`);
|
|
96
126
|
|
|
97
127
|
if (Array.isArray(decodedMessage) && decodedMessage.length > 1) {
|
|
98
128
|
const requestIdRaw = decodedMessage[0];
|
|
@@ -102,8 +132,8 @@ class DiodeConnection extends EventEmitter {
|
|
|
102
132
|
const requestId = parseRequestId(requestIdRaw);
|
|
103
133
|
|
|
104
134
|
// Debug statements
|
|
105
|
-
|
|
106
|
-
|
|
135
|
+
logger.debug(`requestIdRaw: ${requestIdRaw}`);
|
|
136
|
+
logger.debug(`Parsed requestId: ${requestId}`);
|
|
107
137
|
|
|
108
138
|
if (requestId !== null && this.pendingRequests.has(requestId)) {
|
|
109
139
|
// This is a response to a pending request
|
|
@@ -111,16 +141,14 @@ class DiodeConnection extends EventEmitter {
|
|
|
111
141
|
const responseRaw = responseData[0];
|
|
112
142
|
|
|
113
143
|
// Debug statements
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
console.log('Instance of responseTypeRaw:', responseTypeRaw instanceof Uint8Array);
|
|
117
|
-
console.log('Is Array:', Array.isArray(responseTypeRaw));
|
|
144
|
+
logger.debug(`responseTypeRaw: ${responseTypeRaw}`);
|
|
145
|
+
logger.debug(`Type of responseTypeRaw: ${typeof responseTypeRaw}`);
|
|
118
146
|
|
|
119
147
|
// Parse responseType
|
|
120
148
|
const responseType = parseResponseType(responseTypeRaw);
|
|
121
149
|
|
|
122
|
-
|
|
123
|
-
|
|
150
|
+
logger.debug(`Received response for requestId: ${requestId}`);
|
|
151
|
+
logger.debug(`Response Type: '${responseType}'`);
|
|
124
152
|
|
|
125
153
|
const { resolve, reject } = this.pendingRequests.get(requestId);
|
|
126
154
|
try{
|
|
@@ -137,29 +165,29 @@ class DiodeConnection extends EventEmitter {
|
|
|
137
165
|
} else if (responseType === 'error') {
|
|
138
166
|
if (responseData.length > 1) {
|
|
139
167
|
const reason = parseReason(responseData[1]);
|
|
140
|
-
reject(
|
|
168
|
+
reject(reason);
|
|
141
169
|
} else {
|
|
142
170
|
const reason = parseReason(responseData[0]);
|
|
143
|
-
reject(
|
|
171
|
+
reject(reason);
|
|
144
172
|
}
|
|
145
173
|
} else {
|
|
146
174
|
resolve(responseData);
|
|
147
175
|
}
|
|
148
176
|
} catch (error) {
|
|
149
|
-
|
|
177
|
+
logger.error(`Error handling response: ${error}`);
|
|
150
178
|
}
|
|
151
179
|
this.pendingRequests.delete(requestId);
|
|
152
180
|
} else {
|
|
153
181
|
// This is an unsolicited message
|
|
154
|
-
|
|
182
|
+
logger.debug(`Received unsolicited message: ${makeReadable(decodedMessage)}`);
|
|
155
183
|
this.emit('unsolicited', decodedMessage);
|
|
156
184
|
}
|
|
157
185
|
} else {
|
|
158
186
|
// Invalid message format
|
|
159
|
-
|
|
187
|
+
logger.error(`Invalid message format: ${makeReadable(decodedMessage)}`);
|
|
160
188
|
}
|
|
161
189
|
} catch (error) {
|
|
162
|
-
|
|
190
|
+
logger.error(`Error decoding message: ${error}`);
|
|
163
191
|
}
|
|
164
192
|
}
|
|
165
193
|
|
|
@@ -190,67 +218,55 @@ class DiodeConnection extends EventEmitter {
|
|
|
190
218
|
|
|
191
219
|
sendCommand(commandArray) {
|
|
192
220
|
return new Promise((resolve, reject) => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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);
|
|
221
|
+
this._ensureConnected().then(() => {
|
|
222
|
+
const requestId = this._getNextRequestId();
|
|
223
|
+
// Build the message as [requestId, [commandArray]]
|
|
224
|
+
const commandWithId = [requestId, commandArray];
|
|
225
|
+
|
|
226
|
+
// Store the promise callbacks to resolve/reject later
|
|
227
|
+
this.pendingRequests.set(requestId, { resolve, reject });
|
|
228
|
+
|
|
229
|
+
const commandBuffer = RLP.encode(commandWithId);
|
|
230
|
+
const byteLength = Buffer.byteLength(commandBuffer);
|
|
231
|
+
|
|
232
|
+
// Create a 2-byte length buffer
|
|
233
|
+
const lengthBuffer = Buffer.alloc(2);
|
|
234
|
+
lengthBuffer.writeUInt16BE(byteLength, 0);
|
|
235
|
+
|
|
236
|
+
const message = Buffer.concat([lengthBuffer, commandBuffer]);
|
|
237
|
+
|
|
238
|
+
logger.debug(`Sending command with requestId ${requestId}: ${commandArray}`);
|
|
239
|
+
logger.debug(`Command buffer: ${message.toString('hex')}`);
|
|
240
|
+
|
|
241
|
+
this.socket.write(message);
|
|
242
|
+
}).catch(reject);
|
|
221
243
|
});
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
sendCommandWithSessionId(commandArray, sessionId) {
|
|
225
247
|
return new Promise((resolve, reject) => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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);
|
|
248
|
+
this._ensureConnected().then(() => {
|
|
249
|
+
const requestId = sessionId;
|
|
250
|
+
// Build the message as [requestId, [commandArray]]
|
|
251
|
+
const commandWithId = [requestId, commandArray];
|
|
252
|
+
|
|
253
|
+
// Store the promise callbacks to resolve/reject later
|
|
254
|
+
this.pendingRequests.set(requestId, { resolve, reject });
|
|
255
|
+
|
|
256
|
+
const commandBuffer = RLP.encode(commandWithId);
|
|
257
|
+
const byteLength = Buffer.byteLength(commandBuffer);
|
|
258
|
+
|
|
259
|
+
// Create a 2-byte length buffer
|
|
260
|
+
const lengthBuffer = Buffer.alloc(2);
|
|
261
|
+
lengthBuffer.writeUInt16BE(byteLength, 0);
|
|
262
|
+
|
|
263
|
+
const message = Buffer.concat([lengthBuffer, commandBuffer]);
|
|
264
|
+
|
|
265
|
+
logger.debug(`Sending command with requestId ${requestId}: ${commandArray}`);
|
|
266
|
+
logger.debug(`Command buffer: ${message.toString('hex')}`);
|
|
267
|
+
|
|
268
|
+
this.socket.write(message);
|
|
269
|
+
}).catch(reject);
|
|
254
270
|
});
|
|
255
271
|
}
|
|
256
272
|
|
|
@@ -300,7 +316,7 @@ class DiodeConnection extends EventEmitter {
|
|
|
300
316
|
|
|
301
317
|
const ecPrivateKey = ECPrivateKeyASN.decode(privateKeyOctetString, 'der');
|
|
302
318
|
privateKeyBytes = ecPrivateKey.privateKey;
|
|
303
|
-
|
|
319
|
+
logger.debug(`Private key bytes: ${privateKeyBytes.toString('hex')}`);
|
|
304
320
|
} else {
|
|
305
321
|
throw new Error('Unsupported key format. Expected EC PRIVATE KEY or PRIVATE KEY in PEM format.');
|
|
306
322
|
}
|
|
@@ -317,10 +333,10 @@ class DiodeConnection extends EventEmitter {
|
|
|
317
333
|
const addressBuffer = ethUtil.pubToAddress(publicKeyBuffer, true);
|
|
318
334
|
const address = '0x' + addressBuffer.toString('hex');
|
|
319
335
|
|
|
320
|
-
|
|
336
|
+
logger.info(`Ethereum address: ${address}`);
|
|
321
337
|
return address;
|
|
322
338
|
} catch (error) {
|
|
323
|
-
|
|
339
|
+
logger.error(`Error extracting Ethereum address: ${error}`);
|
|
324
340
|
throw error;
|
|
325
341
|
}
|
|
326
342
|
}
|
|
@@ -336,15 +352,15 @@ class DiodeConnection extends EventEmitter {
|
|
|
336
352
|
? serverCert.pubkey
|
|
337
353
|
: Buffer.from(serverCert.pubkey);
|
|
338
354
|
|
|
339
|
-
|
|
355
|
+
logger.debug(`Public key Server: ${publicKeyBuffer.toString('hex')}`);
|
|
340
356
|
|
|
341
357
|
const addressBuffer = ethUtil.pubToAddress(publicKeyBuffer, true);
|
|
342
358
|
const address = '0x' + addressBuffer.toString('hex');
|
|
343
359
|
|
|
344
|
-
|
|
360
|
+
logger.info(`Server Ethereum address: ${address}`);
|
|
345
361
|
return address;
|
|
346
362
|
} catch (error) {
|
|
347
|
-
|
|
363
|
+
logger.error(`Error extracting server Ethereum address: ${error}`);
|
|
348
364
|
throw error;
|
|
349
365
|
}
|
|
350
366
|
}
|
|
@@ -448,7 +464,7 @@ class DiodeConnection extends EventEmitter {
|
|
|
448
464
|
|
|
449
465
|
return privateKeyBytes;
|
|
450
466
|
} catch (error) {
|
|
451
|
-
|
|
467
|
+
logger.error(`Error extracting Ethereum address: ${error}`);
|
|
452
468
|
throw error;
|
|
453
469
|
}
|
|
454
470
|
}
|
|
@@ -475,17 +491,17 @@ class DiodeConnection extends EventEmitter {
|
|
|
475
491
|
// Convert each element in dataToSign to bytes32 and concatenate them
|
|
476
492
|
const encodedData = Buffer.concat(dataToSign.map(item => abi.rawEncode(['bytes32'], [item])));
|
|
477
493
|
|
|
478
|
-
|
|
494
|
+
logger.debug(`Encoded data: ${encodedData.toString('hex')}`);
|
|
479
495
|
|
|
480
|
-
|
|
496
|
+
logger.debug(`Data to sign: ${makeReadable(dataToSign)}`);
|
|
481
497
|
|
|
482
498
|
|
|
483
499
|
// Sign the data
|
|
484
500
|
const privateKey = this.getPrivateKey();
|
|
485
501
|
const msgHash = ethUtil.keccak256(encodedData);
|
|
486
|
-
|
|
502
|
+
logger.debug(`Message hash: ${msgHash.toString('hex')}`);
|
|
487
503
|
const signature = secp256k1.ecdsaSign(msgHash, privateKey);
|
|
488
|
-
|
|
504
|
+
logger.debug(`Signature: ${signature.signature.toString('hex')}`);
|
|
489
505
|
|
|
490
506
|
const signatureBuffer = Buffer.concat([
|
|
491
507
|
ethUtil.toBuffer([signature.recid]),
|
|
@@ -519,7 +535,7 @@ class DiodeConnection extends EventEmitter {
|
|
|
519
535
|
localAddress,
|
|
520
536
|
epoch
|
|
521
537
|
);
|
|
522
|
-
|
|
538
|
+
logger.debug(`Signature hex: ${signature.toString('hex')}`);
|
|
523
539
|
|
|
524
540
|
|
|
525
541
|
// Construct the ticket command
|
|
@@ -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,
|
|
11
|
+
const portForward = new BindPort(connection, 3002, 8080, "5365baf29cb7ab58de588dfc448913cb609283e2");
|
|
12
12
|
portForward.bind();
|
|
13
13
|
|
|
14
14
|
}
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "0.0.5",
|
|
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.
|
|
27
|
+
"secp256k1": "^5.0.1",
|
|
26
28
|
"tls": "^0.0.1"
|
|
27
29
|
}
|
|
28
30
|
}
|
package/publishPort.js
CHANGED
|
@@ -8,6 +8,8 @@ const { Buffer } = require('buffer');
|
|
|
8
8
|
const EventEmitter = require('events');
|
|
9
9
|
const { Duplex } = require('stream');
|
|
10
10
|
const DiodeRPC = require('./rpc');
|
|
11
|
+
const { makeReadable } = require('./utils');
|
|
12
|
+
const logger = require('./logger');
|
|
11
13
|
|
|
12
14
|
class DiodeSocket extends Duplex {
|
|
13
15
|
constructor(ref, rpc) {
|
|
@@ -37,7 +39,7 @@ class PublishPort extends EventEmitter {
|
|
|
37
39
|
constructor(connection, publishedPorts, certPath) {
|
|
38
40
|
super();
|
|
39
41
|
this.connection = connection;
|
|
40
|
-
this.publishedPorts = publishedPorts; //
|
|
42
|
+
this.publishedPorts = new Set(publishedPorts); // Convert array to a Set
|
|
41
43
|
this.connections = new Map(); // Map to store active connections
|
|
42
44
|
this.startListening();
|
|
43
45
|
this.rpc = new DiodeRPC(connection);
|
|
@@ -58,7 +60,7 @@ class PublishPort extends EventEmitter {
|
|
|
58
60
|
} else if (messageType === 'portclose') {
|
|
59
61
|
this.handlePortClose(sessionIdRaw, messageContent);
|
|
60
62
|
} else {
|
|
61
|
-
|
|
63
|
+
logger.warn(`Unknown unsolicited message type: ${messageType}`);
|
|
62
64
|
}
|
|
63
65
|
});
|
|
64
66
|
}
|
|
@@ -70,19 +72,30 @@ class PublishPort extends EventEmitter {
|
|
|
70
72
|
const deviceIdRaw = messageContent[3];
|
|
71
73
|
|
|
72
74
|
const sessionId = Buffer.from(sessionIdRaw);
|
|
73
|
-
const portString =
|
|
75
|
+
const portString = makeReadable(portStringRaw);
|
|
74
76
|
const ref = Buffer.from(refRaw);
|
|
75
77
|
const deviceId = Buffer.from(deviceIdRaw).toString('hex');
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
logger.info(`Received portopen request for portString ${portString} with ref ${ref.toString('hex')} from device ${deviceId}`);
|
|
78
80
|
|
|
79
81
|
// Extract protocol and port number from portString
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
var protocol = 'tcp';
|
|
83
|
+
var port = 0;
|
|
84
|
+
if (typeof portString == 'number') {
|
|
85
|
+
port = portString;
|
|
86
|
+
} else {
|
|
87
|
+
var [protocol, portStr] = portString.split(':');
|
|
88
|
+
console.log(`Protocol: ${protocol}, Port: ${portStr}`);
|
|
89
|
+
if (!portStr) {
|
|
90
|
+
portStr = protocol;
|
|
91
|
+
protocol = 'tcp';
|
|
92
|
+
}
|
|
93
|
+
port = parseInt(portStr, 10);
|
|
94
|
+
}
|
|
82
95
|
|
|
83
96
|
// Check if the port is published
|
|
84
|
-
if (!this.publishedPorts.
|
|
85
|
-
|
|
97
|
+
if (!this.publishedPorts.has(port)) { // Use .has() instead of .includes()
|
|
98
|
+
logger.warn(`Port ${port} is not published. Rejecting request.`);
|
|
86
99
|
// Send error response
|
|
87
100
|
this.rpc.sendError(sessionId, ref, 'Port is not published');
|
|
88
101
|
return;
|
|
@@ -96,7 +109,7 @@ class PublishPort extends EventEmitter {
|
|
|
96
109
|
} else if (protocol === 'udp') {
|
|
97
110
|
this.handleUDPConnection(sessionId, ref, port);
|
|
98
111
|
} else {
|
|
99
|
-
|
|
112
|
+
logger.warn(`Unsupported protocol: ${protocol}`);
|
|
100
113
|
this.rpc.sendError(sessionId, ref, `Unsupported protocol: ${protocol}`);
|
|
101
114
|
}
|
|
102
115
|
}
|
|
@@ -111,14 +124,14 @@ class PublishPort extends EventEmitter {
|
|
|
111
124
|
});
|
|
112
125
|
|
|
113
126
|
localSocket.on('end', () => {
|
|
114
|
-
|
|
127
|
+
logger.info(`Local service disconnected`);
|
|
115
128
|
// Send portclose message to Diode
|
|
116
129
|
this.rpc.portClose(ref);
|
|
117
130
|
this.connections.delete(ref.toString('hex'));
|
|
118
131
|
});
|
|
119
132
|
|
|
120
133
|
localSocket.on('error', (err) => {
|
|
121
|
-
|
|
134
|
+
logger.error(`Error with local service: ${err}`);
|
|
122
135
|
// Send portclose message to Diode
|
|
123
136
|
this.rpc.portClose(ref);
|
|
124
137
|
this.connections.delete(ref.toString('hex'));
|
|
@@ -129,7 +142,7 @@ class PublishPort extends EventEmitter {
|
|
|
129
142
|
handleTCPConnection(sessionId, ref, port) {
|
|
130
143
|
// Create a TCP connection to the local service on the specified port
|
|
131
144
|
const localSocket = net.connect({ port: port }, () => {
|
|
132
|
-
|
|
145
|
+
logger.info(`Connected to local TCP service on port ${port}`);
|
|
133
146
|
// Send success response
|
|
134
147
|
this.rpc.sendResponse(sessionId, ref, 'ok');
|
|
135
148
|
});
|
|
@@ -164,7 +177,7 @@ class PublishPort extends EventEmitter {
|
|
|
164
177
|
|
|
165
178
|
// Connect to the local service (TCP or TLS as needed)
|
|
166
179
|
const localSocket = net.connect({ port: port }, () => {
|
|
167
|
-
|
|
180
|
+
logger.info(`Connected to local TCP service on port ${port}`);
|
|
168
181
|
// Send success response
|
|
169
182
|
this.rpc.sendResponse(sessionId, ref, 'ok');
|
|
170
183
|
});
|
|
@@ -174,7 +187,7 @@ class PublishPort extends EventEmitter {
|
|
|
174
187
|
|
|
175
188
|
// Handle errors and cleanup
|
|
176
189
|
tlsSocket.on('error', (err) => {
|
|
177
|
-
|
|
190
|
+
logger.error(`TLS Socket error: ${err}`);
|
|
178
191
|
this.rpc.portClose(ref);
|
|
179
192
|
this.connections.delete(ref.toString('hex'));
|
|
180
193
|
});
|
|
@@ -210,6 +223,8 @@ class PublishPort extends EventEmitter {
|
|
|
210
223
|
remoteInfo,
|
|
211
224
|
});
|
|
212
225
|
|
|
226
|
+
logger.info(`UDP connection set up on port ${port}`);
|
|
227
|
+
|
|
213
228
|
// Handle messages from the local UDP service
|
|
214
229
|
localSocket.on('message', (msg, rinfo) => {
|
|
215
230
|
//need to add 4 bytes of data length to the beginning of the message but it's Big Endian
|
|
@@ -221,7 +236,7 @@ class PublishPort extends EventEmitter {
|
|
|
221
236
|
});
|
|
222
237
|
|
|
223
238
|
localSocket.on('error', (err) => {
|
|
224
|
-
|
|
239
|
+
logger.error(`UDP Socket error: ${err}`);
|
|
225
240
|
this.rpc.portClose(ref);
|
|
226
241
|
this.connections.delete(ref.toString('hex'));
|
|
227
242
|
});
|
|
@@ -233,7 +248,7 @@ class PublishPort extends EventEmitter {
|
|
|
233
248
|
|
|
234
249
|
const sessionId = Buffer.from(sessionIdRaw);
|
|
235
250
|
const ref = Buffer.from(refRaw);
|
|
236
|
-
const data = Buffer.from(dataRaw)
|
|
251
|
+
const data = Buffer.from(dataRaw)//.slice(4);
|
|
237
252
|
|
|
238
253
|
const connectionInfo = this.connections.get(ref.toString('hex'));
|
|
239
254
|
if (connectionInfo) {
|
|
@@ -262,7 +277,7 @@ class PublishPort extends EventEmitter {
|
|
|
262
277
|
diodeSocket.pushData(data);
|
|
263
278
|
}
|
|
264
279
|
} else {
|
|
265
|
-
|
|
280
|
+
logger.warn(`No local connection found for ref ${ref.toString('hex')}. Sending portclose.`);
|
|
266
281
|
this.rpc.sendError(sessionId, ref, 'No local connection found');
|
|
267
282
|
}
|
|
268
283
|
}
|
|
@@ -272,7 +287,7 @@ class PublishPort extends EventEmitter {
|
|
|
272
287
|
const sessionId = Buffer.from(sessionIdRaw);
|
|
273
288
|
const ref = Buffer.from(refRaw);
|
|
274
289
|
|
|
275
|
-
|
|
290
|
+
logger.info(`Received portclose for ref ${ref.toString('hex')}`);
|
|
276
291
|
|
|
277
292
|
const connectionInfo = this.connections.get(ref.toString('hex'));
|
|
278
293
|
if (connectionInfo) {
|
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,36 +25,49 @@ 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;
|
|
30
|
+
}).catch((error) => {
|
|
31
|
+
logger.error(`Error during get block peak: ${error}`);
|
|
32
|
+
return;
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
getBlockHeader(index) {
|
|
31
36
|
return this.connection.sendCommand(['getblockheader', index]).then((responseData) => {
|
|
32
37
|
return responseData[0]; // block_header
|
|
38
|
+
}).catch((error) => {
|
|
39
|
+
logger.error(`Error during get block header: ${error}`);
|
|
40
|
+
return;
|
|
33
41
|
});
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
getBlock(index) {
|
|
37
45
|
return this.connection.sendCommand(['getblock', index]).then((responseData) => {
|
|
38
46
|
return responseData[0]; // block
|
|
47
|
+
}).catch((error) => {
|
|
48
|
+
logger.error(`Error during get block: ${error}`);
|
|
49
|
+
return;
|
|
39
50
|
});
|
|
40
51
|
}
|
|
41
52
|
|
|
42
53
|
ping() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
});
|
|
54
|
+
return this.connection.sendCommand(['ping']).then((responseData) => {
|
|
55
|
+
// responseData is an array containing [status]
|
|
56
|
+
const statusRaw = responseData[0];
|
|
57
|
+
const status = parseResponseType(statusRaw);
|
|
58
|
+
|
|
59
|
+
if (status === 'pong') {
|
|
60
|
+
return true;
|
|
61
|
+
} else if (status === 'error') {
|
|
62
|
+
throw new Error('Ping failed');
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error(`Unknown status in response: '${status}'`);
|
|
56
65
|
}
|
|
66
|
+
}).catch((error) => {
|
|
67
|
+
logger.error(`Error during ping: ${error}`);
|
|
68
|
+
return false;
|
|
69
|
+
})
|
|
70
|
+
}
|
|
57
71
|
|
|
58
72
|
|
|
59
73
|
|
|
@@ -77,6 +91,9 @@ class DiodeRPC {
|
|
|
77
91
|
} else {
|
|
78
92
|
throw new Error(`Unknown status in response: '${status}'`);
|
|
79
93
|
}
|
|
94
|
+
}).catch((error) => {
|
|
95
|
+
logger.error(`Error during port open: ${error}`);
|
|
96
|
+
return;
|
|
80
97
|
});
|
|
81
98
|
}
|
|
82
99
|
|
|
@@ -94,10 +111,13 @@ class DiodeRPC {
|
|
|
94
111
|
if (status === 'ok') {
|
|
95
112
|
try {
|
|
96
113
|
const ticketCommand = await this.connection.createTicketCommand();
|
|
97
|
-
const ticketResponse = await this.connection.sendCommand(ticketCommand)
|
|
98
|
-
|
|
114
|
+
const ticketResponse = await this.connection.sendCommand(ticketCommand).catch((error) => {
|
|
115
|
+
logger.error(`Error during ticket command: ${error}`);
|
|
116
|
+
throw error;
|
|
117
|
+
});
|
|
118
|
+
logger.debug(`Ticket updated: ${makeReadable(ticketResponse)}`);
|
|
99
119
|
} catch (error) {
|
|
100
|
-
|
|
120
|
+
logger.error(`Error updating ticket: ${error}`);
|
|
101
121
|
throw error;
|
|
102
122
|
}
|
|
103
123
|
return;
|
|
@@ -106,6 +126,9 @@ class DiodeRPC {
|
|
|
106
126
|
} else {
|
|
107
127
|
throw new Error(`Unknown status in response: '${status}'`);
|
|
108
128
|
}
|
|
129
|
+
}).catch((error) => {
|
|
130
|
+
logger.error(`Error during port send: ${error}`);
|
|
131
|
+
return;
|
|
109
132
|
});
|
|
110
133
|
}
|
|
111
134
|
|
|
@@ -124,24 +147,33 @@ class DiodeRPC {
|
|
|
124
147
|
} else {
|
|
125
148
|
throw new Error(`Unknown status in response: '${status}'`);
|
|
126
149
|
}
|
|
150
|
+
}).catch((error) => {
|
|
151
|
+
logger.error(`Error during port close: ${error}`);
|
|
152
|
+
return;
|
|
127
153
|
});
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
sendError(sessionId, ref, error) {
|
|
131
|
-
return this.connection.sendCommandWithSessionId(['response', ref, 'error', error], sessionId)
|
|
157
|
+
return this.connection.sendCommandWithSessionId(['response', ref, 'error', error], sessionId).catch((error) => {
|
|
158
|
+
logger.error(`Error during send error: ${error}`);
|
|
159
|
+
return;
|
|
160
|
+
});
|
|
132
161
|
}
|
|
133
162
|
|
|
134
163
|
sendResponse(sessionId, ref, response) {
|
|
135
|
-
return this.connection.sendCommandWithSessionId(['response', ref, response], sessionId)
|
|
164
|
+
return this.connection.sendCommandWithSessionId(['response', ref, response], sessionId).catch((error) => {
|
|
165
|
+
logger.error(`Error during send response: ${error}`);
|
|
166
|
+
return;
|
|
167
|
+
});
|
|
136
168
|
}
|
|
137
169
|
|
|
138
170
|
async getEpoch() {
|
|
139
171
|
const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
|
|
140
172
|
if (this.epochCache.expiry && this.epochCache.expiry > currentTime) {
|
|
141
|
-
|
|
173
|
+
logger.debug(`Using cached epoch: ${this.epochCache.epoch}`);
|
|
142
174
|
return this.epochCache.epoch;
|
|
143
175
|
}
|
|
144
|
-
|
|
176
|
+
logger.debug(`Fetching new epoch. Expiry: ${this.epochCache.expiry}, Current time: ${currentTime}`);
|
|
145
177
|
const blockPeak = await this.getBlockPeak();
|
|
146
178
|
const blockHeader = await this.getBlockHeader(blockPeak);
|
|
147
179
|
|
|
@@ -175,4 +207,3 @@ class DiodeRPC {
|
|
|
175
207
|
}
|
|
176
208
|
|
|
177
209
|
module.exports = DiodeRPC;
|
|
178
|
-
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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 };
|