mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-03-19 17:15:49 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b54d0344e | ||
|
|
f817f922fe | ||
|
|
55f7fcd1b3 | ||
|
|
b0f974a94d | ||
|
|
6bebde4105 | ||
|
|
fa4a63c958 | ||
|
|
11def0a753 | ||
|
|
513f87550a | ||
|
|
81838b504c | ||
|
|
4980744793 | ||
|
|
5ff6f4094e | ||
|
|
bbce1eb3f7 | ||
|
|
204f73a692 | ||
|
|
641a7d3e57 | ||
|
|
3f7e819a9b | ||
|
|
834d003ab6 | ||
|
|
c627227893 | ||
|
|
2a8725a7a5 | ||
|
|
ca2d1bb901 | ||
|
|
fa19649286 | ||
|
|
56d75f5293 | ||
|
|
e1132a3f41 | ||
|
|
4d479102ad | ||
|
|
e90c575bfd | ||
|
|
9d02f455cc | ||
|
|
13f67f595c | ||
|
|
25741dcb08 |
15
README.md
15
README.md
@@ -20,10 +20,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||||||
|
|
||||||
## Install custom version
|
## Install custom version
|
||||||
|
|
||||||
To install your desired version you can add the version to the end of install command. Example for ver `v1.0.9`:
|
To install your desired version you can add the version to the end of install command. Example for ver `v1.2.6`:
|
||||||
|
|
||||||
```
|
```
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.0.9
|
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.2.6
|
||||||
```
|
```
|
||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
@@ -79,13 +79,19 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||||||
|
|
||||||
If you want to use routing to WARP follow steps as below:
|
If you want to use routing to WARP follow steps as below:
|
||||||
|
|
||||||
1. Install WARP on **socks proxy mode**:
|
1. If you already installed warp, you can uninstall using below command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
warp u
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install WARP on **socks proxy mode**:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -fsSL https://gist.githubusercontent.com/hamid-gh98/dc5dd9b0cc5b0412af927b1ccdb294c7/raw/install_warp_proxy.sh | bash
|
curl -fsSL https://gist.githubusercontent.com/hamid-gh98/dc5dd9b0cc5b0412af927b1ccdb294c7/raw/install_warp_proxy.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Turn on the config you need in panel or [Copy and paste this file to Xray Configuration](./media/configs/traffic+block-ads+warp.json)
|
3. Turn on the config you need in panel or [Copy and paste this file to Xray Configuration](./media/configs/traffic+block-ads+warp.json)
|
||||||
|
|
||||||
Config Features:
|
Config Features:
|
||||||
|
|
||||||
@@ -169,7 +175,6 @@ Reference syntax:
|
|||||||
# A Special Thanks To
|
# A Special Thanks To
|
||||||
|
|
||||||
- [alireza0](https://github.com/alireza0/)
|
- [alireza0](https://github.com/alireza0/)
|
||||||
- [FranzKafkaYu](https://github.com/FranzKafkaYu)
|
|
||||||
|
|
||||||
# Suggestion System
|
# Suggestion System
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.2.4
|
1.2.7
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ func initUser() error {
|
|||||||
}
|
}
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
user := &model.User{
|
user := &model.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
Password: "admin",
|
Password: "admin",
|
||||||
|
LoginSecret: "",
|
||||||
}
|
}
|
||||||
return db.Create(user).Error
|
return db.Create(user).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Id int `json:"id" gorm:"primaryKey;autoIncrement"`
|
Id int `json:"id" gorm:"primaryKey;autoIncrement"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
LoginSecret string `json:"loginSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Inbound struct {
|
type Inbound struct {
|
||||||
|
|||||||
39
install.sh
39
install.sh
@@ -23,23 +23,14 @@ else
|
|||||||
fi
|
fi
|
||||||
echo "The OS release is: $release"
|
echo "The OS release is: $release"
|
||||||
|
|
||||||
arch=$(arch)
|
arch3xui() {
|
||||||
|
case "$(uname -m)" in
|
||||||
if [[ $arch == "x86_64" || $arch == "x64" || $arch == "amd64" ]]; then
|
x86_64 | x64 | amd64 ) echo 'amd64' ;;
|
||||||
arch="amd64"
|
armv8 | arm64 | aarch64 ) echo 'arm64' ;;
|
||||||
elif [[ $arch == "aarch64" || $arch == "arm64" ]]; then
|
* ) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
|
||||||
arch="arm64"
|
esac
|
||||||
else
|
}
|
||||||
arch="amd64"
|
echo "arch: $(arch3xui)"
|
||||||
echo -e "${red} Failed to check system arch, will use default arch: ${arch}${plain}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "arch: ${arch}"
|
|
||||||
|
|
||||||
if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
|
|
||||||
echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead, if there is something wrong, please get in touch with me!"
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
|
|
||||||
os_version=""
|
os_version=""
|
||||||
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||||
@@ -122,18 +113,18 @@ install_x-ui() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
|
echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
|
||||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz
|
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch3xui).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch3xui).tar.gz
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
|
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
last_version=$1
|
last_version=$1
|
||||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz"
|
url="https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch3xui).tar.gz"
|
||||||
echo -e "Begining to install x-ui $1"
|
echo -e "Begining to install x-ui $1"
|
||||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz ${url}
|
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch3xui).tar.gz ${url}
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo -e "${red}Download x-ui $1 failed,please check the version exists${plain}"
|
echo -e "${red}Download x-ui $1 failed,please check the version exists ${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -142,10 +133,10 @@ install_x-ui() {
|
|||||||
rm /usr/local/x-ui/ -rf
|
rm /usr/local/x-ui/ -rf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tar zxvf x-ui-linux-${arch}.tar.gz
|
tar zxvf x-ui-linux-$(arch3xui).tar.gz
|
||||||
rm x-ui-linux-${arch}.tar.gz -f
|
rm x-ui-linux-$(arch3xui).tar.gz -f
|
||||||
cd x-ui
|
cd x-ui
|
||||||
chmod +x x-ui bin/xray-linux-${arch}
|
chmod +x x-ui bin/xray-linux-$(arch3xui)
|
||||||
cp -f x-ui.service /etc/systemd/system/
|
cp -f x-ui.service /etc/systemd/system/
|
||||||
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
||||||
chmod +x /usr/local/x-ui/x-ui.sh
|
chmod +x /usr/local/x-ui/x-ui.sh
|
||||||
|
|||||||
29
main.go
29
main.go
@@ -51,8 +51,8 @@ func runWebServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
//信号量捕获处理
|
// Trap shutdown signals
|
||||||
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL)
|
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)
|
||||||
for {
|
for {
|
||||||
sig := <-sigCh
|
sig := <-sigCh
|
||||||
|
|
||||||
@@ -204,6 +204,24 @@ func updateSetting(port int, username string, password string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeSecret() {
|
||||||
|
err := database.InitDB(config.GetDBPath())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userService := service.UserService{}
|
||||||
|
err = userService.RemoveUserSecret()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
settingService := service.SettingService{}
|
||||||
|
err = settingService.SetSecretStatus(false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
runWebServer()
|
runWebServer()
|
||||||
@@ -229,6 +247,7 @@ func main() {
|
|||||||
var tgbotRuntime string
|
var tgbotRuntime string
|
||||||
var reset bool
|
var reset bool
|
||||||
var show bool
|
var show bool
|
||||||
|
var remove_secret bool
|
||||||
settingCmd.BoolVar(&reset, "reset", false, "reset all settings")
|
settingCmd.BoolVar(&reset, "reset", false, "reset all settings")
|
||||||
settingCmd.BoolVar(&show, "show", false, "show current settings")
|
settingCmd.BoolVar(&show, "show", false, "show current settings")
|
||||||
settingCmd.IntVar(&port, "port", 0, "set panel port")
|
settingCmd.IntVar(&port, "port", 0, "set panel port")
|
||||||
@@ -290,6 +309,12 @@ func main() {
|
|||||||
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
||||||
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
||||||
}
|
}
|
||||||
|
if remove_secret {
|
||||||
|
removeSecret()
|
||||||
|
}
|
||||||
|
if enabletgbot {
|
||||||
|
updateTgbotEnableSts(enabletgbot)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Println("except 'run' or 'v2-ui' or 'setting' subcommands")
|
fmt.Println("except 'run' or 'v2-ui' or 'setting' subcommands")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class User {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.username = "";
|
this.username = "";
|
||||||
this.password = "";
|
this.password = "";
|
||||||
|
this.LoginSecret = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ class AllSetting {
|
|||||||
this.tgBotBackup = false;
|
this.tgBotBackup = false;
|
||||||
this.tgCpu = "";
|
this.tgCpu = "";
|
||||||
this.xrayTemplateConfig = "";
|
this.xrayTemplateConfig = "";
|
||||||
|
this.secretEnable = false;
|
||||||
|
|
||||||
this.timeLocation = "Asia/Tehran";
|
this.timeLocation = "Asia/Tehran";
|
||||||
|
|
||||||
|
|||||||
@@ -853,6 +853,7 @@ class StreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
|
|
||||||
return new StreamSettings(
|
return new StreamSettings(
|
||||||
json.network,
|
json.network,
|
||||||
json.security,
|
json.security,
|
||||||
@@ -1412,13 +1413,13 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
||||||
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (this.stream.network === 'tcp') {
|
if (this.stream.network === 'tcp' && !ObjectUtil.isEmpty(this.settings.vlesses[clientIndex].flow)) {
|
||||||
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
||||||
}
|
}
|
||||||
if (this.stream.reality.shortIds != "") {
|
if (this.stream.reality.shortIds.length > 0) {
|
||||||
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (this.stream.reality.settings.fingerprint != "") {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.fingerprint)) {
|
||||||
params.set("fp", this.stream.reality.settings.fingerprint);
|
params.set("fp", this.stream.reality.settings.fingerprint);
|
||||||
}
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
||||||
@@ -1519,10 +1520,10 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
||||||
address = this.stream.reality.settings.serverName;
|
address = this.stream.reality.settings.serverName;
|
||||||
}
|
}
|
||||||
if (this.stream.reality.shortIds != "") {
|
if (this.stream.reality.shortIds.length > 0) {
|
||||||
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (this.stream.reality.settings.fingerprint != "") {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.fingerprint)) {
|
||||||
params.set("fp", this.stream.reality.settings.fingerprint);
|
params.set("fp", this.stream.reality.settings.fingerprint);
|
||||||
}
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func (a *APIController) initRouter(g *gin.RouterGroup) {
|
|||||||
|
|
||||||
g.GET("/list", a.getAllInbounds)
|
g.GET("/list", a.getAllInbounds)
|
||||||
g.GET("/get/:id", a.getSingleInbound)
|
g.GET("/get/:id", a.getSingleInbound)
|
||||||
|
g.GET("/getClientTraffics/:email", a.getClientTraffics)
|
||||||
g.POST("/add", a.addInbound)
|
g.POST("/add", a.addInbound)
|
||||||
g.POST("/del/:id", a.delInbound)
|
g.POST("/del/:id", a.delInbound)
|
||||||
g.POST("/update/:id", a.updateInbound)
|
g.POST("/update/:id", a.updateInbound)
|
||||||
@@ -39,6 +40,9 @@ func (a *APIController) getAllInbounds(c *gin.Context) {
|
|||||||
func (a *APIController) getSingleInbound(c *gin.Context) {
|
func (a *APIController) getSingleInbound(c *gin.Context) {
|
||||||
a.inboundController.getInbound(c)
|
a.inboundController.getInbound(c)
|
||||||
}
|
}
|
||||||
|
func (a *APIController) getClientTraffics(c *gin.Context) {
|
||||||
|
a.inboundController.getClientTraffics(c)
|
||||||
|
}
|
||||||
func (a *APIController) addInbound(c *gin.Context) {
|
func (a *APIController) addInbound(c *gin.Context) {
|
||||||
a.inboundController.addInbound(c)
|
a.inboundController.addInbound(c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,16 @@ func (a *InboundController) getInbound(c *gin.Context) {
|
|||||||
jsonObj(c, inbound, nil)
|
jsonObj(c, inbound, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *InboundController) getClientTraffics(c *gin.Context) {
|
||||||
|
email := c.Param("email")
|
||||||
|
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
|
||||||
|
if err != nil {
|
||||||
|
jsonMsg(c, "Error getting traffics", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonObj(c, clientTraffics, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *InboundController) addInbound(c *gin.Context) {
|
func (a *InboundController) addInbound(c *gin.Context) {
|
||||||
inbound := &model.Inbound{}
|
inbound := &model.Inbound{}
|
||||||
err := c.ShouldBind(inbound)
|
err := c.ShouldBind(inbound)
|
||||||
|
|||||||
@@ -11,15 +11,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type LoginForm struct {
|
type LoginForm struct {
|
||||||
Username string `json:"username" form:"username"`
|
Username string `json:"username" form:"username"`
|
||||||
Password string `json:"password" form:"password"`
|
Password string `json:"password" form:"password"`
|
||||||
|
LoginSecret string `json:"loginSecret" form:"loginSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IndexController struct {
|
type IndexController struct {
|
||||||
BaseController
|
BaseController
|
||||||
|
|
||||||
userService service.UserService
|
settingService service.SettingService
|
||||||
tgbot service.Tgbot
|
userService service.UserService
|
||||||
|
tgbot service.Tgbot
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIndexController(g *gin.RouterGroup) *IndexController {
|
func NewIndexController(g *gin.RouterGroup) *IndexController {
|
||||||
@@ -32,6 +34,7 @@ func (a *IndexController) initRouter(g *gin.RouterGroup) {
|
|||||||
g.GET("/", a.index)
|
g.GET("/", a.index)
|
||||||
g.POST("/login", a.login)
|
g.POST("/login", a.login)
|
||||||
g.GET("/logout", a.logout)
|
g.GET("/logout", a.logout)
|
||||||
|
g.POST("/getSecretStatus", a.getSecretStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *IndexController) index(c *gin.Context) {
|
func (a *IndexController) index(c *gin.Context) {
|
||||||
@@ -57,7 +60,7 @@ func (a *IndexController) login(c *gin.Context) {
|
|||||||
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyPassword"))
|
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyPassword"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := a.userService.CheckUser(form.Username, form.Password)
|
user := a.userService.CheckUser(form.Username, form.Password, form.LoginSecret)
|
||||||
timeStr := time.Now().Format("2006-01-02 15:04:05")
|
timeStr := time.Now().Format("2006-01-02 15:04:05")
|
||||||
if user == nil {
|
if user == nil {
|
||||||
a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
|
a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
|
||||||
@@ -82,3 +85,11 @@ func (a *IndexController) logout(c *gin.Context) {
|
|||||||
session.ClearSession(c)
|
session.ClearSession(c)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
|
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *IndexController) getSecretStatus(c *gin.Context) {
|
||||||
|
status, err := a.settingService.GetSecretStatus()
|
||||||
|
if err == nil {
|
||||||
|
jsonObj(c, status, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ type updateUserForm struct {
|
|||||||
NewPassword string `json:"newPassword" form:"newPassword"`
|
NewPassword string `json:"newPassword" form:"newPassword"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type updateSecretForm struct {
|
||||||
|
LoginSecret string `json:"loginSecret" form:"loginSecret"`
|
||||||
|
}
|
||||||
|
|
||||||
type SettingController struct {
|
type SettingController struct {
|
||||||
settingService service.SettingService
|
settingService service.SettingService
|
||||||
userService service.UserService
|
userService service.UserService
|
||||||
@@ -38,6 +42,8 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
|
|||||||
g.POST("/updateUser", a.updateUser)
|
g.POST("/updateUser", a.updateUser)
|
||||||
g.POST("/restartPanel", a.restartPanel)
|
g.POST("/restartPanel", a.restartPanel)
|
||||||
g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig)
|
g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig)
|
||||||
|
g.POST("/updateUserSecret", a.updateSecret)
|
||||||
|
g.POST("/getUserSecret", a.getUserSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SettingController) getAllSetting(c *gin.Context) {
|
func (a *SettingController) getAllSetting(c *gin.Context) {
|
||||||
@@ -128,3 +134,25 @@ func (a *SettingController) restartPanel(c *gin.Context) {
|
|||||||
err := a.panelService.RestartPanel(time.Second * 3)
|
err := a.panelService.RestartPanel(time.Second * 3)
|
||||||
jsonMsg(c, I18n(c, "pages.setting.restartPanel"), err)
|
jsonMsg(c, I18n(c, "pages.setting.restartPanel"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *SettingController) updateSecret(c *gin.Context) {
|
||||||
|
form := &updateSecretForm{}
|
||||||
|
err := c.ShouldBind(form)
|
||||||
|
if err != nil {
|
||||||
|
jsonMsg(c, I18n(c, "pages.setting.toasts.modifySetting"), err)
|
||||||
|
}
|
||||||
|
user := session.GetLoginUser(c)
|
||||||
|
err = a.userService.UpdateUserSecret(user.Id, form.LoginSecret)
|
||||||
|
if err == nil {
|
||||||
|
user.LoginSecret = form.LoginSecret
|
||||||
|
session.SetLoginUser(c, user)
|
||||||
|
}
|
||||||
|
jsonMsg(c, I18n(c, "pages.setting.toasts.modifyUser"), err)
|
||||||
|
}
|
||||||
|
func (a *SettingController) getUserSecret(c *gin.Context) {
|
||||||
|
loginUser := session.GetLoginUser(c)
|
||||||
|
user := a.userService.GetUserSecret(loginUser.Id)
|
||||||
|
if user != nil {
|
||||||
|
jsonObj(c, user, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (a *SUBController) subs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add subscription-userinfo
|
// Add subscription-userinfo
|
||||||
c.Writer.Header().Set("subscription-userinfo", header)
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
|
|
||||||
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type AllSetting struct {
|
|||||||
TgCpu int `json:"tgCpu" form:"tgCpu"`
|
TgCpu int `json:"tgCpu" form:"tgCpu"`
|
||||||
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
|
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
|
||||||
TimeLocation string `json:"timeLocation" form:"timeLocation"`
|
TimeLocation string `json:"timeLocation" form:"timeLocation"`
|
||||||
|
SecretEnable bool `json:"secretEnable" form:"secretEnable"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AllSetting) CheckValid() error {
|
func (s *AllSetting) CheckValid() error {
|
||||||
|
|||||||
@@ -57,6 +57,11 @@
|
|||||||
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
|
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item v-if="secretEnable">
|
||||||
|
<a-input type="text" placeholder='{{ i18n "secretToken" }}' v-model.trim="user.loginSecret" @keydown.enter.native="login">
|
||||||
|
<a-icon slot="prefix" type="key" style="color: rgba(0,0,0,.25)"/>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-button block @click="login" :loading="loading">{{ i18n "login" }}</a-button>
|
<a-button block @click="login" :loading="loading">{{ i18n "login" }}</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -98,10 +103,12 @@
|
|||||||
data: {
|
data: {
|
||||||
loading: false,
|
loading: false,
|
||||||
user: new User(),
|
user: new User(),
|
||||||
|
secretEnable: false,
|
||||||
lang : ""
|
lang : ""
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
this.lang = getLang();
|
this.lang = getLang();
|
||||||
|
this.secretEnable = this.getSecretStatus();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async login() {
|
async login() {
|
||||||
@@ -111,6 +118,15 @@
|
|||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
location.href = basePath + 'xui/';
|
location.href = basePath + 'xui/';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async getSecretStatus() {
|
||||||
|
this.loading= true;
|
||||||
|
const msg = await HttpUtil.post('/getSecretStatus');
|
||||||
|
this.loading = false;
|
||||||
|
if (msg.success){
|
||||||
|
this.secretEnable = msg.obj;
|
||||||
|
return msg.obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -144,6 +144,24 @@
|
|||||||
}
|
}
|
||||||
document.getElementById("clientIPs").value = ""
|
document.getElementById("clientIPs").value = ""
|
||||||
},
|
},
|
||||||
|
resetClientTraffic(email,dbInboundId,iconElement) {
|
||||||
|
this.$confirm({
|
||||||
|
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
||||||
|
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||||
|
class: siderDrawer.isDarkTheme ? darkClass : '',
|
||||||
|
okText: '{{ i18n "reset"}}',
|
||||||
|
cancelText: '{{ i18n "cancel"}}',
|
||||||
|
onOk: async () => {
|
||||||
|
iconElement.disabled = true;
|
||||||
|
const msg = await HttpUtil.postWithModal('/xui/inbound/' + dbInboundId + '/resetClientTraffic/'+ email);
|
||||||
|
if (msg.success) {
|
||||||
|
this.clientModal.clientStats.up = 0;
|
||||||
|
this.clientModal.clientStats.down = 0;
|
||||||
|
}
|
||||||
|
iconElement.disabled = false;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -98,6 +98,10 @@
|
|||||||
[[ sizeFormat(clientStats.down) ]]
|
[[ sizeFormat(clientStats.down) ]]
|
||||||
([[ sizeFormat(clientStats.up + clientStats.down) ]])
|
([[ sizeFormat(clientStats.up + clientStats.down) ]])
|
||||||
</a-tag>
|
</a-tag>
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
||||||
|
<a-icon type="retweet" @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)" v-if="client.email.length > 0"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.client.delayedStart" }}'>
|
<a-form-item label='{{ i18n "pages.client.delayedStart" }}'>
|
||||||
|
|||||||
@@ -658,8 +658,8 @@
|
|||||||
inbound = dbInbound.toInbound();
|
inbound = dbInbound.toInbound();
|
||||||
clients = this.getClients(dbInbound.protocol, inbound.settings);
|
clients = this.getClients(dbInbound.protocol, inbound.settings);
|
||||||
index = this.findIndexOfClient(clients, client);
|
index = this.findIndexOfClient(clients, client);
|
||||||
clients[index].enable = ! clients[index].enable
|
clients[index].enable = !clients[index].enable;
|
||||||
await this.updateClient(inbound, dbInbound, index);
|
await this.updateClient(clients[index],dbInboundId, index);
|
||||||
this.loading(false);
|
this.loading(false);
|
||||||
},
|
},
|
||||||
async submit(url, data) {
|
async submit(url, data) {
|
||||||
|
|||||||
@@ -91,8 +91,39 @@
|
|||||||
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
|
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-tab-pane>
|
<a-form :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65); padding: 20px;': 'background: white; padding: 20px;'">
|
||||||
|
<a-list-item style="padding: 20px">
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='{{ i18n "pages.setting.loginSecurity" }}' description='{{ i18n "pages.setting.loginSecurityDesc" }}'/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<template>
|
||||||
|
<a-switch @change="toggleToken(allSetting.secretEnable)" v-model="allSetting.secretEnable"></a-switch>
|
||||||
|
</template>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item style="padding: 20px">
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='{{ i18n "pages.setting.secretToken" }}' description='{{ i18n "pages.setting.secretTokenDesc" }}'/>
|
||||||
|
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<svg
|
||||||
|
@click="getNewSecret"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/>
|
||||||
|
</svg>
|
||||||
|
<template>
|
||||||
|
<a-textarea type="text" id='token' :disabled="!allSetting.secretEnable" v-model="user.loginSecret"></a-textarea>
|
||||||
|
</template>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-list-item>
|
||||||
|
<a-button type="primary" @click="updateSecret">{{ i18n "confirm" }}</a-button>
|
||||||
|
</a-form>
|
||||||
|
</a-tab-pane>
|
||||||
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
|
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
|
||||||
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
||||||
<a-divider>{{ i18n "pages.setting.actions"}}</a-divider>
|
<a-divider>{{ i18n "pages.setting.actions"}}</a-divider>
|
||||||
@@ -103,12 +134,24 @@
|
|||||||
<a-divider>{{ i18n "pages.setting.basicTemplate"}}</a-divider>
|
<a-divider>{{ i18n "pages.setting.basicTemplate"}}</a-divider>
|
||||||
<a-collapse>
|
<a-collapse>
|
||||||
<a-collapse-panel header='{{ i18n "pages.setting.generalConfigs"}}'>
|
<a-collapse-panel header='{{ i18n "pages.setting.generalConfigs"}}'>
|
||||||
|
<a-row :xs="24" :sm="24" :lg="12">
|
||||||
|
<h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
|
||||||
|
<a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
|
||||||
|
{{ i18n "pages.setting.generalConfigsDesc" }}
|
||||||
|
</h2>
|
||||||
|
</a-row>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigTorrent"}}' desc='{{ i18n "pages.setting.xrayConfigTorrentDesc"}}' v-model="torrentSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigTorrent"}}' desc='{{ i18n "pages.setting.xrayConfigTorrentDesc"}}' v-model="torrentSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigPrivateIp"}}' desc='{{ i18n "pages.setting.xrayConfigPrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigPrivateIp"}}' desc='{{ i18n "pages.setting.xrayConfigPrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigAds"}}' desc='{{ i18n "pages.setting.xrayConfigAdsDesc"}}' v-model="AdsSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigAds"}}' desc='{{ i18n "pages.setting.xrayConfigAdsDesc"}}' v-model="AdsSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigPorn"}}' desc='{{ i18n "pages.setting.xrayConfigPornDesc"}}' v-model="PornSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigPorn"}}' desc='{{ i18n "pages.setting.xrayConfigPornDesc"}}' v-model="PornSettings"></setting-list-item>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
<a-collapse-panel header='{{ i18n "pages.setting.countryConfigs"}}'>
|
<a-collapse-panel header='{{ i18n "pages.setting.countryConfigs"}}'>
|
||||||
|
<a-row :xs="24" :sm="24" :lg="12">
|
||||||
|
<h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
|
||||||
|
<a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
|
||||||
|
{{ i18n "pages.setting.countryConfigsDesc" }}
|
||||||
|
</h2>
|
||||||
|
</a-row>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigIRIp"}}' desc='{{ i18n "pages.setting.xrayConfigIRIpDesc"}}' v-model="IRIpSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigIRIp"}}' desc='{{ i18n "pages.setting.xrayConfigIRIpDesc"}}' v-model="IRIpSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigIRDomain"}}' desc='{{ i18n "pages.setting.xrayConfigIRDomainDesc"}}' v-model="IRDomainSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigIRDomain"}}' desc='{{ i18n "pages.setting.xrayConfigIRDomainDesc"}}' v-model="IRDomainSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigChinaIp"}}' desc='{{ i18n "pages.setting.xrayConfigChinaIpDesc"}}' v-model="ChinaIpSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigChinaIp"}}' desc='{{ i18n "pages.setting.xrayConfigChinaIpDesc"}}' v-model="ChinaIpSettings"></setting-list-item>
|
||||||
@@ -117,10 +160,22 @@
|
|||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigRussiaDomain"}}' desc='{{ i18n "pages.setting.xrayConfigRussiaDomainDesc"}}' v-model="RussiaDomainSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigRussiaDomain"}}' desc='{{ i18n "pages.setting.xrayConfigRussiaDomainDesc"}}' v-model="RussiaDomainSettings"></setting-list-item>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
<a-collapse-panel header='{{ i18n "pages.setting.ipv4Configs"}}'>
|
<a-collapse-panel header='{{ i18n "pages.setting.ipv4Configs"}}'>
|
||||||
|
<a-row :xs="24" :sm="24" :lg="12">
|
||||||
|
<h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
|
||||||
|
<a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
|
||||||
|
{{ i18n "pages.setting.ipv4ConfigsDesc" }}
|
||||||
|
</h2>
|
||||||
|
</a-row>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigGoogleIPv4"}}' desc='{{ i18n "pages.setting.xrayConfigGoogleIPv4Desc"}}' v-model="GoogleIPv4Settings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigGoogleIPv4"}}' desc='{{ i18n "pages.setting.xrayConfigGoogleIPv4Desc"}}' v-model="GoogleIPv4Settings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigNetflixIPv4"}}' desc='{{ i18n "pages.setting.xrayConfigNetflixIPv4Desc"}}' v-model="NetflixIPv4Settings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigNetflixIPv4"}}' desc='{{ i18n "pages.setting.xrayConfigNetflixIPv4Desc"}}' v-model="NetflixIPv4Settings"></setting-list-item>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
<a-collapse-panel header='{{ i18n "pages.setting.warpConfigs"}}'>
|
<a-collapse-panel header='{{ i18n "pages.setting.warpConfigs"}}'>
|
||||||
|
<a-row :xs="24" :sm="24" :lg="12">
|
||||||
|
<h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
|
||||||
|
<a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
|
||||||
|
{{ i18n "pages.setting.warpConfigsDesc" }}
|
||||||
|
</h2>
|
||||||
|
</a-row>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigGoogleWARP"}}' desc='{{ i18n "pages.setting.xrayConfigGoogleWARPDesc"}}' v-model="GoogleWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigGoogleWARP"}}' desc='{{ i18n "pages.setting.xrayConfigGoogleWARPDesc"}}' v-model="GoogleWARPSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigOpenAIWARP"}}' desc='{{ i18n "pages.setting.xrayConfigOpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigOpenAIWARP"}}' desc='{{ i18n "pages.setting.xrayConfigOpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigNetflixWARP"}}' desc='{{ i18n "pages.setting.xrayConfigNetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigNetflixWARP"}}' desc='{{ i18n "pages.setting.xrayConfigNetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
|
||||||
@@ -181,7 +236,7 @@
|
|||||||
oldAllSetting: new AllSetting(),
|
oldAllSetting: new AllSetting(),
|
||||||
allSetting: new AllSetting(),
|
allSetting: new AllSetting(),
|
||||||
saveBtnDisable: true,
|
saveBtnDisable: true,
|
||||||
user: {},
|
user: new User(),
|
||||||
lang: getLang(),
|
lang: getLang(),
|
||||||
ipv4Settings: {
|
ipv4Settings: {
|
||||||
tag: "IPv4",
|
tag: "IPv4",
|
||||||
@@ -238,31 +293,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loading(spinning = true) {
|
loading(spinning = true , obj) {
|
||||||
this.spinning = spinning;
|
if(obj == null)
|
||||||
|
this.spinning = spinning;
|
||||||
},
|
},
|
||||||
async getAllSetting() {
|
async getAllSetting() {
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
const msg = await HttpUtil.post("/xui/setting/all");
|
const msg = await HttpUtil.post("/xui/setting/all");
|
||||||
this.loading(false);
|
this.loading(false,null);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
this.oldAllSetting = new AllSetting(msg.obj);
|
this.oldAllSetting = new AllSetting(msg.obj);
|
||||||
this.allSetting = new AllSetting(msg.obj);
|
this.allSetting = new AllSetting(msg.obj);
|
||||||
this.saveBtnDisable = true;
|
this.saveBtnDisable = true;
|
||||||
}
|
}
|
||||||
|
await this.getUserSecret();
|
||||||
},
|
},
|
||||||
async updateAllSetting() {
|
async updateAllSetting() {
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
const msg = await HttpUtil.post("/xui/setting/update", this.allSetting);
|
const msg = await HttpUtil.post("/xui/setting/update", this.allSetting);
|
||||||
this.loading(false);
|
this.loading(false,null);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
await this.getAllSetting();
|
await this.getAllSetting();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async updateUser() {
|
async updateUser() {
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
const msg = await HttpUtil.post("/xui/setting/updateUser", this.user);
|
const msg = await HttpUtil.post("/xui/setting/updateUser", this.user);
|
||||||
this.loading(false);
|
this.loading(false,null);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
this.user = {};
|
this.user = {};
|
||||||
}
|
}
|
||||||
@@ -277,19 +334,54 @@
|
|||||||
onOk: () => resolve(),
|
onOk: () => resolve(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
const msg = await HttpUtil.post("/xui/setting/restartPanel");
|
const msg = await HttpUtil.post("/xui/setting/restartPanel");
|
||||||
this.loading(false);
|
this.loading(false,null);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
await PromiseUtil.sleep(5000);
|
await PromiseUtil.sleep(5000);
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async getUserSecret(){
|
||||||
|
const user_msg = await HttpUtil.post("/xui/setting/getUserSecret", this.user);
|
||||||
|
if (user_msg.success){
|
||||||
|
this.user = user_msg.obj;
|
||||||
|
}
|
||||||
|
this.loading(false);
|
||||||
|
},
|
||||||
|
async updateSecret(){
|
||||||
|
this.loading(true,{});
|
||||||
|
const msg = await HttpUtil.post("/xui/setting/updateUserSecret", this.user);
|
||||||
|
if (msg.success){
|
||||||
|
this.user = msg.obj;
|
||||||
|
}
|
||||||
|
this.loading(false,null);
|
||||||
|
await this.updateAllSetting();
|
||||||
|
},
|
||||||
|
async getNewSecret(){
|
||||||
|
this.loading(true,{});
|
||||||
|
await PromiseUtil.sleep(1000);
|
||||||
|
var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||||
|
var string = '';
|
||||||
|
var len = 64;
|
||||||
|
for(var ii=0; ii<len; ii++){
|
||||||
|
string += chars[Math.floor(Math.random() * chars.length)];
|
||||||
|
}
|
||||||
|
this.user.loginSecret = string;
|
||||||
|
document.getElementById('token').value =this.user.loginSecret;
|
||||||
|
this.loading(false,null);
|
||||||
|
},
|
||||||
|
async toggleToken(value){
|
||||||
|
if(value)
|
||||||
|
this.getNewSecret();
|
||||||
|
else
|
||||||
|
this.user.loginSecret = "";
|
||||||
|
},
|
||||||
async resetXrayConfigToDefault() {
|
async resetXrayConfigToDefault() {
|
||||||
this.loading(true);
|
this.loading(true,{});
|
||||||
const msg = await HttpUtil.get("/xui/setting/getDefaultJsonConfig");
|
const msg = await HttpUtil.get("/xui/setting/getDefaultJsonConfig");
|
||||||
this.loading(false);
|
this.loading(false,null);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
this.templateSettings = JSON.parse(JSON.stringify(msg.obj, null, 2));
|
this.templateSettings = JSON.parse(JSON.stringify(msg.obj, null, 2));
|
||||||
this.saveBtnDisable = true;
|
this.saveBtnDisable = true;
|
||||||
|
|||||||
@@ -266,11 +266,18 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
existEmail, err := s.checkEmailsExistForClients(clients)
|
|
||||||
|
var settings map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interfaceClients := settings["clients"].([]interface{})
|
||||||
|
existEmail, err := s.checkEmailsExistForClients(clients)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if existEmail != "" {
|
if existEmail != "" {
|
||||||
return common.NewError("Duplicate email:", existEmail)
|
return common.NewError("Duplicate email:", existEmail)
|
||||||
}
|
}
|
||||||
@@ -280,21 +287,18 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings map[string]interface{}
|
var oldSettings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
|
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldClients := settings["clients"].([]interface{})
|
oldClients := oldSettings["clients"].([]interface{})
|
||||||
var newClients []interface{}
|
oldClients = append(oldClients, interfaceClients...)
|
||||||
for _, client := range clients {
|
|
||||||
newClients = append(newClients, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings["clients"] = append(oldClients, newClients...)
|
oldSettings["clients"] = oldClients
|
||||||
|
|
||||||
newSettings, err := json.MarshalIndent(settings, "", " ")
|
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -341,6 +345,14 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, index int) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var settings map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inerfaceClients := settings["clients"].([]interface{})
|
||||||
|
|
||||||
oldInbound, err := s.GetInbound(data.Id)
|
oldInbound, err := s.GetInbound(data.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -361,20 +373,18 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, index int) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings map[string]interface{}
|
var oldSettings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
|
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsClients := settings["clients"].([]interface{})
|
settingsClients := oldSettings["clients"].([]interface{})
|
||||||
var newClients []interface{}
|
settingsClients[index] = inerfaceClients[0]
|
||||||
newClients = append(newClients, clients[0])
|
|
||||||
settingsClients[index] = newClients[0]
|
|
||||||
|
|
||||||
settings["clients"] = settingsClients
|
oldSettings["clients"] = settingsClients
|
||||||
|
|
||||||
newSettings, err := json.MarshalIndent(settings, "", " ")
|
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -388,7 +398,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, index int) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.UpdateClientIPs(db, oldClients[index].Email, clients[index].Email)
|
err = s.UpdateClientIPs(db, oldClients[index].Email, clients[0].Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -700,7 +710,7 @@ func (s *InboundService) GetClientTrafficByEmail(email string) (traffic []*xray.
|
|||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
var traffics []*xray.ClientTraffic
|
var traffics []*xray.ClientTraffic
|
||||||
|
|
||||||
err = db.Model(xray.ClientTraffic{}).Where("email like ?", "%"+email+"%").Find(&traffics).Error
|
err = db.Model(xray.ClientTraffic{}).Where("email = ?", email).Find(&traffics).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
logger.Warning(err)
|
logger.Warning(err)
|
||||||
|
|||||||
@@ -323,6 +323,10 @@ func (s *ServerService) UpdateXray(version string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = copyZipFile("iran.dat", xray.GetIranPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ var defaultValueMap = map[string]string{
|
|||||||
"tgRunTime": "@daily",
|
"tgRunTime": "@daily",
|
||||||
"tgBotBackup": "false",
|
"tgBotBackup": "false",
|
||||||
"tgCpu": "0",
|
"tgCpu": "0",
|
||||||
|
"secretEnable": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingService struct {
|
type SettingService struct {
|
||||||
@@ -129,7 +130,13 @@ func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {
|
|||||||
|
|
||||||
func (s *SettingService) ResetSettings() error {
|
func (s *SettingService) ResetSettings() error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
return db.Where("1 = 1").Delete(model.Setting{}).Error
|
err := db.Where("1 = 1").Delete(model.Setting{}).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return db.Model(model.User{}).
|
||||||
|
Where("1 = 1").
|
||||||
|
Update("login_secret", "").Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
|
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
|
||||||
@@ -288,6 +295,14 @@ func (s *SettingService) SetgetTrafficDiff(value int) error {
|
|||||||
return s.setInt("trafficDiff", value)
|
return s.setInt("trafficDiff", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetSecretStatus() (bool, error) {
|
||||||
|
return s.getBool("secretEnable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) SetSecretStatus(value bool) error {
|
||||||
|
return s.setBool("secretEnable", value)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSecret() ([]byte, error) {
|
func (s *SettingService) GetSecret() ([]byte, error) {
|
||||||
secret, err := s.getString("secret")
|
secret, err := s.getString("secret")
|
||||||
if secret == defaultValueMap["secret"] {
|
if secret == defaultValueMap["secret"] {
|
||||||
|
|||||||
@@ -66,13 +66,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, string, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
header = fmt.Sprintf("upload=%d;download=%d", traffic.Up, traffic.Down)
|
header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
||||||
if traffic.Total > 0 {
|
|
||||||
header = header + fmt.Sprintf(";total=%d", traffic.Total)
|
|
||||||
}
|
|
||||||
if traffic.ExpiryTime > 0 {
|
|
||||||
header = header + fmt.Sprintf(";expire=%d", traffic.ExpiryTime)
|
|
||||||
}
|
|
||||||
return result, header, nil
|
return result, header, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,21 +307,29 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
|||||||
|
|
||||||
if security == "reality" {
|
if security == "reality" {
|
||||||
params["security"] = "reality"
|
params["security"] = "reality"
|
||||||
realitySettings, _ := stream["realitySettings"].(map[string]interface{})
|
realitySetting, _ := stream["realitySettings"].(map[string]interface{})
|
||||||
if realitySettings != nil {
|
realitySettings, _ := searchKey(realitySetting, "settings")
|
||||||
if sniValue, ok := searchKey(realitySettings, "serverNames"); ok {
|
if realitySetting != nil {
|
||||||
|
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
||||||
sNames, _ := sniValue.([]interface{})
|
sNames, _ := sniValue.([]interface{})
|
||||||
params["sni"], _ = sNames[0].(string)
|
params["sni"], _ = sNames[0].(string)
|
||||||
}
|
}
|
||||||
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
||||||
params["pbk"], _ = pbkValue.(string)
|
params["pbk"], _ = pbkValue.(string)
|
||||||
}
|
}
|
||||||
if sidValue, ok := searchKey(realitySettings, "shortIds"); ok {
|
if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
|
||||||
shortIds, _ := sidValue.([]interface{})
|
shortIds, _ := sidValue.([]interface{})
|
||||||
params["sid"], _ = shortIds[0].(string)
|
params["sid"], _ = shortIds[0].(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
||||||
params["fp"], _ = fpValue.(string)
|
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
||||||
|
params["fp"] = fp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if serverName, ok := searchKey(realitySettings, "serverName"); ok {
|
||||||
|
if sname, ok := serverName.(string); ok && len(sname) > 0 {
|
||||||
|
address = sname
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,9 +484,10 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||||||
|
|
||||||
if security == "reality" {
|
if security == "reality" {
|
||||||
params["security"] = "reality"
|
params["security"] = "reality"
|
||||||
realitySettings, _ := stream["realitySettings"].(map[string]interface{})
|
realitySetting, _ := stream["realitySettings"].(map[string]interface{})
|
||||||
if realitySettings != nil {
|
realitySettings, _ := searchKey(realitySetting, "settings")
|
||||||
if sniValue, ok := searchKey(realitySettings, "serverNames"); ok {
|
if realitySetting != nil {
|
||||||
|
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
||||||
sNames, _ := sniValue.([]interface{})
|
sNames, _ := sniValue.([]interface{})
|
||||||
params["sni"], _ = sNames[0].(string)
|
params["sni"], _ = sNames[0].(string)
|
||||||
}
|
}
|
||||||
@@ -496,7 +499,14 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||||||
params["sid"], _ = shortIds[0].(string)
|
params["sid"], _ = shortIds[0].(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
||||||
params["fp"], _ = fpValue.(string)
|
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
||||||
|
params["fp"] = fp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if serverName, ok := searchKey(realitySettings, "serverName"); ok {
|
||||||
|
if sname, ok := serverName.(string); ok && len(sname) > 0 {
|
||||||
|
address = sname
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ func (s *UserService) GetFirstUser() (*model.User, error) {
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UserService) CheckUser(username string, password string) *model.User {
|
func (s *UserService) CheckUser(username string, password string, secret string) *model.User {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
|
||||||
user := &model.User{}
|
user := &model.User{}
|
||||||
err := db.Model(model.User{}).
|
err := db.Model(model.User{}).
|
||||||
Where("username = ? and password = ?", username, password).
|
Where("username = ? and password = ? and login_secret = ?", username, password, secret).
|
||||||
First(user).
|
First(user).
|
||||||
Error
|
Error
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
@@ -50,6 +50,35 @@ func (s *UserService) UpdateUser(id int, username string, password string) error
|
|||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *UserService) UpdateUserSecret(id int, secret string) error {
|
||||||
|
db := database.GetDB()
|
||||||
|
return db.Model(model.User{}).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Update("login_secret", secret).
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserService) RemoveUserSecret() error {
|
||||||
|
db := database.GetDB()
|
||||||
|
return db.Model(model.User{}).
|
||||||
|
Where("1 = 1").
|
||||||
|
Update("login_secret", "").
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserService) GetUserSecret(id int) *model.User {
|
||||||
|
db := database.GetDB()
|
||||||
|
user := &model.User{}
|
||||||
|
err := db.Model(model.User{}).
|
||||||
|
Where("id = ?", id).
|
||||||
|
First(user).
|
||||||
|
Error
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UserService) UpdateFirstUser(username string, password string) error {
|
func (s *UserService) UpdateFirstUser(username string, password string) error {
|
||||||
if username == "" {
|
if username == "" {
|
||||||
return errors.New("username can not be empty")
|
return errors.New("username can not be empty")
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"edit" = "Edit"
|
"edit" = "Edit"
|
||||||
"delete" = "Delete"
|
"delete" = "Delete"
|
||||||
"reset" = "Reset"
|
"reset" = "Reset"
|
||||||
"copySuccess" = "Copy successfully"
|
"copySuccess" = "Copied successfully"
|
||||||
"sure" = "Sure"
|
"sure" = "Sure"
|
||||||
"encryption" = "Encryption"
|
"encryption" = "Encryption"
|
||||||
"transmission" = "Transmission"
|
"transmission" = "Transmission"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"depletingSoon" = "Depleting soon"
|
"depletingSoon" = "Depleting soon"
|
||||||
"domainName" = "Domain name"
|
"domainName" = "Domain name"
|
||||||
"additional" = "Alter"
|
"additional" = "Alter"
|
||||||
"monitor" = "Listen IP"
|
"monitor" = "Listening IP"
|
||||||
"certificate" = "Certificate"
|
"certificate" = "Certificate"
|
||||||
"fail" = "Fail"
|
"fail" = "Fail"
|
||||||
"success" = " Success"
|
"success" = " Success"
|
||||||
@@ -48,12 +48,13 @@
|
|||||||
"install" = "Install"
|
"install" = "Install"
|
||||||
"clients" = "Clients"
|
"clients" = "Clients"
|
||||||
"usage" = "Usage"
|
"usage" = "Usage"
|
||||||
|
"secretToken" = "Secret token"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
"dashboard" = "System Status"
|
"dashboard" = "System Status"
|
||||||
"inbounds" = "Inbounds"
|
"inbounds" = "Inbounds"
|
||||||
"setting" = "Panel Setting"
|
"setting" = "Panel Setting"
|
||||||
"logout" = "LogOut"
|
"logout" = "Logout"
|
||||||
"link" = "Other"
|
"link" = "Other"
|
||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
"loginAgain" = "The login time limit has expired, please log in again"
|
"loginAgain" = "The login time limit has expired, please log in again"
|
||||||
|
|
||||||
[pages.login.toasts]
|
[pages.login.toasts]
|
||||||
"invalidFormData" = "Input Data Format Is Invalid"
|
"invalidFormData" = "Input Data Format is Invalid"
|
||||||
"emptyUsername" = "Please Enter Username"
|
"emptyUsername" = "Please Enter Username"
|
||||||
"emptyPassword" = "Please Enter Password"
|
"emptyPassword" = "Please Enter Password"
|
||||||
"wrongUsernameOrPassword" = "Invalid username or password"
|
"wrongUsernameOrPassword" = "Invalid username or password"
|
||||||
@@ -75,17 +76,17 @@
|
|||||||
"stopXray" = "Stop"
|
"stopXray" = "Stop"
|
||||||
"restartXray" = "Restart"
|
"restartXray" = "Restart"
|
||||||
"xraySwitch" = "Switch Version"
|
"xraySwitch" = "Switch Version"
|
||||||
"xraySwitchClick" = "Click on the version you want to switch"
|
"xraySwitchClick" = "Choose the version you want to switch to."
|
||||||
"xraySwitchClickDesk" = "Please choose carefully, older versions may have incompatible configurations"
|
"xraySwitchClickDesk" = "Choose wisely, as older versions may not be compatible with current configurations."
|
||||||
"operationHours" = "Operation Hours"
|
"operationHours" = "Operation Hours"
|
||||||
"operationHoursDesc" = "The running time of the system since it was started"
|
"operationHoursDesc" = "System uptime: time since startup."
|
||||||
"systemLoad" = "System Load"
|
"systemLoad" = "System Load"
|
||||||
"connectionCount" = "Connection Count"
|
"connectionCount" = "Number of connections"
|
||||||
"connectionCountDesc" = "The total number of connections for all network cards"
|
"connectionCountDesc" = "Total connections across all network cards"
|
||||||
"upSpeed" = "Total upload speed for all network cards"
|
"upSpeed" = "Total upload speed for all network cards"
|
||||||
"downSpeed" = "Total download speed for all network cards"
|
"downSpeed" = "Total download speed for all network cards"
|
||||||
"totalSent" = "Total upload traffic of all network cards since system startup"
|
"totalSent" = "Total upload traffic of all network cards since system startup"
|
||||||
"totalReceive" = "Total download traffic of all network cards since system startup"
|
"totalReceive" = "Total download data across all network cards since system startup"
|
||||||
"xraySwitchVersionDialog" = "Switch xray version"
|
"xraySwitchVersionDialog" = "Switch xray version"
|
||||||
"xraySwitchVersionDialogDesc" = "Whether to switch the xray version to"
|
"xraySwitchVersionDialogDesc" = "Whether to switch the xray version to"
|
||||||
"dontRefreshh" = "Installation is in progress, please do not refresh this page"
|
"dontRefreshh" = "Installation is in progress, please do not refresh this page"
|
||||||
@@ -110,8 +111,8 @@
|
|||||||
"revise" = "Update"
|
"revise" = "Update"
|
||||||
"modifyInbound" = "Modify InBound"
|
"modifyInbound" = "Modify InBound"
|
||||||
"deleteInbound" = "Delete Inbound"
|
"deleteInbound" = "Delete Inbound"
|
||||||
"deleteInboundContent" = "Are you sure you want to delete inbound?"
|
"deleteInboundContent" = "Confirm deletion of inbound?"
|
||||||
"resetTrafficContent" = "Are you sure you want to reset traffic?"
|
"resetTrafficContent" = "Confirm traffic reset?"
|
||||||
"copyLink" = "Copy Link"
|
"copyLink" = "Copy Link"
|
||||||
"address" = "Address"
|
"address" = "Address"
|
||||||
"network" = "Network"
|
"network" = "Network"
|
||||||
@@ -121,8 +122,8 @@
|
|||||||
"monitorDesc" = "Leave blank by default"
|
"monitorDesc" = "Leave blank by default"
|
||||||
"meansNoLimit" = "Means no limit"
|
"meansNoLimit" = "Means no limit"
|
||||||
"totalFlow" = "Total flow"
|
"totalFlow" = "Total flow"
|
||||||
"leaveBlankToNeverExpire" = "Leave blank to never expire"
|
"leaveBlankToNeverExpire" = "Leave blank to set no expiration"
|
||||||
"noRecommendKeepDefault" = "There are no special requirements to keep the default"
|
"noRecommendKeepDefault" = "No special requirements to maintain default settings"
|
||||||
"certificatePath" = "Certificate file path"
|
"certificatePath" = "Certificate file path"
|
||||||
"certificateContent" = "Certificate file content"
|
"certificateContent" = "Certificate file content"
|
||||||
"publicKeyPath" = "Public key path"
|
"publicKeyPath" = "Public key path"
|
||||||
@@ -134,7 +135,7 @@
|
|||||||
"export" = "Export links"
|
"export" = "Export links"
|
||||||
"Clone" = "Clone"
|
"Clone" = "Clone"
|
||||||
"cloneInbound" = "Create"
|
"cloneInbound" = "Create"
|
||||||
"cloneInboundContent" = "All items of this inbound except Port, Listening IP, Clients will be applied to the clone"
|
"cloneInboundContent" = "All settings of this inbound, except for Port, Listening IP, and Clients, will be applied to the clone"
|
||||||
"cloneInboundOk" = "Creating a clone from"
|
"cloneInboundOk" = "Creating a clone from"
|
||||||
"resetAllTraffic" = "Reset All Inbounds Traffic"
|
"resetAllTraffic" = "Reset All Inbounds Traffic"
|
||||||
"resetAllTrafficTitle" = "Reset all inbounds traffic"
|
"resetAllTrafficTitle" = "Reset all inbounds traffic"
|
||||||
@@ -142,12 +143,12 @@
|
|||||||
"resetAllTrafficOkText" = "Confirm"
|
"resetAllTrafficOkText" = "Confirm"
|
||||||
"resetAllTrafficCancelText" = "Cancel"
|
"resetAllTrafficCancelText" = "Cancel"
|
||||||
"IPLimit" = "IP Limit"
|
"IPLimit" = "IP Limit"
|
||||||
"IPLimitDesc" = "disable inbound if more than entered count (0 for disable limit ip)"
|
"IPLimitDesc" = "Disable inbound if the count exceeds the entered value (Enter 0 to disable IP limit)"
|
||||||
"resetAllClientTraffics" = "Reset Clients Traffic"
|
"resetAllClientTraffics" = "Reset Clients Traffic"
|
||||||
"resetAllClientTrafficTitle" = "Reset all clients traffic"
|
"resetAllClientTrafficTitle" = "Reset all clients traffic"
|
||||||
"resetAllClientTrafficContent" = "Are you sure to reset all traffics of this inbound's clients ?"
|
"resetAllClientTrafficContent" = "Confirm reset of all traffic for clients of this inbound?"
|
||||||
"Email" = "Email"
|
"Email" = "Email"
|
||||||
"EmailDesc" = "The Email Must Be Completely Unique"
|
"EmailDesc" = "Please provide a unique email address"
|
||||||
"IPLimitlog" = "IP Log"
|
"IPLimitlog" = "IP Log"
|
||||||
"IPLimitlogDesc" = "IPs history Log (before enabling inbound after it has been disabled by IP limit, you should clear the log)"
|
"IPLimitlogDesc" = "IPs history Log (before enabling inbound after it has been disabled by IP limit, you should clear the log)"
|
||||||
"IPLimitlogclear" = "Clear The Log"
|
"IPLimitlogclear" = "Clear The Log"
|
||||||
@@ -221,9 +222,13 @@
|
|||||||
"advancedTemplate" = "Advanced Template parts"
|
"advancedTemplate" = "Advanced Template parts"
|
||||||
"completeTemplate" = "Complete Template of Xray configuration"
|
"completeTemplate" = "Complete Template of Xray configuration"
|
||||||
"generalConfigs" = "General Configs"
|
"generalConfigs" = "General Configs"
|
||||||
|
"generalConfigsDesc" = "This options will prevent users from connecting to specific protocols and websites."
|
||||||
"countryConfigs" = "Country Configs"
|
"countryConfigs" = "Country Configs"
|
||||||
|
"countryConfigsDesc" = "This options will prevent users from connecting to specific country domains."
|
||||||
"ipv4Configs" = "IPv4 Configs"
|
"ipv4Configs" = "IPv4 Configs"
|
||||||
|
"ipv4ConfigsDesc" = "This options will be route to target domains only via IPv4."
|
||||||
"warpConfigs" = "WARP Configs"
|
"warpConfigs" = "WARP Configs"
|
||||||
|
"warpConfigsDesc" = "Caution: Before using this options, Install WARP in socks5 proxy mode on your server by following the steps on the panel's GitHub. WARP will route traffic to websites through Cloudflare servers."
|
||||||
"xrayConfigTemplate" = "Xray Configuration Template"
|
"xrayConfigTemplate" = "Xray Configuration Template"
|
||||||
"xrayConfigTemplateDesc" = "Generate the final xray configuration file based on this template, restart the panel to take effect."
|
"xrayConfigTemplateDesc" = "Generate the final xray configuration file based on this template, restart the panel to take effect."
|
||||||
"xrayConfigTorrent" = "Ban bittorrent usage"
|
"xrayConfigTorrent" = "Ban bittorrent usage"
|
||||||
@@ -232,7 +237,7 @@
|
|||||||
"xrayConfigPrivateIpDesc" = "Change the configuration template to avoid connecting with private IP ranges, restart the panel to take effect"
|
"xrayConfigPrivateIpDesc" = "Change the configuration template to avoid connecting with private IP ranges, restart the panel to take effect"
|
||||||
"xrayConfigAds" = "Block Ads"
|
"xrayConfigAds" = "Block Ads"
|
||||||
"xrayConfigAdsDesc" = "Change the configuration template to block Ads, restart the panel to take effect"
|
"xrayConfigAdsDesc" = "Change the configuration template to block Ads, restart the panel to take effect"
|
||||||
"xrayConfigPorn" = "Ban Porn websites to connect"
|
"xrayConfigPorn" = "Block Porn Websites"
|
||||||
"xrayConfigPornDesc" = "Change the configuration template to avoid connecting to Porn websites, restart the panel to take effect"
|
"xrayConfigPornDesc" = "Change the configuration template to avoid connecting to Porn websites, restart the panel to take effect"
|
||||||
"xrayConfigIRIp" = "Ban Iran IP ranges to connect"
|
"xrayConfigIRIp" = "Ban Iran IP ranges to connect"
|
||||||
"xrayConfigIRIpDesc" = "Change the configuration template to avoid connecting with Iran IP ranges, restart the panel to take effect"
|
"xrayConfigIRIpDesc" = "Change the configuration template to avoid connecting with Iran IP ranges, restart the panel to take effect"
|
||||||
@@ -284,6 +289,10 @@
|
|||||||
"tgNotifyCpuDesc" = "This telegram bot will send you a notification if CPU usage is more than this percentage (unit:%)"
|
"tgNotifyCpuDesc" = "This telegram bot will send you a notification if CPU usage is more than this percentage (unit:%)"
|
||||||
"timeZonee" = "Time Zone"
|
"timeZonee" = "Time Zone"
|
||||||
"timeZoneDesc" = "The scheduled task runs according to the time in the time zone, and restarts the panel to take effect"
|
"timeZoneDesc" = "The scheduled task runs according to the time in the time zone, and restarts the panel to take effect"
|
||||||
|
"loginSecurity" = "Login security"
|
||||||
|
"loginSecurityDesc" = "Toggle additional step in user login page"
|
||||||
|
"secretToken" = "Secret Token"
|
||||||
|
"secretTokenDesc" = "Copy this secret token and keep it in a safe place; without this you won't be able to login. This can not be recovered from x-ui command tool neither"
|
||||||
|
|
||||||
[pages.setting.toasts]
|
[pages.setting.toasts]
|
||||||
"modifySetting" = "Modify setting"
|
"modifySetting" = "Modify setting"
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"install" = "نصب"
|
"install" = "نصب"
|
||||||
"clients" = "کاربران"
|
"clients" = "کاربران"
|
||||||
"usage" = "استفاده"
|
"usage" = "استفاده"
|
||||||
|
"secretToken" = "توکن امنیتی"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
"dashboard" = "وضعیت سیستم"
|
"dashboard" = "وضعیت سیستم"
|
||||||
@@ -219,9 +220,13 @@
|
|||||||
"advancedTemplate" = "بخش های پیشرفته الگو"
|
"advancedTemplate" = "بخش های پیشرفته الگو"
|
||||||
"completeTemplate" = "الگوی کامل تنظیمات ایکس ری"
|
"completeTemplate" = "الگوی کامل تنظیمات ایکس ری"
|
||||||
"generalConfigs" = "تنظیمات عمومی"
|
"generalConfigs" = "تنظیمات عمومی"
|
||||||
|
"generalConfigsDesc" = "این گزینه ها از اتصال کاربران به پروتکل ها و وب سایت های خاص جلوگیری می کند."
|
||||||
"countryConfigs" = "تنظیمات برای کشورها"
|
"countryConfigs" = "تنظیمات برای کشورها"
|
||||||
|
"countryConfigsDesc" = "این گزینه از اتصال کاربران به دامنه های کشوری خاص جلوگیری می کند."
|
||||||
"ipv4Configs" = "تنظیمات برای IPv4"
|
"ipv4Configs" = "تنظیمات برای IPv4"
|
||||||
|
"ipv4ConfigsDesc" = "این گزینه فقط از طریق آیپی ورژن 4 به دامنه های هدف هدایت می شود."
|
||||||
"warpConfigs" = "تنظیمات برای WARP"
|
"warpConfigs" = "تنظیمات برای WARP"
|
||||||
|
"warpConfigsDesc" = "هشدار: قبل از استفاده از این گزینه، WARP را در حالت پراکسی socks5 با دنبال کردن مراحل در GitHub پنل روی سرور خود نصب کنید. WARP ترافیک را از طریق سرورهای Cloudflare به وب سایت ها هدایت می کند."
|
||||||
"xrayConfigTemplate" = "تنظیمات الگو ایکس ری"
|
"xrayConfigTemplate" = "تنظیمات الگو ایکس ری"
|
||||||
"xrayConfigTemplateDesc" = "فایل پیکربندی ایکس ری نهایی بر اساس این الگو ایجاد میشود. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
"xrayConfigTemplateDesc" = "فایل پیکربندی ایکس ری نهایی بر اساس این الگو ایجاد میشود. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||||
"xrayConfigTorrent" = "فیلتر کردن بیت تورنت"
|
"xrayConfigTorrent" = "فیلتر کردن بیت تورنت"
|
||||||
@@ -282,6 +287,10 @@
|
|||||||
"tgNotifyCpuDesc" = "این ربات تلگرام در صورت استفاده پردازنده بیشتر از این درصد برای شما پیام ارسال می کند.(واحد: درصد)"
|
"tgNotifyCpuDesc" = "این ربات تلگرام در صورت استفاده پردازنده بیشتر از این درصد برای شما پیام ارسال می کند.(واحد: درصد)"
|
||||||
"timeZonee" = "منظقه زمانی"
|
"timeZonee" = "منظقه زمانی"
|
||||||
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقه زمانی اجرا می شوند. پنل را مجدداً راه اندازی می کند تا اعمال شود"
|
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقه زمانی اجرا می شوند. پنل را مجدداً راه اندازی می کند تا اعمال شود"
|
||||||
|
"loginSecurity" = "لاگین ایمن"
|
||||||
|
"loginSecurityDesc" = "افزودن یک مرحله دیگر به فرآیند لاگین"
|
||||||
|
"secretToken" = "توکن امنیتی"
|
||||||
|
"secretTokenDesc" = "این کد امنیتی را نزد خود در این جای امن نگه داری، بدون این کد امکان ورود به پنل را نخواهید داشت. امکان بازیابی آن وجود ندارد!"
|
||||||
|
|
||||||
[pages.setting.toasts]
|
[pages.setting.toasts]
|
||||||
"modifySetting" = "ویرایش تنظیمات"
|
"modifySetting" = "ویرایش تنظیمات"
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"install" = "安装"
|
"install" = "安装"
|
||||||
"clients" = "客户端"
|
"clients" = "客户端"
|
||||||
"usage" = "用法"
|
"usage" = "用法"
|
||||||
|
"secretToken" = "秘密令牌"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
"dashboard" = "系统状态"
|
"dashboard" = "系统状态"
|
||||||
@@ -219,9 +220,13 @@
|
|||||||
"advancedTemplate" = "高级模板部件"
|
"advancedTemplate" = "高级模板部件"
|
||||||
"completeTemplate" = "Xray 配置的完整模板"
|
"completeTemplate" = "Xray 配置的完整模板"
|
||||||
"generalConfigs" = "一般配置"
|
"generalConfigs" = "一般配置"
|
||||||
|
"generalConfigsDesc" = "此选项将阻止用户连接到特定协议和网站。"
|
||||||
"countryConfigs" = "国家配置"
|
"countryConfigs" = "国家配置"
|
||||||
|
"countryConfigsDesc" = "此选项将阻止用户连接到特定国家/地区的域。"
|
||||||
"ipv4Configs" = "IPv4 配置"
|
"ipv4Configs" = "IPv4 配置"
|
||||||
|
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域。"
|
||||||
"warpConfigs" = "WARP 配置"
|
"warpConfigs" = "WARP 配置"
|
||||||
|
"warpConfigsDesc" = "警告:在使用此选项之前,请按照面板 GitHub 上的步骤在您的服务器上以 socks5 代理模式安装 WARP。 WARP 将通过 Cloudflare 服务器将流量路由到网站。"
|
||||||
"xrayConfigTemplate" = "xray 配置模板"
|
"xrayConfigTemplate" = "xray 配置模板"
|
||||||
"xrayConfigTemplateDesc" = "以该模型为基础生成最终的xray配置文件,重新启动面板生成效率"
|
"xrayConfigTemplateDesc" = "以该模型为基础生成最终的xray配置文件,重新启动面板生成效率"
|
||||||
"xrayConfigTorrent" = "禁止使用 bittorrent"
|
"xrayConfigTorrent" = "禁止使用 bittorrent"
|
||||||
@@ -282,6 +287,10 @@
|
|||||||
"tgNotifyCpuDesc" = "如果 CPU 使用率超过此百分比(单位:%),此 talegram bot 将向您发送通知"
|
"tgNotifyCpuDesc" = "如果 CPU 使用率超过此百分比(单位:%),此 talegram bot 将向您发送通知"
|
||||||
"timeZonee" = "时区"
|
"timeZonee" = "时区"
|
||||||
"timeZoneDesc" = "定时任务按照该时区的时间运行,重启面板生效"
|
"timeZoneDesc" = "定时任务按照该时区的时间运行,重启面板生效"
|
||||||
|
"loginSecurity" = "登录安全"
|
||||||
|
"loginSecurityDesc" = "在用户登录页面中切换附加步骤"
|
||||||
|
"secretToken" = "秘密令牌"
|
||||||
|
"secretTokenDesc" = "复制此秘密令牌并将其保存在安全的地方;没有这个你将无法登录。这也无法从 x-ui 命令工具中恢复"
|
||||||
|
|
||||||
[pages.setting.toasts]
|
[pages.setting.toasts]
|
||||||
"modifySetting" = "修改设置"
|
"modifySetting" = "修改设置"
|
||||||
|
|||||||
87
x-ui.sh
87
x-ui.sh
@@ -56,9 +56,17 @@ elif [[ "${release}" == "debian" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
arch3xui() {
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64 | x64 | amd64 ) echo 'amd64' ;;
|
||||||
|
armv8 | arm64 | aarch64 ) echo 'arm64' ;;
|
||||||
|
* ) echo -e "${red} Unsupported CPU architecture!${plain}" && exit 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
confirm() {
|
confirm() {
|
||||||
if [[ $# > 1 ]]; then
|
if [[ $# > 1 ]]; then
|
||||||
echo && read -p "$1 [Default$2]: " temp
|
echo && read -p "$1 [Default $2]: " temp
|
||||||
if [[ x"${temp}" == x"" ]]; then
|
if [[ x"${temp}" == x"" ]]; then
|
||||||
temp=$2
|
temp=$2
|
||||||
fi
|
fi
|
||||||
@@ -98,18 +106,49 @@ install() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "n"
|
read -rp "This function will update the X-UI panel to the latest version. Data will not be lost. Whether to continues? [Y/N]: " yn
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $yn =~ "Y"|"y" ]]; then
|
||||||
LOGE "Cancelled"
|
systemctl stop x-ui
|
||||||
if [[ $# == 0 ]]; then
|
if [[ -e /usr/local/x-ui/ ]]; then
|
||||||
before_show_menu
|
cd
|
||||||
|
rm -rf /usr/local/x-ui/
|
||||||
fi
|
fi
|
||||||
return 0
|
|
||||||
fi
|
last_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') || last_version=$(curl -sm8 https://raw.githubusercontent.com/MHSanaei/3x-ui/main/config/version)
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
if [[ -z "$last_version" ]]; then
|
||||||
if [[ $? == 0 ]]; then
|
echo -e "${red}Detecting the X-UI version failed, please make sure your server can connect to the GitHub API ${plain}"
|
||||||
LOGI "Update is complete, Panel has automatically restarted "
|
exit 1
|
||||||
exit 0
|
fi
|
||||||
|
|
||||||
|
echo -e "${yellow}The latest version of X-UI is: ${last_version}, starting update...${plain}"
|
||||||
|
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch3xui).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch3xui).tar.gz
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo -e "${red}Download the X-UI failure, please make sure your server can connect and download the files from github ${plain}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /usr/local/
|
||||||
|
tar zxvf x-ui-linux-$(arch3xui).tar.gz
|
||||||
|
rm -f x-ui-linux-$(arch3xui).tar.gz
|
||||||
|
|
||||||
|
cd x-ui
|
||||||
|
chmod +x x-ui bin/xray-linux-$(arch3xui)
|
||||||
|
cp -f x-ui.service /etc/systemd/system/
|
||||||
|
|
||||||
|
wget -N --no-check-certificate https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh -O /usr/bin/x-ui
|
||||||
|
chmod +x /usr/local/x-ui/x-ui.sh
|
||||||
|
chmod +x /usr/bin/x-ui
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable x-ui >/dev/null 2>&1
|
||||||
|
systemctl start x-ui
|
||||||
|
systemctl restart x-ui
|
||||||
|
|
||||||
|
echo -e "${green}The update is completed, and the X-UI panel has been automatically restarted ${plain}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo -e "${red}The upgrade X-UI panel has been canceled! ${plain}"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,15 +178,23 @@ uninstall() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset_user() {
|
reset_user() {
|
||||||
confirm "Reset your username and password to admin?" "n"
|
confirm "Are you sure to reset the username and password of the panel?" "n"
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
if [[ $# == 0 ]]; then
|
if [[ $# == 0 ]]; then
|
||||||
show_menu
|
show_menu
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
/usr/local/x-ui/x-ui setting -username admin -password admin
|
read -rp "Please set the login username [default is a random username]: " config_account
|
||||||
echo -e "Username and password have been reset to ${green}admin${plain}, Please restart the panel now."
|
[[ -z $config_account ]] && config_account=$(date +%s%N | md5sum | cut -c 1-8)
|
||||||
|
read -rp "Please set the login password [default is a random password]: " config_password
|
||||||
|
[[ -z $config_password ]] && config_password=$(date +%s%N | md5sum | cut -c 1-8)
|
||||||
|
/usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password} >/dev/null 2>&1
|
||||||
|
/usr/local/x-ui/x-ui setting -remove_secret >/dev/null 2>&1
|
||||||
|
echo -e "Panel login username has been reset to: ${green} ${config_account} ${plain}"
|
||||||
|
echo -e "Panel login password has been reset to: ${green} ${config_password} ${plain}"
|
||||||
|
echo -e "${yellow} Panel login secret token disabled ${plain}"
|
||||||
|
echo -e "${green} Please use the new login username and password to access the X-UI panel. Also remember them! ${plain}"
|
||||||
confirm_restart
|
confirm_restart
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,8 +764,8 @@ ssl_cert_issue_by_cloudflare() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
google_recaptcha() {
|
warp_fixchatgpt() {
|
||||||
curl -O https://raw.githubusercontent.com/jinwyp/one_click_script/master/install_kernel.sh && chmod +x ./install_kernel.sh && ./install_kernel.sh
|
curl -fsSL https://gist.githubusercontent.com/hamid-gh98/dc5dd9b0cc5b0412af927b1ccdb294c7/raw/install_warp_proxy.sh | bash
|
||||||
echo ""
|
echo ""
|
||||||
before_show_menu
|
before_show_menu
|
||||||
}
|
}
|
||||||
@@ -781,7 +828,7 @@ show_menu() {
|
|||||||
${green}2.${plain} Update x-ui
|
${green}2.${plain} Update x-ui
|
||||||
${green}3.${plain} Uninstall x-ui
|
${green}3.${plain} Uninstall x-ui
|
||||||
————————————————
|
————————————————
|
||||||
${green}4.${plain} Reset Username And Password
|
${green}4.${plain} Reset Username & Password & Secret Token
|
||||||
${green}5.${plain} Reset Panel Settings
|
${green}5.${plain} Reset Panel Settings
|
||||||
${green}6.${plain} Change Panel Port
|
${green}6.${plain} Change Panel Port
|
||||||
${green}7.${plain} View Current Panel Settings
|
${green}7.${plain} View Current Panel Settings
|
||||||
@@ -799,7 +846,7 @@ show_menu() {
|
|||||||
${green}16.${plain} Apply for an SSL Certificate
|
${green}16.${plain} Apply for an SSL Certificate
|
||||||
${green}17.${plain} Update Geo Files
|
${green}17.${plain} Update Geo Files
|
||||||
${green}18.${plain} Active Firewall and open ports
|
${green}18.${plain} Active Firewall and open ports
|
||||||
${green}19.${plain} Fixing Google reCAPTCHA
|
${green}19.${plain} Install WARP
|
||||||
${green}20.${plain} Speedtest by Ookla
|
${green}20.${plain} Speedtest by Ookla
|
||||||
"
|
"
|
||||||
show_status
|
show_status
|
||||||
@@ -864,7 +911,7 @@ show_menu() {
|
|||||||
open_ports
|
open_ports
|
||||||
;;
|
;;
|
||||||
19)
|
19)
|
||||||
google_recaptcha
|
warp_fixchatgpt
|
||||||
;;
|
;;
|
||||||
20)
|
20)
|
||||||
run_speedtest
|
run_speedtest
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ func GetGeoipPath() string {
|
|||||||
return config.GetBinFolderPath() + "/geoip.dat"
|
return config.GetBinFolderPath() + "/geoip.dat"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetIranPath() string {
|
||||||
|
return config.GetBinFolderPath() + "/iran.dat"
|
||||||
|
}
|
||||||
|
|
||||||
func GetBlockedIPsPath() string {
|
func GetBlockedIPsPath() string {
|
||||||
return config.GetBinFolderPath() + "/blockedIPs"
|
return config.GetBinFolderPath() + "/blockedIPs"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user