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/README.md
CHANGED
|
@@ -5,9 +5,11 @@ Node.js `net` API implementation for React Native using [Nitro Modules](https://
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
* 🚀 **High Performance**: Built on top of Rust's `tokio` asynchronous runtime.
|
|
8
|
-
* 🤝 **Node.js Compatible**: Implements
|
|
8
|
+
* 🤝 **Node.js Compatible**: Implements standard `net` and `tls` APIs including `Socket`, `Server`, `TLSSocket`, and `SecureContext`.
|
|
9
|
+
* 🛡️ **Modern Security**: TLS implementation powered by **Rustls 0.23** (Ring provider), supporting TLS 1.2 and 1.3.
|
|
10
|
+
* 🔒 **Full TLS Support**: Support for PEM/PFX certificates, encrypted private keys, SNI, Session tickets, and 100% Node.js API surface compatibility.
|
|
9
11
|
* ⚡ **Nitro Modules**: Uses JSI for zero-overhead communication between JavaScript and Native code.
|
|
10
|
-
* 🛡️ **Robust & Stable**: Advanced fixes for
|
|
12
|
+
* 🛡️ **Robust & Stable**: Advanced fixes for port reuse, deadlocks, and DNS reliability.
|
|
11
13
|
* 📱 **Cross-Platform**: Supports both iOS and Android.
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
@@ -30,7 +32,7 @@ cd ios && pod install
|
|
|
30
32
|
|
|
31
33
|
This library uses a high-performance three-layer architecture:
|
|
32
34
|
|
|
33
|
-
1. **JavaScript Layer**: Provides
|
|
35
|
+
1. **JavaScript Layer**: Provides high-level Node.js compatible `net` and `tls` APIs using `readable-stream` and `EventEmitter`.
|
|
34
36
|
2. **C++ Bridge (Nitro)**: Handles the zero-copy orchestration between JS and Rust using Nitro Hybrid Objects and JSI.
|
|
35
37
|
3. **Rust Core**: Implements the actual networking logic using the **Tokio** asynchronous runtime, providing memory safety and high concurrency.
|
|
36
38
|
|
|
@@ -73,6 +75,31 @@ server.listen(0, '127.0.0.1', () => {
|
|
|
73
75
|
});
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
### TLS (Secure Socket)
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { tls } from 'react-native-nitro-net';
|
|
82
|
+
|
|
83
|
+
// Client connection
|
|
84
|
+
const socket = tls.connect({
|
|
85
|
+
host: 'example.com',
|
|
86
|
+
port: 443,
|
|
87
|
+
servername: 'example.com', // SNI
|
|
88
|
+
}, () => {
|
|
89
|
+
console.log('Securely connected!');
|
|
90
|
+
console.log('Protocol:', socket.getProtocol());
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Server with PFX
|
|
94
|
+
const server = tls.createServer({
|
|
95
|
+
pfx: fs.readFileSync('server.pfx'),
|
|
96
|
+
passphrase: 'your-password'
|
|
97
|
+
}, (socket) => {
|
|
98
|
+
socket.write('Secure hello!');
|
|
99
|
+
});
|
|
100
|
+
server.listen(443);
|
|
101
|
+
```
|
|
102
|
+
|
|
76
103
|
## Stability Improvements
|
|
77
104
|
|
|
78
105
|
We have implemented several critical fixes to ensure production-grade stability:
|
|
@@ -82,6 +109,11 @@ We have implemented several critical fixes to ensure production-grade stability:
|
|
|
82
109
|
* **DNS Reliability**: Automatically retries all resolved IP addresses if the first one fails to connect.
|
|
83
110
|
* **Resource Management**: Strict protective shutdown logic in Rust to prevent socket and Unix domain socket file leaks.
|
|
84
111
|
|
|
112
|
+
## Compatibility Notes
|
|
113
|
+
|
|
114
|
+
> [!IMPORTANT]
|
|
115
|
+
> **`Server.close()` Behavior**: Unlike Node.js's default behavior where `server.close()` only stops accepting new connections, this implementation **immediately destroys all active connections** when `close()` is called. This ensures clean resource release and is more intuitive for mobile applications.
|
|
116
|
+
|
|
85
117
|
## API Reference
|
|
86
118
|
|
|
87
119
|
### `net.Socket`
|
|
@@ -97,6 +129,20 @@ We have implemented several critical fixes to ensure production-grade stability:
|
|
|
97
129
|
|
|
98
130
|
**Events**: `connect`, `ready`, `data`, `error`, `close`, `timeout`, `lookup`.
|
|
99
131
|
|
|
132
|
+
### `tls.TLSSocket`
|
|
133
|
+
*Extends `net.Socket`*
|
|
134
|
+
|
|
135
|
+
| Property / Method | Description |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `authorized` | `true` if peer certificate is verified. |
|
|
138
|
+
| `getProtocol()` | Returns negotiated TLS version (e.g., "TLSv1.3"). |
|
|
139
|
+
| `getCipher()` | Returns current cipher information. |
|
|
140
|
+
| `getPeerCertificate()`| Returns detailed JSON of the peer certificate. |
|
|
141
|
+
| `getSession()` | Returns the session ticket for resumption. |
|
|
142
|
+
| `encrypted` | Always `true`. |
|
|
143
|
+
|
|
144
|
+
**Events**: `secureConnect`, `session`, `keylog`, `OCSPResponse`.
|
|
145
|
+
|
|
100
146
|
### Global APIs
|
|
101
147
|
|
|
102
148
|
| Method | Description |
|
|
@@ -110,12 +156,18 @@ We have implemented several critical fixes to ensure production-grade stability:
|
|
|
110
156
|
| Method | Description |
|
|
111
157
|
| --- | --- |
|
|
112
158
|
| `listen(options)` | Start listening. Supports `port: 0` for dynamic allocation. |
|
|
113
|
-
| `close()` | Stops the server
|
|
159
|
+
| `close()` | Stops the server and **destroys all active connections**. |
|
|
114
160
|
| `address()` | Returns the bound address (crucial for dynamic ports). |
|
|
115
161
|
| `getConnections(cb)`| Get count of active connections. |
|
|
116
162
|
|
|
117
163
|
**Events**: `listening`, `connection`, `error`, `close`.
|
|
118
164
|
|
|
165
|
+
### `tls.Server`
|
|
166
|
+
*Extends `net.Server`*
|
|
167
|
+
|
|
168
|
+
Supported methods: `listen`, `close`, `addContext`, `setTicketKeys`, `getTicketKeys`.
|
|
169
|
+
**Events**: `secureConnection`, `keylog`, `newSession`.
|
|
170
|
+
|
|
119
171
|
## Debugging
|
|
120
172
|
|
|
121
173
|
Enable verbose logging to see the internal data flow across JS, C++, and Rust:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/cpp/HybridNetDriver.hpp
CHANGED
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
#include "HybridNetServerDriver.hpp"
|
|
5
5
|
#include "HybridNetSocketDriver.hpp"
|
|
6
6
|
#include "NetManager.hpp"
|
|
7
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
8
|
+
#include <optional>
|
|
9
|
+
#include <string>
|
|
7
10
|
|
|
8
11
|
namespace margelo {
|
|
9
12
|
namespace nitro {
|
|
10
13
|
namespace net {
|
|
11
14
|
|
|
15
|
+
using namespace margelo::nitro;
|
|
16
|
+
|
|
12
17
|
class HybridNetDriver : public HybridNetDriverSpec {
|
|
13
18
|
public:
|
|
14
19
|
HybridNetDriver() : HybridObject(TAG) {}
|
|
@@ -31,6 +36,69 @@ public:
|
|
|
31
36
|
return std::make_shared<HybridNetServerDriver>();
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
double
|
|
40
|
+
createSecureContext(const std::string &cert, const std::string &key,
|
|
41
|
+
const std::optional<std::string> &passphrase) override {
|
|
42
|
+
return static_cast<double>(net_create_secure_context(
|
|
43
|
+
cert.c_str(), key.c_str(),
|
|
44
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
double createEmptySecureContext() override {
|
|
48
|
+
return static_cast<double>(net_secure_context_create());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void addCACertToSecureContext(double scId, const std::string &ca) override {
|
|
52
|
+
net_secure_context_add_ca(static_cast<uint32_t>(scId), ca.c_str());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void addContextToSecureContext(
|
|
56
|
+
double scId, const std::string &hostname, const std::string &cert,
|
|
57
|
+
const std::string &key,
|
|
58
|
+
const std::optional<std::string> &passphrase) override {
|
|
59
|
+
net_secure_context_add_context(
|
|
60
|
+
static_cast<uint32_t>(scId), hostname.c_str(), cert.c_str(),
|
|
61
|
+
key.c_str(),
|
|
62
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
void
|
|
66
|
+
setPFXToSecureContext(double scId, const std::shared_ptr<ArrayBuffer> &pfx,
|
|
67
|
+
const std::optional<std::string> &passphrase) override {
|
|
68
|
+
if (pfx) {
|
|
69
|
+
net_secure_context_set_pfx(
|
|
70
|
+
static_cast<uint32_t>(scId), pfx->data(), pfx->size(),
|
|
71
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void setOCSPResponseToSecureContext(
|
|
76
|
+
double scId, const std::shared_ptr<ArrayBuffer> &ocsp) override {
|
|
77
|
+
if (ocsp) {
|
|
78
|
+
net_secure_context_set_ocsp_response(static_cast<uint32_t>(scId),
|
|
79
|
+
ocsp->data(), ocsp->size());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
std::optional<std::shared_ptr<ArrayBuffer>>
|
|
84
|
+
getTicketKeys(double scId) override {
|
|
85
|
+
uint8_t buf[256];
|
|
86
|
+
size_t len = net_server_get_ticket_keys(static_cast<uint32_t>(scId), buf,
|
|
87
|
+
sizeof(buf));
|
|
88
|
+
if (len > 0) {
|
|
89
|
+
return ArrayBuffer::copy(buf, len);
|
|
90
|
+
}
|
|
91
|
+
return std::nullopt;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
void setTicketKeys(double scId,
|
|
95
|
+
const std::shared_ptr<ArrayBuffer> &keys) override {
|
|
96
|
+
if (keys) {
|
|
97
|
+
net_server_set_ticket_keys(static_cast<uint32_t>(scId), keys->data(),
|
|
98
|
+
keys->size());
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
34
102
|
void initWithConfig(const NetConfig &config) override {
|
|
35
103
|
uint32_t workerThreads = config.workerThreads.value_or(0);
|
|
36
104
|
NetManager::shared().initWithConfig(workerThreads);
|
|
@@ -49,6 +49,15 @@ public:
|
|
|
49
49
|
ipv6Only.value_or(false), reusePort.value_or(false));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
void listenTLS(double port, double secureContextId,
|
|
53
|
+
std::optional<double> backlog, std::optional<bool> ipv6Only,
|
|
54
|
+
std::optional<bool> reusePort) override {
|
|
55
|
+
net_listen_tls(_id, static_cast<int>(port),
|
|
56
|
+
static_cast<int>(backlog.value_or(128)),
|
|
57
|
+
ipv6Only.value_or(false), reusePort.value_or(false),
|
|
58
|
+
static_cast<uint32_t>(secureContextId));
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
void listenUnix(const std::string &path,
|
|
53
62
|
std::optional<double> backlog) override {
|
|
54
63
|
net_listen_unix(_id, path.c_str(), static_cast<int>(backlog.value_or(128)));
|
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
#include "NetBindings.hpp"
|
|
5
5
|
#include "NetManager.hpp"
|
|
6
6
|
#include <NitroModules/ArrayBuffer.hpp>
|
|
7
|
+
#include <optional>
|
|
7
8
|
#include <string>
|
|
8
9
|
|
|
9
10
|
namespace margelo {
|
|
10
11
|
namespace nitro {
|
|
11
12
|
namespace net {
|
|
12
13
|
|
|
14
|
+
using namespace margelo::nitro;
|
|
15
|
+
|
|
13
16
|
class HybridNetSocketDriver : public HybridNetSocketDriverSpec {
|
|
14
17
|
public:
|
|
15
18
|
HybridNetSocketDriver() : HybridObject(TAG) {
|
|
@@ -48,6 +51,111 @@ public:
|
|
|
48
51
|
net_connect(_id, host.c_str(), static_cast<int>(port));
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
void connectTLS(const std::string &host, double port,
|
|
55
|
+
const std::optional<std::string> &serverName,
|
|
56
|
+
std::optional<bool> rejectUnauthorized) override {
|
|
57
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : nullptr;
|
|
58
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
59
|
+
net_connect_tls(_id, host.c_str(), static_cast<int>(port), sni,
|
|
60
|
+
static_cast<int>(ru));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void connectTLSWithContext(const std::string &host, double port,
|
|
64
|
+
const std::optional<std::string> &serverName,
|
|
65
|
+
std::optional<bool> rejectUnauthorized,
|
|
66
|
+
std::optional<double> secureContextId) override {
|
|
67
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : nullptr;
|
|
68
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
69
|
+
if (secureContextId.has_value()) {
|
|
70
|
+
net_connect_tls_with_context(
|
|
71
|
+
_id, host.c_str(), static_cast<int>(port), sni, static_cast<int>(ru),
|
|
72
|
+
static_cast<uint32_t>(secureContextId.value()));
|
|
73
|
+
} else {
|
|
74
|
+
net_connect_tls(_id, host.c_str(), static_cast<int>(port), sni,
|
|
75
|
+
static_cast<int>(ru));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
std::optional<std::string> getAuthorizationError() override {
|
|
80
|
+
char buf[1024];
|
|
81
|
+
size_t len = net_get_authorization_error(_id, buf, sizeof(buf));
|
|
82
|
+
if (len > 0) {
|
|
83
|
+
return std::string(buf);
|
|
84
|
+
}
|
|
85
|
+
return std::nullopt;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
std::optional<std::string> getProtocol() override {
|
|
89
|
+
char buf[128];
|
|
90
|
+
size_t len = net_get_protocol(_id, buf, sizeof(buf));
|
|
91
|
+
if (len > 0) {
|
|
92
|
+
return std::string(buf);
|
|
93
|
+
}
|
|
94
|
+
return std::nullopt;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
std::optional<std::string> getCipher() override {
|
|
98
|
+
char buf[256];
|
|
99
|
+
size_t len = net_get_cipher(_id, buf, sizeof(buf));
|
|
100
|
+
if (len > 0) {
|
|
101
|
+
return std::string(buf);
|
|
102
|
+
}
|
|
103
|
+
return std::nullopt;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
std::optional<std::string> getALPN() override {
|
|
107
|
+
char buf[64];
|
|
108
|
+
size_t len = net_get_alpn(_id, buf, sizeof(buf));
|
|
109
|
+
if (len > 0) {
|
|
110
|
+
return std::string(buf);
|
|
111
|
+
}
|
|
112
|
+
return std::nullopt;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
std::optional<std::string> getPeerCertificateJSON() override {
|
|
116
|
+
char buf[16384];
|
|
117
|
+
size_t len = net_get_peer_certificate_json(_id, buf, sizeof(buf));
|
|
118
|
+
if (len > 0) {
|
|
119
|
+
return std::string(buf, len);
|
|
120
|
+
}
|
|
121
|
+
return std::nullopt;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
std::optional<std::string> getEphemeralKeyInfo() override {
|
|
125
|
+
char buf[512];
|
|
126
|
+
size_t len = net_get_ephemeral_key_info(_id, buf, sizeof(buf));
|
|
127
|
+
if (len > 0) {
|
|
128
|
+
return std::string(buf, len);
|
|
129
|
+
}
|
|
130
|
+
return std::nullopt;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
std::optional<std::string> getSharedSigalgs() override {
|
|
134
|
+
char buf[1024];
|
|
135
|
+
size_t len = net_get_shared_sigalgs(_id, buf, sizeof(buf));
|
|
136
|
+
if (len > 0) {
|
|
137
|
+
return std::string(buf, len);
|
|
138
|
+
}
|
|
139
|
+
return std::nullopt;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
bool isSessionReused() override { return net_is_session_reused(_id); }
|
|
143
|
+
|
|
144
|
+
std::optional<std::shared_ptr<ArrayBuffer>> getSession() override {
|
|
145
|
+
uint8_t buf[2048];
|
|
146
|
+
size_t len = net_get_session(_id, buf, sizeof(buf));
|
|
147
|
+
if (len > 0) {
|
|
148
|
+
return ArrayBuffer::copy(buf, len);
|
|
149
|
+
}
|
|
150
|
+
return std::nullopt;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void setSession(const std::shared_ptr<ArrayBuffer> &session) override {
|
|
154
|
+
if (session && session->size() > 0) {
|
|
155
|
+
net_set_session(_id, session->data(), session->size());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
51
159
|
void write(const std::shared_ptr<ArrayBuffer> &data) override {
|
|
52
160
|
if (!data)
|
|
53
161
|
return;
|
|
@@ -70,6 +178,8 @@ public:
|
|
|
70
178
|
}
|
|
71
179
|
}
|
|
72
180
|
|
|
181
|
+
void enableKeylog() override { net_socket_enable_keylog(_id); }
|
|
182
|
+
|
|
73
183
|
void setNoDelay(bool enable) override { net_set_nodelay(_id, enable); }
|
|
74
184
|
|
|
75
185
|
void setKeepAlive(bool enable, double delay) override {
|
|
@@ -107,6 +217,45 @@ public:
|
|
|
107
217
|
net_connect_unix(_id, path.c_str());
|
|
108
218
|
}
|
|
109
219
|
|
|
220
|
+
void connectUnixTLS(const std::string &path,
|
|
221
|
+
const std::optional<std::string> &serverName,
|
|
222
|
+
std::optional<bool> rejectUnauthorized) override {
|
|
223
|
+
#if !defined(__ANDROID__)
|
|
224
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : "";
|
|
225
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
226
|
+
net_connect_unix_tls(_id, path.c_str(), sni, static_cast<int>(ru));
|
|
227
|
+
#else
|
|
228
|
+
// Unix TLS not supported on Android
|
|
229
|
+
(void)path;
|
|
230
|
+
(void)serverName;
|
|
231
|
+
(void)rejectUnauthorized;
|
|
232
|
+
#endif
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void
|
|
236
|
+
connectUnixTLSWithContext(const std::string &path,
|
|
237
|
+
const std::optional<std::string> &serverName,
|
|
238
|
+
std::optional<bool> rejectUnauthorized,
|
|
239
|
+
std::optional<double> secureContextId) override {
|
|
240
|
+
#if !defined(__ANDROID__)
|
|
241
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : "";
|
|
242
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
243
|
+
if (secureContextId.has_value()) {
|
|
244
|
+
net_connect_unix_tls_with_context(
|
|
245
|
+
_id, path.c_str(), sni, static_cast<int>(ru),
|
|
246
|
+
static_cast<uint32_t>(secureContextId.value()));
|
|
247
|
+
} else {
|
|
248
|
+
net_connect_unix_tls(_id, path.c_str(), sni, static_cast<int>(ru));
|
|
249
|
+
}
|
|
250
|
+
#else
|
|
251
|
+
// Unix TLS not supported on Android
|
|
252
|
+
(void)path;
|
|
253
|
+
(void)serverName;
|
|
254
|
+
(void)rejectUnauthorized;
|
|
255
|
+
(void)secureContextId;
|
|
256
|
+
#endif
|
|
257
|
+
}
|
|
258
|
+
|
|
110
259
|
private:
|
|
111
260
|
void onNativeEvent(int type, const uint8_t *data, size_t len) {
|
|
112
261
|
if (!_onEvent)
|
package/cpp/NetBindings.hpp
CHANGED
|
@@ -21,11 +21,27 @@ void net_init_with_config(NetCallback callback, void *context,
|
|
|
21
21
|
// Socket
|
|
22
22
|
uint32_t net_create_socket();
|
|
23
23
|
void net_connect(uint32_t id, const char *host, int port);
|
|
24
|
+
void net_connect_tls(uint32_t id, const char *host, int port,
|
|
25
|
+
const char *server_name, int reject_unauthorized);
|
|
26
|
+
void net_connect_tls_with_context(uint32_t id, const char *host, int port,
|
|
27
|
+
const char *server_name,
|
|
28
|
+
int reject_unauthorized,
|
|
29
|
+
uint32_t secure_context_id);
|
|
30
|
+
size_t net_get_authorization_error(uint32_t id, char *buf, size_t len);
|
|
31
|
+
size_t net_get_protocol(uint32_t id, char *buf, size_t len);
|
|
32
|
+
size_t net_get_cipher(uint32_t id, char *buf, size_t len);
|
|
33
|
+
size_t net_get_alpn(uint32_t id, char *buf, size_t len);
|
|
34
|
+
size_t net_get_peer_certificate_json(uint32_t id, char *buf, size_t len);
|
|
35
|
+
void net_socket_enable_keylog(uint32_t id);
|
|
24
36
|
void net_write(uint32_t id, const uint8_t *data, size_t len);
|
|
25
37
|
void net_close(uint32_t id);
|
|
26
38
|
void net_destroy_socket(uint32_t id);
|
|
27
39
|
void net_socket_reset_and_destroy(uint32_t id);
|
|
28
40
|
|
|
41
|
+
// Phase 13: Advanced TLS inspection
|
|
42
|
+
size_t net_get_ephemeral_key_info(uint32_t id, char *buf, size_t len);
|
|
43
|
+
size_t net_get_shared_sigalgs(uint32_t id, char *buf, size_t len);
|
|
44
|
+
|
|
29
45
|
// New Options
|
|
30
46
|
void net_set_nodelay(uint32_t id, bool enable);
|
|
31
47
|
void net_set_keepalive(uint32_t id, bool enable, uint64_t delay_ms);
|
|
@@ -41,28 +57,63 @@ void net_pause(uint32_t id);
|
|
|
41
57
|
void net_resume(uint32_t id);
|
|
42
58
|
void net_shutdown(uint32_t id);
|
|
43
59
|
|
|
44
|
-
// IPC
|
|
60
|
+
// IPC / Unix Domain Sockets
|
|
45
61
|
void net_connect_unix(uint32_t id, const char *path);
|
|
46
62
|
void net_listen_unix(uint32_t id, const char *path, int backlog);
|
|
47
63
|
|
|
64
|
+
#if !defined(__ANDROID__)
|
|
65
|
+
// Unix-only TLS functions (not available on Android)
|
|
66
|
+
void net_connect_unix_tls(uint32_t id, const char *path,
|
|
67
|
+
const char *server_name, int reject_unauthorized);
|
|
68
|
+
void net_connect_unix_tls_with_context(uint32_t id, const char *path,
|
|
69
|
+
const char *server_name,
|
|
70
|
+
int reject_unauthorized,
|
|
71
|
+
uint32_t secure_context_id);
|
|
72
|
+
#endif
|
|
73
|
+
|
|
48
74
|
// Server
|
|
49
75
|
uint32_t net_create_server();
|
|
50
76
|
void net_listen(uint32_t id, int port, int backlog, bool ipv6_only,
|
|
51
77
|
bool reuse_port);
|
|
78
|
+
void net_listen_tls(uint32_t id, int port, int backlog, bool ipv6_only,
|
|
79
|
+
bool reuse_port, uint32_t secure_context_id);
|
|
52
80
|
void net_server_close(uint32_t id);
|
|
53
81
|
void net_destroy_server(uint32_t id);
|
|
54
82
|
void net_server_set_max_connections(uint32_t id, int max_connections);
|
|
55
83
|
size_t net_get_server_local_address(uint32_t id, char *buf, size_t len);
|
|
84
|
+
uint32_t net_create_secure_context(const char *cert_pem, const char *key_pem,
|
|
85
|
+
const char *passphrase);
|
|
86
|
+
uint32_t net_secure_context_create();
|
|
87
|
+
void net_secure_context_add_ca(uint32_t sc_id, const char *ca_pem);
|
|
88
|
+
void net_secure_context_set_cert_key(uint32_t sc_id, const char *cert_pem,
|
|
89
|
+
const char *key_pem,
|
|
90
|
+
const char *passphrase);
|
|
91
|
+
void net_secure_context_add_context(uint32_t sc_id, const char *hostname,
|
|
92
|
+
const char *cert_pem, const char *key_pem,
|
|
93
|
+
const char *passphrase);
|
|
94
|
+
void net_secure_context_set_pfx(uint32_t sc_id, const uint8_t *data, size_t len,
|
|
95
|
+
const char *passphrase);
|
|
96
|
+
void net_secure_context_set_ocsp_response(uint32_t sc_id, const uint8_t *data,
|
|
97
|
+
size_t len);
|
|
56
98
|
/// Listen on an existing file descriptor (handle)
|
|
57
99
|
/// @param id Server ID
|
|
58
100
|
/// @param fd File descriptor of an already-bound TCP listener
|
|
59
101
|
/// @param backlog Listen backlog
|
|
60
102
|
void net_listen_handle(uint32_t id, int fd, int backlog);
|
|
61
103
|
|
|
104
|
+
// Session
|
|
105
|
+
bool net_is_session_reused(uint32_t id);
|
|
106
|
+
size_t net_get_session(uint32_t id, uint8_t *buf, size_t len);
|
|
107
|
+
void net_set_session(uint32_t id, const uint8_t *ticket, size_t ticket_len);
|
|
108
|
+
size_t net_server_get_ticket_keys(uint32_t id, uint8_t *buf, size_t len);
|
|
109
|
+
void net_server_set_ticket_keys(uint32_t id, const uint8_t *keys, size_t len);
|
|
110
|
+
|
|
62
111
|
// Event Types
|
|
63
112
|
#define NET_EVENT_CONNECT 1
|
|
64
113
|
#define NET_EVENT_DATA 2
|
|
65
114
|
#define NET_EVENT_ERROR 3
|
|
66
115
|
#define NET_EVENT_CLOSE 4
|
|
67
116
|
#define NET_EVENT_CONNECTION 6
|
|
117
|
+
#define NET_EVENT_KEYLOG 10
|
|
118
|
+
#define NET_EVENT_OCSP 11
|
|
68
119
|
}
|
|
@@ -8,32 +8,32 @@
|
|
|
8
8
|
<key>BinaryPath</key>
|
|
9
9
|
<string>RustCNet.framework/RustCNet</string>
|
|
10
10
|
<key>LibraryIdentifier</key>
|
|
11
|
-
<string>ios-
|
|
11
|
+
<string>ios-arm64</string>
|
|
12
12
|
<key>LibraryPath</key>
|
|
13
13
|
<string>RustCNet.framework</string>
|
|
14
14
|
<key>SupportedArchitectures</key>
|
|
15
15
|
<array>
|
|
16
16
|
<string>arm64</string>
|
|
17
|
-
<string>x86_64</string>
|
|
18
17
|
</array>
|
|
19
18
|
<key>SupportedPlatform</key>
|
|
20
19
|
<string>ios</string>
|
|
21
|
-
<key>SupportedPlatformVariant</key>
|
|
22
|
-
<string>simulator</string>
|
|
23
20
|
</dict>
|
|
24
21
|
<dict>
|
|
25
22
|
<key>BinaryPath</key>
|
|
26
23
|
<string>RustCNet.framework/RustCNet</string>
|
|
27
24
|
<key>LibraryIdentifier</key>
|
|
28
|
-
<string>ios-
|
|
25
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
29
26
|
<key>LibraryPath</key>
|
|
30
27
|
<string>RustCNet.framework</string>
|
|
31
28
|
<key>SupportedArchitectures</key>
|
|
32
29
|
<array>
|
|
33
30
|
<string>arm64</string>
|
|
31
|
+
<string>x86_64</string>
|
|
34
32
|
</array>
|
|
35
33
|
<key>SupportedPlatform</key>
|
|
36
34
|
<string>ios</string>
|
|
35
|
+
<key>SupportedPlatformVariant</key>
|
|
36
|
+
<string>simulator</string>
|
|
37
37
|
</dict>
|
|
38
38
|
</array>
|
|
39
39
|
<key>CFBundlePackageType</key>
|
|
Binary file
|
package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet
CHANGED
|
Binary file
|
package/lib/Net.nitro.d.ts
CHANGED
|
@@ -15,7 +15,9 @@ export declare enum NetSocketEvent {
|
|
|
15
15
|
DRAIN = 5,
|
|
16
16
|
TIMEOUT = 7,
|
|
17
17
|
LOOKUP = 8,
|
|
18
|
-
|
|
18
|
+
SESSION = 9,
|
|
19
|
+
KEYLOG = 10,
|
|
20
|
+
OCSP = 11
|
|
19
21
|
}
|
|
20
22
|
export interface NetSocketDriver extends HybridObject<{
|
|
21
23
|
ios: 'swift';
|
|
@@ -23,7 +25,21 @@ export interface NetSocketDriver extends HybridObject<{
|
|
|
23
25
|
}> {
|
|
24
26
|
readonly id: number;
|
|
25
27
|
connect(host: string, port: number): void;
|
|
28
|
+
connectTLS(host: string, port: number, serverName?: string, rejectUnauthorized?: boolean): void;
|
|
29
|
+
connectTLSWithContext(host: string, port: number, serverName?: string, rejectUnauthorized?: boolean, secureContextId?: number): void;
|
|
30
|
+
getAuthorizationError(): string | undefined;
|
|
31
|
+
getProtocol(): string | undefined;
|
|
32
|
+
getCipher(): string | undefined;
|
|
33
|
+
getALPN(): string | undefined;
|
|
34
|
+
getPeerCertificateJSON(): string | undefined;
|
|
35
|
+
getEphemeralKeyInfo(): string | undefined;
|
|
36
|
+
getSharedSigalgs(): string | undefined;
|
|
37
|
+
isSessionReused(): boolean;
|
|
38
|
+
getSession(): ArrayBuffer | undefined;
|
|
39
|
+
setSession(session: ArrayBuffer): void;
|
|
26
40
|
connectUnix(path: string): void;
|
|
41
|
+
connectUnixTLS(path: string, serverName?: string, rejectUnauthorized?: boolean): void;
|
|
42
|
+
connectUnixTLSWithContext(path: string, serverName?: string, rejectUnauthorized?: boolean, secureContextId?: number): void;
|
|
27
43
|
write(data: ArrayBuffer): void;
|
|
28
44
|
pause(): void;
|
|
29
45
|
resume(): void;
|
|
@@ -31,6 +47,7 @@ export interface NetSocketDriver extends HybridObject<{
|
|
|
31
47
|
setTimeout(timeout: number): void;
|
|
32
48
|
destroy(): void;
|
|
33
49
|
resetAndDestroy(): void;
|
|
50
|
+
enableKeylog(): void;
|
|
34
51
|
setNoDelay(enable: boolean): void;
|
|
35
52
|
setKeepAlive(enable: boolean, delay: number): void;
|
|
36
53
|
getLocalAddress(): string;
|
|
@@ -49,6 +66,7 @@ export interface NetServerDriver extends HybridObject<{
|
|
|
49
66
|
}> {
|
|
50
67
|
onEvent: (event: number, data: ArrayBuffer) => void;
|
|
51
68
|
listen(port: number, backlog?: number, ipv6Only?: boolean, reusePort?: boolean): void;
|
|
69
|
+
listenTLS(port: number, secureContextId: number, backlog?: number, ipv6Only?: boolean, reusePort?: boolean): void;
|
|
52
70
|
listenUnix(path: string, backlog?: number): void;
|
|
53
71
|
/**
|
|
54
72
|
* Listen on an existing file descriptor (handle)
|
|
@@ -76,6 +94,14 @@ export interface NetDriver extends HybridObject<{
|
|
|
76
94
|
}> {
|
|
77
95
|
createSocket(id?: string): NetSocketDriver;
|
|
78
96
|
createServer(): NetServerDriver;
|
|
97
|
+
createSecureContext(cert: string, key: string, passphrase?: string): number;
|
|
98
|
+
createEmptySecureContext(): number;
|
|
99
|
+
addCACertToSecureContext(scId: number, ca: string): void;
|
|
100
|
+
addContextToSecureContext(scId: number, hostname: string, cert: string, key: string, passphrase?: string): void;
|
|
101
|
+
setPFXToSecureContext(scId: number, pfx: ArrayBuffer, passphrase?: string): void;
|
|
102
|
+
setOCSPResponseToSecureContext(scId: number, ocsp: ArrayBuffer): void;
|
|
103
|
+
getTicketKeys(scId: number): ArrayBuffer | undefined;
|
|
104
|
+
setTicketKeys(scId: number, keys: ArrayBuffer): void;
|
|
79
105
|
/**
|
|
80
106
|
* Initialize the network module with custom configuration
|
|
81
107
|
* Must be called before any other network operations
|
package/lib/Net.nitro.js
CHANGED
|
@@ -10,7 +10,9 @@ var NetSocketEvent;
|
|
|
10
10
|
NetSocketEvent[NetSocketEvent["DRAIN"] = 5] = "DRAIN";
|
|
11
11
|
NetSocketEvent[NetSocketEvent["TIMEOUT"] = 7] = "TIMEOUT";
|
|
12
12
|
NetSocketEvent[NetSocketEvent["LOOKUP"] = 8] = "LOOKUP";
|
|
13
|
-
NetSocketEvent[NetSocketEvent["
|
|
13
|
+
NetSocketEvent[NetSocketEvent["SESSION"] = 9] = "SESSION";
|
|
14
|
+
NetSocketEvent[NetSocketEvent["KEYLOG"] = 10] = "KEYLOG";
|
|
15
|
+
NetSocketEvent[NetSocketEvent["OCSP"] = 11] = "OCSP";
|
|
14
16
|
})(NetSocketEvent || (exports.NetSocketEvent = NetSocketEvent = {}));
|
|
15
17
|
var NetServerEvent;
|
|
16
18
|
(function (NetServerEvent) {
|
package/lib/index.d.ts
CHANGED
|
@@ -52,10 +52,10 @@ export interface SocketOptions extends DuplexOptions {
|
|
|
52
52
|
remoteFamily?: string;
|
|
53
53
|
}
|
|
54
54
|
export declare class Socket extends Duplex {
|
|
55
|
-
|
|
55
|
+
protected _driver: NetSocketDriver | undefined;
|
|
56
56
|
connecting: boolean;
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
protected _connected: boolean;
|
|
58
|
+
protected _hadError: boolean;
|
|
59
59
|
remoteAddress?: string;
|
|
60
60
|
remotePort?: number;
|
|
61
61
|
remoteFamily?: string;
|
|
@@ -141,6 +141,7 @@ export declare class Server extends EventEmitter {
|
|
|
141
141
|
export declare function createConnection(options: any, connectionListener?: () => void): Socket;
|
|
142
142
|
export declare const connect: typeof createConnection;
|
|
143
143
|
export declare function createServer(options?: any, connectionListener?: (socket: Socket) => void): Server;
|
|
144
|
+
export * as tls from './tls';
|
|
144
145
|
export { isIP, isIPv4, isIPv6, getDefaultAutoSelectFamily, setDefaultAutoSelectFamily, setVerbose, initWithConfig, };
|
|
145
146
|
export type { NetConfig };
|
|
146
147
|
declare const _default: {
|