wireshade 1.0.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.
@@ -0,0 +1,30 @@
1
+ const { WireShade } = require('../index');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Example: TCP Port Forwarding
6
+ * Forwards localhost:8080 -> 10.0.0.5:80 via VPN
7
+ */
8
+
9
+ async function examplePortForward() {
10
+ const gw = new WireShade(path.join(__dirname, 'wireguard.conf'));
11
+
12
+ gw.on('connect', async () => {
13
+ console.log("VPN Connected.");
14
+
15
+ try {
16
+ const server = await gw.forwardLocal(8080, '10.0.0.5', 80);
17
+
18
+ console.log(`Forwarding localhost:8080 -> 10.0.0.5:80`);
19
+ console.log("Press Ctrl+C to stop.");
20
+
21
+ // server is a net.Server
22
+ server.on('error', (e) => console.error("Server error:", e.message));
23
+
24
+ } catch (err) {
25
+ console.error("Failed to start forwarding:", err.message);
26
+ }
27
+ });
28
+ }
29
+
30
+ examplePortForward();
@@ -0,0 +1,128 @@
1
+ /**
2
+ * WireShadeClient Reconnection Demo
3
+ *
4
+ * Zeigt die automatische Reconnection-Logik mit Events und Konfiguration.
5
+ */
6
+
7
+ const { WireShade, ConnectionState } = require('../index');
8
+ const https = require('https');
9
+
10
+ const { readWireGuardConfig } = require('../lib/config_parser');
11
+ const path = require('path');
12
+
13
+ const wireguardConfig = readWireGuardConfig(path.join(__dirname, 'wireguard.conf'));
14
+
15
+ const config = {
16
+ wireguard: wireguardConfig,
17
+
18
+ logging: true,
19
+
20
+ // Reconnection configuration
21
+ reconnect: {
22
+ enabled: true, // Auto-reconnect on disconnect
23
+ maxAttempts: 5, // Max attempts (0 = infinite)
24
+ delay: 1000, // Initial delay: 1 second
25
+ maxDelay: 30000, // Max delay: 30 seconds
26
+ backoffMultiplier: 2, // Double delay each attempt
27
+ healthCheckInterval: 60000 // Check every 60 seconds
28
+ },
29
+
30
+ hosts: {
31
+ 'internal.service.lan': '10.0.0.5'
32
+ }
33
+ };
34
+
35
+ async function main() {
36
+ console.log('=== WireShadeClient Reconnection Demo ===\n');
37
+
38
+ const client = new WireShade(config);
39
+
40
+ // Event: State changes
41
+ client.on('stateChange', (state) => {
42
+ const stateEmoji = {
43
+ [ConnectionState.DISCONNECTED]: '🔴',
44
+ [ConnectionState.CONNECTING]: '🟡',
45
+ [ConnectionState.CONNECTED]: '🟢',
46
+ [ConnectionState.RECONNECTING]: '🟠'
47
+ };
48
+ console.log(`[State] ${stateEmoji[state] || '⚪'} ${state}`);
49
+ });
50
+
51
+ // Event: Connected
52
+ client.on('connect', () => {
53
+ console.log('[Event] ✅ Verbunden!');
54
+ });
55
+
56
+ // Event: Disconnected
57
+ client.on('disconnect', (err) => {
58
+ console.log('[Event] ❌ Verbindung getrennt:', err?.message || 'Unknown');
59
+ });
60
+
61
+ // Event: Reconnecting
62
+ client.on('reconnecting', (attempt) => {
63
+ console.log(`[Event] 🔄 Reconnect Versuch ${attempt}...`);
64
+ });
65
+
66
+ // Event: Reconnected
67
+ client.on('reconnect', () => {
68
+ console.log('[Event] ✅ Wiederverbunden!');
69
+ });
70
+
71
+ // Event: Reconnect failed
72
+ client.on('reconnectFailed', () => {
73
+ console.log('[Event] ❌ Reconnection fehlgeschlagen nach max Versuchen');
74
+ });
75
+
76
+ // Event: Health check
77
+ client.on('healthCheck', () => {
78
+ console.log('[Health] 💓 Health check...');
79
+ });
80
+
81
+ // Wait for initial connection
82
+ await new Promise(resolve => setTimeout(resolve, 4000));
83
+
84
+ // Test: Make a request
85
+ console.log('\n--- Test Request ---');
86
+ try {
87
+ const response = await makeRequest(client, 'https://ifconfig.me/ip');
88
+ console.log('Externe IP:', response.trim());
89
+ } catch (err) {
90
+ console.log('Request fehlgeschlagen:', err.message);
91
+ }
92
+
93
+ // Demo: Manual reconnect
94
+ console.log('\n--- Manual Reconnect Test ---');
95
+ console.log('Drücke Ctrl+C um zu beenden.\n');
96
+
97
+ // Keep running
98
+ setInterval(async () => {
99
+ if (client.connected) {
100
+ console.log(`[${new Date().toLocaleTimeString()}] Status: Verbunden`);
101
+ } else {
102
+ console.log(`[${new Date().toLocaleTimeString()}] Status: ${client.state}`);
103
+ }
104
+ }, 10000);
105
+
106
+ // Graceful shutdown
107
+ process.on('SIGINT', () => {
108
+ console.log('\n\nShutting down...');
109
+ client.close();
110
+ process.exit(0);
111
+ });
112
+ }
113
+
114
+ function makeRequest(client, url) {
115
+ return new Promise((resolve, reject) => {
116
+ const req = https.get(url, { agent: client.getHttpsAgent() }, (res) => {
117
+ let data = '';
118
+ res.on('data', chunk => data += chunk);
119
+ res.on('end', () => resolve(data));
120
+ });
121
+ req.on('error', reject);
122
+ req.setTimeout(10000, () => {
123
+ req.destroy(new Error('Timeout'));
124
+ });
125
+ });
126
+ }
127
+
128
+ main().catch(console.error);
@@ -0,0 +1,63 @@
1
+ const { WireShade } = require('../index');
2
+ const path = require('path');
3
+ const http = require('http');
4
+
5
+ /**
6
+ * Example: Remote Forwarding (Reverse Port Forwarding)
7
+ *
8
+ * Scenario:
9
+ * You have a service running on your local LAN (e.g., a local printer web interface,
10
+ * or a development server on another machine) at '192.168.1.50:80'.
11
+ *
12
+ * You want to make this service accessible to everyone in the VPN at '10.0.0.2:8080'.
13
+ *
14
+ * Flow: [VPN User] -> [WireShade VPN IP:8080] -> [WireShade] -> [Local LAN IP:80]
15
+ */
16
+
17
+ async function main() {
18
+ console.log("=== WireShade Remote Forwarding Demo ===");
19
+
20
+ // 1. Initialize
21
+ const gw = new WireShade(path.join(__dirname, 'wireguard.conf'));
22
+
23
+ gw.on('connect', async () => {
24
+ console.log(`VPN Connected as ${gw.config.wireguard.sourceIp}`);
25
+
26
+ // Mock a "local service" for demonstration purposes
27
+ // In reality, this would be an existing service on your machine or network.
28
+ startMockLocalService(3000);
29
+
30
+ try {
31
+ // 2. Start Forwarding
32
+ // Listen on VPN Port 8080 -> Forward to localhost:3000
33
+ const vpnPort = 8080;
34
+ const localTargetHost = 'localhost';
35
+ const localTargetPort = 3000;
36
+
37
+ await gw.forwardRemote(vpnPort, localTargetHost, localTargetPort);
38
+
39
+ console.log(`\n✅ Forwarding Active!`);
40
+ console.log(`Traffic to VPN ${gw.config.wireguard.sourceIp}:${vpnPort} is now forwarded to ${localTargetHost}:${localTargetPort}`);
41
+
42
+ } catch (err) {
43
+ console.error("Forwarding failed:", err);
44
+ }
45
+ });
46
+
47
+ gw.on('error', console.error);
48
+ await gw.start();
49
+ }
50
+
51
+ function startMockLocalService(port) {
52
+ const server = http.createServer((req, res) => {
53
+ console.log(`[Local Service] Received request: ${req.method} ${req.url}`);
54
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
55
+ res.end(`Hello from the Local Service! You reached me via VPN.`);
56
+ });
57
+ server.listen(port, () => {
58
+ console.log(`[Local Service] Running on port ${port}`);
59
+ });
60
+ return server;
61
+ }
62
+
63
+ main();
@@ -0,0 +1,54 @@
1
+ # WireShade Examples
2
+
3
+ This directory contains example scripts demonstrating various capabilities of the WireShade library.
4
+
5
+ ## Getting Started
6
+
7
+ 1. Ensure you have a valid `wireguard.conf` in this directory (or update the scripts to point to one).
8
+ 2. Run the examples using `node examples/<filename>`.
9
+
10
+ ## Available Examples
11
+
12
+ ### 1. Quickstart (`01_quickstart.js`)
13
+ The "Hello World" of WireShade. Shows how to initialize the connection, perform a simple request, and start a listener.
14
+ - **Run:** `node examples/01_quickstart.js`
15
+
16
+ ### 2. HTTP Request (`02_http_request.js`)
17
+ Performs a simple HTTP GET request to an internal web server using the simplified `gw.get()` API.
18
+ - **Run:** `node examples/02_http_request.js`
19
+
20
+ ### 3. HTTPS & Custom DNS (`03_https_custom_dns.js`)
21
+ Demonstrates how to access an HTTPS server with a custom hostname (`internal.service.lan`) mapped to an internal IP.
22
+ - **Run:** `node examples/03_https_custom_dns.js`
23
+
24
+ ### 4. Raw TCP Socket (`04_tcp_socket.js`)
25
+ Shows low-level usage to send raw data bytes (HTTP request manually constructed) and receive raw bytes, bypassing higher-level helpers.
26
+ - **Run:** `node examples/04_tcp_socket.js`
27
+
28
+ ### 5. Internet Routing (`05_internet_routing.js`)
29
+ Tests routing to the public internet by fetching your IP from `ifconfig.me`. Confirms that traffic exits via the WireGuard VPN gateway.
30
+ - **Run:** `node examples/05_internet_routing.js`
31
+
32
+ ### 6. Simple Server (`06_simple_server.js`)
33
+ Host a basic HTTP server inside the VPN tunnel.
34
+ - **Run:** `node examples/06_simple_server.js`
35
+
36
+ ### 7. Express App (`07_express_app.js`)
37
+ Run a full Express.js application and make it accessible via the VPN tunnel (Reverse Tunneling).
38
+ - **Run:** `node examples/07_express_app.js`
39
+
40
+ ### 8. Local Forwarding (`08_local_forwarding.js`)
41
+ Starts a local TCP server on port `8080` that forwards all traffic to an internal host (`10.0.0.5:80`).
42
+ - **Run:** `node examples/08_local_forwarding.js`
43
+
44
+ ### 9. Advanced Reconnect (`09_reconnect_config.js`)
45
+ Demonstrates reconnection logic, health checks, and event monitoring.
46
+ - **Run:** `node examples/09_reconnect_config.js`
47
+
48
+ ### 10. Remote Forwarding (`10_remote_forwarding.js`)
49
+ Exposes a service running on your local machine (or local network) to the VPN. Traffic sent to a specific VPN port is forwarded to the local target.
50
+ - **Run:** `node examples/10_remote_forwarding.js`
51
+
52
+
53
+ ## Configuration
54
+ All examples read from `wireguard.conf` in this directory. Ensure this file contains your valid Client configuration.
@@ -0,0 +1,53 @@
1
+ const { WireShadeClient } = require('../index');
2
+ const https = require('https');
3
+
4
+ async function testEasyApi() {
5
+ console.log("--- WireShade Easy API Test (Quiet Mode) ---");
6
+
7
+ const client = new WireShadeClient({
8
+ wireguard: {
9
+ privateKey: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
10
+ peerPublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
11
+ presharedKey: "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
12
+ endpoint: "203.0.113.1:51820",
13
+ sourceIp: "10.0.0.2"
14
+ },
15
+ logging: false, // DISABLES INTERNAL LOGS
16
+ onConnect: () => {
17
+ console.log("\n>>> EVENT: WireGuard Connection Ready! <<<");
18
+ },
19
+ onDisconnect: () => {
20
+ console.log(">>> EVENT: WireGuard Connection Closed! <<<");
21
+ },
22
+ hosts: {
23
+ 'internal.service.lan': '10.0.0.5'
24
+ }
25
+ });
26
+
27
+ // Wait a bit to ensure onConnect fired (just for demo flow)
28
+ await new Promise(r => setTimeout(r, 200));
29
+
30
+ const target = 'https://internal.service.lan';
31
+ console.log(`\n[HTTPS] Fetching ${target}...`);
32
+
33
+ https.get(target, { agent: client.getHttpsAgent() }, (res) => {
34
+ console.log(`[Response] Status: ${res.statusCode}`);
35
+ // res.on('data', d => process.stdout.write(d)); // Suppress body for cleaner output
36
+ console.log(`[Response] Headers received.`);
37
+
38
+ // Start Port Forwarding after request
39
+ startForwarding(client);
40
+ }).on('error', console.error);
41
+
42
+ async function startForwarding(client) {
43
+ try {
44
+ await client.forwardLocal(9090, '10.0.0.5', 80);
45
+ console.log("\n[Forward] Listening on localhost:9090 -> 10.0.0.5:80");
46
+ console.log("[Forward] Speed test: Open http://localhost:9090 (Should be fast now!)");
47
+ } catch (e) {
48
+ console.error(e);
49
+ }
50
+ }
51
+ }
52
+
53
+ testEasyApi();
@@ -0,0 +1,8 @@
1
+ [Interface]
2
+ PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
3
+ Address = 10.0.0.2/32
4
+
5
+ [Peer]
6
+ PublicKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
7
+ PresharedKey = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=
8
+ Endpoint = 203.0.113.1:51820
package/index.d.ts ADDED
File without changes
package/index.js ADDED
@@ -0,0 +1,29 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ let binding;
5
+ try {
6
+ binding = require('./wireshade.node');
7
+ } catch (e) {
8
+ try {
9
+ binding = require('./wireshade.win32-x64-msvc.node');
10
+ } catch (e2) {
11
+ throw new Error('Could not load native binding');
12
+ }
13
+ }
14
+
15
+ const { WireShadeAgent } = require('./lib/agent');
16
+ const { WireShadeClient, ConnectionState } = require('./lib/client');
17
+ const { WireShadeServer } = require('./lib/server');
18
+ const { parseWireGuardConfig, readWireGuardConfig } = require('./lib/config_parser');
19
+
20
+ module.exports = {
21
+ WireShade: WireShadeClient, // The high-level client is the main export
22
+ NativeWireShade: binding.WireShade,
23
+ WireShadeClient,
24
+ WireShadeAgent,
25
+ WireShadeServer,
26
+ ConnectionState,
27
+ parseConfig: parseWireGuardConfig,
28
+ readConfig: readWireGuardConfig
29
+ };
package/lib/agent.js ADDED
@@ -0,0 +1,116 @@
1
+ const http = require('http');
2
+ const { Duplex } = require('stream');
3
+ const dns = require('dns');
4
+
5
+ class WireShadeAgent extends http.Agent {
6
+ constructor(wireShade, options) {
7
+ super(options);
8
+ this.gw = wireShade;
9
+ this.options = options || {};
10
+
11
+ // Configure Logger
12
+ // Priority: options.logger -> console.log (unless logging===false)
13
+ this.log = this.options.logger || (this.options.logging === false ? () => { } : console.log);
14
+ this.error = this.options.logger || console.error;
15
+ }
16
+ createConnection(options, cb) {
17
+ const { host, port } = options;
18
+ const log = this.log;
19
+ const error = this.error;
20
+
21
+ log(`[Agent] Connecting to ${host}:${port}`);
22
+
23
+ const stream = new Duplex({
24
+ allowHalfOpen: true,
25
+ read(size) { },
26
+ write(chunk, encoding, callback) {
27
+ log(`[AgentStream] write called with ${chunk.length} bytes`);
28
+ if (this.connection) {
29
+ log(`[AgentStream] Sending immediately...`);
30
+ this.connection.send(chunk).then(() => {
31
+ log(`[AgentStream] Send completed for ${chunk.length} bytes`);
32
+ callback();
33
+ }).catch((err) => {
34
+ error(`[AgentStream] Send error:`, err);
35
+ callback(err);
36
+ });
37
+ } else {
38
+ log(`[AgentStream] Buffering - connection not ready yet`);
39
+ if (!this.pendingBuffer) this.pendingBuffer = [];
40
+ this.pendingBuffer.push({ chunk, callback });
41
+ }
42
+ }
43
+ });
44
+
45
+ // Mock Socket methods required by http.Agent/ClientRequest
46
+ stream.setTimeout = (msecs, callback) => {
47
+ if (callback) stream.once('timeout', callback);
48
+ return stream;
49
+ };
50
+ stream.setNoDelay = (enable) => stream;
51
+ stream.setKeepAlive = (enable, initialDelay) => stream;
52
+ stream.ref = () => stream;
53
+ stream.unref = () => stream;
54
+
55
+ // Use custom lookup if provided in options (Standard node http.Agent behavior), else default dns.lookup
56
+ const lookup = options.lookup || dns.lookup;
57
+
58
+ lookup(host, { family: 4 }, (err, address, family) => {
59
+ if (err) {
60
+ return cb(err);
61
+ }
62
+ log(`[Agent] Resolved ${host} to ${address}`);
63
+
64
+ this.gw.connect(address, parseInt(port),
65
+ (err, data) => {
66
+ const buffer = data || (Buffer.isBuffer(err) ? err : null);
67
+ if (buffer) {
68
+ log(`[Agent] Received ${buffer.length} bytes via connection`);
69
+ stream.push(buffer);
70
+ } else if (err && !data) {
71
+ error('[Agent] Receive error:', err);
72
+ stream.destroy(err);
73
+ }
74
+ },
75
+ () => {
76
+ stream.push(null);
77
+ }
78
+ ).then(conn => {
79
+ log(`[Agent] Connected! Setting stream.connection...`);
80
+ stream.connection = conn;
81
+ stream.emit('connect');
82
+
83
+ log(`[Agent] Checking pendingBuffer: ${stream.pendingBuffer ? stream.pendingBuffer.length + ' items' : 'none'}`);
84
+ if (stream.pendingBuffer && stream.pendingBuffer.length > 0) {
85
+ log(`[AgentStream] Flushing ${stream.pendingBuffer.length} buffered chunks`);
86
+ const flushPromises = stream.pendingBuffer.map(({ chunk, callback }) => {
87
+ log(`[AgentStream] Flushing chunk of ${chunk.length} bytes...`);
88
+ return conn.send(chunk).then(() => {
89
+ log(`[AgentStream] Flush completed for ${chunk.length} bytes`);
90
+ callback();
91
+ }).catch(err => {
92
+ error(`[AgentStream] Flush error:`, err);
93
+ callback(err);
94
+ });
95
+ });
96
+ stream.pendingBuffer = null;
97
+ Promise.all(flushPromises).then(() => {
98
+ log(`[Agent] All buffered data flushed, calling cb`);
99
+ if (cb) cb(null, stream);
100
+ });
101
+ } else {
102
+ log(`[Agent] No buffered data, calling cb immediately`);
103
+ if (cb) cb(null, stream);
104
+ }
105
+ }).catch(err => {
106
+ error('[Agent] Connection failed:', err.message, err.code, err);
107
+ if (cb) cb(err);
108
+ else stream.emit('error', err);
109
+ });
110
+ });
111
+
112
+ return stream;
113
+ }
114
+ }
115
+
116
+ module.exports = { WireShadeAgent };