diff --git a/database/db.go b/database/db.go
index b9c16be8..ae42a6de 100644
--- a/database/db.go
+++ b/database/db.go
@@ -27,8 +27,9 @@ func initUser() error {
}
if count == 0 {
user := &model.User{
- Username: "admin",
- Password: "admin",
+ Username: "admin",
+ Password: "admin",
+ LoginSecret: "",
}
return db.Create(user).Error
}
diff --git a/database/model/model.go b/database/model/model.go
index 778ad9b6..d1498b06 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -18,9 +18,10 @@ const (
)
type User struct {
- Id int `json:"id" gorm:"primaryKey;autoIncrement"`
- Username string `json:"username"`
- Password string `json:"password"`
+ Id int `json:"id" gorm:"primaryKey;autoIncrement"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ LoginSecret string `json:"loginSecret"`
}
type Inbound struct {
diff --git a/install.sh b/install.sh
index 15226a08..df74a0cf 100644
--- a/install.sh
+++ b/install.sh
@@ -23,23 +23,14 @@ else
fi
echo "The OS release is: $release"
-arch=$(arch)
-
-if [[ $arch == "x86_64" || $arch == "x64" || $arch == "amd64" ]]; then
- arch="amd64"
-elif [[ $arch == "aarch64" || $arch == "arm64" ]]; then
- arch="arm64"
-else
- arch="amd64"
- 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
+arch3xui() {
+ case "$(uname -m)" in
+ x86_64 | x64 | amd64 ) echo 'amd64' ;;
+ armv8 | arm64 | aarch64 ) echo 'arm64' ;;
+ * ) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
+ esac
+}
+echo "arch: $(arch3xui)"
os_version=""
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
@@ -122,18 +113,18 @@ install_x-ui() {
exit 1
fi
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
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
exit 1
fi
else
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"
- 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
- 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
fi
fi
@@ -142,10 +133,10 @@ install_x-ui() {
rm /usr/local/x-ui/ -rf
fi
- tar zxvf x-ui-linux-${arch}.tar.gz
- rm x-ui-linux-${arch}.tar.gz -f
+ tar zxvf x-ui-linux-$(arch3xui).tar.gz
+ rm x-ui-linux-$(arch3xui).tar.gz -f
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/
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
diff --git a/main.go b/main.go
index e41546ec..710b80d4 100644
--- a/main.go
+++ b/main.go
@@ -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() {
if len(os.Args) < 2 {
runWebServer()
@@ -229,6 +247,7 @@ func main() {
var tgbotRuntime string
var reset bool
var show bool
+ var remove_secret bool
settingCmd.BoolVar(&reset, "reset", false, "reset all settings")
settingCmd.BoolVar(&show, "show", false, "show current settings")
settingCmd.IntVar(&port, "port", 0, "set panel port")
@@ -290,6 +309,9 @@ func main() {
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
}
+ if remove_secret {
+ removeSecret()
+ }
if enabletgbot {
updateTgbotEnableSts(enabletgbot)
}
diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js
index 1de76850..ace99f48 100644
--- a/web/assets/js/model/models.js
+++ b/web/assets/js/model/models.js
@@ -3,6 +3,7 @@ class User {
constructor() {
this.username = "";
this.password = "";
+ this.LoginSecret = "";
}
}
@@ -180,6 +181,7 @@ class AllSetting {
this.tgBotBackup = false;
this.tgCpu = "";
this.xrayTemplateConfig = "";
+ this.secretEnable = false;
this.timeLocation = "Asia/Tehran";
diff --git a/web/controller/index.go b/web/controller/index.go
index b4f981e8..c19ee799 100644
--- a/web/controller/index.go
+++ b/web/controller/index.go
@@ -11,15 +11,17 @@ import (
)
type LoginForm struct {
- Username string `json:"username" form:"username"`
- Password string `json:"password" form:"password"`
+ Username string `json:"username" form:"username"`
+ Password string `json:"password" form:"password"`
+ LoginSecret string `json:"loginSecret" form:"loginSecret"`
}
type IndexController struct {
BaseController
- userService service.UserService
- tgbot service.Tgbot
+ settingService service.SettingService
+ userService service.UserService
+ tgbot service.Tgbot
}
func NewIndexController(g *gin.RouterGroup) *IndexController {
@@ -32,6 +34,7 @@ func (a *IndexController) initRouter(g *gin.RouterGroup) {
g.GET("/", a.index)
g.POST("/login", a.login)
g.GET("/logout", a.logout)
+ g.POST("/getSecretStatus", a.getSecretStatus)
}
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"))
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")
if user == nil {
a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
@@ -82,3 +85,11 @@ func (a *IndexController) logout(c *gin.Context) {
session.ClearSession(c)
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)
+ }
+
+}
diff --git a/web/controller/setting.go b/web/controller/setting.go
index 1de55ab6..2726c228 100644
--- a/web/controller/setting.go
+++ b/web/controller/setting.go
@@ -17,6 +17,10 @@ type updateUserForm struct {
NewPassword string `json:"newPassword" form:"newPassword"`
}
+type updateSecretForm struct {
+ LoginSecret string `json:"loginSecret" form:"loginSecret"`
+}
+
type SettingController struct {
settingService service.SettingService
userService service.UserService
@@ -38,6 +42,8 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
g.POST("/updateUser", a.updateUser)
g.POST("/restartPanel", a.restartPanel)
g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig)
+ g.POST("/updateUserSecret", a.updateSecret)
+ g.POST("/getUserSecret", a.getUserSecret)
}
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)
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)
+ }
+}
diff --git a/web/entity/entity.go b/web/entity/entity.go
index b464de00..f1b24520 100644
--- a/web/entity/entity.go
+++ b/web/entity/entity.go
@@ -42,6 +42,7 @@ type AllSetting struct {
TgCpu int `json:"tgCpu" form:"tgCpu"`
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
TimeLocation string `json:"timeLocation" form:"timeLocation"`
+ SecretEnable bool `json:"secretEnable" form:"secretEnable"`
}
func (s *AllSetting) CheckValid() error {
diff --git a/web/html/login.html b/web/html/login.html
index 4218793c..2f4cb3e6 100644
--- a/web/html/login.html
+++ b/web/html/login.html
@@ -57,6 +57,11 @@
+
+
+
+
+
{{ i18n "login" }}
@@ -98,10 +103,12 @@
data: {
loading: false,
user: new User(),
+ secretEnable: false,
lang : ""
},
created(){
this.lang = getLang();
+ this.secretEnable = this.getSecretStatus();
},
methods: {
async login() {
@@ -111,6 +118,15 @@
if (msg.success) {
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;
+ }
}
}
});
diff --git a/web/html/xui/setting.html b/web/html/xui/setting.html
index eaaf8b25..db318ee4 100644
--- a/web/html/xui/setting.html
+++ b/web/html/xui/setting.html
@@ -91,8 +91,39 @@
{{ i18n "confirm" }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ i18n "confirm" }}
+
-
{{ i18n "pages.setting.actions"}}
@@ -205,7 +236,7 @@
oldAllSetting: new AllSetting(),
allSetting: new AllSetting(),
saveBtnDisable: true,
- user: {},
+ user: new User(),
lang: getLang(),
ipv4Settings: {
tag: "IPv4",
@@ -262,31 +293,33 @@
}
},
methods: {
- loading(spinning = true) {
- this.spinning = spinning;
+ loading(spinning = true , obj) {
+ if(obj == null)
+ this.spinning = spinning;
},
async getAllSetting() {
- this.loading(true);
+ this.loading(true,{});
const msg = await HttpUtil.post("/xui/setting/all");
- this.loading(false);
+ this.loading(false,null);
if (msg.success) {
this.oldAllSetting = new AllSetting(msg.obj);
this.allSetting = new AllSetting(msg.obj);
this.saveBtnDisable = true;
}
+ await this.getUserSecret();
},
async updateAllSetting() {
- this.loading(true);
+ this.loading(true,{});
const msg = await HttpUtil.post("/xui/setting/update", this.allSetting);
- this.loading(false);
+ this.loading(false,null);
if (msg.success) {
await this.getAllSetting();
}
},
async updateUser() {
- this.loading(true);
+ this.loading(true,{});
const msg = await HttpUtil.post("/xui/setting/updateUser", this.user);
- this.loading(false);
+ this.loading(false,null);
if (msg.success) {
this.user = {};
}
@@ -301,19 +334,54 @@
onOk: () => resolve(),
});
});
- this.loading(true);
+ this.loading(true,{});
const msg = await HttpUtil.post("/xui/setting/restartPanel");
- this.loading(false);
+ this.loading(false,null);
if (msg.success) {
- this.loading(true);
+ this.loading(true,{});
await PromiseUtil.sleep(5000);
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 1 ]]; then
echo && read -p "$1 [Default$2]: " temp
@@ -98,18 +106,49 @@ install() {
}
update() {
- confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "n"
- if [[ $? != 0 ]]; then
- LOGE "Cancelled"
- if [[ $# == 0 ]]; then
- before_show_menu
+ 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 [[ $yn =~ "Y"|"y" ]]; then
+ systemctl stop x-ui
+ if [[ -e /usr/local/x-ui/ ]]; then
+ cd
+ rm -rf /usr/local/x-ui/
fi
- return 0
- fi
- bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
- if [[ $? == 0 ]]; then
- LOGI "Update is complete, Panel has automatically restarted "
- exit 0
+
+ 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)
+ if [[ -z "$last_version" ]]; then
+ echo -e "${red}Detecting the X-UI version failed, please make sure your server can connect to the GitHub API ${plain}"
+ exit 1
+ 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
}
@@ -139,15 +178,23 @@ uninstall() {
}
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
show_menu
fi
return 0
fi
- /usr/local/x-ui/x-ui setting -username admin -password admin
- echo -e "Username and password have been reset to ${green}admin${plain}, Please restart the panel now."
+ read -rp "Please set the login username [default is a random username]: " config_account
+ [[ -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
}
@@ -781,7 +828,7 @@ show_menu() {
${green}2.${plain} Update 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}6.${plain} Change Panel Port
${green}7.${plain} View Current Panel Settings