@robinpath/cli 1.73.0 → 1.75.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/modules/tls.js CHANGED
@@ -1,264 +1,264 @@
1
- /**
2
- * Native TLS module for RobinPath.
3
- * TLS/SSL secure connections — required by databases, email, websockets.
4
- */
5
- import { connect as _tlsConnect, createServer as _tlsCreateServer, TLSSocket } from 'node:tls';
6
- import { readFileSync } from 'node:fs';
7
- import { resolve } from 'node:path';
8
- import { toStr, toNum, requireArgs } from './_helpers.js';
9
-
10
- const _sockets = new Map();
11
- const _servers = new Map();
12
- let _nextId = 1;
13
-
14
- export const TlsFunctions = {
15
-
16
- connect: (args) => {
17
- requireArgs('tls.connect', args, 2);
18
- const host = toStr(args[0]);
19
- const port = toNum(args[1]);
20
- const opts = args[2] && typeof args[2] === 'object' ? args[2] : {};
21
- const id = `tls_${_nextId++}`;
22
-
23
- const tlsOpts = {
24
- host,
25
- port,
26
- rejectUnauthorized: opts.rejectUnauthorized !== false,
27
- };
28
-
29
- // Optional client certificates
30
- if (opts.cert) tlsOpts.cert = readFileSync(resolve(toStr(opts.cert)));
31
- if (opts.key) tlsOpts.key = readFileSync(resolve(toStr(opts.key)));
32
- if (opts.ca) tlsOpts.ca = readFileSync(resolve(toStr(opts.ca)));
33
- if (opts.servername) tlsOpts.servername = toStr(opts.servername);
34
- if (opts.minVersion) tlsOpts.minVersion = toStr(opts.minVersion);
35
- if (opts.maxVersion) tlsOpts.maxVersion = toStr(opts.maxVersion);
36
-
37
- return new Promise((resolve, reject) => {
38
- const socket = _tlsConnect(tlsOpts, () => {
39
- _sockets.set(id, { socket, data: '' });
40
- socket.on('data', (chunk) => {
41
- const entry = _sockets.get(id);
42
- if (entry) entry.data += chunk.toString();
43
- });
44
- socket.on('end', () => { _sockets.delete(id); });
45
- socket.on('error', () => { _sockets.delete(id); });
46
- resolve(id);
47
- });
48
- socket.on('error', (err) => reject(new Error(`tls.connect: ${err.message}`)));
49
- });
50
- },
51
-
52
- send: (args) => {
53
- requireArgs('tls.send', args, 2);
54
- const id = toStr(args[0]);
55
- const data = toStr(args[1]);
56
- const entry = _sockets.get(id);
57
- if (!entry) throw new Error(`tls.send: socket ${id} not found`);
58
- return new Promise((resolve, reject) => {
59
- entry.socket.write(data, (err) => {
60
- if (err) reject(err);
61
- else resolve(true);
62
- });
63
- });
64
- },
65
-
66
- read: (args) => {
67
- requireArgs('tls.read', args, 1);
68
- const id = toStr(args[0]);
69
- const entry = _sockets.get(id);
70
- if (!entry) throw new Error(`tls.read: socket ${id} not found`);
71
- const data = entry.data;
72
- entry.data = '';
73
- return data;
74
- },
75
-
76
- close: (args) => {
77
- requireArgs('tls.close', args, 1);
78
- const id = toStr(args[0]);
79
- const entry = _sockets.get(id);
80
- if (entry) {
81
- entry.socket.destroy();
82
- _sockets.delete(id);
83
- return true;
84
- }
85
- const server = _servers.get(id);
86
- if (server) {
87
- server.close();
88
- _servers.delete(id);
89
- return true;
90
- }
91
- return false;
92
- },
93
-
94
- createServer: (args, callback) => {
95
- requireArgs('tls.createServer', args, 1);
96
- const opts = args[0];
97
- if (typeof opts !== 'object' || opts === null) {
98
- throw new Error('tls.createServer requires options: {port, cert, key}');
99
- }
100
- const port = toNum(opts.port, 443);
101
- const host = toStr(opts.host || '0.0.0.0');
102
- const id = `tlss_${_nextId++}`;
103
-
104
- const serverOpts = {};
105
- if (opts.cert) serverOpts.cert = readFileSync(resolve(toStr(opts.cert)));
106
- if (opts.key) serverOpts.key = readFileSync(resolve(toStr(opts.key)));
107
- if (opts.ca) serverOpts.ca = readFileSync(resolve(toStr(opts.ca)));
108
- if (opts.requestCert) serverOpts.requestCert = true;
109
-
110
- const server = _tlsCreateServer(serverOpts, (socket) => {
111
- const connId = `tlsc_${_nextId++}`;
112
- _sockets.set(connId, { socket, data: '' });
113
- socket.on('data', (chunk) => {
114
- const entry = _sockets.get(connId);
115
- if (entry) entry.data += chunk.toString();
116
- if (callback) callback([connId, chunk.toString()]);
117
- });
118
- socket.on('end', () => { _sockets.delete(connId); });
119
- socket.on('error', () => { _sockets.delete(connId); });
120
- });
121
-
122
- server.listen(port, host);
123
- _servers.set(id, server);
124
- return id;
125
- },
126
-
127
- getCertificate: (args) => {
128
- requireArgs('tls.getCertificate', args, 1);
129
- const id = toStr(args[0]);
130
- const entry = _sockets.get(id);
131
- if (!entry) throw new Error(`tls.getCertificate: socket ${id} not found`);
132
- const cert = entry.socket.getPeerCertificate();
133
- return {
134
- subject: cert.subject,
135
- issuer: cert.issuer,
136
- validFrom: cert.valid_from,
137
- validTo: cert.valid_to,
138
- fingerprint: cert.fingerprint,
139
- fingerprint256: cert.fingerprint256,
140
- serialNumber: cert.serialNumber
141
- };
142
- },
143
-
144
- getPeerCertificate: (args) => {
145
- requireArgs('tls.getPeerCertificate', args, 1);
146
- const id = toStr(args[0]);
147
- const entry = _sockets.get(id);
148
- if (!entry) throw new Error(`tls.getPeerCertificate: socket ${id} not found`);
149
- const cert = entry.socket.getPeerCertificate(true);
150
- return {
151
- subject: cert.subject,
152
- issuer: cert.issuer,
153
- validFrom: cert.valid_from,
154
- validTo: cert.valid_to,
155
- fingerprint: cert.fingerprint,
156
- fingerprint256: cert.fingerprint256,
157
- serialNumber: cert.serialNumber,
158
- raw: cert.raw ? cert.raw.toString('base64') : null
159
- };
160
- },
161
-
162
- isEncrypted: (args) => {
163
- requireArgs('tls.isEncrypted', args, 1);
164
- const id = toStr(args[0]);
165
- const entry = _sockets.get(id);
166
- if (!entry) return false;
167
- return entry.socket.encrypted === true;
168
- },
169
-
170
- getProtocol: (args) => {
171
- requireArgs('tls.getProtocol', args, 1);
172
- const id = toStr(args[0]);
173
- const entry = _sockets.get(id);
174
- if (!entry) throw new Error(`tls.getProtocol: socket ${id} not found`);
175
- return entry.socket.getProtocol();
176
- },
177
-
178
- getCipher: (args) => {
179
- requireArgs('tls.getCipher', args, 1);
180
- const id = toStr(args[0]);
181
- const entry = _sockets.get(id);
182
- if (!entry) throw new Error(`tls.getCipher: socket ${id} not found`);
183
- return entry.socket.getCipher();
184
- },
185
-
186
- active: () => ({
187
- sockets: Array.from(_sockets.keys()),
188
- servers: Array.from(_servers.keys())
189
- })
190
- };
191
-
192
- export const TlsFunctionMetadata = {
193
- connect: {
194
- description: 'Create a TLS/SSL connection',
195
- parameters: [
196
- { name: 'host', dataType: 'string', description: 'Hostname', formInputType: 'text', required: true },
197
- { name: 'port', dataType: 'number', description: 'Port number', formInputType: 'number', required: true },
198
- { name: 'options', dataType: 'object', description: 'TLS options: cert, key, ca, rejectUnauthorized, servername', formInputType: 'json', required: false }
199
- ],
200
- returnType: 'string', returnDescription: 'TLS socket handle ID', example: 'tls.connect "smtp.gmail.com" 465'
201
- },
202
- send: {
203
- description: 'Send data over TLS socket',
204
- parameters: [
205
- { name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true },
206
- { name: 'data', dataType: 'string', description: 'Data to send', formInputType: 'text', required: true }
207
- ],
208
- returnType: 'boolean', returnDescription: 'true on success', example: 'tls.send $sock "EHLO example.com"'
209
- },
210
- read: {
211
- description: 'Read buffered TLS data',
212
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
213
- returnType: 'string', returnDescription: 'Buffered data', example: 'tls.read $sock'
214
- },
215
- close: {
216
- description: 'Close TLS socket or server',
217
- parameters: [{ name: 'id', dataType: 'string', description: 'Socket or server handle', formInputType: 'text', required: true }],
218
- returnType: 'boolean', returnDescription: 'true if closed', example: 'tls.close $sock'
219
- },
220
- createServer: {
221
- description: 'Create a TLS server',
222
- parameters: [{ name: 'options', dataType: 'object', description: 'Server options: port, cert, key, ca', formInputType: 'json', required: true }],
223
- returnType: 'string', returnDescription: 'Server handle ID', example: 'tls.createServer {"port": 443, "cert": "cert.pem", "key": "key.pem"}'
224
- },
225
- getCertificate: {
226
- description: 'Get peer TLS certificate info',
227
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
228
- returnType: 'object', returnDescription: 'Certificate details', example: 'tls.getCertificate $sock'
229
- },
230
- getPeerCertificate: {
231
- description: 'Get full peer certificate with raw data',
232
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
233
- returnType: 'object', returnDescription: 'Full certificate object', example: 'tls.getPeerCertificate $sock'
234
- },
235
- isEncrypted: {
236
- description: 'Check if socket is TLS encrypted',
237
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
238
- returnType: 'boolean', returnDescription: 'true if encrypted', example: 'tls.isEncrypted $sock'
239
- },
240
- getProtocol: {
241
- description: 'Get TLS protocol version (e.g. TLSv1.3)',
242
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
243
- returnType: 'string', returnDescription: 'Protocol version string', example: 'tls.getProtocol $sock'
244
- },
245
- getCipher: {
246
- description: 'Get current cipher info',
247
- parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
248
- returnType: 'object', returnDescription: 'Cipher name and version', example: 'tls.getCipher $sock'
249
- },
250
- active: { description: 'List active TLS sockets and servers', parameters: [], returnType: 'object', returnDescription: '{sockets, servers}', example: 'tls.active' }
251
- };
252
-
253
- export const TlsModuleMetadata = {
254
- description: 'TLS/SSL: secure connections, certificates, encrypted client/server sockets',
255
- methods: Object.keys(TlsFunctions)
256
- };
257
-
258
- export default {
259
- name: 'tls',
260
- functions: TlsFunctions,
261
- functionMetadata: TlsFunctionMetadata,
262
- moduleMetadata: TlsModuleMetadata,
263
- global: false
264
- };
1
+ /**
2
+ * Native TLS module for RobinPath.
3
+ * TLS/SSL secure connections — required by databases, email, websockets.
4
+ */
5
+ import { connect as _tlsConnect, createServer as _tlsCreateServer, TLSSocket } from 'node:tls';
6
+ import { readFileSync } from 'node:fs';
7
+ import { resolve } from 'node:path';
8
+ import { toStr, toNum, requireArgs } from './_helpers.js';
9
+
10
+ const _sockets = new Map();
11
+ const _servers = new Map();
12
+ let _nextId = 1;
13
+
14
+ export const TlsFunctions = {
15
+
16
+ connect: (args) => {
17
+ requireArgs('tls.connect', args, 2);
18
+ const host = toStr(args[0]);
19
+ const port = toNum(args[1]);
20
+ const opts = args[2] && typeof args[2] === 'object' ? args[2] : {};
21
+ const id = `tls_${_nextId++}`;
22
+
23
+ const tlsOpts = {
24
+ host,
25
+ port,
26
+ rejectUnauthorized: opts.rejectUnauthorized !== false,
27
+ };
28
+
29
+ // Optional client certificates
30
+ if (opts.cert) tlsOpts.cert = readFileSync(resolve(toStr(opts.cert)));
31
+ if (opts.key) tlsOpts.key = readFileSync(resolve(toStr(opts.key)));
32
+ if (opts.ca) tlsOpts.ca = readFileSync(resolve(toStr(opts.ca)));
33
+ if (opts.servername) tlsOpts.servername = toStr(opts.servername);
34
+ if (opts.minVersion) tlsOpts.minVersion = toStr(opts.minVersion);
35
+ if (opts.maxVersion) tlsOpts.maxVersion = toStr(opts.maxVersion);
36
+
37
+ return new Promise((resolve, reject) => {
38
+ const socket = _tlsConnect(tlsOpts, () => {
39
+ _sockets.set(id, { socket, data: '' });
40
+ socket.on('data', (chunk) => {
41
+ const entry = _sockets.get(id);
42
+ if (entry) entry.data += chunk.toString();
43
+ });
44
+ socket.on('end', () => { _sockets.delete(id); });
45
+ socket.on('error', () => { _sockets.delete(id); });
46
+ resolve(id);
47
+ });
48
+ socket.on('error', (err) => reject(new Error(`tls.connect: ${err.message}`)));
49
+ });
50
+ },
51
+
52
+ send: (args) => {
53
+ requireArgs('tls.send', args, 2);
54
+ const id = toStr(args[0]);
55
+ const data = toStr(args[1]);
56
+ const entry = _sockets.get(id);
57
+ if (!entry) throw new Error(`tls.send: socket ${id} not found`);
58
+ return new Promise((resolve, reject) => {
59
+ entry.socket.write(data, (err) => {
60
+ if (err) reject(err);
61
+ else resolve(true);
62
+ });
63
+ });
64
+ },
65
+
66
+ read: (args) => {
67
+ requireArgs('tls.read', args, 1);
68
+ const id = toStr(args[0]);
69
+ const entry = _sockets.get(id);
70
+ if (!entry) throw new Error(`tls.read: socket ${id} not found`);
71
+ const data = entry.data;
72
+ entry.data = '';
73
+ return data;
74
+ },
75
+
76
+ close: (args) => {
77
+ requireArgs('tls.close', args, 1);
78
+ const id = toStr(args[0]);
79
+ const entry = _sockets.get(id);
80
+ if (entry) {
81
+ entry.socket.destroy();
82
+ _sockets.delete(id);
83
+ return true;
84
+ }
85
+ const server = _servers.get(id);
86
+ if (server) {
87
+ server.close();
88
+ _servers.delete(id);
89
+ return true;
90
+ }
91
+ return false;
92
+ },
93
+
94
+ createServer: (args, callback) => {
95
+ requireArgs('tls.createServer', args, 1);
96
+ const opts = args[0];
97
+ if (typeof opts !== 'object' || opts === null) {
98
+ throw new Error('tls.createServer requires options: {port, cert, key}');
99
+ }
100
+ const port = toNum(opts.port, 443);
101
+ const host = toStr(opts.host || '0.0.0.0');
102
+ const id = `tlss_${_nextId++}`;
103
+
104
+ const serverOpts = {};
105
+ if (opts.cert) serverOpts.cert = readFileSync(resolve(toStr(opts.cert)));
106
+ if (opts.key) serverOpts.key = readFileSync(resolve(toStr(opts.key)));
107
+ if (opts.ca) serverOpts.ca = readFileSync(resolve(toStr(opts.ca)));
108
+ if (opts.requestCert) serverOpts.requestCert = true;
109
+
110
+ const server = _tlsCreateServer(serverOpts, (socket) => {
111
+ const connId = `tlsc_${_nextId++}`;
112
+ _sockets.set(connId, { socket, data: '' });
113
+ socket.on('data', (chunk) => {
114
+ const entry = _sockets.get(connId);
115
+ if (entry) entry.data += chunk.toString();
116
+ if (callback) callback([connId, chunk.toString()]);
117
+ });
118
+ socket.on('end', () => { _sockets.delete(connId); });
119
+ socket.on('error', () => { _sockets.delete(connId); });
120
+ });
121
+
122
+ server.listen(port, host);
123
+ _servers.set(id, server);
124
+ return id;
125
+ },
126
+
127
+ getCertificate: (args) => {
128
+ requireArgs('tls.getCertificate', args, 1);
129
+ const id = toStr(args[0]);
130
+ const entry = _sockets.get(id);
131
+ if (!entry) throw new Error(`tls.getCertificate: socket ${id} not found`);
132
+ const cert = entry.socket.getPeerCertificate();
133
+ return {
134
+ subject: cert.subject,
135
+ issuer: cert.issuer,
136
+ validFrom: cert.valid_from,
137
+ validTo: cert.valid_to,
138
+ fingerprint: cert.fingerprint,
139
+ fingerprint256: cert.fingerprint256,
140
+ serialNumber: cert.serialNumber
141
+ };
142
+ },
143
+
144
+ getPeerCertificate: (args) => {
145
+ requireArgs('tls.getPeerCertificate', args, 1);
146
+ const id = toStr(args[0]);
147
+ const entry = _sockets.get(id);
148
+ if (!entry) throw new Error(`tls.getPeerCertificate: socket ${id} not found`);
149
+ const cert = entry.socket.getPeerCertificate(true);
150
+ return {
151
+ subject: cert.subject,
152
+ issuer: cert.issuer,
153
+ validFrom: cert.valid_from,
154
+ validTo: cert.valid_to,
155
+ fingerprint: cert.fingerprint,
156
+ fingerprint256: cert.fingerprint256,
157
+ serialNumber: cert.serialNumber,
158
+ raw: cert.raw ? cert.raw.toString('base64') : null
159
+ };
160
+ },
161
+
162
+ isEncrypted: (args) => {
163
+ requireArgs('tls.isEncrypted', args, 1);
164
+ const id = toStr(args[0]);
165
+ const entry = _sockets.get(id);
166
+ if (!entry) return false;
167
+ return entry.socket.encrypted === true;
168
+ },
169
+
170
+ getProtocol: (args) => {
171
+ requireArgs('tls.getProtocol', args, 1);
172
+ const id = toStr(args[0]);
173
+ const entry = _sockets.get(id);
174
+ if (!entry) throw new Error(`tls.getProtocol: socket ${id} not found`);
175
+ return entry.socket.getProtocol();
176
+ },
177
+
178
+ getCipher: (args) => {
179
+ requireArgs('tls.getCipher', args, 1);
180
+ const id = toStr(args[0]);
181
+ const entry = _sockets.get(id);
182
+ if (!entry) throw new Error(`tls.getCipher: socket ${id} not found`);
183
+ return entry.socket.getCipher();
184
+ },
185
+
186
+ active: () => ({
187
+ sockets: Array.from(_sockets.keys()),
188
+ servers: Array.from(_servers.keys())
189
+ })
190
+ };
191
+
192
+ export const TlsFunctionMetadata = {
193
+ connect: {
194
+ description: 'Create a TLS/SSL connection',
195
+ parameters: [
196
+ { name: 'host', dataType: 'string', description: 'Hostname', formInputType: 'text', required: true },
197
+ { name: 'port', dataType: 'number', description: 'Port number', formInputType: 'number', required: true },
198
+ { name: 'options', dataType: 'object', description: 'TLS options: cert, key, ca, rejectUnauthorized, servername', formInputType: 'json', required: false }
199
+ ],
200
+ returnType: 'string', returnDescription: 'TLS socket handle ID', example: 'tls.connect "smtp.gmail.com" 465'
201
+ },
202
+ send: {
203
+ description: 'Send data over TLS socket',
204
+ parameters: [
205
+ { name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true },
206
+ { name: 'data', dataType: 'string', description: 'Data to send', formInputType: 'text', required: true }
207
+ ],
208
+ returnType: 'boolean', returnDescription: 'true on success', example: 'tls.send $sock "EHLO example.com"'
209
+ },
210
+ read: {
211
+ description: 'Read buffered TLS data',
212
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
213
+ returnType: 'string', returnDescription: 'Buffered data', example: 'tls.read $sock'
214
+ },
215
+ close: {
216
+ description: 'Close TLS socket or server',
217
+ parameters: [{ name: 'id', dataType: 'string', description: 'Socket or server handle', formInputType: 'text', required: true }],
218
+ returnType: 'boolean', returnDescription: 'true if closed', example: 'tls.close $sock'
219
+ },
220
+ createServer: {
221
+ description: 'Create a TLS server',
222
+ parameters: [{ name: 'options', dataType: 'object', description: 'Server options: port, cert, key, ca', formInputType: 'json', required: true }],
223
+ returnType: 'string', returnDescription: 'Server handle ID', example: 'tls.createServer {"port": 443, "cert": "cert.pem", "key": "key.pem"}'
224
+ },
225
+ getCertificate: {
226
+ description: 'Get peer TLS certificate info',
227
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
228
+ returnType: 'object', returnDescription: 'Certificate details', example: 'tls.getCertificate $sock'
229
+ },
230
+ getPeerCertificate: {
231
+ description: 'Get full peer certificate with raw data',
232
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
233
+ returnType: 'object', returnDescription: 'Full certificate object', example: 'tls.getPeerCertificate $sock'
234
+ },
235
+ isEncrypted: {
236
+ description: 'Check if socket is TLS encrypted',
237
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
238
+ returnType: 'boolean', returnDescription: 'true if encrypted', example: 'tls.isEncrypted $sock'
239
+ },
240
+ getProtocol: {
241
+ description: 'Get TLS protocol version (e.g. TLSv1.3)',
242
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
243
+ returnType: 'string', returnDescription: 'Protocol version string', example: 'tls.getProtocol $sock'
244
+ },
245
+ getCipher: {
246
+ description: 'Get current cipher info',
247
+ parameters: [{ name: 'socketId', dataType: 'string', description: 'Socket handle', formInputType: 'text', required: true }],
248
+ returnType: 'object', returnDescription: 'Cipher name and version', example: 'tls.getCipher $sock'
249
+ },
250
+ active: { description: 'List active TLS sockets and servers', parameters: [], returnType: 'object', returnDescription: '{sockets, servers}', example: 'tls.active' }
251
+ };
252
+
253
+ export const TlsModuleMetadata = {
254
+ description: 'TLS/SSL: secure connections, certificates, encrypted client/server sockets',
255
+ methods: Object.keys(TlsFunctions)
256
+ };
257
+
258
+ export default {
259
+ name: 'tls',
260
+ functions: TlsFunctions,
261
+ functionMetadata: TlsFunctionMetadata,
262
+ moduleMetadata: TlsModuleMetadata,
263
+ global: false
264
+ };