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/lib/index.js
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.connect = exports.Server = exports.Socket = exports.BlockList = exports.SocketAddress = void 0;
|
|
36
|
+
exports.tls = exports.connect = exports.Server = exports.Socket = exports.BlockList = exports.SocketAddress = void 0;
|
|
4
37
|
exports.createConnection = createConnection;
|
|
5
38
|
exports.createServer = createServer;
|
|
6
39
|
exports.isIP = isIP;
|
|
@@ -219,13 +252,14 @@ class Socket extends readable_stream_1.Duplex {
|
|
|
219
252
|
return;
|
|
220
253
|
const id = this._driver.id ?? this._driver._id;
|
|
221
254
|
this._driver.onEvent = (eventType, data) => {
|
|
255
|
+
this.emit('event', eventType, data);
|
|
222
256
|
if (eventType === 3) { // ERROR
|
|
223
257
|
const msg = new TextDecoder().decode(data);
|
|
224
258
|
debugLog(`Socket (id: ${id}) NATIVE ERROR: ${msg}`);
|
|
225
259
|
}
|
|
226
|
-
if (eventType === 9) { // DEBUG
|
|
227
|
-
|
|
228
|
-
|
|
260
|
+
if (eventType === 9) { // SESSION/DEBUG
|
|
261
|
+
debugLog(`Socket (id: ${id}) NATIVE SESSION EVENT RECEIVED`);
|
|
262
|
+
this.emit('session', data);
|
|
229
263
|
return;
|
|
230
264
|
}
|
|
231
265
|
debugLog(`Socket (id: ${id}, localPort: ${this.localPort}) Event TYPE: ${eventType}, data len: ${data?.byteLength}`);
|
|
@@ -635,8 +669,8 @@ class Server extends eventemitter3_1.EventEmitter {
|
|
|
635
669
|
this.emit('error', new Error(data ? react_native_nitro_buffer_1.Buffer.from(data).toString() : 'Unknown server error'));
|
|
636
670
|
break;
|
|
637
671
|
case Net_nitro_1.NetServerEvent.DEBUG: {
|
|
638
|
-
|
|
639
|
-
|
|
672
|
+
debugLog(`Server NATIVE SESSION/DEBUG EVENT RECEIVED`);
|
|
673
|
+
this.emit('session', data);
|
|
640
674
|
break;
|
|
641
675
|
}
|
|
642
676
|
case Net_nitro_1.NetServerEvent.CLOSE:
|
|
@@ -724,6 +758,12 @@ class Server extends eventemitter3_1.EventEmitter {
|
|
|
724
758
|
return this;
|
|
725
759
|
}
|
|
726
760
|
close(callback) {
|
|
761
|
+
// Destroy all active connections first
|
|
762
|
+
for (const socket of this._sockets) {
|
|
763
|
+
socket.destroy();
|
|
764
|
+
}
|
|
765
|
+
this._sockets.clear();
|
|
766
|
+
this._connections = 0;
|
|
727
767
|
this._driver.close();
|
|
728
768
|
if (callback)
|
|
729
769
|
this.once('close', callback);
|
|
@@ -763,6 +803,7 @@ exports.connect = createConnection;
|
|
|
763
803
|
function createServer(options, connectionListener) {
|
|
764
804
|
return new Server(options, connectionListener);
|
|
765
805
|
}
|
|
806
|
+
exports.tls = __importStar(require("./tls"));
|
|
766
807
|
exports.default = {
|
|
767
808
|
Socket,
|
|
768
809
|
Server,
|
package/lib/tls.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Socket, Server as NetServer, SocketOptions } from './index';
|
|
2
|
+
export interface PeerCertificate {
|
|
3
|
+
subject: {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
};
|
|
6
|
+
issuer: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
};
|
|
9
|
+
valid_from: string;
|
|
10
|
+
valid_to: string;
|
|
11
|
+
fingerprint: string;
|
|
12
|
+
fingerprint256: string;
|
|
13
|
+
serialNumber: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ConnectionOptions extends SocketOptions {
|
|
16
|
+
host?: string;
|
|
17
|
+
port?: number;
|
|
18
|
+
path?: string;
|
|
19
|
+
servername?: string;
|
|
20
|
+
rejectUnauthorized?: boolean;
|
|
21
|
+
session?: ArrayBuffer;
|
|
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;
|
|
29
|
+
}
|
|
30
|
+
export interface SecureContextOptions {
|
|
31
|
+
pfx?: string | ArrayBuffer;
|
|
32
|
+
passphrase?: string;
|
|
33
|
+
cert?: string | string[];
|
|
34
|
+
key?: string | string[];
|
|
35
|
+
ca?: string | string[];
|
|
36
|
+
}
|
|
37
|
+
export declare const DEFAULT_MIN_VERSION = "TLSv1.2";
|
|
38
|
+
export declare const DEFAULT_MAX_VERSION = "TLSv1.3";
|
|
39
|
+
export declare const rootCertificates: string[];
|
|
40
|
+
export declare const DEFAULT_ECDH_CURVE = "auto";
|
|
41
|
+
export declare const SLAB_BUFFER_SIZE: number;
|
|
42
|
+
export declare class SecureContext {
|
|
43
|
+
private _id;
|
|
44
|
+
constructor(options?: SecureContextOptions);
|
|
45
|
+
setOCSPResponse(ocsp: ArrayBuffer): void;
|
|
46
|
+
getTicketKeys(): ArrayBuffer | undefined;
|
|
47
|
+
setTicketKeys(keys: ArrayBuffer): void;
|
|
48
|
+
get id(): number;
|
|
49
|
+
addCACert(ca: string): void;
|
|
50
|
+
}
|
|
51
|
+
export declare function createSecureContext(options?: SecureContextOptions): SecureContext;
|
|
52
|
+
export declare class TLSSocket extends Socket {
|
|
53
|
+
private _servername?;
|
|
54
|
+
get encrypted(): boolean;
|
|
55
|
+
get servername(): string | undefined;
|
|
56
|
+
get authorized(): boolean;
|
|
57
|
+
get authorizationError(): string | undefined;
|
|
58
|
+
get alpnProtocol(): string | undefined;
|
|
59
|
+
getProtocol(): string | undefined;
|
|
60
|
+
getCipher(): {
|
|
61
|
+
name: string;
|
|
62
|
+
version: string;
|
|
63
|
+
} | undefined;
|
|
64
|
+
getPeerCertificate(detailed?: boolean): PeerCertificate | {};
|
|
65
|
+
isSessionReused(): boolean;
|
|
66
|
+
getSession(): ArrayBuffer | undefined;
|
|
67
|
+
getEphemeralKeyInfo(): string | undefined;
|
|
68
|
+
getFinished(): Buffer | undefined;
|
|
69
|
+
getPeerFinished(): Buffer | undefined;
|
|
70
|
+
getSharedSigalgs(): string | undefined;
|
|
71
|
+
renegotiate(options: any, callback: (err: Error | null) => void): boolean;
|
|
72
|
+
disableRenegotiation(): void;
|
|
73
|
+
constructor(socket: Socket, options?: ConnectionOptions);
|
|
74
|
+
constructor(options: ConnectionOptions);
|
|
75
|
+
connect(options: any, connectionListener?: () => void): this;
|
|
76
|
+
}
|
|
77
|
+
export declare function connect(options: ConnectionOptions, connectionListener?: () => void): TLSSocket;
|
|
78
|
+
export declare function connect(port: number, host?: string, options?: ConnectionOptions, connectionListener?: () => void): TLSSocket;
|
|
79
|
+
export declare function connect(port: number, options?: ConnectionOptions, connectionListener?: () => void): TLSSocket;
|
|
80
|
+
export declare class Server extends NetServer {
|
|
81
|
+
private _secureContextId;
|
|
82
|
+
constructor(options?: any, connectionListener?: (socket: Socket) => void);
|
|
83
|
+
addContext(hostname: string, context: {
|
|
84
|
+
key: string;
|
|
85
|
+
cert: string;
|
|
86
|
+
}): void;
|
|
87
|
+
setSecureContext(options: {
|
|
88
|
+
key: string;
|
|
89
|
+
cert: string;
|
|
90
|
+
ca?: string | string[];
|
|
91
|
+
}): void;
|
|
92
|
+
getTicketKeys(): ArrayBuffer | undefined;
|
|
93
|
+
setTicketKeys(keys: ArrayBuffer): void;
|
|
94
|
+
listen(port?: any, host?: any, backlog?: any, callback?: any): this;
|
|
95
|
+
}
|
|
96
|
+
export declare function createServer(options?: any, connectionListener?: (socket: Socket) => void): Server;
|
|
97
|
+
export declare function getCiphers(): string[];
|
|
98
|
+
export declare function checkServerIdentity(hostname: string, cert: PeerCertificate): Error | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Legacy CryptoStream for Node.js compatibility.
|
|
101
|
+
* In this implementation, it's a simple wrapper around TLSSocket.
|
|
102
|
+
*/
|
|
103
|
+
export declare class CryptoStream extends TLSSocket {
|
|
104
|
+
constructor(options?: ConnectionOptions);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Legacy SecurePair for Node.js compatibility.
|
|
108
|
+
*/
|
|
109
|
+
export declare class SecurePair {
|
|
110
|
+
cleartext: CryptoStream;
|
|
111
|
+
encrypted: CryptoStream;
|
|
112
|
+
constructor(secureContext?: SecureContext, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean);
|
|
113
|
+
}
|
|
114
|
+
export declare function createSecurePair(secureContext?: SecureContext, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair;
|
|
115
|
+
/**
|
|
116
|
+
* Legacy certificate string parser.
|
|
117
|
+
*/
|
|
118
|
+
export declare function parseCertString(certString: string): {
|
|
119
|
+
[key: string]: string;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Mock implementation of convertTLSV1CertToPEM.
|
|
123
|
+
*/
|
|
124
|
+
export declare function convertTLSV1CertToPEM(cert: string | Buffer): string;
|
package/lib/tls.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurePair = exports.CryptoStream = exports.Server = exports.TLSSocket = exports.SecureContext = exports.SLAB_BUFFER_SIZE = exports.DEFAULT_ECDH_CURVE = exports.rootCertificates = exports.DEFAULT_MAX_VERSION = exports.DEFAULT_MIN_VERSION = void 0;
|
|
4
|
+
exports.createSecureContext = createSecureContext;
|
|
5
|
+
exports.connect = connect;
|
|
6
|
+
exports.createServer = createServer;
|
|
7
|
+
exports.getCiphers = getCiphers;
|
|
8
|
+
exports.checkServerIdentity = checkServerIdentity;
|
|
9
|
+
exports.createSecurePair = createSecurePair;
|
|
10
|
+
exports.parseCertString = parseCertString;
|
|
11
|
+
exports.convertTLSV1CertToPEM = convertTLSV1CertToPEM;
|
|
12
|
+
const index_1 = require("./index");
|
|
13
|
+
const Driver_1 = require("./Driver");
|
|
14
|
+
exports.DEFAULT_MIN_VERSION = 'TLSv1.2';
|
|
15
|
+
exports.DEFAULT_MAX_VERSION = 'TLSv1.3';
|
|
16
|
+
exports.rootCertificates = [];
|
|
17
|
+
exports.DEFAULT_ECDH_CURVE = 'auto'; // Managed by rustls
|
|
18
|
+
exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB default
|
|
19
|
+
class SecureContext {
|
|
20
|
+
constructor(options) {
|
|
21
|
+
if (options && options.pfx) {
|
|
22
|
+
this._id = Driver_1.Driver.createEmptySecureContext();
|
|
23
|
+
const pfx = typeof options.pfx === 'string' ? Buffer.from(options.pfx).buffer : options.pfx;
|
|
24
|
+
Driver_1.Driver.setPFXToSecureContext(this._id, pfx, options.passphrase);
|
|
25
|
+
}
|
|
26
|
+
else if (options && options.cert && options.key) {
|
|
27
|
+
const cert = Array.isArray(options.cert) ? options.cert[0] : options.cert;
|
|
28
|
+
const key = Array.isArray(options.key) ? options.key[0] : options.key;
|
|
29
|
+
this._id = Driver_1.Driver.createSecureContext(cert, key, options.passphrase);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this._id = Driver_1.Driver.createEmptySecureContext();
|
|
33
|
+
}
|
|
34
|
+
if (options && options.ca) {
|
|
35
|
+
const cas = Array.isArray(options.ca) ? options.ca : [options.ca];
|
|
36
|
+
for (const ca of cas) {
|
|
37
|
+
Driver_1.Driver.addCACertToSecureContext(this._id, ca);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
setOCSPResponse(ocsp) {
|
|
42
|
+
Driver_1.Driver.setOCSPResponseToSecureContext(this._id, ocsp);
|
|
43
|
+
}
|
|
44
|
+
getTicketKeys() {
|
|
45
|
+
return Driver_1.Driver.getTicketKeys(this._id);
|
|
46
|
+
}
|
|
47
|
+
setTicketKeys(keys) {
|
|
48
|
+
Driver_1.Driver.setTicketKeys(this._id, keys);
|
|
49
|
+
}
|
|
50
|
+
get id() {
|
|
51
|
+
return this._id;
|
|
52
|
+
}
|
|
53
|
+
// Node.js doesn't have these on SecureContext but we might need them
|
|
54
|
+
addCACert(ca) {
|
|
55
|
+
Driver_1.Driver.addCACertToSecureContext(this._id, ca);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.SecureContext = SecureContext;
|
|
59
|
+
function createSecureContext(options) {
|
|
60
|
+
return new SecureContext(options);
|
|
61
|
+
}
|
|
62
|
+
class TLSSocket extends index_1.Socket {
|
|
63
|
+
get encrypted() {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
get servername() {
|
|
67
|
+
return this._servername;
|
|
68
|
+
}
|
|
69
|
+
get authorized() {
|
|
70
|
+
const driver = this._driver;
|
|
71
|
+
return driver.getAuthorizationError() === undefined;
|
|
72
|
+
}
|
|
73
|
+
get authorizationError() {
|
|
74
|
+
const driver = this._driver;
|
|
75
|
+
return driver.getAuthorizationError();
|
|
76
|
+
}
|
|
77
|
+
get alpnProtocol() {
|
|
78
|
+
const driver = this._driver;
|
|
79
|
+
return driver.getALPN();
|
|
80
|
+
}
|
|
81
|
+
getProtocol() {
|
|
82
|
+
const driver = this._driver;
|
|
83
|
+
return driver.getProtocol();
|
|
84
|
+
}
|
|
85
|
+
getCipher() {
|
|
86
|
+
const driver = this._driver;
|
|
87
|
+
const cipher = driver.getCipher();
|
|
88
|
+
const protocol = driver.getProtocol();
|
|
89
|
+
if (cipher) {
|
|
90
|
+
return {
|
|
91
|
+
name: cipher,
|
|
92
|
+
version: protocol || 'Unknown'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
getPeerCertificate(detailed) {
|
|
98
|
+
const driver = this._driver;
|
|
99
|
+
const json = driver.getPeerCertificateJSON();
|
|
100
|
+
if (json) {
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(json);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
console.error('Failed to parse peer certificate JSON', e);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
isSessionReused() {
|
|
111
|
+
const driver = this._driver;
|
|
112
|
+
return driver.isSessionReused();
|
|
113
|
+
}
|
|
114
|
+
getSession() {
|
|
115
|
+
const driver = this._driver;
|
|
116
|
+
return driver.getSession();
|
|
117
|
+
}
|
|
118
|
+
getEphemeralKeyInfo() {
|
|
119
|
+
const driver = this._driver;
|
|
120
|
+
return driver.getEphemeralKeyInfo();
|
|
121
|
+
}
|
|
122
|
+
getFinished() {
|
|
123
|
+
throw new Error('getFinished is not supported by rustls');
|
|
124
|
+
}
|
|
125
|
+
getPeerFinished() {
|
|
126
|
+
throw new Error('getPeerFinished is not supported by rustls');
|
|
127
|
+
}
|
|
128
|
+
getSharedSigalgs() {
|
|
129
|
+
const driver = this._driver;
|
|
130
|
+
return driver.getSharedSigalgs();
|
|
131
|
+
}
|
|
132
|
+
renegotiate(options, callback) {
|
|
133
|
+
if (callback) {
|
|
134
|
+
process.nextTick(() => callback(new Error('Renegotiation is not supported by rustls')));
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
disableRenegotiation() {
|
|
139
|
+
// No-op, already effectively disabled
|
|
140
|
+
}
|
|
141
|
+
constructor(socketOrOptions, options) {
|
|
142
|
+
let opts = {};
|
|
143
|
+
if (socketOrOptions instanceof index_1.Socket) {
|
|
144
|
+
opts = { ...options, socketDriver: socketOrOptions._driver };
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
opts = socketOrOptions || {};
|
|
148
|
+
}
|
|
149
|
+
super(opts);
|
|
150
|
+
if (socketOrOptions instanceof index_1.Socket) {
|
|
151
|
+
this._servername = socketOrOptions._servername;
|
|
152
|
+
}
|
|
153
|
+
this.on('event', (event, data) => {
|
|
154
|
+
if (event === 10 && data) { // KEYLOG
|
|
155
|
+
this.emit('keylog', Buffer.from(data));
|
|
156
|
+
}
|
|
157
|
+
else if (event === 11 && data) { // OCSP
|
|
158
|
+
this.emit('OCSPResponse', Buffer.from(data));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
connect(options, connectionListener) {
|
|
163
|
+
// Override connect to use connectTLS
|
|
164
|
+
const port = typeof options === 'number' ? options : options.port;
|
|
165
|
+
const host = (typeof options === 'object' && options.host) ? options.host : (typeof options === 'string' ? arguments[1] : 'localhost');
|
|
166
|
+
const path = (typeof options === 'object' && options.path) ? options.path : undefined;
|
|
167
|
+
const servername = (typeof options === 'object' && options.servername) ? options.servername : (path ? 'localhost' : host);
|
|
168
|
+
this._servername = servername;
|
|
169
|
+
const rejectUnauthorized = (typeof options === 'object' && options.rejectUnauthorized !== undefined) ? options.rejectUnauthorized : true;
|
|
170
|
+
const session = (typeof options === 'object' && options.session) ? options.session : undefined;
|
|
171
|
+
const driver = this._driver;
|
|
172
|
+
if (driver) {
|
|
173
|
+
this.connecting = true;
|
|
174
|
+
if (connectionListener)
|
|
175
|
+
this.once('secureConnect', connectionListener);
|
|
176
|
+
this.once('connect', () => {
|
|
177
|
+
this.emit('secureConnect');
|
|
178
|
+
});
|
|
179
|
+
if (session) {
|
|
180
|
+
driver.setSession(session);
|
|
181
|
+
}
|
|
182
|
+
const secureContext = (typeof options === 'object' && options.secureContext) ? options.secureContext : undefined;
|
|
183
|
+
let secureContextId = secureContext ? secureContext.id : undefined;
|
|
184
|
+
// If cert/key/ca provided directly, create a temporary secure context
|
|
185
|
+
if (!secureContextId && typeof options === 'object' && (options.cert || options.key || options.ca)) {
|
|
186
|
+
secureContextId = createSecureContext({
|
|
187
|
+
cert: options.cert,
|
|
188
|
+
key: options.key,
|
|
189
|
+
ca: options.ca
|
|
190
|
+
}).id;
|
|
191
|
+
}
|
|
192
|
+
if (options && options.keylog) {
|
|
193
|
+
driver.enableKeylog();
|
|
194
|
+
}
|
|
195
|
+
if (path) {
|
|
196
|
+
if (secureContextId !== undefined) {
|
|
197
|
+
driver.connectUnixTLSWithContext(path, servername, rejectUnauthorized, secureContextId);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
driver.connectUnixTLS(path, servername, rejectUnauthorized);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
if (secureContextId !== undefined) {
|
|
205
|
+
driver.connectTLSWithContext(host, port, servername, rejectUnauthorized, secureContextId);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
driver.connectTLS(host, port, servername, rejectUnauthorized);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
exports.TLSSocket = TLSSocket;
|
|
216
|
+
function connect(...args) {
|
|
217
|
+
let port;
|
|
218
|
+
let host = 'localhost';
|
|
219
|
+
let options = {};
|
|
220
|
+
let listener;
|
|
221
|
+
if (typeof args[0] === 'object') {
|
|
222
|
+
options = args[0];
|
|
223
|
+
port = options.port || 443;
|
|
224
|
+
host = options.host || 'localhost';
|
|
225
|
+
listener = args[1];
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
port = args[0];
|
|
229
|
+
if (typeof args[1] === 'string') {
|
|
230
|
+
host = args[1];
|
|
231
|
+
options = args[2] || {};
|
|
232
|
+
listener = args[3];
|
|
233
|
+
}
|
|
234
|
+
else if (typeof args[1] === 'object') {
|
|
235
|
+
options = args[1];
|
|
236
|
+
listener = args[2];
|
|
237
|
+
}
|
|
238
|
+
else if (typeof args[1] === 'function') {
|
|
239
|
+
listener = args[1];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const socket = new TLSSocket(options);
|
|
243
|
+
socket.connect({
|
|
244
|
+
port,
|
|
245
|
+
host,
|
|
246
|
+
...options
|
|
247
|
+
}, listener);
|
|
248
|
+
return socket;
|
|
249
|
+
}
|
|
250
|
+
class Server extends index_1.Server {
|
|
251
|
+
constructor(options, connectionListener) {
|
|
252
|
+
super(options);
|
|
253
|
+
this._secureContextId = 0;
|
|
254
|
+
if (options && options.secureContext) {
|
|
255
|
+
this._secureContextId = options.secureContext.id;
|
|
256
|
+
}
|
|
257
|
+
else if (options && (options.key || options.cert || options.ca)) {
|
|
258
|
+
this._secureContextId = createSecureContext({
|
|
259
|
+
cert: options.cert,
|
|
260
|
+
key: options.key,
|
|
261
|
+
ca: options.ca
|
|
262
|
+
}).id;
|
|
263
|
+
}
|
|
264
|
+
this.on('connection', (socket) => {
|
|
265
|
+
const tlsSocket = new TLSSocket(socket);
|
|
266
|
+
this.emit('secureConnection', tlsSocket);
|
|
267
|
+
});
|
|
268
|
+
this.on('session', (data) => {
|
|
269
|
+
this.emit('newSession', data);
|
|
270
|
+
});
|
|
271
|
+
if (options && options.SNICallback) {
|
|
272
|
+
console.warn("SNICallback is not supported yet, use addContext() instead");
|
|
273
|
+
}
|
|
274
|
+
if (connectionListener) {
|
|
275
|
+
this.on('secureConnection', connectionListener);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
addContext(hostname, context) {
|
|
279
|
+
if (!this._secureContextId) {
|
|
280
|
+
throw new Error("Cannot addContext to a non-TLS server. Provide initial cert/key in constructor.");
|
|
281
|
+
}
|
|
282
|
+
Driver_1.Driver.addContextToSecureContext(this._secureContextId, hostname, context.cert, context.key);
|
|
283
|
+
}
|
|
284
|
+
setSecureContext(options) {
|
|
285
|
+
this._secureContextId = createSecureContext(options).id;
|
|
286
|
+
}
|
|
287
|
+
getTicketKeys() {
|
|
288
|
+
return this._secureContextId ? Driver_1.Driver.getTicketKeys(this._secureContextId) : undefined;
|
|
289
|
+
}
|
|
290
|
+
setTicketKeys(keys) {
|
|
291
|
+
if (!this._secureContextId)
|
|
292
|
+
throw new Error("Not a TLS server");
|
|
293
|
+
Driver_1.Driver.setTicketKeys(this._secureContextId, keys);
|
|
294
|
+
}
|
|
295
|
+
listen(port, host, backlog, callback) {
|
|
296
|
+
if (!this._secureContextId) {
|
|
297
|
+
return super.listen(port, host, backlog, callback);
|
|
298
|
+
}
|
|
299
|
+
let _port = 0;
|
|
300
|
+
let _host;
|
|
301
|
+
let _backlog;
|
|
302
|
+
let _path;
|
|
303
|
+
let _callback;
|
|
304
|
+
let ipv6Only = false;
|
|
305
|
+
let reusePort = false;
|
|
306
|
+
let handle;
|
|
307
|
+
if (typeof port === 'object' && port !== null) {
|
|
308
|
+
if (typeof port.fd === 'number') {
|
|
309
|
+
handle = port;
|
|
310
|
+
_backlog = port.backlog;
|
|
311
|
+
_callback = host;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
_port = port.port;
|
|
315
|
+
_host = port.host;
|
|
316
|
+
_backlog = port.backlog;
|
|
317
|
+
_path = port.path;
|
|
318
|
+
ipv6Only = port.ipv6Only === true;
|
|
319
|
+
reusePort = port.reusePort === true;
|
|
320
|
+
_callback = host;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
_port = typeof port === 'number' ? port : (typeof port === 'string' && !isNaN(Number(port)) ? Number(port) : 0);
|
|
325
|
+
if (typeof port === 'string' && isNaN(Number(port)))
|
|
326
|
+
_path = port;
|
|
327
|
+
if (typeof host === 'string')
|
|
328
|
+
_host = host;
|
|
329
|
+
else if (typeof host === 'function')
|
|
330
|
+
_callback = host;
|
|
331
|
+
if (typeof backlog === 'number')
|
|
332
|
+
_backlog = backlog;
|
|
333
|
+
else if (typeof backlog === 'function')
|
|
334
|
+
_callback = backlog;
|
|
335
|
+
if (typeof callback === 'function')
|
|
336
|
+
_callback = callback;
|
|
337
|
+
}
|
|
338
|
+
if (_callback)
|
|
339
|
+
this.once('listening', _callback);
|
|
340
|
+
const driver = this._driver;
|
|
341
|
+
if (handle || _path) {
|
|
342
|
+
console.warn("TLS over Unix sockets/handles not fully implemented yet");
|
|
343
|
+
}
|
|
344
|
+
driver.listenTLS(_port || 0, this._secureContextId, _backlog, ipv6Only, reusePort);
|
|
345
|
+
return this;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
exports.Server = Server;
|
|
349
|
+
function createServer(options, connectionListener) {
|
|
350
|
+
return new Server(options, connectionListener);
|
|
351
|
+
}
|
|
352
|
+
function getCiphers() {
|
|
353
|
+
return [
|
|
354
|
+
'TLS_AES_128_GCM_SHA256',
|
|
355
|
+
'TLS_AES_256_GCM_SHA384',
|
|
356
|
+
'TLS_CHACHA20_POLY1305_SHA256',
|
|
357
|
+
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
|
|
358
|
+
'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
|
|
359
|
+
'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
|
|
360
|
+
'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
|
|
361
|
+
'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
|
|
362
|
+
'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256'
|
|
363
|
+
];
|
|
364
|
+
}
|
|
365
|
+
function checkServerIdentity(hostname, cert) {
|
|
366
|
+
const subject = cert.subject;
|
|
367
|
+
const dnsNames = [];
|
|
368
|
+
// In a real implementation we'd extract SANs from the cert object if available.
|
|
369
|
+
// Our PeerCertificate already has subject.CN.
|
|
370
|
+
if (subject && subject.CN) {
|
|
371
|
+
dnsNames.push(subject.CN);
|
|
372
|
+
}
|
|
373
|
+
// SANs are preferred over CN but our current peer_cert JSON might not have them exploded yet
|
|
374
|
+
// unless x509-parser logic is updated. For now, we match against CN.
|
|
375
|
+
// Wildcard matching logic:
|
|
376
|
+
const matchHash = (host, pattern) => {
|
|
377
|
+
const parts = host.split('.');
|
|
378
|
+
const patternParts = pattern.split('.');
|
|
379
|
+
if (parts.length !== patternParts.length)
|
|
380
|
+
return false;
|
|
381
|
+
for (let i = 0; i < parts.length; i++) {
|
|
382
|
+
if (patternParts[i] === '*')
|
|
383
|
+
continue;
|
|
384
|
+
if (parts[i].toLowerCase() !== patternParts[i].toLowerCase())
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
};
|
|
389
|
+
const matches = dnsNames.some(name => {
|
|
390
|
+
if (name.includes('*')) {
|
|
391
|
+
return matchHash(hostname, name);
|
|
392
|
+
}
|
|
393
|
+
return name.toLowerCase() === hostname.toLowerCase();
|
|
394
|
+
});
|
|
395
|
+
if (!matches) {
|
|
396
|
+
const err = new Error(`Hostname/IP does not match certificate's altnames: Host: ${hostname}. is not in cert's altnames: ${dnsNames.join(', ')}`);
|
|
397
|
+
err.reason = 'Host name mismatch';
|
|
398
|
+
err.host = hostname;
|
|
399
|
+
err.cert = cert;
|
|
400
|
+
return err;
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
// -----------------------------------------------------------------------------
|
|
405
|
+
// Legacy Classes & Utils
|
|
406
|
+
// -----------------------------------------------------------------------------
|
|
407
|
+
/**
|
|
408
|
+
* Legacy CryptoStream for Node.js compatibility.
|
|
409
|
+
* In this implementation, it's a simple wrapper around TLSSocket.
|
|
410
|
+
*/
|
|
411
|
+
class CryptoStream extends TLSSocket {
|
|
412
|
+
constructor(options) {
|
|
413
|
+
super(options || {});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
exports.CryptoStream = CryptoStream;
|
|
417
|
+
/**
|
|
418
|
+
* Legacy SecurePair for Node.js compatibility.
|
|
419
|
+
*/
|
|
420
|
+
class SecurePair {
|
|
421
|
+
constructor(secureContext, isServer, requestCert, rejectUnauthorized) {
|
|
422
|
+
this.cleartext = new CryptoStream();
|
|
423
|
+
this.encrypted = this.cleartext; // Logically the same in our simplified model
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
exports.SecurePair = SecurePair;
|
|
427
|
+
function createSecurePair(secureContext, isServer, requestCert, rejectUnauthorized) {
|
|
428
|
+
return new SecurePair(secureContext, isServer, requestCert, rejectUnauthorized);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Legacy certificate string parser.
|
|
432
|
+
*/
|
|
433
|
+
function parseCertString(certString) {
|
|
434
|
+
const out = {};
|
|
435
|
+
const parts = certString.split('/');
|
|
436
|
+
for (const part of parts) {
|
|
437
|
+
const [key, value] = part.split('=');
|
|
438
|
+
if (key && value)
|
|
439
|
+
out[key] = value;
|
|
440
|
+
}
|
|
441
|
+
return out;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Mock implementation of convertTLSV1CertToPEM.
|
|
445
|
+
*/
|
|
446
|
+
function convertTLSV1CertToPEM(cert) {
|
|
447
|
+
if (typeof cert === 'string' && cert.includes('BEGIN CERTIFICATE'))
|
|
448
|
+
return cert;
|
|
449
|
+
const body = (cert instanceof Buffer) ? cert.toString('base64') : Buffer.from(cert).toString('base64');
|
|
450
|
+
return `-----BEGIN CERTIFICATE-----\n${body}\n-----END CERTIFICATE-----`;
|
|
451
|
+
}
|