x3ui-api 1.0.4 → 1.0.6-3
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 +100 -0
- package/package.json +1 -1
- package/src/core/ClientBuilder.js +3 -1
- package/src/core/X3UIClient.d.ts +2 -1
- package/src/core/X3UIClient.js +32 -6
- package/src/index.d.ts +6 -0
- package/src/index.js +1 -0
- package/src/protocols/vless/RealityBuilder.d.ts +12 -5
- package/src/protocols/vless/RealityBuilder.js +12 -2
- package/src/protocols/vless/RealityClientBuilder.js +3 -1
- package/src/protocols/vless/index.js +3 -1
- package/src/protocols/vmess/VmessBuilder.d.ts +3 -3
- package/src/protocols/vmess/VmessBuilder.js +3 -1
- package/src/protocols/vmess/VmessClientBuilder.js +3 -1
- package/src/protocols/vmess/index.js +3 -1
- package/src/protocols/wireguard/WireguardBuilder.d.ts +118 -0
- package/src/protocols/wireguard/WireguardBuilder.js +206 -0
- package/src/protocols/wireguard/WireguardClientBuilder.d.ts +79 -0
- package/src/protocols/wireguard/WireguardClientBuilder.js +90 -0
- package/src/protocols/wireguard/index.d.ts +9 -0
- package/src/protocols/wireguard/index.js +6 -0
- package/src/protocols/wireguard/keyUtils.js +95 -0
- package/src/index.d.ts~ +0 -185
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
package/src/core/X3UIClient.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {AxiosInstance} from "axios";
|
|
2
2
|
import {
|
|
3
|
+
DeepPartial,
|
|
3
4
|
InboundConfig,
|
|
4
5
|
LoginResponse,
|
|
5
6
|
SystemStats,
|
|
@@ -19,7 +20,7 @@ export default class X3UIClient {
|
|
|
19
20
|
|
|
20
21
|
addInbound(config: Omit<InboundConfig, 'id'>): Promise<InboundConfig>;
|
|
21
22
|
|
|
22
|
-
updateInbound(id: number, config:
|
|
23
|
+
updateInbound(id: number, config: DeepPartial<InboundConfig>): Promise<void>;
|
|
23
24
|
|
|
24
25
|
deleteInbound(id: number): Promise<void>;
|
|
25
26
|
|
package/src/core/X3UIClient.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
const axios = require("axios");
|
|
2
2
|
|
|
3
3
|
module.exports = class X3UIClient {
|
|
4
|
+
|
|
5
|
+
isAuthed = false;
|
|
6
|
+
config = {};
|
|
7
|
+
|
|
4
8
|
constructor(config) {
|
|
5
|
-
this.
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.config.parseJSONSettings ??= true;
|
|
6
11
|
this.client = axios.create({
|
|
7
12
|
baseURL: config.baseURL,
|
|
8
13
|
headers: config.token ? {
|
|
@@ -15,14 +20,14 @@ module.exports = class X3UIClient {
|
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* Login to the x3ui panel
|
|
18
|
-
* @param {string} username Panel username
|
|
19
|
-
* @param {string} password Panel password
|
|
23
|
+
* @param {string?} username Panel username
|
|
24
|
+
* @param {string?} password Panel password
|
|
20
25
|
* @returns {Promise<{success: boolean, msg: string, obj: any}>} Login response with success status and token
|
|
21
26
|
*/
|
|
22
27
|
async login(username, password) {
|
|
23
28
|
const formData = new URLSearchParams();
|
|
24
|
-
formData.append('username', username);
|
|
25
|
-
formData.append('password', password);
|
|
29
|
+
formData.append('username', username || this.config.username);
|
|
30
|
+
formData.append('password', password || this.config.password);
|
|
26
31
|
|
|
27
32
|
const response = await this.client.post('/login', formData, {
|
|
28
33
|
headers: {
|
|
@@ -32,12 +37,16 @@ module.exports = class X3UIClient {
|
|
|
32
37
|
|
|
33
38
|
if (response.data.success) {
|
|
34
39
|
this.client.defaults.headers.Cookie = `lang=en-US; ${response.headers.get("set-cookie")[0].split(";")[0]}`;
|
|
40
|
+
this.isAuthed = true;
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
return response.data;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
async getSystemStats() {
|
|
47
|
+
if(!this.isAuthed) {
|
|
48
|
+
await this.login();
|
|
49
|
+
}
|
|
41
50
|
const response = await this.client.post('/server/status');
|
|
42
51
|
return response.data.obj;
|
|
43
52
|
}
|
|
@@ -61,6 +70,9 @@ module.exports = class X3UIClient {
|
|
|
61
70
|
* }>>}
|
|
62
71
|
*/
|
|
63
72
|
async getInbounds() {
|
|
73
|
+
if(!this.isAuthed) {
|
|
74
|
+
await this.login();
|
|
75
|
+
}
|
|
64
76
|
const response = await this.client.get('/panel/api/inbounds/list');
|
|
65
77
|
let inbounds = response.data.obj;
|
|
66
78
|
if (this.parseJSONSettings) {
|
|
@@ -106,6 +118,9 @@ module.exports = class X3UIClient {
|
|
|
106
118
|
* @returns {Promise<void>}
|
|
107
119
|
*/
|
|
108
120
|
async addInbound(config) {
|
|
121
|
+
if(!this.isAuthed) {
|
|
122
|
+
await this.login();
|
|
123
|
+
}
|
|
109
124
|
config = this.stringifyInbound(config);
|
|
110
125
|
const response = await this.client.post('/panel/api/inbounds/add', config);
|
|
111
126
|
if(!response.data.success)
|
|
@@ -120,6 +135,9 @@ module.exports = class X3UIClient {
|
|
|
120
135
|
* @returns {Promise<void>}
|
|
121
136
|
*/
|
|
122
137
|
async updateInbound(id, config) {
|
|
138
|
+
if(!this.isAuthed) {
|
|
139
|
+
await this.login();
|
|
140
|
+
}
|
|
123
141
|
config = this.stringifyInbound(config);
|
|
124
142
|
const response = await this.client.post(`/panel/api/inbounds/update/${id}`, config);
|
|
125
143
|
if(!response.data.success)
|
|
@@ -133,6 +151,9 @@ module.exports = class X3UIClient {
|
|
|
133
151
|
* @returns {Promise<void>}
|
|
134
152
|
*/
|
|
135
153
|
async deleteInbound(id) {
|
|
154
|
+
if(!this.isAuthed) {
|
|
155
|
+
await this.login();
|
|
156
|
+
}
|
|
136
157
|
await this.client.post(`/panel/api/inbounds/del/${id}`);
|
|
137
158
|
}
|
|
138
159
|
|
|
@@ -141,7 +162,12 @@ module.exports = class X3UIClient {
|
|
|
141
162
|
* @returns {Promise<{privateKey: string, publicKey: string}>} New X25519 key pair
|
|
142
163
|
*/
|
|
143
164
|
async getNewX25519Cert() {
|
|
165
|
+
if(!this.isAuthed) {
|
|
166
|
+
await this.login();
|
|
167
|
+
}
|
|
144
168
|
const response = await this.client.post('/server/getNewX25519Cert');
|
|
145
169
|
return response.data.obj;
|
|
146
170
|
}
|
|
147
|
-
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports.default = module.exports;
|
package/src/index.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import X3UIClient from "./core/X3UIClient";
|
|
2
2
|
|
|
3
|
+
export type DeepPartial<T> = {
|
|
4
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
5
|
+
};
|
|
6
|
+
|
|
3
7
|
export default X3UIClient;
|
|
4
8
|
|
|
5
9
|
export interface X3UIConfig {
|
|
6
10
|
baseURL: string;
|
|
7
11
|
token?: string;
|
|
8
12
|
parseJSONSettings?: boolean;
|
|
13
|
+
username?: string;
|
|
14
|
+
password?: string;
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
export interface LoginResponse {
|
package/src/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import X3UIClient, {ClientSettings, InboundConfig} from "../../index";
|
|
2
|
-
import
|
|
1
|
+
import X3UIClient, {ClientSettings, InboundConfig, DeepPartial} from "../../index";
|
|
2
|
+
import RealityClientBuilder from "./RealityClientBuilder";
|
|
3
3
|
|
|
4
4
|
export default class RealityBuilder {
|
|
5
5
|
|
|
6
|
-
constructor(client: X3UIClient, inbound?:
|
|
6
|
+
constructor(client: X3UIClient, inbound?: DeepPartial<InboundConfig>);
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Set the port for the inbound. If not provided, will auto-generate unused port
|
|
@@ -53,14 +53,21 @@ export default class RealityBuilder {
|
|
|
53
53
|
/**
|
|
54
54
|
* Add a new client to the inbound
|
|
55
55
|
*/
|
|
56
|
-
addClient(options?:
|
|
56
|
+
addClient(options?: DeepPartial<ClientSettings>): RealityClientBuilder;
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* Get connection link for a client
|
|
60
60
|
* @param clientIndex Index of the client (defaults to 0)
|
|
61
61
|
* @param host Optional host address (defaults to listenIP or 'localhost')
|
|
62
62
|
*/
|
|
63
|
-
|
|
63
|
+
getClientLinkByIndex(clientIndex?: number, host?: string): string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get connection link for a client
|
|
67
|
+
* @param email Email of the client
|
|
68
|
+
* @param host Optional host address (defaults to listenIP or 'localhost')
|
|
69
|
+
*/
|
|
70
|
+
getClientLinkByEmail(email: string, host?: string): string;
|
|
64
71
|
|
|
65
72
|
/**
|
|
66
73
|
* Build the final inbound config
|
|
@@ -107,7 +107,7 @@ module.exports = class RealityBuilder {
|
|
|
107
107
|
return builder;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
getClientLinkByIndex(clientIndex = 0, host) {
|
|
111
111
|
if (clientIndex < 0 || clientIndex >= this.clients.length) {
|
|
112
112
|
throw new Error('Invalid client index');
|
|
113
113
|
}
|
|
@@ -115,6 +115,14 @@ module.exports = class RealityBuilder {
|
|
|
115
115
|
return client.getLink(host || this.listenIP || 'localhost', this.port);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
getClientLinkByEmail(email, host) {
|
|
119
|
+
const client = this.clients.find(client => client.email === email);
|
|
120
|
+
if (!client) {
|
|
121
|
+
throw new Error('Client not found');
|
|
122
|
+
}
|
|
123
|
+
return client.getLink(host || this.listenIP || 'localhost', this.port);
|
|
124
|
+
}
|
|
125
|
+
|
|
118
126
|
generateRandomPort() {
|
|
119
127
|
return Math.floor(Math.random() * (65535 - 1024) + 1024);
|
|
120
128
|
}
|
|
@@ -220,4 +228,6 @@ module.exports = class RealityBuilder {
|
|
|
220
228
|
}
|
|
221
229
|
};
|
|
222
230
|
}
|
|
223
|
-
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
module.exports.default = module.exports;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import X3UIClient, {ClientSettings, InboundConfig} from "../../index";
|
|
1
|
+
import X3UIClient, { ClientSettings, DeepPartial, InboundConfig } from "../../index";
|
|
2
2
|
import VmessClientBuilder from "./VmessClientBuilder";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -6,7 +6,7 @@ import VmessClientBuilder from "./VmessClientBuilder";
|
|
|
6
6
|
*/
|
|
7
7
|
export default class VmessBuilder {
|
|
8
8
|
|
|
9
|
-
constructor(client: X3UIClient, inbound?:
|
|
9
|
+
constructor(client: X3UIClient, inbound?: DeepPartial<InboundConfig>);
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Set the port for the inbound. If not provided, will auto-generate unused port
|
|
@@ -56,7 +56,7 @@ export default class VmessBuilder {
|
|
|
56
56
|
/**
|
|
57
57
|
* Add a new client to the inbound
|
|
58
58
|
*/
|
|
59
|
-
addClient(options?:
|
|
59
|
+
addClient(options?: DeepPartial<ClientSettings>): VmessClientBuilder;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Get connection link for a client
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import WireguardClientBuilder from './WireguardClientBuilder';
|
|
2
|
+
import { ClientSettings, DeepPartial } 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?: DeepPartial<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,206 @@
|
|
|
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
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports.default = module.exports;
|
|
@@ -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,90 @@
|
|
|
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
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports.default = module.exports;
|
|
@@ -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,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
|
+
};
|
package/src/index.d.ts~
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import X3UIClient from "./core/X3UIClient";
|
|
2
|
-
|
|
3
|
-
export default X3UIClient;
|
|
4
|
-
|
|
5
|
-
export interface X3UIConfig {
|
|
6
|
-
baseURL: string;
|
|
7
|
-
token?: string;
|
|
8
|
-
parseJSONSettings?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface LoginResponse {
|
|
12
|
-
success: boolean;
|
|
13
|
-
msg: string;
|
|
14
|
-
obj: any;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface InboundConfig {
|
|
18
|
-
id?: number;
|
|
19
|
-
up: number;
|
|
20
|
-
down: number;
|
|
21
|
-
total: number;
|
|
22
|
-
remark: string;
|
|
23
|
-
enable: boolean;
|
|
24
|
-
expiryTime: number | null;
|
|
25
|
-
clientStats: ClientStats[];
|
|
26
|
-
listen: string;
|
|
27
|
-
port: number;
|
|
28
|
-
protocol: string;
|
|
29
|
-
settings: string | InboundSettings;
|
|
30
|
-
streamSettings: string | StreamSettings;
|
|
31
|
-
tag: string;
|
|
32
|
-
sniffing: string | SniffingSettings;
|
|
33
|
-
allocate: string | AllocateSettings;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface AllocateSettings {
|
|
37
|
-
strategy: string;
|
|
38
|
-
refresh: number;
|
|
39
|
-
concurrency: number;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface SniffingSettings {
|
|
43
|
-
enabled: boolean;
|
|
44
|
-
destOverride: string[];
|
|
45
|
-
metadataOnly: boolean;
|
|
46
|
-
routeOnly: boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface StreamSettings {
|
|
50
|
-
network: string;
|
|
51
|
-
security: string;
|
|
52
|
-
externalProxy: any[];
|
|
53
|
-
realitySettings?: RealitySettings;
|
|
54
|
-
tcpSettings?: TCPSettings;
|
|
55
|
-
httpupgradeSettings?: HttpUpgradeSettings;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface HttpUpgradeSettings {
|
|
59
|
-
acceptProxyProtocol: boolean;
|
|
60
|
-
path: string;
|
|
61
|
-
host: string;
|
|
62
|
-
headers: Record<string, string>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface TCPSettings {
|
|
66
|
-
acceptProxyProtocol: boolean;
|
|
67
|
-
header: {
|
|
68
|
-
type: string;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface RealitySettings {
|
|
73
|
-
show: boolean;
|
|
74
|
-
xver: number;
|
|
75
|
-
dest: string;
|
|
76
|
-
serverNames: string[];
|
|
77
|
-
privateKey: string;
|
|
78
|
-
minClient: string;
|
|
79
|
-
maxClient: string;
|
|
80
|
-
maxTimediff: number;
|
|
81
|
-
shortIds: string[];
|
|
82
|
-
settings: {
|
|
83
|
-
publicKey: string;
|
|
84
|
-
fingerprint: string;
|
|
85
|
-
serverName: string;
|
|
86
|
-
spiderX: string;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface InboundSettings {
|
|
91
|
-
clients: ClientSettings[];
|
|
92
|
-
decryption: string;
|
|
93
|
-
fallbacks: any[];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface ClientSettings {
|
|
97
|
-
id: string;
|
|
98
|
-
flow: string;
|
|
99
|
-
email: string;
|
|
100
|
-
limitIp: number;
|
|
101
|
-
totalGB: number;
|
|
102
|
-
expiryTime: number | null;
|
|
103
|
-
enable: boolean;
|
|
104
|
-
tgId: string;
|
|
105
|
-
subId: string;
|
|
106
|
-
reset: number;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface ClientStats {
|
|
110
|
-
id: number;
|
|
111
|
-
inboundId: number;
|
|
112
|
-
enable: boolean;
|
|
113
|
-
email: string;
|
|
114
|
-
up: number;
|
|
115
|
-
down: number;
|
|
116
|
-
expiryTime: number | null;
|
|
117
|
-
total: number;
|
|
118
|
-
reset: number;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export interface SystemStats {
|
|
122
|
-
cpu: number;
|
|
123
|
-
cpuCores: number;
|
|
124
|
-
logicalPro: number;
|
|
125
|
-
cpuSpeedMhz: number;
|
|
126
|
-
mem: {
|
|
127
|
-
current: number;
|
|
128
|
-
total: number;
|
|
129
|
-
};
|
|
130
|
-
swap: {
|
|
131
|
-
current: number;
|
|
132
|
-
total: number;
|
|
133
|
-
}
|
|
134
|
-
disk: {
|
|
135
|
-
current: number;
|
|
136
|
-
total: number;
|
|
137
|
-
};
|
|
138
|
-
xray: {
|
|
139
|
-
state: boolean;
|
|
140
|
-
errorMsg: string;
|
|
141
|
-
version: string;
|
|
142
|
-
};
|
|
143
|
-
uptime: number;
|
|
144
|
-
loads: number[];
|
|
145
|
-
tcpCount: number;
|
|
146
|
-
udpCount: number;
|
|
147
|
-
netIO: {
|
|
148
|
-
up: number;
|
|
149
|
-
down: number;
|
|
150
|
-
};
|
|
151
|
-
netTraffic: {
|
|
152
|
-
up: number;
|
|
153
|
-
down: number;
|
|
154
|
-
};
|
|
155
|
-
publicIP: {
|
|
156
|
-
ipv4: string;
|
|
157
|
-
ipv6: string;
|
|
158
|
-
}
|
|
159
|
-
appStats: {
|
|
160
|
-
threads: number;
|
|
161
|
-
mem: number;
|
|
162
|
-
uptime: number;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface RealityInboundOptions {
|
|
167
|
-
remark: string;
|
|
168
|
-
port?: number;
|
|
169
|
-
dest?: string;
|
|
170
|
-
serverNames?: string[];
|
|
171
|
-
privateKey?: string;
|
|
172
|
-
publicKey?: string;
|
|
173
|
-
shortIds?: string[];
|
|
174
|
-
fingerprint?: string;
|
|
175
|
-
listenIP?: string;
|
|
176
|
-
expiryTime?: number;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export interface ClientOptions {
|
|
180
|
-
id?: string;
|
|
181
|
-
email?: string;
|
|
182
|
-
totalGB?: number;
|
|
183
|
-
expiryTime?: number;
|
|
184
|
-
tgId?: string;
|
|
185
|
-
}
|