mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-12 05:00:05 +00:00
parent
3d54e33051
commit
2c53007580
29 changed files with 193 additions and 290 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
1
go.mod
1
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
|
||||
|
|
2
go.sum
2
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=
|
||||
|
|
35
main.go
35
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)
|
||||
}
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -512,11 +512,11 @@
|
|||
<a-icon slot="prefix" type="lock" :style="{ fontSize: '1rem' }"></a-icon>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="secretEnable">
|
||||
<a-input-password autocomplete="secret" name="secret" v-model.trim="user.loginSecret"
|
||||
placeholder='{{ i18n "secretToken" }}' @keydown.enter.native="login">
|
||||
<a-form-item v-if="twoFactorEnable">
|
||||
<a-input autocomplete="totp" name="twoFactorCode" v-model.trim="user.twoFactorCode"
|
||||
placeholder='{{ i18n "twoFactorCode" }}' @keydown.enter.native="login">
|
||||
<a-icon slot="prefix" type="key" :style="{ fontSize: '1rem' }"></a-icon>
|
||||
</a-input-password>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-row justify="center" class="centered">
|
||||
|
@ -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;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -31,30 +31,23 @@
|
|||
</a-space>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel key="2" header='{{ i18n "pages.settings.security.secret"}}'>
|
||||
<a-collapse-panel key="2" header='{{ i18n "pages.settings.security.twoFactor" }}'>
|
||||
<a-setting-list-item paddings="small">
|
||||
<template #title>{{ i18n "pages.settings.security.loginSecurity" }}</template>
|
||||
<template #description>{{ i18n "pages.settings.security.loginSecurityDesc" }}</template>
|
||||
<template #title>{{ i18n "pages.settings.security.twoFactorEnable" }}</template>
|
||||
<template #description>{{ i18n "pages.settings.security.twoFactorEnableDesc" }}</template>
|
||||
<template #control>
|
||||
<a-switch @change="toggleToken(allSetting.secretEnable)" v-model="allSetting.secretEnable"></a-switch>
|
||||
<a-icon :style="{ marginLeft: '1rem' }" v-if="allSetting.secretEnable" :spin="this.changeSecret" type="sync"
|
||||
@click="getNewSecret"></a-icon>
|
||||
<a-switch @change="toggleTwoFactor" v-model="allSetting.twoFactorEnable"></a-switch>
|
||||
</template>
|
||||
</a-setting-list-item>
|
||||
<a-setting-list-item paddings="small">
|
||||
<template #title>{{ i18n "pages.settings.security.secretToken" }}</template>
|
||||
<template #description>{{ i18n "pages.settings.security.secretTokenDesc" }}</template>
|
||||
<a-setting-list-item paddings="small" v-if="allSetting.twoFactorEnable">
|
||||
<template #title>{{ i18n "pages.settings.security.twoFactorToken" }}</template>
|
||||
<template #description>{{ i18n "pages.settings.security.twoFactorTokenDesc" }}</template>
|
||||
<template #control>
|
||||
<a-textarea type="text" :disabled="!allSetting.secretEnable" v-model="user.loginSecret"></a-textarea>
|
||||
<a-input disabled="disabled" v-model="allSetting.twoFactorToken" :style="{ cursor: 'text' }">
|
||||
<a-icon slot="addonAfter" type="copy" @click="ClipboardManager.copyText(allSetting.twoFactorToken)"/>
|
||||
</a-input>
|
||||
</template>
|
||||
</a-setting-list-item>
|
||||
<a-list-item>
|
||||
<a-space direction="horizontal" :style="{ padding: '0 20px' }">
|
||||
<a-button type="primary" :loading="this.changeSecret" @click="updateSecret">
|
||||
<span>{{ i18n "confirm"}}</span>
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
{{end}}
|
|
@ -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"] {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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" = "تعديل الإعدادات"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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" = "ویرایش تنظیمات"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" = "設定を変更"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" = "Настройки изменены"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" = "Змінити налаштування"
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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" = "修改设置"
|
||||
|
|
|
@ -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" = "修改設定"
|
||||
|
|
4
x-ui.sh
4
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 │
|
||||
|
|
Loading…
Reference in a new issue