From 2c53007580ddd646c2ab34ade8b4345b5d9122c9 Mon Sep 17 00:00:00 2001
From: "Shishkevich D." <135337715+shishkevichd@users.noreply.github.com>
Date: Sat, 3 May 2025 08:03:09 +0000
Subject: [PATCH] chore: implement 2fa auth
from #2786
---
database/db.go | 2 -
database/model/model.go | 1 -
go.mod | 1 +
go.sum | 2 +
main.go | 35 -------------
web/assets/js/model/setting.js | 3 +-
web/assets/js/util/index.js | 27 ++++++++++
web/controller/index.go | 17 +++----
web/controller/setting.go | 29 -----------
web/entity/entity.go | 3 +-
web/html/login.html | 20 ++++----
web/html/settings.html | 37 ++------------
web/html/settings/panel/security.html | 27 ++++------
web/service/setting.go | 22 ++++-----
web/service/user.go | 71 +++++++++------------------
web/translation/translate.ar_EG.toml | 14 +++---
web/translation/translate.en_US.toml | 14 +++---
web/translation/translate.es_ES.toml | 14 +++---
web/translation/translate.fa_IR.toml | 14 +++---
web/translation/translate.id_ID.toml | 14 +++---
web/translation/translate.ja_JP.toml | 14 +++---
web/translation/translate.pt_BR.toml | 14 +++---
web/translation/translate.ru_RU.toml | 14 +++---
web/translation/translate.tr_TR.toml | 14 +++---
web/translation/translate.uk_UA.toml | 14 +++---
web/translation/translate.vi_VN.toml | 14 +++---
web/translation/translate.zh_CN.toml | 14 +++---
web/translation/translate.zh_TW.toml | 14 +++---
x-ui.sh | 4 +-
29 files changed, 193 insertions(+), 290 deletions(-)
diff --git a/database/db.go b/database/db.go
index 744f1401..78270dbb 100644
--- a/database/db.go
+++ b/database/db.go
@@ -22,7 +22,6 @@ var db *gorm.DB
const (
defaultUsername = "admin"
defaultPassword = "admin"
- defaultSecret = ""
)
func initModels() error {
@@ -53,7 +52,6 @@ func initUser() error {
user := &model.User{
Username: defaultUsername,
Password: defaultPassword,
- LoginSecret: defaultSecret,
}
return db.Create(user).Error
}
diff --git a/database/model/model.go b/database/model/model.go
index e9d1836f..ca430826 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -24,7 +24,6 @@ type User struct {
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/go.mod b/go.mod
index 82aee875..66ebce41 100644
--- a/go.mod
+++ b/go.mod
@@ -78,6 +78,7 @@ require (
github.com/valyala/fastjson v1.6.4 // indirect
github.com/vishvananda/netlink v1.3.0 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
+ github.com/xlzd/gotp v0.1.0 // indirect
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
diff --git a/go.sum b/go.sum
index e49e9645..8fca69a2 100644
--- a/go.sum
+++ b/go.sum
@@ -187,6 +187,8 @@ github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
+github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po=
+github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg=
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882 h1:O/aN4TCrJ+fmaDOBoQhtTRev2hVHIENy2EJ70jQcyEY=
diff --git a/main.go b/main.go
index 84ffca6e..c9e26bd4 100644
--- a/main.go
+++ b/main.go
@@ -343,36 +343,6 @@ func migrateDb() {
fmt.Println("Migration done!")
}
-func removeSecret() {
- userService := service.UserService{}
-
- secretExists, err := userService.CheckSecretExistence()
- if err != nil {
- fmt.Println("Error checking secret existence:", err)
- return
- }
-
- if !secretExists {
- fmt.Println("No secret exists to remove.")
- return
- }
-
- err = userService.RemoveUserSecret()
- if err != nil {
- fmt.Println("Error removing secret:", err)
- return
- }
-
- settingService := service.SettingService{}
- err = settingService.SetSecretStatus(false)
- if err != nil {
- fmt.Println("Error updating secret status:", err)
- return
- }
-
- fmt.Println("Secret removed successfully.")
-}
-
func main() {
if len(os.Args) < 2 {
runWebServer()
@@ -400,10 +370,8 @@ func main() {
var reset bool
var show bool
var getCert bool
- var remove_secret bool
settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
settingCmd.BoolVar(&show, "show", false, "Display current settings")
- settingCmd.BoolVar(&remove_secret, "remove_secret", false, "Remove secret key")
settingCmd.IntVar(&port, "port", 0, "Set panel port number")
settingCmd.StringVar(&username, "username", "", "Set login username")
settingCmd.StringVar(&password, "password", "", "Set login password")
@@ -467,9 +435,6 @@ 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/setting.js b/web/assets/js/model/setting.js
index 6c8abe0d..89ea171f 100644
--- a/web/assets/js/model/setting.js
+++ b/web/assets/js/model/setting.js
@@ -23,8 +23,9 @@ class AllSetting {
this.tgBotLoginNotify = true;
this.tgCpu = 80;
this.tgLang = "en-US";
+ this.twoFactorEnable = false;
+ this.twoFactorToken = "";
this.xrayTemplateConfig = "";
- this.secretEnable = false;
this.subEnable = false;
this.subTitle = "";
this.subListen = "";
diff --git a/web/assets/js/util/index.js b/web/assets/js/util/index.js
index a13006d4..0d869af6 100644
--- a/web/assets/js/util/index.js
+++ b/web/assets/js/util/index.js
@@ -145,6 +145,33 @@ class RandomUtil {
return Base64.alternativeEncode(String.fromCharCode(...array));
}
+
+ static randomBase32String(length = 16) {
+ const array = new Uint8Array(length);
+
+ window.crypto.getRandomValues(array);
+
+ const base32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
+ let result = '';
+ let bits = 0;
+ let buffer = 0;
+
+ for (let i = 0; i < array.length; i++) {
+ buffer = (buffer << 8) | array[i];
+ bits += 8;
+
+ while (bits >= 5) {
+ bits -= 5;
+ result += base32Chars[(buffer >>> bits) & 0x1F];
+ }
+ }
+
+ if (bits > 0) {
+ result += base32Chars[(buffer << (5 - bits)) & 0x1F];
+ }
+
+ return result;
+ }
}
class ObjectUtil {
diff --git a/web/controller/index.go b/web/controller/index.go
index 9af4ed7f..c19d1b6e 100644
--- a/web/controller/index.go
+++ b/web/controller/index.go
@@ -14,9 +14,9 @@ import (
)
type LoginForm struct {
- Username string `json:"username" form:"username"`
- Password string `json:"password" form:"password"`
- LoginSecret string `json:"loginSecret" form:"loginSecret"`
+ Username string `json:"username" form:"username"`
+ Password string `json:"password" form:"password"`
+ TwoFactorCode string `json:"twoFactorCode" form:"twoFactorCode"`
}
type IndexController struct {
@@ -37,7 +37,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)
+ g.POST("/getTwoFactorEnable", a.getTwoFactorEnable)
}
func (a *IndexController) index(c *gin.Context) {
@@ -64,14 +64,13 @@ func (a *IndexController) login(c *gin.Context) {
return
}
- user := a.userService.CheckUser(form.Username, form.Password, form.LoginSecret)
+ user := a.userService.CheckUser(form.Username, form.Password, form.TwoFactorCode)
timeStr := time.Now().Format("2006-01-02 15:04:05")
safeUser := template.HTMLEscapeString(form.Username)
safePass := template.HTMLEscapeString(form.Password)
- safeSecret := template.HTMLEscapeString(form.LoginSecret)
if user == nil {
- logger.Warningf("wrong username: \"%s\", password: \"%s\", secret: \"%s\", IP: \"%s\"", safeUser, safePass, safeSecret, getRemoteIp(c))
+ logger.Warningf("wrong username: \"%s\", password: \"%s\", IP: \"%s\"", safeUser, safePass, getRemoteIp(c))
a.tgbot.UserLoginNotify(safeUser, safePass, getRemoteIp(c), timeStr, 0)
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
return
@@ -108,8 +107,8 @@ func (a *IndexController) logout(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}
-func (a *IndexController) getSecretStatus(c *gin.Context) {
- status, err := a.settingService.GetSecretStatus()
+func (a *IndexController) getTwoFactorEnable(c *gin.Context) {
+ status, err := a.settingService.GetTwoFactorEnable()
if err == nil {
jsonObj(c, status, nil)
}
diff --git a/web/controller/setting.go b/web/controller/setting.go
index d04969dc..bb17c4b3 100644
--- a/web/controller/setting.go
+++ b/web/controller/setting.go
@@ -18,10 +18,6 @@ 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
@@ -43,8 +39,6 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
g.POST("/updateUser", a.updateUser)
g.POST("/restartPanel", a.restartPanel)
g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
- g.POST("/updateUserSecret", a.updateSecret)
- g.POST("/getUserSecret", a.getUserSecret)
}
func (a *SettingController) getAllSetting(c *gin.Context) {
@@ -106,29 +100,6 @@ func (a *SettingController) restartPanel(c *gin.Context) {
jsonMsg(c, I18nWeb(c, "pages.settings.restartPanel"), err)
}
-func (a *SettingController) updateSecret(c *gin.Context) {
- form := &updateSecretForm{}
- err := c.ShouldBind(form)
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), 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, I18nWeb(c, "pages.settings.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)
- }
-}
-
func (a *SettingController) getDefaultXrayConfig(c *gin.Context) {
defaultJsonConfig, err := a.settingService.GetDefaultXrayConfig()
if err != nil {
diff --git a/web/entity/entity.go b/web/entity/entity.go
index 872901b8..543b80e0 100644
--- a/web/entity/entity.go
+++ b/web/entity/entity.go
@@ -38,7 +38,8 @@ type AllSetting struct {
TgCpu int `json:"tgCpu" form:"tgCpu"`
TgLang string `json:"tgLang" form:"tgLang"`
TimeLocation string `json:"timeLocation" form:"timeLocation"`
- SecretEnable bool `json:"secretEnable" form:"secretEnable"`
+ TwoFactorEnable bool `json:"twoFactorEnable" form:"twoFactorEnable"`
+ TwoFactorToken string `json:"twoFactorToken" form:"twoFactorToken"`
SubEnable bool `json:"subEnable" form:"subEnable"`
SubTitle string `json:"subTitle" form:"subTitle"`
SubListen string `json:"subListen" form:"subListen"`
diff --git a/web/html/login.html b/web/html/login.html
index 9f292d84..515ea2b3 100644
--- a/web/html/login.html
+++ b/web/html/login.html
@@ -512,11 +512,11 @@
-
-
+
+
-
+
@@ -549,14 +549,14 @@
user: {
username: "",
password: "",
- loginSecret: ""
+ twoFactorCode: ""
},
- secretEnable: false,
+ twoFactorEnable: false,
lang: ""
},
async mounted() {
this.lang = LanguageManager.getLanguage();
- this.secretEnable = await this.getSecretStatus();
+ this.twoFactorEnable = await this.getTwoFactorEnable();
},
methods: {
async login() {
@@ -567,12 +567,12 @@
location.href = basePath + 'panel/';
}
},
- async getSecretStatus() {
+ async getTwoFactorEnable() {
this.loading = true;
- const msg = await HttpUtil.post('/getSecretStatus');
+ const msg = await HttpUtil.post('/getTwoFactorEnable');
this.loading = false;
if (msg.success) {
- this.secretEnable = msg.obj;
+ this.twoFactorEnable = msg.obj;
return msg.obj;
}
},
diff --git a/web/html/settings.html b/web/html/settings.html
index 82e636d9..75cadc51 100644
--- a/web/html/settings.html
+++ b/web/html/settings.html
@@ -133,7 +133,6 @@
data: {
themeSwitcher,
spinning: false,
- changeSecret: false,
oldAllSetting: new AllSetting(),
allSetting: new AllSetting(),
saveBtnDisable: true,
@@ -258,7 +257,6 @@
app.changeRemarkSample();
this.saveBtnDisable = true;
}
- await this.fetchUserSecret();
},
async updateAllSetting() {
this.loading(true);
@@ -302,38 +300,11 @@
window.location.replace(url);
}
},
- async fetchUserSecret() {
- this.loading(true);
- const userMessage = await HttpUtil.post("/panel/setting/getUserSecret", this.user);
- if (userMessage.success) {
- this.user = userMessage.obj;
- }
- this.loading(false);
- },
- async updateSecret() {
- this.loading(true);
- const msg = await HttpUtil.post("/panel/setting/updateUserSecret", this.user);
- if (msg && msg.obj) {
- this.user = msg.obj;
- }
- this.loading(false);
- await this.updateAllSetting();
- },
- async getNewSecret() {
- if (!this.changeSecret) {
- this.changeSecret = true;
- this.user.loginSecret = '';
- const newSecret = RandomUtil.randomSeq(64);
- await PromiseUtil.sleep(1000);
- this.user.loginSecret = newSecret;
- this.changeSecret = false;
- }
- },
- async toggleToken(value) {
- if (value) {
- await this.getNewSecret();
+ toggleTwoFactor(newValue) {
+ if (newValue) {
+ this.allSetting.twoFactorToken = RandomUtil.randomBase32String();
} else {
- this.user.loginSecret = "";
+ this.allSetting.twoFactorToken = "";
}
},
addNoise() {
diff --git a/web/html/settings/panel/security.html b/web/html/settings/panel/security.html
index 48e7796f..4abad4c7 100644
--- a/web/html/settings/panel/security.html
+++ b/web/html/settings/panel/security.html
@@ -31,30 +31,23 @@
-
+
- {{ i18n "pages.settings.security.loginSecurity" }}
- {{ i18n "pages.settings.security.loginSecurityDesc" }}
+ {{ i18n "pages.settings.security.twoFactorEnable" }}
+ {{ i18n "pages.settings.security.twoFactorEnableDesc" }}
-
-
+
-
- {{ i18n "pages.settings.security.secretToken" }}
- {{ i18n "pages.settings.security.secretTokenDesc" }}
+
+ {{ i18n "pages.settings.security.twoFactorToken" }}
+ {{ i18n "pages.settings.security.twoFactorTokenDesc" }}
-
+
+
+
-
-
-
- {{ i18n "confirm"}}
-
-
-
{{end}}
\ No newline at end of file
diff --git a/web/service/setting.go b/web/service/setting.go
index 5443760c..62d66c11 100644
--- a/web/service/setting.go
+++ b/web/service/setting.go
@@ -48,7 +48,8 @@ var defaultValueMap = map[string]string{
"tgBotLoginNotify": "true",
"tgCpu": "80",
"tgLang": "en-US",
- "secretEnable": "false",
+ "twoFactorEnable": "false",
+ "twoFactorToken": "",
"subEnable": "false",
"subTitle": "",
"subListen": "",
@@ -166,8 +167,7 @@ func (s *SettingService) ResetSettings() error {
return err
}
return db.Model(model.User{}).
- Where("1 = 1").
- Update("login_secret", "").Error
+ Where("1 = 1").Error
}
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
@@ -318,6 +318,14 @@ func (s *SettingService) GetTgLang() (string, error) {
return s.getString("tgLang")
}
+func (s *SettingService) GetTwoFactorEnable() (bool, error) {
+ return s.getBool("twoFactorEnable")
+}
+
+func (s *SettingService) GetTwoFactorToken() (string, error) {
+ return s.getString("twoFactorToken")
+}
+
func (s *SettingService) GetPort() (int, error) {
return s.getInt("webPort")
}
@@ -358,14 +366,6 @@ func (s *SettingService) GetRemarkModel() (string, error) {
return s.getString("remarkModel")
}
-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) {
secret, err := s.getString("secret")
if secret == defaultValueMap["secret"] {
diff --git a/web/service/user.go b/web/service/user.go
index 7438cf1a..ed8fb5b4 100644
--- a/web/service/user.go
+++ b/web/service/user.go
@@ -8,9 +8,12 @@ import (
"x-ui/logger"
"gorm.io/gorm"
+ "github.com/xlzd/gotp"
)
-type UserService struct{}
+type UserService struct {
+ settingService SettingService
+}
func (s *UserService) GetFirstUser() (*model.User, error) {
db := database.GetDB()
@@ -25,12 +28,12 @@ func (s *UserService) GetFirstUser() (*model.User, error) {
return user, nil
}
-func (s *UserService) CheckUser(username string, password string, secret string) *model.User {
+func (s *UserService) CheckUser(username string, password string, twoFactorCode string) *model.User {
db := database.GetDB()
user := &model.User{}
err := db.Model(model.User{}).
- Where("username = ? and password = ? and login_secret = ?", username, password, secret).
+ Where("username = ? and password = ?", username, password).
First(user).
Error
if err == gorm.ErrRecordNotFound {
@@ -39,6 +42,24 @@ func (s *UserService) CheckUser(username string, password string, secret string)
logger.Warning("check user err:", err)
return nil
}
+ twoFactorEnable, err := s.settingService.GetTwoFactorEnable();
+ if err != nil {
+ logger.Warning("check two factor err:", err)
+ return nil
+ }
+ if twoFactorEnable {
+ twoFactorToken, err := s.settingService.GetTwoFactorToken();
+
+ if err != nil {
+ logger.Warning("check two factor token err:", err)
+ return nil
+ }
+
+ if gotp.NewDefaultTOTP(twoFactorToken).Now() != twoFactorCode {
+ return nil
+ }
+ }
+
return user
}
@@ -50,50 +71,6 @@ func (s *UserService) UpdateUser(id int, username string, password string) 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) CheckSecretExistence() (bool, error) {
- db := database.GetDB()
-
- var count int64
- err := db.Model(model.User{}).
- Where("login_secret IS NOT NULL").
- Count(&count).
- Error
- if err != nil {
- return false, err
- }
-
- return count > 0, nil
-}
-
func (s *UserService) UpdateFirstUser(username string, password string) error {
if username == "" {
return errors.New("username can not be empty")
diff --git a/web/translation/translate.ar_EG.toml b/web/translation/translate.ar_EG.toml
index 229f1320..81547465 100644
--- a/web/translation/translate.ar_EG.toml
+++ b/web/translation/translate.ar_EG.toml
@@ -51,7 +51,7 @@
"install" = "تثبيت"
"clients" = "عملاء"
"usage" = "استخدام"
-"secretToken" = "توكن سري"
+"twoFactorCode" = "الكود"
"remained" = "المتبقي"
"security" = "أمان"
"secAlertTitle" = "تنبيه أمني"
@@ -87,7 +87,7 @@
"invalidFormData" = "تنسيق البيانات المدخلة مش صحيح."
"emptyUsername" = "اسم المستخدم مطلوب"
"emptyPassword" = "الباسورد مطلوب"
-"wrongUsernameOrPassword" = "اسم المستخدم أو الباسورد أو السر مش صحيح."
+"wrongUsernameOrPassword" = "اسم المستخدم أو كلمة المرور أو كود المصادقة الثنائية غير صحيح."
"successLogin" = "تسجيل دخول ناجح"
[pages.index]
@@ -497,11 +497,11 @@
[pages.settings.security]
"admin" = "بيانات الأدمن"
-"secret" = "توكن سري"
-"loginSecurity" = "أمان تسجيل الدخول"
-"loginSecurityDesc" = "بيضيف طبقة مصادقة إضافية لزيادة الأمان."
-"secretToken" = "توكن سري"
-"secretTokenDesc" = "احتفظ بالتوكن ده في مكان آمن. التوكن ده مطلوب لتسجيل الدخول ومش ممكن تسترجعه لو ضاع."
+"twoFactor" = "المصادقة الثنائية"
+"twoFactorEnable" = "تفعيل المصادقة الثنائية"
+"twoFactorEnableDesc" = "يضيف طبقة إضافية من المصادقة لتعزيز الأمان."
+"twoFactorToken" = "رمز المصادقة الثنائية"
+"twoFactorTokenDesc" = "يرجى حفظ هذا الرمز بشكل آمن في تطبيق المصادقة."
[pages.settings.toasts]
"modifySettings" = "تعديل الإعدادات"
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index c691cbdd..2afb7c15 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -51,7 +51,7 @@
"install" = "Install"
"clients" = "Clients"
"usage" = "Usage"
-"secretToken" = "Secret Token"
+"twoFactorCode" = "Code"
"remained" = "Remained"
"security" = "Security"
"secAlertTitle" = "Security Alert"
@@ -87,7 +87,7 @@
"invalidFormData" = "The Input data format is invalid."
"emptyUsername" = "Username is required"
"emptyPassword" = "Password is required"
-"wrongUsernameOrPassword" = "Invalid username or password or secret."
+"wrongUsernameOrPassword" = "Invalid username or password or two-factor code."
"successLogin" = "Login"
[pages.index]
@@ -497,11 +497,11 @@
[pages.settings.security]
"admin" = "Admin credentials"
-"secret" = "Secret Token"
-"loginSecurity" = "Secure Login"
-"loginSecurityDesc" = "Adds an additional layer of authentication to provide more security."
-"secretToken" = "Secret Token"
-"secretTokenDesc" = "Please securely store this token in a safe place. This token is required for login and cannot be recovered."
+"twoFactor" = "Two-factor authentication"
+"twoFactorEnable" = "Enable 2FA"
+"twoFactorEnableDesc" = "Adds an additional layer of authentication to provide more security."
+"twoFactorToken" = "2FA token"
+"twoFactorTokenDesc" = "Please securely store this token in a authentication app."
[pages.settings.toasts]
"modifySettings" = "Modify Settings"
diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml
index d989b3e9..92a4d64e 100644
--- a/web/translation/translate.es_ES.toml
+++ b/web/translation/translate.es_ES.toml
@@ -51,7 +51,7 @@
"install" = "Instalar"
"clients" = "Clientes"
"usage" = "Uso"
-"secretToken" = "Token Secreto"
+"twoFactorCode" = "Código"
"remained" = "Restante"
"security" = "Seguridad"
"secAlertTitle" = "Alerta de Seguridad"
@@ -87,7 +87,7 @@
"invalidFormData" = "El formato de los datos de entrada es inválido."
"emptyUsername" = "Por favor ingresa el nombre de usuario."
"emptyPassword" = "Por favor ingresa la contraseña."
-"wrongUsernameOrPassword" = "Nombre de usuario o contraseña inválidos."
+"wrongUsernameOrPassword" = "Nombre de usuario, contraseña o código de dos factores incorrecto."
"successLogin" = "Inicio de Sesión Exitoso"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Credenciales de administrador"
-"secret" = "Token Secreto"
-"loginSecurity" = "Seguridad de Inicio de Sesión"
-"loginSecurityDesc" = "Habilitar un paso adicional de seguridad para el inicio de sesión de usuarios."
-"secretToken" = "Token Secreto"
-"secretTokenDesc" = "Por favor, copia y guarda este token de forma segura en un lugar seguro. Este token es necesario para iniciar sesión y no se puede recuperar con la herramienta de comando x-ui."
+"twoFactor" = "Autenticación de dos factores"
+"twoFactorEnable" = "Habilitar 2FA"
+"twoFactorEnableDesc" = "Añade una capa adicional de autenticación para mayor seguridad."
+"twoFactorToken" = "Token de 2FA"
+"twoFactorTokenDesc" = "Guarde este token de forma segura en una aplicación de autenticación."
[pages.settings.toasts]
"modifySettings" = "Modificar Configuraciones "
diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml
index 96a39ca9..dccb17e5 100644
--- a/web/translation/translate.fa_IR.toml
+++ b/web/translation/translate.fa_IR.toml
@@ -51,7 +51,7 @@
"install" = "نصب"
"clients" = "کاربران"
"usage" = "استفاده"
-"secretToken" = "توکن امنیتی"
+"twoFactorCode" = "کد"
"remained" = "باقیمانده"
"security" = "امنیت"
"secAlertTitle" = "هشدارامنیتی"
@@ -87,7 +87,7 @@
"invalidFormData" = "اطلاعات بهدرستی وارد نشدهاست"
"emptyUsername" = "لطفا یک نامکاربری وارد کنید"
"emptyPassword" = "لطفا یک رمزعبور وارد کنید"
-"wrongUsernameOrPassword" = "نامکاربری یا رمزعبوراشتباهاست"
+"wrongUsernameOrPassword" = "نام کاربری، رمز عبور یا کد دو مرحلهای نامعتبر است."
"successLogin" = "ورود"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "اعتبارنامههای ادمین"
-"secret" = "توکن مخفی"
-"loginSecurity" = "ورود ایمن"
-"loginSecurityDesc" = "یک لایه اضافی از احراز هویت برای ایجاد امنیت بیشتر اضافه می کند"
-"secretToken" = "توکن مخفی"
-"secretTokenDesc" = "لطفاً این توکن را در مکانی امن ذخیره کنید. این توکن برای ورود به سیستم مورد نیاز است و قابل بازیابی نیست"
+"twoFactor" = "احراز هویت دو مرحلهای"
+"twoFactorEnable" = "فعالسازی 2FA"
+"twoFactorEnableDesc" = "یک لایه اضافی امنیتی برای احراز هویت فراهم میکند."
+"twoFactorToken" = "توکن 2FA"
+"twoFactorTokenDesc" = "لطفاً این توکن را در یک برنامه احراز هویت ذخیره کنید."
[pages.settings.toasts]
"modifySettings" = "ویرایش تنظیمات"
diff --git a/web/translation/translate.id_ID.toml b/web/translation/translate.id_ID.toml
index f2277a27..191f6311 100644
--- a/web/translation/translate.id_ID.toml
+++ b/web/translation/translate.id_ID.toml
@@ -51,7 +51,7 @@
"install" = "Instal"
"clients" = "Klien"
"usage" = "Penggunaan"
-"secretToken" = "Token Rahasia"
+"twoFactorCode" = "Kode"
"remained" = "Tersisa"
"security" = "Keamanan"
"secAlertTitle" = "Peringatan keamanan"
@@ -87,7 +87,7 @@
"invalidFormData" = "Format data input tidak valid."
"emptyUsername" = "Nama Pengguna diperlukan"
"emptyPassword" = "Kata Sandi diperlukan"
-"wrongUsernameOrPassword" = "Nama pengguna atau kata sandi tidak valid."
+"wrongUsernameOrPassword" = "Username, kata sandi, atau kode dua faktor tidak valid."
"successLogin" = "Login berhasil"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Kredensial admin"
-"secret" = "Token Rahasia"
-"loginSecurity" = "Login Aman"
-"loginSecurityDesc" = "Menambahkan lapisan otentikasi tambahan untuk memberikan keamanan lebih."
-"secretToken" = "Token Rahasia"
-"secretTokenDesc" = "Simpan token ini dengan aman di tempat yang aman. Token ini diperlukan untuk login dan tidak dapat dipulihkan."
+"twoFactor" = "Autentikasi dua faktor"
+"twoFactorEnable" = "Aktifkan 2FA"
+"twoFactorEnableDesc" = "Menambahkan lapisan autentikasi tambahan untuk keamanan lebih."
+"twoFactorToken" = "Token 2FA"
+"twoFactorTokenDesc" = "Harap simpan token ini dengan aman di aplikasi autentikasi."
[pages.settings.toasts]
"modifySettings" = "Ubah Pengaturan"
diff --git a/web/translation/translate.ja_JP.toml b/web/translation/translate.ja_JP.toml
index 2c8df756..3966ac4b 100644
--- a/web/translation/translate.ja_JP.toml
+++ b/web/translation/translate.ja_JP.toml
@@ -51,7 +51,7 @@
"install" = "インストール"
"clients" = "クライアント"
"usage" = "利用状況"
-"secretToken" = "シークレットトークン"
+"twoFactorCode" = "コード"
"remained" = "残り"
"security" = "セキュリティ"
"secAlertTitle" = "セキュリティアラート"
@@ -87,7 +87,7 @@
"invalidFormData" = "データ形式エラー"
"emptyUsername" = "ユーザー名を入力してください"
"emptyPassword" = "パスワードを入力してください"
-"wrongUsernameOrPassword" = "ユーザー名またはパスワードが間違っています"
+"wrongUsernameOrPassword" = "ユーザー名、パスワード、または二段階認証コードが無効です。"
"successLogin" = "ログイン成功"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "管理者の資格情報"
-"secret" = "セキュリティトークン"
-"loginSecurity" = "ログインセキュリティ"
-"loginSecurityDesc" = "追加の認証を追加してセキュリティを向上させる"
-"secretToken" = "セキュリティトークン"
-"secretTokenDesc" = "このトークンを安全な場所に保管してください。このトークンはログインに使用され、紛失すると回復できません。"
+"twoFactor" = "二段階認証"
+"twoFactorEnable" = "2FAを有効化"
+"twoFactorEnableDesc" = "セキュリティを強化するために追加の認証層を追加します。"
+"twoFactorToken" = "2FAトークン"
+"twoFactorTokenDesc" = "このトークンを認証アプリに安全に保存してください。"
[pages.settings.toasts]
"modifySettings" = "設定を変更"
diff --git a/web/translation/translate.pt_BR.toml b/web/translation/translate.pt_BR.toml
index 87a44ca6..f6c2e88d 100644
--- a/web/translation/translate.pt_BR.toml
+++ b/web/translation/translate.pt_BR.toml
@@ -51,7 +51,7 @@
"install" = "Instalar"
"clients" = "Clientes"
"usage" = "Uso"
-"secretToken" = "Token Secreto"
+"twoFactorCode" = "Código"
"remained" = "Restante"
"security" = "Segurança"
"secAlertTitle" = "Alerta de Segurança"
@@ -87,7 +87,7 @@
"invalidFormData" = "O formato dos dados de entrada é inválido."
"emptyUsername" = "Nome de usuário é obrigatório"
"emptyPassword" = "Senha é obrigatória"
-"wrongUsernameOrPassword" = "Nome de usuário, senha ou segredo inválidos."
+"wrongUsernameOrPassword" = "Nome de usuário, senha ou código de dois fatores inválido."
"successLogin" = "Login realizado com sucesso"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Credenciais de administrador"
-"secret" = "Token Secreto"
-"loginSecurity" = "Login Seguro"
-"loginSecurityDesc" = "Adiciona uma camada extra de autenticação para fornecer mais segurança."
-"secretToken" = "Token Secreto"
-"secretTokenDesc" = "Por favor, armazene este token em um local seguro. Este token é necessário para o login e não pode ser recuperado."
+"twoFactor" = "Autenticação de dois fatores"
+"twoFactorEnable" = "Ativar 2FA"
+"twoFactorEnableDesc" = "Adiciona uma camada extra de autenticação para mais segurança."
+"twoFactorToken" = "Token 2FA"
+"twoFactorTokenDesc" = "Guarde este token com segurança em um aplicativo de autenticação."
[pages.settings.toasts]
"modifySettings" = "Modificar Configurações"
diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml
index 47891227..634d393d 100644
--- a/web/translation/translate.ru_RU.toml
+++ b/web/translation/translate.ru_RU.toml
@@ -51,7 +51,7 @@
"install" = "Установка"
"clients" = "Клиенты"
"usage" = "Использование"
-"secretToken" = "Секретный токен"
+"twoFactorCode" = "Код"
"remained" = "Остаток"
"security" = "Безопасность"
"secAlertTitle" = "Предупреждение системы безопасности"
@@ -87,7 +87,7 @@
"invalidFormData" = "Недопустимый формат данных"
"emptyUsername" = "Введите имя пользователя"
"emptyPassword" = "Введите пароль"
-"wrongUsernameOrPassword" = "Неверное имя пользователя, пароль или секретный токен."
+"wrongUsernameOrPassword" = "Неверное имя пользователя, пароль или код двухфакторной аутентификации."
"successLogin" = "Успешный вход"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Учетные данные администратора"
-"secret" = "Секретный токен"
-"loginSecurity" = "Безопасность входа"
-"loginSecurityDesc" = "Включить дополнительные меры безопасности входа пользователя"
-"secretToken" = "Секретный токен"
-"secretTokenDesc" = "Пожалуйста, скопируйте и сохраните этот токен в безопасном месте. Этот токен необходим для входа в систему и не может быть восстановлен с помощью инструмента x-ui"
+"twoFactor" = "Двухфакторная аутентификация"
+"twoFactorEnable" = "Включить 2FA"
+"twoFactorEnableDesc" = "Добавляет дополнительный уровень аутентификации для повышения безопасности."
+"twoFactorToken" = "Токен 2FA"
+"twoFactorTokenDesc" = "Пожалуйста, сохраните этот токен в приложении для аутентификации."
[pages.settings.toasts]
"modifySettings" = "Настройки изменены"
diff --git a/web/translation/translate.tr_TR.toml b/web/translation/translate.tr_TR.toml
index 2b617ca5..a43b68fb 100644
--- a/web/translation/translate.tr_TR.toml
+++ b/web/translation/translate.tr_TR.toml
@@ -51,7 +51,7 @@
"install" = "Yükle"
"clients" = "Müşteriler"
"usage" = "Kullanım"
-"secretToken" = "Gizli Anahtar"
+"twoFactorCode" = "Kod"
"remained" = "Kalan"
"security" = "Güvenlik"
"secAlertTitle" = "Güvenlik Uyarısı"
@@ -87,7 +87,7 @@
"invalidFormData" = "Girdi verisi formatı geçersiz."
"emptyUsername" = "Kullanıcı adı gerekli"
"emptyPassword" = "Şifre gerekli"
-"wrongUsernameOrPassword" = "Geçersiz kullanıcı adı veya şifre veya gizli anahtar."
+"wrongUsernameOrPassword" = "Geçersiz kullanıcı adı, şifre veya iki adımlı doğrulama kodu."
"successLogin" = "Giriş Başarılı"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Yönetici kimlik bilgileri"
-"secret" = "Gizli Anahtar"
-"loginSecurity" = "Güvenli Giriş"
-"loginSecurityDesc" = "Daha fazla güvenlik sağlamak için ek bir kimlik doğrulama katmanı ekler."
-"secretToken" = "Gizli Anahtar"
-"secretTokenDesc" = "Bu anahtarı güvenli bir yerde saklayın. Bu anahtar giriş için gereklidir ve geri alınamaz."
+"twoFactor" = "İki adımlı doğrulama"
+"twoFactorEnable" = "2FA'yı Etkinleştir"
+"twoFactorEnableDesc" = "Daha fazla güvenlik için ek bir doğrulama katmanı ekler."
+"twoFactorToken" = "2FA Token"
+"twoFactorTokenDesc" = "Lütfen bu token'ı bir doğrulama uygulamasında güvenle saklayın."
[pages.settings.toasts]
"modifySettings" = "Ayarları Değiştir"
diff --git a/web/translation/translate.uk_UA.toml b/web/translation/translate.uk_UA.toml
index ad3aea41..4825ea37 100644
--- a/web/translation/translate.uk_UA.toml
+++ b/web/translation/translate.uk_UA.toml
@@ -51,7 +51,7 @@
"install" = "Встановити"
"clients" = "Клієнти"
"usage" = "Використання"
-"secretToken" = "Секретний маркер"
+"twoFactorCode" = "Код"
"remained" = "Залишилося"
"security" = "Беспека"
"secAlertTitle" = "Попередження системи безпеки"
@@ -87,7 +87,7 @@
"invalidFormData" = "Формат вхідних даних недійсний."
"emptyUsername" = "Потрібне ім'я користувача"
"emptyPassword" = "Потрібен пароль"
-"wrongUsernameOrPassword" = "Невірне ім'я користувача або пароль."
+"wrongUsernameOrPassword" = "Невірне ім’я користувача, пароль або код двофакторної аутентифікації."
"successLogin" = "Вхід"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Облікові дані адміністратора"
-"secret" = "Секретний маркер"
-"loginSecurity" = "Безпечний вхід"
-"loginSecurityDesc" = "Додає додатковий рівень автентифікації для забезпечення більшої безпеки."
-"secretToken" = "Секретний маркер"
-"secretTokenDesc" = "Будь ласка, надійно зберігайте цей маркер у безпечному місці. Цей маркер потрібен для входу, і його неможливо відновити."
+"twoFactor" = "Двофакторна аутентифікація"
+"twoFactorEnable" = "Увімкнути 2FA"
+"twoFactorEnableDesc" = "Додає додатковий рівень аутентифікації для підвищення безпеки."
+"twoFactorToken" = "Токен 2FA"
+"twoFactorTokenDesc" = "Будь ласка, збережіть цей токен у захищеному додатку для аутентифікації."
[pages.settings.toasts]
"modifySettings" = "Змінити налаштування"
diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml
index 3a825770..ef10ddc7 100644
--- a/web/translation/translate.vi_VN.toml
+++ b/web/translation/translate.vi_VN.toml
@@ -51,7 +51,7 @@
"install" = "Cài đặt"
"clients" = "Các khách hàng"
"usage" = "Sử dụng"
-"secretToken" = "Mã bí mật"
+"twoFactorCode" = "Mã"
"remained" = "Còn lại"
"security" = "Bảo vệ"
"secAlertTitle" = "Cảnh báo an ninh-Tiếng Việt by Ohoang7"
@@ -87,7 +87,7 @@
"invalidFormData" = "Dạng dữ liệu nhập không hợp lệ."
"emptyUsername" = "Vui lòng nhập tên người dùng."
"emptyPassword" = "Vui lòng nhập mật khẩu."
-"wrongUsernameOrPassword" = "Tên người dùng hoặc mật khẩu không đúng."
+"wrongUsernameOrPassword" = "Tên người dùng, mật khẩu hoặc mã xác thực hai yếu tố không hợp lệ."
"successLogin" = "Đăng nhập thành công."
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "Thông tin đăng nhập quản trị viên"
-"secret" = "Mã thông báo bí mật"
-"loginSecurity" = "Bảo mật đăng nhập"
-"loginSecurityDesc" = "Bật bước bảo mật đăng nhập bổ sung cho người dùng"
-"secretToken" = "Mã bí mật"
-"secretTokenDesc" = "Vui lòng sao chép và lưu trữ mã này một cách an toàn ở nơi an toàn. Mã này cần thiết để đăng nhập và không thể phục hồi từ công cụ lệnh x-ui."
+"twoFactor" = "Xác thực hai yếu tố"
+"twoFactorEnable" = "Bật 2FA"
+"twoFactorEnableDesc" = "Thêm một lớp bảo mật bổ sung để tăng cường an toàn."
+"twoFactorToken" = "Token 2FA"
+"twoFactorTokenDesc" = "Vui lòng lưu token này vào ứng dụng xác thực một cách an toàn."
[pages.settings.toasts]
"modifySettings" = "Chỉnh sửa cài đặt "
diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml
index 750db7e6..3769d89a 100644
--- a/web/translation/translate.zh_CN.toml
+++ b/web/translation/translate.zh_CN.toml
@@ -51,7 +51,7 @@
"install" = "安装"
"clients" = "客户端"
"usage" = "使用情况"
-"secretToken" = "安全密钥"
+"twoFactorCode" = "代码"
"remained" = "剩余"
"security" = "安全"
"secAlertTitle" = "安全警报"
@@ -87,7 +87,7 @@
"invalidFormData" = "数据格式错误"
"emptyUsername" = "请输入用户名"
"emptyPassword" = "请输入密码"
-"wrongUsernameOrPassword" = "用户名或密码错误"
+"wrongUsernameOrPassword" = "用户名、密码或双重验证码无效。"
"successLogin" = "登录"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "管理员凭据"
-"secret" = "安全令牌"
-"loginSecurity" = "登录安全"
-"loginSecurityDesc" = "添加额外的身份验证以提高安全性"
-"secretToken" = "安全令牌"
-"secretTokenDesc" = "请将此令牌存储在安全的地方。此令牌用于登录,丢失无法恢复。"
+"twoFactor" = "双重验证"
+"twoFactorEnable" = "启用2FA"
+"twoFactorEnableDesc" = "增加额外的验证层以提高安全性。"
+"twoFactorToken" = "2FA令牌"
+"twoFactorTokenDesc" = "请将此令牌安全地保存在验证应用中。"
[pages.settings.toasts]
"modifySettings" = "修改设置"
diff --git a/web/translation/translate.zh_TW.toml b/web/translation/translate.zh_TW.toml
index abc953f5..8dfc13a5 100644
--- a/web/translation/translate.zh_TW.toml
+++ b/web/translation/translate.zh_TW.toml
@@ -51,7 +51,7 @@
"install" = "安裝"
"clients" = "客戶端"
"usage" = "使用情況"
-"secretToken" = "安全金鑰"
+"twoFactorCode" = "代碼"
"remained" = "剩餘"
"security" = "安全"
"secAlertTitle" = "安全警報"
@@ -87,7 +87,7 @@
"invalidFormData" = "資料格式錯誤"
"emptyUsername" = "請輸入使用者名稱"
"emptyPassword" = "請輸入密碼"
-"wrongUsernameOrPassword" = "使用者名稱或密碼錯誤"
+"wrongUsernameOrPassword" = "用戶名、密碼或雙重驗證碼無效。"
"successLogin" = "登入"
[pages.index]
@@ -499,11 +499,11 @@
[pages.settings.security]
"admin" = "管理員憑證"
-"secret" = "安全令牌"
-"loginSecurity" = "登入安全"
-"loginSecurityDesc" = "新增額外的身份驗證以提高安全性"
-"secretToken" = "安全令牌"
-"secretTokenDesc" = "請將此令牌儲存在安全的地方。此令牌用於登入,丟失無法恢復。"
+"twoFactor" = "雙重驗證"
+"twoFactorEnable" = "啟用2FA"
+"twoFactorEnableDesc" = "增加額外的驗證層以提高安全性。"
+"twoFactorToken" = "2FA令牌"
+"twoFactorTokenDesc" = "請將此令牌安全地保存在驗證應用中。"
[pages.settings.toasts]
"modifySettings" = "修改設定"
diff --git a/x-ui.sh b/x-ui.sh
index c8df6735..a7cee914 100644
--- a/x-ui.sh
+++ b/x-ui.sh
@@ -184,10 +184,8 @@ reset_user() {
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
}
@@ -1731,7 +1729,7 @@ show_menu() {
│ ${green}4.${plain} Legacy Version │
│ ${green}5.${plain} Uninstall │
│────────────────────────────────────────────────│
-│ ${green}6.${plain} Reset Username & Password & Secret Token │
+│ ${green}6.${plain} Reset Username & Password │
│ ${green}7.${plain} Reset Web Base Path │
│ ${green}8.${plain} Reset Settings │
│ ${green}9.${plain} Change Port │