@push.rocks/smartvpn 1.4.0 → 1.5.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartvpn',
6
- version: '1.4.0',
6
+ version: '1.5.0',
7
7
  description: 'A VPN solution with TypeScript control plane and Rust data plane daemon'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHlFQUF5RTtDQUN2RixDQUFBIn0=
@@ -4,3 +4,4 @@ export { VpnClient } from './smartvpn.classes.vpnclient.js';
4
4
  export { VpnServer } from './smartvpn.classes.vpnserver.js';
5
5
  export { VpnConfig } from './smartvpn.classes.vpnconfig.js';
6
6
  export { VpnInstaller } from './smartvpn.classes.vpninstaller.js';
7
+ export { WgConfigGenerator } from './smartvpn.classes.wgconfig.js';
package/dist_ts/index.js CHANGED
@@ -4,4 +4,5 @@ export { VpnClient } from './smartvpn.classes.vpnclient.js';
4
4
  export { VpnServer } from './smartvpn.classes.vpnserver.js';
5
5
  export { VpnConfig } from './smartvpn.classes.vpnconfig.js';
6
6
  export { VpnInstaller } from './smartvpn.classes.vpninstaller.js';
7
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM1RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0NBQW9DLENBQUMifQ==
7
+ export { WgConfigGenerator } from './smartvpn.classes.wgconfig.js';
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM1RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDbEUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0NBQWdDLENBQUMifQ==
@@ -27,4 +27,12 @@ export declare class VpnConfig {
27
27
  * Basic subnet validation (CIDR notation).
28
28
  */
29
29
  private static isValidSubnet;
30
+ /**
31
+ * Validate a CIDR string (IPv4 or IPv6).
32
+ */
33
+ private static isValidCidr;
34
+ /**
35
+ * Validate a base64-encoded 32-byte key (WireGuard X25519 format).
36
+ */
37
+ private static validateBase64Key;
30
38
  }
@@ -7,17 +7,46 @@ export class VpnConfig {
7
7
  * Validate a client config object. Throws on invalid config.
8
8
  */
9
9
  static validateClientConfig(config) {
10
- if (!config.serverUrl) {
11
- throw new Error('VpnConfig: serverUrl is required');
12
- }
13
- // For QUIC-only transport, serverUrl is a host:port address; for WebSocket/auto it must be ws:// or wss://
14
- if (config.transport !== 'quic') {
15
- if (!config.serverUrl.startsWith('wss://') && !config.serverUrl.startsWith('ws://')) {
16
- throw new Error('VpnConfig: serverUrl must start with wss:// or ws:// (for WebSocket transport)');
10
+ if (config.transport === 'wireguard') {
11
+ // WireGuard-specific validation
12
+ if (!config.wgPrivateKey) {
13
+ throw new Error('VpnConfig: wgPrivateKey is required for WireGuard transport');
14
+ }
15
+ VpnConfig.validateBase64Key(config.wgPrivateKey, 'wgPrivateKey');
16
+ if (!config.wgAddress) {
17
+ throw new Error('VpnConfig: wgAddress is required for WireGuard transport');
18
+ }
19
+ if (!config.serverPublicKey) {
20
+ throw new Error('VpnConfig: serverPublicKey is required for WireGuard transport');
21
+ }
22
+ VpnConfig.validateBase64Key(config.serverPublicKey, 'serverPublicKey');
23
+ if (!config.wgEndpoint) {
24
+ throw new Error('VpnConfig: wgEndpoint is required for WireGuard transport');
25
+ }
26
+ if (config.wgPresharedKey) {
27
+ VpnConfig.validateBase64Key(config.wgPresharedKey, 'wgPresharedKey');
28
+ }
29
+ if (config.wgAllowedIps) {
30
+ for (const cidr of config.wgAllowedIps) {
31
+ if (!VpnConfig.isValidCidr(cidr)) {
32
+ throw new Error(`VpnConfig: invalid allowedIp CIDR: ${cidr}`);
33
+ }
34
+ }
17
35
  }
18
36
  }
19
- if (!config.serverPublicKey) {
20
- throw new Error('VpnConfig: serverPublicKey is required');
37
+ else {
38
+ if (!config.serverUrl) {
39
+ throw new Error('VpnConfig: serverUrl is required');
40
+ }
41
+ // For QUIC-only transport, serverUrl is a host:port address; for WebSocket/auto it must be ws:// or wss://
42
+ if (config.transport !== 'quic') {
43
+ if (!config.serverUrl.startsWith('wss://') && !config.serverUrl.startsWith('ws://')) {
44
+ throw new Error('VpnConfig: serverUrl must start with wss:// or ws:// (for WebSocket transport)');
45
+ }
46
+ }
47
+ if (!config.serverPublicKey) {
48
+ throw new Error('VpnConfig: serverPublicKey is required');
49
+ }
21
50
  }
22
51
  if (config.mtu !== undefined && (config.mtu < 576 || config.mtu > 65535)) {
23
52
  throw new Error('VpnConfig: mtu must be between 576 and 65535');
@@ -37,20 +66,52 @@ export class VpnConfig {
37
66
  * Validate a server config object. Throws on invalid config.
38
67
  */
39
68
  static validateServerConfig(config) {
40
- if (!config.listenAddr) {
41
- throw new Error('VpnConfig: listenAddr is required');
42
- }
43
- if (!config.privateKey) {
44
- throw new Error('VpnConfig: privateKey is required');
45
- }
46
- if (!config.publicKey) {
47
- throw new Error('VpnConfig: publicKey is required');
48
- }
49
- if (!config.subnet) {
50
- throw new Error('VpnConfig: subnet is required');
69
+ if (config.transportMode === 'wireguard') {
70
+ // WireGuard server validation
71
+ if (!config.privateKey) {
72
+ throw new Error('VpnConfig: privateKey is required');
73
+ }
74
+ VpnConfig.validateBase64Key(config.privateKey, 'privateKey');
75
+ if (!config.wgPeers || config.wgPeers.length === 0) {
76
+ throw new Error('VpnConfig: at least one wgPeers entry is required for WireGuard mode');
77
+ }
78
+ for (const peer of config.wgPeers) {
79
+ if (!peer.publicKey) {
80
+ throw new Error('VpnConfig: peer publicKey is required');
81
+ }
82
+ VpnConfig.validateBase64Key(peer.publicKey, 'peer.publicKey');
83
+ if (!peer.allowedIps || peer.allowedIps.length === 0) {
84
+ throw new Error('VpnConfig: peer allowedIps is required');
85
+ }
86
+ for (const cidr of peer.allowedIps) {
87
+ if (!VpnConfig.isValidCidr(cidr)) {
88
+ throw new Error(`VpnConfig: invalid peer allowedIp CIDR: ${cidr}`);
89
+ }
90
+ }
91
+ if (peer.presharedKey) {
92
+ VpnConfig.validateBase64Key(peer.presharedKey, 'peer.presharedKey');
93
+ }
94
+ }
95
+ if (config.wgListenPort !== undefined && (config.wgListenPort < 1 || config.wgListenPort > 65535)) {
96
+ throw new Error('VpnConfig: wgListenPort must be between 1 and 65535');
97
+ }
51
98
  }
52
- if (!VpnConfig.isValidSubnet(config.subnet)) {
53
- throw new Error(`VpnConfig: invalid subnet: ${config.subnet}`);
99
+ else {
100
+ if (!config.listenAddr) {
101
+ throw new Error('VpnConfig: listenAddr is required');
102
+ }
103
+ if (!config.privateKey) {
104
+ throw new Error('VpnConfig: privateKey is required');
105
+ }
106
+ if (!config.publicKey) {
107
+ throw new Error('VpnConfig: publicKey is required');
108
+ }
109
+ if (!config.subnet) {
110
+ throw new Error('VpnConfig: subnet is required');
111
+ }
112
+ if (!VpnConfig.isValidSubnet(config.subnet)) {
113
+ throw new Error(`VpnConfig: invalid subnet: ${config.subnet}`);
114
+ }
54
115
  }
55
116
  if (config.mtu !== undefined && (config.mtu < 576 || config.mtu > 65535)) {
56
117
  throw new Error('VpnConfig: mtu must be between 576 and 65535');
@@ -97,5 +158,44 @@ export class VpnConfig {
97
158
  const prefixNum = parseInt(prefix, 10);
98
159
  return !isNaN(prefixNum) && prefixNum >= 0 && prefixNum <= 32;
99
160
  }
161
+ /**
162
+ * Validate a CIDR string (IPv4 or IPv6).
163
+ */
164
+ static isValidCidr(cidr) {
165
+ const parts = cidr.split('/');
166
+ if (parts.length !== 2)
167
+ return false;
168
+ const prefixNum = parseInt(parts[1], 10);
169
+ if (isNaN(prefixNum) || prefixNum < 0)
170
+ return false;
171
+ // IPv4
172
+ if (VpnConfig.isValidIp(parts[0])) {
173
+ return prefixNum <= 32;
174
+ }
175
+ // IPv6 (basic check)
176
+ if (parts[0].includes(':')) {
177
+ return prefixNum <= 128;
178
+ }
179
+ return false;
180
+ }
181
+ /**
182
+ * Validate a base64-encoded 32-byte key (WireGuard X25519 format).
183
+ */
184
+ static validateBase64Key(key, fieldName) {
185
+ if (key.length !== 44) {
186
+ throw new Error(`VpnConfig: ${fieldName} must be 44 characters (base64 of 32 bytes), got ${key.length}`);
187
+ }
188
+ try {
189
+ const buf = Buffer.from(key, 'base64');
190
+ if (buf.length !== 32) {
191
+ throw new Error(`VpnConfig: ${fieldName} must decode to 32 bytes, got ${buf.length}`);
192
+ }
193
+ }
194
+ catch (e) {
195
+ if (e instanceof Error && e.message.startsWith('VpnConfig:'))
196
+ throw e;
197
+ throw new Error(`VpnConfig: ${fieldName} is not valid base64`);
198
+ }
199
+ }
100
200
  }
101
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5jb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbmNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBTWpEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDcEI7O09BRUc7SUFDSSxNQUFNLENBQUMsb0JBQW9CLENBQUMsTUFBd0I7UUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUNELDJHQUEyRztRQUMzRyxJQUFJLE1BQU0sQ0FBQyxTQUFTLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDcEYsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRkFBZ0YsQ0FBQyxDQUFDO1lBQ3BHLENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7UUFDNUQsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLEdBQUcsS0FBSyxTQUFTLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLEdBQUcsSUFBSSxNQUFNLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDekUsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxxQkFBcUIsS0FBSyxTQUFTLElBQUksTUFBTSxD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
201
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5jb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbmNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBTWpEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDcEI7O09BRUc7SUFDSSxNQUFNLENBQUMsb0JBQW9CLENBQUMsTUFBd0I7UUFDekQsSUFBSSxNQUFNLENBQUMsU0FBUyxLQUFLLFdBQVcsRUFBRSxDQUFDO1lBQ3JDLGdDQUFnQztZQUNoQyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7WUFDakYsQ0FBQztZQUNELFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ2pFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsMERBQTBELENBQUMsQ0FBQztZQUM5RSxDQUFDO1lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1lBQ3BGLENBQUM7WUFDRCxTQUFTLENBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1lBQ3ZFLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztZQUMvRSxDQUFDO1lBQ0QsSUFBSSxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQzFCLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsY0FB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
@@ -1,5 +1,5 @@
1
1
  import * as plugins from './smartvpn.plugins.js';
2
- import type { IVpnServerOptions, IVpnServerConfig, IVpnStatus, IVpnServerStatistics, IVpnClientInfo, IVpnKeypair, IVpnClientTelemetry } from './smartvpn.interfaces.js';
2
+ import type { IVpnServerOptions, IVpnServerConfig, IVpnStatus, IVpnServerStatistics, IVpnClientInfo, IVpnKeypair, IVpnClientTelemetry, IWgPeerConfig, IWgPeerInfo } from './smartvpn.interfaces.js';
3
3
  /**
4
4
  * VPN Server — manages a smartvpn daemon in server mode.
5
5
  */
@@ -47,6 +47,22 @@ export declare class VpnServer extends plugins.events.EventEmitter {
47
47
  * Get telemetry for a specific client.
48
48
  */
49
49
  getClientTelemetry(clientId: string): Promise<IVpnClientTelemetry>;
50
+ /**
51
+ * Generate a WireGuard-compatible X25519 keypair.
52
+ */
53
+ generateWgKeypair(): Promise<IVpnKeypair>;
54
+ /**
55
+ * Add a WireGuard peer (server must be running in wireguard mode).
56
+ */
57
+ addWgPeer(peer: IWgPeerConfig): Promise<void>;
58
+ /**
59
+ * Remove a WireGuard peer by public key.
60
+ */
61
+ removeWgPeer(publicKey: string): Promise<void>;
62
+ /**
63
+ * List WireGuard peers with stats.
64
+ */
65
+ listWgPeers(): Promise<IWgPeerInfo[]>;
50
66
  /**
51
67
  * Stop the daemon bridge.
52
68
  */
@@ -91,6 +91,31 @@ export class VpnServer extends plugins.events.EventEmitter {
91
91
  async getClientTelemetry(clientId) {
92
92
  return this.bridge.sendCommand('getClientTelemetry', { clientId });
93
93
  }
94
+ /**
95
+ * Generate a WireGuard-compatible X25519 keypair.
96
+ */
97
+ async generateWgKeypair() {
98
+ return this.bridge.sendCommand('generateWgKeypair', {});
99
+ }
100
+ /**
101
+ * Add a WireGuard peer (server must be running in wireguard mode).
102
+ */
103
+ async addWgPeer(peer) {
104
+ await this.bridge.sendCommand('addWgPeer', { peer });
105
+ }
106
+ /**
107
+ * Remove a WireGuard peer by public key.
108
+ */
109
+ async removeWgPeer(publicKey) {
110
+ await this.bridge.sendCommand('removeWgPeer', { publicKey });
111
+ }
112
+ /**
113
+ * List WireGuard peers with stats.
114
+ */
115
+ async listWgPeers() {
116
+ const result = await this.bridge.sendCommand('listWgPeers', {});
117
+ return result.peers;
118
+ }
94
119
  /**
95
120
  * Stop the daemon bridge.
96
121
  */
@@ -104,4 +129,4 @@ export class VpnServer extends plugins.events.EventEmitter {
104
129
  return this.bridge.running;
105
130
  }
106
131
  }
107
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbnNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQVk1RDs7R0FFRztBQUNILE1BQU0sT0FBTyxTQUFVLFNBQVEsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZO0lBSXhELFlBQVksT0FBMEI7UUFDcEMsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksU0FBUyxDQUFxQjtZQUM5QyxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7WUFDNUIsSUFBSSxFQUFFLFFBQVE7U0FDZixDQUFDLENBQUM7UUFFSCx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBbUIsRUFBRSxNQUFxQixFQUFFLEVBQUU7WUFDcEUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN0QyxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUU7WUFDakMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUMzQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBeUI7UUFDMUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzFDLElBQUksQ0FBQyxPQUFPLEVB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
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbnNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQWM1RDs7R0FFRztBQUNILE1BQU0sT0FBTyxTQUFVLFNBQVEsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZO0lBSXhELFlBQVksT0FBMEI7UUFDcEMsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksU0FBUyxDQUFxQjtZQUM5QyxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7WUFDNUIsSUFBSSxFQUFFLFFBQVE7U0FDZixDQUFDLENBQUM7UUFFSCx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBbUIsRUFBRSxNQUFxQixFQUFFLEVBQUU7WUFDcEUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN0QyxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUU7WUFDakMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUMzQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBeUI7UUFDMUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzFDLElBQUksQ0FBQyxPQUFPLEVB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
@@ -0,0 +1,51 @@
1
+ import type { IWgPeerConfig } from './smartvpn.interfaces.js';
2
+ export interface IWgClientConfOptions {
3
+ /** Client private key (base64) */
4
+ privateKey: string;
5
+ /** Client TUN address with prefix (e.g. 10.8.0.2/24) */
6
+ address: string;
7
+ /** DNS servers */
8
+ dns?: string[];
9
+ /** TUN MTU */
10
+ mtu?: number;
11
+ /** Server peer config */
12
+ peer: {
13
+ publicKey: string;
14
+ presharedKey?: string;
15
+ endpoint: string;
16
+ allowedIps: string[];
17
+ persistentKeepalive?: number;
18
+ };
19
+ }
20
+ export interface IWgServerConfOptions {
21
+ /** Server private key (base64) */
22
+ privateKey: string;
23
+ /** Server TUN address with prefix (e.g. 10.8.0.1/24) */
24
+ address: string;
25
+ /** UDP listen port */
26
+ listenPort: number;
27
+ /** DNS servers */
28
+ dns?: string[];
29
+ /** TUN MTU */
30
+ mtu?: number;
31
+ /** Enable NAT — adds PostUp/PostDown iptables rules */
32
+ enableNat?: boolean;
33
+ /** Network interface for NAT (e.g. eth0). Auto-detected if omitted. */
34
+ natInterface?: string;
35
+ /** Configured peers */
36
+ peers: IWgPeerConfig[];
37
+ }
38
+ /**
39
+ * Generates standard WireGuard .conf files compatible with wg-quick,
40
+ * WireGuard iOS/Android apps, and other standard WireGuard clients.
41
+ */
42
+ export declare class WgConfigGenerator {
43
+ /**
44
+ * Generate a client .conf file content.
45
+ */
46
+ static generateClientConfig(opts: IWgClientConfOptions): string;
47
+ /**
48
+ * Generate a server .conf file content.
49
+ */
50
+ static generateServerConfig(opts: IWgServerConfOptions): string;
51
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Generates standard WireGuard .conf files compatible with wg-quick,
3
+ * WireGuard iOS/Android apps, and other standard WireGuard clients.
4
+ */
5
+ export class WgConfigGenerator {
6
+ /**
7
+ * Generate a client .conf file content.
8
+ */
9
+ static generateClientConfig(opts) {
10
+ const lines = [];
11
+ lines.push('[Interface]');
12
+ lines.push(`PrivateKey = ${opts.privateKey}`);
13
+ lines.push(`Address = ${opts.address}`);
14
+ if (opts.dns && opts.dns.length > 0) {
15
+ lines.push(`DNS = ${opts.dns.join(', ')}`);
16
+ }
17
+ if (opts.mtu) {
18
+ lines.push(`MTU = ${opts.mtu}`);
19
+ }
20
+ lines.push('');
21
+ lines.push('[Peer]');
22
+ lines.push(`PublicKey = ${opts.peer.publicKey}`);
23
+ if (opts.peer.presharedKey) {
24
+ lines.push(`PresharedKey = ${opts.peer.presharedKey}`);
25
+ }
26
+ lines.push(`Endpoint = ${opts.peer.endpoint}`);
27
+ lines.push(`AllowedIPs = ${opts.peer.allowedIps.join(', ')}`);
28
+ if (opts.peer.persistentKeepalive) {
29
+ lines.push(`PersistentKeepalive = ${opts.peer.persistentKeepalive}`);
30
+ }
31
+ lines.push('');
32
+ return lines.join('\n');
33
+ }
34
+ /**
35
+ * Generate a server .conf file content.
36
+ */
37
+ static generateServerConfig(opts) {
38
+ const lines = [];
39
+ lines.push('[Interface]');
40
+ lines.push(`PrivateKey = ${opts.privateKey}`);
41
+ lines.push(`Address = ${opts.address}`);
42
+ lines.push(`ListenPort = ${opts.listenPort}`);
43
+ if (opts.dns && opts.dns.length > 0) {
44
+ lines.push(`DNS = ${opts.dns.join(', ')}`);
45
+ }
46
+ if (opts.mtu) {
47
+ lines.push(`MTU = ${opts.mtu}`);
48
+ }
49
+ if (opts.enableNat) {
50
+ const iface = opts.natInterface || 'eth0';
51
+ lines.push(`PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ${iface} -j MASQUERADE`);
52
+ lines.push(`PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ${iface} -j MASQUERADE`);
53
+ }
54
+ for (const peer of opts.peers) {
55
+ lines.push('');
56
+ lines.push('[Peer]');
57
+ lines.push(`PublicKey = ${peer.publicKey}`);
58
+ if (peer.presharedKey) {
59
+ lines.push(`PresharedKey = ${peer.presharedKey}`);
60
+ }
61
+ lines.push(`AllowedIPs = ${peer.allowedIps.join(', ')}`);
62
+ if (peer.endpoint) {
63
+ lines.push(`Endpoint = ${peer.endpoint}`);
64
+ }
65
+ if (peer.persistentKeepalive) {
66
+ lines.push(`PersistentKeepalive = ${peer.persistentKeepalive}`);
67
+ }
68
+ }
69
+ lines.push('');
70
+ return lines.join('\n');
71
+ }
72
+ }
73
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy53Z2NvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0dnBuLmNsYXNzZXMud2djb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNENBOzs7R0FHRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUI7O09BRUc7SUFDSSxNQUFNLENBQUMsb0JBQW9CLENBQUMsSUFBMEI7UUFDM0QsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO1FBRTNCLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDMUIsS0FBSyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDOUMsS0FBSyxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3hDLElBQUksSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNiLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBRUQsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNmLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckIsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNqRCxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDM0IsS0FB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
@@ -21,10 +21,24 @@ export interface IVpnClientConfig {
21
21
  mtu?: number;
22
22
  /** Keepalive interval in seconds (default: 30) */
23
23
  keepaliveIntervalSecs?: number;
24
- /** Transport protocol: 'auto' (default, tries QUIC then WS), 'websocket', or 'quic' */
25
- transport?: 'auto' | 'websocket' | 'quic';
24
+ /** Transport protocol: 'auto' (default, tries QUIC then WS), 'websocket', 'quic', or 'wireguard' */
25
+ transport?: 'auto' | 'websocket' | 'quic' | 'wireguard';
26
26
  /** For QUIC: SHA-256 hash of server certificate (base64) for cert pinning */
27
27
  serverCertHash?: string;
28
+ /** WireGuard: client private key (base64, X25519) */
29
+ wgPrivateKey?: string;
30
+ /** WireGuard: client TUN address (e.g. 10.8.0.2) */
31
+ wgAddress?: string;
32
+ /** WireGuard: client TUN address prefix length (default: 24) */
33
+ wgAddressPrefix?: number;
34
+ /** WireGuard: preshared key (base64, optional) */
35
+ wgPresharedKey?: string;
36
+ /** WireGuard: persistent keepalive interval in seconds */
37
+ wgPersistentKeepalive?: number;
38
+ /** WireGuard: server endpoint (host:port, e.g. vpn.example.com:51820) */
39
+ wgEndpoint?: string;
40
+ /** WireGuard: allowed IPs (CIDR strings, e.g. ['0.0.0.0/0']) */
41
+ wgAllowedIps?: string[];
28
42
  }
29
43
  export interface IVpnClientOptions {
30
44
  transport: TVpnTransportOptions;
@@ -55,12 +69,16 @@ export interface IVpnServerConfig {
55
69
  defaultRateLimitBytesPerSec?: number;
56
70
  /** Default burst size for new clients (bytes). Omit for unlimited. */
57
71
  defaultBurstBytes?: number;
58
- /** Transport mode: 'both' (default, WS+QUIC), 'websocket', or 'quic' */
59
- transportMode?: 'websocket' | 'quic' | 'both';
72
+ /** Transport mode: 'both' (default, WS+QUIC), 'websocket', 'quic', or 'wireguard' */
73
+ transportMode?: 'websocket' | 'quic' | 'both' | 'wireguard';
60
74
  /** QUIC listen address (host:port). Defaults to listenAddr. */
61
75
  quicListenAddr?: string;
62
76
  /** QUIC idle timeout in seconds (default: 30) */
63
77
  quicIdleTimeoutSecs?: number;
78
+ /** WireGuard: UDP listen port (default: 51820) */
79
+ wgListenPort?: number;
80
+ /** WireGuard: configured peers */
81
+ wgPeers?: IWgPeerConfig[];
64
82
  }
65
83
  export interface IVpnServerOptions {
66
84
  transport: TVpnTransportOptions;
@@ -136,6 +154,29 @@ export interface IVpnClientTelemetry {
136
154
  rateLimitBytesPerSec?: number;
137
155
  burstBytes?: number;
138
156
  }
157
+ export interface IWgPeerConfig {
158
+ /** Peer's public key (base64, X25519) */
159
+ publicKey: string;
160
+ /** Optional preshared key (base64) */
161
+ presharedKey?: string;
162
+ /** Allowed IP ranges (CIDR strings) */
163
+ allowedIps: string[];
164
+ /** Peer endpoint (host:port) — optional for server peers, required for client */
165
+ endpoint?: string;
166
+ /** Persistent keepalive interval in seconds */
167
+ persistentKeepalive?: number;
168
+ }
169
+ export interface IWgPeerInfo {
170
+ publicKey: string;
171
+ allowedIps: string[];
172
+ endpoint?: string;
173
+ persistentKeepalive?: number;
174
+ bytesSent: number;
175
+ bytesReceived: number;
176
+ packetsSent: number;
177
+ packetsReceived: number;
178
+ lastHandshakeTime?: string;
179
+ }
139
180
  export type TVpnClientCommands = {
140
181
  connect: {
141
182
  params: {
@@ -221,6 +262,28 @@ export type TVpnServerCommands = {
221
262
  };
222
263
  result: IVpnClientTelemetry;
223
264
  };
265
+ generateWgKeypair: {
266
+ params: Record<string, never>;
267
+ result: IVpnKeypair;
268
+ };
269
+ addWgPeer: {
270
+ params: {
271
+ peer: IWgPeerConfig;
272
+ };
273
+ result: void;
274
+ };
275
+ removeWgPeer: {
276
+ params: {
277
+ publicKey: string;
278
+ };
279
+ result: void;
280
+ };
281
+ listWgPeers: {
282
+ params: Record<string, never>;
283
+ result: {
284
+ peers: IWgPeerInfo[];
285
+ };
286
+ };
224
287
  };
225
288
  export type TVpnPlatform = 'linux' | 'macos' | 'windows' | 'unknown';
226
289
  export interface IVpnServiceUnit {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartvpn",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "private": false,
5
5
  "description": "A VPN solution with TypeScript control plane and Rust data plane daemon",
6
6
  "type": "module",
package/readme.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  A high-performance VPN with a **TypeScript control plane** and a **Rust data plane daemon**. Manage VPN connections with clean, fully-typed APIs while all networking heavy lifting — encryption, tunneling, QoS, rate limiting — runs at native speed in Rust.
4
4
 
5
- 🔒 **Noise NK** handshake + **XChaCha20-Poly1305** encryption
6
- 🚀 **Dual transport**: WebSocket (Cloudflare-friendly) and raw **QUIC** (with datagram support)
7
- 📊 **Adaptive QoS**: packet classification, priority queues, per-client rate limiting
8
- 🔄 **Auto-transport**: tries QUIC first, falls back to WebSocket seamlessly
9
- 📡 **Real-time telemetry**: RTT, jitter, loss, link health — all exposed via typed APIs
5
+ 🔒 **Noise NK** handshake + **XChaCha20-Poly1305** encryption
6
+ 🚀 **Dual transport**: WebSocket (Cloudflare-friendly) and raw **QUIC** (with datagram support)
7
+ 📊 **Adaptive QoS**: packet classification, priority queues, per-client rate limiting
8
+ 🔄 **Auto-transport**: tries QUIC first, falls back to WebSocket seamlessly
9
+ 📡 **Real-time telemetry**: RTT, jitter, loss, link health — all exposed via typed APIs
10
10
 
11
11
  ## Issue Reporting and Security
12
12
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartvpn',
6
- version: '1.4.0',
6
+ version: '1.5.0',
7
7
  description: 'A VPN solution with TypeScript control plane and Rust data plane daemon'
8
8
  }
package/ts/index.ts CHANGED
@@ -4,3 +4,4 @@ export { VpnClient } from './smartvpn.classes.vpnclient.js';
4
4
  export { VpnServer } from './smartvpn.classes.vpnserver.js';
5
5
  export { VpnConfig } from './smartvpn.classes.vpnconfig.js';
6
6
  export { VpnInstaller } from './smartvpn.classes.vpninstaller.js';
7
+ export { WgConfigGenerator } from './smartvpn.classes.wgconfig.js';
@@ -12,17 +12,45 @@ export class VpnConfig {
12
12
  * Validate a client config object. Throws on invalid config.
13
13
  */
14
14
  public static validateClientConfig(config: IVpnClientConfig): void {
15
- if (!config.serverUrl) {
16
- throw new Error('VpnConfig: serverUrl is required');
17
- }
18
- // For QUIC-only transport, serverUrl is a host:port address; for WebSocket/auto it must be ws:// or wss://
19
- if (config.transport !== 'quic') {
20
- if (!config.serverUrl.startsWith('wss://') && !config.serverUrl.startsWith('ws://')) {
21
- throw new Error('VpnConfig: serverUrl must start with wss:// or ws:// (for WebSocket transport)');
15
+ if (config.transport === 'wireguard') {
16
+ // WireGuard-specific validation
17
+ if (!config.wgPrivateKey) {
18
+ throw new Error('VpnConfig: wgPrivateKey is required for WireGuard transport');
19
+ }
20
+ VpnConfig.validateBase64Key(config.wgPrivateKey, 'wgPrivateKey');
21
+ if (!config.wgAddress) {
22
+ throw new Error('VpnConfig: wgAddress is required for WireGuard transport');
23
+ }
24
+ if (!config.serverPublicKey) {
25
+ throw new Error('VpnConfig: serverPublicKey is required for WireGuard transport');
26
+ }
27
+ VpnConfig.validateBase64Key(config.serverPublicKey, 'serverPublicKey');
28
+ if (!config.wgEndpoint) {
29
+ throw new Error('VpnConfig: wgEndpoint is required for WireGuard transport');
30
+ }
31
+ if (config.wgPresharedKey) {
32
+ VpnConfig.validateBase64Key(config.wgPresharedKey, 'wgPresharedKey');
33
+ }
34
+ if (config.wgAllowedIps) {
35
+ for (const cidr of config.wgAllowedIps) {
36
+ if (!VpnConfig.isValidCidr(cidr)) {
37
+ throw new Error(`VpnConfig: invalid allowedIp CIDR: ${cidr}`);
38
+ }
39
+ }
40
+ }
41
+ } else {
42
+ if (!config.serverUrl) {
43
+ throw new Error('VpnConfig: serverUrl is required');
44
+ }
45
+ // For QUIC-only transport, serverUrl is a host:port address; for WebSocket/auto it must be ws:// or wss://
46
+ if (config.transport !== 'quic') {
47
+ if (!config.serverUrl.startsWith('wss://') && !config.serverUrl.startsWith('ws://')) {
48
+ throw new Error('VpnConfig: serverUrl must start with wss:// or ws:// (for WebSocket transport)');
49
+ }
50
+ }
51
+ if (!config.serverPublicKey) {
52
+ throw new Error('VpnConfig: serverPublicKey is required');
22
53
  }
23
- }
24
- if (!config.serverPublicKey) {
25
- throw new Error('VpnConfig: serverPublicKey is required');
26
54
  }
27
55
  if (config.mtu !== undefined && (config.mtu < 576 || config.mtu > 65535)) {
28
56
  throw new Error('VpnConfig: mtu must be between 576 and 65535');
@@ -43,20 +71,51 @@ export class VpnConfig {
43
71
  * Validate a server config object. Throws on invalid config.
44
72
  */
45
73
  public static validateServerConfig(config: IVpnServerConfig): void {
46
- if (!config.listenAddr) {
47
- throw new Error('VpnConfig: listenAddr is required');
48
- }
49
- if (!config.privateKey) {
50
- throw new Error('VpnConfig: privateKey is required');
51
- }
52
- if (!config.publicKey) {
53
- throw new Error('VpnConfig: publicKey is required');
54
- }
55
- if (!config.subnet) {
56
- throw new Error('VpnConfig: subnet is required');
57
- }
58
- if (!VpnConfig.isValidSubnet(config.subnet)) {
59
- throw new Error(`VpnConfig: invalid subnet: ${config.subnet}`);
74
+ if (config.transportMode === 'wireguard') {
75
+ // WireGuard server validation
76
+ if (!config.privateKey) {
77
+ throw new Error('VpnConfig: privateKey is required');
78
+ }
79
+ VpnConfig.validateBase64Key(config.privateKey, 'privateKey');
80
+ if (!config.wgPeers || config.wgPeers.length === 0) {
81
+ throw new Error('VpnConfig: at least one wgPeers entry is required for WireGuard mode');
82
+ }
83
+ for (const peer of config.wgPeers) {
84
+ if (!peer.publicKey) {
85
+ throw new Error('VpnConfig: peer publicKey is required');
86
+ }
87
+ VpnConfig.validateBase64Key(peer.publicKey, 'peer.publicKey');
88
+ if (!peer.allowedIps || peer.allowedIps.length === 0) {
89
+ throw new Error('VpnConfig: peer allowedIps is required');
90
+ }
91
+ for (const cidr of peer.allowedIps) {
92
+ if (!VpnConfig.isValidCidr(cidr)) {
93
+ throw new Error(`VpnConfig: invalid peer allowedIp CIDR: ${cidr}`);
94
+ }
95
+ }
96
+ if (peer.presharedKey) {
97
+ VpnConfig.validateBase64Key(peer.presharedKey, 'peer.presharedKey');
98
+ }
99
+ }
100
+ if (config.wgListenPort !== undefined && (config.wgListenPort < 1 || config.wgListenPort > 65535)) {
101
+ throw new Error('VpnConfig: wgListenPort must be between 1 and 65535');
102
+ }
103
+ } else {
104
+ if (!config.listenAddr) {
105
+ throw new Error('VpnConfig: listenAddr is required');
106
+ }
107
+ if (!config.privateKey) {
108
+ throw new Error('VpnConfig: privateKey is required');
109
+ }
110
+ if (!config.publicKey) {
111
+ throw new Error('VpnConfig: publicKey is required');
112
+ }
113
+ if (!config.subnet) {
114
+ throw new Error('VpnConfig: subnet is required');
115
+ }
116
+ if (!VpnConfig.isValidSubnet(config.subnet)) {
117
+ throw new Error(`VpnConfig: invalid subnet: ${config.subnet}`);
118
+ }
60
119
  }
61
120
  if (config.mtu !== undefined && (config.mtu < 576 || config.mtu > 65535)) {
62
121
  throw new Error('VpnConfig: mtu must be between 576 and 65535');
@@ -104,4 +163,41 @@ export class VpnConfig {
104
163
  const prefixNum = parseInt(prefix, 10);
105
164
  return !isNaN(prefixNum) && prefixNum >= 0 && prefixNum <= 32;
106
165
  }
166
+
167
+ /**
168
+ * Validate a CIDR string (IPv4 or IPv6).
169
+ */
170
+ private static isValidCidr(cidr: string): boolean {
171
+ const parts = cidr.split('/');
172
+ if (parts.length !== 2) return false;
173
+ const prefixNum = parseInt(parts[1], 10);
174
+ if (isNaN(prefixNum) || prefixNum < 0) return false;
175
+ // IPv4
176
+ if (VpnConfig.isValidIp(parts[0])) {
177
+ return prefixNum <= 32;
178
+ }
179
+ // IPv6 (basic check)
180
+ if (parts[0].includes(':')) {
181
+ return prefixNum <= 128;
182
+ }
183
+ return false;
184
+ }
185
+
186
+ /**
187
+ * Validate a base64-encoded 32-byte key (WireGuard X25519 format).
188
+ */
189
+ private static validateBase64Key(key: string, fieldName: string): void {
190
+ if (key.length !== 44) {
191
+ throw new Error(`VpnConfig: ${fieldName} must be 44 characters (base64 of 32 bytes), got ${key.length}`);
192
+ }
193
+ try {
194
+ const buf = Buffer.from(key, 'base64');
195
+ if (buf.length !== 32) {
196
+ throw new Error(`VpnConfig: ${fieldName} must decode to 32 bytes, got ${buf.length}`);
197
+ }
198
+ } catch (e) {
199
+ if (e instanceof Error && e.message.startsWith('VpnConfig:')) throw e;
200
+ throw new Error(`VpnConfig: ${fieldName} is not valid base64`);
201
+ }
202
+ }
107
203
  }
@@ -8,6 +8,8 @@ import type {
8
8
  IVpnClientInfo,
9
9
  IVpnKeypair,
10
10
  IVpnClientTelemetry,
11
+ IWgPeerConfig,
12
+ IWgPeerInfo,
11
13
  TVpnServerCommands,
12
14
  } from './smartvpn.interfaces.js';
13
15
 
@@ -121,6 +123,35 @@ export class VpnServer extends plugins.events.EventEmitter {
121
123
  return this.bridge.sendCommand('getClientTelemetry', { clientId });
122
124
  }
123
125
 
126
+ /**
127
+ * Generate a WireGuard-compatible X25519 keypair.
128
+ */
129
+ public async generateWgKeypair(): Promise<IVpnKeypair> {
130
+ return this.bridge.sendCommand('generateWgKeypair', {} as Record<string, never>);
131
+ }
132
+
133
+ /**
134
+ * Add a WireGuard peer (server must be running in wireguard mode).
135
+ */
136
+ public async addWgPeer(peer: IWgPeerConfig): Promise<void> {
137
+ await this.bridge.sendCommand('addWgPeer', { peer });
138
+ }
139
+
140
+ /**
141
+ * Remove a WireGuard peer by public key.
142
+ */
143
+ public async removeWgPeer(publicKey: string): Promise<void> {
144
+ await this.bridge.sendCommand('removeWgPeer', { publicKey });
145
+ }
146
+
147
+ /**
148
+ * List WireGuard peers with stats.
149
+ */
150
+ public async listWgPeers(): Promise<IWgPeerInfo[]> {
151
+ const result = await this.bridge.sendCommand('listWgPeers', {} as Record<string, never>);
152
+ return result.peers;
153
+ }
154
+
124
155
  /**
125
156
  * Stop the daemon bridge.
126
157
  */
@@ -0,0 +1,123 @@
1
+ import type { IWgPeerConfig } from './smartvpn.interfaces.js';
2
+
3
+ // ============================================================================
4
+ // WireGuard .conf file generator
5
+ // ============================================================================
6
+
7
+ export interface IWgClientConfOptions {
8
+ /** Client private key (base64) */
9
+ privateKey: string;
10
+ /** Client TUN address with prefix (e.g. 10.8.0.2/24) */
11
+ address: string;
12
+ /** DNS servers */
13
+ dns?: string[];
14
+ /** TUN MTU */
15
+ mtu?: number;
16
+ /** Server peer config */
17
+ peer: {
18
+ publicKey: string;
19
+ presharedKey?: string;
20
+ endpoint: string;
21
+ allowedIps: string[];
22
+ persistentKeepalive?: number;
23
+ };
24
+ }
25
+
26
+ export interface IWgServerConfOptions {
27
+ /** Server private key (base64) */
28
+ privateKey: string;
29
+ /** Server TUN address with prefix (e.g. 10.8.0.1/24) */
30
+ address: string;
31
+ /** UDP listen port */
32
+ listenPort: number;
33
+ /** DNS servers */
34
+ dns?: string[];
35
+ /** TUN MTU */
36
+ mtu?: number;
37
+ /** Enable NAT — adds PostUp/PostDown iptables rules */
38
+ enableNat?: boolean;
39
+ /** Network interface for NAT (e.g. eth0). Auto-detected if omitted. */
40
+ natInterface?: string;
41
+ /** Configured peers */
42
+ peers: IWgPeerConfig[];
43
+ }
44
+
45
+ /**
46
+ * Generates standard WireGuard .conf files compatible with wg-quick,
47
+ * WireGuard iOS/Android apps, and other standard WireGuard clients.
48
+ */
49
+ export class WgConfigGenerator {
50
+ /**
51
+ * Generate a client .conf file content.
52
+ */
53
+ public static generateClientConfig(opts: IWgClientConfOptions): string {
54
+ const lines: string[] = [];
55
+
56
+ lines.push('[Interface]');
57
+ lines.push(`PrivateKey = ${opts.privateKey}`);
58
+ lines.push(`Address = ${opts.address}`);
59
+ if (opts.dns && opts.dns.length > 0) {
60
+ lines.push(`DNS = ${opts.dns.join(', ')}`);
61
+ }
62
+ if (opts.mtu) {
63
+ lines.push(`MTU = ${opts.mtu}`);
64
+ }
65
+
66
+ lines.push('');
67
+ lines.push('[Peer]');
68
+ lines.push(`PublicKey = ${opts.peer.publicKey}`);
69
+ if (opts.peer.presharedKey) {
70
+ lines.push(`PresharedKey = ${opts.peer.presharedKey}`);
71
+ }
72
+ lines.push(`Endpoint = ${opts.peer.endpoint}`);
73
+ lines.push(`AllowedIPs = ${opts.peer.allowedIps.join(', ')}`);
74
+ if (opts.peer.persistentKeepalive) {
75
+ lines.push(`PersistentKeepalive = ${opts.peer.persistentKeepalive}`);
76
+ }
77
+
78
+ lines.push('');
79
+ return lines.join('\n');
80
+ }
81
+
82
+ /**
83
+ * Generate a server .conf file content.
84
+ */
85
+ public static generateServerConfig(opts: IWgServerConfOptions): string {
86
+ const lines: string[] = [];
87
+
88
+ lines.push('[Interface]');
89
+ lines.push(`PrivateKey = ${opts.privateKey}`);
90
+ lines.push(`Address = ${opts.address}`);
91
+ lines.push(`ListenPort = ${opts.listenPort}`);
92
+ if (opts.dns && opts.dns.length > 0) {
93
+ lines.push(`DNS = ${opts.dns.join(', ')}`);
94
+ }
95
+ if (opts.mtu) {
96
+ lines.push(`MTU = ${opts.mtu}`);
97
+ }
98
+ if (opts.enableNat) {
99
+ const iface = opts.natInterface || 'eth0';
100
+ lines.push(`PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ${iface} -j MASQUERADE`);
101
+ lines.push(`PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ${iface} -j MASQUERADE`);
102
+ }
103
+
104
+ for (const peer of opts.peers) {
105
+ lines.push('');
106
+ lines.push('[Peer]');
107
+ lines.push(`PublicKey = ${peer.publicKey}`);
108
+ if (peer.presharedKey) {
109
+ lines.push(`PresharedKey = ${peer.presharedKey}`);
110
+ }
111
+ lines.push(`AllowedIPs = ${peer.allowedIps.join(', ')}`);
112
+ if (peer.endpoint) {
113
+ lines.push(`Endpoint = ${peer.endpoint}`);
114
+ }
115
+ if (peer.persistentKeepalive) {
116
+ lines.push(`PersistentKeepalive = ${peer.persistentKeepalive}`);
117
+ }
118
+ }
119
+
120
+ lines.push('');
121
+ return lines.join('\n');
122
+ }
123
+ }
@@ -32,10 +32,24 @@ export interface IVpnClientConfig {
32
32
  mtu?: number;
33
33
  /** Keepalive interval in seconds (default: 30) */
34
34
  keepaliveIntervalSecs?: number;
35
- /** Transport protocol: 'auto' (default, tries QUIC then WS), 'websocket', or 'quic' */
36
- transport?: 'auto' | 'websocket' | 'quic';
35
+ /** Transport protocol: 'auto' (default, tries QUIC then WS), 'websocket', 'quic', or 'wireguard' */
36
+ transport?: 'auto' | 'websocket' | 'quic' | 'wireguard';
37
37
  /** For QUIC: SHA-256 hash of server certificate (base64) for cert pinning */
38
38
  serverCertHash?: string;
39
+ /** WireGuard: client private key (base64, X25519) */
40
+ wgPrivateKey?: string;
41
+ /** WireGuard: client TUN address (e.g. 10.8.0.2) */
42
+ wgAddress?: string;
43
+ /** WireGuard: client TUN address prefix length (default: 24) */
44
+ wgAddressPrefix?: number;
45
+ /** WireGuard: preshared key (base64, optional) */
46
+ wgPresharedKey?: string;
47
+ /** WireGuard: persistent keepalive interval in seconds */
48
+ wgPersistentKeepalive?: number;
49
+ /** WireGuard: server endpoint (host:port, e.g. vpn.example.com:51820) */
50
+ wgEndpoint?: string;
51
+ /** WireGuard: allowed IPs (CIDR strings, e.g. ['0.0.0.0/0']) */
52
+ wgAllowedIps?: string[];
39
53
  }
40
54
 
41
55
  export interface IVpnClientOptions {
@@ -72,12 +86,16 @@ export interface IVpnServerConfig {
72
86
  defaultRateLimitBytesPerSec?: number;
73
87
  /** Default burst size for new clients (bytes). Omit for unlimited. */
74
88
  defaultBurstBytes?: number;
75
- /** Transport mode: 'both' (default, WS+QUIC), 'websocket', or 'quic' */
76
- transportMode?: 'websocket' | 'quic' | 'both';
89
+ /** Transport mode: 'both' (default, WS+QUIC), 'websocket', 'quic', or 'wireguard' */
90
+ transportMode?: 'websocket' | 'quic' | 'both' | 'wireguard';
77
91
  /** QUIC listen address (host:port). Defaults to listenAddr. */
78
92
  quicListenAddr?: string;
79
93
  /** QUIC idle timeout in seconds (default: 30) */
80
94
  quicIdleTimeoutSecs?: number;
95
+ /** WireGuard: UDP listen port (default: 51820) */
96
+ wgListenPort?: number;
97
+ /** WireGuard: configured peers */
98
+ wgPeers?: IWgPeerConfig[];
81
99
  }
82
100
 
83
101
  export interface IVpnServerOptions {
@@ -187,6 +205,35 @@ export interface IVpnClientTelemetry {
187
205
  burstBytes?: number;
188
206
  }
189
207
 
208
+ // ============================================================================
209
+ // WireGuard-specific types
210
+ // ============================================================================
211
+
212
+ export interface IWgPeerConfig {
213
+ /** Peer's public key (base64, X25519) */
214
+ publicKey: string;
215
+ /** Optional preshared key (base64) */
216
+ presharedKey?: string;
217
+ /** Allowed IP ranges (CIDR strings) */
218
+ allowedIps: string[];
219
+ /** Peer endpoint (host:port) — optional for server peers, required for client */
220
+ endpoint?: string;
221
+ /** Persistent keepalive interval in seconds */
222
+ persistentKeepalive?: number;
223
+ }
224
+
225
+ export interface IWgPeerInfo {
226
+ publicKey: string;
227
+ allowedIps: string[];
228
+ endpoint?: string;
229
+ persistentKeepalive?: number;
230
+ bytesSent: number;
231
+ bytesReceived: number;
232
+ packetsSent: number;
233
+ packetsReceived: number;
234
+ lastHandshakeTime?: string;
235
+ }
236
+
190
237
  // ============================================================================
191
238
  // IPC Command maps (used by smartrust RustBridge<TCommands>)
192
239
  // ============================================================================
@@ -211,6 +258,10 @@ export type TVpnServerCommands = {
211
258
  setClientRateLimit: { params: { clientId: string; rateBytesPerSec: number; burstBytes: number }; result: void };
212
259
  removeClientRateLimit: { params: { clientId: string }; result: void };
213
260
  getClientTelemetry: { params: { clientId: string }; result: IVpnClientTelemetry };
261
+ generateWgKeypair: { params: Record<string, never>; result: IVpnKeypair };
262
+ addWgPeer: { params: { peer: IWgPeerConfig }; result: void };
263
+ removeWgPeer: { params: { publicKey: string }; result: void };
264
+ listWgPeers: { params: Record<string, never>; result: { peers: IWgPeerInfo[] } };
214
265
  };
215
266
 
216
267
  // ============================================================================