x3ui-api 1.0.4 → 1.0.5

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 CHANGED
@@ -16,6 +16,7 @@ npm install x3ui-api
16
16
  - Protocol-specific builders with fluent API:
17
17
  - VLESS with Reality support
18
18
  - VMess with HTTP Upgrade support
19
+ - WireGuard support
19
20
  - Client management with fluent API
20
21
  - TypeScript support
21
22
 
@@ -161,6 +162,67 @@ async function createRealityInbound() {
161
162
  }
162
163
  ```
163
164
 
165
+ ### Creating a WireGuard Inbound
166
+
167
+ The library provides a convenient builder pattern for creating WireGuard inbounds:
168
+
169
+ ```javascript
170
+ const X3UIClient = require('x3ui-api');
171
+ const wireguard = require('x3ui-api/src/protocols/wireguard');
172
+
173
+ const client = new X3UIClient({
174
+ baseURL: 'http://your-x3ui-panel.com:54321'
175
+ });
176
+
177
+ async function createWireguardInbound() {
178
+ try {
179
+ await client.login('admin', 'password');
180
+
181
+ // Create a WireGuard inbound builder
182
+ let builder = new wireguard.WireguardBuilder(client)
183
+ .setRemark('My WireGuard Inbound')
184
+ .setPort(51820) // WireGuard port, will auto-generate if not provided
185
+ .setMtu(1420); // Optional, default is 1420
186
+
187
+ // Keys are automatically generated, but you can set them manually if needed
188
+ // builder.setSecretKey('your-base64-encoded-secret-key');
189
+
190
+ // Add a client
191
+ const clientBuilder = builder.addClient()
192
+ .setEmail('user@example.com')
193
+ .setTotalGB(100) // 100 GB traffic limit
194
+ .setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
195
+
196
+ // Generate key pair for the client (or you can set them manually)
197
+ clientBuilder.generateKeyPair();
198
+
199
+ // Set allowed IPs (default is 10.0.0.2/32)
200
+ clientBuilder.setAllowedIPs(['10.0.0.2/32']);
201
+
202
+ // Optionally generate a pre-shared key for additional security
203
+ clientBuilder.generatePresharedKey();
204
+
205
+ // Build and add the inbound
206
+ const inbound = await builder.build();
207
+ const createdInbound = await client.addInbound(inbound);
208
+
209
+ // Update the builder with the server-returned inbound to get all metrics and IDs
210
+ builder = new wireguard.WireguardBuilder(client, createdInbound);
211
+
212
+ console.log('Inbound created:', createdInbound);
213
+
214
+ // Get WireGuard configuration for the client
215
+ const config = builder.getClientConfig(0, 'your-server-ip.com');
216
+ console.log('Client configuration:');
217
+ console.log(config);
218
+ } catch (error) {
219
+ console.error('Error creating inbound:', error.message);
220
+ }
221
+ }
222
+
223
+ createWireguardInbound();
224
+ ```
225
+
164
226
  ### Real-World Example
165
227
 
166
228
  Here's a complete example showing how to create a VMess inbound and get the client link:
@@ -313,6 +375,44 @@ Methods:
313
375
  - `getClientLink(clientIndex, host)` - Get connection link for a client
314
376
  - `build()` - Build the final inbound config
315
377
 
378
+ #### WireGuard Builder
379
+
380
+ ```javascript
381
+ const wireguard = require('x3ui-api/src/protocols/wireguard');
382
+ const builder = new wireguard.WireguardBuilder(client, options);
383
+ ```
384
+
385
+ Methods:
386
+ - `setPort(port)` - Set the port for the inbound
387
+ - `setRemark(remark)` - Set the name/remark for the inbound
388
+ - `setMtu(mtu)` - Set the MTU value (default: 1420)
389
+ - `setSecretKey(secretKey)` - Set the server's secret key (automatically generates if not provided)
390
+ - `setNoKernelTun(noKernelTun)` - Set whether to disable kernel TUN support
391
+ - `setSniffing(enabled, destOverride, metadataOnly, routeOnly)` - Configure sniffing
392
+ - `setListenIP(ip)` - Set listen IP address
393
+ - `setExpiryTime(timestamp)` - Set inbound expiry time
394
+ - `addClient(options)` - Add a new client to the inbound
395
+ - `getClientLink(clientIndex, host, port)` - Get connection link for a client
396
+ - `getClientConfig(clientIndex, host, port)` - Get WireGuard configuration file content for a client
397
+ - `build()` - Build the final inbound config
398
+
399
+ ##### WireGuard Client Builder
400
+
401
+ Methods:
402
+ - `setPrivateKey(privateKey)` - Set client's private key
403
+ - `setPublicKey(publicKey)` - Set client's public key
404
+ - `setPreSharedKey(preSharedKey)` - Set pre-shared key for additional security
405
+ - `setAllowedIPs(allowedIPs)` - Set allowed IP ranges (default: ['10.0.0.2/32'])
406
+ - `setKeepAlive(keepAlive)` - Set keep-alive interval in seconds
407
+ - `generateKeyPair()` - Generate a new key pair for the client
408
+ - `generatePresharedKey()` - Generate a new pre-shared key
409
+ - `setEmail(email)` - Set client email
410
+ - `setTotalGB(gb)` - Set total traffic limit in GB
411
+ - `setExpiryTime(timestamp)` - Set client expiry time
412
+ - `setTgId(id)` - Set Telegram ID
413
+ - `getLink(host, port)` - Get WireGuard configuration as text
414
+ - `getConfigFile(host, port)` - Get WireGuard configuration file content
415
+
316
416
  ## License
317
417
 
318
418
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x3ui-api",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "API client for x3ui panel",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -0,0 +1,118 @@
1
+ import WireguardClientBuilder from './WireguardClientBuilder';
2
+ import {ClientSettings} from "../../index";
3
+
4
+ /**
5
+ * WireguardBuilder class for creating and managing Wireguard server configurations.
6
+ * This builder provides a fluent interface for setting up Wireguard servers and managing clients.
7
+ */
8
+ export default class WireguardBuilder {
9
+ /**
10
+ * Creates a new WireguardBuilder instance.
11
+ * @param client - The client connection or context to use for building the configuration
12
+ * @param options - Optional configuration parameters for the Wireguard server
13
+ */
14
+ constructor(client: any, options?: any);
15
+
16
+ /**
17
+ * Sets the port for the Wireguard server.
18
+ * @param port - The port number to listen on
19
+ * @returns The current builder instance for method chaining
20
+ */
21
+ setPort(port: number): this;
22
+
23
+ /**
24
+ * Sets a descriptive remark for the Wireguard server.
25
+ * @param remark - The remark or name for this server
26
+ * @returns The current builder instance for method chaining
27
+ */
28
+ setRemark(remark: string): this;
29
+
30
+ /**
31
+ * Sets the Maximum Transmission Unit (MTU) size.
32
+ * @param mtu - The MTU value in bytes
33
+ * @returns The current builder instance for method chaining
34
+ */
35
+ setMtu(mtu: number): this;
36
+
37
+ /**
38
+ * Sets the server's private key.
39
+ * @param secretKey - The Wireguard private key in base64 format
40
+ * @returns The current builder instance for method chaining
41
+ */
42
+ setSecretKey(secretKey: string): this;
43
+
44
+ /**
45
+ * Configures whether to use kernel TUN interface or userspace implementation.
46
+ * @param noKernelTun - If true, uses userspace implementation instead of kernel TUN
47
+ * @returns The current builder instance for method chaining
48
+ */
49
+ setNoKernelTun(noKernelTun: boolean): this;
50
+
51
+ /**
52
+ * Configures traffic sniffing options.
53
+ * @param enabled - Whether sniffing is enabled
54
+ * @param destOverride - Array of protocols to override destination with sniffed value
55
+ * @param metadataOnly - If true, only sniffs metadata
56
+ * @param routeOnly - If true, only uses sniffed information for routing
57
+ * @returns The current builder instance for method chaining
58
+ */
59
+ setSniffing(enabled: boolean, destOverride?: string[], metadataOnly?: boolean, routeOnly?: boolean): this;
60
+
61
+ /**
62
+ * Sets the IP address the server listens on.
63
+ * @param ip - The IP address to bind to
64
+ * @returns The current builder instance for method chaining
65
+ */
66
+ setListenIP(ip: string): this;
67
+
68
+ /**
69
+ * Sets the expiration time for the server configuration.
70
+ * @param timestamp - Unix timestamp when the configuration expires
71
+ * @returns The current builder instance for method chaining
72
+ */
73
+ setExpiryTime(timestamp: number): this;
74
+
75
+ /**
76
+ * Creates and adds a new client to this Wireguard server.
77
+ * @param options - Optional client settings
78
+ * @returns A new WireguardClientBuilder instance for configuring the client
79
+ */
80
+ addClient(options?: Partial<ClientSettings>): WireguardClientBuilder;
81
+
82
+ /**
83
+ * Generates a connection link for a client.
84
+ * @param clientIndex - Index of the client (default: 0)
85
+ * @param host - Host address to use in the link (defaults to server address)
86
+ * @param port - Port to use in the link (defaults to server port)
87
+ * @returns A formatted connection link string
88
+ */
89
+ getClientLink(clientIndex?: number, host?: string, port?: number): string;
90
+
91
+ /**
92
+ * Generates a configuration file for a client.
93
+ * @param clientIndex - Index of the client (default: 0)
94
+ * @param host - Host address to use in the config (defaults to server address)
95
+ * @param port - Port to use in the config (defaults to server port)
96
+ * @returns A formatted configuration file content as string
97
+ */
98
+ getClientConfig(clientIndex?: number, host?: string, port?: number): string;
99
+
100
+ /**
101
+ * Generates a random port number for the Wireguard server.
102
+ * @returns A random port number
103
+ */
104
+ generateRandomPort(): number;
105
+
106
+ /**
107
+ * Derives the public key from a given private key.
108
+ * @param secretKey - The Wireguard private key in base64 format
109
+ * @returns The corresponding public key in base64 format
110
+ */
111
+ derivePublicKey(secretKey: string): string;
112
+
113
+ /**
114
+ * Builds and finalizes the Wireguard server configuration.
115
+ * @returns A Promise that resolves to the built configuration
116
+ */
117
+ build(): Promise<any>;
118
+ }
@@ -0,0 +1,204 @@
1
+ const keyUtils = require('./keyUtils');
2
+ const WireguardClientBuilder = require('./WireguardClientBuilder');
3
+
4
+ module.exports = class WireguardBuilder {
5
+ constructor(client, options = {}) {
6
+ this.client = client;
7
+ // Initialize from InboundConfig
8
+ this.id = options.id || undefined;
9
+ this.port = options.port || 0;
10
+ this.remark = options.remark || '';
11
+ this.listenIP = options.listen || '';
12
+ this.expiryTime = options.expiryTime || 0;
13
+ this.enable = true;
14
+ this.up = options.up || 0;
15
+ this.down = options.down || 0;
16
+ this.total = options.total || 0;
17
+
18
+ // Initialize WireGuard specific settings
19
+ const settings = typeof options.settings === 'string'
20
+ ? JSON.parse(options.settings)
21
+ : options.settings || {};
22
+
23
+ this.mtu = settings.mtu || 1420;
24
+ this.secretKey = settings.secretKey || '';
25
+ this.publicKey = ''; // Will be derived from secretKey
26
+ this.noKernelTun = settings.noKernelTun || false;
27
+
28
+ // Initialize sniffing
29
+ this.sniffing = options.sniffing || {
30
+ enabled: false,
31
+ destOverride: ['http', 'tls', 'quic', 'fakedns'],
32
+ metadataOnly: false,
33
+ routeOnly: false
34
+ };
35
+
36
+ // Initialize allocate
37
+ this.allocate = options.allocate || {
38
+ strategy: 'always',
39
+ refresh: 5,
40
+ concurrency: 3
41
+ };
42
+
43
+ // Initialize clients
44
+ this.clients = [];
45
+
46
+ if (settings?.peers) {
47
+ settings.peers.forEach(peer => {
48
+ this.addClient(peer);
49
+ });
50
+ }
51
+
52
+ // If secretKey is provided, derive publicKey
53
+ if (this.secretKey) {
54
+ this.publicKey = keyUtils.derivePublicKey(this.secretKey);
55
+ }
56
+
57
+ // If no secretKey provided, generate one
58
+ if (!this.secretKey) {
59
+ let pair = keyUtils.generateKeyPair();
60
+ this.secretKey = pair.privateKey;
61
+ this.publicKey = pair.publicKey;
62
+ }
63
+ }
64
+
65
+ setPort(port) {
66
+ this.port = port;
67
+ return this;
68
+ }
69
+
70
+ setRemark(remark) {
71
+ this.remark = remark;
72
+ return this;
73
+ }
74
+
75
+ setMtu(mtu) {
76
+ this.mtu = mtu;
77
+ return this;
78
+ }
79
+
80
+ setSecretKey(secretKey) {
81
+ this.secretKey = secretKey;
82
+ this.publicKey = keyUtils.derivePublicKey(secretKey);
83
+ return this;
84
+ }
85
+
86
+ setNoKernelTun(noKernelTun) {
87
+ this.noKernelTun = noKernelTun;
88
+ return this;
89
+ }
90
+
91
+ setSniffing(enabled, destOverride = ['http', 'tls', 'quic', 'fakedns'], metadataOnly = false, routeOnly = false) {
92
+ this.sniffing = {
93
+ enabled,
94
+ destOverride,
95
+ metadataOnly,
96
+ routeOnly
97
+ };
98
+ return this;
99
+ }
100
+
101
+ setListenIP(ip) {
102
+ this.listenIP = ip;
103
+ return this;
104
+ }
105
+
106
+ setExpiryTime(timestamp) {
107
+ this.expiryTime = timestamp;
108
+ return this;
109
+ }
110
+
111
+ addClient(options = {}) {
112
+ const builder = new WireguardClientBuilder(this);
113
+ if (options.privateKey) builder.setPrivateKey(options.privateKey);
114
+ if (options.publicKey) builder.setPublicKey(options.publicKey);
115
+ if (options.preSharedKey) builder.setPreSharedKey(options.preSharedKey);
116
+ if (options.allowedIPs) builder.setAllowedIPs(options.allowedIPs);
117
+ if (options.keepAlive !== undefined) builder.setKeepAlive(options.keepAlive);
118
+ if (options.email) builder.setEmail(options.email);
119
+ if (options.totalGB) builder.setTotalGB(options.totalGB);
120
+ if (options.expiryTime) builder.setExpiryTime(options.expiryTime);
121
+ if (options.tgId) builder.setTgId(options.tgId);
122
+
123
+ this.clients.push(builder);
124
+ return builder;
125
+ }
126
+
127
+ getClientLink(clientIndex = 0, host, port) {
128
+ if (clientIndex < 0 || clientIndex >= this.clients.length) {
129
+ throw new Error('Invalid client index');
130
+ }
131
+ const client = this.clients[clientIndex];
132
+ return client.getLink(host || this.listenIP || 'localhost', port || this.port);
133
+ }
134
+
135
+ getClientConfig(clientIndex = 0, host, port) {
136
+ if (clientIndex < 0 || clientIndex >= this.clients.length) {
137
+ throw new Error('Invalid client index');
138
+ }
139
+ const client = this.clients[clientIndex];
140
+ return client.getConfigFile(host || this.listenIP || 'localhost', port || this.port);
141
+ }
142
+
143
+ generateRandomPort() {
144
+ return Math.floor(Math.random() * (65535 - 1024) + 1024);
145
+ }
146
+
147
+ async build() {
148
+ if (!this.remark) {
149
+ throw new Error('Remark is required');
150
+ }
151
+
152
+ // If no port specified, find unused one
153
+ if (!this.port) {
154
+ const inbounds = await this.client.getInbounds();
155
+ const usedPorts = new Set(inbounds.map(i => i.port));
156
+ let port;
157
+ do {
158
+ port = this.generateRandomPort();
159
+ } while (usedPorts.has(port));
160
+ this.port = port;
161
+ }
162
+
163
+ // If no secretKey provided, generate one
164
+ if (!this.secretKey) {
165
+ this.secretKey = keyUtils.generatePrivateKey();
166
+ this.publicKey = keyUtils.derivePublicKey(this.secretKey);
167
+ }
168
+
169
+ // If no clients added, create one default client
170
+ if (this.clients.length === 0) {
171
+ this.addClient();
172
+ }
173
+
174
+ // Build all clients
175
+ const clientConfigs = await Promise.all(this.clients.map(builder => builder.build()));
176
+
177
+ // Create tag for inbound
178
+ const tag = `inbound-${this.port}`;
179
+
180
+ // Build the complete inbound configuration
181
+ return {
182
+ id: this.id,
183
+ up: this.up,
184
+ down: this.down,
185
+ total: this.total,
186
+ remark: this.remark,
187
+ enable: this.enable,
188
+ expiryTime: this.expiryTime,
189
+ listen: this.listenIP,
190
+ port: this.port,
191
+ protocol: 'wireguard',
192
+ settings: {
193
+ mtu: this.mtu,
194
+ secretKey: this.secretKey,
195
+ peers: clientConfigs,
196
+ noKernelTun: this.noKernelTun
197
+ },
198
+ streamSettings: {},
199
+ tag,
200
+ sniffing: this.sniffing,
201
+ allocate: this.allocate
202
+ };
203
+ }
204
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Type definitions for WireguardClientBuilder
3
+ * Provides functionality for building WireGuard client configurations
4
+ */
5
+ import ClientBuilder from '../../core/ClientBuilder';
6
+
7
+ /**
8
+ * WireguardClientBuilder class for creating and managing WireGuard client configurations
9
+ * Extends the base ClientBuilder to provide WireGuard-specific functionality
10
+ */
11
+ export default class WireguardClientBuilder extends ClientBuilder {
12
+ /**
13
+ * Creates a new WireguardClientBuilder instance
14
+ * @param parent - The parent object that owns this builder
15
+ * @param options - Optional client settings
16
+ */
17
+ constructor(parent: any, options?: any);
18
+
19
+ /**
20
+ * Sets the client's private key
21
+ * @param privateKey - The WireGuard private key in base64 format
22
+ * @returns The builder instance for method chaining
23
+ */
24
+ setPrivateKey(privateKey: string): this;
25
+
26
+ /**
27
+ * Sets the server's public key
28
+ * @param publicKey - The WireGuard public key in base64 format
29
+ * @returns The builder instance for method chaining
30
+ */
31
+ setPublicKey(publicKey: string): this;
32
+
33
+ /**
34
+ * Sets the pre-shared key for additional security
35
+ * @param preSharedKey - The pre-shared key in base64 format
36
+ * @returns The builder instance for method chaining
37
+ */
38
+ setPreSharedKey(preSharedKey: string): this;
39
+
40
+ /**
41
+ * Sets the allowed IP addresses/ranges for routing through the tunnel
42
+ * @param allowedIPs - Array of IP addresses/ranges in CIDR notation
43
+ * @returns The builder instance for method chaining
44
+ */
45
+ setAllowedIPs(allowedIPs: string[]): this;
46
+
47
+ /**
48
+ * Sets the persistent keepalive interval
49
+ * @param keepAlive - Interval in seconds between keepalive packets
50
+ * @returns The builder instance for method chaining
51
+ */
52
+ setKeepAlive(keepAlive: number): this;
53
+
54
+ /**
55
+ * Generates a random pre-shared key
56
+ * @returns The builder instance for method chaining
57
+ */
58
+ generatePresharedKey(): this;
59
+
60
+ /**
61
+ * Generates a new public/private key pair
62
+ * @returns The builder instance for method chaining
63
+ */
64
+ generateKeyPair(): this;
65
+
66
+ /**
67
+ * Builds and returns the complete WireGuard client configuration
68
+ * @returns The WireGuard client configuration object
69
+ */
70
+ build(): any;
71
+
72
+ /**
73
+ * Generates a WireGuard connection URI/link for easy client configuration
74
+ * @param host - The server hostname or IP address
75
+ * @param port - The server port number
76
+ * @returns A WireGuard connection URI string
77
+ */
78
+ getLink(host: string, port: number): string;
79
+ }
@@ -0,0 +1,88 @@
1
+ const crypto = require("crypto");
2
+ const keyUtils = require('./keyUtils');
3
+ const ClientBuilder = require('./../../core/ClientBuilder');
4
+
5
+ module.exports = class WireguardClientBuilder extends ClientBuilder {
6
+ constructor(parent, options) {
7
+ super(parent);
8
+ this.privateKey = options.privateKey || '';
9
+ this.publicKey = options.publicKey || '';
10
+ this.preSharedKey = options.preSharedKey || '';
11
+ this.allowedIPs = options.allowedIPs || ['10.0.0.2/32'];
12
+ this.keepAlive = options.keepAlive || 0;
13
+ }
14
+
15
+ setPrivateKey(privateKey) {
16
+ this.privateKey = privateKey;
17
+ return this;
18
+ }
19
+
20
+ setPublicKey(publicKey) {
21
+ this.publicKey = publicKey;
22
+ return this;
23
+ }
24
+
25
+ setPreSharedKey(preSharedKey) {
26
+ this.preSharedKey = preSharedKey;
27
+ return this;
28
+ }
29
+
30
+ setAllowedIPs(allowedIPs) {
31
+ this.allowedIPs = allowedIPs;
32
+ return this;
33
+ }
34
+
35
+ setKeepAlive(keepAlive) {
36
+ this.keepAlive = keepAlive;
37
+ return this;
38
+ }
39
+
40
+ generatePresharedKey() {
41
+ this.preSharedKey = keyUtils.generatePresharedKey();
42
+ return this;
43
+ }
44
+
45
+ generateKeyPair() {
46
+ const keyPair = keyUtils.generateKeyPair();
47
+ this.privateKey = keyPair.privateKey;
48
+ this.publicKey = keyPair.publicKey;
49
+ return this;
50
+ }
51
+
52
+ build() {
53
+ const baseConfig = super.build();
54
+ return {
55
+ ...baseConfig,
56
+ privateKey: this.privateKey || '',
57
+ publicKey: this.publicKey || '',
58
+ preSharedKey: this.preSharedKey || '',
59
+ allowedIPs: this.allowedIPs,
60
+ keepAlive: this.keepAlive
61
+ };
62
+ }
63
+
64
+ getLink(host, port) {
65
+ // Generate WireGuard client configuration
66
+ const serverPublicKey = this.parent.secretKey ?
67
+ this.parent.publicKey :
68
+ 'MISSING_SERVER_PUBLIC_KEY';
69
+
70
+ const config = [
71
+ '[Interface]',
72
+ `PrivateKey = ${this.privateKey}`,
73
+ `Address = ${this.allowedIPs[0]}`,
74
+ 'DNS = 1.1.1.1, 1.0.0.1',
75
+ `MTU = ${this.parent.mtu || 1420}`,
76
+ '',
77
+ `# ${this.parent.remark || 'WireGuard'}-${this.email || 'default'}`,
78
+ '[Peer]',
79
+ `PublicKey = ${serverPublicKey}`,
80
+ 'AllowedIPs = 0.0.0.0/0, ::/0',
81
+ `Endpoint = ${host}:${port}`,
82
+ this.preSharedKey ? `PresharedKey = ${this.preSharedKey}` : '',
83
+ ].filter(Boolean).join('\n');
84
+
85
+ // Return the configuration as a data URI
86
+ return config;
87
+ }
88
+ }
@@ -0,0 +1,9 @@
1
+ import WireguardBuilder from "./WireguardBuilder";
2
+ import WireguardClientBuilder from "./WireguardClientBuilder";
3
+
4
+ declare const _default: {
5
+ WireguardBuilder: typeof WireguardBuilder;
6
+ WireguardClientBuilder: typeof WireguardClientBuilder;
7
+ };
8
+
9
+ export default _default;
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ WireguardBuilder: require('./WireguardBuilder'),
3
+ WireguardClientBuilder: require('./WireguardClientBuilder')
4
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * WireGuard key utilities
3
+ * Pure JavaScript implementation of Curve25519 for WireGuard key generation
4
+ */
5
+
6
+ const crypto = require('crypto');
7
+
8
+ /**
9
+ * Generate a new WireGuard private key
10
+ * @returns {string} Base64-encoded private key
11
+ */
12
+ function generatePrivateKey() {
13
+ const key = crypto.randomBytes(32);
14
+ return key.toString('base64');
15
+ }
16
+
17
+ /**
18
+ * Generate a new WireGuard pre-shared key
19
+ * @returns {string} Base64-encoded pre-shared key
20
+ */
21
+ function generatePresharedKey() {
22
+ const key = crypto.randomBytes(32);
23
+ return key.toString('base64');
24
+ }
25
+
26
+ /**
27
+ * Derive a public key from a private key using Curve25519
28
+ * @param {string} privateKeyBase64 Base64-encoded private key
29
+ * @returns {string} Base64-encoded public key
30
+ */
31
+ function derivePublicKey(privateKeyBase64) {
32
+ const privateKey = Buffer.from(privateKeyBase64, 'base64');
33
+ const publicKey = crypto.createPublicKey({
34
+ key: crypto.createPrivateKey({
35
+ key: Buffer.concat([
36
+ Buffer.from('302e020100300506032b656e04220420', 'hex'),
37
+ privateKey
38
+ ]),
39
+ format: 'der',
40
+ type: 'pkcs8'
41
+ }),
42
+ format: 'der',
43
+ type: 'spki'
44
+ }).export({ format: 'der', type: 'spki' });
45
+
46
+ // Extract the raw public key bytes
47
+ return publicKey.slice(-32).toString('base64');
48
+ }
49
+
50
+ /**
51
+ * Generate a new WireGuard key pair
52
+ * @returns {Object} Object containing privateKey and publicKey in base64 format
53
+ */
54
+ function generateKeyPair() {
55
+ const privateKey = generatePrivateKey();
56
+ const publicKey = derivePublicKey(privateKey);
57
+ return { privateKey, publicKey };
58
+ }
59
+
60
+ /**
61
+ * Validate a WireGuard private key
62
+ * @param {string} privateKeyBase64 Base64-encoded private key
63
+ * @returns {boolean} True if valid, false otherwise
64
+ */
65
+ function isValidPrivateKey(privateKeyBase64) {
66
+ try {
67
+ const buf = Buffer.from(privateKeyBase64, 'base64');
68
+ return buf.length === 32;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Validate a WireGuard public key
76
+ * @param {string} publicKeyBase64 Base64-encoded public key
77
+ * @returns {boolean} True if valid, false otherwise
78
+ */
79
+ function isValidPublicKey(publicKeyBase64) {
80
+ try {
81
+ const buf = Buffer.from(publicKeyBase64, 'base64');
82
+ return buf.length === 32;
83
+ } catch {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ module.exports = {
89
+ generatePrivateKey,
90
+ generatePresharedKey,
91
+ derivePublicKey,
92
+ generateKeyPair,
93
+ isValidPrivateKey,
94
+ isValidPublicKey
95
+ };