diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 96ef2d7b..1c36c5cc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -146,3 +146,79 @@ jobs:
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
overwrite: true
prerelease: true
+
+ # =================================
+ # Windows Build
+ # =================================
+ build-windows:
+ name: Build for Windows
+ permissions:
+ contents: write
+ strategy:
+ matrix:
+ platform:
+ - amd64
+ runs-on: windows-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Setup Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: go.mod
+ check-latest: true
+
+ - name: Build 3X-UI for Windows
+ shell: pwsh
+ run: |
+ $env:CGO_ENABLED="1"
+ $env:GOOS="windows"
+ $env:GOARCH="amd64"
+ go build -ldflags "-w -s" -o xui-release.exe -v main.go
+
+ mkdir x-ui
+ Copy-Item xui-release.exe x-ui\
+ mkdir x-ui\bin
+ cd x-ui\bin
+
+ # Download Xray for Windows
+ $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v25.6.8/"
+ Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
+ Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
+ Remove-Item "Xray-windows-64.zip"
+ Remove-Item geoip.dat, geosite.dat -ErrorAction SilentlyContinue
+ Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip.dat"
+ Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite.dat"
+ Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" -OutFile "geoip_IR.dat"
+ Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" -OutFile "geosite_IR.dat"
+ Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip_RU.dat"
+ Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite_RU.dat"
+ Rename-Item xray.exe xray-windows-amd64.exe
+ cd ..
+ Copy-Item -Path ..\windows_files\* -Destination . -Recurse
+ cd ..
+
+ - name: Package to Zip
+ shell: pwsh
+ run: |
+ Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
+
+ - name: Upload files to Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: x-ui-windows-amd64
+ path: ./x-ui-windows-amd64.zip
+
+ - name: Upload files to GH release
+ uses: svenstaro/upload-release-action@v2
+ if: |
+ (github.event_name == 'release' && github.event.action == 'published') ||
+ (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
+ with:
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ tag: ${{ github.ref }}
+ file: x-ui-windows-amd64.zip
+ asset_name: x-ui-windows-amd64.zip
+ overwrite: true
+ prerelease: true
\ No newline at end of file
diff --git a/database/model/model.go b/database/model/model.go
index 8157c510..7bc44ce3 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -12,11 +12,11 @@ type Protocol string
const (
VMESS Protocol = "vmess"
VLESS Protocol = "vless"
- DOKODEMO Protocol = "dokodemo-door"
+ Tunnel Protocol = "tunnel"
HTTP Protocol = "http"
Trojan Protocol = "trojan"
Shadowsocks Protocol = "shadowsocks"
- Socks Protocol = "socks"
+ Mixed Protocol = "mixed"
WireGuard Protocol = "wireguard"
)
diff --git a/sub/default.json b/sub/default.json
index fff1b3ad..59c8a5ce 100644
--- a/sub/default.json
+++ b/sub/default.json
@@ -13,7 +13,7 @@
"inbounds": [
{
"port": 10808,
- "protocol": "socks",
+ "protocol": "mixed",
"settings": {
"auth": "noauth",
"udp": true,
@@ -28,7 +28,7 @@
],
"enabled": true
},
- "tag": "socks"
+ "tag": "mixed"
},
{
"port": 10809,
diff --git a/web/assets/js/model/dbinbound.js b/web/assets/js/model/dbinbound.js
index acb62ce4..1added25 100644
--- a/web/assets/js/model/dbinbound.js
+++ b/web/assets/js/model/dbinbound.js
@@ -49,8 +49,8 @@ class DBInbound {
return this.protocol === Protocols.SHADOWSOCKS;
}
- get isSocks() {
- return this.protocol === Protocols.SOCKS;
+ get isMixed() {
+ return this.protocol === Protocols.MIXED;
}
get isHTTP() {
diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js
index c2467c36..aecedf75 100644
--- a/web/assets/js/model/inbound.js
+++ b/web/assets/js/model/inbound.js
@@ -3,8 +3,8 @@ const Protocols = {
VLESS: 'vless',
TROJAN: 'trojan',
SHADOWSOCKS: 'shadowsocks',
- DOKODEMO: 'dokodemo-door',
- SOCKS: 'socks',
+ TUNNEL: 'tunnel',
+ MIXED: 'mixed',
HTTP: 'http',
WIREGUARD: 'wireguard',
};
@@ -729,7 +729,7 @@ class RealityStreamSettings extends XrayCommonClass {
constructor(
show = false,
xver = 0,
- dest = 'google.com:443',
+ target = 'google.com:443',
serverNames = 'google.com,www.google.com',
privateKey = '',
minClientVer = '',
@@ -742,7 +742,7 @@ class RealityStreamSettings extends XrayCommonClass {
super();
this.show = show;
this.xver = xver;
- this.dest = dest;
+ this.target = target;
this.serverNames = Array.isArray(serverNames) ? serverNames.join(",") : serverNames;
this.privateKey = privateKey;
this.minClientVer = minClientVer;
@@ -767,7 +767,7 @@ class RealityStreamSettings extends XrayCommonClass {
return new RealityStreamSettings(
json.show,
json.xver,
- json.dest,
+ json.target,
json.serverNames,
json.privateKey,
json.minClientVer,
@@ -783,7 +783,7 @@ class RealityStreamSettings extends XrayCommonClass {
return {
show: this.show,
xver: this.xver,
- dest: this.dest,
+ target: this.target,
serverNames: this.serverNames.split(","),
privateKey: this.privateKey,
minClientVer: this.minClientVer,
@@ -1712,8 +1712,8 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.VLESS: return new Inbound.VLESSSettings(protocol);
case Protocols.TROJAN: return new Inbound.TrojanSettings(protocol);
case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings(protocol);
- case Protocols.DOKODEMO: return new Inbound.DokodemoSettings(protocol);
- case Protocols.SOCKS: return new Inbound.SocksSettings(protocol);
+ case Protocols.TUNNEL: return new Inbound.TunnelSettings(protocol);
+ case Protocols.MIXED: return new Inbound.MixedSettings(protocol);
case Protocols.HTTP: return new Inbound.HttpSettings(protocol);
case Protocols.WIREGUARD: return new Inbound.WireguardSettings(protocol);
default: return null;
@@ -1726,8 +1726,8 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.VLESS: return Inbound.VLESSSettings.fromJson(json);
case Protocols.TROJAN: return Inbound.TrojanSettings.fromJson(json);
case Protocols.SHADOWSOCKS: return Inbound.ShadowsocksSettings.fromJson(json);
- case Protocols.DOKODEMO: return Inbound.DokodemoSettings.fromJson(json);
- case Protocols.SOCKS: return Inbound.SocksSettings.fromJson(json);
+ case Protocols.TUNNEL: return Inbound.TunnelSettings.fromJson(json);
+ case Protocols.MIXED: return Inbound.MixedSettings.fromJson(json);
case Protocols.HTTP: return Inbound.HttpSettings.fromJson(json);
case Protocols.WIREGUARD: return Inbound.WireguardSettings.fromJson(json);
default: return null;
@@ -2327,7 +2327,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
};
-Inbound.DokodemoSettings = class extends Inbound.Settings {
+Inbound.TunnelSettings = class extends Inbound.Settings {
constructor(
protocol,
address,
@@ -2345,8 +2345,8 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
}
static fromJson(json = {}) {
- return new Inbound.DokodemoSettings(
- Protocols.DOKODEMO,
+ return new Inbound.TunnelSettings(
+ Protocols.TUNNEL,
json.address,
json.port,
XrayCommonClass.toHeaders(json.portMap),
@@ -2366,8 +2366,8 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
}
};
-Inbound.SocksSettings = class extends Inbound.Settings {
- constructor(protocol, auth = 'password', accounts = [new Inbound.SocksSettings.SocksAccount()], udp = false, ip = '127.0.0.1') {
+Inbound.MixedSettings = class extends Inbound.Settings {
+ constructor(protocol, auth = 'password', accounts = [new Inbound.MixedSettings.SocksAccount()], udp = false, ip = '127.0.0.1') {
super(protocol);
this.auth = auth;
this.accounts = accounts;
@@ -2387,11 +2387,11 @@ Inbound.SocksSettings = class extends Inbound.Settings {
let accounts;
if (json.auth === 'password') {
accounts = json.accounts.map(
- account => Inbound.SocksSettings.SocksAccount.fromJson(account)
+ account => Inbound.MixedSettings.SocksAccount.fromJson(account)
)
}
- return new Inbound.SocksSettings(
- Protocols.SOCKS,
+ return new Inbound.MixedSettings(
+ Protocols.MIXED,
json.auth,
accounts,
json.udp,
@@ -2408,7 +2408,7 @@ Inbound.SocksSettings = class extends Inbound.Settings {
};
}
};
-Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass {
+Inbound.MixedSettings.SocksAccount = class extends XrayCommonClass {
constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) {
super();
this.user = user;
@@ -2416,7 +2416,7 @@ Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass {
}
static fromJson(json = {}) {
- return new Inbound.SocksSettings.SocksAccount(json.user, json.pass);
+ return new Inbound.MixedSettings.SocksAccount(json.user, json.pass);
}
};
diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js
index 2d5660fb..e798ddc1 100644
--- a/web/assets/js/model/outbound.js
+++ b/web/assets/js/model/outbound.js
@@ -6,7 +6,7 @@ const Protocols = {
VLESS: "vless",
Trojan: "trojan",
Shadowsocks: "shadowsocks",
- Socks: "socks",
+ Mixed: "mixed",
HTTP: "http",
Wireguard: "wireguard"
};
@@ -643,7 +643,7 @@ class Outbound extends CommonClass {
Protocols.Trojan,
Protocols.Shadowsocks,
Protocols.HTTP,
- Protocols.Socks
+ Protocols.Mixed
].includes(this.protocol);
}
@@ -652,7 +652,7 @@ class Outbound extends CommonClass {
}
hasServers() {
- return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Socks, Protocols.HTTP].includes(this.protocol);
+ return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Mixed, Protocols.HTTP].includes(this.protocol);
}
hasAddressPort() {
@@ -662,13 +662,13 @@ class Outbound extends CommonClass {
Protocols.VLESS,
Protocols.Trojan,
Protocols.Shadowsocks,
- Protocols.Socks,
+ Protocols.Mixed,
Protocols.HTTP
].includes(this.protocol);
}
hasUsername() {
- return [Protocols.Socks, Protocols.HTTP].includes(this.protocol);
+ return [Protocols.Mixed, Protocols.HTTP].includes(this.protocol);
}
static fromJson(json = {}) {
@@ -847,7 +847,7 @@ Outbound.Settings = class extends CommonClass {
case Protocols.VLESS: return new Outbound.VLESSSettings();
case Protocols.Trojan: return new Outbound.TrojanSettings();
case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings();
- case Protocols.Socks: return new Outbound.SocksSettings();
+ case Protocols.Mixed: return new Outbound.MixedSettings();
case Protocols.HTTP: return new Outbound.HttpSettings();
case Protocols.Wireguard: return new Outbound.WireguardSettings();
default: return null;
@@ -863,7 +863,7 @@ Outbound.Settings = class extends CommonClass {
case Protocols.VLESS: return Outbound.VLESSSettings.fromJson(json);
case Protocols.Trojan: return Outbound.TrojanSettings.fromJson(json);
case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json);
- case Protocols.Socks: return Outbound.SocksSettings.fromJson(json);
+ case Protocols.Mixed: return Outbound.MixedSettings.fromJson(json);
case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json);
case Protocols.Wireguard: return Outbound.WireguardSettings.fromJson(json);
default: return null;
@@ -1141,7 +1141,7 @@ Outbound.ShadowsocksSettings = class extends CommonClass {
}
};
-Outbound.SocksSettings = class extends CommonClass {
+Outbound.MixedSettings = class extends CommonClass {
constructor(address, port, user, pass) {
super();
this.address = address;
@@ -1153,7 +1153,7 @@ Outbound.SocksSettings = class extends CommonClass {
static fromJson(json = {}) {
let servers = json.servers;
if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
- return new Outbound.SocksSettings(
+ return new Outbound.MixedSettings(
servers[0].address,
servers[0].port,
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
diff --git a/web/controller/api.go b/web/controller/api.go
index 32af934e..6edd7939 100644
--- a/web/controller/api.go
+++ b/web/controller/api.go
@@ -9,6 +9,7 @@ import (
type APIController struct {
BaseController
inboundController *InboundController
+ serverController *ServerController
Tgbot service.Tgbot
}
@@ -19,43 +20,22 @@ func NewAPIController(g *gin.RouterGroup) *APIController {
}
func (a *APIController) initRouter(g *gin.RouterGroup) {
- g = g.Group("/panel/api/inbounds")
- g.Use(a.checkLogin)
+ // Main API group
+ api := g.Group("/panel/api")
+ api.Use(a.checkLogin)
- a.inboundController = NewInboundController(g)
+ // Inbounds API
+ inbounds := api.Group("/inbounds")
+ a.inboundController = NewInboundController(inbounds)
- inboundRoutes := []struct {
- Method string
- Path string
- Handler gin.HandlerFunc
- }{
- {"GET", "/createbackup", a.createBackup},
- {"GET", "/list", a.inboundController.getInbounds},
- {"GET", "/get/:id", a.inboundController.getInbound},
- {"GET", "/getClientTraffics/:email", a.inboundController.getClientTraffics},
- {"GET", "/getClientTrafficsById/:id", a.inboundController.getClientTrafficsById},
- {"POST", "/add", a.inboundController.addInbound},
- {"POST", "/del/:id", a.inboundController.delInbound},
- {"POST", "/update/:id", a.inboundController.updateInbound},
- {"POST", "/clientIps/:email", a.inboundController.getClientIps},
- {"POST", "/clearClientIps/:email", a.inboundController.clearClientIps},
- {"POST", "/addClient", a.inboundController.addInboundClient},
- {"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient},
- {"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient},
- {"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic},
- {"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics},
- {"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics},
- {"POST", "/delDepletedClients/:id", a.inboundController.delDepletedClients},
- {"POST", "/onlines", a.inboundController.onlines},
- {"POST", "/lastOnline", a.inboundController.lastOnline},
- {"POST", "/updateClientTraffic/:email", a.inboundController.updateClientTraffic},
- }
+ // Server API
+ server := api.Group("/server")
+ a.serverController = NewServerController(server)
- for _, route := range inboundRoutes {
- g.Handle(route.Method, route.Path, route.Handler)
- }
+ // Extra routes
+ api.GET("/backuptotgbot", a.BackuptoTgbot)
}
-func (a *APIController) createBackup(c *gin.Context) {
+func (a *APIController) BackuptoTgbot(c *gin.Context) {
a.Tgbot.SendBackupToAdmins()
}
diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index bcf4215b..2ce4695a 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -25,34 +25,28 @@ func NewInboundController(g *gin.RouterGroup) *InboundController {
}
func (a *InboundController) initRouter(g *gin.RouterGroup) {
- g = g.Group("/inbound")
- g.POST("/list", a.getInbounds)
+ g.GET("/list", a.getInbounds)
+ g.GET("/get/:id", a.getInbound)
+ g.GET("/getClientTraffics/:email", a.getClientTraffics)
+ g.GET("/getClientTrafficsById/:id", a.getClientTrafficsById)
+
g.POST("/add", a.addInbound)
g.POST("/del/:id", a.delInbound)
g.POST("/update/:id", a.updateInbound)
g.POST("/clientIps/:email", a.getClientIps)
g.POST("/clearClientIps/:email", a.clearClientIps)
+ g.POST("/addClient", a.addInboundClient)
+ g.POST("/:id/delClient/:clientId", a.delInboundClient)
+ g.POST("/updateClient/:clientId", a.updateInboundClient)
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
g.POST("/resetAllTraffics", a.resetAllTraffics)
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
g.POST("/delDepletedClients/:id", a.delDepletedClients)
g.POST("/import", a.importInbound)
g.POST("/onlines", a.onlines)
-
- // Routes for UI
- g.POST("/addClient", a.addInboundClient)
- g.POST("/:id/delClient/:clientId", a.delInboundClient)
- g.POST("/updateClient/:clientId", a.updateInboundClient)
-
- // Routes for API (for slave servers)
- apiGroup := g.Group("/api")
- apiGroup.Use(middleware.ApiAuth())
- {
- apiGroup.POST("/addClient", a.addInboundClient)
- apiGroup.POST("/:id/delClient/:clientId", a.delInboundClient)
- apiGroup.POST("/updateClient/:clientId", a.updateInboundClient)
- }
+ g.POST("/lastOnline", a.lastOnline)
+ g.POST("/updateClientTraffic/:email", a.updateClientTraffic)
}
func (a *InboundController) getInbounds(c *gin.Context) {
diff --git a/web/controller/server.go b/web/controller/server.go
index b1174b8f..d5ae688b 100644
--- a/web/controller/server.go
+++ b/web/controller/server.go
@@ -37,11 +37,17 @@ func NewServerController(g *gin.RouterGroup) *ServerController {
}
func (a *ServerController) initRouter(g *gin.RouterGroup) {
- g = g.Group("/server")
- g.Use(a.checkLogin)
- g.POST("/status", a.status)
- g.POST("/getXrayVersion", a.getXrayVersion)
+ g.GET("/status", a.status)
+ g.GET("/getXrayVersion", a.getXrayVersion)
+ g.GET("/getConfigJson", a.getConfigJson)
+ g.GET("/getDb", a.getDb)
+ g.GET("/getNewUUID", a.getNewUUID)
+ g.GET("/getNewX25519Cert", a.getNewX25519Cert)
+ g.GET("/getNewmldsa65", a.getNewmldsa65)
+ g.GET("/getNewmlkem768", a.getNewmlkem768)
+ g.GET("/getNewVlessEnc", a.getNewVlessEnc)
+
g.POST("/stopXrayService", a.stopXrayService)
g.POST("/restartXrayService", a.restartXrayService)
g.POST("/installXray/:version", a.installXray)
@@ -49,13 +55,8 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
g.POST("/updateGeofile/:fileName", a.updateGeofile)
g.POST("/logs/:count", a.getLogs)
g.POST("/xraylogs/:count", a.getXrayLogs)
- g.POST("/getConfigJson", a.getConfigJson)
- g.GET("/getDb", a.getDb)
g.POST("/importDB", a.importDB)
- g.POST("/getNewX25519Cert", a.getNewX25519Cert)
- g.POST("/getNewmldsa65", a.getNewmldsa65)
g.POST("/getNewEchCert", a.getNewEchCert)
- g.POST("/getNewVlessEnc", a.getNewVlessEnc)
}
func (a *ServerController) refreshStatus() {
@@ -276,3 +277,22 @@ func (a *ServerController) getNewVlessEnc(c *gin.Context) {
}
jsonObj(c, out, nil)
}
+
+func (a *ServerController) getNewUUID(c *gin.Context) {
+ uuidResp, err := a.serverService.GetNewUUID()
+ if err != nil {
+ jsonMsg(c, "Failed to generate UUID", err)
+ return
+ }
+
+ jsonObj(c, uuidResp, nil)
+}
+
+func (a *ServerController) getNewmlkem768(c *gin.Context) {
+ out, err := a.serverService.GetNewmlkem768()
+ if err != nil {
+ jsonMsg(c, "Failed to generate mlkem768 keys", err)
+ return
+ }
+ jsonObj(c, out, nil)
+}
diff --git a/web/controller/xui.go b/web/controller/xui.go
index 42c02a15..4b620a7d 100644
--- a/web/controller/xui.go
+++ b/web/controller/xui.go
@@ -8,6 +8,7 @@ type XUIController struct {
BaseController
inboundController *InboundController
+ serverController *ServerController
settingController *SettingController
xraySettingController *XraySettingController
}
@@ -29,6 +30,7 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) {
g.GET("/xray", a.xraySettings)
a.inboundController = NewInboundController(g)
+ a.serverController = NewServerController(g)
a.settingController = NewSettingController(g)
a.xraySettingController = NewXraySettingController(g)
}
diff --git a/web/html/form/inbound.html b/web/html/form/inbound.html
index 9554d6aa..69f5fbb3 100644
--- a/web/html/form/inbound.html
+++ b/web/html/form/inbound.html
@@ -83,14 +83,14 @@
{{template "form/shadowsocks"}}
-
-
- {{template "form/dokodemo"}}
+
+
+ {{template "form/tunnel"}}
-
-
- {{template "form/socks"}}
+
+
+ {{template "form/mixed"}}
diff --git a/web/html/form/outbound.html b/web/html/form/outbound.html
index cfaaafd7..271dea83 100644
--- a/web/html/form/outbound.html
+++ b/web/html/form/outbound.html
@@ -241,9 +241,9 @@
-
+
-
+
@@ -441,6 +441,9 @@
[[ alpn ]]
+
+
+
diff --git a/web/html/form/protocol/dokodemo.html b/web/html/form/protocol/dokodemo.html
index 819b7727..b73a7641 100644
--- a/web/html/form/protocol/dokodemo.html
+++ b/web/html/form/protocol/dokodemo.html
@@ -1,4 +1,4 @@
-{{define "form/dokodemo"}}
+{{define "form/tunnel"}}
diff --git a/web/html/form/protocol/socks.html b/web/html/form/protocol/socks.html
index e126c51c..979769da 100644
--- a/web/html/form/protocol/socks.html
+++ b/web/html/form/protocol/socks.html
@@ -1,4 +1,4 @@
-{{define "form/socks"}}
+{{define "form/mixed"}}
@@ -15,7 +15,7 @@
{{ i18n "username" }} |
{{ i18n "password" }} |
-
+
|
diff --git a/web/html/form/protocol/vless.html b/web/html/form/protocol/vless.html
index 69e74285..140b9c1a 100644
--- a/web/html/form/protocol/vless.html
+++ b/web/html/form/protocol/vless.html
@@ -22,7 +22,6 @@
- None
X25519 (not Post-Quantum)
ML-KEM-768 (Post-Quantum)
@@ -31,17 +30,17 @@
-
+
Get New keys
- Clear
+ Clear
-
+
diff --git a/web/html/form/reality_settings.html b/web/html/form/reality_settings.html
index feacccbe..8758dae1 100644
--- a/web/html/form/reality_settings.html
+++ b/web/html/form/reality_settings.html
@@ -12,8 +12,8 @@
[[ key ]]
-
-
+
+
@@ -48,7 +48,10 @@
- Get New Cert
+
+ Get New Cert
+ Clear
+
@@ -57,7 +60,10 @@
- Get New Seed
+
+ Get New Seed
+ Clear
+
{{end}}
\ No newline at end of file
diff --git a/web/html/form/tls_settings.html b/web/html/form/tls_settings.html
index 82031bd7..c3844a7f 100644
--- a/web/html/form/tls_settings.html
+++ b/web/html/form/tls_settings.html
@@ -5,13 +5,13 @@
{{ i18n "none" }}
- Reality
- TLS
+ Reality
+ TLS
-
+
@@ -116,12 +116,15 @@
+
Get New ECH Cert
+ Clear
+
-
+
{{template "form/realitySettings"}}
diff --git a/web/html/inbounds.html b/web/html/inbounds.html
index 81ef1b39..830c940f 100644
--- a/web/html/inbounds.html
+++ b/web/html/inbounds.html
@@ -830,7 +830,7 @@
},
async getDBInbounds() {
this.refreshing = true;
- const msg = await HttpUtil.post('/panel/inbound/list');
+ const msg = await HttpUtil.get('/panel/api/inbounds/list');
if (!msg.success) {
this.refreshing = false;
return;
@@ -845,7 +845,7 @@
}, 500);
},
async getOnlineUsers() {
- const msg = await HttpUtil.post('/panel/inbound/onlines');
+ const msg = await HttpUtil.post('/panel/api/inbounds/onlines');
if (!msg.success) {
return;
}
@@ -1099,7 +1099,7 @@
streamSettings: baseInbound.stream.toString(),
sniffing: baseInbound.sniffing.toString(),
};
- await this.submit('/panel/inbound/add', data, inModal);
+ await this.submit('/panel/api/inbounds/add', data, inModal);
},
openAddInbound() {
inModal.show({
@@ -1148,7 +1148,7 @@
}
data.sniffing = inbound.sniffing.toString();
- await this.submit('/panel/inbound/add', data, inModal);
+ await this.submit('/panel/api/inbounds/add', data, inModal);
},
async updateInbound(inbound, dbInbound) {
const data = {
@@ -1171,7 +1171,7 @@
}
data.sniffing = inbound.sniffing.toString();
- await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
+ await this.submit(`/panel/api/inbounds/update/${dbInbound.id}`, data, inModal);
},
openAddClient(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
@@ -1226,14 +1226,14 @@
id: dbInboundId,
settings: '{"clients": [' + clients.toString() + ']}',
};
- await this.submit(`/panel/inbound/addClient`, data, modal);
+ await this.submit(`/panel/api/inbounds/addClient`, data, modal);
},
async updateClient(client, dbInboundId, clientId) {
const data = {
id: dbInboundId,
settings: '{"clients": [' + client.toString() + ']}',
};
- await this.submit(`/panel/inbound/updateClient/${clientId}`, data, clientModal);
+ await this.submit(`/panel/api/inbounds/updateClient/${clientId}`, data, clientModal);
},
resetTraffic(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
@@ -1258,7 +1258,7 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "delete"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/panel/inbound/del/' + dbInboundId),
+ onOk: () => this.submit('/panel/api/inbounds/del/' + dbInboundId),
});
},
delClient(dbInboundId, client,confirmation = true) {
@@ -1271,10 +1271,10 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "delete"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`),
+ onOk: () => this.submit(`/panel/api/inbounds/${dbInboundId}/delClient/${clientId}`),
});
} else {
- this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`);
+ this.submit(`/panel/api/inbounds/${dbInboundId}/delClient/${clientId}`);
}
},
getSubGroupClients(dbInbounds, currentClient) {
@@ -1353,7 +1353,7 @@
switchEnable(dbInboundId,state) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
dbInbound.enable = state;
- this.submit(`/panel/inbound/update/${dbInboundId}`, dbInbound);
+ this.submit(`/panel/api/inbounds/update/${dbInboundId}`, dbInbound);
},
async switchEnableClient(dbInboundId, client) {
this.loading()
@@ -1383,10 +1383,10 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email),
+ onOk: () => this.submit('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + client.email),
})
} else {
- this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email);
+ this.submit('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + client.email);
}
},
resetAllTraffic() {
@@ -1396,7 +1396,7 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/panel/inbound/resetAllTraffics'),
+ onOk: () => this.submit('/panel/api/inbounds/resetAllTraffics'),
});
},
resetAllClientTraffics(dbInboundId) {
@@ -1406,7 +1406,7 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/panel/inbound/resetAllClientTraffics/' + dbInboundId),
+ onOk: () => this.submit('/panel/api/inbounds/resetAllClientTraffics/' + dbInboundId),
})
},
delDepletedClients(dbInboundId) {
@@ -1416,7 +1416,7 @@
class: themeSwitcher.currentTheme,
okText: '{{ i18n "delete"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/panel/inbound/delDepletedClients/' + dbInboundId),
+ onOk: () => this.submit('/panel/api/inbounds/delDepletedClients/' + dbInboundId),
})
},
isExpiry(dbInbound, index) {
@@ -1542,7 +1542,7 @@
value: '',
okText: '{{ i18n "pages.inbounds.import" }}',
confirm: async (dbInboundText) => {
- await this.submit('/panel/inbound/import', {data: dbInboundText}, promptModal);
+ await this.submit('/panel/api/inbounds/import', {data: dbInboundText}, promptModal);
},
});
},
diff --git a/web/html/index.html b/web/html/index.html
index 42b8a032..5d5c3b1d 100644
--- a/web/html/index.html
+++ b/web/html/index.html
@@ -746,7 +746,7 @@ ${dateTime}
},
async getStatus() {
try {
- const msg = await HttpUtil.post('/server/status');
+ const msg = await HttpUtil.get('/panel/api/server/status');
if (msg.success) {
if (!this.loadingStates.fetched) {
this.loadingStates.fetched = true;
@@ -763,7 +763,7 @@ ${dateTime}
},
async openSelectV2rayVersion() {
this.loading(true);
- const msg = await HttpUtil.post('server/getXrayVersion');
+ const msg = await HttpUtil.get('/panel/api/server/getXrayVersion');
this.loading(false);
if (!msg.success) {
return;
@@ -780,7 +780,7 @@ ${dateTime}
onOk: async () => {
versionModal.hide();
this.loading(true, '{{ i18n "pages.index.dontRefresh"}}');
- await HttpUtil.post(`/server/installXray/${version}`);
+ await HttpUtil.post(`/panel/api/server/installXray/${version}`);
this.loading(false);
},
});
@@ -798,9 +798,9 @@ ${dateTime}
onOk: async () => {
versionModal.hide();
this.loading(true, '{{ i18n "pages.index.dontRefresh"}}');
- const url = isSingleFile
- ? `/server/updateGeofile/${fileName}`
- : `/server/updateGeofile`;
+ const url = isSingleFile
+ ? `/panel/api/server/updateGeofile/${fileName}`
+ : `/panel/api/server/updateGeofile`;
await HttpUtil.post(url);
this.loading(false);
},
@@ -808,7 +808,7 @@ ${dateTime}
},
async stopXrayService() {
this.loading(true);
- const msg = await HttpUtil.post('server/stopXrayService');
+ const msg = await HttpUtil.post('/panel/api/server/stopXrayService');
this.loading(false);
if (!msg.success) {
return;
@@ -816,7 +816,7 @@ ${dateTime}
},
async restartXrayService() {
this.loading(true);
- const msg = await HttpUtil.post('server/restartXrayService');
+ const msg = await HttpUtil.post('/panel/api/server/restartXrayService');
this.loading(false);
if (!msg.success) {
return;
@@ -824,7 +824,7 @@ ${dateTime}
},
async openLogs(){
logModal.loading = true;
- const msg = await HttpUtil.post('server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog});
+ const msg = await HttpUtil.post('/panel/api/server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog});
if (!msg.success) {
return;
}
@@ -834,7 +834,7 @@ ${dateTime}
},
async openXrayLogs(){
xraylogModal.loading = true;
- const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows,{filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy});
+ const msg = await HttpUtil.post('/panel/api/server/xraylogs/'+xraylogModal.rows,{filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy});
if (!msg.success) {
return;
}
@@ -844,7 +844,7 @@ ${dateTime}
},
async openConfig() {
this.loading(true);
- const msg = await HttpUtil.post('server/getConfigJson');
+ const msg = await HttpUtil.get('/panel/api/server/getConfigJson');
this.loading(false);
if (!msg.success) {
return;
@@ -855,7 +855,7 @@ ${dateTime}
backupModal.show();
},
exportDatabase() {
- window.location = basePath + 'server/getDb';
+ window.location = basePath + 'panel/api/server/getDb';
},
importDatabase() {
const fileInput = document.createElement('input');
@@ -868,7 +868,7 @@ ${dateTime}
formData.append('db', dbFile);
backupModal.hide();
this.loading(true);
- const uploadMsg = await HttpUtil.post('server/importDB', formData, {
+ const uploadMsg = await HttpUtil.post('/panel/api/server/importDB', formData, {
headers: {
'Content-Type': 'multipart/form-data',
}
diff --git a/web/html/modals/client_modal.html b/web/html/modals/client_modal.html
index 623e720d..8b57b8b2 100644
--- a/web/html/modals/client_modal.html
+++ b/web/html/modals/client_modal.html
@@ -121,7 +121,7 @@
},
methods: {
async getDBClientIps(email) {
- const msg = await HttpUtil.post(`/panel/inbound/clientIps/${email}`);
+ const msg = await HttpUtil.post(`/panel/api/inbounds/clientIps/${email}`);
if (!msg.success) {
document.getElementById("clientIPs").value = msg.obj;
return;
@@ -139,7 +139,7 @@
},
async clearDBClientIps(email) {
try {
- const msg = await HttpUtil.post(`/panel/inbound/clearClientIps/${email}`);
+ const msg = await HttpUtil.post(`/panel/api/inbounds/clearClientIps/${email}`);
if (!msg.success) {
return;
}
@@ -156,7 +156,7 @@
cancelText: '{{ i18n "cancel"}}',
onOk: async () => {
iconElement.disabled = true;
- const msg = await HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + email);
+ const msg = await HttpUtil.postWithModal('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + email);
if (msg.success) {
this.clientModal.clientStats.up = 0;
this.clientModal.clientStats.down = 0;
diff --git a/web/html/modals/inbound_info_modal.html b/web/html/modals/inbound_info_modal.html
index 4110c244..7b7b0af7 100644
--- a/web/html/modals/inbound_info_modal.html
+++ b/web/html/modals/inbound_info_modal.html
@@ -354,7 +354,7 @@
[[ link.link ]]
-
+
{{ i18n "pages.inbounds.targetAddress" }} |
{{ i18n "pages.inbounds.destinationPort" }} |
@@ -376,7 +376,7 @@
-
+
{{ i18n "password" }} Auth |
{{ i18n "pages.inbounds.enable" }} udp |
@@ -492,7 +492,7 @@