react-native-nitro-net 0.1.5 → 0.2.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 +56 -4
- package/android/libs/arm64-v8a/librust_c_net.so +0 -0
- package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
- package/android/libs/x86/librust_c_net.so +0 -0
- package/android/libs/x86_64/librust_c_net.so +0 -0
- package/cpp/HybridNetDriver.hpp +68 -0
- package/cpp/HybridNetServerDriver.hpp +9 -0
- package/cpp/HybridNetSocketDriver.hpp +149 -0
- package/cpp/NetBindings.hpp +52 -1
- package/ios/Frameworks/RustCNet.xcframework/Info.plist +5 -5
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
- package/lib/Net.nitro.d.ts +27 -1
- package/lib/Net.nitro.js +3 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.js +47 -6
- package/lib/tls.d.ts +124 -0
- package/lib/tls.js +451 -0
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +38 -1
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +8 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +4 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +1 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +70 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +33 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +60 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +95 -44
- package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +58 -0
- package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +6 -0
- package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +109 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +8 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +118 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +1 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +25 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +15 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +278 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +8 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +9 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +15 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +16 -0
- package/package.json +5 -3
- package/react-native-nitro-net.podspec +1 -3
- package/src/Net.nitro.ts +27 -1
- package/src/index.ts +18 -9
- package/src/tls.ts +532 -0
package/src/tls.ts
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import { Socket, Server as NetServer, SocketOptions } from './index'
|
|
2
|
+
import { Driver } from './Driver'
|
|
3
|
+
import { NetSocketDriver } from './Net.nitro'
|
|
4
|
+
|
|
5
|
+
export interface PeerCertificate {
|
|
6
|
+
subject: { [key: string]: string }
|
|
7
|
+
issuer: { [key: string]: string }
|
|
8
|
+
valid_from: string
|
|
9
|
+
valid_to: string
|
|
10
|
+
fingerprint: string
|
|
11
|
+
fingerprint256: string
|
|
12
|
+
serialNumber: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ConnectionOptions extends SocketOptions {
|
|
16
|
+
host?: string
|
|
17
|
+
port?: number
|
|
18
|
+
path?: string
|
|
19
|
+
servername?: string // SNI
|
|
20
|
+
rejectUnauthorized?: boolean
|
|
21
|
+
session?: ArrayBuffer // TLS Session ticket for resumption
|
|
22
|
+
secureContext?: SecureContext
|
|
23
|
+
ca?: string | string[]
|
|
24
|
+
cert?: string | string[]
|
|
25
|
+
key?: string | string[]
|
|
26
|
+
pfx?: string | ArrayBuffer
|
|
27
|
+
passphrase?: string
|
|
28
|
+
keylog?: boolean // Enable keylogging (SSLKEYLOGFILE format)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SecureContextOptions {
|
|
32
|
+
pfx?: string | ArrayBuffer
|
|
33
|
+
passphrase?: string
|
|
34
|
+
cert?: string | string[]
|
|
35
|
+
key?: string | string[]
|
|
36
|
+
ca?: string | string[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const DEFAULT_MIN_VERSION = 'TLSv1.2';
|
|
40
|
+
export const DEFAULT_MAX_VERSION = 'TLSv1.3';
|
|
41
|
+
export const rootCertificates: string[] = [];
|
|
42
|
+
export const DEFAULT_ECDH_CURVE = 'auto'; // Managed by rustls
|
|
43
|
+
export const SLAB_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB default
|
|
44
|
+
|
|
45
|
+
export class SecureContext {
|
|
46
|
+
private _id: number;
|
|
47
|
+
|
|
48
|
+
constructor(options?: SecureContextOptions) {
|
|
49
|
+
if (options && options.pfx) {
|
|
50
|
+
this._id = Driver.createEmptySecureContext();
|
|
51
|
+
const pfx = typeof options.pfx === 'string' ? Buffer.from(options.pfx).buffer : options.pfx;
|
|
52
|
+
Driver.setPFXToSecureContext(this._id, pfx, options.passphrase);
|
|
53
|
+
} else if (options && options.cert && options.key) {
|
|
54
|
+
const cert = Array.isArray(options.cert) ? options.cert[0] : options.cert;
|
|
55
|
+
const key = Array.isArray(options.key) ? options.key[0] : options.key;
|
|
56
|
+
this._id = Driver.createSecureContext(cert, key, options.passphrase);
|
|
57
|
+
} else {
|
|
58
|
+
this._id = Driver.createEmptySecureContext();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (options && options.ca) {
|
|
62
|
+
const cas = Array.isArray(options.ca) ? options.ca : [options.ca];
|
|
63
|
+
for (const ca of cas) {
|
|
64
|
+
Driver.addCACertToSecureContext(this._id, ca);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setOCSPResponse(ocsp: ArrayBuffer): void {
|
|
70
|
+
Driver.setOCSPResponseToSecureContext(this._id, ocsp);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getTicketKeys(): ArrayBuffer | undefined {
|
|
74
|
+
return Driver.getTicketKeys(this._id);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setTicketKeys(keys: ArrayBuffer): void {
|
|
78
|
+
Driver.setTicketKeys(this._id, keys);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get id(): number {
|
|
82
|
+
return this._id;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Node.js doesn't have these on SecureContext but we might need them
|
|
86
|
+
addCACert(ca: string): void {
|
|
87
|
+
Driver.addCACertToSecureContext(this._id, ca);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function createSecureContext(options?: SecureContextOptions): SecureContext {
|
|
92
|
+
return new SecureContext(options);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class TLSSocket extends Socket {
|
|
96
|
+
private _servername?: string
|
|
97
|
+
|
|
98
|
+
get encrypted(): boolean {
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
get servername(): string | undefined {
|
|
103
|
+
return this._servername
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get authorized(): boolean {
|
|
107
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
108
|
+
return driver.getAuthorizationError() === undefined
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get authorizationError(): string | undefined {
|
|
112
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
113
|
+
return driver.getAuthorizationError()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
get alpnProtocol(): string | undefined {
|
|
117
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
118
|
+
return driver.getALPN()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getProtocol(): string | undefined {
|
|
122
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
123
|
+
return driver.getProtocol()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getCipher(): { name: string, version: string } | undefined {
|
|
127
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
128
|
+
const cipher = driver.getCipher()
|
|
129
|
+
const protocol = driver.getProtocol()
|
|
130
|
+
if (cipher) {
|
|
131
|
+
return {
|
|
132
|
+
name: cipher,
|
|
133
|
+
version: protocol || 'Unknown'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return undefined
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getPeerCertificate(detailed?: boolean): PeerCertificate | {} {
|
|
140
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
141
|
+
const json = driver.getPeerCertificateJSON()
|
|
142
|
+
if (json) {
|
|
143
|
+
try {
|
|
144
|
+
return JSON.parse(json) as PeerCertificate
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.error('Failed to parse peer certificate JSON', e)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
isSessionReused(): boolean {
|
|
153
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
154
|
+
return driver.isSessionReused()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getSession(): ArrayBuffer | undefined {
|
|
158
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
159
|
+
return driver.getSession()
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
getEphemeralKeyInfo(): string | undefined {
|
|
163
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
164
|
+
return driver.getEphemeralKeyInfo()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
getFinished(): Buffer | undefined {
|
|
168
|
+
throw new Error('getFinished is not supported by rustls');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
getPeerFinished(): Buffer | undefined {
|
|
172
|
+
throw new Error('getPeerFinished is not supported by rustls');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getSharedSigalgs(): string | undefined {
|
|
176
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
177
|
+
return driver.getSharedSigalgs()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
renegotiate(options: any, callback: (err: Error | null) => void): boolean {
|
|
181
|
+
if (callback) {
|
|
182
|
+
process.nextTick(() => callback(new Error('Renegotiation is not supported by rustls')));
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
disableRenegotiation(): void {
|
|
188
|
+
// No-op, already effectively disabled
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
constructor(socket: Socket, options?: ConnectionOptions)
|
|
192
|
+
constructor(options: ConnectionOptions)
|
|
193
|
+
constructor(socketOrOptions: Socket | ConnectionOptions, options?: ConnectionOptions) {
|
|
194
|
+
let opts: ConnectionOptions = {}
|
|
195
|
+
if (socketOrOptions instanceof Socket) {
|
|
196
|
+
opts = { ...options, socketDriver: (socketOrOptions as any)._driver }
|
|
197
|
+
} else {
|
|
198
|
+
opts = socketOrOptions || {}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
super(opts)
|
|
202
|
+
|
|
203
|
+
if (socketOrOptions instanceof Socket) {
|
|
204
|
+
this._servername = (socketOrOptions as any)._servername
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.on('event', (event: number, data?: ArrayBuffer) => {
|
|
208
|
+
if (event === 10 && data) { // KEYLOG
|
|
209
|
+
this.emit('keylog', Buffer.from(data))
|
|
210
|
+
} else if (event === 11 && data) { // OCSP
|
|
211
|
+
this.emit('OCSPResponse', Buffer.from(data))
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
override connect(options: any, connectionListener?: () => void): this {
|
|
217
|
+
// Override connect to use connectTLS
|
|
218
|
+
const port = typeof options === 'number' ? options : options.port
|
|
219
|
+
const host = (typeof options === 'object' && options.host) ? options.host : (typeof options === 'string' ? arguments[1] : 'localhost')
|
|
220
|
+
const path = (typeof options === 'object' && options.path) ? options.path : undefined
|
|
221
|
+
const servername = (typeof options === 'object' && options.servername) ? options.servername : (path ? 'localhost' : host)
|
|
222
|
+
this._servername = servername
|
|
223
|
+
const rejectUnauthorized = (typeof options === 'object' && options.rejectUnauthorized !== undefined) ? options.rejectUnauthorized : true
|
|
224
|
+
const session = (typeof options === 'object' && options.session) ? options.session : undefined
|
|
225
|
+
|
|
226
|
+
const driver = (this as any)._driver as NetSocketDriver
|
|
227
|
+
|
|
228
|
+
if (driver) {
|
|
229
|
+
this.connecting = true;
|
|
230
|
+
if (connectionListener) this.once('secureConnect', connectionListener);
|
|
231
|
+
|
|
232
|
+
this.once('connect', () => {
|
|
233
|
+
this.emit('secureConnect')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
if (session) {
|
|
237
|
+
driver.setSession(session)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const secureContext = (typeof options === 'object' && options.secureContext) ? options.secureContext : undefined;
|
|
241
|
+
let secureContextId: number | undefined = secureContext ? secureContext.id : undefined;
|
|
242
|
+
|
|
243
|
+
// If cert/key/ca provided directly, create a temporary secure context
|
|
244
|
+
if (!secureContextId && typeof options === 'object' && (options.cert || options.key || options.ca)) {
|
|
245
|
+
secureContextId = createSecureContext({
|
|
246
|
+
cert: options.cert,
|
|
247
|
+
key: options.key,
|
|
248
|
+
ca: options.ca
|
|
249
|
+
}).id;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (options && options.keylog) {
|
|
253
|
+
driver.enableKeylog()
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (path) {
|
|
257
|
+
if (secureContextId !== undefined) {
|
|
258
|
+
driver.connectUnixTLSWithContext(path, servername, rejectUnauthorized, secureContextId)
|
|
259
|
+
} else {
|
|
260
|
+
driver.connectUnixTLS(path, servername, rejectUnauthorized)
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
if (secureContextId !== undefined) {
|
|
264
|
+
driver.connectTLSWithContext(host, port, servername, rejectUnauthorized, secureContextId)
|
|
265
|
+
} else {
|
|
266
|
+
driver.connectTLS(host, port, servername, rejectUnauthorized)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return this
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function connect(options: ConnectionOptions, connectionListener?: () => void): TLSSocket
|
|
276
|
+
export function connect(port: number, host?: string, options?: ConnectionOptions, connectionListener?: () => void): TLSSocket
|
|
277
|
+
export function connect(port: number, options?: ConnectionOptions, connectionListener?: () => void): TLSSocket
|
|
278
|
+
export function connect(...args: any[]): TLSSocket {
|
|
279
|
+
let port: number
|
|
280
|
+
let host: string = 'localhost'
|
|
281
|
+
let options: ConnectionOptions = {}
|
|
282
|
+
let listener: (() => void) | undefined
|
|
283
|
+
|
|
284
|
+
if (typeof args[0] === 'object') {
|
|
285
|
+
options = args[0]
|
|
286
|
+
port = options.port || 443
|
|
287
|
+
host = options.host || 'localhost'
|
|
288
|
+
listener = args[1]
|
|
289
|
+
} else {
|
|
290
|
+
port = args[0]
|
|
291
|
+
if (typeof args[1] === 'string') {
|
|
292
|
+
host = args[1]
|
|
293
|
+
options = args[2] || {}
|
|
294
|
+
listener = args[3]
|
|
295
|
+
} else if (typeof args[1] === 'object') {
|
|
296
|
+
options = args[1]
|
|
297
|
+
listener = args[2]
|
|
298
|
+
} else if (typeof args[1] === 'function') {
|
|
299
|
+
listener = args[1]
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const socket = new TLSSocket(options)
|
|
304
|
+
socket.connect({
|
|
305
|
+
port,
|
|
306
|
+
host,
|
|
307
|
+
...options
|
|
308
|
+
}, listener)
|
|
309
|
+
return socket
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export class Server extends NetServer {
|
|
313
|
+
private _secureContextId: number = 0;
|
|
314
|
+
|
|
315
|
+
constructor(options?: any, connectionListener?: (socket: Socket) => void) {
|
|
316
|
+
super(options);
|
|
317
|
+
|
|
318
|
+
if (options && options.secureContext) {
|
|
319
|
+
this._secureContextId = (options.secureContext as SecureContext).id;
|
|
320
|
+
} else if (options && (options.key || options.cert || options.ca)) {
|
|
321
|
+
this._secureContextId = createSecureContext({
|
|
322
|
+
cert: options.cert,
|
|
323
|
+
key: options.key,
|
|
324
|
+
ca: options.ca
|
|
325
|
+
}).id;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
this.on('connection', (socket: Socket) => {
|
|
329
|
+
const tlsSocket = new TLSSocket(socket);
|
|
330
|
+
this.emit('secureConnection', tlsSocket);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
this.on('session', (data: ArrayBuffer) => {
|
|
334
|
+
this.emit('newSession', data);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
if (options && options.SNICallback) {
|
|
338
|
+
console.warn("SNICallback is not supported yet, use addContext() instead");
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (connectionListener) {
|
|
342
|
+
this.on('secureConnection', connectionListener);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
addContext(hostname: string, context: { key: string, cert: string }): void {
|
|
347
|
+
if (!this._secureContextId) {
|
|
348
|
+
throw new Error("Cannot addContext to a non-TLS server. Provide initial cert/key in constructor.");
|
|
349
|
+
}
|
|
350
|
+
Driver.addContextToSecureContext(this._secureContextId, hostname, context.cert, context.key);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
setSecureContext(options: { key: string, cert: string, ca?: string | string[] }): void {
|
|
354
|
+
this._secureContextId = createSecureContext(options).id;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
getTicketKeys(): ArrayBuffer | undefined {
|
|
358
|
+
return this._secureContextId ? Driver.getTicketKeys(this._secureContextId) : undefined;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
setTicketKeys(keys: ArrayBuffer): void {
|
|
362
|
+
if (!this._secureContextId) throw new Error("Not a TLS server");
|
|
363
|
+
Driver.setTicketKeys(this._secureContextId, keys);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
override listen(port?: any, host?: any, backlog?: any, callback?: any): this {
|
|
367
|
+
if (!this._secureContextId) {
|
|
368
|
+
return super.listen(port, host, backlog, callback);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
let _port = 0;
|
|
372
|
+
let _host: string | undefined;
|
|
373
|
+
let _backlog: number | undefined;
|
|
374
|
+
let _path: string | undefined;
|
|
375
|
+
let _callback: (() => void) | undefined;
|
|
376
|
+
let ipv6Only = false;
|
|
377
|
+
let reusePort = false;
|
|
378
|
+
let handle: { fd?: number } | undefined;
|
|
379
|
+
|
|
380
|
+
if (typeof port === 'object' && port !== null) {
|
|
381
|
+
if (typeof port.fd === 'number') {
|
|
382
|
+
handle = port;
|
|
383
|
+
_backlog = port.backlog;
|
|
384
|
+
_callback = host;
|
|
385
|
+
} else {
|
|
386
|
+
_port = port.port;
|
|
387
|
+
_host = port.host;
|
|
388
|
+
_backlog = port.backlog;
|
|
389
|
+
_path = port.path;
|
|
390
|
+
ipv6Only = port.ipv6Only === true;
|
|
391
|
+
reusePort = port.reusePort === true;
|
|
392
|
+
_callback = host;
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
_port = typeof port === 'number' ? port : (typeof port === 'string' && !isNaN(Number(port)) ? Number(port) : 0);
|
|
396
|
+
if (typeof port === 'string' && isNaN(Number(port))) _path = port;
|
|
397
|
+
|
|
398
|
+
if (typeof host === 'string') _host = host;
|
|
399
|
+
else if (typeof host === 'function') _callback = host;
|
|
400
|
+
|
|
401
|
+
if (typeof backlog === 'number') _backlog = backlog;
|
|
402
|
+
else if (typeof backlog === 'function') _callback = backlog;
|
|
403
|
+
|
|
404
|
+
if (typeof callback === 'function') _callback = callback;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (_callback) this.once('listening', _callback);
|
|
408
|
+
|
|
409
|
+
const driver = (this as any)._driver;
|
|
410
|
+
|
|
411
|
+
if (handle || _path) {
|
|
412
|
+
console.warn("TLS over Unix sockets/handles not fully implemented yet");
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
driver.listenTLS(_port || 0, this._secureContextId, _backlog, ipv6Only, reusePort);
|
|
416
|
+
|
|
417
|
+
return this;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function createServer(options?: any, connectionListener?: (socket: Socket) => void): Server {
|
|
422
|
+
return new Server(options, connectionListener);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export function getCiphers(): string[] {
|
|
426
|
+
return [
|
|
427
|
+
'TLS_AES_128_GCM_SHA256',
|
|
428
|
+
'TLS_AES_256_GCM_SHA384',
|
|
429
|
+
'TLS_CHACHA20_POLY1305_SHA256',
|
|
430
|
+
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
|
|
431
|
+
'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
|
|
432
|
+
'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
|
|
433
|
+
'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
|
|
434
|
+
'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
|
|
435
|
+
'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256'
|
|
436
|
+
];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function checkServerIdentity(hostname: string, cert: PeerCertificate): Error | undefined {
|
|
440
|
+
const subject = cert.subject;
|
|
441
|
+
const dnsNames: string[] = [];
|
|
442
|
+
|
|
443
|
+
// In a real implementation we'd extract SANs from the cert object if available.
|
|
444
|
+
// Our PeerCertificate already has subject.CN.
|
|
445
|
+
if (subject && subject.CN) {
|
|
446
|
+
dnsNames.push(subject.CN);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// SANs are preferred over CN but our current peer_cert JSON might not have them exploded yet
|
|
450
|
+
// unless x509-parser logic is updated. For now, we match against CN.
|
|
451
|
+
// Wildcard matching logic:
|
|
452
|
+
const matchHash = (host: string, pattern: string) => {
|
|
453
|
+
const parts = host.split('.');
|
|
454
|
+
const patternParts = pattern.split('.');
|
|
455
|
+
if (parts.length !== patternParts.length) return false;
|
|
456
|
+
for (let i = 0; i < parts.length; i++) {
|
|
457
|
+
if (patternParts[i] === '*') continue;
|
|
458
|
+
if (parts[i].toLowerCase() !== patternParts[i].toLowerCase()) return false;
|
|
459
|
+
}
|
|
460
|
+
return true;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const matches = dnsNames.some(name => {
|
|
464
|
+
if (name.includes('*')) {
|
|
465
|
+
return matchHash(hostname, name);
|
|
466
|
+
}
|
|
467
|
+
return name.toLowerCase() === hostname.toLowerCase();
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
if (!matches) {
|
|
471
|
+
const err = new Error(`Hostname/IP does not match certificate's altnames: Host: ${hostname}. is not in cert's altnames: ${dnsNames.join(', ')}`);
|
|
472
|
+
(err as any).reason = 'Host name mismatch';
|
|
473
|
+
(err as any).host = hostname;
|
|
474
|
+
(err as any).cert = cert;
|
|
475
|
+
return err;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// -----------------------------------------------------------------------------
|
|
482
|
+
// Legacy Classes & Utils
|
|
483
|
+
// -----------------------------------------------------------------------------
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Legacy CryptoStream for Node.js compatibility.
|
|
487
|
+
* In this implementation, it's a simple wrapper around TLSSocket.
|
|
488
|
+
*/
|
|
489
|
+
export class CryptoStream extends TLSSocket {
|
|
490
|
+
constructor(options?: ConnectionOptions) {
|
|
491
|
+
super(options || {});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Legacy SecurePair for Node.js compatibility.
|
|
497
|
+
*/
|
|
498
|
+
export class SecurePair {
|
|
499
|
+
public cleartext: CryptoStream;
|
|
500
|
+
public encrypted: CryptoStream;
|
|
501
|
+
|
|
502
|
+
constructor(secureContext?: SecureContext, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean) {
|
|
503
|
+
this.cleartext = new CryptoStream();
|
|
504
|
+
this.encrypted = this.cleartext; // Logically the same in our simplified model
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export function createSecurePair(secureContext?: SecureContext, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair {
|
|
509
|
+
return new SecurePair(secureContext, isServer, requestCert, rejectUnauthorized);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Legacy certificate string parser.
|
|
514
|
+
*/
|
|
515
|
+
export function parseCertString(certString: string): { [key: string]: string } {
|
|
516
|
+
const out: { [key: string]: string } = {};
|
|
517
|
+
const parts = certString.split('/');
|
|
518
|
+
for (const part of parts) {
|
|
519
|
+
const [key, value] = part.split('=');
|
|
520
|
+
if (key && value) out[key] = value;
|
|
521
|
+
}
|
|
522
|
+
return out;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Mock implementation of convertTLSV1CertToPEM.
|
|
527
|
+
*/
|
|
528
|
+
export function convertTLSV1CertToPEM(cert: string | Buffer): string {
|
|
529
|
+
if (typeof cert === 'string' && cert.includes('BEGIN CERTIFICATE')) return cert;
|
|
530
|
+
const body = (cert instanceof Buffer) ? cert.toString('base64') : Buffer.from(cert).toString('base64');
|
|
531
|
+
return `-----BEGIN CERTIFICATE-----\n${body}\n-----END CERTIFICATE-----`;
|
|
532
|
+
}
|