x3ui-api 1.0.3 → 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 +274 -26
- package/package.json +1 -1
- package/src/core/ClientBuilder.d.ts +37 -0
- package/src/core/ClientBuilder.js +57 -0
- package/src/core/IndoundBuilder.d.ts +1 -0
- package/src/core/X3UIClient.d.ts +31 -0
- package/src/core/X3UIClient.js +147 -0
- package/src/index.d.ts +12 -148
- package/src/index.d.ts~ +185 -0
- package/src/index.js +2 -455
- package/src/protocols/vless/RealityBuilder.d.ts +69 -0
- package/src/protocols/vless/RealityBuilder.js +223 -0
- package/src/protocols/vless/RealityClientBuilder.d.ts +11 -0
- package/src/protocols/vless/RealityClientBuilder.js +25 -0
- package/src/protocols/vless/index.d.ts +9 -0
- package/src/protocols/vless/index.js +4 -0
- package/src/protocols/vmess/VmessBuilder.d.ts +77 -0
- package/src/protocols/vmess/VmessBuilder.js +189 -0
- package/src/protocols/vmess/VmessClientBuilder.d.ts +13 -0
- package/src/protocols/vmess/VmessClientBuilder.js +92 -0
- package/src/protocols/vmess/index.d.ts +9 -0
- package/src/protocols/vmess/index.js +4 -0
- package/src/protocols/wireguard/WireguardBuilder.d.ts +118 -0
- package/src/protocols/wireguard/WireguardBuilder.js +204 -0
- package/src/protocols/wireguard/WireguardClientBuilder.d.ts +79 -0
- package/src/protocols/wireguard/WireguardClientBuilder.js +88 -0
- package/src/protocols/wireguard/index.d.ts +9 -0
- package/src/protocols/wireguard/index.js +4 -0
- package/src/protocols/wireguard/keyUtils.js +95 -0
package/README.md
CHANGED
|
@@ -13,7 +13,10 @@ npm install x3ui-api
|
|
|
13
13
|
- Authentication with x3ui panel
|
|
14
14
|
- Get system statistics (CPU, memory, network, etc.)
|
|
15
15
|
- Manage inbounds (list, add, update, delete)
|
|
16
|
-
-
|
|
16
|
+
- Protocol-specific builders with fluent API:
|
|
17
|
+
- VLESS with Reality support
|
|
18
|
+
- VMess with HTTP Upgrade support
|
|
19
|
+
- WireGuard support
|
|
17
20
|
- Client management with fluent API
|
|
18
21
|
- TypeScript support
|
|
19
22
|
|
|
@@ -59,15 +62,72 @@ async function main() {
|
|
|
59
62
|
main();
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
### Creating a
|
|
65
|
+
### Creating a VMess Inbound
|
|
66
|
+
|
|
67
|
+
The library provides a convenient builder pattern for creating VMess inbounds with HTTP Upgrade:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const X3UIClient = require('x3ui-api');
|
|
71
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
72
|
+
|
|
73
|
+
const client = new X3UIClient({
|
|
74
|
+
baseURL: 'http://your-x3ui-panel.com:54321'
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
async function createVmessInbound() {
|
|
78
|
+
try {
|
|
79
|
+
await client.login('admin', 'password');
|
|
80
|
+
|
|
81
|
+
// Create a VMess inbound builder
|
|
82
|
+
let builder = new vmess.VmessBuilder(client)
|
|
83
|
+
.setRemark('My VMess Inbound')
|
|
84
|
+
.setPort(8443) // Optional, will auto-generate if not provided
|
|
85
|
+
.setHttpUpgradeHost('your-domain.com');
|
|
86
|
+
|
|
87
|
+
// Add a client
|
|
88
|
+
builder.addClient()
|
|
89
|
+
.setEmail('user@example.com')
|
|
90
|
+
.setTotalGB(100) // 100 GB traffic limit
|
|
91
|
+
.setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
92
|
+
|
|
93
|
+
// Build and add the inbound
|
|
94
|
+
const inbound = await builder.build();
|
|
95
|
+
const createdInbound = await client.addInbound(inbound);
|
|
96
|
+
|
|
97
|
+
// Update the builder with the server-returned inbound to get all metrics and IDs
|
|
98
|
+
builder = new vmess.VmessBuilder(client, createdInbound);
|
|
99
|
+
|
|
100
|
+
console.log('Inbound created:', createdInbound);
|
|
101
|
+
|
|
102
|
+
// Get connection link for the client (now with accurate server-assigned values)
|
|
103
|
+
const link = builder.getClientLink(0, 'your-server-ip.com');
|
|
104
|
+
console.log('Client connection link:', link);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Error creating inbound:', error.message);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
createVmessInbound();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Creating a VLESS Reality Inbound
|
|
63
114
|
|
|
64
115
|
The library provides a convenient builder pattern for creating Reality inbounds:
|
|
65
116
|
|
|
66
117
|
```javascript
|
|
118
|
+
const X3UIClient = require('x3ui-api');
|
|
119
|
+
const vless = require('x3ui-api/src/protocols/vless');
|
|
120
|
+
|
|
121
|
+
const client = new X3UIClient({
|
|
122
|
+
baseURL: 'http://your-x3ui-panel.com:54321'
|
|
123
|
+
});
|
|
124
|
+
|
|
67
125
|
async function createRealityInbound() {
|
|
68
126
|
try {
|
|
127
|
+
await client.login('admin', 'password');
|
|
128
|
+
|
|
69
129
|
// Create a Reality inbound builder
|
|
70
|
-
|
|
130
|
+
let builder = new vless.RealityBuilder(client, {
|
|
71
131
|
remark: 'My Reality Inbound',
|
|
72
132
|
port: 8443 // Optional, will auto-generate if not provided
|
|
73
133
|
});
|
|
@@ -79,18 +139,21 @@ async function createRealityInbound() {
|
|
|
79
139
|
.setFingerprint('chrome');
|
|
80
140
|
|
|
81
141
|
// Add a client
|
|
82
|
-
|
|
142
|
+
builder.addClient()
|
|
83
143
|
.setEmail('user@example.com')
|
|
84
144
|
.setTotalGB(100) // 100 GB traffic limit
|
|
85
145
|
.setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
86
146
|
|
|
87
147
|
// Build and add the inbound
|
|
88
148
|
const inbound = await builder.build();
|
|
89
|
-
const
|
|
149
|
+
const createdInbound = await client.addInbound(inbound);
|
|
150
|
+
|
|
151
|
+
// Update the builder with the server-returned inbound to get all metrics and IDs
|
|
152
|
+
builder = new vless.RealityBuilder(client, createdInbound);
|
|
90
153
|
|
|
91
|
-
console.log('Inbound created:',
|
|
154
|
+
console.log('Inbound created:', createdInbound);
|
|
92
155
|
|
|
93
|
-
// Get connection link for the client
|
|
156
|
+
// Get connection link for the client (now with accurate server-assigned values)
|
|
94
157
|
const link = builder.getClientLink(0, 'your-server-ip.com');
|
|
95
158
|
console.log('Client connection link:', link);
|
|
96
159
|
} catch (error) {
|
|
@@ -99,24 +162,145 @@ async function createRealityInbound() {
|
|
|
99
162
|
}
|
|
100
163
|
```
|
|
101
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
|
+
|
|
226
|
+
### Real-World Example
|
|
227
|
+
|
|
228
|
+
Here's a complete example showing how to create a VMess inbound and get the client link:
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
const X3UIClient = require('x3ui-api');
|
|
232
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
233
|
+
|
|
234
|
+
const client = new X3UIClient({
|
|
235
|
+
baseURL: 'https://your-panel-url.com/path/',
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
(async () => {
|
|
239
|
+
await client.login('username', 'password');
|
|
240
|
+
|
|
241
|
+
// Create VMess builder with HTTP Upgrade
|
|
242
|
+
let vmessBuilder = new vmess.VmessBuilder(client)
|
|
243
|
+
.setRemark("My VMess Inbound")
|
|
244
|
+
.setHttpUpgradeHost("your-domain.com");
|
|
245
|
+
|
|
246
|
+
// Add the inbound to the server
|
|
247
|
+
const vmessInbound = await client.addInbound(await vmessBuilder.build());
|
|
248
|
+
|
|
249
|
+
// Create a new builder with the server-returned inbound to get accurate client links
|
|
250
|
+
vmessBuilder = new vmess.VmessBuilder(client, vmessInbound);
|
|
251
|
+
|
|
252
|
+
// Generate and output the client connection link
|
|
253
|
+
console.log(vmessBuilder.getClientLink(0, "your-domain.com"));
|
|
254
|
+
})();
|
|
255
|
+
```
|
|
256
|
+
|
|
102
257
|
### Managing Existing Inbounds
|
|
103
258
|
|
|
104
259
|
```javascript
|
|
105
260
|
async function manageInbounds() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (inbounds.length > 0) {
|
|
110
|
-
const inboundId = inbounds[0].id;
|
|
111
|
-
|
|
112
|
-
// Update an inbound
|
|
113
|
-
await client.updateInbound(inboundId, {
|
|
114
|
-
remark: 'Updated Inbound Name',
|
|
115
|
-
enable: true
|
|
116
|
-
});
|
|
261
|
+
try {
|
|
262
|
+
// Get all inbounds
|
|
263
|
+
const inbounds = await client.getInbounds();
|
|
117
264
|
|
|
118
|
-
|
|
119
|
-
|
|
265
|
+
if (inbounds.length > 0) {
|
|
266
|
+
// Get the first inbound
|
|
267
|
+
const inbound = inbounds[0];
|
|
268
|
+
const inboundId = inbound.id;
|
|
269
|
+
|
|
270
|
+
// IMPORTANT: When updating an inbound, always start with the complete inbound object
|
|
271
|
+
// to avoid losing data, then modify only what you need to change
|
|
272
|
+
|
|
273
|
+
// Example 1: Update the remark and enable status
|
|
274
|
+
inbound.remark = 'Updated Inbound Name';
|
|
275
|
+
inbound.enable = true;
|
|
276
|
+
|
|
277
|
+
// Send the complete updated inbound back to the server
|
|
278
|
+
await client.updateInbound(inboundId, inbound);
|
|
279
|
+
|
|
280
|
+
// Example 2: Add a new client to an existing inbound
|
|
281
|
+
if (inbound.protocol === 'vmess') {
|
|
282
|
+
// Create a builder with the existing inbound
|
|
283
|
+
const builder = new vmess.VmessBuilder(client, inbound);
|
|
284
|
+
|
|
285
|
+
// Add a new client
|
|
286
|
+
builder.addClient()
|
|
287
|
+
.setEmail('newuser@example.com')
|
|
288
|
+
.setTotalGB(50);
|
|
289
|
+
|
|
290
|
+
// Build the updated inbound and send it to the server
|
|
291
|
+
const updatedInbound = await builder.build();
|
|
292
|
+
await client.updateInbound(inboundId, updatedInbound);
|
|
293
|
+
|
|
294
|
+
// Get the link for the new client
|
|
295
|
+
const link = builder.getClientLink(builder.clients.length - 1, 'your-server-ip.com');
|
|
296
|
+
console.log('New client link:', link);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Example 3: Delete an inbound
|
|
300
|
+
await client.deleteInbound(inboundId);
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Error managing inbounds:', error.message);
|
|
120
304
|
}
|
|
121
305
|
}
|
|
122
306
|
```
|
|
@@ -140,18 +324,44 @@ new X3UIClient({
|
|
|
140
324
|
- `login(username: string, password: string)` - Authenticate with the panel
|
|
141
325
|
- `getSystemStats()` - Get system statistics
|
|
142
326
|
- `getInbounds()` - Get all configured inbounds
|
|
143
|
-
- `addInbound(config)` - Add a new inbound
|
|
144
|
-
- `updateInbound(id, config)` - Update an existing inbound
|
|
327
|
+
- `addInbound(config)` - Add a new inbound and returns the created inbound with server-assigned values
|
|
328
|
+
- `updateInbound(id, config)` - Update an existing inbound with the complete inbound configuration
|
|
145
329
|
- `deleteInbound(id)` - Delete an inbound
|
|
146
330
|
- `getNewX25519Cert()` - Generate a new X25519 certificate
|
|
147
|
-
- `createRealityBuilder(options)` - Create a Reality inbound builder
|
|
148
331
|
|
|
149
|
-
###
|
|
332
|
+
### Protocol Builders
|
|
150
333
|
|
|
151
|
-
|
|
334
|
+
The library provides protocol-specific builders for creating different types of inbounds:
|
|
152
335
|
|
|
153
|
-
####
|
|
336
|
+
#### VMess Builder
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
340
|
+
const builder = new vmess.VmessBuilder(client, options);
|
|
341
|
+
```
|
|
154
342
|
|
|
343
|
+
Methods:
|
|
344
|
+
- `setPort(port)` - Set the port for the inbound
|
|
345
|
+
- `setRemark(remark)` - Set the name/remark for the inbound
|
|
346
|
+
- `setNetwork(network)` - Set the network type (default: 'httpupgrade')
|
|
347
|
+
- `setSecurity(security)` - Set the security type (default: 'none')
|
|
348
|
+
- `setHttpUpgradePath(path)` - Set the HTTP upgrade path
|
|
349
|
+
- `setHttpUpgradeHost(host)` - Set the HTTP upgrade host
|
|
350
|
+
- `setSniffing(enabled, destOverride, metadataOnly, routeOnly)` - Configure sniffing
|
|
351
|
+
- `setListenIP(ip)` - Set listen IP address
|
|
352
|
+
- `setExpiryTime(timestamp)` - Set inbound expiry time
|
|
353
|
+
- `addClient(options)` - Add a new client to the inbound
|
|
354
|
+
- `getClientLink(clientIndex, host, port)` - Get connection link for a client
|
|
355
|
+
- `build()` - Build the final inbound config
|
|
356
|
+
|
|
357
|
+
#### VLESS Reality Builder
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
const vless = require('x3ui-api/src/protocols/vless');
|
|
361
|
+
const builder = new vless.RealityBuilder(client, options);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Methods:
|
|
155
365
|
- `setPort(port)` - Set the port for the inbound
|
|
156
366
|
- `setRemark(remark)` - Set the name/remark for the inbound
|
|
157
367
|
- `setDest(dest)` - Set the destination address (e.g., "yahoo.com:443")
|
|
@@ -165,6 +375,44 @@ Builder class for creating Reality inbounds with a fluent API.
|
|
|
165
375
|
- `getClientLink(clientIndex, host)` - Get connection link for a client
|
|
166
376
|
- `build()` - Build the final inbound config
|
|
167
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
|
+
|
|
168
416
|
## License
|
|
169
417
|
|
|
170
418
|
MIT
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {ClientSettings, InboundConfig} from "../index";
|
|
2
|
+
import InboundBuilder from "./IndoundBuilder";
|
|
3
|
+
|
|
4
|
+
export default class ClientBuilder {
|
|
5
|
+
|
|
6
|
+
constructor(parent: InboundBuilder | InboundConfig);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Set client UUID. If not provided, will be auto-generated
|
|
10
|
+
*/
|
|
11
|
+
setId(id: string): this;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Set client email
|
|
15
|
+
*/
|
|
16
|
+
setEmail(email: string): this;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Set total traffic limit in GB
|
|
20
|
+
*/
|
|
21
|
+
setTotalGB(gb: number): this;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set expiry time in unix timestamp
|
|
25
|
+
*/
|
|
26
|
+
setExpiryTime(timestamp: number): this;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set Telegram ID
|
|
30
|
+
*/
|
|
31
|
+
setTgId(id: string): this;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build the client configuration
|
|
35
|
+
*/
|
|
36
|
+
build(): ClientSettings;
|
|
37
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const crypto = require("crypto");
|
|
2
|
+
|
|
3
|
+
module.exports = class ClientBuilder {
|
|
4
|
+
constructor(parent) {
|
|
5
|
+
this.parent = parent;
|
|
6
|
+
this.id = '';
|
|
7
|
+
this.flow = '';
|
|
8
|
+
this.email = '';
|
|
9
|
+
this.limitIp = 0;
|
|
10
|
+
this.totalGB = 0;
|
|
11
|
+
this.expiryTime = 0;
|
|
12
|
+
this.enable = true;
|
|
13
|
+
this.tgId = '';
|
|
14
|
+
this.subId = '';
|
|
15
|
+
this.reset = 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setId(id) {
|
|
19
|
+
this.id = id;
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setEmail(email) {
|
|
24
|
+
this.email = email;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setTotalGB(gb) {
|
|
29
|
+
this.totalGB = gb;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setExpiryTime(timestamp) {
|
|
34
|
+
this.expiryTime = timestamp;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setTgId(id) {
|
|
39
|
+
this.tgId = id;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
build() {
|
|
44
|
+
return {
|
|
45
|
+
id: this.id || crypto.randomUUID(),
|
|
46
|
+
flow: this.flow,
|
|
47
|
+
email: this.email || Math.random().toString(36).substring(2, 10),
|
|
48
|
+
limitIp: this.limitIp,
|
|
49
|
+
totalGB: this.totalGB,
|
|
50
|
+
expiryTime: this.expiryTime,
|
|
51
|
+
enable: this.enable,
|
|
52
|
+
tgId: this.tgId,
|
|
53
|
+
subId: this.subId || Math.random().toString(36).substring(2, 18),
|
|
54
|
+
reset: this.reset
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class InboundBuilder {}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {AxiosInstance} from "axios";
|
|
2
|
+
import {
|
|
3
|
+
InboundConfig,
|
|
4
|
+
LoginResponse,
|
|
5
|
+
SystemStats,
|
|
6
|
+
X3UIConfig
|
|
7
|
+
} from "../index";
|
|
8
|
+
|
|
9
|
+
export default class X3UIClient {
|
|
10
|
+
private client: AxiosInstance;
|
|
11
|
+
|
|
12
|
+
constructor(config: X3UIConfig);
|
|
13
|
+
|
|
14
|
+
login(username: string, password: string): Promise<LoginResponse>;
|
|
15
|
+
|
|
16
|
+
getSystemStats(): Promise<SystemStats>;
|
|
17
|
+
|
|
18
|
+
getInbounds(): Promise<InboundConfig[]>;
|
|
19
|
+
|
|
20
|
+
addInbound(config: Omit<InboundConfig, 'id'>): Promise<InboundConfig>;
|
|
21
|
+
|
|
22
|
+
updateInbound(id: number, config: Partial<InboundConfig>): Promise<void>;
|
|
23
|
+
|
|
24
|
+
deleteInbound(id: number): Promise<void>;
|
|
25
|
+
|
|
26
|
+
getInboundTraffic(id: number): Promise<{ up: number; down: number }>;
|
|
27
|
+
|
|
28
|
+
resetInboundTraffic(id: number): Promise<void>;
|
|
29
|
+
|
|
30
|
+
getNewX25519Cert(): Promise<{ privateKey: string; publicKey: string }>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
|
|
3
|
+
module.exports = class X3UIClient {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.parseJSONSettings = config.parseJSONSettings || true;
|
|
6
|
+
this.client = axios.create({
|
|
7
|
+
baseURL: config.baseURL,
|
|
8
|
+
headers: config.token ? {
|
|
9
|
+
'Cookie': `lang=en-US; 3x-ui=${config.token}`,
|
|
10
|
+
} : {
|
|
11
|
+
'Cookie': 'lang=en-US'
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Login to the x3ui panel
|
|
18
|
+
* @param {string} username Panel username
|
|
19
|
+
* @param {string} password Panel password
|
|
20
|
+
* @returns {Promise<{success: boolean, msg: string, obj: any}>} Login response with success status and token
|
|
21
|
+
*/
|
|
22
|
+
async login(username, password) {
|
|
23
|
+
const formData = new URLSearchParams();
|
|
24
|
+
formData.append('username', username);
|
|
25
|
+
formData.append('password', password);
|
|
26
|
+
|
|
27
|
+
const response = await this.client.post('/login', formData, {
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (response.data.success) {
|
|
34
|
+
this.client.defaults.headers.Cookie = `lang=en-US; ${response.headers.get("set-cookie")[0].split(";")[0]}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getSystemStats() {
|
|
41
|
+
const response = await this.client.post('/server/status');
|
|
42
|
+
return response.data.obj;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get all inbounds
|
|
47
|
+
* @returns {Promise<Array<{
|
|
48
|
+
* id?: number,
|
|
49
|
+
* up: number,
|
|
50
|
+
* down: number,
|
|
51
|
+
* total: number,
|
|
52
|
+
* remark: string,
|
|
53
|
+
* enable: boolean,
|
|
54
|
+
* expiryTime: number | null,
|
|
55
|
+
* listen: string,
|
|
56
|
+
* port: number,
|
|
57
|
+
* protocol: string,
|
|
58
|
+
* settings: any,
|
|
59
|
+
* streamSettings: any,
|
|
60
|
+
* sniffing: any
|
|
61
|
+
* }>>}
|
|
62
|
+
*/
|
|
63
|
+
async getInbounds() {
|
|
64
|
+
const response = await this.client.get('/panel/api/inbounds/list');
|
|
65
|
+
let inbounds = response.data.obj;
|
|
66
|
+
if (this.parseJSONSettings) {
|
|
67
|
+
inbounds = inbounds.map(inbound => this.parseInbound(inbound));
|
|
68
|
+
}
|
|
69
|
+
return inbounds;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
parseInbound(inbound) {
|
|
73
|
+
if (this.parseJSONSettings) {
|
|
74
|
+
inbound.settings = inbound.settings && inbound.settings.length > 0 ? JSON.parse(inbound.settings) : {};
|
|
75
|
+
inbound.streamSettings = inbound.streamSettings && inbound.streamSettings.length > 0 ? JSON.parse(inbound.streamSettings) : {};
|
|
76
|
+
inbound.sniffing = inbound.sniffing && inbound.sniffing.length > 0 ? JSON.parse(inbound.sniffing) : {};
|
|
77
|
+
inbound.allocate = inbound.allocate && inbound.allocate.length > 0 ? JSON.parse(inbound.allocate) : {};
|
|
78
|
+
}
|
|
79
|
+
return inbound;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stringifyInbound(inbound) {
|
|
83
|
+
inbound.settings = JSON.stringify(inbound.settings);
|
|
84
|
+
inbound.streamSettings = JSON.stringify(inbound.streamSettings);
|
|
85
|
+
inbound.sniffing = JSON.stringify(inbound.sniffing);
|
|
86
|
+
inbound.allocate = JSON.stringify(inbound.allocate);
|
|
87
|
+
return inbound;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Add new inbound
|
|
92
|
+
* @param {Object} config Inbound configuration
|
|
93
|
+
* @param {number} config.up Upload traffic in bytes
|
|
94
|
+
* @param {number} config.down Download traffic in bytes
|
|
95
|
+
* @param {number} config.total Total traffic limit in bytes
|
|
96
|
+
* @param {string} config.remark Inbound remark/name
|
|
97
|
+
* @param {boolean} config.enable Enable status
|
|
98
|
+
* @param {number|null} config.expiryTime Expiry timestamp
|
|
99
|
+
* @param {string} config.listen Listen address
|
|
100
|
+
* @param {number} config.port Port number
|
|
101
|
+
* @param {string} config.protocol Protocol type
|
|
102
|
+
* @param {Object} config.settings Protocol settings
|
|
103
|
+
* @param {Object} config.streamSettings Stream settings
|
|
104
|
+
* @param {Object} config.sniffing Sniffing settings
|
|
105
|
+
* @param {Object} config.allocate Allocation settings
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
async addInbound(config) {
|
|
109
|
+
config = this.stringifyInbound(config);
|
|
110
|
+
const response = await this.client.post('/panel/api/inbounds/add', config);
|
|
111
|
+
if(!response.data.success)
|
|
112
|
+
throw new Error(response.data.msg);
|
|
113
|
+
return this.parseInbound(response.data.obj);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Update existing inbound
|
|
118
|
+
* @param {number} id Inbound ID
|
|
119
|
+
* @param {Object} config Partial inbound configuration
|
|
120
|
+
* @returns {Promise<void>}
|
|
121
|
+
*/
|
|
122
|
+
async updateInbound(id, config) {
|
|
123
|
+
config = this.stringifyInbound(config);
|
|
124
|
+
const response = await this.client.post(`/panel/api/inbounds/update/${id}`, config);
|
|
125
|
+
if(!response.data.success)
|
|
126
|
+
throw new Error(response.data.msg);
|
|
127
|
+
return this.parseInbound(response.data.obj);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Delete inbound
|
|
132
|
+
* @param {number} id Inbound ID
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async deleteInbound(id) {
|
|
136
|
+
await this.client.post(`/panel/api/inbounds/del/${id}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get new X25519 certificate
|
|
141
|
+
* @returns {Promise<{privateKey: string, publicKey: string}>} New X25519 key pair
|
|
142
|
+
*/
|
|
143
|
+
async getNewX25519Cert() {
|
|
144
|
+
const response = await this.client.post('/server/getNewX25519Cert');
|
|
145
|
+
return response.data.obj;
|
|
146
|
+
}
|
|
147
|
+
}
|