소스 검색

Merge pull request #439 from 0xJacky/enhance/login

Enhance/login
Jacky 9 달 전
부모
커밋
fb2ea7ec7d
63개의 변경된 파일3318개의 추가작업 그리고 2271개의 파일을 삭제
  1. 45 0
      api/settings/auth.go
  2. 14 0
      api/settings/router.go
  3. 4 1
      api/settings/settings.go
  4. 7 11
      api/system/router.go
  5. 65 18
      api/user/auth.go
  6. 3 3
      api/user/casdoor.go
  7. 0 1
      app/.eslintrc.cjs
  8. 16 16
      app/package.json
  9. 226 224
      app/pnpm-lock.yaml
  10. 2 2
      app/src/api/curd.ts
  11. 15 5
      app/src/api/settings.ts
  12. 1 1
      app/src/language/LINGUAS
  13. 163 98
      app/src/language/en/app.po
  14. 165 98
      app/src/language/es/app.po
  15. 165 98
      app/src/language/fr_FR/app.po
  16. 165 98
      app/src/language/ko_KR/app.po
  17. 164 103
      app/src/language/messages.pot
  18. 165 98
      app/src/language/ru_RU/app.po
  19. 165 98
      app/src/language/vi_VN/app.po
  20. BIN
      app/src/language/zh_CN/app.mo
  21. 163 98
      app/src/language/zh_CN/app.po
  22. 165 98
      app/src/language/zh_TW/app.po
  23. 1 1
      app/src/version.json
  24. 0 4
      app/src/views/domain/DomainAdd.vue
  25. 0 2
      app/src/views/domain/DomainEdit.vue
  26. 1 4
      app/src/views/domain/components/Deploy.vue
  27. 2 6
      app/src/views/domain/components/SiteDuplicate.vue
  28. 1 2
      app/src/views/other/Install.vue
  29. 15 3
      app/src/views/other/Login.vue
  30. 114 0
      app/src/views/preference/AuthSettings.vue
  31. 16 1
      app/src/views/preference/Preference.vue
  32. 5 0
      app/src/views/preference/typedef.ts
  33. 0 2
      app/src/views/stream/StreamEdit.vue
  34. 1 4
      app/src/views/stream/components/Deploy.vue
  35. 2 6
      app/src/views/stream/components/StreamDuplicate.vue
  36. 1 1
      app/version.json
  37. 86 0
      app/vite.config.ts.timestamp-1721542436572-91822f5b8889d.mjs
  38. 2 1
      docs/.vitepress/config/en.ts
  39. 2 1
      docs/.vitepress/config/zh_CN.ts
  40. 2 1
      docs/.vitepress/config/zh_TW.ts
  41. 30 0
      docs/guide/config-auth.md
  42. 6 0
      docs/guide/env.md
  43. 3 3
      docs/package.json
  44. 286 749
      docs/pnpm-lock.yaml
  45. 30 0
      docs/zh_CN/guide/config-auth.md
  46. 7 1
      docs/zh_CN/guide/env.md
  47. 29 0
      docs/zh_TW/guide/config-auth.md
  48. 7 1
      docs/zh_TW/guide/env.md
  49. 81 81
      go.mod
  50. 170 168
      go.sum
  51. 47 0
      internal/user/login.go
  52. 57 0
      internal/user/user.go
  53. 5 55
      model/auth.go
  54. 7 0
      model/ban_ip.go
  55. 1 0
      model/model.go
  56. 5 1
      query/auths.gen.go
  57. 358 0
      query/ban_ips.gen.go
  58. 8 0
      query/gen.go
  59. 25 0
      router/ip.go
  60. 2 2
      router/middleware.go
  61. 3 2
      router/routers.go
  62. 12 0
      settings/auth.go
  63. 10 0
      settings/settings.go

+ 45 - 0
api/settings/auth.go

@@ -0,0 +1,45 @@
+package settings
+
+import (
+	"github.com/0xJacky/Nginx-UI/api"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"time"
+)
+
+func GetBanLoginIP(c *gin.Context) {
+	b := query.BanIP
+
+	// clear expired banned IPs
+	_, _ = b.Where(b.ExpiredAt.Lte(time.Now().Unix())).Delete()
+
+	banIps, err := b.Where(
+		b.ExpiredAt.Gte(time.Now().Unix()),
+		b.Attempts.Gte(settings.AuthSettings.MaxAttempts)).Find()
+	if err != nil {
+		api.ErrHandler(c, err)
+		return
+	}
+	c.JSON(http.StatusOK, banIps)
+}
+
+func RemoveBannedIP(c *gin.Context) {
+	var json struct {
+		IP string `json:"ip"`
+	}
+	if !api.BindAndValid(c, &json) {
+		return
+	}
+
+	b := query.BanIP
+	_, err := b.Where(b.IP.Eq(json.IP)).Delete()
+
+	if err != nil {
+		api.ErrHandler(c, err)
+		return
+	}
+
+	c.JSON(http.StatusNoContent, nil)
+}

+ 14 - 0
api/settings/router.go

@@ -0,0 +1,14 @@
+package settings
+
+import (
+	"github.com/gin-gonic/gin"
+)
+
+func InitRouter(r *gin.RouterGroup) {
+	r.GET("settings/server/name", GetServerName)
+	r.GET("settings", GetSettings)
+	r.POST("settings", SaveSettings)
+
+	r.GET("settings/auth/banned_ips", GetBanLoginIP)
+	r.DELETE("settings/auth/banned_ip", RemoveBannedIP)
+}

+ 4 - 1
api/system/settings.go → api/settings/settings.go

@@ -1,4 +1,4 @@
-package system
+package settings
 
 
 import (
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/api"
@@ -20,6 +20,7 @@ func GetSettings(c *gin.Context) {
 		"nginx":     settings.NginxSettings,
 		"nginx":     settings.NginxSettings,
 		"openai":    settings.OpenAISettings,
 		"openai":    settings.OpenAISettings,
 		"logrotate": settings.LogrotateSettings,
 		"logrotate": settings.LogrotateSettings,
+		"auth":      settings.AuthSettings,
 	})
 	})
 }
 }
 
 
@@ -29,6 +30,7 @@ func SaveSettings(c *gin.Context) {
 		Nginx     settings.Nginx     `json:"nginx"`
 		Nginx     settings.Nginx     `json:"nginx"`
 		Openai    settings.OpenAI    `json:"openai"`
 		Openai    settings.OpenAI    `json:"openai"`
 		Logrotate settings.Logrotate `json:"logrotate"`
 		Logrotate settings.Logrotate `json:"logrotate"`
+		Auth      settings.Auth      `json:"auth"`
 	}
 	}
 
 
 	if !api.BindAndValid(c, &json) {
 	if !api.BindAndValid(c, &json) {
@@ -44,6 +46,7 @@ func SaveSettings(c *gin.Context) {
 	settings.ProtectedFill(&settings.NginxSettings, &json.Nginx)
 	settings.ProtectedFill(&settings.NginxSettings, &json.Nginx)
 	settings.ProtectedFill(&settings.OpenAISettings, &json.Openai)
 	settings.ProtectedFill(&settings.OpenAISettings, &json.Openai)
 	settings.ProtectedFill(&settings.LogrotateSettings, &json.Logrotate)
 	settings.ProtectedFill(&settings.LogrotateSettings, &json.Logrotate)
+	settings.ProtectedFill(&settings.AuthSettings, &json.Auth)
 
 
 	err := settings.Save()
 	err := settings.Save()
 	if err != nil {
 	if err != nil {

+ 7 - 11
api/system/router.go

@@ -1,21 +1,17 @@
 package system
 package system
 
 
 import (
 import (
-    "github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin"
 )
 )
 
 
 func InitPublicRouter(r *gin.RouterGroup) {
 func InitPublicRouter(r *gin.RouterGroup) {
-    r.GET("install", InstallLockCheck)
-    r.POST("install", InstallNginxUI)
-    r.GET("translation/:code", GetTranslation)
+	r.GET("install", InstallLockCheck)
+	r.POST("install", InstallNginxUI)
+	r.GET("translation/:code", GetTranslation)
 }
 }
 
 
 func InitPrivateRouter(r *gin.RouterGroup) {
 func InitPrivateRouter(r *gin.RouterGroup) {
-    r.GET("settings/server/name", GetServerName)
-    r.GET("settings", GetSettings)
-    r.POST("settings", SaveSettings)
-
-    r.GET("upgrade/release", GetRelease)
-    r.GET("upgrade/current", GetCurrentVersion)
-    r.GET("upgrade/perform", PerformCoreUpgrade)
+	r.GET("upgrade/release", GetRelease)
+	r.GET("upgrade/current", GetCurrentVersion)
+	r.GET("upgrade/perform", PerformCoreUpgrade)
 }
 }

+ 65 - 18
api/user/auth.go

@@ -2,45 +2,92 @@ package user
 
 
 import (
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/0xJacky/Nginx-UI/internal/user"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
 	"net/http"
 	"net/http"
+	"sync"
 	"time"
 	"time"
-
-	"github.com/gin-gonic/gin"
-	"golang.org/x/crypto/bcrypt"
 )
 )
 
 
+var mutex = &sync.Mutex{}
+
 type LoginUser struct {
 type LoginUser struct {
 	Name     string `json:"name" binding:"required,max=255"`
 	Name     string `json:"name" binding:"required,max=255"`
 	Password string `json:"password" binding:"required,max=255"`
 	Password string `json:"password" binding:"required,max=255"`
 }
 }
 
 
+const (
+	ErrPasswordIncorrect = 4031
+	ErrMaxAttempts       = 4291
+	ErrUserBanned        = 4033
+)
+
 type LoginResponse struct {
 type LoginResponse struct {
 	Message string `json:"message"`
 	Message string `json:"message"`
-	Token   string `json:"token"`
+	Error   string `json:"error,omitempty"`
+	Code    int    `json:"code"`
+	Token   string `json:"token,omitempty"`
 }
 }
 
 
 func Login(c *gin.Context) {
 func Login(c *gin.Context) {
-	var user LoginUser
-	ok := api.BindAndValid(c, &user)
-	if !ok {
+	// make sure that only one request is processed at a time
+	mutex.Lock()
+	defer mutex.Unlock()
+	// check if the ip is banned
+	clientIP := c.ClientIP()
+	b := query.BanIP
+	banIP, _ := b.Where(b.IP.Eq(clientIP),
+		b.ExpiredAt.Gte(time.Now().Unix()),
+		b.Attempts.Gte(settings.AuthSettings.MaxAttempts),
+	).Count()
+
+	if banIP > 0 {
+		c.JSON(http.StatusTooManyRequests, LoginResponse{
+			Message: "Max attempts",
+			Code:    ErrMaxAttempts,
+		})
 		return
 		return
 	}
 	}
 
 
-	u, _ := model.GetUser(user.Name)
+	var json LoginUser
+	ok := api.BindAndValid(c, &json)
+	if !ok {
+		return
+	}
 
 
-	if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(user.Password)); err != nil {
-		time.Sleep(5 * time.Second)
-		c.JSON(http.StatusForbidden, gin.H{
-			"message": "The username or password is incorrect",
-		})
+	u, err := user.Login(json.Name, json.Password)
+	if err != nil {
+		// time.Sleep(5 * time.Second)
+		switch {
+		case errors.Is(err, user.ErrPasswordIncorrect):
+			c.JSON(http.StatusForbidden, LoginResponse{
+				Message: "Password incorrect",
+				Code:    ErrPasswordIncorrect,
+			})
+		case errors.Is(err, user.ErrUserBanned):
+			c.JSON(http.StatusForbidden, LoginResponse{
+				Message: "The user is banned",
+				Code:    ErrUserBanned,
+			})
+		default:
+			api.ErrHandler(c, err)
+		}
+		user.BanIP(clientIP)
 		return
 		return
 	}
 	}
 
 
-	token, err := model.GenerateJWT(u.Name)
+	// login success, clear banned record
+	_, _ = b.Where(b.IP.Eq(clientIP)).Delete()
+
+	logger.Info("[User Login]", u.Name)
+	token, err := user.GenerateJWT(u.Name)
 	if err != nil {
 	if err != nil {
-		c.JSON(http.StatusInternalServerError, gin.H{
-			"message": err.Error(),
+		c.JSON(http.StatusInternalServerError, LoginResponse{
+			Message: err.Error(),
 		})
 		})
 		return
 		return
 	}
 	}
@@ -54,7 +101,7 @@ func Login(c *gin.Context) {
 func Logout(c *gin.Context) {
 func Logout(c *gin.Context) {
 	token := c.GetHeader("Authorization")
 	token := c.GetHeader("Authorization")
 	if token != "" {
 	if token != "" {
-		err := model.DeleteToken(token)
+		err := user.DeleteToken(token)
 		if err != nil {
 		if err != nil {
 			c.JSON(http.StatusInternalServerError, gin.H{
 			c.JSON(http.StatusInternalServerError, gin.H{
 				"message": err.Error(),
 				"message": err.Error(),

+ 3 - 3
api/user/casdoor.go

@@ -3,7 +3,7 @@ package user
 import (
 import (
 	"fmt"
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/internal/user"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
 	"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
@@ -53,7 +53,7 @@ func CasdoorCallback(c *gin.Context) {
 		return
 		return
 	}
 	}
 
 
-	u, err := model.GetUser(claims.Name)
+	u, err := user.GetUser(claims.Name)
 	if err != nil {
 	if err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			c.JSON(http.StatusForbidden, gin.H{
 			c.JSON(http.StatusForbidden, gin.H{
@@ -65,7 +65,7 @@ func CasdoorCallback(c *gin.Context) {
 		return
 		return
 	}
 	}
 
 
-	userToken, err := model.GenerateJWT(u.Name)
+	userToken, err := user.GenerateJWT(u.Name)
 	if err != nil {
 	if err != nil {
 		api.ErrHandler(c, err)
 		api.ErrHandler(c, err)
 		return
 		return

+ 0 - 1
app/.eslintrc.cjs

@@ -8,7 +8,6 @@ module.exports = {
     'plugin:vue/vue3-recommended',
     'plugin:vue/vue3-recommended',
     'plugin:import/recommended',
     'plugin:import/recommended',
     'plugin:import/typescript',
     'plugin:import/typescript',
-    'plugin:promise/recommended',
     'plugin:sonarjs/recommended',
     'plugin:sonarjs/recommended',
     'plugin:@typescript-eslint/recommended',
     'plugin:@typescript-eslint/recommended',
 
 

+ 16 - 16
app/package.json

@@ -3,7 +3,7 @@
   "version": "2.0.0-beta.25",
   "version": "2.0.0-beta.25",
   "type": "module",
   "type": "module",
   "scripts": {
   "scripts": {
-    "dev": "vite",
+    "dev": "vite --host",
     "typecheck": "vue-tsc --noEmit",
     "typecheck": "vue-tsc --noEmit",
     "lint": "eslint . -c .eslintrc.cjs --fix --ext .ts,.vue,.tsx,.d.ts",
     "lint": "eslint . -c .eslintrc.cjs --fix --ext .ts,.vue,.tsx,.d.ts",
     "build": "vite build",
     "build": "vite build",
@@ -13,17 +13,17 @@
   "dependencies": {
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
     "@ant-design/icons-vue": "^7.0.1",
     "@formkit/auto-animate": "^0.8.2",
     "@formkit/auto-animate": "^0.8.2",
-    "@vue/reactivity": "^3.4.29",
-    "@vue/shared": "^3.4.29",
+    "@vue/reactivity": "^3.4.33",
+    "@vue/shared": "^3.4.33",
     "@vueuse/core": "^10.11.0",
     "@vueuse/core": "^10.11.0",
     "@xterm/addon-attach": "^0.11.0",
     "@xterm/addon-attach": "^0.11.0",
     "@xterm/addon-fit": "^0.10.0",
     "@xterm/addon-fit": "^0.10.0",
     "@xterm/xterm": "^5.5.0",
     "@xterm/xterm": "^5.5.0",
     "ant-design-vue": "^4.2.3",
     "ant-design-vue": "^4.2.3",
-    "apexcharts": "^3.49.1",
+    "apexcharts": "^3.50.0",
     "axios": "^1.7.2",
     "axios": "^1.7.2",
-    "dayjs": "^1.11.11",
-    "highlight.js": "^11.9.0",
+    "dayjs": "^1.11.12",
+    "highlight.js": "^11.10.0",
     "lodash": "^4.17.21",
     "lodash": "^4.17.21",
     "marked": "^10.0.0",
     "marked": "^10.0.0",
     "nprogress": "^0.2.0",
     "nprogress": "^0.2.0",
@@ -32,9 +32,9 @@
     "reconnecting-websocket": "^4.4.0",
     "reconnecting-websocket": "^4.4.0",
     "sortablejs": "^1.15.2",
     "sortablejs": "^1.15.2",
     "vite-plugin-build-id": "^0.2.9",
     "vite-plugin-build-id": "^0.2.9",
-    "vue": "^3.4.29",
+    "vue": "^3.4.33",
     "vue-github-button": "github:0xJacky/vue-github-button",
     "vue-github-button": "github:0xJacky/vue-github-button",
-    "vue-router": "^4.3.3",
+    "vue-router": "^4.4.0",
     "vue3-ace-editor": "2.2.4",
     "vue3-ace-editor": "2.2.4",
     "vue3-apexcharts": "1.4.4",
     "vue3-apexcharts": "1.4.4",
     "vue3-gettext": "3.0.0-beta.4",
     "vue3-gettext": "3.0.0-beta.4",
@@ -42,16 +42,16 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@antfu/eslint-config-vue": "^0.43.1",
     "@antfu/eslint-config-vue": "^0.43.1",
-    "@types/lodash": "^4.17.5",
+    "@types/lodash": "^4.17.7",
     "@types/nprogress": "^0.2.3",
     "@types/nprogress": "^0.2.3",
     "@types/sortablejs": "^1.15.8",
     "@types/sortablejs": "^1.15.8",
     "@typescript-eslint/eslint-plugin": "^6.21.0",
     "@typescript-eslint/eslint-plugin": "^6.21.0",
     "@typescript-eslint/parser": "^6.21.0",
     "@typescript-eslint/parser": "^6.21.0",
     "@vitejs/plugin-vue": "^5.0.5",
     "@vitejs/plugin-vue": "^5.0.5",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
-    "@vue/compiler-sfc": "^3.4.29",
+    "@vue/compiler-sfc": "^3.4.33",
     "@vue/tsconfig": "^0.5.1",
     "@vue/tsconfig": "^0.5.1",
-    "ace-builds": "^1.35.0",
+    "ace-builds": "^1.35.3",
     "autoprefixer": "^10.4.19",
     "autoprefixer": "^10.4.19",
     "eslint": "^8.57.0",
     "eslint": "^8.57.0",
     "eslint-import-resolver-alias": "^1.1.2",
     "eslint-import-resolver-alias": "^1.1.2",
@@ -59,15 +59,15 @@
     "eslint-plugin-import": "^2.29.1",
     "eslint-plugin-import": "^2.29.1",
     "eslint-plugin-regex": "^1.10.0",
     "eslint-plugin-regex": "^1.10.0",
     "eslint-plugin-sonarjs": "^0.23.0",
     "eslint-plugin-sonarjs": "^0.23.0",
-    "eslint-plugin-vue": "^9.26.0",
+    "eslint-plugin-vue": "^9.27.0",
     "less": "^4.2.0",
     "less": "^4.2.0",
-    "postcss": "^8.4.38",
-    "tailwindcss": "^3.4.4",
+    "postcss": "^8.4.39",
+    "tailwindcss": "^3.4.6",
     "typescript": "5.3.3",
     "typescript": "5.3.3",
-    "unplugin-auto-import": "^0.17.6",
+    "unplugin-auto-import": "^0.17.8",
     "unplugin-vue-components": "^0.26.0",
     "unplugin-vue-components": "^0.26.0",
     "unplugin-vue-define-options": "^1.4.5",
     "unplugin-vue-define-options": "^1.4.5",
-    "vite": "^5.3.1",
+    "vite": "^5.3.4",
     "vite-svg-loader": "^5.1.0",
     "vite-svg-loader": "^5.1.0",
     "vue-tsc": "^1.8.27"
     "vue-tsc": "^1.8.27"
   },
   },

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 226 - 224
app/pnpm-lock.yaml


+ 2 - 2
app/src/api/curd.ts

@@ -13,7 +13,7 @@ export interface Pagination {
   total_pages: number
   total_pages: number
 }
 }
 
 
-export interface IGetListResponse<T> {
+export interface GetListResponse<T> {
   data: T[]
   data: T[]
   pagination: Pagination
   pagination: Pagination
 }
 }
@@ -35,7 +35,7 @@ class Curd<T> {
   }
   }
 
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  _get_list(params: any = null): Promise<IGetListResponse<T>> {
+  _get_list(params: any = null): Promise<GetListResponse<T>> {
     return http.get(this.plural, { params })
     return http.get(this.plural, { params })
   }
   }
 
 

+ 15 - 5
app/src/api/settings.ts

@@ -1,17 +1,27 @@
 import http from '@/lib/http'
 import http from '@/lib/http'
 
 
+export interface BannedIP {
+  ip: string
+  attempts: number
+  expired_at: string
+}
+
 const settings = {
 const settings = {
-  get() {
+  get<T>(): Promise<T> {
     return http.get('/settings')
     return http.get('/settings')
   },
   },
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  save(data: any) {
+  save<T>(data: T) {
     return http.post('/settings', data)
     return http.post('/settings', data)
   },
   },
-
-  get_server_name() {
+  get_server_name(): Promise<{ name: string }> {
     return http.get('/settings/server/name')
     return http.get('/settings/server/name')
   },
   },
+  get_banned_ips(): Promise<BannedIP[]> {
+    return http.get('/settings/auth/banned_ips')
+  },
+  remove_banned_ip(ip: string) {
+    return http.delete('/settings/auth/banned_ip', { data: { ip } })
+  },
 }
 }
 
 
 export default settings
 export default settings

+ 1 - 1
app/src/language/LINGUAS

@@ -1 +1 @@
-es fr_FR ko_KR ru_RU vi_VN zh_CN zh_TW
+en zh_CN zh_TW fr_FR es ru_RU vi_VN ko_KR

+ 163 - 98
app/src/language/en/app.po

@@ -28,7 +28,8 @@ msgstr "Username"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "Action"
 msgstr "Action"
 
 
@@ -51,7 +52,7 @@ msgstr "Add Directive Below"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "Add Location"
 msgstr "Add Location"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "Add Site"
 msgstr "Add Site"
 
 
@@ -70,11 +71,11 @@ msgstr "Saved successfully"
 msgid "Additional"
 msgid "Additional"
 msgstr "Add Location"
 msgstr "Add Location"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Advance Mode"
 msgstr "Advance Mode"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +83,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -94,7 +95,12 @@ msgstr ""
 msgid "Arch"
 msgid "Arch"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "Are you sure you want to remove this directive?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
@@ -147,6 +153,14 @@ msgstr ""
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+msgid "Auth"
+msgstr ""
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -170,8 +184,8 @@ msgstr "Auto-renewal enabled for %{name}"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "Back"
 msgstr "Back"
 
 
@@ -180,19 +194,31 @@ msgstr "Back"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "Back"
 msgstr "Back"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "Base information"
 msgstr "Base information"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
 msgstr "Basic Mode"
 msgstr "Basic Mode"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "Basic Mode"
 msgstr "Basic Mode"
 
 
@@ -280,12 +306,12 @@ msgid "Cleaning environment variables"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 #, fuzzy
 #, fuzzy
 msgid "Cleared successfully"
 msgid "Cleared successfully"
@@ -312,7 +338,7 @@ msgstr "Configurations"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "Configuration Name"
 msgstr "Configuration Name"
 
 
@@ -320,7 +346,7 @@ msgstr "Configuration Name"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "Configurations"
 msgstr "Configurations"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configure SSL"
 msgstr "Configure SSL"
 
 
@@ -351,7 +377,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "Created at"
 msgstr "Created at"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "Create Another"
 msgstr "Create Another"
 
 
@@ -390,7 +416,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Dashboard"
 msgstr "Dashboard"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "Database (Optional, default: database)"
 msgstr "Database (Optional, default: database)"
 
 
@@ -423,15 +449,15 @@ msgstr ""
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "Disabled successfully"
 msgstr "Disabled successfully"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
@@ -481,9 +507,9 @@ msgstr "Disabled"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Disable auto-renewal failed for %{name}"
 msgstr "Disable auto-renewal failed for %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Disabled"
 msgstr "Disabled"
 
 
@@ -562,7 +588,7 @@ msgstr "Are you sure you want to remove this directive?"
 msgid "Domain"
 msgid "Domain"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "Domain Config Created Successfully"
 msgstr "Domain Config Created Successfully"
 
 
@@ -582,38 +608,38 @@ msgstr ""
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 #, fuzzy
 #, fuzzy
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "Enable failed"
 msgstr "Enable failed"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 #, fuzzy
 #, fuzzy
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 #, fuzzy
 #, fuzzy
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Edit %{n}"
 msgstr "Edit %{n}"
 
 
@@ -635,25 +661,25 @@ msgstr "Edit Site"
 msgid "Email"
 msgid "Email"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 #, fuzzy
 #, fuzzy
 msgid "Enable"
 msgid "Enable"
 msgstr "Enabled"
 msgstr "Enabled"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr ""
 msgstr ""
 
 
@@ -661,12 +687,12 @@ msgstr ""
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "Enable auto-renewal failed for %{name}"
 msgstr "Enable auto-renewal failed for %{name}"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "Enable failed"
 msgstr "Enable failed"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 #, fuzzy
 #, fuzzy
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "Enabled successfully"
 msgstr "Enabled successfully"
@@ -677,19 +703,19 @@ msgstr "Enable TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "Enabled"
 msgstr "Enabled"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "Enabled successfully"
 msgstr "Enabled successfully"
@@ -759,7 +785,7 @@ msgstr "Failed to enable %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 msgstr ""
 
 
@@ -785,7 +811,7 @@ msgstr "File Not Found"
 msgid "Filter"
 msgid "Filter"
 msgstr ""
 msgstr ""
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "Finished"
 msgstr "Finished"
 
 
@@ -857,6 +883,12 @@ msgstr ""
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 msgid "Import"
 msgid "Import"
 msgstr ""
 msgstr ""
@@ -866,6 +898,10 @@ msgstr ""
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
+#: src/views/other/Login.vue:59
+msgid "Incorrect username or password"
+msgstr ""
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr ""
 msgstr ""
@@ -878,7 +914,7 @@ msgstr ""
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "Install"
 msgstr "Install"
 
 
@@ -900,6 +936,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr "Invalid E-mail!"
 msgstr "Invalid E-mail!"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -933,7 +973,7 @@ msgstr ""
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Leave blank for no change"
 msgstr "Leave blank for no change"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 msgstr ""
 
 
@@ -990,11 +1030,11 @@ msgstr "Locations"
 msgid "Log"
 msgid "Log"
 msgstr "Login"
 msgstr "Login"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "Login"
 msgstr "Login"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "Login successful"
 msgstr "Login successful"
 
 
@@ -1002,7 +1042,7 @@ msgstr "Login successful"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Logout successful"
 msgstr "Logout successful"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1047,6 +1087,10 @@ msgstr "Manage Users"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1060,7 +1104,7 @@ msgstr "Memory and Storage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Advance Mode"
 msgstr "Advance Mode"
@@ -1077,7 +1121,7 @@ msgstr "Modify Config"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "Modify Config"
 msgstr "Modify Config"
 
 
@@ -1097,12 +1141,12 @@ msgstr "Single Directive"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "Name"
 msgstr "Name"
@@ -1129,11 +1173,11 @@ msgstr ""
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "Next"
 msgstr "Next"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1141,7 +1185,7 @@ msgstr ""
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 #, fuzzy
 #, fuzzy
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Configuration Name"
 msgstr "Configuration Name"
@@ -1169,7 +1213,7 @@ msgid "Nginx restarted successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1177,6 +1221,7 @@ msgstr "Saved successfully"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1208,7 +1253,7 @@ msgstr ""
 msgid "Notification"
 msgid "Notification"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
@@ -1234,7 +1279,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1264,7 +1309,7 @@ msgstr ""
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1277,13 +1322,13 @@ msgstr "OS:"
 msgid "OS:"
 msgid "OS:"
 msgstr "OS:"
 msgstr "OS:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -1291,11 +1336,11 @@ msgstr ""
 msgid "Params"
 msgid "Params"
 msgstr "Params"
 msgstr "Params"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "Password"
 msgstr "Password"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "Password (*)"
 msgstr "Password (*)"
 
 
@@ -1358,7 +1403,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr ""
 msgstr ""
 
 
@@ -1454,7 +1499,16 @@ msgstr ""
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "Saved successfully"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
@@ -1513,9 +1567,9 @@ msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "Save"
 msgstr "Save"
 
 
@@ -1523,7 +1577,7 @@ msgstr "Save"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "Save Directive"
 msgstr "Save Directive"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "Save error %{msg}"
 msgstr "Save error %{msg}"
@@ -1531,15 +1585,15 @@ msgstr "Save error %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
@@ -1564,8 +1618,9 @@ msgstr "Send"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "Server error"
 msgstr "Server error"
@@ -1584,7 +1639,7 @@ msgid "server_name not found in directives"
 msgstr "server_name not found in directives"
 msgstr "server_name not found in directives"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "server_name parameter is required"
 msgstr "server_name parameter is required"
 
 
@@ -1641,7 +1696,7 @@ msgstr "Certificate Status"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 #, fuzzy
 #, fuzzy
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "Login"
 msgstr "Login"
@@ -1728,8 +1783,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr ""
 msgstr ""
 
 
@@ -1763,7 +1818,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1798,8 +1853,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
@@ -1825,6 +1880,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1841,10 +1897,14 @@ msgid ""
 "continue?"
 "continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1900,11 +1960,15 @@ msgstr ""
 msgid "User"
 msgid "User"
 msgstr "Username"
 msgstr "Username"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "Username"
 msgstr "Username"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "Username (*)"
 msgstr "Username (*)"
 
 
@@ -1918,7 +1982,7 @@ msgstr ""
 msgid "View"
 msgid "View"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
@@ -1934,7 +1998,7 @@ msgstr "Basic Mode"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "Warning"
 msgstr "Warning"
 
 
@@ -1965,6 +2029,7 @@ msgstr ""
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "Yes"
 msgstr "Yes"

+ 165 - 98
app/src/language/es/app.po

@@ -33,7 +33,8 @@ msgstr "Usuario"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "Acción"
 msgstr "Acción"
 
 
@@ -56,7 +57,7 @@ msgstr "Añadir directiva a continuación"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "Agregar Ubicación"
 msgstr "Agregar Ubicación"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "Agregar Sitio"
 msgstr "Agregar Sitio"
 
 
@@ -72,11 +73,11 @@ msgstr "Agregado exitoso"
 msgid "Additional"
 msgid "Additional"
 msgstr "Adicional"
 msgstr "Adicional"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Modo avanzado"
 msgstr "Modo avanzado"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "URL Base de la API"
 msgstr "URL Base de la API"
 
 
@@ -85,11 +86,11 @@ msgstr "URL Base de la API"
 msgid "API Document"
 msgid "API Document"
 msgstr "Token de la API"
 msgstr "Token de la API"
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "Proxy de la API"
 msgstr "Proxy de la API"
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr "Token de la API"
 msgstr "Token de la API"
 
 
@@ -97,7 +98,12 @@ msgstr "Token de la API"
 msgid "Arch"
 msgid "Arch"
 msgstr "Arquitectura"
 msgstr "Arquitectura"
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "¿Está seguro de que quiere borrar?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "¿Está seguro de que desea borrar todas las notificaciones?"
 msgstr "¿Está seguro de que desea borrar todas las notificaciones?"
@@ -146,6 +152,15 @@ msgstr "Preguntar por ayuda a ChatGPT"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Asistente"
 msgstr "Asistente"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "Autor"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -169,8 +184,8 @@ msgstr "Renovación automática habilitada por %{name}"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "Volver"
 msgstr "Volver"
 
 
@@ -178,18 +193,30 @@ msgstr "Volver"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "Volver al Inicio"
 msgstr "Volver al Inicio"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "Información general"
 msgstr "Información general"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "Básico"
 msgstr "Básico"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "Modo Básico"
 msgstr "Modo Básico"
 
 
@@ -273,12 +300,12 @@ msgid "Cleaning environment variables"
 msgstr "Borrar las variables de entorno"
 msgstr "Borrar las variables de entorno"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "Borrar"
 msgstr "Borrar"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 msgid "Cleared successfully"
 msgid "Cleared successfully"
 msgstr "Limpiado exitoso"
 msgstr "Limpiado exitoso"
@@ -303,7 +330,7 @@ msgstr "Plantillas de configuración"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "El archivo de configuración se probó exitosamente"
 msgstr "El archivo de configuración se probó exitosamente"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "Nombre de la configuración"
 msgstr "Nombre de la configuración"
 
 
@@ -311,7 +338,7 @@ msgstr "Nombre de la configuración"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "Configuraciones"
 msgstr "Configuraciones"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configurar SSL"
 msgstr "Configurar SSL"
 
 
@@ -341,7 +368,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "Crear"
 msgstr "Crear"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "Crear otro"
 msgstr "Crear otro"
 
 
@@ -380,7 +407,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Panel"
 msgstr "Panel"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "Base de datos (Opcional, default: database)"
 msgstr "Base de datos (Opcional, default: database)"
 
 
@@ -412,15 +439,15 @@ msgstr "Eliminar stream: %{site_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "Borrado exitoso"
 msgstr "Borrado exitoso"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Desplegar"
 msgstr "Desplegar"
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr "Falló el desplegado de %{conf_name} a %{node_name}"
 msgstr "Falló el desplegado de %{conf_name} a %{node_name}"
 
 
@@ -467,9 +494,9 @@ msgstr "Desactivar"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "No se pudo desactivar la renovación automática por %{name}"
 msgstr "No se pudo desactivar la renovación automática por %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Desactivado"
 msgstr "Desactivado"
 
 
@@ -540,7 +567,7 @@ msgstr "¿Quieres eliminar esta transmisión?"
 msgid "Domain"
 msgid "Domain"
 msgstr "Dominio"
 msgstr "Dominio"
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "Configuración de dominio creada con éxito"
 msgstr "Configuración de dominio creada con éxito"
 
 
@@ -562,34 +589,34 @@ msgstr "Descargando la última versión"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "Modo de ejecución de prueba habilitado"
 msgstr "Modo de ejecución de prueba habilitado"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "Duplicar"
 msgstr "Duplicar"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "Duplicado con éxito de %{conf_name} a %{node_name}"
 msgstr "Duplicado con éxito de %{conf_name} a %{node_name}"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "Duplicado fallido"
 msgstr "Duplicado fallido"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "Duplicado con éxito"
 msgstr "Duplicado con éxito"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "Duplicado con éxito a local"
 msgstr "Duplicado con éxito a local"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Editar %{n}"
 msgstr "Editar %{n}"
 
 
@@ -610,24 +637,24 @@ msgstr "Editar Transmisión"
 msgid "Email"
 msgid "Email"
 msgstr "Correo (*)"
 msgstr "Correo (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "Correo (*)"
 msgstr "Correo (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 msgid "Enable"
 msgid "Enable"
 msgstr "Habilitar"
 msgstr "Habilitar"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "Falló el habilitado de %{conf_name} en %{node_name}"
 msgstr "Falló el habilitado de %{conf_name} en %{node_name}"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "Habilitado exitoso de %{conf_name} en %{node_name}"
 msgstr "Habilitado exitoso de %{conf_name} en %{node_name}"
 
 
@@ -635,12 +662,12 @@ msgstr "Habilitado exitoso de %{conf_name} en %{node_name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "No se pudo activar la renovación automática por %{name}"
 msgstr "No se pudo activar la renovación automática por %{name}"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "Falló la habilitación"
 msgstr "Falló la habilitación"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "Habilitado con Éxito"
 msgstr "Habilitado con Éxito"
 
 
@@ -650,19 +677,19 @@ msgstr "Habilitar TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "Habilitado"
 msgstr "Habilitado"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "Habilitado con éxito"
 msgstr "Habilitado con éxito"
@@ -731,7 +758,7 @@ msgstr "Error al habilitar %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "No se pudo obtener la información del certificado"
 msgstr "No se pudo obtener la información del certificado"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 msgstr ""
 "No se pudo guardar, se detectó un error(es) de sintaxis en la configuración."
 "No se pudo guardar, se detectó un error(es) de sintaxis en la configuración."
@@ -757,7 +784,7 @@ msgstr "Archivo no encontrado"
 msgid "Filter"
 msgid "Filter"
 msgstr "Filtro"
 msgstr "Filtro"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "Terminado"
 msgstr "Terminado"
 
 
@@ -825,6 +852,12 @@ msgstr "HTTP01"
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 msgid "Import"
 msgid "Import"
 msgstr "Importar"
 msgstr "Importar"
@@ -833,6 +866,11 @@ msgstr "Importar"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "Importar Certificado"
 msgstr "Importar Certificado"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "El nombre de usuario o contraseña son incorrectos"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr "Información"
 msgstr "Información"
@@ -845,7 +883,7 @@ msgstr "Error de actualización de kernel inicial"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "Inicializando la actualización del kernel"
 msgstr "Inicializando la actualización del kernel"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "Instalar"
 msgstr "Instalar"
 
 
@@ -866,6 +904,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr "Válido"
 msgstr "Válido"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
 msgstr "Obtener certificado comodín"
 msgstr "Obtener certificado comodín"
@@ -897,7 +939,7 @@ msgstr "Comprobado por última vez el"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Para no modificar dejar en blanco"
 msgstr "Para no modificar dejar en blanco"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Dejar en blanco para el valor predeterminado: https://api.openai.com/"
 msgstr "Dejar en blanco para el valor predeterminado: https://api.openai.com/"
 
 
@@ -949,11 +991,11 @@ msgstr "Ubicaciones"
 msgid "Log"
 msgid "Log"
 msgstr "Registro"
 msgstr "Registro"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "Acceso"
 msgstr "Acceso"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "Acceso exitoso"
 msgstr "Acceso exitoso"
 
 
@@ -961,7 +1003,7 @@ msgstr "Acceso exitoso"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Cierre de sesión exitoso"
 msgstr "Cierre de sesión exitoso"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1003,6 +1045,10 @@ msgstr "Administrar usuarios"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "Certificado Administrado"
 msgstr "Certificado Administrado"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1016,7 +1062,7 @@ msgstr "Memoria y almacenamiento"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Modo de ejecución"
 msgstr "Modo de ejecución"
@@ -1031,7 +1077,7 @@ msgstr "Modificar"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "Modificar Certificado"
 msgstr "Modificar Certificado"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "Modificar configuración"
 msgstr "Modificar configuración"
 
 
@@ -1050,12 +1096,12 @@ msgstr "Directiva multilínea"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "Nombre"
 msgstr "Nombre"
@@ -1082,11 +1128,11 @@ msgstr "Se liberó una nueva versión"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "Siguiente"
 msgstr "Siguiente"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1094,7 +1140,7 @@ msgstr "Nginx"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Ruta de registro de acceso de Nginx"
 msgstr "Ruta de registro de acceso de Nginx"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Error de análisis de configuración de Nginx"
 msgstr "Error de análisis de configuración de Nginx"
 
 
@@ -1119,7 +1165,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx reiniciado con éxito"
 msgstr "Nginx reiniciado con éxito"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1127,6 +1173,7 @@ msgstr "Nginx reiniciado con éxito"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1157,7 +1204,7 @@ msgstr "Nota"
 msgid "Notification"
 msgid "Notification"
 msgstr "Notificación"
 msgstr "Notificación"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 msgid "Notifications"
 msgid "Notifications"
 msgstr "Notificaciones"
 msgstr "Notificaciones"
 
 
@@ -1181,7 +1228,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1211,7 +1258,7 @@ msgstr "Una vez que se complete la verificación, los registros se eliminarán."
 msgid "Online"
 msgid "Online"
 msgstr "En línea"
 msgstr "En línea"
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1223,13 +1270,13 @@ msgstr "SO"
 msgid "OS:"
 msgid "OS:"
 msgstr "SO:"
 msgstr "SO:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Sobrescribir"
 msgstr "Sobrescribir"
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Sobrescribir archivo existente"
 msgstr "Sobrescribir archivo existente"
 
 
@@ -1237,11 +1284,11 @@ msgstr "Sobrescribir archivo existente"
 msgid "Params"
 msgid "Params"
 msgstr "Parámetros"
 msgstr "Parámetros"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "Contraseña"
 msgstr "Contraseña"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "Contraseña (*)"
 msgstr "Contraseña (*)"
 
 
@@ -1313,7 +1360,7 @@ msgstr "¡Seleccione al menos un nodo!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "Prelanzamiento"
 msgstr "Prelanzamiento"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "Configuración"
 msgstr "Configuración"
 
 
@@ -1409,7 +1456,16 @@ msgstr "Recargando"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "Recargando Nginx"
 msgstr "Recargando Nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "Eliminado con éxito"
+
+#: src/components/Notification/Notification.vue:52
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "Eliminado con éxito"
 msgstr "Eliminado con éxito"
 
 
@@ -1461,9 +1517,9 @@ msgstr "Corriendo"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "Guardar"
 msgstr "Guardar"
 
 
@@ -1471,7 +1527,7 @@ msgstr "Guardar"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "Guardar Directiva"
 msgstr "Guardar Directiva"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "Error al guardar %{msg}"
 msgstr "Error al guardar %{msg}"
@@ -1479,14 +1535,14 @@ msgstr "Error al guardar %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Guardado con éxito"
 msgstr "Guardado con éxito"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "Guardado con éxito"
 msgstr "Guardado con éxito"
 
 
@@ -1511,8 +1567,9 @@ msgstr "Enviado"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "Error del servidor"
 msgstr "Error del servidor"
@@ -1531,7 +1588,7 @@ msgid "server_name not found in directives"
 msgstr "No se encuentra server_name en las directivas"
 msgstr "No se encuentra server_name en las directivas"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "Se requiere el parámetro server_name"
 msgstr "Se requiere el parámetro server_name"
 
 
@@ -1583,7 +1640,7 @@ msgstr "Ruta de la llave del certificado SSL"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "Ruta del certificado SSL"
 msgstr "Ruta del certificado SSL"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "Acceso SSO"
 msgstr "Acceso SSO"
 
 
@@ -1667,8 +1724,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "Sistema"
 msgstr "Sistema"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr "Objetivo"
 msgstr "Objetivo"
 
 
@@ -1701,7 +1758,7 @@ msgstr "La entrada no es un Certificado SSL"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "La entrada no es una clave de certificado SSL"
 msgstr "La entrada no es una clave de certificado SSL"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1736,8 +1793,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr "La URL no es válida"
 msgstr "La URL no es válida"
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 #, fuzzy
 #, fuzzy
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr "La URL no es válida"
 msgstr "La URL no es válida"
@@ -1764,6 +1821,7 @@ msgstr "Este campo es obligatorio"
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "Este campo no debe estar vacío"
 msgstr "Este campo no debe estar vacío"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1784,10 +1842,14 @@ msgstr ""
 "de la autoridad al backend, y debemos guardar este archivo y volver a cargar "
 "de la autoridad al backend, y debemos guardar este archivo y volver a cargar "
 "Nginx. ¿Estás seguro de que quieres continuar?"
 "Nginx. ¿Estás seguro de que quieres continuar?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "El token no es válido"
 msgstr "El token no es válido"
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1840,11 +1902,15 @@ msgstr "URL"
 msgid "User"
 msgid "User"
 msgstr "Usuario"
 msgstr "Usuario"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "Nombre de usuario"
 msgstr "Nombre de usuario"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "Nombre de usuario (*)"
 msgstr "Nombre de usuario (*)"
 
 
@@ -1858,7 +1924,7 @@ msgstr "Válido"
 msgid "View"
 msgid "View"
 msgstr "Ver"
 msgstr "Ver"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Ver todas las notificaciones"
 msgstr "Ver todas las notificaciones"
 
 
@@ -1874,7 +1940,7 @@ msgstr "Modo Básico"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "Advertencia"
 msgstr "Advertencia"
 
 
@@ -1909,6 +1975,7 @@ msgstr "Escribir certificado a disco"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "Si"
 msgstr "Si"

+ 165 - 98
app/src/language/fr_FR/app.po

@@ -30,7 +30,8 @@ msgstr "Nom d'utilisateur"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "Action"
 msgstr "Action"
 
 
@@ -53,7 +54,7 @@ msgstr "Ajouter une directive"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "Ajouter une localisation"
 msgstr "Ajouter une localisation"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "Ajouter un site"
 msgstr "Ajouter un site"
 
 
@@ -72,11 +73,11 @@ msgstr "Mis à jour avec succés"
 msgid "Additional"
 msgid "Additional"
 msgstr "Supplémentaire"
 msgstr "Supplémentaire"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Mode avancé"
 msgstr "Mode avancé"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "URL de base de l'API"
 msgstr "URL de base de l'API"
 
 
@@ -85,11 +86,11 @@ msgstr "URL de base de l'API"
 msgid "API Document"
 msgid "API Document"
 msgstr "Jeton d'API"
 msgstr "Jeton d'API"
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "Proxy d'API"
 msgstr "Proxy d'API"
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr "Jeton d'API"
 msgstr "Jeton d'API"
 
 
@@ -98,7 +99,12 @@ msgstr "Jeton d'API"
 msgid "Arch"
 msgid "Arch"
 msgstr "Arch"
 msgstr "Arch"
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "Etes-vous sûr que vous voulez supprimer ?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
@@ -149,6 +155,15 @@ msgstr "Modèle ChatGPT"
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "Autheur"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -172,8 +187,8 @@ msgstr "Renouvellement automatique activé pour %{name}"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "Retour"
 msgstr "Retour"
 
 
@@ -181,18 +196,30 @@ msgstr "Retour"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "Retour au menu principal"
 msgstr "Retour au menu principal"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "Information générale"
 msgstr "Information générale"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "Basique"
 msgstr "Basique"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "Mode simple"
 msgstr "Mode simple"
 
 
@@ -279,12 +306,12 @@ msgid "Cleaning environment variables"
 msgstr "Nettoyage des variables d'environnement"
 msgstr "Nettoyage des variables d'environnement"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "Effacer"
 msgstr "Effacer"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 #, fuzzy
 #, fuzzy
 msgid "Cleared successfully"
 msgid "Cleared successfully"
@@ -310,7 +337,7 @@ msgstr "Modèles de configuration"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "Le fichier de configuration est testé avec succès"
 msgstr "Le fichier de configuration est testé avec succès"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "Nom de la configuration"
 msgstr "Nom de la configuration"
 
 
@@ -318,7 +345,7 @@ msgstr "Nom de la configuration"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "Configurations"
 msgstr "Configurations"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configurer SSL"
 msgstr "Configurer SSL"
 
 
@@ -349,7 +376,7 @@ msgstr "CPU :"
 msgid "Create"
 msgid "Create"
 msgstr "Créé le"
 msgstr "Créé le"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "Créer un autre"
 msgstr "Créer un autre"
 
 
@@ -388,7 +415,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Dashboard"
 msgstr "Dashboard"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "Base de données (Facultatif, par défaut : database)"
 msgstr "Base de données (Facultatif, par défaut : database)"
 
 
@@ -422,15 +449,15 @@ msgstr "Supprimer le site : %{site_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "Désactivé avec succès"
 msgstr "Désactivé avec succès"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
@@ -480,9 +507,9 @@ msgstr "Désactivé"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "La désactivation du renouvellement automatique a échoué pour %{name}"
 msgstr "La désactivation du renouvellement automatique a échoué pour %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Désactivé"
 msgstr "Désactivé"
 
 
@@ -557,7 +584,7 @@ msgstr "Voulez-vous supprimer ce serveur ?"
 msgid "Domain"
 msgid "Domain"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "La configuration du domaine a été créée avec succès"
 msgstr "La configuration du domaine a été créée avec succès"
 
 
@@ -580,38 +607,38 @@ msgstr "Téléchargement de la dernière version"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "Dupliquer"
 msgstr "Dupliquer"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "Dupliqué avec succès"
 msgstr "Dupliqué avec succès"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 #, fuzzy
 #, fuzzy
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "Dupliquer"
 msgstr "Dupliquer"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 #, fuzzy
 #, fuzzy
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "Dupliqué avec succès"
 msgstr "Dupliqué avec succès"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 #, fuzzy
 #, fuzzy
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "Dupliqué avec succès"
 msgstr "Dupliqué avec succès"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Modifier %{n}"
 msgstr "Modifier %{n}"
 
 
@@ -633,25 +660,25 @@ msgstr "Modifier le site"
 msgid "Email"
 msgid "Email"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 #, fuzzy
 #, fuzzy
 msgid "Enable"
 msgid "Enable"
 msgstr "Activé"
 msgstr "Activé"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr ""
 msgstr ""
 
 
@@ -659,12 +686,12 @@ msgstr ""
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "Échec de l'activation du renouvellement automatique pour %{name}"
 msgstr "Échec de l'activation du renouvellement automatique pour %{name}"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "Échec de l'activation"
 msgstr "Échec de l'activation"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 #, fuzzy
 #, fuzzy
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "Activé avec succès"
 msgstr "Activé avec succès"
@@ -675,19 +702,19 @@ msgstr "Activer TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "Activé"
 msgstr "Activé"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "Activé avec succès"
 msgstr "Activé avec succès"
@@ -758,7 +785,7 @@ msgstr "Impossible d'activer %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Échec de l'obtention des informations sur le certificat"
 msgstr "Échec de l'obtention des informations sur le certificat"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 msgstr ""
 "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été "
 "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été "
@@ -786,7 +813,7 @@ msgstr "Fichier introuvable"
 msgid "Filter"
 msgid "Filter"
 msgstr "Filtrer"
 msgstr "Filtrer"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "Finie"
 msgstr "Finie"
 
 
@@ -856,6 +883,12 @@ msgstr "HTTP01"
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 #, fuzzy
 #, fuzzy
 msgid "Import"
 msgid "Import"
@@ -866,6 +899,11 @@ msgstr "Exporter"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "État du certificat"
 msgstr "État du certificat"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "Le pseudo ou mot de passe est incorect"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr ""
 msgstr ""
@@ -878,7 +916,7 @@ msgstr "Erreur du programme de mise à niveau initial du core"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "Initialisation du programme de mise à niveau du core"
 msgstr "Initialisation du programme de mise à niveau du core"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "Installer"
 msgstr "Installer"
 
 
@@ -898,6 +936,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -931,7 +973,7 @@ msgstr "Dernière vérification le"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Laisser vide pour aucun changement"
 msgstr "Laisser vide pour aucun changement"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Laissez vide pour la valeur par défaut : https://api.openai.com/"
 msgstr "Laissez vide pour la valeur par défaut : https://api.openai.com/"
 
 
@@ -990,11 +1032,11 @@ msgstr "Localisations"
 msgid "Log"
 msgid "Log"
 msgstr "Connexion"
 msgstr "Connexion"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "Connexion"
 msgstr "Connexion"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "Connexion réussie"
 msgstr "Connexion réussie"
 
 
@@ -1002,7 +1044,7 @@ msgstr "Connexion réussie"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Déconnexion réussie"
 msgstr "Déconnexion réussie"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1047,6 +1089,10 @@ msgstr "Gérer les utilisateurs"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "Changer de certificat"
 msgstr "Changer de certificat"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1060,7 +1106,7 @@ msgstr "Mémoire et stockage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Mode d'exécution"
 msgstr "Mode d'exécution"
@@ -1076,7 +1122,7 @@ msgstr "Modifier"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "État du certificat"
 msgstr "État du certificat"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "Modifier la configuration"
 msgstr "Modifier la configuration"
 
 
@@ -1095,12 +1141,12 @@ msgstr "Directive multiligne"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "Nom"
 msgstr "Nom"
@@ -1127,11 +1173,11 @@ msgstr "Nouvelle version publiée"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "Suivant"
 msgstr "Suivant"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 #, fuzzy
 #, fuzzy
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Journal Nginx"
 msgstr "Journal Nginx"
@@ -1140,7 +1186,7 @@ msgstr "Journal Nginx"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Chemin du journal d'accès Nginx"
 msgstr "Chemin du journal d'accès Nginx"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Erreur d'analyse de configuration Nginx"
 msgstr "Erreur d'analyse de configuration Nginx"
 
 
@@ -1165,7 +1211,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx a redémarré avec succès"
 msgstr "Nginx a redémarré avec succès"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1173,6 +1219,7 @@ msgstr "Nginx a redémarré avec succès"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1205,7 +1252,7 @@ msgstr "Note"
 msgid "Notification"
 msgid "Notification"
 msgstr "Certification"
 msgstr "Certification"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "Certification"
 msgstr "Certification"
@@ -1230,7 +1277,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1260,7 +1307,7 @@ msgstr ""
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1272,13 +1319,13 @@ msgstr "OS"
 msgid "OS:"
 msgid "OS:"
 msgstr "OS :"
 msgstr "OS :"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -1286,11 +1333,11 @@ msgstr ""
 msgid "Params"
 msgid "Params"
 msgstr "Paramètres"
 msgstr "Paramètres"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "Mot de passe"
 msgstr "Mot de passe"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "Mot de passe (*)"
 msgstr "Mot de passe (*)"
 
 
@@ -1360,7 +1407,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "Préférence"
 msgstr "Préférence"
 
 
@@ -1459,7 +1506,16 @@ msgstr "Rechargement"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "Rechargement de nginx"
 msgstr "Rechargement de nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "Enregistré avec succès"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "Enregistré avec succès"
 msgstr "Enregistré avec succès"
@@ -1517,9 +1573,9 @@ msgstr "En cours d'éxécution"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "Enregistrer"
 msgstr "Enregistrer"
 
 
@@ -1527,7 +1583,7 @@ msgstr "Enregistrer"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "Enregistrer la directive"
 msgstr "Enregistrer la directive"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "Enregistrer l'erreur %{msg}"
 msgstr "Enregistrer l'erreur %{msg}"
@@ -1535,14 +1591,14 @@ msgstr "Enregistrer l'erreur %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Sauvegarde réussie"
 msgstr "Sauvegarde réussie"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "Enregistré avec succès"
 msgstr "Enregistré avec succès"
 
 
@@ -1567,8 +1623,9 @@ msgstr "Envoyer"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "Erreur du serveur"
 msgstr "Erreur du serveur"
@@ -1587,7 +1644,7 @@ msgid "server_name not found in directives"
 msgstr "server_name introuvable dans les directives"
 msgstr "server_name introuvable dans les directives"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "Le paramètre server_name est obligatoire"
 msgstr "Le paramètre server_name est obligatoire"
 
 
@@ -1643,7 +1700,7 @@ msgstr "Chemin de la clé du certificat SSL"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "Chemin du certificat SSL"
 msgstr "Chemin du certificat SSL"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 #, fuzzy
 #, fuzzy
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "Connexion"
 msgstr "Connexion"
@@ -1731,8 +1788,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "Système"
 msgstr "Système"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr ""
 msgstr ""
 
 
@@ -1766,7 +1823,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Chemin de la clé du certificat SSL"
 msgstr "Chemin de la clé du certificat SSL"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1802,8 +1859,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
@@ -1832,6 +1889,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1852,10 +1910,14 @@ msgstr ""
 "transmettre la demande de l'autorité au backend, et nous devons enregistrer "
 "transmettre la demande de l'autorité au backend, et nous devons enregistrer "
 "ce fichier et recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 "ce fichier et recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1909,11 +1971,15 @@ msgstr ""
 msgid "User"
 msgid "User"
 msgstr "Nom d'utilisateur"
 msgstr "Nom d'utilisateur"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "Nom d'utilisateur"
 msgstr "Nom d'utilisateur"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "Nom d'utilisateur (*)"
 msgstr "Nom d'utilisateur (*)"
 
 
@@ -1927,7 +1993,7 @@ msgstr ""
 msgid "View"
 msgid "View"
 msgstr "Voir"
 msgstr "Voir"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Certification"
 msgstr "Certification"
@@ -1943,7 +2009,7 @@ msgstr "Mode simple"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "Avertissement"
 msgstr "Avertissement"
 
 
@@ -1976,6 +2042,7 @@ msgstr "Écriture du certificat sur le disque"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "Oui"
 msgstr "Oui"

+ 165 - 98
app/src/language/ko_KR/app.po

@@ -32,7 +32,8 @@ msgstr "사용자 이름"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "작업"
 msgstr "작업"
 
 
@@ -55,7 +56,7 @@ msgstr "아래에 지시문 추가"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "위치 추가"
 msgstr "위치 추가"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "사이트 추가"
 msgstr "사이트 추가"
 
 
@@ -71,11 +72,11 @@ msgstr "성공적으로 추가됨"
 msgid "Additional"
 msgid "Additional"
 msgstr "추가적인"
 msgstr "추가적인"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "고급 모드"
 msgstr "고급 모드"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 기본 URL"
 msgstr "API 기본 URL"
 
 
@@ -84,11 +85,11 @@ msgstr "API 기본 URL"
 msgid "API Document"
 msgid "API Document"
 msgstr "API 토큰"
 msgstr "API 토큰"
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 프록시"
 msgstr "API 프록시"
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr "API 토큰"
 msgstr "API 토큰"
 
 
@@ -96,7 +97,12 @@ msgstr "API 토큰"
 msgid "Arch"
 msgid "Arch"
 msgstr "아키텍처"
 msgstr "아키텍처"
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "정말 삭제하시겠습니까?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "모든 알림을 지우시겠습니까?"
 msgstr "모든 알림을 지우시겠습니까?"
@@ -145,6 +151,15 @@ msgstr "ChatGPT에게 도움 요청"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "조수"
 msgstr "조수"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "저자"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -168,8 +183,8 @@ msgstr "%{name}에 대한 자동 갱신 활성화됨"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "뒤로"
 msgstr "뒤로"
 
 
@@ -177,18 +192,30 @@ msgstr "뒤로"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "홈으로"
 msgstr "홈으로"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "기본 정보"
 msgstr "기본 정보"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "기본"
 msgstr "기본"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "기본 모드"
 msgstr "기본 모드"
 
 
@@ -272,12 +299,12 @@ msgid "Cleaning environment variables"
 msgstr "환경 변수 정리"
 msgstr "환경 변수 정리"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "클리어"
 msgstr "클리어"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 msgid "Cleared successfully"
 msgid "Cleared successfully"
 msgstr "성공적으로 제거됨"
 msgstr "성공적으로 제거됨"
@@ -301,7 +328,7 @@ msgstr "구성 템플릿"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "구성 파일 테스트 성공"
 msgstr "구성 파일 테스트 성공"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "구성 이름"
 msgstr "구성 이름"
 
 
@@ -309,7 +336,7 @@ msgstr "구성 이름"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "구성들"
 msgstr "구성들"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "SSL 구성하기"
 msgstr "SSL 구성하기"
 
 
@@ -339,7 +366,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "생성"
 msgstr "생성"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "다른 것 생성하기"
 msgstr "다른 것 생성하기"
 
 
@@ -378,7 +405,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "대시보드"
 msgstr "대시보드"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "데이터베이스 (선택사항, 기본값: database)"
 msgstr "데이터베이스 (선택사항, 기본값: database)"
 
 
@@ -410,15 +437,15 @@ msgstr "스트림 삭제: %{stream_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "성공적으로 삭제됨"
 msgstr "성공적으로 삭제됨"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr "배포"
 msgstr "배포"
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr "%{conf_name}을(를) %{node_name}(으)로 배포 실패"
 msgstr "%{conf_name}을(를) %{node_name}(으)로 배포 실패"
 
 
@@ -465,9 +492,9 @@ msgstr "비활성화"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "%{name}의 자동 갱신 비활성화 실패"
 msgstr "%{name}의 자동 갱신 비활성화 실패"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "비활성화됨"
 msgstr "비활성화됨"
 
 
@@ -538,7 +565,7 @@ msgstr "이 업스트림을 제거하시겠습니까?"
 msgid "Domain"
 msgid "Domain"
 msgstr "도메인"
 msgstr "도메인"
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "도메인 구성이 성공적으로 생성되었습니다"
 msgstr "도메인 구성이 성공적으로 생성되었습니다"
 
 
@@ -559,35 +586,35 @@ msgstr "최신 릴리스 다운로드 중"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "드라이런 모드 활성화됨"
 msgstr "드라이런 모드 활성화됨"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "복제"
 msgstr "복제"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "%{conf_name}을(를) %{node_name}(으)로 성공적으로 복제함"
 msgstr "%{conf_name}을(를) %{node_name}(으)로 성공적으로 복제함"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "복제 실패"
 msgstr "복제 실패"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 #, fuzzy
 #, fuzzy
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "성공적으로 복제됨"
 msgstr "성공적으로 복제됨"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "로컬로 성공적으로 복제됨"
 msgstr "로컬로 성공적으로 복제됨"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "%{n} 편집"
 msgstr "%{n} 편집"
 
 
@@ -608,24 +635,24 @@ msgstr "스트림 편집"
 msgid "Email"
 msgid "Email"
 msgstr "이메일 (*)"
 msgstr "이메일 (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "이메일 (*)"
 msgstr "이메일 (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 msgid "Enable"
 msgid "Enable"
 msgstr "활성화"
 msgstr "활성화"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "%{node_name}에서 %{conf_name} 활성화 실패"
 msgstr "%{node_name}에서 %{conf_name} 활성화 실패"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "%{node_name}에서 %{conf_name} 성공적으로 활성화됨"
 msgstr "%{node_name}에서 %{conf_name} 성공적으로 활성화됨"
 
 
@@ -633,12 +660,12 @@ msgstr "%{node_name}에서 %{conf_name} 성공적으로 활성화됨"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "%{name}에 대한 자동 갱신 활성화 실패"
 msgstr "%{name}에 대한 자동 갱신 활성화 실패"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "활성화 실패"
 msgstr "활성화 실패"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "성공적으로 활성화"
 msgstr "성공적으로 활성화"
 
 
@@ -648,19 +675,19 @@ msgstr "TLS 활성화"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "활성화됨"
 msgstr "활성화됨"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "성공적으로 활성화됨"
 msgstr "성공적으로 활성화됨"
@@ -730,7 +757,7 @@ msgstr "%{msg} 활성화 실패"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "인증서 정보 가져오기 실패"
 msgstr "인증서 정보 가져오기 실패"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다."
 msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다."
 
 
@@ -756,7 +783,7 @@ msgstr "파일을 찾을 수 없음"
 msgid "Filter"
 msgid "Filter"
 msgstr "필터"
 msgstr "필터"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "완료됨"
 msgstr "완료됨"
 
 
@@ -828,6 +855,12 @@ msgstr "HTTP01"
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 msgid "Import"
 msgid "Import"
 msgstr "가져오기"
 msgstr "가져오기"
@@ -837,6 +870,11 @@ msgstr "가져오기"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "인증서 상태"
 msgstr "인증서 상태"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "사용자 이름 또는 비밀번호가 올바르지 않습니다"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr "정보"
 msgstr "정보"
@@ -849,7 +887,7 @@ msgstr "초기 코어 업그레이더 오류"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "코어 업그레이더 초기화"
 msgstr "코어 업그레이더 초기화"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "설치"
 msgstr "설치"
 
 
@@ -871,6 +909,10 @@ msgstr "간격"
 msgid "Invalid"
 msgid "Invalid"
 msgstr "유효함"
 msgstr "유효함"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -904,7 +946,7 @@ msgstr "마지막 확인 시간"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "변경사항이 없으면 비워두세요"
 msgstr "변경사항이 없으면 비워두세요"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "기본값을 사용하려면 비워 두세요: https://api.openai.com/"
 msgstr "기본값을 사용하려면 비워 두세요: https://api.openai.com/"
 
 
@@ -961,11 +1003,11 @@ msgstr "위치들"
 msgid "Log"
 msgid "Log"
 msgstr "로그인"
 msgstr "로그인"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "로그인"
 msgstr "로그인"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "로그인 성공"
 msgstr "로그인 성공"
 
 
@@ -973,7 +1015,7 @@ msgstr "로그인 성공"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "로그아웃 성공"
 msgstr "로그아웃 성공"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr "로그관리"
 msgstr "로그관리"
 
 
@@ -1023,6 +1065,10 @@ msgstr "사용자 관리"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "인증서 유효"
 msgstr "인증서 유효"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1036,7 +1082,7 @@ msgstr "메모리 및 저장소"
 msgid "Minutes"
 msgid "Minutes"
 msgstr "분"
 msgstr "분"
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "실행 모드"
 msgstr "실행 모드"
@@ -1053,7 +1099,7 @@ msgstr "설정 수정"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "인증서 상태"
 msgstr "인증서 상태"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "설정 수정"
 msgstr "설정 수정"
 
 
@@ -1073,12 +1119,12 @@ msgstr "단일 지시문"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "이름"
 msgstr "이름"
@@ -1105,11 +1151,11 @@ msgstr "새 버전 출시"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "다음"
 msgstr "다음"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1117,7 +1163,7 @@ msgstr "Nginx"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Nginx 접근 로그 경로"
 msgstr "Nginx 접근 로그 경로"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 #, fuzzy
 #, fuzzy
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 구성 오류름"
 msgstr "Nginx 구성 오류름"
@@ -1145,7 +1191,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx가 성공적으로 재시작됨"
 msgstr "Nginx가 성공적으로 재시작됨"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1153,6 +1199,7 @@ msgstr "Nginx가 성공적으로 재시작됨"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1184,7 +1231,7 @@ msgstr "참고"
 msgid "Notification"
 msgid "Notification"
 msgstr "알림"
 msgstr "알림"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "알림"
 msgstr "알림"
@@ -1210,7 +1257,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1240,7 +1287,7 @@ msgstr "검증이 완료되면, 레코드는 제거됩니다."
 msgid "Online"
 msgid "Online"
 msgstr "온라인"
 msgstr "온라인"
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "오픈AI"
 msgstr "오픈AI"
 
 
@@ -1253,13 +1300,13 @@ msgstr "OS"
 msgid "OS:"
 msgid "OS:"
 msgstr "OS:"
 msgstr "OS:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "덮어쓰기"
 msgstr "덮어쓰기"
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "기존 파일 덮어쓰기"
 msgstr "기존 파일 덮어쓰기"
 
 
@@ -1267,11 +1314,11 @@ msgstr "기존 파일 덮어쓰기"
 msgid "Params"
 msgid "Params"
 msgstr "파라미터"
 msgstr "파라미터"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "비밀번호"
 msgstr "비밀번호"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "비밀번호 (*)"
 msgstr "비밀번호 (*)"
 
 
@@ -1336,7 +1383,7 @@ msgstr "적어도 하나의 노드를 선택해주세요!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "사전 출시"
 msgstr "사전 출시"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "환경설정"
 msgstr "환경설정"
 
 
@@ -1434,7 +1481,16 @@ msgstr "리로딩 중"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "Nginx 리로딩 중"
 msgstr "Nginx 리로딩 중"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "성공적으로 제거됨"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "성공적으로 제거됨"
 msgstr "성공적으로 제거됨"
@@ -1493,9 +1549,9 @@ msgstr "실행 중"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "저장"
 msgstr "저장"
 
 
@@ -1503,7 +1559,7 @@ msgstr "저장"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "지시문 저장"
 msgstr "지시문 저장"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "저장 오류 %{msg}"
 msgstr "저장 오류 %{msg}"
@@ -1511,15 +1567,15 @@ msgstr "저장 오류 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "성공적으로 저장됨"
 msgstr "성공적으로 저장됨"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "성공적으로 저장됨"
 msgstr "성공적으로 저장됨"
 
 
@@ -1544,8 +1600,9 @@ msgstr "보내기"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "서버 오류"
 msgstr "서버 오류"
@@ -1564,7 +1621,7 @@ msgid "server_name not found in directives"
 msgstr "directives에서 server_name을 찾을 수 없습니다"
 msgstr "directives에서 server_name을 찾을 수 없습니다"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "server_name 매개변수가 필요합니다"
 msgstr "server_name 매개변수가 필요합니다"
 
 
@@ -1620,7 +1677,7 @@ msgstr "SSL 인증서 키 경로"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "SSL 인증서 경로"
 msgstr "SSL 인증서 경로"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 #, fuzzy
 #, fuzzy
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "SSO 로그인"
 msgstr "SSO 로그인"
@@ -1707,8 +1764,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "시스템"
 msgstr "시스템"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr "대상"
 msgstr "대상"
 
 
@@ -1742,7 +1799,7 @@ msgstr "입력이 SSL 인증서가 아닙니다"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1778,8 +1835,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr "유효한 URL이 아닙니다"
 msgstr "유효한 URL이 아닙니다"
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 #, fuzzy
 #, fuzzy
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr "유효한 URL이 아닙니다"
 msgstr "유효한 URL이 아닙니다"
@@ -1806,6 +1863,7 @@ msgstr "이 필드는 필수입니다"
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "이 필드는 비워둘 수 없습니다"
 msgstr "이 필드는 비워둘 수 없습니다"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr "팁"
 msgstr "팁"
@@ -1825,10 +1883,14 @@ msgstr ""
 "시할 수 있는 위치를 추가해야 하며,이 파일을 저장하고 Nginx를 다시로드해야 합"
 "시할 수 있는 위치를 추가해야 하며,이 파일을 저장하고 Nginx를 다시로드해야 합"
 "니다.계속하시겠습니까?"
 "니다.계속하시겠습니까?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "토큰이 유효하지 않습니다"
 msgstr "토큰이 유효하지 않습니다"
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1884,11 +1946,15 @@ msgstr "URL"
 msgid "User"
 msgid "User"
 msgstr "사용자 이름"
 msgstr "사용자 이름"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "사용자 이름"
 msgstr "사용자 이름"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "사용자 이름 (*)"
 msgstr "사용자 이름 (*)"
 
 
@@ -1902,7 +1968,7 @@ msgstr "유효함"
 msgid "View"
 msgid "View"
 msgstr "보기"
 msgstr "보기"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
@@ -1919,7 +1985,7 @@ msgstr "기본 모드"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "경고"
 msgstr "경고"
 
 
@@ -1954,6 +2020,7 @@ msgstr "인증서를 디스크에 쓰기"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "예"
 msgstr "예"

+ 164 - 103
app/src/language/messages.pot

@@ -24,6 +24,7 @@ msgstr ""
 #: src/views/domain/DomainList.vue:47
 #: src/views/domain/DomainList.vue:47
 #: src/views/environment/Environment.vue:129
 #: src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
+#: src/views/preference/AuthSettings.vue:26
 #: src/views/stream/StreamList.vue:47
 #: src/views/stream/StreamList.vue:47
 #: src/views/user/User.vue:43
 #: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -49,7 +50,7 @@ msgid "Add Location"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:64
 #: src/routes/index.ts:64
-#: src/views/domain/DomainAdd.vue:93
+#: src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr ""
 msgstr ""
 
 
@@ -65,12 +66,12 @@ msgstr ""
 msgid "Additional"
 msgid "Additional"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:199
-#: src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197
+#: src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -78,11 +79,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -90,7 +91,11 @@ msgstr ""
 msgid "Arch"
 msgid "Arch"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr ""
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
 msgstr ""
@@ -136,6 +141,14 @@ msgstr ""
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+msgid "Auth"
+msgstr ""
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -160,9 +173,9 @@ msgstr ""
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73
 #: src/views/config/Config.vue:73
 #: src/views/config/ConfigEdit.vue:87
 #: src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256
+#: src/views/domain/DomainEdit.vue:254
 #: src/views/nginx_log/NginxLog.vue:168
 #: src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr ""
 msgstr ""
 
 
@@ -170,19 +183,31 @@ msgstr ""
 msgid "Back Home"
 msgid "Back Home"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:202
-#: src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200
+#: src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr ""
 msgstr ""
 
 
@@ -266,12 +291,12 @@ msgid "Cleaning environment variables"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 msgid "Cleared successfully"
 msgid "Cleared successfully"
 msgstr ""
 msgstr ""
@@ -295,7 +320,7 @@ msgstr ""
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr ""
 msgstr ""
 
 
@@ -303,7 +328,7 @@ msgstr ""
 msgid "Configurations"
 msgid "Configurations"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr ""
 msgstr ""
 
 
@@ -333,7 +358,7 @@ msgstr ""
 msgid "Create"
 msgid "Create"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr ""
 msgstr ""
 
 
@@ -371,7 +396,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr ""
 msgstr ""
 
 
@@ -403,15 +428,15 @@ msgstr ""
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
@@ -460,10 +485,10 @@ msgid "Disable auto-renewal failed for %{name}"
 msgstr ""
 msgstr ""
 
 
 #: src/views/domain/cert/ChangeCert.vue:44
 #: src/views/domain/cert/ChangeCert.vue:44
-#: src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33
 #: src/views/domain/DomainList.vue:33
 #: src/views/environment/Environment.vue:93
 #: src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177
+#: src/views/stream/StreamEdit.vue:175
 #: src/views/stream/StreamList.vue:33
 #: src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr ""
 msgstr ""
@@ -536,7 +561,7 @@ msgstr ""
 msgid "Domain"
 msgid "Domain"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr ""
 msgstr ""
 
 
@@ -556,35 +581,35 @@ msgstr ""
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:174
-#: src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172
+#: src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr ""
 msgstr ""
 
 
@@ -605,24 +630,24 @@ msgstr ""
 msgid "Email"
 msgid "Email"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 msgid "Enable"
 msgid "Enable"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr ""
 msgstr ""
 
 
@@ -630,12 +655,12 @@ msgstr ""
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr ""
 msgstr ""
 
 
@@ -645,22 +670,22 @@ msgstr ""
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179
+#: src/views/domain/DomainEdit.vue:177
 #: src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171
+#: src/views/stream/StreamEdit.vue:169
 #: src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr ""
 msgstr ""
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40
 #: src/views/domain/DomainList.vue:57
 #: src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr ""
 msgstr ""
@@ -730,8 +755,8 @@ msgstr ""
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:132
-#: src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130
+#: src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 msgstr ""
 
 
@@ -757,7 +782,7 @@ msgid "Filter"
 msgstr ""
 msgstr ""
 
 
 #: src/language/constants.ts:19
 #: src/language/constants.ts:19
-#: src/views/domain/DomainAdd.vue:101
+#: src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr ""
 msgstr ""
 
 
@@ -825,6 +850,10 @@ msgstr ""
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid "If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 msgid "Import"
 msgid "Import"
 msgstr ""
 msgstr ""
@@ -834,6 +863,10 @@ msgstr ""
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:59
+msgid "Incorrect username or password"
+msgstr ""
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr ""
 msgstr ""
@@ -847,7 +880,7 @@ msgid "Initialing core upgrader"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:273
 #: src/routes/index.ts:273
-#: src/views/other/Install.vue:136
+#: src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr ""
 msgstr ""
 
 
@@ -867,6 +900,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
 msgstr ""
 msgstr ""
@@ -897,7 +934,7 @@ msgstr ""
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 msgstr ""
 
 
@@ -949,12 +986,12 @@ msgid "Log"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:279
 #: src/routes/index.ts:279
-#: src/views/other/Login.vue:147
+#: src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:109
 #: src/views/other/Login.vue:51
 #: src/views/other/Login.vue:51
-#: src/views/other/Login.vue:97
 msgid "Login successful"
 msgid "Login successful"
 msgstr ""
 msgstr ""
 
 
@@ -962,7 +999,7 @@ msgstr ""
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -997,6 +1034,10 @@ msgstr ""
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1010,7 +1051,7 @@ msgstr ""
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 msgid "Model"
 msgid "Model"
 msgstr ""
 msgstr ""
 
 
@@ -1025,7 +1066,7 @@ msgstr ""
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr ""
 msgstr ""
 
 
@@ -1044,12 +1085,12 @@ msgstr ""
 #: src/views/config/config.ts:7
 #: src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13
 #: src/views/stream/StreamList.vue:13
 #: src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
@@ -1077,11 +1118,11 @@ msgstr ""
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1089,8 +1130,8 @@ msgstr ""
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainEdit.vue:217
-#: src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215
+#: src/views/stream/StreamEdit.vue:207
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr ""
 msgstr ""
 
 
@@ -1116,7 +1157,7 @@ msgid "Nginx restarted successfully"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1124,6 +1165,7 @@ msgstr ""
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1154,7 +1196,7 @@ msgstr ""
 msgid "Notification"
 msgid "Notification"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:82
 #: src/routes/index.ts:221
 #: src/routes/index.ts:221
 msgid "Notifications"
 msgid "Notifications"
 msgstr ""
 msgstr ""
@@ -1179,7 +1221,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1209,7 +1251,7 @@ msgstr ""
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1221,13 +1263,13 @@ msgstr ""
 msgid "OS:"
 msgid "OS:"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -1235,12 +1277,12 @@ msgstr ""
 msgid "Params"
 msgid "Params"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Login.vue:132
+#: src/views/other/Login.vue:144
 #: src/views/user/User.vue:18
 #: src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr ""
 msgstr ""
 
 
@@ -1300,7 +1342,7 @@ msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:239
 #: src/routes/index.ts:239
-#: src/views/preference/Preference.vue:96
+#: src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr ""
 msgstr ""
 
 
@@ -1391,7 +1433,15 @@ msgstr ""
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+msgid "Remove successfully"
+msgstr ""
+
+#: src/components/Notification/Notification.vue:52
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr ""
 msgstr ""
 
 
@@ -1444,10 +1494,10 @@ msgstr ""
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/config/ConfigEdit.vue:96
 #: src/views/config/ConfigEdit.vue:96
-#: src/views/domain/DomainEdit.vue:263
+#: src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130
-#: src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145
+#: src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr ""
 msgstr ""
 
 
@@ -1456,7 +1506,7 @@ msgid "Save Directive"
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/ConfigEdit.vue:57
 #: src/views/config/ConfigEdit.vue:57
-#: src/views/domain/DomainAdd.vue:50
+#: src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr ""
 msgstr ""
@@ -1464,15 +1514,15 @@ msgstr ""
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/ConfigEdit.vue:55
 #: src/views/config/ConfigEdit.vue:55
-#: src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr ""
 msgstr ""
 
 
@@ -1499,8 +1549,9 @@ msgstr ""
 #: src/views/config/ConfigEdit.vue:40
 #: src/views/config/ConfigEdit.vue:40
 #: src/views/domain/DomainList.vue:81
 #: src/views/domain/DomainList.vue:81
 #: src/views/environment/Environment.vue:139
 #: src/views/environment/Environment.vue:139
-#: src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70
+#: src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78
 #: src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
@@ -1520,7 +1571,7 @@ msgid "server_name not found in directives"
 msgstr ""
 msgstr ""
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr ""
 msgstr ""
 
 
@@ -1570,7 +1621,7 @@ msgstr ""
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr ""
 msgstr ""
 
 
@@ -1649,8 +1700,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr ""
 msgstr ""
 
 
@@ -1679,7 +1730,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid "The model name should only contain letters, unicode, numbers, hyphens, dashes, and dots."
 msgid "The model name should only contain letters, unicode, numbers, hyphens, dashes, and dots."
 msgstr ""
 msgstr ""
 
 
@@ -1704,8 +1755,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
@@ -1731,6 +1782,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1743,10 +1795,14 @@ msgstr ""
 msgid "To make sure the certification auto-renewal can work normally, we need to add a location which can proxy the request from authority to backend, and we need to save this file and reload the Nginx. Are you sure you want to continue?"
 msgid "To make sure the certification auto-renewal can work normally, we need to add a location which can proxy the request from authority to backend, and we need to save this file and reload the Nginx. Are you sure you want to continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1804,12 +1860,16 @@ msgstr ""
 msgid "User"
 msgid "User"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Login.vue:122
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134
 #: src/views/user/User.vue:9
 #: src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr ""
 msgstr ""
 
 
@@ -1823,7 +1883,7 @@ msgstr ""
 msgid "View"
 msgid "View"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr ""
 msgstr ""
 
 
@@ -1838,7 +1898,7 @@ msgstr ""
 #: src/constants/index.ts:17
 #: src/constants/index.ts:17
 #: src/views/config/InspectConfig.vue:33
 #: src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr ""
 msgstr ""
 
 
@@ -1865,6 +1925,7 @@ msgstr ""
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 165 - 98
app/src/language/ru_RU/app.po

@@ -28,7 +28,8 @@ msgstr "Пользователь"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "Действие"
 msgstr "Действие"
 
 
@@ -51,7 +52,7 @@ msgstr "Добавить директиву ниже"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "Добавить Location"
 msgstr "Добавить Location"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "Добавть Сайт"
 msgstr "Добавть Сайт"
 
 
@@ -70,11 +71,11 @@ msgstr "Обновлено успешно"
 msgid "Additional"
 msgid "Additional"
 msgstr "Дополнительно"
 msgstr "Дополнительно"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Расширенный режим"
 msgstr "Расширенный режим"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +83,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -94,7 +95,12 @@ msgstr ""
 msgid "Arch"
 msgid "Arch"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "Вы уверены, что хотите удалить?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
@@ -147,6 +153,15 @@ msgstr "Обратитесь за помощью к ChatGPT"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Ассистент"
 msgstr "Ассистент"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "Автор"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -170,8 +185,8 @@ msgstr "Автообновление включено для %{name}"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "Назад"
 msgstr "Назад"
 
 
@@ -180,19 +195,31 @@ msgstr "Назад"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "Вернутся"
 msgstr "Вернутся"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "Основная информация"
 msgstr "Основная информация"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
 msgstr "Простой режим"
 msgstr "Простой режим"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "Простой режим"
 msgstr "Простой режим"
 
 
@@ -280,12 +307,12 @@ msgid "Cleaning environment variables"
 msgstr "Очистка переменных среды"
 msgstr "Очистка переменных среды"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "Очистить"
 msgstr "Очистить"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 #, fuzzy
 #, fuzzy
 msgid "Cleared successfully"
 msgid "Cleared successfully"
@@ -312,7 +339,7 @@ msgstr "Шаблоны конфигураций"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "Проверка конфигурации успешна"
 msgstr "Проверка конфигурации успешна"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "Название конфигурации"
 msgstr "Название конфигурации"
 
 
@@ -320,7 +347,7 @@ msgstr "Название конфигурации"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "Конфигурации"
 msgstr "Конфигурации"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Настроить SSL"
 msgstr "Настроить SSL"
 
 
@@ -351,7 +378,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "Создан в"
 msgstr "Создан в"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "Создать еще"
 msgstr "Создать еще"
 
 
@@ -390,7 +417,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Доска"
 msgstr "Доска"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "База данных (Опционально, по умолчанию: database)"
 msgstr "База данных (Опционально, по умолчанию: database)"
 
 
@@ -423,15 +450,15 @@ msgstr ""
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "Отключено успешно"
 msgstr "Отключено успешно"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr ""
 msgstr ""
 
 
@@ -481,9 +508,9 @@ msgstr "Отключить"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Не удалось отключить автоматическое продление для %{name}"
 msgstr "Не удалось отключить автоматическое продление для %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Отключено"
 msgstr "Отключено"
 
 
@@ -562,7 +589,7 @@ msgstr "Вы хотите удалить этот сервер?"
 msgid "Domain"
 msgid "Domain"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "Конфигурация домена успешно создана"
 msgstr "Конфигурация домена успешно создана"
 
 
@@ -584,38 +611,38 @@ msgstr "Загрузка последней версии"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "Включен пробный режим"
 msgstr "Включен пробный режим"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "Дублировать"
 msgstr "Дублировать"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "Продублированно %{conf_name} в %{node_name}"
 msgstr "Продублированно %{conf_name} в %{node_name}"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 #, fuzzy
 #, fuzzy
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "Дублировать не удалось"
 msgstr "Дублировать не удалось"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 #, fuzzy
 #, fuzzy
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "Продублированно"
 msgstr "Продублированно"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 #, fuzzy
 #, fuzzy
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Редактировать %{n}"
 msgstr "Редактировать %{n}"
 
 
@@ -637,25 +664,25 @@ msgstr "Редактировать Сайт"
 msgid "Email"
 msgid "Email"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 #, fuzzy
 #, fuzzy
 msgid "Enable"
 msgid "Enable"
 msgstr "Включить"
 msgstr "Включить"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "Включение %{conf_name} in %{node_name} нипалучилася"
 msgstr "Включение %{conf_name} in %{node_name} нипалучилася"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "Включение %{conf_name} in %{node_name} успешно"
 msgstr "Включение %{conf_name} in %{node_name} успешно"
 
 
@@ -663,12 +690,12 @@ msgstr "Включение %{conf_name} in %{node_name} успешно"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "Не удалось включить автоматическое продление для %{name}"
 msgstr "Не удалось включить автоматическое продление для %{name}"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "Включить не удалось"
 msgstr "Включить не удалось"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 #, fuzzy
 #, fuzzy
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "Активировано успешно"
 msgstr "Активировано успешно"
@@ -679,19 +706,19 @@ msgstr "Включить TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "Включено"
 msgstr "Включено"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "Активировано успешно"
 msgstr "Активировано успешно"
@@ -762,7 +789,7 @@ msgstr "Не удалось включить %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Не удалось получить информацию о сертификате"
 msgstr "Не удалось получить информацию о сертификате"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
 msgstr "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
 
 
@@ -788,7 +815,7 @@ msgstr "Файл не найден"
 msgid "Filter"
 msgid "Filter"
 msgstr "Фильтр"
 msgstr "Фильтр"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "Готово"
 msgstr "Готово"
 
 
@@ -860,6 +887,12 @@ msgstr ""
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 #, fuzzy
 #, fuzzy
 msgid "Import"
 msgid "Import"
@@ -870,6 +903,11 @@ msgstr "Экспорт"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "Статус сертификата"
 msgstr "Статус сертификата"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "Имя пользователя или пароль неверны"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr ""
 msgstr ""
@@ -882,7 +920,7 @@ msgstr "Ошибка первоначального обновления ядр
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "Инициализация программы обновления ядра"
 msgstr "Инициализация программы обновления ядра"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "Установить"
 msgstr "Установить"
 
 
@@ -904,6 +942,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr "Действительный"
 msgstr "Действительный"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -938,7 +980,7 @@ msgstr "Последняя проверка в"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Оставьте пустым без изменений"
 msgstr "Оставьте пустым без изменений"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Оставьте пустым для значения по умолчанию: https://api.openai.com/"
 msgstr "Оставьте пустым для значения по умолчанию: https://api.openai.com/"
 
 
@@ -995,11 +1037,11 @@ msgstr "Locations"
 msgid "Log"
 msgid "Log"
 msgstr "Логин"
 msgstr "Логин"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "Логин"
 msgstr "Логин"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "Авторизация успешна"
 msgstr "Авторизация успешна"
 
 
@@ -1007,7 +1049,7 @@ msgstr "Авторизация успешна"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Выход выполнен успешно"
 msgstr "Выход выполнен успешно"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1052,6 +1094,10 @@ msgstr "Пользователи"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "Управление сертификатами"
 msgstr "Управление сертификатами"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1065,7 +1111,7 @@ msgstr "Память и хранилище"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Расширенный режим"
 msgstr "Расширенный режим"
@@ -1082,7 +1128,7 @@ msgstr "Изменить"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "Статус сертификата"
 msgstr "Статус сертификата"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "Изменить конфигурацию"
 msgstr "Изменить конфигурацию"
 
 
@@ -1102,12 +1148,12 @@ msgstr "Одиночная директива"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "Имя"
 msgstr "Имя"
@@ -1134,11 +1180,11 @@ msgstr "Вышла новая версия"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "Дальше"
 msgstr "Дальше"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 #, fuzzy
 #, fuzzy
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Журнал"
 msgstr "Журнал"
@@ -1147,7 +1193,7 @@ msgstr "Журнал"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Путь для Nginx Access Log"
 msgstr "Путь для Nginx Access Log"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 #, fuzzy
 #, fuzzy
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Ошибка синтаксического анализа конфигурации Nginx"
 msgstr "Ошибка синтаксического анализа конфигурации Nginx"
@@ -1175,7 +1221,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx успешно перезапущен"
 msgstr "Nginx успешно перезапущен"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1183,6 +1229,7 @@ msgstr "Nginx успешно перезапущен"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1214,7 +1261,7 @@ msgstr "Заметка"
 msgid "Notification"
 msgid "Notification"
 msgstr "Сертификат"
 msgstr "Сертификат"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "Уведомления"
 msgstr "Уведомления"
@@ -1240,7 +1287,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1270,7 +1317,7 @@ msgstr ""
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1283,13 +1330,13 @@ msgstr "OS:"
 msgid "OS:"
 msgid "OS:"
 msgstr "OS:"
 msgstr "OS:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -1297,11 +1344,11 @@ msgstr ""
 msgid "Params"
 msgid "Params"
 msgstr "Параметры"
 msgstr "Параметры"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "Пароль"
 msgstr "Пароль"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "Пароль (*)"
 msgstr "Пароль (*)"
 
 
@@ -1366,7 +1413,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "Настройки"
 msgstr "Настройки"
 
 
@@ -1464,7 +1511,16 @@ msgstr "Перезагружается"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "Перезагружается nginx"
 msgstr "Перезагружается nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "Успешно сохранено"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "Успешно сохранено"
 msgstr "Успешно сохранено"
@@ -1523,9 +1579,9 @@ msgstr "Выполняется"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "Сохранить"
 msgstr "Сохранить"
 
 
@@ -1533,7 +1589,7 @@ msgstr "Сохранить"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "Сохранить директиву"
 msgstr "Сохранить директиву"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "Ошибка сохранения %{msg}"
 msgstr "Ошибка сохранения %{msg}"
@@ -1541,15 +1597,15 @@ msgstr "Ошибка сохранения %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Успешно сохранено"
 msgstr "Успешно сохранено"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "Успешно сохранено"
 msgstr "Успешно сохранено"
 
 
@@ -1574,8 +1630,9 @@ msgstr "Отправлено"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "Ошибка сервера"
 msgstr "Ошибка сервера"
@@ -1594,7 +1651,7 @@ msgid "server_name not found in directives"
 msgstr "server_name не нашел в директивах"
 msgstr "server_name не нашел в директивах"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "server_name параметр обязателен"
 msgstr "server_name параметр обязателен"
 
 
@@ -1651,7 +1708,7 @@ msgstr "Путь к ключу сертификата SSL"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "Путь к сертификату SSL"
 msgstr "Путь к сертификату SSL"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 #, fuzzy
 #, fuzzy
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "Логин"
 msgstr "Логин"
@@ -1738,8 +1795,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "Система"
 msgstr "Система"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr ""
 msgstr ""
 
 
@@ -1773,7 +1830,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Путь к ключу сертификата SSL"
 msgstr "Путь к ключу сертификата SSL"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1809,8 +1866,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr "URL-адрес неверный"
 msgstr "URL-адрес неверный"
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 #, fuzzy
 #, fuzzy
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr "URL-адрес неверный"
 msgstr "URL-адрес неверный"
@@ -1838,6 +1895,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "Это поле обязательно к заполнению"
 msgstr "Это поле обязательно к заполнению"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1854,10 +1912,14 @@ msgid ""
 "continue?"
 "continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1913,11 +1975,15 @@ msgstr ""
 msgid "User"
 msgid "User"
 msgstr "Пользователь"
 msgstr "Пользователь"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "Имя пользователя"
 msgstr "Имя пользователя"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "Имя пользователя (*)"
 msgstr "Имя пользователя (*)"
 
 
@@ -1931,7 +1997,7 @@ msgstr "Действительный"
 msgid "View"
 msgid "View"
 msgstr "Просмотр"
 msgstr "Просмотр"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Просмотреть все уведомления"
 msgstr "Просмотреть все уведомления"
@@ -1947,7 +2013,7 @@ msgstr "Простой режим"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "Внимание"
 msgstr "Внимание"
 
 
@@ -1980,6 +2046,7 @@ msgstr "Запись сертификата на диск"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "Да"
 msgstr "Да"

+ 165 - 98
app/src/language/vi_VN/app.po

@@ -28,7 +28,8 @@ msgstr "Người dùng"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "Hành động"
 msgstr "Hành động"
 
 
@@ -51,7 +52,7 @@ msgstr "Thêm Directive"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "Thêm Location"
 msgstr "Thêm Location"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "Thêm Website"
 msgstr "Thêm Website"
 
 
@@ -70,11 +71,11 @@ msgstr "Cập nhật thành công"
 msgid "Additional"
 msgid "Additional"
 msgstr "Tùy chọn bổ sung"
 msgstr "Tùy chọn bổ sung"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Nâng cao"
 msgstr "Nâng cao"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +83,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -94,7 +95,12 @@ msgstr ""
 msgid "Arch"
 msgid "Arch"
 msgstr ""
 msgstr ""
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "Bạn chắc chắn muốn xóa nó "
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
@@ -147,6 +153,15 @@ msgstr "Hỏi ChatGPT"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Trợ lý"
 msgstr "Trợ lý"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "Tác giả"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -170,8 +185,8 @@ msgstr "Đã bật tự động gia hạn SSL cho %{name}"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "Quay lại"
 msgstr "Quay lại"
 
 
@@ -180,19 +195,31 @@ msgstr "Quay lại"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "Quay lại"
 msgstr "Quay lại"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "Thông tin"
 msgstr "Thông tin"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
 msgstr "Cơ bản"
 msgstr "Cơ bản"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "Cơ bản"
 msgstr "Cơ bản"
 
 
@@ -280,12 +307,12 @@ msgid "Cleaning environment variables"
 msgstr "Xoá các biến môi trường"
 msgstr "Xoá các biến môi trường"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "Xoá"
 msgstr "Xoá"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 #, fuzzy
 #, fuzzy
 msgid "Cleared successfully"
 msgid "Cleared successfully"
@@ -312,7 +339,7 @@ msgstr "Mẫu Cấu hình"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "Tệp cấu hình được kiểm tra thành công"
 msgstr "Tệp cấu hình được kiểm tra thành công"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "Tên cấu hình"
 msgstr "Tên cấu hình"
 
 
@@ -320,7 +347,7 @@ msgstr "Tên cấu hình"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "Cấu hình"
 msgstr "Cấu hình"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Cấu hình SSL"
 msgstr "Cấu hình SSL"
 
 
@@ -351,7 +378,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "Ngày tạo"
 msgstr "Ngày tạo"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "Tạo thêm"
 msgstr "Tạo thêm"
 
 
@@ -390,7 +417,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Bảng điều khiển"
 msgstr "Bảng điều khiển"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "Tên cơ sở dữ liệu (Tuỳ chọn, Mặc định là: database)"
 msgstr "Tên cơ sở dữ liệu (Tuỳ chọn, Mặc định là: database)"
 
 
@@ -424,15 +451,15 @@ msgstr "Xoá trang web: %{site_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "Đã xoá thành công"
 msgstr "Đã xoá thành công"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Triển khai"
 msgstr "Triển khai"
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr "Triển khai %{conf_name} tới %{node_name} thất bại"
 msgstr "Triển khai %{conf_name} tới %{node_name} thất bại"
 
 
@@ -482,9 +509,9 @@ msgstr "Tắt"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Tắt tự động gia hạn SSL cho %{name} thất bại"
 msgstr "Tắt tự động gia hạn SSL cho %{name} thất bại"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Đã tắt"
 msgstr "Đã tắt"
 
 
@@ -563,7 +590,7 @@ msgstr "Bạn muốn xóa máy chủ này ?"
 msgid "Domain"
 msgid "Domain"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "Tên miền đã được tạo"
 msgstr "Tên miền đã được tạo"
 
 
@@ -585,38 +612,38 @@ msgstr "Đang tải phiên bản mới nhất"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "Đã bật chế độ Dry run"
 msgstr "Đã bật chế độ Dry run"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "Nhân bản"
 msgstr "Nhân bản"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 #, fuzzy
 #, fuzzy
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "Nhân bản thất bại"
 msgstr "Nhân bản thất bại"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 #, fuzzy
 #, fuzzy
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "Nhân bản thành công"
 msgstr "Nhân bản thành công"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 #, fuzzy
 #, fuzzy
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "Đã sao chép thành công vào máy cục bộ"
 msgstr "Đã sao chép thành công vào máy cục bộ"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Sửa %{n}"
 msgstr "Sửa %{n}"
 
 
@@ -638,25 +665,25 @@ msgstr "Sửa trang web"
 msgid "Email"
 msgid "Email"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "Email (*)"
 msgstr "Email (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 #, fuzzy
 #, fuzzy
 msgid "Enable"
 msgid "Enable"
 msgstr "Đã bật"
 msgstr "Đã bật"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "Không thể bật %{conf_name} trên %{node_name}"
 msgstr "Không thể bật %{conf_name} trên %{node_name}"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "Đã bật %{conf_name} trên %{node_name}"
 msgstr "Đã bật %{conf_name} trên %{node_name}"
 
 
@@ -664,12 +691,12 @@ msgstr "Đã bật %{conf_name} trên %{node_name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "Không thể bật tự động gia hạn SSL cho %{name}"
 msgstr "Không thể bật tự động gia hạn SSL cho %{name}"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "Bật không thành công"
 msgstr "Bật không thành công"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 #, fuzzy
 #, fuzzy
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "Đã bật"
 msgstr "Đã bật"
@@ -680,19 +707,19 @@ msgstr "Bật TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "Đã bật"
 msgstr "Đã bật"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "Đã bật"
 msgstr "Đã bật"
@@ -763,7 +790,7 @@ msgstr "Không thể bật %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình."
 msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình."
 
 
@@ -789,7 +816,7 @@ msgstr "Không tìm thấy tệp tin"
 msgid "Filter"
 msgid "Filter"
 msgstr "Lọc"
 msgstr "Lọc"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "Đã hoàn thành"
 msgstr "Đã hoàn thành"
 
 
@@ -862,6 +889,12 @@ msgstr ""
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 #, fuzzy
 #, fuzzy
 msgid "Import"
 msgid "Import"
@@ -872,6 +905,11 @@ msgstr "Xuất"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "Chứng chỉ"
 msgstr "Chứng chỉ"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "Tên người dùng hoặc mật khẩu không chính xác"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr "Thông tin"
 msgstr "Thông tin"
@@ -884,7 +922,7 @@ msgstr "Không thể khởi tạo trình nâng cấp"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "Đang khởi tạo trình nâng cấp"
 msgstr "Đang khởi tạo trình nâng cấp"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "Cài đặt"
 msgstr "Cài đặt"
 
 
@@ -906,6 +944,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr "Hợp lệ"
 msgstr "Hợp lệ"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -940,7 +982,7 @@ msgstr "Kiểm tra lần cuối lúc"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Bỏ trống nếu không thay đổi"
 msgstr "Bỏ trống nếu không thay đổi"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Bỏ trống để sử dụng địa chỉ mặc định: https://api.openai.com/"
 msgstr "Bỏ trống để sử dụng địa chỉ mặc định: https://api.openai.com/"
 
 
@@ -997,11 +1039,11 @@ msgstr "Locations"
 msgid "Log"
 msgid "Log"
 msgstr "Log"
 msgstr "Log"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "Đăng nhập"
 msgstr "Đăng nhập"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "Đăng nhập thành công"
 msgstr "Đăng nhập thành công"
 
 
@@ -1009,7 +1051,7 @@ msgstr "Đăng nhập thành công"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Đã đăng xuất"
 msgstr "Đã đăng xuất"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1053,6 +1095,10 @@ msgstr "Người dùng"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1066,7 +1112,7 @@ msgstr "Memory và Storage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Run Mode"
 msgstr "Run Mode"
@@ -1083,7 +1129,7 @@ msgstr "Sửa"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "Sửa chứng chỉ"
 msgstr "Sửa chứng chỉ"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "Sửa cấu hình"
 msgstr "Sửa cấu hình"
 
 
@@ -1103,12 +1149,12 @@ msgstr "Single Directive"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "Tên"
 msgstr "Tên"
@@ -1135,11 +1181,11 @@ msgstr "Đã có phiên bản mới"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "Tiếp theo"
 msgstr "Tiếp theo"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1147,7 +1193,7 @@ msgstr ""
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Vị trí lưu log truy cập (Access log) của Nginx"
 msgstr "Vị trí lưu log truy cập (Access log) của Nginx"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 #, fuzzy
 #, fuzzy
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Lỗi phân tích cú pháp cấu hình Nginx"
 msgstr "Lỗi phân tích cú pháp cấu hình Nginx"
@@ -1175,7 +1221,7 @@ msgid "Nginx restarted successfully"
 msgstr "Restart Nginx thành công"
 msgstr "Restart Nginx thành công"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1183,6 +1229,7 @@ msgstr "Restart Nginx thành công"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1214,7 +1261,7 @@ msgstr "Ghi chú"
 msgid "Notification"
 msgid "Notification"
 msgstr "Thông báo"
 msgstr "Thông báo"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "Thông báo"
 msgstr "Thông báo"
@@ -1240,7 +1287,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1270,7 +1317,7 @@ msgstr "Sau khi quá trình xác minh hoàn tất, bản ghi sẽ bị xóa."
 msgid "Online"
 msgid "Online"
 msgstr "Trực tuyến"
 msgstr "Trực tuyến"
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1283,13 +1330,13 @@ msgstr "Hệ điều hành"
 msgid "OS:"
 msgid "OS:"
 msgstr "Hệ điều hành:"
 msgstr "Hệ điều hành:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Ghi đè"
 msgstr "Ghi đè"
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Ghi đè tập tin đã tồn tại"
 msgstr "Ghi đè tập tin đã tồn tại"
 
 
@@ -1297,11 +1344,11 @@ msgstr "Ghi đè tập tin đã tồn tại"
 msgid "Params"
 msgid "Params"
 msgstr "Tham số"
 msgstr "Tham số"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "Mật khẩu"
 msgstr "Mật khẩu"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "Mật khẩu (*)"
 msgstr "Mật khẩu (*)"
 
 
@@ -1368,7 +1415,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "Cài đặt"
 msgstr "Cài đặt"
 
 
@@ -1466,7 +1513,16 @@ msgstr "Đang tải lại"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "Tải lại nginx"
 msgstr "Tải lại nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "Xoá thành công"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "Xoá thành công"
 msgstr "Xoá thành công"
@@ -1525,9 +1581,9 @@ msgstr "Running"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "Lưu"
 msgstr "Lưu"
 
 
@@ -1535,7 +1591,7 @@ msgstr "Lưu"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "Lưu Directive"
 msgstr "Lưu Directive"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "Đã xảy ra lỗi khi lưu %{msg}"
 msgstr "Đã xảy ra lỗi khi lưu %{msg}"
@@ -1543,15 +1599,15 @@ msgstr "Đã xảy ra lỗi khi lưu %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Lưu thành công"
 msgstr "Lưu thành công"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "Lưu thành công"
 msgstr "Lưu thành công"
 
 
@@ -1576,8 +1632,9 @@ msgstr "Gửi"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "Lỗi máy chủ"
 msgstr "Lỗi máy chủ"
@@ -1596,7 +1653,7 @@ msgid "server_name not found in directives"
 msgstr "không tìm thấy server_name trong directives"
 msgstr "không tìm thấy server_name trong directives"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "Tham số server_name là bắt buộc"
 msgstr "Tham số server_name là bắt buộc"
 
 
@@ -1650,7 +1707,7 @@ msgstr ""
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr ""
 msgstr ""
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr ""
 msgstr ""
 
 
@@ -1736,8 +1793,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "Thông tin"
 msgstr "Thông tin"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr "Mục tiêu"
 msgstr "Mục tiêu"
 
 
@@ -1770,7 +1827,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1803,8 +1860,8 @@ msgstr ""
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
@@ -1830,6 +1887,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "Trường này không được để trống"
 msgstr "Trường này không được để trống"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1850,10 +1908,14 @@ msgstr ""
 "quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1909,11 +1971,15 @@ msgstr ""
 msgid "User"
 msgid "User"
 msgstr "Người dùng"
 msgstr "Người dùng"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "Username"
 msgstr "Username"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "Username (*)"
 msgstr "Username (*)"
 
 
@@ -1927,7 +1993,7 @@ msgstr "Hợp lệ"
 msgid "View"
 msgid "View"
 msgstr "Xem"
 msgstr "Xem"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "Xem tất cả thông báo"
 msgstr "Xem tất cả thông báo"
@@ -1944,7 +2010,7 @@ msgstr "Cơ bản"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "Lưu ý"
 msgstr "Lưu ý"
 
 
@@ -1979,6 +2045,7 @@ msgstr "Ghi chứng chỉ vào disk"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "Có"
 msgstr "Có"

BIN
app/src/language/zh_CN/app.mo


+ 163 - 98
app/src/language/zh_CN/app.po

@@ -31,7 +31,8 @@ msgstr "ACME 用户"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "操作"
 msgstr "操作"
 
 
@@ -54,7 +55,7 @@ msgstr "在下面添加指令"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "添加 Location"
 msgstr "添加 Location"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "添加站点"
 msgstr "添加站点"
 
 
@@ -70,11 +71,11 @@ msgstr "添加成功"
 msgid "Additional"
 msgid "Additional"
 msgstr "额外选项"
 msgstr "额外选项"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "高级模式"
 msgstr "高级模式"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 地址"
 msgstr "API 地址"
 
 
@@ -82,11 +83,11 @@ msgstr "API 地址"
 msgid "API Document"
 msgid "API Document"
 msgstr "API 文档"
 msgstr "API 文档"
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 代理"
 msgstr "API 代理"
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr "API Token"
 msgstr "API Token"
 
 
@@ -94,7 +95,11 @@ msgstr "API Token"
 msgid "Arch"
 msgid "Arch"
 msgstr "架构"
 msgstr "架构"
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "您确定要立即删除这个被禁用的 IP 吗?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "您确定要清除所有通知吗?"
 msgstr "您确定要清除所有通知吗?"
@@ -139,6 +144,14 @@ msgstr "与ChatGPT聊天"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "助手"
 msgstr "助手"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr "尝试次数"
+
+#: src/views/preference/Preference.vue:116
+msgid "Auth"
+msgstr "认证"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -162,8 +175,8 @@ msgstr "成功启用 %{name} 自动续签"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "返回"
 msgstr "返回"
 
 
@@ -171,18 +184,30 @@ msgstr "返回"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "返回首页"
 msgstr "返回首页"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr "禁止阈值(分钟)"
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr "禁止 IP 列表"
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr "禁用至"
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "基本信息"
 msgstr "基本信息"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "基本"
 msgstr "基本"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "基本模式"
 msgstr "基本模式"
 
 
@@ -265,12 +290,12 @@ msgid "Cleaning environment variables"
 msgstr "正在清理环境变量"
 msgstr "正在清理环境变量"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "清空"
 msgstr "清空"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 msgid "Cleared successfully"
 msgid "Cleared successfully"
 msgstr "清除成功"
 msgstr "清除成功"
@@ -294,7 +319,7 @@ msgstr "配置"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "配置文件测试成功"
 msgstr "配置文件测试成功"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "配置名称"
 msgstr "配置名称"
 
 
@@ -302,7 +327,7 @@ msgstr "配置名称"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "配置"
 msgstr "配置"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "配置 SSL"
 msgstr "配置 SSL"
 
 
@@ -332,7 +357,7 @@ msgstr "CPU:"
 msgid "Create"
 msgid "Create"
 msgstr "创建"
 msgstr "创建"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "再创建一个"
 msgstr "再创建一个"
 
 
@@ -371,7 +396,7 @@ msgstr "自定义显示在环境指示器中的本地服务器名称。"
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "仪表盘"
 msgstr "仪表盘"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "数据库 (可选,默认: database)"
 msgstr "数据库 (可选,默认: database)"
 
 
@@ -403,15 +428,15 @@ msgstr "删除 Stream: %{stream_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "删除成功"
 msgstr "删除成功"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr "部署"
 msgstr "部署"
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr "部署%{conf_name}到%{node_name}失败"
 msgstr "部署%{conf_name}到%{node_name}失败"
 
 
@@ -458,9 +483,9 @@ msgstr "禁用"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "关闭 %{name} 自动续签失败"
 msgstr "关闭 %{name} 自动续签失败"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "禁用"
 msgstr "禁用"
 
 
@@ -530,7 +555,7 @@ msgstr "你想删除这个 Upstream 吗?"
 msgid "Domain"
 msgid "Domain"
 msgstr "域名"
 msgstr "域名"
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "域名配置文件创建成功"
 msgstr "域名配置文件创建成功"
 
 
@@ -550,34 +575,34 @@ msgstr "下载最新版本"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "试运行模式已启动"
 msgstr "试运行模式已启动"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "复制"
 msgstr "复制"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "成功地将%{conf_name}复制到%{node_name}"
 msgstr "成功地将%{conf_name}复制到%{node_name}"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "复制失败"
 msgstr "复制失败"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "复制成功"
 msgstr "复制成功"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "成功复制到本地"
 msgstr "成功复制到本地"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "编辑 %{n}"
 msgstr "编辑 %{n}"
 
 
@@ -597,24 +622,24 @@ msgstr "编辑 Stream"
 msgid "Email"
 msgid "Email"
 msgstr "邮箱"
 msgstr "邮箱"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "邮箱 (*)"
 msgstr "邮箱 (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 msgid "Enable"
 msgid "Enable"
 msgstr "启用"
 msgstr "启用"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "在%{node_name}中启用%{conf_name}失败"
 msgstr "在%{node_name}中启用%{conf_name}失败"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "成功启用%{node_name}中的%{conf_name}"
 msgstr "成功启用%{node_name}中的%{conf_name}"
 
 
@@ -622,12 +647,12 @@ msgstr "成功启用%{node_name}中的%{conf_name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "启用 %{name} 自动续签失败"
 msgstr "启用 %{name} 自动续签失败"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "启用失败"
 msgstr "启用失败"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "启用成功"
 msgstr "启用成功"
 
 
@@ -637,19 +662,19 @@ msgstr "启用 TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "启用"
 msgstr "启用"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "启用成功"
 msgstr "启用成功"
@@ -716,7 +741,7 @@ msgstr "启用失败 %{msg}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "获取证书信息失败"
 msgstr "获取证书信息失败"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "保存失败,在配置中检测到语法错误。"
 msgstr "保存失败,在配置中检测到语法错误。"
 
 
@@ -741,7 +766,7 @@ msgstr "未找到文件"
 msgid "Filter"
 msgid "Filter"
 msgstr "过滤"
 msgstr "过滤"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "完成"
 msgstr "完成"
 
 
@@ -809,6 +834,14 @@ msgstr "HTTP01"
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr "如果留空,则使用默认 CA Dir。"
 msgstr "如果留空,则使用默认 CA Dir。"
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+"如果某个 IP 的登录失败次数达到禁用阈值分钟内的最大尝试次数,该 IP 将被禁止登"
+"录一段时间。"
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 msgid "Import"
 msgid "Import"
 msgstr "导入"
 msgstr "导入"
@@ -817,6 +850,10 @@ msgstr "导入"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "导入证书"
 msgstr "导入证书"
 
 
+#: src/views/other/Login.vue:59
+msgid "Incorrect username or password"
+msgstr "用户名或密码错误"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr "信息"
 msgstr "信息"
@@ -829,7 +866,7 @@ msgstr "初始化核心升级程序错误"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "初始化核心升级器"
 msgstr "初始化核心升级器"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "安装"
 msgstr "安装"
 
 
@@ -849,6 +886,10 @@ msgstr "间隔"
 msgid "Invalid"
 msgid "Invalid"
 msgstr "无效的"
 msgstr "无效的"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr "IP"
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
 msgstr "签发通配符证书"
 msgstr "签发通配符证书"
@@ -879,7 +920,7 @@ msgstr "最后检查时间"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 msgstr "留空表示不修改"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "留空为默认:https://api.openai.com/"
 msgstr "留空为默认:https://api.openai.com/"
 
 
@@ -930,11 +971,11 @@ msgstr "Locations"
 msgid "Log"
 msgid "Log"
 msgstr "日志"
 msgstr "日志"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "登录"
 msgstr "登录"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "登录成功"
 msgstr "登录成功"
 
 
@@ -942,7 +983,7 @@ msgstr "登录成功"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "登出成功"
 msgstr "登出成功"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr "Logrotate"
 msgstr "Logrotate"
 
 
@@ -988,6 +1029,10 @@ msgstr "用户管理"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "托管证书"
 msgstr "托管证书"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr "最大尝试次数"
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1001,7 +1046,7 @@ msgstr "内存与存储"
 msgid "Minutes"
 msgid "Minutes"
 msgstr "分钟"
 msgstr "分钟"
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 msgid "Model"
 msgid "Model"
 msgstr "模型"
 msgstr "模型"
 
 
@@ -1015,7 +1060,7 @@ msgstr "修改"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "修改证书"
 msgstr "修改证书"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "修改配置文件"
 msgstr "修改配置文件"
 
 
@@ -1033,12 +1078,12 @@ msgstr "多行指令"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "名称"
 msgstr "名称"
@@ -1065,11 +1110,11 @@ msgstr "新版本发布"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "下一步"
 msgstr "下一步"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1077,7 +1122,7 @@ msgstr "Nginx"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Nginx 访问日志路径"
 msgstr "Nginx 访问日志路径"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 配置解析错误"
 msgstr "Nginx 配置解析错误"
 
 
@@ -1102,7 +1147,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx 重启成功"
 msgstr "Nginx 重启成功"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1110,6 +1155,7 @@ msgstr "Nginx 重启成功"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1140,7 +1186,7 @@ msgstr "注意"
 msgid "Notification"
 msgid "Notification"
 msgstr "通知"
 msgstr "通知"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 msgid "Notifications"
 msgid "Notifications"
 msgstr "通知"
 msgstr "通知"
 
 
@@ -1164,7 +1210,7 @@ msgid "Ok"
 msgstr "确定"
 msgstr "确定"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1194,7 +1240,7 @@ msgstr "一旦验证完成,这些记录将被删除。"
 msgid "Online"
 msgid "Online"
 msgstr "在线"
 msgstr "在线"
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1206,13 +1252,13 @@ msgstr "OS"
 msgid "OS:"
 msgid "OS:"
 msgstr "OS:"
 msgstr "OS:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "覆盖"
 msgstr "覆盖"
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "覆盖现有文件"
 msgstr "覆盖现有文件"
 
 
@@ -1220,11 +1266,11 @@ msgstr "覆盖现有文件"
 msgid "Params"
 msgid "Params"
 msgstr "参数"
 msgstr "参数"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "密码"
 msgstr "密码"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "密码 (*)"
 msgstr "密码 (*)"
 
 
@@ -1289,7 +1335,7 @@ msgstr "请至少选择一个节点!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "预发布"
 msgstr "预发布"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "偏好设置"
 msgstr "偏好设置"
 
 
@@ -1380,7 +1426,15 @@ msgstr "重载中"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "正在重载 Nginx"
 msgstr "正在重载 Nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr "删除"
+
+#: src/views/preference/AuthSettings.vue:47
+msgid "Remove successfully"
+msgstr "移除成功"
+
+#: src/components/Notification/Notification.vue:52
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "删除成功"
 msgstr "删除成功"
 
 
@@ -1432,9 +1486,9 @@ msgstr "运行中"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "保存"
 msgstr "保存"
 
 
@@ -1442,7 +1496,7 @@ msgstr "保存"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "保存指令"
 msgstr "保存指令"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "保存错误 %{msg}"
 msgstr "保存错误 %{msg}"
@@ -1450,14 +1504,14 @@ msgstr "保存错误 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "保存成功"
 msgstr "保存成功"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "保存成功"
 msgstr "保存成功"
 
 
@@ -1482,8 +1536,9 @@ msgstr "上传"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "服务器错误"
 msgstr "服务器错误"
@@ -1501,7 +1556,7 @@ msgid "server_name not found in directives"
 msgstr "未在指令集合中找到 server_name"
 msgstr "未在指令集合中找到 server_name"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "必须为 server_name 指令指明参数"
 msgstr "必须为 server_name 指令指明参数"
 
 
@@ -1553,7 +1608,7 @@ msgstr "SSL证书密钥路径"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "SSL证书路径"
 msgstr "SSL证书路径"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "SSO 登录"
 msgstr "SSO 登录"
 
 
@@ -1633,8 +1688,8 @@ msgstr "同步到"
 msgid "System"
 msgid "System"
 msgstr "系统"
 msgstr "系统"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr "目标"
 msgstr "目标"
 
 
@@ -1666,7 +1721,7 @@ msgstr "输入的内容不是 SSL 证书"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "输入的内容不是 SSL 证书密钥"
 msgstr "输入的内容不是 SSL 证书密钥"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1697,8 +1752,8 @@ msgstr "当前配置中的 server_name 必须是获取证书所需的域名,
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr "URL无效"
 msgstr "URL无效"
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr "URL 无效."
 msgstr "URL 无效."
 
 
@@ -1724,6 +1779,7 @@ msgstr "此字段必填"
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "该字段不能为空"
 msgstr "该字段不能为空"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr "提示"
 msgstr "提示"
@@ -1742,10 +1798,14 @@ msgstr ""
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "Token 无效"
 msgstr "Token 无效"
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr "登录失败次数过多,请稍后再试"
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr "回收站"
 msgstr "回收站"
@@ -1798,11 +1858,15 @@ msgstr "URL"
 msgid "User"
 msgid "User"
 msgstr "用户"
 msgstr "用户"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr "用户被禁止"
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "用户名"
 msgstr "用户名"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "用户名 (*)"
 msgstr "用户名 (*)"
 
 
@@ -1816,7 +1880,7 @@ msgstr "有效的"
 msgid "View"
 msgid "View"
 msgstr "查看"
 msgstr "查看"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "查看全部通知"
 msgstr "查看全部通知"
 
 
@@ -1830,7 +1894,7 @@ msgstr "预览模式"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "警告"
 msgstr "警告"
 
 
@@ -1862,6 +1926,7 @@ msgstr "正在将证书写入磁盘"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "是的"
 msgstr "是的"

+ 165 - 98
app/src/language/zh_TW/app.po

@@ -33,7 +33,8 @@ msgstr "使用者名稱"
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:33 src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:37
 #: src/views/notification/Notification.vue:37
-#: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
+#: src/views/preference/AuthSettings.vue:26 src/views/stream/StreamList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
 msgstr "操作"
 msgstr "操作"
 
 
@@ -56,7 +57,7 @@ msgstr "在下方新增指令"
 msgid "Add Location"
 msgid "Add Location"
 msgstr "新增 Location"
 msgstr "新增 Location"
 
 
-#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:93
+#: src/routes/index.ts:64 src/views/domain/DomainAdd.vue:89
 msgid "Add Site"
 msgid "Add Site"
 msgstr "新增網站"
 msgstr "新增網站"
 
 
@@ -74,11 +75,11 @@ msgstr "更新成功"
 msgid "Additional"
 msgid "Additional"
 msgstr "其他設定"
 msgstr "其他設定"
 
 
-#: src/views/domain/DomainEdit.vue:199 src/views/stream/StreamEdit.vue:191
+#: src/views/domain/DomainEdit.vue:197 src/views/stream/StreamEdit.vue:189
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "進階模式"
 msgstr "進階模式"
 
 
-#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:45
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 基礎網址"
 msgstr "API 基礎網址"
 
 
@@ -87,11 +88,11 @@ msgstr "API 基礎網址"
 msgid "API Document"
 msgid "API Document"
 msgstr "API Token"
 msgstr "API Token"
 
 
-#: src/views/preference/OpenAISettings.vue:54
+#: src/views/preference/OpenAISettings.vue:57
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 代理"
 msgstr "API 代理"
 
 
-#: src/views/preference/OpenAISettings.vue:66
+#: src/views/preference/OpenAISettings.vue:69
 msgid "API Token"
 msgid "API Token"
 msgstr "API Token"
 msgstr "API Token"
 
 
@@ -99,7 +100,12 @@ msgstr "API Token"
 msgid "Arch"
 msgid "Arch"
 msgstr "架構"
 msgstr "架構"
 
 
-#: src/components/Notification/Notification.vue:84
+#: src/views/preference/AuthSettings.vue:94
+#, fuzzy
+msgid "Are you sure to delete this banned IP immediately?"
+msgstr "您確定要刪除嗎?"
+
+#: src/components/Notification/Notification.vue:86
 #: src/views/notification/Notification.vue:72
 #: src/views/notification/Notification.vue:72
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
@@ -149,6 +155,15 @@ msgstr "向 ChatGPT 尋求幫助"
 msgid "Assistant"
 msgid "Assistant"
 msgstr "助理"
 msgstr "助理"
 
 
+#: src/views/preference/AuthSettings.vue:17
+msgid "Attempts"
+msgstr ""
+
+#: src/views/preference/Preference.vue:116
+#, fuzzy
+msgid "Auth"
+msgstr "作者"
+
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:106
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:120
 msgid "Author"
 msgid "Author"
@@ -172,8 +187,8 @@ msgstr "已啟用 %{name} 的自動續簽"
 
 
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
 #: src/views/config/Config.vue:73 src/views/config/ConfigEdit.vue:87
-#: src/views/domain/DomainEdit.vue:256 src/views/nginx_log/NginxLog.vue:168
-#: src/views/stream/StreamEdit.vue:247
+#: src/views/domain/DomainEdit.vue:254 src/views/nginx_log/NginxLog.vue:168
+#: src/views/stream/StreamEdit.vue:245
 msgid "Back"
 msgid "Back"
 msgstr "返回"
 msgstr "返回"
 
 
@@ -181,18 +196,30 @@ msgstr "返回"
 msgid "Back Home"
 msgid "Back Home"
 msgstr "返回首頁"
 msgstr "返回首頁"
 
 
-#: src/views/domain/DomainAdd.vue:99
+#: src/views/preference/AuthSettings.vue:68
+msgid "Ban Threshold Minutes"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:82
+msgid "Banned IPs"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:20
+msgid "Banned Until"
+msgstr ""
+
+#: src/views/domain/DomainAdd.vue:95
 msgid "Base information"
 msgid "Base information"
 msgstr "基本資訊"
 msgstr "基本資訊"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:101
+#: src/views/preference/Preference.vue:110
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "基本"
 msgstr "基本"
 
 
-#: src/views/domain/DomainEdit.vue:202 src/views/stream/StreamEdit.vue:194
+#: src/views/domain/DomainEdit.vue:200 src/views/stream/StreamEdit.vue:192
 msgid "Basic Mode"
 msgid "Basic Mode"
 msgstr "基本模式"
 msgstr "基本模式"
 
 
@@ -278,12 +305,12 @@ msgid "Cleaning environment variables"
 msgstr "清理環境變數"
 msgstr "清理環境變數"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/ChatGPT/ChatGPT.vue:276
-#: src/components/Notification/Notification.vue:89
+#: src/components/Notification/Notification.vue:91
 #: src/views/notification/Notification.vue:77
 #: src/views/notification/Notification.vue:77
 msgid "Clear"
 msgid "Clear"
 msgstr "清除"
 msgstr "清除"
 
 
-#: src/components/Notification/Notification.vue:40
+#: src/components/Notification/Notification.vue:42
 #: src/views/notification/Notification.vue:46
 #: src/views/notification/Notification.vue:46
 #, fuzzy
 #, fuzzy
 msgid "Cleared successfully"
 msgid "Cleared successfully"
@@ -309,7 +336,7 @@ msgstr "設定模板"
 msgid "Configuration file is test successful"
 msgid "Configuration file is test successful"
 msgstr "設定檔案測試成功"
 msgstr "設定檔案測試成功"
 
 
-#: src/views/domain/DomainAdd.vue:105
+#: src/views/domain/DomainAdd.vue:101
 msgid "Configuration Name"
 msgid "Configuration Name"
 msgstr "設定名稱"
 msgstr "設定名稱"
 
 
@@ -317,7 +344,7 @@ msgstr "設定名稱"
 msgid "Configurations"
 msgid "Configurations"
 msgstr "設定"
 msgstr "設定"
 
 
-#: src/views/domain/DomainAdd.vue:100
+#: src/views/domain/DomainAdd.vue:96
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "設定 SSL"
 msgstr "設定 SSL"
 
 
@@ -348,7 +375,7 @@ msgstr "中央處理器:"
 msgid "Create"
 msgid "Create"
 msgstr "建立時間"
 msgstr "建立時間"
 
 
-#: src/views/domain/DomainAdd.vue:158
+#: src/views/domain/DomainAdd.vue:154
 msgid "Create Another"
 msgid "Create Another"
 msgstr "再建立一個"
 msgstr "再建立一個"
 
 
@@ -387,7 +414,7 @@ msgstr ""
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "儀表板"
 msgstr "儀表板"
 
 
-#: src/views/other/Install.vue:121
+#: src/views/other/Install.vue:120
 msgid "Database (Optional, default: database)"
 msgid "Database (Optional, default: database)"
 msgstr "資料庫 (可選,預設: database)"
 msgstr "資料庫 (可選,預設: database)"
 
 
@@ -421,15 +448,15 @@ msgstr "刪除網站:%{site_name}"
 msgid "Deleted successfully"
 msgid "Deleted successfully"
 msgstr "成功停用"
 msgstr "成功停用"
 
 
-#: src/views/domain/components/Deploy.vue:106
+#: src/views/domain/components/Deploy.vue:103
 #: src/views/domain/components/RightSettings.vue:93
 #: src/views/domain/components/RightSettings.vue:93
-#: src/views/stream/components/Deploy.vue:106
+#: src/views/stream/components/Deploy.vue:103
 #: src/views/stream/components/RightSettings.vue:92
 #: src/views/stream/components/RightSettings.vue:92
 msgid "Deploy"
 msgid "Deploy"
 msgstr "部署"
 msgstr "部署"
 
 
-#: src/views/domain/components/Deploy.vue:63
-#: src/views/stream/components/Deploy.vue:63
+#: src/views/domain/components/Deploy.vue:60
+#: src/views/stream/components/Deploy.vue:60
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgid "Deploy %{conf_name} to %{node_name} failed"
 msgstr "部署 %{conf_name} 至 %{node_name} 失敗"
 msgstr "部署 %{conf_name} 至 %{node_name} 失敗"
 
 
@@ -477,9 +504,9 @@ msgstr "停用"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "關閉 %{name} 自動續簽失敗"
 msgstr "關閉 %{name} 自動續簽失敗"
 
 
-#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:183
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
 #: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
-#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
+#: src/views/stream/StreamEdit.vue:175 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "停用"
 msgstr "停用"
 
 
@@ -552,7 +579,7 @@ msgstr "您要移除此伺服器嗎?"
 msgid "Domain"
 msgid "Domain"
 msgstr "網域"
 msgstr "網域"
 
 
-#: src/views/domain/DomainAdd.vue:148
+#: src/views/domain/DomainAdd.vue:144
 msgid "Domain Config Created Successfully"
 msgid "Domain Config Created Successfully"
 msgstr "網域設定檔成功建立"
 msgstr "網域設定檔成功建立"
 
 
@@ -573,34 +600,34 @@ msgstr "正在下載最新版本"
 msgid "Dry run mode enabled"
 msgid "Dry run mode enabled"
 msgstr "試運轉模式已啟用"
 msgstr "試運轉模式已啟用"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:126
+#: src/views/domain/components/SiteDuplicate.vue:122
 #: src/views/domain/DomainList.vue:140
 #: src/views/domain/DomainList.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:126
+#: src/views/stream/components/StreamDuplicate.vue:122
 #: src/views/stream/StreamList.vue:161
 #: src/views/stream/StreamList.vue:161
 msgid "Duplicate"
 msgid "Duplicate"
 msgstr "複製"
 msgstr "複製"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:84
-#: src/views/stream/components/StreamDuplicate.vue:84
+#: src/views/domain/components/SiteDuplicate.vue:82
+#: src/views/stream/components/StreamDuplicate.vue:82
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgid "Duplicate %{conf_name} to %{node_name} successfully"
 msgstr "成功複製 %{conf_name} 到 %{node_name}"
 msgstr "成功複製 %{conf_name} 到 %{node_name}"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:90
-#: src/views/stream/components/StreamDuplicate.vue:90
+#: src/views/domain/components/SiteDuplicate.vue:87
+#: src/views/stream/components/StreamDuplicate.vue:87
 msgid "Duplicate failed"
 msgid "Duplicate failed"
 msgstr "複製失敗"
 msgstr "複製失敗"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:82
+#: src/views/domain/components/SiteDuplicate.vue:80
+#: src/views/stream/components/StreamDuplicate.vue:80
 msgid "Duplicate successfully"
 msgid "Duplicate successfully"
 msgstr "複製成功"
 msgstr "複製成功"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:64
-#: src/views/stream/components/StreamDuplicate.vue:64
+#: src/views/domain/components/SiteDuplicate.vue:63
+#: src/views/stream/components/StreamDuplicate.vue:63
 msgid "Duplicate to local successfully"
 msgid "Duplicate to local successfully"
 msgstr "成功複製至本機"
 msgstr "成功複製至本機"
 
 
-#: src/views/domain/DomainEdit.vue:174 src/views/stream/StreamEdit.vue:166
+#: src/views/domain/DomainEdit.vue:172 src/views/stream/StreamEdit.vue:164
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "編輯 %{n}"
 msgstr "編輯 %{n}"
 
 
@@ -622,24 +649,24 @@ msgstr "編輯網站"
 msgid "Email"
 msgid "Email"
 msgstr "電子郵件 (*)"
 msgstr "電子郵件 (*)"
 
 
-#: src/views/other/Install.vue:90
+#: src/views/other/Install.vue:89
 msgid "Email (*)"
 msgid "Email (*)"
 msgstr "電子郵件 (*)"
 msgstr "電子郵件 (*)"
 
 
-#: src/views/domain/components/Deploy.vue:86
+#: src/views/domain/components/Deploy.vue:83
 #: src/views/domain/DomainList.vue:132
 #: src/views/domain/DomainList.vue:132
-#: src/views/stream/components/Deploy.vue:86
+#: src/views/stream/components/Deploy.vue:83
 #: src/views/stream/StreamList.vue:153
 #: src/views/stream/StreamList.vue:153
 msgid "Enable"
 msgid "Enable"
 msgstr "啟用"
 msgstr "啟用"
 
 
-#: src/views/domain/components/Deploy.vue:52
-#: src/views/stream/components/Deploy.vue:52
+#: src/views/domain/components/Deploy.vue:50
+#: src/views/stream/components/Deploy.vue:50
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgid "Enable %{conf_name} in %{node_name} failed"
 msgstr "在 %{node_name} 啟用 %{conf_name} 失敗"
 msgstr "在 %{node_name} 啟用 %{conf_name} 失敗"
 
 
-#: src/views/domain/components/Deploy.vue:46
-#: src/views/stream/components/Deploy.vue:46
+#: src/views/domain/components/Deploy.vue:45
+#: src/views/stream/components/Deploy.vue:45
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "成功在 %{node_name} 啟用 %{conf_name}"
 msgstr "成功在 %{node_name} 啟用 %{conf_name}"
 
 
@@ -647,12 +674,12 @@ msgstr "成功在 %{node_name} 啟用 %{conf_name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "啟用 %{name} 自動續簽失敗"
 msgstr "啟用 %{name} 自動續簽失敗"
 
 
-#: src/views/domain/DomainAdd.vue:46
+#: src/views/domain/DomainAdd.vue:43
 msgid "Enable failed"
 msgid "Enable failed"
 msgstr "啟用失敗"
 msgstr "啟用失敗"
 
 
-#: src/views/domain/components/Deploy.vue:44
-#: src/views/stream/components/Deploy.vue:44
+#: src/views/domain/components/Deploy.vue:43
+#: src/views/stream/components/Deploy.vue:43
 msgid "Enable successfully"
 msgid "Enable successfully"
 msgstr "啟用成功"
 msgstr "啟用成功"
 
 
@@ -662,19 +689,19 @@ msgstr "啟用 TLS"
 
 
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
-#: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/domain/DomainEdit.vue:177 src/views/domain/DomainList.vue:29
 #: src/views/environment/Environment.vue:102
 #: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
-#: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
+#: src/views/stream/StreamEdit.vue:169 src/views/stream/StreamList.vue:29
 msgid "Enabled"
 msgid "Enabled"
 msgstr "已啟用"
 msgstr "已啟用"
 
 
 #: src/views/domain/components/RightSettings.vue:29
 #: src/views/domain/components/RightSettings.vue:29
-#: src/views/domain/components/SiteDuplicate.vue:98
-#: src/views/domain/DomainAdd.vue:42 src/views/domain/DomainList.vue:57
+#: src/views/domain/components/SiteDuplicate.vue:94
+#: src/views/domain/DomainAdd.vue:40 src/views/domain/DomainList.vue:57
 #: src/views/stream/components/RightSettings.vue:29
 #: src/views/stream/components/RightSettings.vue:29
-#: src/views/stream/components/StreamDuplicate.vue:98
+#: src/views/stream/components/StreamDuplicate.vue:94
 #: src/views/stream/StreamList.vue:57
 #: src/views/stream/StreamList.vue:57
 msgid "Enabled successfully"
 msgid "Enabled successfully"
 msgstr "成功啟用"
 msgstr "成功啟用"
@@ -744,7 +771,7 @@ msgstr "啟用 %{msg} 失敗"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "取得憑證資訊失敗"
 msgstr "取得憑證資訊失敗"
 
 
-#: src/views/domain/DomainEdit.vue:132 src/views/stream/StreamEdit.vue:124
+#: src/views/domain/DomainEdit.vue:130 src/views/stream/StreamEdit.vue:122
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "儲存失敗,在設定中檢測到語法錯誤。"
 msgstr "儲存失敗,在設定中檢測到語法錯誤。"
 
 
@@ -770,7 +797,7 @@ msgstr "找不到檔案"
 msgid "Filter"
 msgid "Filter"
 msgstr "篩選"
 msgstr "篩選"
 
 
-#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:101
+#: src/language/constants.ts:19 src/views/domain/DomainAdd.vue:97
 msgid "Finished"
 msgid "Finished"
 msgstr "完成"
 msgstr "完成"
 
 
@@ -840,6 +867,12 @@ msgstr "HTTP01"
 msgid "If left blank, the default CA Dir will be used."
 msgid "If left blank, the default CA Dir will be used."
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/AuthSettings.vue:60
+msgid ""
+"If the number of login failed attempts from a ip reach the max attempts in "
+"ban threshold minutes, the ip will be banned for a period of time."
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:136
 #: src/views/certificate/Certificate.vue:136
 #, fuzzy
 #, fuzzy
 msgid "Import"
 msgid "Import"
@@ -850,6 +883,11 @@ msgstr "匯出"
 msgid "Import Certificate"
 msgid "Import Certificate"
 msgstr "憑證狀態"
 msgstr "憑證狀態"
 
 
+#: src/views/other/Login.vue:59
+#, fuzzy
+msgid "Incorrect username or password"
+msgstr "使用者名稱或密碼不正確"
+
 #: src/constants/index.ts:18
 #: src/constants/index.ts:18
 msgid "Info"
 msgid "Info"
 msgstr ""
 msgstr ""
@@ -862,7 +900,7 @@ msgstr "初始化核心升級程式錯誤"
 msgid "Initialing core upgrader"
 msgid "Initialing core upgrader"
 msgstr "正在初始化核心升級程式"
 msgstr "正在初始化核心升級程式"
 
 
-#: src/routes/index.ts:273 src/views/other/Install.vue:136
+#: src/routes/index.ts:273 src/views/other/Install.vue:135
 msgid "Install"
 msgid "Install"
 msgstr "安裝"
 msgstr "安裝"
 
 
@@ -883,6 +921,10 @@ msgstr ""
 msgid "Invalid"
 msgid "Invalid"
 msgstr "無效的郵箱!"
 msgstr "無效的郵箱!"
 
 
+#: src/views/preference/AuthSettings.vue:14
+msgid "IP"
+msgstr ""
+
 #: src/views/certificate/Certificate.vue:144
 #: src/views/certificate/Certificate.vue:144
 #, fuzzy
 #, fuzzy
 msgid "Issue wildcard certificate"
 msgid "Issue wildcard certificate"
@@ -916,7 +958,7 @@ msgstr "上次檢查時間"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 msgstr "留空表示不修改"
 
 
-#: src/views/preference/OpenAISettings.vue:50
+#: src/views/preference/OpenAISettings.vue:53
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "預設留空:https://api.openai.com/"
 msgstr "預設留空:https://api.openai.com/"
 
 
@@ -972,11 +1014,11 @@ msgstr "Locations"
 msgid "Log"
 msgid "Log"
 msgstr "登入"
 msgstr "登入"
 
 
-#: src/routes/index.ts:279 src/views/other/Login.vue:147
+#: src/routes/index.ts:279 src/views/other/Login.vue:159
 msgid "Login"
 msgid "Login"
 msgstr "登入"
 msgstr "登入"
 
 
-#: src/views/other/Login.vue:51 src/views/other/Login.vue:97
+#: src/views/other/Login.vue:109 src/views/other/Login.vue:51
 msgid "Login successful"
 msgid "Login successful"
 msgstr "登入成功"
 msgstr "登入成功"
 
 
@@ -984,7 +1026,7 @@ msgstr "登入成功"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "登出成功"
 msgstr "登出成功"
 
 
-#: src/views/preference/Preference.vue:119
+#: src/views/preference/Preference.vue:134
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1027,6 +1069,10 @@ msgstr "管理使用者"
 msgid "Managed Certificate"
 msgid "Managed Certificate"
 msgstr "更換憑證"
 msgstr "更換憑證"
 
 
+#: src/views/preference/AuthSettings.vue:74
+msgid "Max Attempts"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:218
 #: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
@@ -1040,7 +1086,7 @@ msgstr "記憶體與儲存"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:30
+#: src/views/preference/OpenAISettings.vue:33
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "執行模式"
 msgstr "執行模式"
@@ -1056,7 +1102,7 @@ msgstr "修改"
 msgid "Modify Certificate"
 msgid "Modify Certificate"
 msgstr "憑證狀態"
 msgstr "憑證狀態"
 
 
-#: src/views/domain/DomainAdd.vue:155
+#: src/views/domain/DomainAdd.vue:151
 msgid "Modify Config"
 msgid "Modify Config"
 msgstr "修改設定"
 msgstr "修改設定"
 
 
@@ -1075,12 +1121,12 @@ msgstr "多行指令"
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:11 src/views/config/config.ts:7
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
-#: src/views/domain/components/SiteDuplicate.vue:133
+#: src/views/domain/components/SiteDuplicate.vue:129
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/domain/ngx_conf/NgxUpstream.vue:175
 #: src/views/environment/Environment.vue:12
 #: src/views/environment/Environment.vue:12
 #: src/views/stream/components/RightSettings.vue:82
 #: src/views/stream/components/RightSettings.vue:82
-#: src/views/stream/components/StreamDuplicate.vue:133
+#: src/views/stream/components/StreamDuplicate.vue:129
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 #: src/views/stream/StreamList.vue:13 src/views/stream/StreamList.vue:187
 msgid "Name"
 msgid "Name"
 msgstr "名稱"
 msgstr "名稱"
@@ -1107,11 +1153,11 @@ msgstr "新版本發布"
 
 
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/certificate/WildcardCertificate.vue:99
 #: src/views/domain/cert/components/ObtainCert.vue:203
 #: src/views/domain/cert/components/ObtainCert.vue:203
-#: src/views/domain/DomainAdd.vue:142
+#: src/views/domain/DomainAdd.vue:138
 msgid "Next"
 msgid "Next"
 msgstr "下一步"
 msgstr "下一步"
 
 
-#: src/views/preference/Preference.vue:107
+#: src/views/preference/Preference.vue:122
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1119,7 +1165,7 @@ msgstr "Nginx"
 msgid "Nginx Access Log Path"
 msgid "Nginx Access Log Path"
 msgstr "Nginx 存取日誌路徑"
 msgstr "Nginx 存取日誌路徑"
 
 
-#: src/views/domain/DomainEdit.vue:217 src/views/stream/StreamEdit.vue:209
+#: src/views/domain/DomainEdit.vue:215 src/views/stream/StreamEdit.vue:207
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 設定解析錯誤"
 msgstr "Nginx 設定解析錯誤"
 
 
@@ -1144,7 +1190,7 @@ msgid "Nginx restarted successfully"
 msgstr "Nginx 重啟成功"
 msgstr "Nginx 重啟成功"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/ChatGPT/ChatGPT.vue:270
-#: src/components/Notification/Notification.vue:82
+#: src/components/Notification/Notification.vue:84
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:535
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:549
@@ -1152,6 +1198,7 @@ msgstr "Nginx 重啟成功"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:90
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/domain/ngx_conf/LocationEditor.vue:71
 #: src/views/notification/Notification.vue:70
 #: src/views/notification/Notification.vue:70
+#: src/views/preference/AuthSettings.vue:96
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/preference/BasicSettings.vue:101
 #: src/views/stream/StreamList.vue:165
 #: src/views/stream/StreamList.vue:165
 msgid "No"
 msgid "No"
@@ -1183,7 +1230,7 @@ msgstr "備註"
 msgid "Notification"
 msgid "Notification"
 msgstr "憑證"
 msgstr "憑證"
 
 
-#: src/components/Notification/Notification.vue:80 src/routes/index.ts:221
+#: src/components/Notification/Notification.vue:82 src/routes/index.ts:221
 #, fuzzy
 #, fuzzy
 msgid "Notifications"
 msgid "Notifications"
 msgstr "憑證"
 msgstr "憑證"
@@ -1208,7 +1255,7 @@ msgid "Ok"
 msgstr ""
 msgstr ""
 
 
 #: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/ChatGPT/ChatGPT.vue:271
-#: src/components/Notification/Notification.vue:83
+#: src/components/Notification/Notification.vue:85
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:536
@@ -1238,7 +1285,7 @@ msgstr ""
 msgid "Online"
 msgid "Online"
 msgstr "線上"
 msgstr "線上"
 
 
-#: src/views/preference/Preference.vue:113
+#: src/views/preference/Preference.vue:128
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1250,13 +1297,13 @@ msgstr "作業系統"
 msgid "OS:"
 msgid "OS:"
 msgstr "作業系統:"
 msgstr "作業系統:"
 
 
-#: src/views/domain/components/Deploy.vue:90
-#: src/views/stream/components/Deploy.vue:90
+#: src/views/domain/components/Deploy.vue:87
+#: src/views/stream/components/Deploy.vue:87
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "覆蓋"
 msgstr "覆蓋"
 
 
-#: src/views/domain/components/Deploy.vue:94
-#: src/views/stream/components/Deploy.vue:94
+#: src/views/domain/components/Deploy.vue:91
+#: src/views/stream/components/Deploy.vue:91
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "覆蓋現有檔案"
 msgstr "覆蓋現有檔案"
 
 
@@ -1264,11 +1311,11 @@ msgstr "覆蓋現有檔案"
 msgid "Params"
 msgid "Params"
 msgstr "參數"
 msgstr "參數"
 
 
-#: src/views/other/Login.vue:132 src/views/user/User.vue:18
+#: src/views/other/Login.vue:144 src/views/user/User.vue:18
 msgid "Password"
 msgid "Password"
 msgstr "密碼"
 msgstr "密碼"
 
 
-#: src/views/other/Install.vue:110
+#: src/views/other/Install.vue:109
 msgid "Password (*)"
 msgid "Password (*)"
 msgstr "密碼 (*)"
 msgstr "密碼 (*)"
 
 
@@ -1334,7 +1381,7 @@ msgstr "請至少選擇一個節點!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "預先發布"
 msgstr "預先發布"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:105
 msgid "Preference"
 msgid "Preference"
 msgstr "偏好設定"
 msgstr "偏好設定"
 
 
@@ -1431,7 +1478,16 @@ msgstr "重新載入中"
 msgid "Reloading nginx"
 msgid "Reloading nginx"
 msgstr "正在重新載入 Nginx"
 msgstr "正在重新載入 Nginx"
 
 
-#: src/components/Notification/Notification.vue:50
+#: src/views/preference/AuthSettings.vue:101
+msgid "Remove"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:47
+#, fuzzy
+msgid "Remove successfully"
+msgstr "儲存成功"
+
+#: src/components/Notification/Notification.vue:52
 #, fuzzy
 #, fuzzy
 msgid "Removed successfully"
 msgid "Removed successfully"
 msgstr "儲存成功"
 msgstr "儲存成功"
@@ -1489,9 +1545,9 @@ msgstr "執行中"
 
 
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:249
 #: src/views/certificate/CertificateEditor.vue:249
-#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
+#: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:261
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:145 src/views/stream/StreamEdit.vue:252
 msgid "Save"
 msgid "Save"
 msgstr "儲存"
 msgstr "儲存"
 
 
@@ -1499,7 +1555,7 @@ msgstr "儲存"
 msgid "Save Directive"
 msgid "Save Directive"
 msgstr "儲存指令"
 msgstr "儲存指令"
 
 
-#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:50
+#: src/views/config/ConfigEdit.vue:57 src/views/domain/DomainAdd.vue:46
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:41
 msgid "Save error %{msg}"
 msgid "Save error %{msg}"
 msgstr "儲存錯誤 %{msg}"
 msgstr "儲存錯誤 %{msg}"
@@ -1507,14 +1563,14 @@ msgstr "儲存錯誤 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:46
 #: src/views/certificate/CertificateEditor.vue:46
-#: src/views/preference/Preference.vue:66
+#: src/views/preference/Preference.vue:74
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "儲存成功"
 msgstr "儲存成功"
 
 
-#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:38
-#: src/views/domain/DomainEdit.vue:148
+#: src/views/config/ConfigEdit.vue:55 src/views/domain/DomainAdd.vue:37
+#: src/views/domain/DomainEdit.vue:146
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:39
-#: src/views/stream/StreamEdit.vue:140
+#: src/views/stream/StreamEdit.vue:138
 msgid "Saved successfully"
 msgid "Saved successfully"
 msgstr "儲存成功"
 msgstr "儲存成功"
 
 
@@ -1539,8 +1595,9 @@ msgstr "傳送"
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:196
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:235
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:70 src/views/stream/StreamList.vue:113
+#: src/views/environment/Environment.vue:139 src/views/other/Install.vue:69
+#: src/views/preference/AuthSettings.vue:49
+#: src/views/preference/Preference.vue:78 src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 #: src/views/stream/StreamList.vue:81 src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
 msgstr "伺服器錯誤"
 msgstr "伺服器錯誤"
@@ -1559,7 +1616,7 @@ msgid "server_name not found in directives"
 msgstr "在指令中未找到 server_name"
 msgstr "在指令中未找到 server_name"
 
 
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
 #: src/views/domain/cert/components/AutoCertStepOne.vue:34
-#: src/views/domain/DomainAdd.vue:121
+#: src/views/domain/DomainAdd.vue:117
 msgid "server_name parameter is required"
 msgid "server_name parameter is required"
 msgstr "必須提供 server_name 參數"
 msgstr "必須提供 server_name 參數"
 
 
@@ -1615,7 +1672,7 @@ msgstr "SSL 憑證金鑰路徑"
 msgid "SSL Certificate Path"
 msgid "SSL Certificate Path"
 msgstr "SSL 憑證路徑"
 msgstr "SSL 憑證路徑"
 
 
-#: src/views/other/Login.vue:158
+#: src/views/other/Login.vue:170
 #, fuzzy
 #, fuzzy
 msgid "SSO Login"
 msgid "SSO Login"
 msgstr "登入"
 msgstr "登入"
@@ -1701,8 +1758,8 @@ msgstr ""
 msgid "System"
 msgid "System"
 msgstr "系統"
 msgstr "系統"
 
 
-#: src/views/domain/components/SiteDuplicate.vue:140
-#: src/views/stream/components/StreamDuplicate.vue:140
+#: src/views/domain/components/SiteDuplicate.vue:136
+#: src/views/stream/components/StreamDuplicate.vue:136
 msgid "Target"
 msgid "Target"
 msgstr "目標"
 msgstr "目標"
 
 
@@ -1736,7 +1793,7 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "SSL 憑證金鑰路徑"
 msgstr "SSL 憑證金鑰路徑"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, and dots."
 "dashes, and dots."
@@ -1770,8 +1827,8 @@ msgstr "注意:目前設定中的 server_name 必須為需要申請憑證的
 msgid "The url is invalid"
 msgid "The url is invalid"
 msgstr "此功能在演示中不可用。"
 msgstr "此功能在演示中不可用。"
 
 
-#: src/views/preference/OpenAISettings.vue:45
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:60
 #, fuzzy
 #, fuzzy
 msgid "The url is invalid."
 msgid "The url is invalid."
 msgstr "此功能在演示中不可用。"
 msgstr "此功能在演示中不可用。"
@@ -1799,6 +1856,7 @@ msgstr ""
 msgid "This field should not be empty"
 msgid "This field should not be empty"
 msgstr "此欄位不應為空"
 msgstr "此欄位不應為空"
 
 
+#: src/views/preference/AuthSettings.vue:59
 #: src/views/preference/LogrotateSettings.vue:12
 #: src/views/preference/LogrotateSettings.vue:12
 msgid "Tips"
 msgid "Tips"
 msgstr ""
 msgstr ""
@@ -1817,10 +1875,14 @@ msgstr ""
 "為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
 "為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
 "的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 "的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:72
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
+#: src/views/other/Login.vue:62
+msgid "Too many login failed attempts, please try again later"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:221
 msgid "Trash"
 msgid "Trash"
 msgstr ""
 msgstr ""
@@ -1873,11 +1935,15 @@ msgstr "URL"
 msgid "User"
 msgid "User"
 msgstr "使用者名稱"
 msgstr "使用者名稱"
 
 
-#: src/views/other/Login.vue:122 src/views/user/User.vue:9
+#: src/views/other/Login.vue:65
+msgid "User is banned"
+msgstr ""
+
+#: src/views/other/Login.vue:134 src/views/user/User.vue:9
 msgid "Username"
 msgid "Username"
 msgstr "使用者名稱"
 msgstr "使用者名稱"
 
 
-#: src/views/other/Install.vue:100
+#: src/views/other/Install.vue:99
 msgid "Username (*)"
 msgid "Username (*)"
 msgstr "使用者名稱 (*)"
 msgstr "使用者名稱 (*)"
 
 
@@ -1891,7 +1957,7 @@ msgstr ""
 msgid "View"
 msgid "View"
 msgstr "檢視"
 msgstr "檢視"
 
 
-#: src/components/Notification/Notification.vue:141
+#: src/components/Notification/Notification.vue:143
 #, fuzzy
 #, fuzzy
 msgid "View all notifications"
 msgid "View all notifications"
 msgstr "憑證"
 msgstr "憑證"
@@ -1907,7 +1973,7 @@ msgstr "基本模式"
 
 
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
 #: src/views/domain/cert/components/AutoCertStepOne.vue:28
-#: src/views/domain/DomainAdd.vue:116
+#: src/views/domain/DomainAdd.vue:112
 msgid "Warning"
 msgid "Warning"
 msgstr "警告"
 msgstr "警告"
 
 
@@ -1940,6 +2006,7 @@ msgstr "將憑證寫入磁碟"
 
 
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:89
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
 #: src/views/domain/ngx_conf/LocationEditor.vue:70
+#: src/views/preference/AuthSettings.vue:95
 #: src/views/preference/BasicSettings.vue:100
 #: src/views/preference/BasicSettings.vue:100
 msgid "Yes"
 msgid "Yes"
 msgstr "是的"
 msgstr "是的"

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.0.0-beta.25","build_id":139,"total_build":343}
+{"version":"2.0.0-beta.25","build_id":140,"total_build":344}

+ 0 - 4
app/src/views/domain/DomainAdd.vue

@@ -33,19 +33,15 @@ function init() {
 
 
 async function save() {
 async function save() {
   return ngx.build_config(ngx_config).then(r => {
   return ngx.build_config(ngx_config).then(r => {
-    // eslint-disable-next-line promise/no-nesting
     domain.save(ngx_config.name, { name: ngx_config.name, content: r.content, overwrite: true }).then(() => {
     domain.save(ngx_config.name, { name: ngx_config.name, content: r.content, overwrite: true }).then(() => {
       message.success($gettext('Saved successfully'))
       message.success($gettext('Saved successfully'))
 
 
-      // eslint-disable-next-line promise/no-nesting
       domain.enable(ngx_config.name).then(() => {
       domain.enable(ngx_config.name).then(() => {
         message.success($gettext('Enabled successfully'))
         message.success($gettext('Enabled successfully'))
         window.scroll({ top: 0, left: 0, behavior: 'smooth' })
         window.scroll({ top: 0, left: 0, behavior: 'smooth' })
-        // eslint-disable-next-line promise/no-nesting
       }).catch(e => {
       }).catch(e => {
         message.error(e.message ?? $gettext('Enable failed'), 5)
         message.error(e.message ?? $gettext('Enable failed'), 5)
       })
       })
-      // eslint-disable-next-line promise/no-nesting
     }).catch(e => {
     }).catch(e => {
       message.error($gettext('Save error %{msg}', { msg: $gettext(e.message) ?? '' }), 5)
       message.error($gettext('Save error %{msg}', { msg: $gettext(e.message) ?? '' }), 5)
     })
     })

+ 0 - 2
app/src/views/domain/DomainEdit.vue

@@ -105,10 +105,8 @@ function on_mode_change(advanced: CheckedType) {
       build_config()
       build_config()
     }
     }
     else {
     else {
-      // eslint-disable-next-line promise/no-nesting
       return ngx.tokenize_config(configText.value).then(r => {
       return ngx.tokenize_config(configText.value).then(r => {
         Object.assign(ngx_config, r)
         Object.assign(ngx_config, r)
-        // eslint-disable-next-line promise/no-nesting
       }).catch(handle_parse_error)
       }).catch(handle_parse_error)
     }
     }
   })
   })

+ 1 - 4
app/src/views/domain/components/Deploy.vue

@@ -29,7 +29,7 @@ function deploy() {
             name: name.value,
             name: name.value,
             content: r.config,
             content: r.config,
             overwrite: overwrite.value,
             overwrite: overwrite.value,
-            // eslint-disable-next-line promise/no-nesting
+
           }, { headers: { 'X-Node-ID': id } }).then(async () => {
           }, { headers: { 'X-Node-ID': id } }).then(async () => {
             notification.success({
             notification.success({
               message: $gettext('Deploy successfully'),
               message: $gettext('Deploy successfully'),
@@ -38,7 +38,6 @@ function deploy() {
                   { conf_name: name.value, node_name }),
                   { conf_name: name.value, node_name }),
             })
             })
             if (enabled.value) {
             if (enabled.value) {
-              // eslint-disable-next-line promise/no-nesting
               domain.enable(name.value).then(() => {
               domain.enable(name.value).then(() => {
                 notification.success({
                 notification.success({
                   message: $gettext('Enable successfully'),
                   message: $gettext('Enable successfully'),
@@ -46,7 +45,6 @@ function deploy() {
                     $gettext('Enable %{conf_name} in %{node_name} successfully',
                     $gettext('Enable %{conf_name} in %{node_name} successfully',
                       { conf_name: name.value, node_name }),
                       { conf_name: name.value, node_name }),
                 })
                 })
-                // eslint-disable-next-line promise/no-nesting
               }).catch(e => {
               }).catch(e => {
                 notification.error({
                 notification.error({
                   message: $gettext('Enable %{conf_name} in %{node_name} failed', {
                   message: $gettext('Enable %{conf_name} in %{node_name} failed', {
@@ -57,7 +55,6 @@ function deploy() {
                 })
                 })
               })
               })
             }
             }
-            // eslint-disable-next-line promise/no-nesting
           }).catch(e => {
           }).catch(e => {
             notification.error({
             notification.error({
               message: $gettext('Deploy %{conf_name} to %{node_name} failed', {
               message: $gettext('Deploy %{conf_name} to %{node_name} failed', {

+ 2 - 6
app/src/views/domain/components/SiteDuplicate.vue

@@ -59,24 +59,22 @@ function onSubmit() {
 
 
     modelRef.target.forEach(id => {
     modelRef.target.forEach(id => {
       if (id === 0) {
       if (id === 0) {
-        // eslint-disable-next-line promise/no-nesting
         domain.duplicate(props.name, { name: modelRef.name }).then(() => {
         domain.duplicate(props.name, { name: modelRef.name }).then(() => {
           message.success($gettext('Duplicate to local successfully'))
           message.success($gettext('Duplicate to local successfully'))
           show.value = false
           show.value = false
           emit('duplicated')
           emit('duplicated')
-          // eslint-disable-next-line promise/no-nesting
         }).catch(e => {
         }).catch(e => {
           message.error($gettext(e?.message ?? 'Server error'))
           message.error($gettext(e?.message ?? 'Server error'))
         })
         })
       }
       }
       else {
       else {
         // get source content
         // get source content
-        // eslint-disable-next-line promise/no-nesting
+
         domain.get(props.name).then(r => {
         domain.get(props.name).then(r => {
           domain.save(modelRef.name, {
           domain.save(modelRef.name, {
             name: modelRef.name,
             name: modelRef.name,
             content: r.config,
             content: r.config,
-            // eslint-disable-next-line promise/no-nesting
+
           }, { headers: { 'X-Node-ID': id } }).then(() => {
           }, { headers: { 'X-Node-ID': id } }).then(() => {
             notification.success({
             notification.success({
               message: $gettext('Duplicate successfully'),
               message: $gettext('Duplicate successfully'),
@@ -84,7 +82,6 @@ function onSubmit() {
                 $gettext('Duplicate %{conf_name} to %{node_name} successfully',
                 $gettext('Duplicate %{conf_name} to %{node_name} successfully',
                   { conf_name: props.name, node_name: node_map[id] }),
                   { conf_name: props.name, node_name: node_map[id] }),
             })
             })
-            // eslint-disable-next-line promise/no-nesting
           }).catch(e => {
           }).catch(e => {
             notification.error({
             notification.error({
               message: $gettext('Duplicate failed'),
               message: $gettext('Duplicate failed'),
@@ -92,7 +89,6 @@ function onSubmit() {
             })
             })
           })
           })
           if (r.enabled) {
           if (r.enabled) {
-            // eslint-disable-next-line promise/no-nesting
             domain.enable(modelRef.name, { headers: { 'X-Node-ID': id } }).then(() => {
             domain.enable(modelRef.name, { headers: { 'X-Node-ID': id } }).then(() => {
               notification.success({
               notification.success({
                 message: $gettext('Enabled successfully'),
                 message: $gettext('Enabled successfully'),

+ 1 - 2
app/src/views/other/Install.vue

@@ -61,11 +61,10 @@ const onSubmit = () => {
   validate().then(() => {
   validate().then(() => {
     // modelRef
     // modelRef
     loading.value = true
     loading.value = true
-    // eslint-disable-next-line promise/no-nesting
+
     install.install_nginx_ui(modelRef).then(async () => {
     install.install_nginx_ui(modelRef).then(async () => {
       message.success($gettext('Install successfully'))
       message.success($gettext('Install successfully'))
       await router.push('/login')
       await router.push('/login')
-      // eslint-disable-next-line promise/no-nesting
     }).catch(e => {
     }).catch(e => {
       message.error(e.message ?? $gettext('Server error'))
       message.error(e.message ?? $gettext('Server error'))
     }).finally(() => {
     }).finally(() => {

+ 15 - 3
app/src/views/other/Login.vue

@@ -46,16 +46,28 @@ const { validate, validateInfos, clearValidate } = Form.useForm(modelRef, rulesR
 const onSubmit = () => {
 const onSubmit = () => {
   validate().then(async () => {
   validate().then(async () => {
     loading.value = true
     loading.value = true
-    // eslint-disable-next-line promise/no-nesting
+
     await auth.login(modelRef.username, modelRef.password).then(async () => {
     await auth.login(modelRef.username, modelRef.password).then(async () => {
       message.success($gettext('Login successful'), 1)
       message.success($gettext('Login successful'), 1)
 
 
       const next = (route.query?.next || '').toString() || '/'
       const next = (route.query?.next || '').toString() || '/'
 
 
       await router.push(next)
       await router.push(next)
-      // eslint-disable-next-line promise/no-nesting
     }).catch(e => {
     }).catch(e => {
-      message.error($gettext(e.message ?? 'Server error'))
+      switch (e.code) {
+        case 4031:
+          message.error($gettext('Incorrect username or password'))
+          break
+        case 4291:
+          message.error($gettext('Too many login failed attempts, please try again later'))
+          break
+        case 4033:
+          message.error($gettext('User is banned'))
+          break
+        default:
+          message.error($gettext(e.message ?? 'Server error'))
+          break
+      }
     })
     })
     loading.value = false
     loading.value = false
   })
   })

+ 114 - 0
app/src/views/preference/AuthSettings.vue

@@ -0,0 +1,114 @@
+<script setup lang="tsx">
+import { message } from 'ant-design-vue'
+import type { Ref } from 'vue'
+import { inject } from 'vue'
+import dayjs from 'dayjs'
+import type { BannedIP } from '@/api/settings'
+import setting from '@/api/settings'
+import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
+import type { Settings } from '@/views/preference/typedef'
+
+const data: Settings = inject('data') as Settings
+
+const bannedIPColumns = [{
+  title: $gettext('IP'),
+  dataIndex: 'ip',
+}, {
+  title: $gettext('Attempts'),
+  dataIndex: 'attempts',
+}, {
+  title: $gettext('Banned Until'),
+  dataIndex: 'expired_at',
+  customRender: (args: customRender) => {
+    return dayjs.unix(args.text).format('YYYY-MM-DD HH:mm:ss')
+  },
+}, {
+  title: $gettext('Action'),
+  dataIndex: 'action',
+}]
+
+const bannedIPs: Ref<BannedIP[]> = ref([])
+
+function getBannedIPs() {
+  setting.get_banned_ips().then(r => {
+    bannedIPs.value = r
+  })
+}
+
+getBannedIPs()
+
+defineExpose({
+  getBannedIPs,
+})
+
+function removeBannedIP(ip: string) {
+  setting.remove_banned_ip(ip).then(() => {
+    bannedIPs.value = bannedIPs.value.filter(v => v.ip !== ip)
+    message.success($gettext('Remove successfully'))
+  }).catch((e: { message?: string }) => {
+    message.error(e?.message ?? $gettext('Server error'))
+  })
+}
+</script>
+
+<template>
+  <div class="flex justify-center">
+    <div>
+      <AAlert
+        class="mb-4"
+        :message="$gettext('Tips')"
+        :description="$gettext('If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes,'
+          + ' the ip will be banned for a period of time.')"
+        type="info"
+      />
+      <AForm
+        layout="horizontal"
+        style="width:90%;max-width: 500px"
+      >
+        <AFormItem :label="$gettext('Ban Threshold Minutes')">
+          <AInputNumber
+            v-model:value="data.auth.ban_threshold_minutes"
+            min="1"
+          />
+        </AFormItem>
+        <AFormItem :label="$gettext('Max Attempts')">
+          <AInputNumber
+            v-model:value="data.auth.max_attempts"
+            min="1"
+          />
+        </AFormItem>
+      </AForm>
+      <h3>
+        {{ $gettext('Banned IPs') }}
+      </h3>
+      <div class="mb-6">
+        <ATable
+          :columns="bannedIPColumns"
+          row-key="ip"
+          :data-source="bannedIPs"
+          size="small"
+        >
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.dataIndex === 'action'">
+              <APopconfirm
+                :title="$gettext('Are you sure to delete this banned IP immediately?')"
+                :ok-text="$gettext('Yes')"
+                :cancel-text="$gettext('No')"
+                placement="bottom"
+                @confirm="() => removeBannedIP(record.ip)"
+              >
+                <a>
+                  {{ $gettext('Remove') }}
+                </a>
+              </APopconfirm>
+            </template>
+          </template>
+        </ATable>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="less" scoped>
+
+</style>

+ 16 - 1
app/src/views/preference/Preference.vue

@@ -10,6 +10,7 @@ import NginxSettings from '@/views/preference/NginxSettings.vue'
 import type { Settings } from '@/views/preference/typedef'
 import type { Settings } from '@/views/preference/typedef'
 import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
 import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
 import { useSettingsStore } from '@/pinia'
 import { useSettingsStore } from '@/pinia'
+import AuthSettings from '@/views/preference/AuthSettings.vue'
 
 
 const data = ref<Settings>({
 const data = ref<Settings>({
   server: {
   server: {
@@ -46,15 +47,21 @@ const data = ref<Settings>({
     cmd: '',
     cmd: '',
     interval: 1440,
     interval: 1440,
   },
   },
+  auth: {
+    ip_white_list: [],
+    ban_threshold_minutes: 10,
+    max_attempts: 10,
+  },
 })
 })
 
 
-settings.get().then(r => {
+settings.get<Settings>().then(r => {
   data.value = r
   data.value = r
 })
 })
 
 
 const settingsStore = useSettingsStore()
 const settingsStore = useSettingsStore()
 const { server_name } = storeToRefs(settingsStore)
 const { server_name } = storeToRefs(settingsStore)
 const errors = ref({}) as Ref<Record<string, Record<string, string>>>
 const errors = ref({}) as Ref<Record<string, Record<string, string>>>
+const refAuthSettings = ref()
 
 
 async function save() {
 async function save() {
   // fix type
   // fix type
@@ -63,6 +70,7 @@ async function save() {
     if (!settingsStore.is_remote)
     if (!settingsStore.is_remote)
       server_name.value = r?.server?.name ?? ''
       server_name.value = r?.server?.name ?? ''
     data.value = r
     data.value = r
+    refAuthSettings.value.getBannedIPs()
     message.success($gettext('Save successfully'))
     message.success($gettext('Save successfully'))
     errors.value = {}
     errors.value = {}
   }).catch(e => {
   }).catch(e => {
@@ -90,6 +98,7 @@ onMounted(() => {
   if (route.query?.tab)
   if (route.query?.tab)
     activeKey.value = route.query.tab.toString()
     activeKey.value = route.query.tab.toString()
 })
 })
+
 </script>
 </script>
 
 
 <template>
 <template>
@@ -102,6 +111,12 @@ onMounted(() => {
         >
         >
           <BasicSettings />
           <BasicSettings />
         </ATabPane>
         </ATabPane>
+        <ATabPane
+          key="auth"
+          :tab="$gettext('Auth')"
+        >
+          <AuthSettings ref="refAuthSettings" />
+        </ATabPane>
         <ATabPane
         <ATabPane
           key="nginx"
           key="nginx"
           :tab="$gettext('Nginx')"
           :tab="$gettext('Nginx')"

+ 5 - 0
app/src/views/preference/typedef.ts

@@ -33,4 +33,9 @@ export interface Settings {
     cmd: string
     cmd: string
     interval: number
     interval: number
   }
   }
+  auth: {
+    ip_white_list: string[]
+    ban_threshold_minutes: number
+    max_attempts: number
+  }
 }
 }

+ 0 - 2
app/src/views/stream/StreamEdit.vue

@@ -97,10 +97,8 @@ function on_mode_change(advanced: CheckedType) {
       build_config()
       build_config()
     }
     }
     else {
     else {
-      // eslint-disable-next-line promise/no-nesting
       return ngx.tokenize_config(configText.value).then(r => {
       return ngx.tokenize_config(configText.value).then(r => {
         Object.assign(ngx_config, r)
         Object.assign(ngx_config, r)
-        // eslint-disable-next-line promise/no-nesting
       }).catch(handle_parse_error)
       }).catch(handle_parse_error)
     }
     }
   })
   })

+ 1 - 4
app/src/views/stream/components/Deploy.vue

@@ -29,7 +29,7 @@ function deploy() {
             name: name.value,
             name: name.value,
             content: r.config,
             content: r.config,
             overwrite: overwrite.value,
             overwrite: overwrite.value,
-            // eslint-disable-next-line promise/no-nesting
+
           }, { headers: { 'X-Node-ID': id } }).then(async () => {
           }, { headers: { 'X-Node-ID': id } }).then(async () => {
             notification.success({
             notification.success({
               message: $gettext('Deploy successfully'),
               message: $gettext('Deploy successfully'),
@@ -38,7 +38,6 @@ function deploy() {
                   { conf_name: name.value, node_name }),
                   { conf_name: name.value, node_name }),
             })
             })
             if (enabled.value) {
             if (enabled.value) {
-              // eslint-disable-next-line promise/no-nesting
               stream.enable(name.value).then(() => {
               stream.enable(name.value).then(() => {
                 notification.success({
                 notification.success({
                   message: $gettext('Enable successfully'),
                   message: $gettext('Enable successfully'),
@@ -46,7 +45,6 @@ function deploy() {
                     $gettext('Enable %{conf_name} in %{node_name} successfully',
                     $gettext('Enable %{conf_name} in %{node_name} successfully',
                       { conf_name: name.value, node_name }),
                       { conf_name: name.value, node_name }),
                 })
                 })
-                // eslint-disable-next-line promise/no-nesting
               }).catch(e => {
               }).catch(e => {
                 notification.error({
                 notification.error({
                   message: $gettext('Enable %{conf_name} in %{node_name} failed', {
                   message: $gettext('Enable %{conf_name} in %{node_name} failed', {
@@ -57,7 +55,6 @@ function deploy() {
                 })
                 })
               })
               })
             }
             }
-            // eslint-disable-next-line promise/no-nesting
           }).catch(e => {
           }).catch(e => {
             notification.error({
             notification.error({
               message: $gettext('Deploy %{conf_name} to %{node_name} failed', {
               message: $gettext('Deploy %{conf_name} to %{node_name} failed', {

+ 2 - 6
app/src/views/stream/components/StreamDuplicate.vue

@@ -59,24 +59,22 @@ function onSubmit() {
 
 
     modelRef.target.forEach(id => {
     modelRef.target.forEach(id => {
       if (id === 0) {
       if (id === 0) {
-        // eslint-disable-next-line promise/no-nesting
         stream.duplicate(props.name, { name: modelRef.name }).then(() => {
         stream.duplicate(props.name, { name: modelRef.name }).then(() => {
           message.success($gettext('Duplicate to local successfully'))
           message.success($gettext('Duplicate to local successfully'))
           show.value = false
           show.value = false
           emit('duplicated')
           emit('duplicated')
-          // eslint-disable-next-line promise/no-nesting
         }).catch(e => {
         }).catch(e => {
           message.error($gettext(e?.message ?? 'Server error'))
           message.error($gettext(e?.message ?? 'Server error'))
         })
         })
       }
       }
       else {
       else {
         // get source content
         // get source content
-        // eslint-disable-next-line promise/no-nesting
+
         stream.get(props.name).then(r => {
         stream.get(props.name).then(r => {
           stream.save(modelRef.name, {
           stream.save(modelRef.name, {
             name: modelRef.name,
             name: modelRef.name,
             content: r.config,
             content: r.config,
-            // eslint-disable-next-line promise/no-nesting
+
           }, { headers: { 'X-Node-ID': id } }).then(() => {
           }, { headers: { 'X-Node-ID': id } }).then(() => {
             notification.success({
             notification.success({
               message: $gettext('Duplicate successfully'),
               message: $gettext('Duplicate successfully'),
@@ -84,7 +82,6 @@ function onSubmit() {
                 $gettext('Duplicate %{conf_name} to %{node_name} successfully',
                 $gettext('Duplicate %{conf_name} to %{node_name} successfully',
                   { conf_name: props.name, node_name: node_map[id] }),
                   { conf_name: props.name, node_name: node_map[id] }),
             })
             })
-            // eslint-disable-next-line promise/no-nesting
           }).catch(e => {
           }).catch(e => {
             notification.error({
             notification.error({
               message: $gettext('Duplicate failed'),
               message: $gettext('Duplicate failed'),
@@ -92,7 +89,6 @@ function onSubmit() {
             })
             })
           })
           })
           if (r.enabled) {
           if (r.enabled) {
-            // eslint-disable-next-line promise/no-nesting
             stream.enable(modelRef.name, { headers: { 'X-Node-ID': id } }).then(() => {
             stream.enable(modelRef.name, { headers: { 'X-Node-ID': id } }).then(() => {
               notification.success({
               notification.success({
                 message: $gettext('Enabled successfully'),
                 message: $gettext('Enabled successfully'),

+ 1 - 1
app/version.json

@@ -1 +1 @@
-{"version":"2.0.0-beta.25","build_id":139,"total_build":343}
+{"version":"2.0.0-beta.25","build_id":140,"total_build":344}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 86 - 0
app/vite.config.ts.timestamp-1721542436572-91822f5b8889d.mjs


+ 2 - 1
docs/.vitepress/config/en.ts

@@ -39,7 +39,8 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Open AI', link: '/guide/config-openai'},
             {text: 'Open AI', link: '/guide/config-openai'},
             {text: 'Casdoor', link: '/guide/config-casdoor'},
             {text: 'Casdoor', link: '/guide/config-casdoor'},
             {text: 'Logrotate', link: '/guide/config-logrotate'},
             {text: 'Logrotate', link: '/guide/config-logrotate'},
-            {text: 'Cluster', link: '/guide/config-cluster'}
+            {text: 'Cluster', link: '/guide/config-cluster'},
+            {text: 'Auth', link: '/guide/config-auth'}
           ]
           ]
         },
         },
         {
         {

+ 2 - 1
docs/.vitepress/config/zh_CN.ts

@@ -44,7 +44,8 @@ export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Open AI', link: '/zh_CN/guide/config-openai'},
             {text: 'Open AI', link: '/zh_CN/guide/config-openai'},
             {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
             {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
             {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'},
             {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'},
-            {text: '集群', link: '/zh_CN/guide/config-cluster'}
+            {text: '集群', link: '/zh_CN/guide/config-cluster'},
+            {text: '认证', link: '/zh_CN/guide/config-auth'}
           ]
           ]
         },
         },
         {
         {

+ 2 - 1
docs/.vitepress/config/zh_TW.ts

@@ -43,7 +43,8 @@ export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Open AI', link: '/zh_TW/guide/config-openai'},
             {text: 'Open AI', link: '/zh_TW/guide/config-openai'},
             {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
             {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
             {text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'},
             {text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'},
-            {text: '集群', link: '/zh_TW/guide/config-cluster'}
+            {text: '集群', link: '/zh_TW/guide/config-cluster'},
+            {text: '認證', link: '/zh_TM/guide/config-auth'}
           ]
           ]
         },
         },
         {
         {

+ 30 - 0
docs/guide/config-auth.md

@@ -0,0 +1,30 @@
+# Auth
+From v2.0.0-beta.26, you can authorization settings in the `auth` section of the configuration file.
+
+## IPWhiteList
+- Type: `string`
+- Example: `10.0.0.1`
+
+```ini
+[auth]
+IPWhiteList = 10.0.0.1
+IPWhiteList = 10.0.0.2
+IPWhiteList = 2001:0000:130F:0000:0000:09C0:876A:130B
+```
+
+By default, if you do not set the `IPWhiteList`, all IP addresses are allowed to access the Nginx UI.
+
+Once you set the `IPWhiteList`, only the users from IP addresses in the list and `127.0.0.1` can access the Nginx UI,
+others will receive a `403 Forbidden` error.
+
+## BanThresholdMinutes
+- Type: `int`
+- Default: `10`
+
+By default, if a user fails to log in 10 times within 10 minutes, the user will be banned for 10 minutes.
+
+## MaxAttempts
+- Type: `int`
+- Default: `10`
+
+By default, a user can try to log in 10 times within 10 minutes.

+ 6 - 0
docs/guide/env.md

@@ -63,6 +63,12 @@ Applicable for version v2.0.0-beta.23 and above.
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 
 
+## Auth
+
+| Configuration Setting | Environment Variable        |
+|-----------------------|-----------------------------|
+| IPWhiteList           | NGINX_UI_AUTH_IPWhiteList   |
+
 ## Predefined User
 ## Predefined User
 
 
 In skip installation mode, you can set the following environment variables to create a predefined user:
 In skip installation mode, you can set the following environment variables to create a predefined user:

+ 3 - 3
docs/package.json

@@ -7,11 +7,11 @@
     "docs:preview": "vitepress preview"
     "docs:preview": "vitepress preview"
   },
   },
   "dependencies": {
   "dependencies": {
-    "vue": "^3.4.26",
-    "vitepress": "^1.1.4"
+    "vitepress": "^1.3.1",
+    "vue": "^3.4.33"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@types/node": "^20.12.8",
+    "@types/node": "^20.14.11",
     "less": "^4.2.0"
     "less": "^4.2.0"
   },
   },
   "license": "AGPL-3.0",
   "license": "AGPL-3.0",

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 286 - 749
docs/pnpm-lock.yaml


+ 30 - 0
docs/zh_CN/guide/config-auth.md

@@ -0,0 +1,30 @@
+# Auth
+从 v2.0.0-beta.26 版本开始,您可以在配置文件的 `auth` 部分设置授权选项。
+
+## IPWhiteList
+- 类型:`string`
+- 示例:`10.0.0.1`
+
+```ini
+[auth]
+IPWhiteList = 10.0.0.1
+IPWhiteList = 10.0.0.2
+IPWhiteList = 2001:0000:130F:0000:0000:09C0:876A:130B
+```
+
+默认情况下,如果您没有设置 `IPWhiteList`,所有 IP 地址都允许访问 Nginx UI。
+
+一旦您设置了 `IPWhiteList`,只有列表中和 `127.0.0.1` 的 IP 地址的用户可以访问 Nginx UI,
+其他人将收到 `403 Forbidden` 错误。
+
+## BanThresholdMinutes
+- Type: `int`
+- Default: `10`
+
+默认情况下,如果用户在 10 分钟内登录失败 10 次,用户将被禁止登录 10 分钟。
+
+## MaxAttempts
+- Type: `int`
+- Default: `10`
+
+默认情况下,用户可以在 10 分钟内尝试登录 10 次。

+ 7 - 1
docs/zh_CN/guide/env.md

@@ -1,7 +1,7 @@
 # 环境变量
 # 环境变量
 适用于 v2.0.0-beta.23 及以上版本
 适用于 v2.0.0-beta.23 及以上版本
 
 
-## 服务器
+## Server
 
 
 | Configuration Setting         | Environment Variable                  |
 | Configuration Setting         | Environment Variable                  |
 | ----------------------------- | ------------------------------------- |
 | ----------------------------- | ------------------------------------- |
@@ -63,6 +63,12 @@
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 
 
+## Auth
+
+| Configuration Setting | Environment Variable        |
+|-----------------------|-----------------------------|
+| IPWhiteList           | NGINX_UI_AUTH_IPWhiteList   |
+
 ## 预定义用户
 ## 预定义用户
 
 
 在跳过安装模式下,您可以设置以下环境变量以创建预定义用户:
 在跳过安装模式下,您可以设置以下环境变量以创建预定义用户:

+ 29 - 0
docs/zh_TW/guide/config-auth.md

@@ -0,0 +1,29 @@
+# Auth
+從 v2.0.0-beta.26 版本開始,您可以在配置文件的 `auth` 部分設置授權選項。
+
+## IPWhiteList
+- 類型:`string`
+- 範例:`10.0.0.1`
+
+```ini
+[auth]
+IPWhiteList = 10.0.0.1
+IPWhiteList = 10.0.0.2
+IPWhiteList = 2001:0000:130F:0000:0000:09C0:876A:130B
+```
+
+默認情況下,如果您沒有設置 IPWhiteList,所有 IP 地址都允許訪問 Nginx UI。
+一旦您設置了 IPWhiteList,只有列表中和 `127.0.0.1` 的 IP 地址的用戶可以訪問 Nginx UI,
+其他人將收到 `403 Forbidden` 錯誤。
+
+## BanThresholdMinutes
+- Type: `int`
+- Default: `10`
+
+默認情況下,如果用戶在 10 分鐘內登錄失敗 10 次,用戶將被禁止登錄 10 分鐘。
+
+## MaxAttempts
+- Type: `int`
+- Default: `10`
+
+默認情況下,如果用戶在 10 分鐘內登錄失敗 10 次,用戶將被禁止登錄 10 分鐘。

+ 7 - 1
docs/zh_TW/guide/env.md

@@ -1,7 +1,7 @@
 # 環境變量
 # 環境變量
 適用於 v2.0.0-beta.23 及以上版本
 適用於 v2.0.0-beta.23 及以上版本
 
 
-## 伺服器
+## Server
 
 
 | Configuration Setting         | Environment Variable                  |
 | Configuration Setting         | Environment Variable                  |
 | ----------------------------- | ------------------------------------- |
 | ----------------------------- | ------------------------------------- |
@@ -63,6 +63,12 @@
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | CMD                           | NGINX_UI_LOGROTATE_CMD                |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 | Interval                      | NGINX_UI_LOGROTATE_INTERVAL           |
 
 
+## Auth
+
+| Configuration Setting | Environment Variable        |
+|-----------------------|-----------------------------|
+| IPWhiteList           | NGINX_UI_AUTH_IPWhiteList   |
+
 ## 預定義使用者
 ## 預定義使用者
 
 
 在跳過安裝模式下,您可以設置以下環境變量以創建預定義使用者:
 在跳過安裝模式下,您可以設置以下環境變量以創建預定義使用者:

+ 81 - 81
go.mod

@@ -5,52 +5,52 @@ go 1.22.0
 require (
 require (
 	github.com/0xJacky/pofile v0.2.1
 	github.com/0xJacky/pofile v0.2.1
 	github.com/BurntSushi/toml v1.4.0
 	github.com/BurntSushi/toml v1.4.0
-	github.com/caarlos0/env/v11 v11.0.1
-	github.com/casdoor/casdoor-go-sdk v0.46.0
+	github.com/caarlos0/env/v11 v11.1.0
+	github.com/casdoor/casdoor-go-sdk v0.47.0
 	github.com/creack/pty v1.1.21
 	github.com/creack/pty v1.1.21
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/dustin/go-humanize v1.0.1
 	github.com/dustin/go-humanize v1.0.1
 	github.com/fatih/color v1.17.0
 	github.com/fatih/color v1.17.0
 	github.com/gin-contrib/static v1.1.2
 	github.com/gin-contrib/static v1.1.2
 	github.com/gin-gonic/gin v1.10.0
 	github.com/gin-gonic/gin v1.10.0
-	github.com/go-acme/lego/v4 v4.17.3
+	github.com/go-acme/lego/v4 v4.17.4
 	github.com/go-co-op/gocron v1.37.0
 	github.com/go-co-op/gocron v1.37.0
-	github.com/go-playground/validator/v10 v10.21.0
-	github.com/golang-jwt/jwt v3.2.2+incompatible
+	github.com/go-playground/validator/v10 v10.22.0
 	github.com/google/uuid v1.6.0
 	github.com/google/uuid v1.6.0
-	github.com/gorilla/websocket v1.5.2
+	github.com/gorilla/websocket v1.5.3
 	github.com/hpcloud/tail v1.0.0
 	github.com/hpcloud/tail v1.0.0
 	github.com/jpillora/overseer v1.1.6
 	github.com/jpillora/overseer v1.1.6
 	github.com/lib/pq v1.10.9
 	github.com/lib/pq v1.10.9
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/pkg/errors v0.9.1
 	github.com/pkg/errors v0.9.1
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
-	github.com/samber/lo v1.39.0
-	github.com/sashabaranov/go-openai v1.24.1
+	github.com/samber/lo v1.46.0
+	github.com/sashabaranov/go-openai v1.27.0
 	github.com/shirou/gopsutil/v3 v3.24.5
 	github.com/shirou/gopsutil/v3 v3.24.5
 	github.com/shopspring/decimal v1.4.0
 	github.com/shopspring/decimal v1.4.0
 	github.com/spf13/cast v1.6.0
 	github.com/spf13/cast v1.6.0
 	github.com/stretchr/testify v1.9.0
 	github.com/stretchr/testify v1.9.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20240109151651-bb3e845a7a2a
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20240109151651-bb3e845a7a2a
 	go.uber.org/zap v1.27.0
 	go.uber.org/zap v1.27.0
-	golang.org/x/crypto v0.24.0
+	golang.org/x/crypto v0.25.0
 	gopkg.in/guregu/null.v4 v4.0.0
 	gopkg.in/guregu/null.v4 v4.0.0
 	gopkg.in/ini.v1 v1.67.0
 	gopkg.in/ini.v1 v1.67.0
-	gorm.io/driver/sqlite v1.5.5
+	gorm.io/driver/sqlite v1.5.6
 	gorm.io/gen v0.3.26
 	gorm.io/gen v0.3.26
-	gorm.io/gorm v1.25.10
-	gorm.io/plugin/dbresolver v1.5.1
+	gorm.io/gorm v1.25.11
+	gorm.io/plugin/dbresolver v1.5.2
 )
 )
 
 
 require (
 require (
-	cloud.google.com/go/auth v0.5.1 // indirect
-	cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
-	cloud.google.com/go/compute/metadata v0.3.0 // indirect
+	cloud.google.com/go/auth v0.7.1 // indirect
+	cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
+	cloud.google.com/go/compute/metadata v0.5.0 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
 	github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
@@ -71,40 +71,40 @@ require (
 	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
 	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
-	github.com/aliyun/alibaba-cloud-sdk-go v1.62.758 // indirect
+	github.com/aliyun/alibaba-cloud-sdk-go v1.62.793 // indirect
 	github.com/andybalholm/brotli v1.1.0 // indirect
 	github.com/andybalholm/brotli v1.1.0 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
-	github.com/aws/aws-sdk-go-v2 v1.27.2 // indirect
-	github.com/aws/aws-sdk-go-v2/config v1.27.18 // indirect
-	github.com/aws/aws-sdk-go-v2/credentials v1.17.18 // indirect
-	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect
-	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect
-	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect
+	github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
+	github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
+	github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
+	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
+	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
+	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
-	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
-	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect
-	github.com/aws/aws-sdk-go-v2/service/lightsail v1.38.3 // indirect
-	github.com/aws/aws-sdk-go-v2/service/route53 v1.40.10 // indirect
-	github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect
-	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect
-	github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect
-	github.com/aws/smithy-go v1.20.2 // indirect
+	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
+	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
+	github.com/aws/aws-sdk-go-v2/service/lightsail v1.40.3 // indirect
+	github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 // indirect
+	github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
+	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
+	github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
+	github.com/aws/smithy-go v1.20.3 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/benbjohnson/clock v1.3.5 // indirect
 	github.com/benbjohnson/clock v1.3.5 // indirect
-	github.com/boombuler/barcode v1.0.1 // indirect
-	github.com/bytedance/sonic v1.11.8 // indirect
+	github.com/boombuler/barcode v1.0.2 // indirect
+	github.com/bytedance/sonic v1.11.9 // indirect
 	github.com/bytedance/sonic/loader v0.1.1 // indirect
 	github.com/bytedance/sonic/loader v0.1.1 // indirect
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
-	github.com/civo/civogo v0.3.70 // indirect
-	github.com/cloudflare/cloudflare-go v0.97.0 // indirect
+	github.com/civo/civogo v0.3.73 // indirect
+	github.com/cloudflare/cloudflare-go v0.100.0 // indirect
 	github.com/cloudwego/base64x v0.1.4 // indirect
 	github.com/cloudwego/base64x v0.1.4 // indirect
 	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/cpu/goacmedns v0.1.1 // indirect
 	github.com/cpu/goacmedns v0.1.1 // indirect
-	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/deepmap/oapi-codegen v1.16.3 // indirect
 	github.com/deepmap/oapi-codegen v1.16.3 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
-	github.com/exoscale/egoscale v0.102.3 // indirect
+	github.com/exoscale/egoscale v0.102.4 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/flosch/pongo2/v4 v4.0.2 // indirect
 	github.com/flosch/pongo2/v4 v4.0.2 // indirect
@@ -113,7 +113,7 @@ require (
 	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-errors/errors v1.5.1 // indirect
 	github.com/go-errors/errors v1.5.1 // indirect
-	github.com/go-jose/go-jose/v4 v4.0.2 // indirect
+	github.com/go-jose/go-jose/v4 v4.0.3 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-ole/go-ole v1.3.0 // indirect
 	github.com/go-ole/go-ole v1.3.0 // indirect
@@ -123,7 +123,7 @@ require (
 	github.com/go-sql-driver/mysql v1.8.1 // indirect
 	github.com/go-sql-driver/mysql v1.8.1 // indirect
 	github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
 	github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
 	github.com/goccy/go-json v0.10.3 // indirect
 	github.com/goccy/go-json v0.10.3 // indirect
-	github.com/gofrs/flock v0.8.1 // indirect
+	github.com/gofrs/flock v0.12.0 // indirect
 	github.com/gofrs/uuid v4.4.0+incompatible // indirect
 	github.com/gofrs/uuid v4.4.0+incompatible // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
@@ -131,13 +131,13 @@ require (
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
-	github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 // indirect
+	github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
-	github.com/googleapis/gax-go/v2 v2.12.4 // indirect
-	github.com/gophercloud/gophercloud v1.12.0 // indirect
+	github.com/googleapis/gax-go/v2 v2.12.5 // indirect
+	github.com/gophercloud/gophercloud v1.13.0 // indirect
 	github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
 	github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -162,7 +162,7 @@ require (
 	github.com/kataras/pio v0.0.13 // indirect
 	github.com/kataras/pio v0.0.13 // indirect
 	github.com/kataras/sitemap v0.0.6 // indirect
 	github.com/kataras/sitemap v0.0.6 // indirect
 	github.com/kataras/tunnel v0.0.4 // indirect
 	github.com/kataras/tunnel v0.0.4 // indirect
-	github.com/klauspost/compress v1.17.8 // indirect
+	github.com/klauspost/compress v1.17.9 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
 	github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
@@ -171,7 +171,7 @@ require (
 	github.com/labstack/echo/v4 v4.12.0 // indirect
 	github.com/labstack/echo/v4 v4.12.0 // indirect
 	github.com/labstack/gommon v0.4.2 // indirect
 	github.com/labstack/gommon v0.4.2 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
-	github.com/linode/linodego v1.35.0 // indirect
+	github.com/linode/linodego v1.37.0 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
 	github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
 	github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
@@ -180,8 +180,8 @@ require (
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-sqlite3 v1.14.22 // indirect
 	github.com/mattn/go-sqlite3 v1.14.22 // indirect
-	github.com/microcosm-cc/bluemonday v1.0.26 // indirect
-	github.com/miekg/dns v1.1.59 // indirect
+	github.com/microcosm-cc/bluemonday v1.0.27 // indirect
+	github.com/miekg/dns v1.1.61 // indirect
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -196,15 +196,15 @@ require (
 	github.com/nrdcg/mailinabox v0.2.0 // indirect
 	github.com/nrdcg/mailinabox v0.2.0 // indirect
 	github.com/nrdcg/namesilo v0.2.1 // indirect
 	github.com/nrdcg/namesilo v0.2.1 // indirect
 	github.com/nrdcg/nodion v0.1.0 // indirect
 	github.com/nrdcg/nodion v0.1.0 // indirect
-	github.com/nrdcg/porkbun v0.3.0 // indirect
+	github.com/nrdcg/porkbun v0.4.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
-	github.com/oracle/oci-go-sdk/v65 v65.67.0 // indirect
-	github.com/ovh/go-ovh v1.5.1 // indirect
+	github.com/oracle/oci-go-sdk/v65 v65.69.2 // indirect
+	github.com/ovh/go-ovh v1.6.0 // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/pquerna/otp v1.4.0 // indirect
 	github.com/pquerna/otp v1.4.0 // indirect
 	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/robfig/cron/v3 v3.0.1 // indirect
@@ -213,7 +213,7 @@ require (
 	github.com/sacloud/go-http v0.1.8 // indirect
 	github.com/sacloud/go-http v0.1.8 // indirect
 	github.com/sacloud/iaas-api-go v1.12.0 // indirect
 	github.com/sacloud/iaas-api-go v1.12.0 // indirect
 	github.com/sacloud/packages-go v0.0.10 // indirect
 	github.com/sacloud/packages-go v0.0.10 // indirect
-	github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 // indirect
+	github.com/scaleway/scaleway-sdk-go v1.0.0-beta.29 // indirect
 	github.com/schollz/closestmatch v2.1.0+incompatible // indirect
 	github.com/schollz/closestmatch v2.1.0+incompatible // indirect
 	github.com/selectel/domains-go v1.1.0 // indirect
 	github.com/selectel/domains-go v1.1.0 // indirect
 	github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect
 	github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect
@@ -224,13 +224,13 @@ require (
 	github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
 	github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
 	github.com/sony/gobreaker v1.0.0 // indirect
 	github.com/sony/gobreaker v1.0.0 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
-	github.com/tdewolff/minify/v2 v2.20.33 // indirect
-	github.com/tdewolff/parse/v2 v2.7.14 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.939 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.939 // indirect
+	github.com/tdewolff/minify/v2 v2.20.37 // indirect
+	github.com/tdewolff/parse/v2 v2.7.15 // indirect
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.967 // indirect
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.967 // indirect
 	github.com/tklauser/go-sysconf v0.3.14 // indirect
 	github.com/tklauser/go-sysconf v0.3.14 // indirect
 	github.com/tklauser/numcpus v0.8.0 // indirect
 	github.com/tklauser/numcpus v0.8.0 // indirect
-	github.com/transip/gotransip/v6 v6.24.0 // indirect
+	github.com/transip/gotransip/v6 v6.25.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
 	github.com/ultradns/ultradns-go-sdk v1.6.2-20240501171831-432d643 // indirect
 	github.com/ultradns/ultradns-go-sdk v1.6.2-20240501171831-432d643 // indirect
@@ -240,47 +240,47 @@ require (
 	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
 	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/vultr/govultr/v2 v2.17.2 // indirect
 	github.com/vultr/govultr/v2 v2.17.2 // indirect
-	github.com/yandex-cloud/go-genproto v0.0.0-20240529120826-df2b24336f42 // indirect
-	github.com/yandex-cloud/go-sdk v0.0.0-20240529122015-8b0dc5b8bcbf // indirect
+	github.com/yandex-cloud/go-genproto v0.0.0-20240715115219-0c1e192fbf5c // indirect
+	github.com/yandex-cloud/go-sdk v0.0.0-20240701143239-7326d2d09169 // indirect
 	github.com/yosssi/ace v0.0.5 // indirect
 	github.com/yosssi/ace v0.0.5 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
-	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
-	go.opentelemetry.io/otel v1.27.0 // indirect
-	go.opentelemetry.io/otel/metric v1.27.0 // indirect
-	go.opentelemetry.io/otel/trace v1.27.0 // indirect
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
+	go.opentelemetry.io/otel v1.28.0 // indirect
+	go.opentelemetry.io/otel/metric v1.28.0 // indirect
+	go.opentelemetry.io/otel/trace v1.28.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
 	golang.org/x/arch v0.8.0 // indirect
 	golang.org/x/arch v0.8.0 // indirect
-	golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
-	golang.org/x/mod v0.18.0 // indirect
-	golang.org/x/net v0.26.0 // indirect
+	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+	golang.org/x/mod v0.19.0 // indirect
+	golang.org/x/net v0.27.0 // indirect
 	golang.org/x/oauth2 v0.21.0 // indirect
 	golang.org/x/oauth2 v0.21.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/sys v0.21.0 // indirect
+	golang.org/x/sys v0.22.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	golang.org/x/tools v0.22.0 // indirect
-	google.golang.org/api v0.183.0 // indirect
-	google.golang.org/genproto v0.0.0-20240604185151-ef581f913117 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
-	google.golang.org/grpc v1.64.1 // indirect
-	google.golang.org/protobuf v1.34.1 // indirect
+	golang.org/x/tools v0.23.0 // indirect
+	google.golang.org/api v0.188.0 // indirect
+	google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
+	google.golang.org/grpc v1.65.0 // indirect
+	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.11.0 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.11.0 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	gorm.io/datatypes v1.2.0 // indirect
-	gorm.io/driver/mysql v1.5.6 // indirect
+	gorm.io/datatypes v1.2.1 // indirect
+	gorm.io/driver/mysql v1.5.7 // indirect
 	gorm.io/hints v1.1.2 // indirect
 	gorm.io/hints v1.1.2 // indirect
-	k8s.io/api v0.30.1 // indirect
-	k8s.io/apimachinery v0.30.1 // indirect
-	k8s.io/klog/v2 v2.120.1 // indirect
-	k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
+	k8s.io/api v0.30.3 // indirect
+	k8s.io/apimachinery v0.30.3 // indirect
+	k8s.io/klog/v2 v2.130.1 // indirect
+	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
 )

+ 170 - 168
go.sum

@@ -97,10 +97,10 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo
 cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
 cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
 cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
 cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
 cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
 cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
-cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw=
-cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s=
-cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
-cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
+cloud.google.com/go/auth v0.7.1 h1:Iv1bbpzJ2OIg16m94XI9/tlzZZl3cdeR3nGVGj78N7s=
+cloud.google.com/go/auth v0.7.1/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
+cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
+cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
 cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
 cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
 cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
 cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
 cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=
 cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=
@@ -179,8 +179,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
 cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
-cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
+cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
 cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
 cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
 cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
 cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
 cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
 cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
@@ -611,12 +611,12 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs
 github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo=
 github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
@@ -690,8 +690,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/alibaba-cloud-sdk-go v1.62.758 h1:jAq1MJDZkNZlqSAmzdyu5vauCB2O1Ki8BsJNkcFER00=
-github.com/aliyun/alibaba-cloud-sdk-go v1.62.758/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.793 h1:7FmdfF5fZMxM8Y0YtwrnMLkwud+egvoB5X5xczqISNQ=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.793/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
 github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
@@ -706,36 +706,36 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
 github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
 github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8=
-github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
-github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk=
-github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw=
+github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
+github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
+github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
+github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.38.3 h1:YdA5QgoYa2wNblkWyZfPlLLYsAEKCwLfdMxpWu16wpM=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.38.3/go.mod h1:T0LiPG5vKHZ7DmOq4Cmw0Kku3tMkaR9AknskS2hUXvI=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.40.10 h1:J9uHribwEgHmesH5r0enxsZYyiGBWd2AaExSW2SydqE=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.40.10/go.mod h1:tdzmlLwRjsHJjd4XXoSSnubCkVdRa39y4jCp4RACMkY=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
-github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
-github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
+github.com/aws/aws-sdk-go-v2/service/lightsail v1.40.3 h1:dy4sbyGy7BS4c0KaPZwg1P5ZP+lW+auTVcPiwrmbn8M=
+github.com/aws/aws-sdk-go-v2/service/lightsail v1.40.3/go.mod h1:EMgqMhof+RuaYvQavxKC0ZWvP7yB4B4NJhP+dbm13u0=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 h1:MmLCRqP4U4Cw9gJ4bNrCG0mWqEtBlmAVleyelcHARMU=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3/go.mod h1:AMPjK2YnRh0YgOID3PqhJA1BRNfXDfGOnSsKHtAe8yA=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
+github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
+github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -749,19 +749,20 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
 github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
 github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/bytedance/sonic v1.11.8 h1:Zw/j1KfiS+OYTi9lyB3bb0CFxPJVkM17k1wyDG32LRA=
-github.com/bytedance/sonic v1.11.8/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
+github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg=
+github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
 github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
 github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
 github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
 github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
-github.com/caarlos0/env/v11 v11.0.1 h1:A8dDt9Ub9ybqRSUF3fQc/TA/gTam2bKT4Pit+cwrsPs=
-github.com/caarlos0/env/v11 v11.0.1/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM=
-github.com/casdoor/casdoor-go-sdk v0.46.0 h1:4U/xas0k+7TmS34LAn105JJ/xsv3Lm9C4S3V68KqlKQ=
-github.com/casdoor/casdoor-go-sdk v0.46.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
+github.com/caarlos0/env/v11 v11.1.0 h1:a5qZqieE9ZfzdvbbdhTalRrHT5vu/4V1/ad1Ka6frhI=
+github.com/caarlos0/env/v11 v11.1.0/go.mod h1:LwgkYk1kDvfGpHthrWWLof3Ny7PezzFwS4QrsJdHTMo=
+github.com/casdoor/casdoor-go-sdk v0.47.0 h1:Fmyn5buhH9G2m41tr89Y/NwygingpXgoZwGVMTwUodU=
+github.com/casdoor/casdoor-go-sdk v0.47.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -775,11 +776,11 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/civo/civogo v0.3.70 h1:QPuFm5EmpkScbdFo5/6grcG2xcvd/lgdolOtENT04Ac=
-github.com/civo/civogo v0.3.70/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM=
+github.com/civo/civogo v0.3.73 h1:thkNnkziU+xh+MEOChIUwRZI1forN20+SSAPe/VFDME=
+github.com/civo/civogo v0.3.73/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/cloudflare-go v0.97.0 h1:feZRGiRF1EbljnNIYdt8014FnOLtC3CCvgkLXu915ks=
-github.com/cloudflare/cloudflare-go v0.97.0/go.mod h1:JXRwuTfHpe5xFg8xytc2w0XC6LcrFsBVMS4WlVaiGg8=
+github.com/cloudflare/cloudflare-go v0.100.0 h1:4iCUI2ZoIhRMyd7Z1TDsHhH1OhkgHC83eYbPlSgTRjo=
+github.com/cloudflare/cloudflare-go v0.100.0/go.mod h1:VQ1t9Mvgdu4VFLx6uwQgFC10XxcCRIUuvkYGc9daMRU=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
 github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@@ -811,10 +812,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
 github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
 github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
 github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/deepmap/oapi-codegen v1.16.3 h1:GT9G86SbQtT1r8ZB+4Cybi9VGdu1P5ieNvNdEoCSbrA=
 github.com/deepmap/oapi-codegen v1.16.3 h1:GT9G86SbQtT1r8ZB+4Cybi9VGdu1P5ieNvNdEoCSbrA=
 github.com/deepmap/oapi-codegen v1.16.3/go.mod h1:JD6ErqeX0nYnhdciLc61Konj3NBASREMlkHOgHn8WAM=
 github.com/deepmap/oapi-codegen v1.16.3/go.mod h1:JD6ErqeX0nYnhdciLc61Konj3NBASREMlkHOgHn8WAM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
@@ -840,8 +843,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
 github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
 github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
 github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
 github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
-github.com/exoscale/egoscale v0.102.3 h1:DYqN2ipoLKpiFoprRGQkp2av/Ze7sUYYlGhi1N62tfY=
-github.com/exoscale/egoscale v0.102.3/go.mod h1:RPf2Gah6up+6kAEayHTQwqapzXlm93f0VQas/UEGU5c=
+github.com/exoscale/egoscale v0.102.4 h1:GBKsZMIOzwBfSu+4ZmWka3Ejf2JLiaBDHp4CQUgvp2E=
+github.com/exoscale/egoscale v0.102.4/go.mod h1:ROSmPtle0wvf91iLZb09++N/9BH2Jo9XxIpAEumvocA=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
@@ -874,8 +877,8 @@ github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0Nglqm
 github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
 github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
 github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
 github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
 github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
 github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
-github.com/go-acme/lego/v4 v4.17.3 h1:5our7Qdyik0abag40abdmQuytq97iweaNHFMT4pYDnQ=
-github.com/go-acme/lego/v4 v4.17.3/go.mod h1:Ol6l04hnmavqVHKYS/ByhXXqE64x8yVYhomha82uAUk=
+github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q=
+github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U=
 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
 github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
 github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
 github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
 github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
@@ -890,8 +893,8 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
-github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
+github.com/go-jose/go-jose/v4 v4.0.3 h1:o8aphO8Hv6RPmH+GfzVuyf7YXSBibp+8YyHdOoDESGo=
+github.com/go-jose/go-jose/v4 v4.0.3/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
@@ -918,11 +921,10 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H8W+rNYyH/ySBb0=
-github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
+github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
 github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
 github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
 github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
 github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
 github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
 github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
@@ -940,8 +942,9 @@ github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
 github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
 github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
+github.com/gofrs/flock v0.12.0 h1:xHW8t8GPAiGtqz7KxiSqfOEXwpOaqhpYZrTE2MQBgXY=
+github.com/gofrs/flock v0.12.0/go.mod h1:FirDy1Ing0mI2+kB6wk+vyyAH+e6xiE+EYA0jnzV9jc=
 github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
 github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -949,8 +952,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
 github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
@@ -1004,8 +1005,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 h1:yEt5djSYb4iNtmV9iJGVday+i4e9u6Mrn5iP64HH5QM=
-github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 h1:saBP362Qm7zDdDXqv61kI4rzhmLFq3Z1gx34xpl6cWE=
+github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
@@ -1084,13 +1085,13 @@ github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMd
 github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
 github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
 github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
 github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
-github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
-github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
+github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
+github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
 github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
 github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
 github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
-github.com/gophercloud/gophercloud v1.12.0 h1:Jrz16vPAL93l80q16fp8NplrTCp93y7rZh2P3Q4Yq7g=
-github.com/gophercloud/gophercloud v1.12.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
+github.com/gophercloud/gophercloud v1.13.0 h1:8iY9d1DAbzMW6Vok1AxbbK5ZaUjzMp0tdyt4fX9IeJ0=
+github.com/gophercloud/gophercloud v1.13.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
 github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE=
 github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE=
 github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto=
 github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -1098,8 +1099,8 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
 github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gorilla/websocket v1.5.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
-github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -1177,16 +1178,17 @@ github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/my
 github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
 github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
-github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA=
-github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
+github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
+github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
+github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
 github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
 github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
 github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
 github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
 github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -1236,8 +1238,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
 github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
 github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
 github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
-github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
-github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
 github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -1272,8 +1274,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/linode/linodego v1.35.0 h1:rIhUeCHBLEDlkoRnOTwzSGzljQ3ksXwLxacmXnrV+Do=
-github.com/linode/linodego v1.35.0/go.mod h1:JxuhOEAMfSxun6RU5/MgTKH2GGTmFrhKRj3wL1NFin0=
+github.com/linode/linodego v1.37.0 h1:B/2Spzv9jYXzKA+p+GD8fVCNJ7Wuw6P91ZDD9eCkkso=
+github.com/linode/linodego v1.37.0/go.mod h1:L7GXKFD3PoN2xSEtFc04wIXP5WK65O10jYQx0PQISWQ=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
 github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
@@ -1322,16 +1324,16 @@ github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvr
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
 github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
 github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
 github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
-github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
-github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
 github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
 github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
 github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
 github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
 github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
-github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
+github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
+github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
 github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34=
 github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34=
 github.com/mimuret/golang-iij-dpf v0.9.1/go.mod h1:sl9KyOkESib9+KRD3HaGpgi1xk7eoN2+d96LCLsME2M=
 github.com/mimuret/golang-iij-dpf v0.9.1/go.mod h1:sl9KyOkESib9+KRD3HaGpgi1xk7eoN2+d96LCLsME2M=
 github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
 github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
@@ -1385,8 +1387,8 @@ github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
 github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
 github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
 github.com/nrdcg/nodion v0.1.0 h1:zLKaqTn2X0aDuBHHfyA1zFgeZfiCpmu/O9DM73okavw=
 github.com/nrdcg/nodion v0.1.0 h1:zLKaqTn2X0aDuBHHfyA1zFgeZfiCpmu/O9DM73okavw=
 github.com/nrdcg/nodion v0.1.0/go.mod h1:inbuh3neCtIWlMPZHtEpe43TmRXxHV6+hk97iCZicms=
 github.com/nrdcg/nodion v0.1.0/go.mod h1:inbuh3neCtIWlMPZHtEpe43TmRXxHV6+hk97iCZicms=
-github.com/nrdcg/porkbun v0.3.0 h1:jnRV7j2zd3hmh+tSDOGetJyy3+WklaMxbs7HtTTmWMs=
-github.com/nrdcg/porkbun v0.3.0/go.mod h1:jh1DKz96jGHW+NCdG3AmTbbnQeBlNUz1KeSgeN/cBVw=
+github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
+github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
 github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
@@ -1410,10 +1412,10 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
 github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
 github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
-github.com/oracle/oci-go-sdk/v65 v65.67.0 h1:bKcbNQyWUDiDgyE4crer3hZmiwpZ3rQnMi03jdKta/w=
-github.com/oracle/oci-go-sdk/v65 v65.67.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
-github.com/ovh/go-ovh v1.5.1 h1:P8O+7H+NQuFK9P/j4sFW5C0fvSS2DnHYGPwdVCp45wI=
-github.com/ovh/go-ovh v1.5.1/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
+github.com/oracle/oci-go-sdk/v65 v65.69.2 h1:lROMJ8/VakGOGObAWUxTVY2AX1wQCUIzVqfL4Fb2Ay8=
+github.com/oracle/oci-go-sdk/v65 v65.69.2/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
+github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI=
+github.com/ovh/go-ovh v1.6.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
 github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
@@ -1438,8 +1440,9 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
 github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
 github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
 github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
@@ -1502,14 +1505,14 @@ github.com/sacloud/iaas-api-go v1.12.0/go.mod h1:SZLXeWOdXk3WReIS557sbU1gkOgrE4r
 github.com/sacloud/packages-go v0.0.10 h1:UiQGjy8LretewkRhsuna1TBM9Vz/l9FoYpQx+D+AOck=
 github.com/sacloud/packages-go v0.0.10 h1:UiQGjy8LretewkRhsuna1TBM9Vz/l9FoYpQx+D+AOck=
 github.com/sacloud/packages-go v0.0.10/go.mod h1:f8QITBh9z4IZc4yE9j21Q8b0sXEMwRlRmhhjWeDVTYs=
 github.com/sacloud/packages-go v0.0.10/go.mod h1:f8QITBh9z4IZc4yE9j21Q8b0sXEMwRlRmhhjWeDVTYs=
 github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ=
 github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ=
-github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
-github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
+github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ=
+github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
 github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
 github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
 github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
 github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
-github.com/sashabaranov/go-openai v1.24.1 h1:DWK95XViNb+agQtuzsn+FyHhn3HQJ7Va8z04DQDJ1MI=
-github.com/sashabaranov/go-openai v1.24.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 h1:yGAraK1uUjlhSXgNMIy8o/J4LFNcy7yeipBqt9N9mVg=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
+github.com/sashabaranov/go-openai v1.27.0 h1:L3hO6650YUbKrbGUC6yCjsUluhKZ9h1/jcgbTItI8Mo=
+github.com/sashabaranov/go-openai v1.27.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.29 h1:BkTk4gynLjguayxrYxZoMZjBnAOh7ntQvUkOFmkMqPU=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.29/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
 github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
 github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
 github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
 github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -1596,24 +1599,24 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
-github.com/tdewolff/minify/v2 v2.20.33 h1:lZFesDQagd+zGxyC3fEO/X2jZWB8CrahKi77lNrgAAQ=
-github.com/tdewolff/minify/v2 v2.20.33/go.mod h1:1TJni7+mATKu24cBQQpgwakrYRD27uC1/rdJOgdv8ns=
-github.com/tdewolff/parse/v2 v2.7.14 h1:100KJ+QAO3PpMb3uUjzEU/NpmCdbBYz6KPmCIAfWpR8=
-github.com/tdewolff/parse/v2 v2.7.14/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
+github.com/tdewolff/minify/v2 v2.20.37 h1:Q97cx4STXCh1dlWDlNHZniE8BJ2EBL0+2b0n92BJQhw=
+github.com/tdewolff/minify/v2 v2.20.37/go.mod h1:L1VYef/jwKw6Wwyk5A+T0mBjjn3mMPgmjjA688RNsxU=
+github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw=
+github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
 github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
 github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.939 h1:rhoWKZbcj46KIfDTQnrGck8zA0LEgZURy6jhPuizOWE=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.939/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.939 h1:X32xf2dNYlkx+MXDL0NiugLgqeCtqEih8esM2wki6SQ=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.939/go.mod h1:HjiDxBO5QACtJ/vlD3sbyjmvdU7zbmU2dik5jVzeWOc=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.967 h1:ui73H/2pKk2aDCxaBCLAeMB3JlNgdCkn0nx1x0pqvf0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.967/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.967 h1:4w33xHFgyrlFZYoGkPQ3uhld8tqoezpObfmCBrdlFBY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.967/go.mod h1:T0RlPIT2imBeCxLkWfzoiEVP1r5WwzC6becSq7wvSgU=
 github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
 github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
 github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
 github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
 github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
 github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
 github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
 github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/transip/gotransip/v6 v6.24.0 h1:QaHgRT3ikpMCXr8Ntojiced/W4izd9ra9PNE/i+7qTE=
-github.com/transip/gotransip/v6 v6.24.0/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s=
+github.com/transip/gotransip/v6 v6.25.0 h1:/H+SjMq/9HNZ0/maE1OLhJpxLaCGHsxq0PWaMPJHxK4=
+github.com/transip/gotransip/v6 v6.25.0/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
@@ -1646,10 +1649,11 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
 github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
 github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
 github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yandex-cloud/go-genproto v0.0.0-20240529120826-df2b24336f42 h1:l5Wu1kRcM34HqBR2FZI6tWc6QKyPziNj5fGZ4eXTCRI=
-github.com/yandex-cloud/go-genproto v0.0.0-20240529120826-df2b24336f42/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
-github.com/yandex-cloud/go-sdk v0.0.0-20240529122015-8b0dc5b8bcbf h1:R46d2p9AmCeotDrb8alxjeSukKOtU1gNLnBDZxsS7F0=
-github.com/yandex-cloud/go-sdk v0.0.0-20240529122015-8b0dc5b8bcbf/go.mod h1:CuHkaRm2ZXv5SulglkbSFjdxh1R6VwpyfSM9EXMYz2U=
+github.com/yandex-cloud/go-genproto v0.0.0-20240701142715-6a03f33f8ec8/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
+github.com/yandex-cloud/go-genproto v0.0.0-20240715115219-0c1e192fbf5c h1:GzMfpQ/oAP93MOQb5/B+3daDzdcLRRqetZ8radtnJJ4=
+github.com/yandex-cloud/go-genproto v0.0.0-20240715115219-0c1e192fbf5c/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
+github.com/yandex-cloud/go-sdk v0.0.0-20240701143239-7326d2d09169 h1:5LGYQ/0h1uUo3HH8MsG6R40gvSVPj/7r4D1sKVMa370=
+github.com/yandex-cloud/go-sdk v0.0.0-20240701143239-7326d2d09169/go.mod h1:kRqpmRyPs8rzXuYEJe57AH546a3VcSjEIzdFa1V66hY=
 github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
 github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
 github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
 github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
 github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
 github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
@@ -1683,14 +1687,14 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0=
-go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
-go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
-go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
-go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
-go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
-go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
+go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
+go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
+go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
+go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -1740,8 +1744,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1757,8 +1761,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
-golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
-golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1801,8 +1805,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1878,8 +1882,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2044,8 +2048,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -2060,8 +2064,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2160,8 +2164,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
 golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
 golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
+golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2236,8 +2240,8 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
 google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
 google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
 google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
 google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
 google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
 google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
-google.golang.org/api v0.183.0 h1:PNMeRDwo1pJdgNcFQ9GstuLe/noWKIc89pRWRLMvLwE=
-google.golang.org/api v0.183.0/go.mod h1:q43adC5/pHoSZTx5h2mSmdF7NcyfW9JuDyIOJAgS9ZQ=
+google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw=
+google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2378,12 +2382,12 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl
 google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-google.golang.org/genproto v0.0.0-20240604185151-ef581f913117 h1:HCZ6DlkKtCDAtD8ForECsY3tKuaR+p4R3grlK80uCCc=
-google.golang.org/genproto v0.0.0-20240604185151-ef581f913117/go.mod h1:lesfX/+9iA+3OdqeCpoDddJaNxVB1AB6tD7EfqMmprc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
-google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
+google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d h1:/hmn0Ku5kWij/kjGsrcJeC1T/MrJi2iNWwgAqrihFwc=
+google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -2426,8 +2430,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
 google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
 google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
 google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
-google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
-google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -2446,8 +2450,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2490,31 +2494,29 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco=
-gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04=
-gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
-gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
+gorm.io/datatypes v1.2.1 h1:r+g0bk4LPCW2v4+Ls7aeNgGme7JYdNDQ2VtvlNUfBh0=
+gorm.io/datatypes v1.2.1/go.mod h1:hYK6OTb/1x+m96PgoZZq10UXJ6RvEBb9kRDQ2yyhzGs=
 gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
 gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
+gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
+gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
 gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
 gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
 gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
 gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
 gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
 gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
-gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
-gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
+gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
+gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
 gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
 gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
 gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
 gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
 gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY=
 gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY=
 gorm.io/gen v0.3.26/go.mod h1:a5lq5y3w4g5LMxBcw0wnO6tYUCdNutWODq5LrIt75LE=
 gorm.io/gen v0.3.26/go.mod h1:a5lq5y3w4g5LMxBcw0wnO6tYUCdNutWODq5LrIt75LE=
-gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
-gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
-gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
-gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
+gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
 gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o=
 gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o=
 gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
 gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
-gorm.io/plugin/dbresolver v1.5.1 h1:s9Dj9f7r+1rE3nx/Ywzc85nXptUEaeOO0pt27xdopM8=
-gorm.io/plugin/dbresolver v1.5.1/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
+gorm.io/plugin/dbresolver v1.5.2 h1:Iut7lW4TXNoVs++I+ra3zxjSxTRj4ocIeFEVp4lLhII=
+gorm.io/plugin/dbresolver v1.5.2/go.mod h1:jPh59GOQbO7v7v28ZKZPd45tr+u3vyT+8tHdfdfOWcU=
 gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
 gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
 gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
 gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2525,14 +2527,14 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
-k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
-k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
-k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
-k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
-k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
+k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
+k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
 modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=

+ 47 - 0
internal/user/login.go

@@ -0,0 +1,47 @@
+package user
+
+import (
+	"errors"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"golang.org/x/crypto/bcrypt"
+	"time"
+)
+
+var (
+	ErrPasswordIncorrect = errors.New("password incorrect")
+	ErrUserBanned        = errors.New("user banned")
+)
+
+func Login(name string, password string) (user *model.Auth, err error) {
+	u := query.Auth
+
+	user, err = u.Where(u.Name.Eq(name)).First()
+	if err != nil {
+		return nil, ErrPasswordIncorrect
+	}
+
+	if err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
+		return nil, ErrPasswordIncorrect
+	}
+
+	if !user.Status {
+		return nil, ErrUserBanned
+	}
+
+	return
+}
+
+func BanIP(ip string) {
+	b := query.BanIP
+	banIP, err := b.Where(b.IP.Eq(ip)).First()
+	if err != nil || banIP.ExpiredAt <= time.Now().Unix() {
+		_ = b.Create(&model.BanIP{
+			IP:        ip,
+			Attempts:  1,
+			ExpiredAt: time.Now().Unix() + int64(settings.AuthSettings.BanThresholdMinutes*60),
+		})
+	}
+	_, _ = b.Where(b.IP.Eq(ip)).UpdateSimple(b.Attempts.Add(1))
+}

+ 57 - 0
internal/user/user.go

@@ -0,0 +1,57 @@
+package user
+
+import (
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/dgrijalva/jwt-go"
+	"time"
+)
+
+type JWTClaims struct {
+	Name string `json:"name"`
+	jwt.StandardClaims
+}
+
+func GetUser(name string) (user model.Auth, err error) {
+	db := model.UseDB()
+	err = db.Where("name", name).First(&user).Error
+	if err != nil {
+		return
+	}
+	return
+}
+
+func DeleteToken(token string) error {
+	db := model.UseDB()
+	return db.Where("token", token).Delete(&model.AuthToken{}).Error
+}
+
+func CheckToken(token string) int64 {
+	db := model.UseDB()
+	return db.Where("token", token).Find(&model.AuthToken{}).RowsAffected
+}
+
+func GenerateJWT(name string) (string, error) {
+	claims := JWTClaims{
+		Name: name,
+		StandardClaims: jwt.StandardClaims{
+			ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
+		},
+	}
+	unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+	signedToken, err := unsignedToken.SignedString([]byte(settings.ServerSettings.JwtSecret))
+	if err != nil {
+		return "", err
+	}
+
+	db := model.UseDB()
+	err = db.Create(&model.AuthToken{
+		Token: signedToken,
+	}).Error
+
+	if err != nil {
+		return "", err
+	}
+
+	return signedToken, err
+}

+ 5 - 55
model/auth.go

@@ -1,63 +1,13 @@
 package model
 package model
 
 
-import (
-	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/golang-jwt/jwt"
-	"time"
-)
-
 type Auth struct {
 type Auth struct {
-	Model
+    Model
 
 
-	Name     string `json:"name"`
-	Password string `json:"-"`
+    Name     string `json:"name"`
+    Password string `json:"-"`
+    Status   bool   `json:"status" gorm:"default:1"`
 }
 }
 
 
 type AuthToken struct {
 type AuthToken struct {
-	Token string `json:"token"`
-}
-
-type JWTClaims struct {
-	Name string `json:"name"`
-	jwt.StandardClaims
-}
-
-func GetUser(name string) (user Auth, err error) {
-	err = db.Where("name = ?", name).First(&user).Error
-	if err != nil {
-		return Auth{}, err
-	}
-	return user, err
-}
-
-func DeleteToken(token string) error {
-	return db.Where("token = ?", token).Delete(&AuthToken{}).Error
-}
-
-func CheckToken(token string) int64 {
-	return db.Where("token = ?", token).Find(&AuthToken{}).RowsAffected
-}
-
-func GenerateJWT(name string) (string, error) {
-	claims := JWTClaims{
-		Name: name,
-		StandardClaims: jwt.StandardClaims{
-			ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
-		},
-	}
-	unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
-	signedToken, err := unsignedToken.SignedString([]byte(settings.ServerSettings.JwtSecret))
-	if err != nil {
-		return "", err
-	}
-
-	err = db.Create(&AuthToken{
-		Token: signedToken,
-	}).Error
-
-	if err != nil {
-		return "", err
-	}
-
-	return signedToken, err
+    Token string `json:"token"`
 }
 }

+ 7 - 0
model/ban_ip.go

@@ -0,0 +1,7 @@
+package model
+
+type BanIP struct {
+	IP        string `json:"ip"`
+	Attempts  int    `json:"attempts"`
+	ExpiredAt int64  `json:"expired_at" gorm:"index"`
+}

+ 1 - 0
model/model.go

@@ -35,6 +35,7 @@ func GenerateAllModel() []any {
 		Environment{},
 		Environment{},
 		Notification{},
 		Notification{},
 		AcmeUser{},
 		AcmeUser{},
+		BanIP{},
 	}
 	}
 }
 }
 
 

+ 5 - 1
query/auths.gen.go

@@ -34,6 +34,7 @@ func newAuth(db *gorm.DB, opts ...gen.DOOption) auth {
 	_auth.DeletedAt = field.NewField(tableName, "deleted_at")
 	_auth.DeletedAt = field.NewField(tableName, "deleted_at")
 	_auth.Name = field.NewString(tableName, "name")
 	_auth.Name = field.NewString(tableName, "name")
 	_auth.Password = field.NewString(tableName, "password")
 	_auth.Password = field.NewString(tableName, "password")
+	_auth.Status = field.NewBool(tableName, "status")
 
 
 	_auth.fillFieldMap()
 	_auth.fillFieldMap()
 
 
@@ -50,6 +51,7 @@ type auth struct {
 	DeletedAt field.Field
 	DeletedAt field.Field
 	Name      field.String
 	Name      field.String
 	Password  field.String
 	Password  field.String
+	Status    field.Bool
 
 
 	fieldMap map[string]field.Expr
 	fieldMap map[string]field.Expr
 }
 }
@@ -72,6 +74,7 @@ func (a *auth) updateTableName(table string) *auth {
 	a.DeletedAt = field.NewField(table, "deleted_at")
 	a.DeletedAt = field.NewField(table, "deleted_at")
 	a.Name = field.NewString(table, "name")
 	a.Name = field.NewString(table, "name")
 	a.Password = field.NewString(table, "password")
 	a.Password = field.NewString(table, "password")
+	a.Status = field.NewBool(table, "status")
 
 
 	a.fillFieldMap()
 	a.fillFieldMap()
 
 
@@ -88,13 +91,14 @@ func (a *auth) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
 }
 }
 
 
 func (a *auth) fillFieldMap() {
 func (a *auth) fillFieldMap() {
-	a.fieldMap = make(map[string]field.Expr, 6)
+	a.fieldMap = make(map[string]field.Expr, 7)
 	a.fieldMap["id"] = a.ID
 	a.fieldMap["id"] = a.ID
 	a.fieldMap["created_at"] = a.CreatedAt
 	a.fieldMap["created_at"] = a.CreatedAt
 	a.fieldMap["updated_at"] = a.UpdatedAt
 	a.fieldMap["updated_at"] = a.UpdatedAt
 	a.fieldMap["deleted_at"] = a.DeletedAt
 	a.fieldMap["deleted_at"] = a.DeletedAt
 	a.fieldMap["name"] = a.Name
 	a.fieldMap["name"] = a.Name
 	a.fieldMap["password"] = a.Password
 	a.fieldMap["password"] = a.Password
+	a.fieldMap["status"] = a.Status
 }
 }
 
 
 func (a auth) clone(db *gorm.DB) auth {
 func (a auth) clone(db *gorm.DB) auth {

+ 358 - 0
query/ban_ips.gen.go

@@ -0,0 +1,358 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package query
+
+import (
+	"context"
+	"strings"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+	"gorm.io/gorm/schema"
+
+	"gorm.io/gen"
+	"gorm.io/gen/field"
+
+	"gorm.io/plugin/dbresolver"
+
+	"github.com/0xJacky/Nginx-UI/model"
+)
+
+func newBanIP(db *gorm.DB, opts ...gen.DOOption) banIP {
+	_banIP := banIP{}
+
+	_banIP.banIPDo.UseDB(db, opts...)
+	_banIP.banIPDo.UseModel(&model.BanIP{})
+
+	tableName := _banIP.banIPDo.TableName()
+	_banIP.ALL = field.NewAsterisk(tableName)
+	_banIP.IP = field.NewString(tableName, "ip")
+	_banIP.Attempts = field.NewInt(tableName, "attempts")
+	_banIP.ExpiredAt = field.NewInt64(tableName, "expired_at")
+
+	_banIP.fillFieldMap()
+
+	return _banIP
+}
+
+type banIP struct {
+	banIPDo
+
+	ALL       field.Asterisk
+	IP        field.String
+	Attempts  field.Int
+	ExpiredAt field.Int64
+
+	fieldMap map[string]field.Expr
+}
+
+func (b banIP) Table(newTableName string) *banIP {
+	b.banIPDo.UseTable(newTableName)
+	return b.updateTableName(newTableName)
+}
+
+func (b banIP) As(alias string) *banIP {
+	b.banIPDo.DO = *(b.banIPDo.As(alias).(*gen.DO))
+	return b.updateTableName(alias)
+}
+
+func (b *banIP) updateTableName(table string) *banIP {
+	b.ALL = field.NewAsterisk(table)
+	b.IP = field.NewString(table, "ip")
+	b.Attempts = field.NewInt(table, "attempts")
+	b.ExpiredAt = field.NewInt64(table, "expired_at")
+
+	b.fillFieldMap()
+
+	return b
+}
+
+func (b *banIP) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
+	_f, ok := b.fieldMap[fieldName]
+	if !ok || _f == nil {
+		return nil, false
+	}
+	_oe, ok := _f.(field.OrderExpr)
+	return _oe, ok
+}
+
+func (b *banIP) fillFieldMap() {
+	b.fieldMap = make(map[string]field.Expr, 3)
+	b.fieldMap["ip"] = b.IP
+	b.fieldMap["attempts"] = b.Attempts
+	b.fieldMap["expired_at"] = b.ExpiredAt
+}
+
+func (b banIP) clone(db *gorm.DB) banIP {
+	b.banIPDo.ReplaceConnPool(db.Statement.ConnPool)
+	return b
+}
+
+func (b banIP) replaceDB(db *gorm.DB) banIP {
+	b.banIPDo.ReplaceDB(db)
+	return b
+}
+
+type banIPDo struct{ gen.DO }
+
+// FirstByID Where("id=@id")
+func (b banIPDo) FirstByID(id int) (result *model.BanIP, err error) {
+	var params []interface{}
+
+	var generateSQL strings.Builder
+	params = append(params, id)
+	generateSQL.WriteString("id=? ")
+
+	var executeSQL *gorm.DB
+	executeSQL = b.UnderlyingDB().Where(generateSQL.String(), params...).Take(&result) // ignore_security_alert
+	err = executeSQL.Error
+
+	return
+}
+
+// DeleteByID update @@table set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=@id
+func (b banIPDo) DeleteByID(id int) (err error) {
+	var params []interface{}
+
+	var generateSQL strings.Builder
+	params = append(params, id)
+	generateSQL.WriteString("update ban_ips set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=? ")
+
+	var executeSQL *gorm.DB
+	executeSQL = b.UnderlyingDB().Exec(generateSQL.String(), params...) // ignore_security_alert
+	err = executeSQL.Error
+
+	return
+}
+
+func (b banIPDo) Debug() *banIPDo {
+	return b.withDO(b.DO.Debug())
+}
+
+func (b banIPDo) WithContext(ctx context.Context) *banIPDo {
+	return b.withDO(b.DO.WithContext(ctx))
+}
+
+func (b banIPDo) ReadDB() *banIPDo {
+	return b.Clauses(dbresolver.Read)
+}
+
+func (b banIPDo) WriteDB() *banIPDo {
+	return b.Clauses(dbresolver.Write)
+}
+
+func (b banIPDo) Session(config *gorm.Session) *banIPDo {
+	return b.withDO(b.DO.Session(config))
+}
+
+func (b banIPDo) Clauses(conds ...clause.Expression) *banIPDo {
+	return b.withDO(b.DO.Clauses(conds...))
+}
+
+func (b banIPDo) Returning(value interface{}, columns ...string) *banIPDo {
+	return b.withDO(b.DO.Returning(value, columns...))
+}
+
+func (b banIPDo) Not(conds ...gen.Condition) *banIPDo {
+	return b.withDO(b.DO.Not(conds...))
+}
+
+func (b banIPDo) Or(conds ...gen.Condition) *banIPDo {
+	return b.withDO(b.DO.Or(conds...))
+}
+
+func (b banIPDo) Select(conds ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Select(conds...))
+}
+
+func (b banIPDo) Where(conds ...gen.Condition) *banIPDo {
+	return b.withDO(b.DO.Where(conds...))
+}
+
+func (b banIPDo) Order(conds ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Order(conds...))
+}
+
+func (b banIPDo) Distinct(cols ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Distinct(cols...))
+}
+
+func (b banIPDo) Omit(cols ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Omit(cols...))
+}
+
+func (b banIPDo) Join(table schema.Tabler, on ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Join(table, on...))
+}
+
+func (b banIPDo) LeftJoin(table schema.Tabler, on ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.LeftJoin(table, on...))
+}
+
+func (b banIPDo) RightJoin(table schema.Tabler, on ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.RightJoin(table, on...))
+}
+
+func (b banIPDo) Group(cols ...field.Expr) *banIPDo {
+	return b.withDO(b.DO.Group(cols...))
+}
+
+func (b banIPDo) Having(conds ...gen.Condition) *banIPDo {
+	return b.withDO(b.DO.Having(conds...))
+}
+
+func (b banIPDo) Limit(limit int) *banIPDo {
+	return b.withDO(b.DO.Limit(limit))
+}
+
+func (b banIPDo) Offset(offset int) *banIPDo {
+	return b.withDO(b.DO.Offset(offset))
+}
+
+func (b banIPDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *banIPDo {
+	return b.withDO(b.DO.Scopes(funcs...))
+}
+
+func (b banIPDo) Unscoped() *banIPDo {
+	return b.withDO(b.DO.Unscoped())
+}
+
+func (b banIPDo) Create(values ...*model.BanIP) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return b.DO.Create(values)
+}
+
+func (b banIPDo) CreateInBatches(values []*model.BanIP, batchSize int) error {
+	return b.DO.CreateInBatches(values, batchSize)
+}
+
+// Save : !!! underlying implementation is different with GORM
+// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
+func (b banIPDo) Save(values ...*model.BanIP) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return b.DO.Save(values)
+}
+
+func (b banIPDo) First() (*model.BanIP, error) {
+	if result, err := b.DO.First(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.BanIP), nil
+	}
+}
+
+func (b banIPDo) Take() (*model.BanIP, error) {
+	if result, err := b.DO.Take(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.BanIP), nil
+	}
+}
+
+func (b banIPDo) Last() (*model.BanIP, error) {
+	if result, err := b.DO.Last(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.BanIP), nil
+	}
+}
+
+func (b banIPDo) Find() ([]*model.BanIP, error) {
+	result, err := b.DO.Find()
+	return result.([]*model.BanIP), err
+}
+
+func (b banIPDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.BanIP, err error) {
+	buf := make([]*model.BanIP, 0, batchSize)
+	err = b.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
+		defer func() { results = append(results, buf...) }()
+		return fc(tx, batch)
+	})
+	return results, err
+}
+
+func (b banIPDo) FindInBatches(result *[]*model.BanIP, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+	return b.DO.FindInBatches(result, batchSize, fc)
+}
+
+func (b banIPDo) Attrs(attrs ...field.AssignExpr) *banIPDo {
+	return b.withDO(b.DO.Attrs(attrs...))
+}
+
+func (b banIPDo) Assign(attrs ...field.AssignExpr) *banIPDo {
+	return b.withDO(b.DO.Assign(attrs...))
+}
+
+func (b banIPDo) Joins(fields ...field.RelationField) *banIPDo {
+	for _, _f := range fields {
+		b = *b.withDO(b.DO.Joins(_f))
+	}
+	return &b
+}
+
+func (b banIPDo) Preload(fields ...field.RelationField) *banIPDo {
+	for _, _f := range fields {
+		b = *b.withDO(b.DO.Preload(_f))
+	}
+	return &b
+}
+
+func (b banIPDo) FirstOrInit() (*model.BanIP, error) {
+	if result, err := b.DO.FirstOrInit(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.BanIP), nil
+	}
+}
+
+func (b banIPDo) FirstOrCreate() (*model.BanIP, error) {
+	if result, err := b.DO.FirstOrCreate(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.BanIP), nil
+	}
+}
+
+func (b banIPDo) FindByPage(offset int, limit int) (result []*model.BanIP, count int64, err error) {
+	result, err = b.Offset(offset).Limit(limit).Find()
+	if err != nil {
+		return
+	}
+
+	if size := len(result); 0 < limit && 0 < size && size < limit {
+		count = int64(size + offset)
+		return
+	}
+
+	count, err = b.Offset(-1).Limit(-1).Count()
+	return
+}
+
+func (b banIPDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
+	count, err = b.Count()
+	if err != nil {
+		return
+	}
+
+	err = b.Offset(offset).Limit(limit).Scan(result)
+	return
+}
+
+func (b banIPDo) Scan(result interface{}) (err error) {
+	return b.DO.Scan(result)
+}
+
+func (b banIPDo) Delete(models ...*model.BanIP) (result gen.ResultInfo, err error) {
+	return b.DO.Delete(models)
+}
+
+func (b *banIPDo) withDO(do gen.Dao) *banIPDo {
+	b.DO = *do.(*gen.DO)
+	return b
+}

+ 8 - 0
query/gen.go

@@ -20,6 +20,7 @@ var (
 	AcmeUser      *acmeUser
 	AcmeUser      *acmeUser
 	Auth          *auth
 	Auth          *auth
 	AuthToken     *authToken
 	AuthToken     *authToken
+	BanIP         *banIP
 	Cert          *cert
 	Cert          *cert
 	ChatGPTLog    *chatGPTLog
 	ChatGPTLog    *chatGPTLog
 	ConfigBackup  *configBackup
 	ConfigBackup  *configBackup
@@ -35,6 +36,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
 	AcmeUser = &Q.AcmeUser
 	AcmeUser = &Q.AcmeUser
 	Auth = &Q.Auth
 	Auth = &Q.Auth
 	AuthToken = &Q.AuthToken
 	AuthToken = &Q.AuthToken
+	BanIP = &Q.BanIP
 	Cert = &Q.Cert
 	Cert = &Q.Cert
 	ChatGPTLog = &Q.ChatGPTLog
 	ChatGPTLog = &Q.ChatGPTLog
 	ConfigBackup = &Q.ConfigBackup
 	ConfigBackup = &Q.ConfigBackup
@@ -51,6 +53,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
 		AcmeUser:      newAcmeUser(db, opts...),
 		AcmeUser:      newAcmeUser(db, opts...),
 		Auth:          newAuth(db, opts...),
 		Auth:          newAuth(db, opts...),
 		AuthToken:     newAuthToken(db, opts...),
 		AuthToken:     newAuthToken(db, opts...),
+		BanIP:         newBanIP(db, opts...),
 		Cert:          newCert(db, opts...),
 		Cert:          newCert(db, opts...),
 		ChatGPTLog:    newChatGPTLog(db, opts...),
 		ChatGPTLog:    newChatGPTLog(db, opts...),
 		ConfigBackup:  newConfigBackup(db, opts...),
 		ConfigBackup:  newConfigBackup(db, opts...),
@@ -68,6 +71,7 @@ type Query struct {
 	AcmeUser      acmeUser
 	AcmeUser      acmeUser
 	Auth          auth
 	Auth          auth
 	AuthToken     authToken
 	AuthToken     authToken
+	BanIP         banIP
 	Cert          cert
 	Cert          cert
 	ChatGPTLog    chatGPTLog
 	ChatGPTLog    chatGPTLog
 	ConfigBackup  configBackup
 	ConfigBackup  configBackup
@@ -86,6 +90,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
 		AcmeUser:      q.AcmeUser.clone(db),
 		AcmeUser:      q.AcmeUser.clone(db),
 		Auth:          q.Auth.clone(db),
 		Auth:          q.Auth.clone(db),
 		AuthToken:     q.AuthToken.clone(db),
 		AuthToken:     q.AuthToken.clone(db),
+		BanIP:         q.BanIP.clone(db),
 		Cert:          q.Cert.clone(db),
 		Cert:          q.Cert.clone(db),
 		ChatGPTLog:    q.ChatGPTLog.clone(db),
 		ChatGPTLog:    q.ChatGPTLog.clone(db),
 		ConfigBackup:  q.ConfigBackup.clone(db),
 		ConfigBackup:  q.ConfigBackup.clone(db),
@@ -111,6 +116,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
 		AcmeUser:      q.AcmeUser.replaceDB(db),
 		AcmeUser:      q.AcmeUser.replaceDB(db),
 		Auth:          q.Auth.replaceDB(db),
 		Auth:          q.Auth.replaceDB(db),
 		AuthToken:     q.AuthToken.replaceDB(db),
 		AuthToken:     q.AuthToken.replaceDB(db),
+		BanIP:         q.BanIP.replaceDB(db),
 		Cert:          q.Cert.replaceDB(db),
 		Cert:          q.Cert.replaceDB(db),
 		ChatGPTLog:    q.ChatGPTLog.replaceDB(db),
 		ChatGPTLog:    q.ChatGPTLog.replaceDB(db),
 		ConfigBackup:  q.ConfigBackup.replaceDB(db),
 		ConfigBackup:  q.ConfigBackup.replaceDB(db),
@@ -126,6 +132,7 @@ type queryCtx struct {
 	AcmeUser      *acmeUserDo
 	AcmeUser      *acmeUserDo
 	Auth          *authDo
 	Auth          *authDo
 	AuthToken     *authTokenDo
 	AuthToken     *authTokenDo
+	BanIP         *banIPDo
 	Cert          *certDo
 	Cert          *certDo
 	ChatGPTLog    *chatGPTLogDo
 	ChatGPTLog    *chatGPTLogDo
 	ConfigBackup  *configBackupDo
 	ConfigBackup  *configBackupDo
@@ -141,6 +148,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
 		AcmeUser:      q.AcmeUser.WithContext(ctx),
 		AcmeUser:      q.AcmeUser.WithContext(ctx),
 		Auth:          q.Auth.WithContext(ctx),
 		Auth:          q.Auth.WithContext(ctx),
 		AuthToken:     q.AuthToken.WithContext(ctx),
 		AuthToken:     q.AuthToken.WithContext(ctx),
+		BanIP:         q.BanIP.WithContext(ctx),
 		Cert:          q.Cert.WithContext(ctx),
 		Cert:          q.Cert.WithContext(ctx),
 		ChatGPTLog:    q.ChatGPTLog.WithContext(ctx),
 		ChatGPTLog:    q.ChatGPTLog.WithContext(ctx),
 		ConfigBackup:  q.ConfigBackup.WithContext(ctx),
 		ConfigBackup:  q.ConfigBackup.WithContext(ctx),

+ 25 - 0
router/ip.go

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
+	"github.com/samber/lo"
+	"net/http"
+)
+
+func ipWhiteList() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		clientIP := c.ClientIP()
+		if len(settings.AuthSettings.IPWhiteList) == 0 || clientIP == "127.0.0.1" {
+			c.Next()
+			return
+		}
+
+		if !lo.Contains(settings.AuthSettings.IPWhiteList, clientIP) {
+			c.AbortWithStatus(http.StatusForbidden)
+			return
+		}
+
+		c.Next()
+	}
+}

+ 2 - 2
router/middleware.go

@@ -4,7 +4,7 @@ import (
 	"encoding/base64"
 	"encoding/base64"
 	"github.com/0xJacky/Nginx-UI/app"
 	"github.com/0xJacky/Nginx-UI/app"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/internal/user"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-contrib/static"
 	"github.com/gin-contrib/static"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
@@ -58,7 +58,7 @@ func authRequired() gin.HandlerFunc {
 			}
 			}
 		}
 		}
 
 
-		if model.CheckToken(token) < 1 {
+		if user.CheckToken(token) < 1 {
 			abortWithAuthFailure()
 			abortWithAuthFailure()
 			return
 			return
 		}
 		}

+ 3 - 2
router/routers.go

@@ -8,6 +8,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api/nginx"
 	"github.com/0xJacky/Nginx-UI/api/nginx"
 	"github.com/0xJacky/Nginx-UI/api/notification"
 	"github.com/0xJacky/Nginx-UI/api/notification"
 	"github.com/0xJacky/Nginx-UI/api/openai"
 	"github.com/0xJacky/Nginx-UI/api/openai"
+	"github.com/0xJacky/Nginx-UI/api/settings"
 	"github.com/0xJacky/Nginx-UI/api/sites"
 	"github.com/0xJacky/Nginx-UI/api/sites"
 	"github.com/0xJacky/Nginx-UI/api/streams"
 	"github.com/0xJacky/Nginx-UI/api/streams"
 	"github.com/0xJacky/Nginx-UI/api/system"
 	"github.com/0xJacky/Nginx-UI/api/system"
@@ -23,10 +24,9 @@ import (
 func InitRouter() *gin.Engine {
 func InitRouter() *gin.Engine {
 	r := gin.New()
 	r := gin.New()
 	r.Use(gin.Logger())
 	r.Use(gin.Logger())
-
 	r.Use(recovery())
 	r.Use(recovery())
-
 	r.Use(cacheJs())
 	r.Use(cacheJs())
+	r.Use(ipWhiteList())
 
 
 	//r.Use(OperationSync())
 	//r.Use(OperationSync())
 
 
@@ -57,6 +57,7 @@ func InitRouter() *gin.Engine {
 			certificate.InitDNSCredentialRouter(g)
 			certificate.InitDNSCredentialRouter(g)
 			certificate.InitAcmeUserRouter(g)
 			certificate.InitAcmeUserRouter(g)
 			system.InitPrivateRouter(g)
 			system.InitPrivateRouter(g)
+			settings.InitRouter(g)
 			openai.InitRouter(g)
 			openai.InitRouter(g)
 			cluster.InitRouter(g)
 			cluster.InitRouter(g)
 			notification.InitRouter(g)
 			notification.InitRouter(g)

+ 12 - 0
settings/auth.go

@@ -0,0 +1,12 @@
+package settings
+
+type Auth struct {
+	IPWhiteList         []string `json:"ip_white_list" binding:"omitempty,dive,ip" ini:",,allowshadow"`
+	BanThresholdMinutes int      `json:"ban_threshold_minutes" binding:"min=1"`
+	MaxAttempts         int      `json:"max_attempts" binding:"min=1"`
+}
+
+var AuthSettings = Auth{
+	BanThresholdMinutes: 10,
+	MaxAttempts:         10,
+}

+ 10 - 0
settings/settings.go

@@ -27,6 +27,7 @@ var sections = map[string]interface{}{
 	"casdoor":   &CasdoorSettings,
 	"casdoor":   &CasdoorSettings,
 	"logrotate": &LogrotateSettings,
 	"logrotate": &LogrotateSettings,
 	"cluster":   &ClusterSettings,
 	"cluster":   &ClusterSettings,
+	"auth":      &AuthSettings,
 }
 }
 
 
 func init() {
 func init() {
@@ -62,6 +63,7 @@ func Setup() {
 	parseEnv(&OpenAISettings, "OPENAI_")
 	parseEnv(&OpenAISettings, "OPENAI_")
 	parseEnv(&CasdoorSettings, "CASDOOR_")
 	parseEnv(&CasdoorSettings, "CASDOOR_")
 	parseEnv(&LogrotateSettings, "LOGROTATE_")
 	parseEnv(&LogrotateSettings, "LOGROTATE_")
+	parseEnv(&AuthSettings, "AUTH_")
 
 
 	// if in official docker, set the restart cmd of nginx to "nginx -s stop",
 	// if in official docker, set the restart cmd of nginx to "nginx -s stop",
 	// then the supervisor of s6-overlay will start the nginx again.
 	// then the supervisor of s6-overlay will start the nginx again.
@@ -69,6 +71,14 @@ func Setup() {
 		NginxSettings.RestartCmd = "nginx -s stop"
 		NginxSettings.RestartCmd = "nginx -s stop"
 	}
 	}
 
 
+	if AuthSettings.BanThresholdMinutes <= 0 {
+		AuthSettings.BanThresholdMinutes = 10
+	}
+
+	if AuthSettings.MaxAttempts <= 0 {
+		AuthSettings.MaxAttempts = 10
+	}
+
 	err = Save()
 	err = Save()
 	if err != nil {
 	if err != nil {
 		log.Fatalf("settings.Setup: %v\n", err)
 		log.Fatalf("settings.Setup: %v\n", err)

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.