Bladeren bron

Merge branch 'dev' into refactor/otp

Hintay 2 maanden geleden
bovenliggende
commit
121287df21
40 gewijzigde bestanden met toevoegingen van 1084 en 326 verwijderingen
  1. 28 0
      .github/workflows/sync-main-on-release.yml
  2. 22 0
      api/crypto/crypto.go
  3. 10 0
      api/crypto/router.go
  4. 2 1
      api/system/router.go
  5. 1 1
      api/user/router.go
  6. 1 0
      app/package.json
  7. 8 0
      app/pnpm-lock.yaml
  8. 1 1
      app/src/api/auth.ts
  9. 1 1
      app/src/api/install.ts
  10. 1 0
      app/src/constants/errors/crypto.ts
  11. 4 0
      app/src/constants/errors/middleware.ts
  12. 18 0
      app/src/constants/llm.ts
  13. 34 20
      app/src/language/ar/app.po
  14. 34 20
      app/src/language/en/app.po
  15. 34 20
      app/src/language/es/app.po
  16. 33 20
      app/src/language/fr_FR/app.po
  17. 102 0
      app/src/language/ko_KR/app.po
  18. 33 21
      app/src/language/messages.pot
  19. 108 0
      app/src/language/ru_RU/app.po
  20. 110 0
      app/src/language/tr_TR/app.po
  21. 102 0
      app/src/language/vi_VN/app.po
  22. 34 20
      app/src/language/zh_CN/app.po
  23. 61 57
      app/src/language/zh_TW/app.po
  24. 48 42
      app/src/lib/http/index.ts
  25. 1 1
      app/src/version.json
  26. 10 21
      app/src/views/preference/OpenAISettings.vue
  27. 11 0
      app/src/views/site/ngx_conf/config_template/ConfigTemplate.vue
  28. 7 0
      app/src/vite-env.d.ts
  29. 1 1
      gen.sh
  30. 3 3
      go.mod
  31. 6 60
      go.sum
  32. 102 0
      internal/crypto/crypto.go
  33. 1 0
      internal/crypto/errors.go
  34. 9 6
      internal/kernel/boot.go
  35. 46 0
      internal/middleware/encrypted_params.go
  36. 8 8
      internal/middleware/middleware.go
  37. 6 2
      internal/middleware/proxy_ws.go
  38. 32 0
      internal/nginx/nginx_directives.json
  39. 2 0
      router/routers.go
  40. 9 0
      template/block/vue-router-history-mode.conf

+ 28 - 0
.github/workflows/sync-main-on-release.yml

@@ -0,0 +1,28 @@
+name: Sync branch
+
+on:
+  workflow_dispatch:
+  release:
+    types: [published]
+    branches: [dev]
+
+jobs:
+  force-push-main:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+          ref: dev
+          clean: false
+
+      - name: Configure Git
+        run: |
+          git config --global user.name "github-actions[bot]"
+          git config --global user.email "github-actions[bot]@users.noreply.github.com"
+
+      - name: Force push dev to main
+        run: |
+          git fetch origin
+          git push origin dev:main --force

+ 22 - 0
api/crypto/crypto.go

@@ -0,0 +1,22 @@
+package crypto
+
+import (
+	"net/http"
+
+	"github.com/0xJacky/Nginx-UI/api"
+	"github.com/0xJacky/Nginx-UI/internal/crypto"
+	"github.com/gin-gonic/gin"
+)
+
+// GetPublicKey generates a new ED25519 key pair and registers it in the cache
+func GetPublicKey(c *gin.Context) {
+	params, err := crypto.GetCryptoParams()
+	if err != nil {
+		api.ErrHandler(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"public_key": params.PublicKey,
+	})
+}

+ 10 - 0
api/crypto/router.go

@@ -0,0 +1,10 @@
+package crypto
+
+import "github.com/gin-gonic/gin"
+
+func InitPublicRouter(r *gin.RouterGroup) {
+	g := r.Group("/crypto")
+	{
+		g.GET("public_key", GetPublicKey)
+	}
+}

+ 2 - 1
api/system/router.go

@@ -1,12 +1,13 @@
 package system
 
 import (
+	"github.com/0xJacky/Nginx-UI/internal/middleware"
 	"github.com/gin-gonic/gin"
 )
 
 func InitPublicRouter(r *gin.RouterGroup) {
 	r.GET("install", InstallLockCheck)
-	r.POST("install", InstallNginxUI)
+	r.POST("install", middleware.EncryptedParams(), InstallNginxUI)
 	r.GET("translation/:code", GetTranslation)
 }
 

+ 1 - 1
api/user/router.go

@@ -6,7 +6,7 @@ import (
 )
 
 func InitAuthRouter(r *gin.RouterGroup) {
-	r.POST("/login", Login)
+	r.POST("/login", middleware.EncryptedParams(), Login)
 	r.DELETE("/logout", Logout)
 
 	r.GET("/begin_passkey_login", BeginPasskeyLogin)

+ 1 - 0
app/package.json

@@ -30,6 +30,7 @@
     "axios": "^1.7.9",
     "dayjs": "^1.11.13",
     "highlight.js": "^11.11.1",
+    "jsencrypt": "^3.3.2",
     "lodash": "^4.17.21",
     "marked": "^15.0.6",
     "marked-highlight": "^2.2.1",

+ 8 - 0
app/pnpm-lock.yaml

@@ -59,6 +59,9 @@ importers:
       highlight.js:
         specifier: ^11.11.1
         version: 11.11.1
+      jsencrypt:
+        specifier: ^3.3.2
+        version: 3.3.2
       lodash:
         specifier: ^4.17.21
         version: 4.17.21
@@ -3122,6 +3125,9 @@ packages:
     resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
     engines: {node: '>=12.0.0'}
 
+  jsencrypt@3.3.2:
+    resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
+
   jsesc@0.5.0:
     resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
     hasBin: true
@@ -7904,6 +7910,8 @@ snapshots:
 
   jsdoc-type-pratt-parser@4.1.0: {}
 
+  jsencrypt@3.3.2: {}
+
   jsesc@0.5.0: {}
 
   jsesc@3.0.2: {}

+ 1 - 1
app/src/api/auth.ts

@@ -19,7 +19,7 @@ const auth = {
       password,
       otp,
       recovery_code: recoveryCode,
-    })
+    }, { crypto: true })
   },
   async casdoor_login(code?: string, state?: string) {
     await http.post('/casdoor_callback', {

+ 1 - 1
app/src/api/install.ts

@@ -12,7 +12,7 @@ const install = {
     return http.get('/install')
   },
   install_nginx_ui(data: InstallRequest) {
-    return http.post('/install', data)
+    return http.post('/install', data, { crypto: true })
   },
 }
 

+ 1 - 0
app/src/constants/errors/crypto.ts

@@ -1,4 +1,5 @@
 export default {
   50001: () => $gettext('Plain text is empty'),
   50002: () => $gettext('Cipher text is too short'),
+  40401: () => $gettext('Request timeout'),
 }

+ 4 - 0
app/src/constants/errors/middleware.ts

@@ -0,0 +1,4 @@
+export default {
+  40000: () => $gettext('Invalid request format'),
+  40001: () => $gettext('Decryption failed'),
+}

+ 18 - 0
app/src/constants/llm.ts

@@ -0,0 +1,18 @@
+export const LLM_MODELS = [
+  'o3-mini',
+  'o1',
+  'deepseek-reasoner',
+  'deepseek-chat',
+  'gpt-4o-mini',
+  'gpt-4o',
+  'gpt-4',
+  'gpt-4-32k',
+  'gpt-4-turbo',
+  'gpt-3.5-turbo',
+]
+
+export const LLM_PROVIDERS = [
+  'https://api.openai.com',
+  'https://api.deepseek.com',
+  'http://localhost:11434',
+]

+ 34 - 20
app/src/language/ar/app.po

@@ -106,7 +106,7 @@ msgstr "بعد ذلك، قم بتحديث هذه الصفحة وانقر فوق
 msgid "All"
 msgstr "الكل"
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr "عنوان URL الأساسي لAPI"
 
@@ -114,15 +114,15 @@ msgstr "عنوان URL الأساسي لAPI"
 msgid "API Document"
 msgstr "ملف API"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr "وسيط API"
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr "رمز API"
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 #, fuzzy
 msgid "API Type"
 msgstr "رمز API"
@@ -222,7 +222,7 @@ msgstr "محاولات"
 msgid "Auth"
 msgstr "مصادقة"
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr "المصادقة باستخدام مفتاح المرور"
 
@@ -617,6 +617,11 @@ msgstr "قاعدة البيانات (اختياري، الافتراضي: قاع
 msgid "Days"
 msgstr "أيام"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "وصف"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1231,7 +1236,7 @@ msgstr "بدء ترقية النواة"
 msgid "Input the code from the app:"
 msgstr "أدخل الرمز من التطبيق:"
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr "أدخل رمز الاسترداد:"
 
@@ -1274,6 +1279,11 @@ msgstr "رمز المرور أو رمز الاسترداد غير صالح"
 msgid "Invalid recovery code"
 msgstr "رمز 2FA أو الاسترداد غير صالح"
 
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "رمز 2FA أو الاسترداد غير صالح"
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr "IP"
@@ -1321,7 +1331,7 @@ msgstr "آخر استخدام في"
 msgid "Leave blank for no change"
 msgstr "اتركه فارغًا لعدم التغيير"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "اتركه فارغًا للإعداد الافتراضي: /https://api.openai.com"
 
@@ -1384,7 +1394,7 @@ msgstr "أماكن"
 msgid "Log"
 msgstr "سجل"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "تسجيل الدخول"
 
@@ -1462,7 +1472,7 @@ msgstr "الذاكرة والتخزين"
 msgid "Minutes"
 msgstr "دقائق"
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 msgid "Model"
 msgstr "نموذج"
 
@@ -1746,7 +1756,7 @@ msgstr "متصل"
 msgid "OpenAI"
 msgstr "أوبن أي آي"
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr "أو"
 
@@ -1853,7 +1863,7 @@ msgid ""
 msgstr ""
 "يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "يرجى إدخال رمز OTP:"
 
@@ -1992,7 +2002,7 @@ msgstr "استعادة"
 msgid "Recovered Successfully"
 msgstr "تم الاسترداد بنجاح"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr "استرداد"
 
@@ -2163,6 +2173,10 @@ msgstr "تجديد الشهادة بنجاح"
 msgid "Renew successfully"
 msgstr "تم التجديد بنجاح"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "تم الطلب باستخدام عوامل خاطئة"
@@ -2340,7 +2354,7 @@ msgstr ""
 msgid "Show"
 msgstr "عرض"
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr "تسجيل الدخول باستخدام مفتاح المرور"
 
@@ -2592,7 +2606,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 #, fuzzy
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
@@ -2647,8 +2661,8 @@ msgstr ""
 msgid "The url is invalid"
 msgstr "عنوان URL غير صالح"
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr "عنوان URL غير صالح."
 
@@ -2746,7 +2760,7 @@ msgstr ""
 "توجيه الطلب من السلطة إلى الخلفية، ونحتاج إلى حفظ هذا الملف وإعادة تحميل "
 "Nginx. هل أنت متأكد أنك تريد المتابعة؟"
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 #, fuzzy
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
@@ -2757,7 +2771,7 @@ msgstr ""
 "نهاية API متوافقة مع OpenAI، لذا قم فقط بتعيين baseUrl إلىAPI المحلية الخاصة "
 "بك."
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr "الرمز غير صالح"
 
@@ -2845,11 +2859,11 @@ msgstr "مدة التشغيل:"
 msgid "URL"
 msgstr "عنوان URL"
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr "استخدم كلمة المرور لمرة واحدة"
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr "استخدم رمز الاسترداد"
 

+ 34 - 20
app/src/language/en/app.po

@@ -108,7 +108,7 @@ msgstr ""
 msgid "All"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr ""
 
@@ -117,15 +117,15 @@ msgstr ""
 msgid "API Document"
 msgstr "Comments"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 msgid "API Type"
 msgstr ""
 
@@ -233,7 +233,7 @@ msgstr ""
 msgid "Auth"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr ""
 
@@ -634,6 +634,11 @@ msgstr "Database (Optional, default: database)"
 msgid "Days"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Enable failed"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1279,7 +1284,7 @@ msgstr ""
 msgid "Input the code from the app:"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr ""
 
@@ -1326,6 +1331,11 @@ msgstr ""
 msgid "Invalid recovery code"
 msgstr "Invalid E-mail!"
 
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "Invalid E-mail!"
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr ""
@@ -1378,7 +1388,7 @@ msgstr "Created at"
 msgid "Leave blank for no change"
 msgstr "Leave blank for no change"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 
@@ -1449,7 +1459,7 @@ msgstr "Locations"
 msgid "Log"
 msgstr "Login"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "Login"
 
@@ -1524,7 +1534,7 @@ msgstr "Memory and Storage"
 msgid "Minutes"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 #, fuzzy
 msgid "Model"
 msgstr "Advance Mode"
@@ -1822,7 +1832,7 @@ msgstr ""
 msgid "OpenAI"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr ""
 
@@ -1926,7 +1936,7 @@ msgid ""
 "button below."
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr ""
 
@@ -2068,7 +2078,7 @@ msgstr ""
 msgid "Recovered Successfully"
 msgstr "Saved successfully"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr ""
 
@@ -2260,6 +2270,10 @@ msgstr "Certificate is valid"
 msgid "Renew successfully"
 msgstr "Enabled successfully"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr ""
@@ -2442,7 +2456,7 @@ msgstr ""
 msgid "Show"
 msgstr ""
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr ""
 
@@ -2711,7 +2725,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
@@ -2760,8 +2774,8 @@ msgstr ""
 msgid "The url is invalid"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr ""
 
@@ -2854,14 +2868,14 @@ msgid ""
 "continue?"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr ""
 
@@ -2947,11 +2961,11 @@ msgstr "Uptime:"
 msgid "URL"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr ""
 

+ 34 - 20
app/src/language/es/app.po

@@ -111,7 +111,7 @@ msgstr ""
 msgid "All"
 msgstr "Todo"
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr "URL Base de la API"
 
@@ -119,15 +119,15 @@ msgstr "URL Base de la API"
 msgid "API Document"
 msgstr "Documento de la API"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr "Proxy de la API"
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr "Token de la API"
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 #, fuzzy
 msgid "API Type"
 msgstr "Token de la API"
@@ -227,7 +227,7 @@ msgstr "Intentos"
 msgid "Auth"
 msgstr "Autenticación"
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr "Autenticarse con una llave de acceso"
 
@@ -618,6 +618,11 @@ msgstr "Base de datos (Opcional, default: database)"
 msgid "Days"
 msgstr "Días"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Descripción"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1238,7 +1243,7 @@ msgstr "Inicializando la actualización del kernel"
 msgid "Input the code from the app:"
 msgstr "Ingrese el código de la aplicación:"
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr "Ingrese el código de recuperación:"
 
@@ -1281,6 +1286,11 @@ msgstr "Código de acceso o código de recuperación inválido"
 msgid "Invalid recovery code"
 msgstr "Código 2FA o de recuperación inválido"
 
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "Código 2FA o de recuperación inválido"
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr "IP"
@@ -1329,7 +1339,7 @@ msgstr "Comprobado por última vez el"
 msgid "Leave blank for no change"
 msgstr "Para no modificar dejar en blanco"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Dejar en blanco para el valor predeterminado: https://api.openai.com/"
 
@@ -1393,7 +1403,7 @@ msgstr "Ubicaciones"
 msgid "Log"
 msgstr "Registro"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "Acceso"
 
@@ -1472,7 +1482,7 @@ msgstr "Memoria y almacenamiento"
 msgid "Minutes"
 msgstr "Minutos"
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Modelo"
 
@@ -1761,7 +1771,7 @@ msgstr "En línea"
 msgid "OpenAI"
 msgstr "OpenAI"
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr "O"
 
@@ -1870,7 +1880,7 @@ msgstr ""
 "Ingrese un nombre para la llave de acceso que desea crear y a continuación "
 "haga clic en el botón Aceptar."
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 #, fuzzy
 msgid "Please enter the OTP code:"
 msgstr "Por favor, ingrese el código 2FA:"
@@ -2024,7 +2034,7 @@ msgstr "Recuperar"
 msgid "Recovered Successfully"
 msgstr "Recuperado con éxito"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr "Recuperación"
 
@@ -2203,6 +2213,10 @@ msgstr "Renovado de Certificado exitoso"
 msgid "Renew successfully"
 msgstr "Renovado con éxito"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "Pedido con parámetros incorrectos"
@@ -2388,7 +2402,7 @@ msgstr ""
 msgid "Show"
 msgstr "Mostrar"
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr "Iniciar sesión con una llave de acceso"
 
@@ -2648,7 +2662,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 #, fuzzy
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
@@ -2706,8 +2720,8 @@ msgstr ""
 msgid "The url is invalid"
 msgstr "La URL es inválida"
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr "La URL no es válida."
 
@@ -2814,7 +2828,7 @@ msgstr ""
 "de la autoridad al backend, y debemos guardar este archivo y volver a cargar "
 "Nginx. ¿Estás seguro de que quieres continuar?"
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 #, fuzzy
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
@@ -2825,7 +2839,7 @@ msgstr ""
 "Estos proporcionan un API endpoint compatible con OpenAI, por lo que solo "
 "debe configurar la baseUrl en su API local."
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr "El token no es válido"
 
@@ -2910,11 +2924,11 @@ msgstr "Tiempo encendido:"
 msgid "URL"
 msgstr "URL"
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr "Usar OTP"
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr "Usar código de recuperación"
 

+ 33 - 20
app/src/language/fr_FR/app.po

@@ -109,7 +109,7 @@ msgstr ""
 msgid "All"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr "URL de base de l'API"
 
@@ -118,15 +118,15 @@ msgstr "URL de base de l'API"
 msgid "API Document"
 msgstr "Jeton d'API"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr "Proxy d'API"
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr "Jeton d'API"
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 #, fuzzy
 msgid "API Type"
 msgstr "Jeton d'API"
@@ -235,7 +235,7 @@ msgstr ""
 msgid "Auth"
 msgstr "Autheur"
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr ""
 
@@ -635,6 +635,11 @@ msgstr "Base de données (Facultatif, par défaut : database)"
 msgid "Days"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Description"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1278,7 +1283,7 @@ msgstr "Initialisation du programme de mise à niveau du core"
 msgid "Input the code from the app:"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr ""
 
@@ -1320,6 +1325,10 @@ msgstr ""
 msgid "Invalid recovery code"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:2
+msgid "Invalid request format"
+msgstr ""
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr ""
@@ -1371,7 +1380,7 @@ msgstr "Dernière vérification le"
 msgid "Leave blank for no change"
 msgstr "Laisser vide pour aucun changement"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Laissez vide pour la valeur par défaut : https://api.openai.com/"
 
@@ -1444,7 +1453,7 @@ msgstr "Localisations"
 msgid "Log"
 msgstr "Connexion"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "Connexion"
 
@@ -1519,7 +1528,7 @@ msgstr "Mémoire et stockage"
 msgid "Minutes"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 #, fuzzy
 msgid "Model"
 msgstr "Mode d'exécution"
@@ -1814,7 +1823,7 @@ msgstr ""
 msgid "OpenAI"
 msgstr "OpenAI"
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr ""
 
@@ -1916,7 +1925,7 @@ msgid ""
 "button below."
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr ""
 
@@ -2071,7 +2080,7 @@ msgstr ""
 msgid "Recovered Successfully"
 msgstr "Enregistré avec succès"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr ""
 
@@ -2262,6 +2271,10 @@ msgstr "Changer de certificat"
 msgid "Renew successfully"
 msgstr "Activé avec succès"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr ""
@@ -2444,7 +2457,7 @@ msgstr ""
 msgid "Show"
 msgstr ""
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr ""
 
@@ -2711,7 +2724,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
@@ -2761,8 +2774,8 @@ msgstr ""
 msgid "The url is invalid"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr ""
 
@@ -2861,14 +2874,14 @@ msgstr ""
 "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?"
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr ""
 
@@ -2952,11 +2965,11 @@ msgstr "Disponibilité :"
 msgid "URL"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr ""
 

+ 102 - 0
app/src/language/ko_KR/app.po

@@ -327,6 +327,13 @@ msgstr "CA 디렉토리"
 msgid "CADir"
 msgstr "CA 디렉토리"
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:129
+msgid "Can't scan? Use text key binding"
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:246
 #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:187
@@ -579,11 +586,19 @@ msgstr "인증 정보"
 msgid "Credentials"
 msgstr "인증 정보들"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:72
 msgid "Current account is enabled TOTP."
 msgstr ""
 
 #: src/views/preference/components/TOTP.vue:70
+=======
+#: src/views/preference/components/TOTP.vue:77
+msgid "Current account is enabled TOTP."
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:74
+>>>>>>> remotes/origin/dev
 msgid "Current account is not enabled TOTP."
 msgstr ""
 
@@ -615,6 +630,11 @@ msgstr "데이터베이스 (선택사항, 기본값: database)"
 msgid "Days"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "설명"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -919,7 +939,11 @@ msgstr "%{node_name}에서 %{conf_name} 활성화 실패"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "%{node_name}에서 %{conf_name} 성공적으로 활성화됨"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:45
+=======
+#: src/views/preference/components/TOTP.vue:38
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Enable 2FA successfully"
 msgstr "성공적으로 활성화"
@@ -960,7 +984,11 @@ msgstr "성공적으로 활성화"
 msgid "Enable TLS"
 msgstr "TLS 활성화"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:81
+=======
+#: src/views/preference/components/TOTP.vue:103
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Enable TOTP"
 msgstr "TLS 활성화"
@@ -1201,6 +1229,15 @@ msgid ""
 "ban threshold minutes, the ip will be banned for a period of time."
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:89
+msgid ""
+"If you lose your mobile phone, you can use the recovery code to reset your "
+"2FA."
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/views/preference/components/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
 msgstr ""
@@ -1233,11 +1270,19 @@ msgstr "초기 코어 업그레이더 오류"
 msgid "Initialing core upgrader"
 msgstr "코어 업그레이더 초기화"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:119
+=======
+#: src/views/preference/components/TOTP.vue:136
+>>>>>>> remotes/origin/dev
 msgid "Input the code from the app:"
 msgstr ""
 
 #: src/components/TwoFA/Authorization.vue:82
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:149
+>>>>>>> remotes/origin/dev
 msgid "Input the recovery code:"
 msgstr ""
 
@@ -1284,7 +1329,15 @@ msgstr ""
 msgid "Invalid recovery code"
 msgstr "유효함"
 
+<<<<<<< HEAD
 #: src/views/preference/AuthSettings.vue:18
+=======
+#: src/constants/errors/middleware.ts:2
+msgid "Invalid request format"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:14
+>>>>>>> remotes/origin/dev
 msgid "IP"
 msgstr ""
 
@@ -2037,6 +2090,7 @@ msgid "Recovered Successfully"
 msgstr "성공적으로 제거됨"
 
 #: src/components/TwoFA/Authorization.vue:89
+<<<<<<< HEAD
 msgid "Recovery"
 msgstr ""
 
@@ -2049,6 +2103,18 @@ msgstr "유효함"
 msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
+=======
+#: src/views/preference/components/TOTP.vue:156
+msgid "Recovery"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:82
+msgid "Recovery Code"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:91
+msgid "Recovery Code:"
+>>>>>>> remotes/origin/dev
 msgstr ""
 
 #: src/views/preference/CertSettings.vue:37
@@ -2229,6 +2295,10 @@ msgstr "인증서 갱신 성공"
 msgid "Renew successfully"
 msgstr "성공적으로 갱신됨"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "잘못된 매개변수로 요청됨"
@@ -2237,7 +2307,11 @@ msgstr "잘못된 매개변수로 요청됨"
 msgid "Reset"
 msgstr "재설정"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:93
+=======
+#: src/views/preference/components/TOTP.vue:111
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Reset 2FA"
 msgstr "재설정"
@@ -2331,7 +2405,11 @@ msgstr "성공적으로 저장됨"
 msgid "Saved successfully"
 msgstr "성공적으로 저장됨"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:69
+=======
+#: src/views/preference/components/TOTP.vue:72
+>>>>>>> remotes/origin/dev
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr ""
 
@@ -2339,7 +2417,11 @@ msgstr ""
 msgid "SDK"
 msgstr ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:109
+=======
+#: src/views/preference/components/TOTP.vue:128
+>>>>>>> remotes/origin/dev
 msgid "Secret has been copied"
 msgstr ""
 
@@ -2705,6 +2787,14 @@ msgid ""
 "hyphens, dashes, colons, and dots."
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:90
+msgid ""
+"The recovery code is only displayed once, please save it in a safe place."
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/views/dashboard/Environments.vue:148
 msgid ""
 "The remote Nginx UI version is not compatible with the local Nginx UI "
@@ -2802,7 +2892,11 @@ msgstr "팁"
 msgid "Title"
 msgstr "제목"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:68
+=======
+#: src/views/preference/components/TOTP.vue:71
+>>>>>>> remotes/origin/dev
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
@@ -2843,11 +2937,19 @@ msgid_plural "Total %{total} items"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:66
 msgid "TOTP"
 msgstr ""
 
 #: src/views/preference/components/TOTP.vue:67
+=======
+#: src/views/preference/components/TOTP.vue:69
+msgid "TOTP"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:70
+>>>>>>> remotes/origin/dev
 msgid ""
 "TOTP is a two-factor authentication method that uses a time-based one-time "
 "password algorithm."

+ 33 - 21
app/src/language/messages.pot

@@ -100,7 +100,7 @@ msgstr ""
 msgid "All"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr ""
 
@@ -108,15 +108,15 @@ msgstr ""
 msgid "API Document"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 msgid "API Type"
 msgstr ""
 
@@ -210,7 +210,7 @@ msgstr ""
 msgid "Auth"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr ""
 
@@ -592,6 +592,10 @@ msgstr ""
 msgid "Days"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:3
+msgid "Decryption failed"
+msgstr ""
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1191,7 +1195,7 @@ msgstr ""
 msgid "Input the code from the app:"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr ""
 
@@ -1233,6 +1237,10 @@ msgstr ""
 msgid "Invalid recovery code"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:2
+msgid "Invalid request format"
+msgstr ""
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr ""
@@ -1278,7 +1286,7 @@ msgstr ""
 msgid "Leave blank for no change"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 
@@ -1342,7 +1350,7 @@ msgid "Log"
 msgstr ""
 
 #: src/routes/index.ts:318
-#: src/views/other/Login.vue:222
+#: src/views/other/Login.vue:223
 msgid "Login"
 msgstr ""
 
@@ -1410,7 +1418,7 @@ msgstr ""
 msgid "Minutes"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 msgid "Model"
 msgstr ""
 
@@ -1691,8 +1699,8 @@ msgstr ""
 msgid "OpenAI"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:112
-#: src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100
+#: src/views/other/Login.vue:232
 msgid "Or"
 msgstr ""
 
@@ -1790,7 +1798,7 @@ msgstr ""
 msgid "Please enter a name for the passkey you wish to create and click the OK button below."
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr ""
 
@@ -1922,7 +1930,7 @@ msgstr ""
 msgid "Recovered Successfully"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr ""
 
@@ -2083,6 +2091,10 @@ msgstr ""
 msgid "Renew successfully"
 msgstr ""
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr ""
@@ -2253,7 +2265,7 @@ msgstr ""
 msgid "Show"
 msgstr ""
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr ""
 
@@ -2482,7 +2494,7 @@ msgstr ""
 msgid "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 msgid "The model name should only contain letters, unicode, numbers, hyphens, dashes, colons, and dots."
 msgstr ""
 
@@ -2515,8 +2527,8 @@ msgstr ""
 msgid "The url is invalid"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr ""
 
@@ -2593,11 +2605,11 @@ 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?"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 msgid "To use a local large model, deploy it with ollama, vllm or lmdeploy. They provide an OpenAI-compatible API endpoint, so just set the baseUrl to your local API."
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr ""
 
@@ -2682,11 +2694,11 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr ""
 

+ 108 - 0
app/src/language/ru_RU/app.po

@@ -330,6 +330,13 @@ msgstr "Директория корневого сертификата"
 msgid "CADir"
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:129
+msgid "Can't scan? Use text key binding"
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:246
 #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:187
@@ -579,12 +586,20 @@ msgstr "Учетные данные"
 msgid "Credentials"
 msgstr "Учетные данные"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:72
+=======
+#: src/views/preference/components/TOTP.vue:77
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Current account is enabled TOTP."
 msgstr "Текущая учетная запись имеет включенную 2ФА."
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:70
+=======
+#: src/views/preference/components/TOTP.vue:74
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Current account is not enabled TOTP."
 msgstr ""
@@ -619,6 +634,11 @@ msgstr "База данных (Опционально, по умолчанию:
 msgid "Days"
 msgstr "Дни"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Описание"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -927,7 +947,11 @@ msgstr "Включение %{conf_name} in %{node_name} нипалучилася
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "Включение %{conf_name} in %{node_name} успешно"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:45
+=======
+#: src/views/preference/components/TOTP.vue:38
+>>>>>>> remotes/origin/dev
 msgid "Enable 2FA successfully"
 msgstr "Двухфакторная аутентификация успешно включена"
 
@@ -967,7 +991,11 @@ msgstr "Включено успешно"
 msgid "Enable TLS"
 msgstr "Включить TLS"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:81
+=======
+#: src/views/preference/components/TOTP.vue:103
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Enable TOTP"
 msgstr "Включить TLS"
@@ -1207,6 +1235,17 @@ msgstr ""
 "количества попыток в течение пороговых минут блокировки, IP будет "
 "заблокирован на определенный период времени."
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:89
+msgid ""
+"If you lose your mobile phone, you can use the recovery code to reset your "
+"2FA."
+msgstr ""
+"Если вы потеряете свой мобильный телефон, вы можете использовать код "
+"восстановления для сброса 2FA."
+
+>>>>>>> remotes/origin/dev
 #: src/views/preference/components/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
 msgstr ""
@@ -1241,11 +1280,19 @@ msgstr "Ошибка первоначального обновления ядр
 msgid "Initialing core upgrader"
 msgstr "Инициализация программы обновления ядра"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:119
+=======
+#: src/views/preference/components/TOTP.vue:136
+>>>>>>> remotes/origin/dev
 msgid "Input the code from the app:"
 msgstr "Введите код из приложения:"
 
 #: src/components/TwoFA/Authorization.vue:82
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:149
+>>>>>>> remotes/origin/dev
 msgid "Input the recovery code:"
 msgstr "Введите код восстановления:"
 
@@ -1288,7 +1335,16 @@ msgstr "Неверный пароль или код восстановления
 msgid "Invalid recovery code"
 msgstr "Неверный 2FA или код восстановления"
 
+<<<<<<< HEAD
 #: src/views/preference/AuthSettings.vue:18
+=======
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "Неверный 2FA или код восстановления"
+
+#: src/views/preference/AuthSettings.vue:14
+>>>>>>> remotes/origin/dev
 msgid "IP"
 msgstr "IP"
 
@@ -2023,6 +2079,7 @@ msgid "Recovered Successfully"
 msgstr "Восстановлено успешно"
 
 #: src/components/TwoFA/Authorization.vue:89
+<<<<<<< HEAD
 msgid "Recovery"
 msgstr "Восстановление"
 
@@ -2036,6 +2093,19 @@ msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
 msgstr ""
+=======
+#: src/views/preference/components/TOTP.vue:156
+msgid "Recovery"
+msgstr "Восстановление"
+
+#: src/views/preference/components/TOTP.vue:82
+msgid "Recovery Code"
+msgstr "Код восстановления"
+
+#: src/views/preference/components/TOTP.vue:91
+msgid "Recovery Code:"
+msgstr "Код восстановления:"
+>>>>>>> remotes/origin/dev
 
 #: src/views/preference/CertSettings.vue:37
 msgid "Recursive Nameservers"
@@ -2200,6 +2270,10 @@ msgstr "Успешное обновление сертификата"
 msgid "Renew successfully"
 msgstr "Успешно обновлено"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "Запрос с неправильными параметрами"
@@ -2208,7 +2282,11 @@ msgstr "Запрос с неправильными параметрами"
 msgid "Reset"
 msgstr "Сброс"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:93
+=======
+#: src/views/preference/components/TOTP.vue:111
+>>>>>>> remotes/origin/dev
 msgid "Reset 2FA"
 msgstr "Сброс 2FA"
 
@@ -2301,7 +2379,11 @@ msgstr "Сохранено успешно"
 msgid "Saved successfully"
 msgstr "Успешно сохранено"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:69
+=======
+#: src/views/preference/components/TOTP.vue:72
+>>>>>>> remotes/origin/dev
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr ""
 "Отсканируйте QR-код с помощью мобильного телефона, чтобы добавить учетную "
@@ -2311,7 +2393,11 @@ msgstr ""
 msgid "SDK"
 msgstr "SDK"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:109
+=======
+#: src/views/preference/components/TOTP.vue:128
+>>>>>>> remotes/origin/dev
 msgid "Secret has been copied"
 msgstr ""
 
@@ -2681,6 +2767,16 @@ msgstr ""
 "Имя сервера должно содержать только буквы, юникод, цифры, дефисы, тире и "
 "точки."
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:90
+msgid ""
+"The recovery code is only displayed once, please save it in a safe place."
+msgstr ""
+"Код восстановления отображается только один раз, пожалуйста, сохраните его в "
+"безопасном месте."
+
+>>>>>>> remotes/origin/dev
 #: src/views/dashboard/Environments.vue:148
 msgid ""
 "The remote Nginx UI version is not compatible with the local Nginx UI "
@@ -2782,7 +2878,11 @@ msgstr "Советы"
 msgid "Title"
 msgstr "Заголовок"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:68
+=======
+#: src/views/preference/components/TOTP.vue:71
+>>>>>>> remotes/origin/dev
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
@@ -2826,11 +2926,19 @@ msgid_plural "Total %{total} items"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:66
 msgid "TOTP"
 msgstr ""
 
 #: src/views/preference/components/TOTP.vue:67
+=======
+#: src/views/preference/components/TOTP.vue:69
+msgid "TOTP"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:70
+>>>>>>> remotes/origin/dev
 msgid ""
 "TOTP is a two-factor authentication method that uses a time-based one-time "
 "password algorithm."

+ 110 - 0
app/src/language/tr_TR/app.po

@@ -325,6 +325,13 @@ msgstr "CA Dizini"
 msgid "CADir"
 msgstr "CADizini"
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:129
+msgid "Can't scan? Use text key binding"
+msgstr "Tarayamıyor musunuz? Metin anahtar bağlamasını kullanın"
+
+>>>>>>> remotes/origin/dev
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:246
 #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:187
@@ -573,11 +580,19 @@ msgstr "Kimlik bilgisi"
 msgid "Credentials"
 msgstr "Kimlik bilgileri"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:72
 msgid "Current account is enabled TOTP."
 msgstr "Mevcut hesap için TOTP etkinleştirildi."
 
 #: src/views/preference/components/TOTP.vue:70
+=======
+#: src/views/preference/components/TOTP.vue:77
+msgid "Current account is enabled TOTP."
+msgstr "Mevcut hesap için TOTP etkinleştirildi."
+
+#: src/views/preference/components/TOTP.vue:74
+>>>>>>> remotes/origin/dev
 msgid "Current account is not enabled TOTP."
 msgstr "Mevcut hesap için TOTP etkin değil."
 
@@ -610,6 +625,11 @@ msgstr "Veritabanı (İsteğe bağlı, varsayılan: database)"
 msgid "Days"
 msgstr "Günler"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Açıklama"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -925,7 +945,11 @@ msgstr ""
 "%{conf_name} yapılandırmasını %{node_name} düğümünde etkinleştirme başarılı "
 "oldu"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:45
+=======
+#: src/views/preference/components/TOTP.vue:38
+>>>>>>> remotes/origin/dev
 msgid "Enable 2FA successfully"
 msgstr "2FA'yı başarıyla etkinleştirildi"
 
@@ -969,7 +993,11 @@ msgstr "Başarıyla etkinleştirildi"
 msgid "Enable TLS"
 msgstr "TLS'yi Etkinleştir"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:81
+=======
+#: src/views/preference/components/TOTP.vue:103
+>>>>>>> remotes/origin/dev
 msgid "Enable TOTP"
 msgstr "TOTP'yi Etkinleştir"
 
@@ -1208,6 +1236,17 @@ msgstr ""
 "yasaklama eşiği dakikaları içinde maksimum deneme sayısına ulaşırsa, IP "
 "adresi belirli bir süre için yasaklanacaktır."
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:89
+msgid ""
+"If you lose your mobile phone, you can use the recovery code to reset your "
+"2FA."
+msgstr ""
+"Cep telefonunuzu kaybederseniz, 2FA'nızı sıfırlamak için kurtarma kodunu "
+"kullanabilirsiniz."
+
+>>>>>>> remotes/origin/dev
 #: src/views/preference/components/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
 msgstr ""
@@ -1243,11 +1282,19 @@ msgstr "İlk çekirdek yükseltici hatası"
 msgid "Initialing core upgrader"
 msgstr "Çekirdek yükseltici başlatılıyor"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:119
+=======
+#: src/views/preference/components/TOTP.vue:136
+>>>>>>> remotes/origin/dev
 msgid "Input the code from the app:"
 msgstr "Uygulamadan kodu girin:"
 
 #: src/components/TwoFA/Authorization.vue:82
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:149
+>>>>>>> remotes/origin/dev
 msgid "Input the recovery code:"
 msgstr "Kurtarma kodunu girin:"
 
@@ -1290,7 +1337,16 @@ msgstr "Geçersiz parola veya kurtarma kodu"
 msgid "Invalid recovery code"
 msgstr "Geçersiz 2FA veya kurtarma kodu"
 
+<<<<<<< HEAD
 #: src/views/preference/AuthSettings.vue:18
+=======
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "Geçersiz 2FA veya kurtarma kodu"
+
+#: src/views/preference/AuthSettings.vue:14
+>>>>>>> remotes/origin/dev
 msgid "IP"
 msgstr "IP"
 
@@ -2119,20 +2175,35 @@ msgid "Recovered Successfully"
 msgstr "Başarıyla Kurtarıldı"
 
 #: src/components/TwoFA/Authorization.vue:89
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:156
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Recovery"
 msgstr "Kurtarma"
 
+<<<<<<< HEAD
 #: src/views/preference/components/RecoveryCodes.vue:68
+=======
+#: src/views/preference/components/TOTP.vue:82
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Recovery Codes"
 msgstr "Kurtarma Kodu"
 
+<<<<<<< HEAD
 #: src/views/preference/components/RecoveryCodes.vue:73
 msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
 msgstr ""
+=======
+#: src/views/preference/components/TOTP.vue:91
+#, fuzzy
+msgid "Recovery Code:"
+msgstr "Kurtarma Kodu:"
+>>>>>>> remotes/origin/dev
 
 #: src/views/preference/CertSettings.vue:37
 #, fuzzy
@@ -2328,6 +2399,10 @@ msgstr "Sertifika Yenileme Başarısı"
 msgid "Renew successfully"
 msgstr "Başarıyla yenileyin"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 #, fuzzy
 msgid "Requested with wrong parameters"
@@ -2338,7 +2413,11 @@ msgstr "Yanlış parametrelerle talep edildi"
 msgid "Reset"
 msgstr "Sıfırla"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:93
+=======
+#: src/views/preference/components/TOTP.vue:111
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Reset 2FA"
 msgstr "2FA'yı Sıfırla"
@@ -2441,7 +2520,11 @@ msgstr "Başarıyla kaydedin"
 msgid "Saved successfully"
 msgstr "Başarıyla Kaydedildi"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:69
+=======
+#: src/views/preference/components/TOTP.vue:72
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr "Hesabı uygulamaya eklemek için QR kodunu cep telefonunuzla tarayın."
@@ -2451,7 +2534,11 @@ msgstr "Hesabı uygulamaya eklemek için QR kodunu cep telefonunuzla tarayın."
 msgid "SDK"
 msgstr "SDK"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:109
+=======
+#: src/views/preference/components/TOTP.vue:128
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Secret has been copied"
 msgstr "Sır kopyalandı"
@@ -2867,6 +2954,17 @@ msgstr ""
 "Sunucu adı yalnızca harf, unicode, sayı, kısa çizgi, tire ve nokta "
 "içermelidir."
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:90
+#, fuzzy
+msgid ""
+"The recovery code is only displayed once, please save it in a safe place."
+msgstr ""
+"Kurtarma kodu yalnızca bir kez görüntülenir, lütfen güvenli bir yere "
+"kaydedin."
+
+>>>>>>> remotes/origin/dev
 #: src/views/dashboard/Environments.vue:148
 #, fuzzy
 msgid ""
@@ -2979,7 +3077,11 @@ msgstr "İpuçları"
 msgid "Title"
 msgstr "Başlık"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:68
+=======
+#: src/views/preference/components/TOTP.vue:71
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
@@ -3034,12 +3136,20 @@ msgid_plural "Total %{total} items"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:66
+=======
+#: src/views/preference/components/TOTP.vue:69
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "TOTP"
 msgstr "TOTP"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:67
+=======
+#: src/views/preference/components/TOTP.vue:70
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid ""
 "TOTP is a two-factor authentication method that uses a time-based one-time "

+ 102 - 0
app/src/language/vi_VN/app.po

@@ -342,6 +342,13 @@ msgstr ""
 msgid "CADir"
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:129
+msgid "Can't scan? Use text key binding"
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:246
 #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:187
@@ -603,11 +610,19 @@ msgstr "Chứng chỉ"
 msgid "Credentials"
 msgstr "Chứng chỉ"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:72
 msgid "Current account is enabled TOTP."
 msgstr ""
 
 #: src/views/preference/components/TOTP.vue:70
+=======
+#: src/views/preference/components/TOTP.vue:77
+msgid "Current account is enabled TOTP."
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:74
+>>>>>>> remotes/origin/dev
 msgid "Current account is not enabled TOTP."
 msgstr ""
 
@@ -639,6 +654,11 @@ msgstr "Tên cơ sở dữ liệu (Tuỳ chọn, Mặc định là: database)"
 msgid "Days"
 msgstr ""
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "Mô tả"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -961,7 +981,11 @@ msgstr "Không thể bật %{conf_name} trên %{node_name}"
 msgid "Enable %{conf_name} in %{node_name} successfully"
 msgstr "Đã bật %{conf_name} trên %{node_name}"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:45
+=======
+#: src/views/preference/components/TOTP.vue:38
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Enable 2FA successfully"
 msgstr "Đã bật"
@@ -1003,7 +1027,11 @@ msgstr "Đã bật"
 msgid "Enable TLS"
 msgstr "Bật TLS"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:81
+=======
+#: src/views/preference/components/TOTP.vue:103
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Enable TOTP"
 msgstr "Bật TLS"
@@ -1247,6 +1275,15 @@ msgid ""
 "ban threshold minutes, the ip will be banned for a period of time."
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:89
+msgid ""
+"If you lose your mobile phone, you can use the recovery code to reset your "
+"2FA."
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/views/preference/components/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
 msgstr ""
@@ -1280,11 +1317,19 @@ msgstr "Không thể khởi tạo trình nâng cấp"
 msgid "Initialing core upgrader"
 msgstr "Đang khởi tạo trình nâng cấp"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:119
+=======
+#: src/views/preference/components/TOTP.vue:136
+>>>>>>> remotes/origin/dev
 msgid "Input the code from the app:"
 msgstr ""
 
 #: src/components/TwoFA/Authorization.vue:82
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:149
+>>>>>>> remotes/origin/dev
 msgid "Input the recovery code:"
 msgstr ""
 
@@ -1331,7 +1376,15 @@ msgstr ""
 msgid "Invalid recovery code"
 msgstr "Hợp lệ"
 
+<<<<<<< HEAD
 #: src/views/preference/AuthSettings.vue:18
+=======
+#: src/constants/errors/middleware.ts:2
+msgid "Invalid request format"
+msgstr ""
+
+#: src/views/preference/AuthSettings.vue:14
+>>>>>>> remotes/origin/dev
 msgid "IP"
 msgstr ""
 
@@ -2080,6 +2133,7 @@ msgid "Recovered Successfully"
 msgstr "Xoá thành công"
 
 #: src/components/TwoFA/Authorization.vue:89
+<<<<<<< HEAD
 msgid "Recovery"
 msgstr ""
 
@@ -2092,6 +2146,18 @@ msgstr "Hợp lệ"
 msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
+=======
+#: src/views/preference/components/TOTP.vue:156
+msgid "Recovery"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:82
+msgid "Recovery Code"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:91
+msgid "Recovery Code:"
+>>>>>>> remotes/origin/dev
 msgstr ""
 
 #: src/views/preference/CertSettings.vue:37
@@ -2272,6 +2338,10 @@ msgstr "Gia hạn chứng chỉ SSL thành công"
 msgid "Renew successfully"
 msgstr "Gia hạn chứng chỉ SSL"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "Yêu cầu có chứa tham số sai"
@@ -2280,7 +2350,11 @@ msgstr "Yêu cầu có chứa tham số sai"
 msgid "Reset"
 msgstr "Đặt lại"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:93
+=======
+#: src/views/preference/components/TOTP.vue:111
+>>>>>>> remotes/origin/dev
 #, fuzzy
 msgid "Reset 2FA"
 msgstr "Đặt lại"
@@ -2374,7 +2448,11 @@ msgstr "Lưu thành công"
 msgid "Saved successfully"
 msgstr "Lưu thành công"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:69
+=======
+#: src/views/preference/components/TOTP.vue:72
+>>>>>>> remotes/origin/dev
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr ""
 
@@ -2382,7 +2460,11 @@ msgstr ""
 msgid "SDK"
 msgstr ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:109
+=======
+#: src/views/preference/components/TOTP.vue:128
+>>>>>>> remotes/origin/dev
 msgid "Secret has been copied"
 msgstr ""
 
@@ -2748,6 +2830,14 @@ msgid ""
 "hyphens, dashes, colons, and dots."
 msgstr ""
 
+<<<<<<< HEAD
+=======
+#: src/views/preference/components/TOTP.vue:90
+msgid ""
+"The recovery code is only displayed once, please save it in a safe place."
+msgstr ""
+
+>>>>>>> remotes/origin/dev
 #: src/views/dashboard/Environments.vue:148
 msgid ""
 "The remote Nginx UI version is not compatible with the local Nginx UI "
@@ -2842,7 +2932,11 @@ msgstr ""
 msgid "Title"
 msgstr "Tiêu đề"
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:68
+=======
+#: src/views/preference/components/TOTP.vue:71
+>>>>>>> remotes/origin/dev
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
@@ -2884,11 +2978,19 @@ msgid_plural "Total %{total} items"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< HEAD
 #: src/views/preference/components/TOTP.vue:66
 msgid "TOTP"
 msgstr ""
 
 #: src/views/preference/components/TOTP.vue:67
+=======
+#: src/views/preference/components/TOTP.vue:69
+msgid "TOTP"
+msgstr ""
+
+#: src/views/preference/components/TOTP.vue:70
+>>>>>>> remotes/origin/dev
 msgid ""
 "TOTP is a two-factor authentication method that uses a time-based one-time "
 "password algorithm."

+ 34 - 20
app/src/language/zh_CN/app.po

@@ -106,7 +106,7 @@ msgstr "然后,刷新此页面并再次点击添加 Passkey。"
 msgid "All"
 msgstr "全部"
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr "API 地址"
 
@@ -114,15 +114,15 @@ msgstr "API 地址"
 msgid "API Document"
 msgstr "API 文档"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr "API 代理"
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr "API Token"
 
-#: src/views/preference/OpenAISettings.vue:78
+#: src/views/preference/OpenAISettings.vue:67
 msgid "API Type"
 msgstr "API 类型"
 
@@ -216,7 +216,7 @@ msgstr "尝试次数"
 msgid "Auth"
 msgstr "认证"
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr "通过 Passkey 认证"
 
@@ -596,6 +596,11 @@ msgstr "数据库 (可选,默认: database)"
 msgid "Days"
 msgstr "天"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "描述"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -1191,7 +1196,7 @@ msgstr "初始化核心升级器"
 msgid "Input the code from the app:"
 msgstr "输入应用程序中的代码:"
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr "输入恢复代码:"
 
@@ -1232,6 +1237,11 @@ msgstr "二次验证码或恢复代码无效"
 msgid "Invalid recovery code"
 msgstr "无效的恢复代码"
 
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "无效的恢复代码"
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr "IP"
@@ -1280,7 +1290,7 @@ msgstr "上次使用"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "留空为默认:https://api.openai.com/"
 
@@ -1343,7 +1353,7 @@ msgstr "Locations"
 msgid "Log"
 msgstr "日志"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "登录"
 
@@ -1419,7 +1429,7 @@ msgstr "内存与存储"
 msgid "Minutes"
 msgstr "分钟"
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 msgid "Model"
 msgstr "模型"
 
@@ -1699,7 +1709,7 @@ msgstr "在线"
 msgid "OpenAI"
 msgstr "OpenAI"
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr "或"
 
@@ -1802,7 +1812,7 @@ msgid ""
 "button below."
 msgstr "请为您要创建的 Passkey 输入一个名称,然后单击下面的 \"确定 \"按钮。"
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "请输入 OTP:"
 
@@ -1941,7 +1951,7 @@ msgstr "恢复"
 msgid "Recovered Successfully"
 msgstr "恢复成功"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr "恢复"
 
@@ -2110,6 +2120,10 @@ msgstr "证书续期成功"
 msgid "Renew successfully"
 msgstr "更新成功"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr "请求超时"
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "请求参数错误"
@@ -2288,7 +2302,7 @@ msgstr ""
 msgid "Show"
 msgstr "显示"
 
-#: src/views/other/Login.vue:240
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
 msgstr "使用 Passkey 登录"
 
@@ -2530,7 +2544,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr "日志路径不在 settings.NginxSettings.LogDirWhiteList 中的路径之下"
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
@@ -2576,8 +2590,8 @@ msgstr "当前配置中的 server_name 必须是获取证书所需的域名,
 msgid "The url is invalid"
 msgstr "URL无效"
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr "URL 无效."
 
@@ -2675,7 +2689,7 @@ msgstr ""
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
@@ -2684,7 +2698,7 @@ msgstr ""
 "要使用本地大型模型,可使用 ollama、vllm 或 lmdeploy 进行部署。它们提供了与 "
 "OpenAI 兼容的 API 端点,因此只需将 baseUrl 设置为本地 API 即可。"
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr "Token 无效"
 
@@ -2765,11 +2779,11 @@ msgstr "运行时间:"
 msgid "URL"
 msgstr "URL"
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr "使用二步验证码"
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr "使用恢复代码"
 

+ 61 - 57
app/src/language/zh_TW/app.po

@@ -2,25 +2,26 @@
 # Hintay Lin <hintay@me.com>, 2024.
 # Weblate <noreply-mt-weblate@weblate.org>, 2024.
 # "Xaver Y.R. Chen" <yrchen@atcity.org>, 2025.
+# 0xJacky <me@jackyu.cn>, 2025.
 msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "POT-Creation-Date: \n"
-"PO-Revision-Date: 2025-02-01 18:25+0000\n"
-"Last-Translator: \"Xaver Y.R. Chen\" <yrchen@atcity.org>\n"
-"Language-Team: Chinese (Traditional) <https://weblate.nginxui.com/projects/"
-"nginx-ui/frontend/zh_Hant/>\n"
+"PO-Revision-Date: 2025-02-08 18:25+0000\n"
+"Last-Translator: 0xJacky <me@jackyu.cn>\n"
+"Language-Team: Chinese (Traditional Han script) <https://weblate.nginxui.com/"
+"projects/nginx-ui/frontend/zh_Hant/>\n"
 "Language: zh_TW\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.6.2\n"
+"X-Generator: Weblate 5.9.2\n"
 "Generated-By: easygettext\n"
 
 #: src/views/user/userColumns.tsx:32
 msgid "2FA"
-msgstr "多重要素驗證"
+msgstr "雙因素驗證"
 
 #: src/views/preference/AuthSettings.vue:70
 msgid "2FA Settings"
@@ -32,7 +33,7 @@ msgstr "關於"
 
 #: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75
 msgid "Access Logs"
-msgstr "存取日誌"
+msgstr "訪問日誌"
 
 #: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113
 #: src/views/certificate/ACMEUserSelector.vue:85
@@ -111,7 +112,7 @@ msgstr "然後,重新整理此頁面並再次點選新增通行密鑰。"
 msgid "All"
 msgstr "全部"
 
-#: src/views/preference/OpenAISettings.vue:44
+#: src/views/preference/OpenAISettings.vue:32
 msgid "API Base Url"
 msgstr "API 基礎網址"
 
@@ -119,27 +120,25 @@ msgstr "API 基礎網址"
 msgid "API Document"
 msgstr "API 文件"
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:46
 msgid "API Proxy"
 msgstr "API 代理"
 
-#: src/views/preference/OpenAISettings.vue:69
+#: src/views/preference/OpenAISettings.vue:58
 msgid "API Token"
 msgstr "API Token"
 
-#: src/views/preference/OpenAISettings.vue:78
-#, fuzzy
+#: src/views/preference/OpenAISettings.vue:67
 msgid "API Type"
-msgstr "API Token"
+msgstr "API 類型"
 
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:103
 msgid "Apply"
 msgstr "套用"
 
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:67
-#, fuzzy
 msgid "Apply bulk action successfully"
-msgstr "複製成功"
+msgstr "批量操作成功應用"
 
 #: src/views/system/Upgrade.vue:176
 msgid "Arch"
@@ -227,7 +226,7 @@ msgstr "嘗試次數"
 msgid "Auth"
 msgstr "身份驗證"
 
-#: src/components/TwoFA/Authorization.vue:121
+#: src/components/TwoFA/Authorization.vue:109
 msgid "Authenticate with a passkey"
 msgstr "使用通行密鑰認證"
 
@@ -522,7 +521,6 @@ msgid "Copy"
 msgstr "複製"
 
 #: src/views/preference/components/RecoveryCodes.vue:121
-#, fuzzy
 msgid "Copy Codes"
 msgstr "恢復碼"
 
@@ -615,6 +613,11 @@ msgstr "資料庫 (可選,預設: database)"
 msgid "Days"
 msgstr "天"
 
+#: src/constants/errors/middleware.ts:3
+#, fuzzy
+msgid "Decryption failed"
+msgstr "描述"
+
 #: src/components/StdDesign/StdDataDisplay/StdBulkActions.vue:21
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519
 #: src/views/site/ngx_conf/NgxServer.vue:110
@@ -691,9 +694,8 @@ msgid "Directive"
 msgstr "指令"
 
 #: src/constants/errors/nginx_log.ts:6
-#, fuzzy
 msgid "Directive params is empty"
-msgstr "檔名空白"
+msgstr ""
 
 #: src/constants/errors/nginx_log.ts:5
 msgid "Directive.Params neither access_log nor error_log"
@@ -1049,9 +1051,8 @@ msgid "Failed to get certificate information"
 msgstr "取得憑證資訊失敗"
 
 #: src/constants/errors/self_check.ts:4
-#, fuzzy
 msgid "Failed to parse nginx.conf"
-msgstr "讀取 nginx.conf 失敗"
+msgstr ""
 
 #: src/constants/errors/self_check.ts:3
 msgid "Failed to read nginx.conf"
@@ -1228,7 +1229,7 @@ msgstr "正在初始化核心升級程式"
 msgid "Input the code from the app:"
 msgstr "請輸入應用程式中的代碼:"
 
-#: src/components/TwoFA/Authorization.vue:82
+#: src/components/TwoFA/Authorization.vue:72
 msgid "Input the recovery code:"
 msgstr "輸入恢復碼:"
 
@@ -1271,6 +1272,11 @@ msgstr "無效的密碼或恢復碼"
 msgid "Invalid recovery code"
 msgstr "無效的多重因素驗證或恢復碼"
 
+#: src/constants/errors/middleware.ts:2
+#, fuzzy
+msgid "Invalid request format"
+msgstr "無效的多重因素驗證或恢復碼"
+
 #: src/views/preference/AuthSettings.vue:18
 msgid "IP"
 msgstr "IP"
@@ -1319,7 +1325,7 @@ msgstr "上次檢查時間"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 
-#: src/views/preference/OpenAISettings.vue:53
+#: src/views/preference/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "預設留空:https://api.openai.com/"
 
@@ -1384,7 +1390,7 @@ msgstr "Locations"
 msgid "Log"
 msgstr "日誌"
 
-#: src/routes/index.ts:318 src/views/other/Login.vue:222
+#: src/routes/index.ts:318 src/views/other/Login.vue:223
 msgid "Login"
 msgstr "登入"
 
@@ -1459,7 +1465,7 @@ msgstr "記憶體與儲存"
 msgid "Minutes"
 msgstr "分鐘"
 
-#: src/views/preference/OpenAISettings.vue:32
+#: src/views/preference/OpenAISettings.vue:20
 msgid "Model"
 msgstr "模型"
 
@@ -1598,9 +1604,8 @@ msgid "Nginx Log"
 msgstr "Nginx 日誌"
 
 #: src/views/preference/NginxSettings.vue:18
-#, fuzzy
 msgid "Nginx Log Directory Whitelist"
-msgstr "Nginx 設定解析錯誤"
+msgstr ""
 
 #: src/views/preference/NginxSettings.vue:27
 #, fuzzy
@@ -1608,9 +1613,8 @@ msgid "Nginx PID Path"
 msgstr "Nginx 錯誤日誌路徑"
 
 #: src/views/preference/NginxSettings.vue:30
-#, fuzzy
 msgid "Nginx Reload Command"
-msgstr "終端機啟動指令"
+msgstr ""
 
 #: src/components/NginxControl/NginxControl.vue:26
 msgid "Nginx reloaded successfully"
@@ -1745,7 +1749,7 @@ msgstr "線上"
 msgid "OpenAI"
 msgstr "OpenAI"
 
-#: src/components/TwoFA/Authorization.vue:112 src/views/other/Login.vue:231
+#: src/components/TwoFA/Authorization.vue:100 src/views/other/Login.vue:232
 msgid "Or"
 msgstr "或"
 
@@ -1819,9 +1823,8 @@ msgid "Path"
 msgstr "路徑"
 
 #: src/constants/errors/cert.ts:7 src/constants/errors/config.ts:2
-#, fuzzy
 msgid "Path: {0} is not under the nginx conf dir: {1}"
-msgstr "簽章路徑不在 Nginx 設定檔資料夾下"
+msgstr ""
 
 #: src/constants/errors/cert.ts:6
 msgid "Payload resource is nil"
@@ -1840,9 +1843,8 @@ msgid "Performing core upgrade"
 msgstr "正在執行核心升級"
 
 #: src/constants/errors/crypto.ts:2
-#, fuzzy
 msgid "Plain text is empty"
-msgstr "檔名空白"
+msgstr ""
 
 #: src/views/preference/components/AddPasskey.vue:69
 msgid ""
@@ -1850,7 +1852,7 @@ msgid ""
 "button below."
 msgstr ""
 
-#: src/components/TwoFA/Authorization.vue:70
+#: src/components/TwoFA/Authorization.vue:85
 #, fuzzy
 msgid "Please enter the OTP code:"
 msgstr "請輸入多重因素驗證碼:"
@@ -1995,7 +1997,7 @@ msgstr "恢復"
 msgid "Recovered Successfully"
 msgstr "恢復成功"
 
-#: src/components/TwoFA/Authorization.vue:89
+#: src/components/TwoFA/Authorization.vue:79
 msgid "Recovery"
 msgstr "恢復"
 
@@ -2172,6 +2174,10 @@ msgstr "更新憑證成功"
 msgid "Renew successfully"
 msgstr "更新成功"
 
+#: src/constants/errors/crypto.ts:4
+msgid "Request timeout"
+msgstr ""
+
 #: src/language/constants.ts:32
 msgid "Requested with wrong parameters"
 msgstr "請求參數錯誤"
@@ -2351,19 +2357,17 @@ msgstr ""
 msgid "Show"
 msgstr "顯示"
 
-#: src/views/other/Login.vue:240
-#, fuzzy
+#: src/views/other/Login.vue:241
 msgid "Sign in with a passkey"
-msgstr "使用通行密鑰認證"
+msgstr ""
 
 #: src/views/site/ngx_conf/directive/DirectiveAdd.vue:65
 msgid "Single Directive"
 msgstr "單一指令"
 
 #: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10
-#, fuzzy
 msgid "Site Categories"
-msgstr "類別"
+msgstr ""
 
 #: src/constants/errors/site.ts:4
 #, fuzzy
@@ -2389,14 +2393,12 @@ msgid "Sites List"
 msgstr "網站列表"
 
 #: src/constants/errors/self_check.ts:10
-#, fuzzy
 msgid "Sites-available directory not exist"
-msgstr "目錄"
+msgstr ""
 
 #: src/constants/errors/self_check.ts:11
-#, fuzzy
 msgid "Sites-enabled directory not exist"
-msgstr "目錄"
+msgstr ""
 
 #: src/views/certificate/CertificateEditor.vue:211
 msgid "SSL Certificate Content"
@@ -2446,9 +2448,8 @@ msgid "Streams Directory"
 msgstr "目錄"
 
 #: src/constants/errors/self_check.ts:12
-#, fuzzy
 msgid "Streams-available directory not exist"
-msgstr "目錄"
+msgstr ""
 
 #: src/constants/errors/self_check.ts:13
 #, fuzzy
@@ -2604,7 +2605,7 @@ msgid ""
 "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:23
 #, fuzzy
 msgid ""
 "The model name should only contain letters, unicode, numbers, hyphens, "
@@ -2653,8 +2654,8 @@ msgstr "當前配置中的 server_name 必須是您需要獲取憑證的網域
 msgid "The url is invalid"
 msgstr "網址無效"
 
-#: src/views/preference/OpenAISettings.vue:47
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:35
+#: src/views/preference/OpenAISettings.vue:49
 msgid "The url is invalid."
 msgstr "網址無效。"
 
@@ -2751,14 +2752,14 @@ msgstr ""
 "為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
 "的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 
-#: src/views/preference/OpenAISettings.vue:48
+#: src/views/preference/OpenAISettings.vue:36
 msgid ""
 "To use a local large model, deploy it with ollama, vllm or lmdeploy. They "
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
 
-#: src/views/preference/OpenAISettings.vue:72
+#: src/views/preference/OpenAISettings.vue:61
 msgid "Token is not valid"
 msgstr "令牌無效"
 
@@ -2840,11 +2841,11 @@ msgstr "運作時間:"
 msgid "URL"
 msgstr "URL"
 
-#: src/components/TwoFA/Authorization.vue:102
+#: src/components/TwoFA/Authorization.vue:121
 msgid "Use OTP"
 msgstr "使用一次性密碼"
 
-#: src/components/TwoFA/Authorization.vue:98
+#: src/components/TwoFA/Authorization.vue:117
 msgid "Use recovery code"
 msgstr "使用恢復碼"
 
@@ -2994,8 +2995,9 @@ msgid ""
 msgstr ""
 
 #: src/views/preference/components/RecoveryCodes.vue:94
+#, fuzzy
 msgid "You have not generated recovery codes yet."
-msgstr ""
+msgstr "您確定要恢復此項目嗎?"
 
 #: src/views/preference/components/RecoveryCodes.vue:91
 msgid ""
@@ -3009,9 +3011,8 @@ msgid "Your old codes won't work anymore."
 msgstr ""
 
 #: src/views/preference/components/Passkey.vue:75
-#, fuzzy
 msgid "Your passkeys"
-msgstr "新增通行密鑰"
+msgstr ""
 
 #~ msgid ""
 #~ "If you lose your mobile phone, you can use the recovery code to reset "
@@ -3164,6 +3165,9 @@ msgstr "新增通行密鑰"
 #~ msgid "404 Not Found"
 #~ msgstr "404 未找到頁面"
 
+#~ msgid "Are you sure you want to restore?"
+#~ msgstr "您確定要恢復?"
+
 #~ msgid "Destroy"
 #~ msgstr "刪除"
 

+ 48 - 42
app/src/lib/http/index.ts

@@ -5,6 +5,7 @@ import { useSettingsStore, useUserStore } from '@/pinia'
 import router from '@/routes'
 import { message } from 'ant-design-vue'
 import axios from 'axios'
+import JSEncrypt from 'jsencrypt'
 import { storeToRefs } from 'pinia'
 import 'nprogress/nprogress.css'
 
@@ -33,16 +34,35 @@ const instance = axios.create({
   baseURL: import.meta.env.VITE_API_ROOT,
   timeout: 50000,
   headers: { 'Content-Type': 'application/json' },
-  transformRequest: [function (data, headers) {
-    if (!(headers) || headers['Content-Type'] === 'multipart/form-data;charset=UTF-8')
-      return data
-    else
-      headers['Content-Type'] = 'application/json'
-
-    return JSON.stringify(data)
-  }],
 })
 
+const http = {
+  get(url: string, config: AxiosRequestConfig = {}) {
+    // eslint-disable-next-line ts/no-explicit-any
+    return instance.get<any, any>(url, config)
+  },
+  // eslint-disable-next-line ts/no-explicit-any
+  post(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
+    // eslint-disable-next-line ts/no-explicit-any
+    return instance.post<any, any>(url, data, config)
+  },
+  // eslint-disable-next-line ts/no-explicit-any
+  put(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
+    // eslint-disable-next-line ts/no-explicit-any
+    return instance.put<any, any>(url, data, config)
+  },
+  delete(url: string, config: AxiosRequestConfig = {}) {
+    // eslint-disable-next-line ts/no-explicit-any
+    return instance.delete<any, any>(url, config)
+  },
+  patch(url: string, config: AxiosRequestConfig = {}) {
+    // eslint-disable-next-line ts/no-explicit-any
+    return instance.patch<any, any>(url, config)
+  },
+}
+
+export default http
+
 const nprogress = useNProgress()
 
 // Add new dedupe utility at the top
@@ -65,23 +85,36 @@ function useMessageDedupe(interval = 5000): MessageDedupe {
 }
 
 instance.interceptors.request.use(
-  config => {
+  async config => {
     nprogress.start()
     if (token.value) {
-      // eslint-disable-next-line ts/no-explicit-any
-      (config.headers as any).Authorization = token.value
+      config.headers.Authorization = token.value
     }
 
     if (settings.environment.id) {
-      // eslint-disable-next-line ts/no-explicit-any
-      (config.headers as any)['X-Node-ID'] = settings.environment.id
+      config.headers['X-Node-ID'] = settings.environment.id
     }
 
     if (secureSessionId.value) {
-      // eslint-disable-next-line ts/no-explicit-any
-      (config.headers as any)['X-Secure-Session-ID'] = secureSessionId.value
+      config.headers['X-Secure-Session-ID'] = secureSessionId.value
     }
 
+    if (config.headers?.['Content-Type'] !== 'multipart/form-data;charset=UTF-8') {
+      config.headers['Content-Type'] = 'application/json'
+
+      if (config.crypto) {
+        const cryptoParams = await http.get('/crypto/public_key')
+        const { public_key } = await cryptoParams
+
+        // Encrypt data with RSA public key
+        const encrypt = new JSEncrypt()
+        encrypt.setPublicKey(public_key)
+
+        config.data = JSON.stringify({
+          encrypted_params: encrypt.encrypt(JSON.stringify(config.data)),
+        })
+      }
+    }
     return config
   },
   err => {
@@ -154,30 +187,3 @@ instance.interceptors.response.use(
     return Promise.reject(error.response.data)
   },
 )
-
-const http = {
-  get(url: string, config: AxiosRequestConfig = {}) {
-    // eslint-disable-next-line ts/no-explicit-any
-    return instance.get<any, any>(url, config)
-  },
-  // eslint-disable-next-line ts/no-explicit-any
-  post(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
-    // eslint-disable-next-line ts/no-explicit-any
-    return instance.post<any, any>(url, data, config)
-  },
-  // eslint-disable-next-line ts/no-explicit-any
-  put(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
-    // eslint-disable-next-line ts/no-explicit-any
-    return instance.put<any, any>(url, data, config)
-  },
-  delete(url: string, config: AxiosRequestConfig = {}) {
-    // eslint-disable-next-line ts/no-explicit-any
-    return instance.delete<any, any>(url, config)
-  },
-  patch(url: string, config: AxiosRequestConfig = {}) {
-    // eslint-disable-next-line ts/no-explicit-any
-    return instance.patch<any, any>(url, config)
-  },
-}
-
-export default http

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.0.0-rc.1","build_id":7,"total_build":381}
+{"version":"2.0.0-rc.1","build_id":8,"total_build":382}

+ 10 - 21
app/src/views/preference/OpenAISettings.vue

@@ -1,29 +1,17 @@
 <script setup lang="ts">
 import type { Settings } from '@/api/settings'
+import { LLM_MODELS, LLM_PROVIDERS } from '@/constants/llm'
 
 const data: Settings = inject('data')!
 const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>
 
-const models = shallowRef([
-  {
-    value: 'gpt-4o-mini',
-  },
-  {
-    value: 'gpt-4o',
-  },
-  {
-    value: 'gpt-4-1106-preview',
-  },
-  {
-    value: 'gpt-4',
-  },
-  {
-    value: 'gpt-4-32k',
-  },
-  {
-    value: 'gpt-3.5-turbo',
-  },
-])
+const models = LLM_MODELS.map(model => ({
+  value: model,
+}))
+
+const providers = LLM_PROVIDERS.map(provider => ({
+  value: provider,
+}))
 </script>
 
 <template>
@@ -48,9 +36,10 @@ const models = shallowRef([
         : $gettext('To use a local large model, deploy it with ollama, vllm or lmdeploy. '
           + 'They provide an OpenAI-compatible API endpoint, so just set the baseUrl to your local API.')"
     >
-      <AInput
+      <AAutoComplete
         v-model:value="data.openai.base_url"
         :placeholder="$gettext('Leave blank for the default: https://api.openai.com/')"
+        :options="providers"
       />
     </AFormItem>
     <AFormItem

+ 11 - 0
app/src/views/site/ngx_conf/config_template/ConfigTemplate.vue

@@ -149,4 +149,15 @@ provide('ngx_directives', ngx_directives)
   overflow-y: scroll;
   overflow-x: hidden;
 }
+
+:deep(.ant-col) {
+  height: calc(100% - 16px);
+  .ant-list-item {
+    height: 100%;
+
+    .ant-card {
+      height: 100%;
+    }
+  }
+}
 </style>

+ 7 - 0
app/src/vite-env.d.ts

@@ -27,3 +27,10 @@ declare module '@vue/runtime-core' {
     }, disableHtmlEscaping?: boolean) => string
   }
 }
+
+declare module 'axios' {
+  interface AxiosRequestConfig {
+    crypto?: boolean
+    skipErrHandling?: boolean
+  }
+}

+ 1 - 1
gen.sh

@@ -4,7 +4,7 @@ go run generate.go -config ../../app.ini
 popd || exit
 
 # generate error definitions
-go run cmd/errdef/generate.go . ts ./app/src/constants/errors
+go run cmd/errdef/generate.go -project . -type ts -output ./app/src/constants/errors -ignore-dirs .devcontainer,app,.github
 
 # parse nginx directive indexs
 go run cmd/ngx_dir_index/ngx_dir_index.go ./internal/nginx/nginx_directives.json

+ 3 - 3
go.mod

@@ -35,7 +35,7 @@ require (
 	github.com/spf13/cast v1.7.1
 	github.com/stretchr/testify v1.10.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a
-	github.com/uozi-tech/cosy v1.14.3
+	github.com/uozi-tech/cosy v1.14.4
 	github.com/uozi-tech/cosy-driver-sqlite v0.2.1
 	github.com/urfave/cli/v3 v3.0.0-beta1
 	golang.org/x/crypto v0.32.0
@@ -256,7 +256,7 @@ require (
 	go.uber.org/ratelimit v0.3.1 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	golang.org/x/arch v0.14.0 // indirect
-	golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
+	golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 // indirect
 	golang.org/x/mod v0.23.0 // indirect
 	golang.org/x/oauth2 v0.26.0 // indirect
 	golang.org/x/sync v0.11.0 // indirect
@@ -269,7 +269,7 @@ require (
 	google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect
 	google.golang.org/grpc v1.70.0 // indirect
-	google.golang.org/protobuf v1.36.4 // indirect
+	google.golang.org/protobuf v1.36.5 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 	gopkg.in/guregu/null.v4 v4.0.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect

+ 6 - 60
go.sum

@@ -712,28 +712,16 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
 github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
 github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
 github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
-github.com/aws/aws-sdk-go-v2 v1.35.0 h1:jTPxEJyzjSuuz0wB+302hr8Eu9KUI+Zv8zlujMGJpVI=
-github.com/aws/aws-sdk-go-v2 v1.35.0/go.mod h1:JgstGg0JjWU1KpVJjD5H0y0yyAIpSdKEq556EI6yOOM=
 github.com/aws/aws-sdk-go-v2 v1.36.0 h1:b1wM5CcE65Ujwn565qcwgtOTT1aT4ADOHHgglKjG7fk=
 github.com/aws/aws-sdk-go-v2 v1.36.0/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM=
-github.com/aws/aws-sdk-go-v2/config v1.29.3 h1:a5Ucjxe6iV+LHEBmYA9w40rT5aGxWybx/4l/O/fvJlE=
-github.com/aws/aws-sdk-go-v2/config v1.29.3/go.mod h1:pt9z1x12zDiDb4iFLrxoeAKLVCU/Gp9DL/5BnwlY77o=
 github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k=
 github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.56 h1:JKMBreKudV+ozx6rZJLvEtiexv48aEdhdC7mXUw9MLs=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.56/go.mod h1:S3xRjIHD8HHFgMTz4L56q/7IldfNtGL9JjH/vP3U6DA=
 github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y=
 github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.26 h1:XMBqBEuZLf8yxtH+mU/uUDyQbN4iD/xv9h6he2+lzhw=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.26/go.mod h1:d0+wQ/3CYGPuHEfBTPpQdfUX7gjk0/Lxs5Q6KzdEGY8=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.30 h1:+7AzSGNhHoY53di13lvztf9Dyd/9ofzoYGBllkWp3a0=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.30/go.mod h1:Jxd/FrCny99yURiQiMywgXvBhd7tmgdv6KdlUTNzMSo=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 h1:lWm9ucLSRFiI4dQQafLrEOmEDGry3Swrz0BIRdiHJqQ=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31/go.mod h1:Huu6GG0YTfbPphQkDSo4dEGmQRTKb9k9G7RdtyQWxuI=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.30 h1:Ex06eY6I5rO7IX0HalGfa5nGjpBoOsS1Qm3xfjkuszs=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.30/go.mod h1:AvyEMA9QcX59kFhVizBpIBpEMThUTXssuJe+emBdcGM=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 h1:ACxDklUKKXb48+eg5ROZXi1vDgfMyfIA/WyvqHcHI0o=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31/go.mod h1:yadnfsDwqXeVaohbGc/RaD287PuyRw2wugkh5ZL2J6k=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk=
@@ -741,28 +729,16 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJN
 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.11 h1:5JKQ2J3BBW4ovy6A/5Lwx9SpA6IzgH8jB3bquGZ1NUw=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.11/go.mod h1:VShCk7rfCzK/b9U1aSkzLwcOoaDlYna16482QqEavis=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 h1:O+8vD2rGjfihBewr5bT+QUfYUHIxCVgG61LHoT59shM=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12/go.mod h1:usVdWJaosa66NMvmCrr08NcWDBRv4E6+YFG2pUdw1Lk=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.13 h1:yukUijkcclShNo3QXry+udZDyDQOy8siCjqNfpRKuf8=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.13/go.mod h1:Ka+a4bm2nmtvk+Ql1K2Bmr7MrJCs8qz4UDmaLQs1daY=
 github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.14 h1:GH3vnPsdH2sTkZRBPnAeMqwkJXdwPNrEh9nI+DEdD0o=
 github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.14/go.mod h1:fHFrxpH3kA2iK2NBg/jj3jxgVVfNS7WaKYC5axxr/PY=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.48.4 h1:qajhoD/ElVskbXAJfgljClGj7DGME0uoDGUMVjFTkNs=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.48.4/go.mod h1:kDfNqSNtcqB8aNUJClykJ+xLILNoYAaUIo72A2uR73Y=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.48.6 h1:O7L9iEodiF07vJoXShMrw2XyeAqZhLUIXqWEitCq6EE=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.48.6/go.mod h1:E93uWfli9RToQzVA7+bYnynKOFcYOhNWqhY1hWSMZRc=
-github.com/aws/aws-sdk-go-v2/service/sso v1.24.13 h1:q4pOAKxypbFoUJzOpgo939bF50qb4DgYshiDfcsdN0M=
-github.com/aws/aws-sdk-go-v2/service/sso v1.24.13/go.mod h1:G/0PTg7+vQT42ictQGjJhixzTcVZtHFvrN/OeTXrRfQ=
 github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok=
 github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.12 h1:4sGSGshSSfO1vrcXruPick3ioSf8nhhD6nuB2ni37P4=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.12/go.mod h1:NHpu/pLOelViA4qxkAFH10VLqh+XeLhZfXDaFyMVgSs=
 github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU=
 github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U=
-github.com/aws/aws-sdk-go-v2/service/sts v1.33.11 h1:RIXOjp7Dp4siCYJRwBHUcBdVgOWflSJGlq4ZhMI5Ta0=
-github.com/aws/aws-sdk-go-v2/service/sts v1.33.11/go.mod h1:ZR17k9bPKPR8u0IkyA6xVsjr56doNQ4ZB1fs7abYBfE=
 github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5gre3FI7BNOiDcVWc=
 github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w=
 github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
@@ -1558,8 +1534,6 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
 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/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
-github.com/oracle/oci-go-sdk/v65 v65.82.0 h1:42fSqE847E95ICfVPcKhRmzkvM6tucwbPdUMQydfWGc=
-github.com/oracle/oci-go-sdk/v65 v65.82.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
 github.com/oracle/oci-go-sdk/v65 v65.83.0 h1:KFI0oyyCTPmgevHF+QlN02Zdf23Jx1p1X+4KPyH14H8=
 github.com/oracle/oci-go-sdk/v65 v65.83.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
 github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI=
@@ -1678,8 +1652,6 @@ github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd
 github.com/sashabaranov/go-openai v1.36.1 h1:EVfRXwIlW2rUzpx6vR+aeIKCK/xylSrVYAx1TMTSX3g=
 github.com/sashabaranov/go-openai v1.36.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.31 h1:Fj7jPyu9TQjqfXcLylINK5PANSzOWXIX4QtGmfp67AY=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.31/go.mod h1:kzh+BSAvpoyHHdHBCDhmSWtBc1NbLMZ2lWHqnBoxFks=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32 h1:4+LP7qmsLSGbmc66m1s5dKRMBwztRppfxFKlYqYte/c=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32/go.mod h1:kzh+BSAvpoyHHdHBCDhmSWtBc1NbLMZ2lWHqnBoxFks=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -1687,8 +1659,6 @@ github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5
 github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
 github.com/selectel/go-selvpcclient/v3 v3.2.1 h1:ny6WIAMiHzKxOgOEnwcWE79wIQij1AHHylzPA41MXCw=
 github.com/selectel/go-selvpcclient/v3 v3.2.1/go.mod h1:3EfSf8aEWyhspOGbvZ6mvnFg7JN5uckxNyBFPGWsXNQ=
-github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
-github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
 github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
 github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@@ -1780,12 +1750,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1090 h1:0fZ+FZE7ZvqxGdYbtQW8OyPXGD1qGPmg4wT+Tjkv+1s=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1090/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1091 h1:RxogX8ZCPBmZ6PY7DjnWnwGRkAkYEEinT5WNNxbLVeo=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1091/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1090 h1:8AXFluT9RV4EeWC7kfJUWjnFQlIJ4pBVC/+Qtqgg0hM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1090/go.mod h1:/XMAs17Sih+pqp/Pxy0WpmdZE/CychzXEnW/tTrCujk=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1091 h1:36WwNgrtoGKszQovUj3+0CjNsM1gMQ3a5lvZx2bkjng=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1091/go.mod h1:cWRGvOUnMQMky4oliMX1dXT6Z4CbsSGOIxaUcrD5Zvw=
 github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
@@ -1812,12 +1778,12 @@ github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
 github.com/uozi-tech/cosy v1.14.3 h1:YDleGHghw5Dtd8H7Fy0Iq0caXfxmhk7Zt6tJBONjq5Q=
 github.com/uozi-tech/cosy v1.14.3/go.mod h1:DSKLtoVaGLUlJ8KiQ1vWEsnv85epRrAAMXSijuq+asM=
+github.com/uozi-tech/cosy v1.14.4 h1:9X9CzxYjTg9DRQKgBjYvDNOAYYFclOXYYq518nO4vr0=
+github.com/uozi-tech/cosy v1.14.4/go.mod h1:DSKLtoVaGLUlJ8KiQ1vWEsnv85epRrAAMXSijuq+asM=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2/go.mod h1:EZnRIbSj1V5U0gEeTobrXai/d1SV11lkl4zP9NFEmyE=
 github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CGXLmk/zD+aS51Z2o=
 github.com/uozi-tech/cosy-driver-postgres v0.2.1/go.mod h1:eAy1A89yHbAEfjkhNAifaJQk172NqrNoRyRtFcZc9Go=
-github.com/uozi-tech/cosy-driver-sqlite v0.2.0 h1:eTpIMyGoFUK4JcaiKfJHD5AyiM6vtCwN98c7Bz5n25o=
-github.com/uozi-tech/cosy-driver-sqlite v0.2.0/go.mod h1:87a6mzn5IuEtIR4z7U4Ey8eKLGfNEOSkv7kPQlbNQgM=
 github.com/uozi-tech/cosy-driver-sqlite v0.2.1 h1:W+Z4pY25PSJCeReqroG7LIBeffsqotbpHzgqSMqZDIM=
 github.com/uozi-tech/cosy-driver-sqlite v0.2.1/go.mod h1:2ya7Z5P3HzFi1ktfL8gvwaAGx0DDV0bmWxNSNpaLlwo=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
@@ -1840,12 +1806,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/yandex-cloud/go-genproto v0.0.0-20250127124313-5be1a2cc06d4 h1:3N8k0k2YikzqQUUAFqPhbhiLEodQrRKIvlsUuJ09DYo=
-github.com/yandex-cloud/go-genproto v0.0.0-20250127124313-5be1a2cc06d4/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
 github.com/yandex-cloud/go-genproto v0.0.0-20250203115010-0bcba64c41f6 h1:CHYGew+KO1JaK5sx/N2ApgVCTGCKvfSl0sSPplTyCog=
 github.com/yandex-cloud/go-genproto v0.0.0-20250203115010-0bcba64c41f6/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
-github.com/yandex-cloud/go-sdk v0.0.0-20250127132311-016f84adc072 h1:s2wfllm5Z32Sl1TktCxHXMKJ9yQXpdFUuN5CFA/8qJY=
-github.com/yandex-cloud/go-sdk v0.0.0-20250127132311-016f84adc072/go.mod h1:/7UdvQNU5/ISIOPHcj0S4lUcp/KejW2LJQhZGt9tdMU=
 github.com/yandex-cloud/go-sdk v0.0.0-20250203123950-24786ecffd92 h1:UTcY1921ZXBABB5JpSWxccyZaCjMuSbniyifW6nmLZ4=
 github.com/yandex-cloud/go-sdk v0.0.0-20250203123950-24786ecffd92/go.mod h1:MQm5WxsYpQRdUklz2C8q3uDhuIaDzzV7seLErAILLBE=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
@@ -1931,8 +1893,6 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
-golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
 golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1991,6 +1951,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
 golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
+golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 h1:qNgPs5exUA+G0C96DrPwNrvLSj7GT/9D+3WMWUcUg34=
+golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
 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-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -2033,8 +1995,6 @@ 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
-golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
 golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -2147,8 +2107,6 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec
 golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
 golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
-golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
-golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
 golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -2167,8 +2125,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
-golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
 golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2293,8 +2249,6 @@ 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.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.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
 golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -2335,8 +2289,6 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
 golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2347,8 +2299,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb
 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
-golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
 golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -2645,16 +2595,10 @@ 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-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-20250127172529-29210b9bc287 h1:WoUI1G0DQ648FKvSl756SKxHQR/bI+y4HyyIQfxMWI8=
-google.golang.org/genproto v0.0.0-20250127172529-29210b9bc287/go.mod h1:wkQ2Aj/xvshAUDtO/JHvu9y+AaN9cqs28QuSVSHtZSY=
 google.golang.org/genproto v0.0.0-20250204164813-702378808489 h1:nQcbCCOg2h2CQ0yA8SY3AHqriNKDvsetuq9mE/HFjtc=
 google.golang.org/genproto v0.0.0-20250204164813-702378808489/go.mod h1:wkQ2Aj/xvshAUDtO/JHvu9y+AaN9cqs28QuSVSHtZSY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287 h1:A2ni10G3UlplFrWdCDJTl7D7mJ7GSRm37S+PDimaKRw=
-google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
 google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 h1:fCuMM4fowGzigT89NCIsW57Pk9k2D12MMi2ODn+Nk+o=
 google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 h1:J1H9f+LEdWAfHcez/4cvaVBox7cOYT+IU6rgqj5x++8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -2721,6 +2665,8 @@ google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
 google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 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 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

+ 102 - 0
internal/crypto/crypto.go

@@ -0,0 +1,102 @@
+package crypto
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/json"
+	"encoding/pem"
+	"fmt"
+	"time"
+
+	"github.com/0xJacky/Nginx-UI/internal/cache"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+const (
+	CacheKey = "crypto"
+	timeout  = 10 * time.Minute
+)
+
+type Params struct {
+	PrivateKey string `json:"-"`
+	PublicKey  string `json:"public_key"`
+}
+
+// GenerateRSAKeyPair generates a new RSA key pair
+func GenerateRSAKeyPair() (privateKeyPEM, publicKeyPEM []byte, err error) {
+	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		return nil, nil, err
+	}
+	privateKeyPEM = pem.EncodeToMemory(&pem.Block{
+		Type:  "RSA PRIVATE KEY",
+		Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
+	})
+	publicKeyPEM = pem.EncodeToMemory(&pem.Block{
+		Type:  "RSA PUBLIC KEY",
+		Bytes: x509.MarshalPKCS1PublicKey(&privateKey.PublicKey),
+	})
+	return
+}
+
+// GetCryptoParams registers a new key pair in the cache if it doesn't exist
+// otherwise, it returns the existing nonce and public key
+func GetCryptoParams() (params *Params, err error) {
+	// Check if the key pair exists in then cache
+	if value, ok := cache.Get(CacheKey); ok {
+		return value.(*Params), nil
+	}
+	// Generate a nonce = hash(publicKey)
+	privateKeyPEM, publicKeyPEM, err := GenerateRSAKeyPair()
+	if err != nil {
+		return nil, err
+	}
+	params = &Params{
+		PrivateKey: string(privateKeyPEM),
+		PublicKey:  string(publicKeyPEM),
+	}
+	cache.Set(CacheKey, params, timeout)
+	return
+}
+
+// Decrypt decrypts the data with the private key (nonce, paramEncrypted)
+func Decrypt(paramEncrypted string) (data map[string]interface{}, err error) {
+	// Get crypto params from cache
+	value, ok := cache.Get(CacheKey)
+	if !ok {
+		return nil, ErrTimeout
+	}
+
+	params := value.(*Params)
+	block, _ := pem.Decode([]byte(params.PrivateKey))
+	if block == nil {
+		return nil, fmt.Errorf("failed to decode PEM block containing private key")
+	}
+
+	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		logger.Errorf("failed to parse private key: %v", err)
+		return nil, err
+	}
+
+	paramEncryptedDecoded, err := base64.StdEncoding.DecodeString(paramEncrypted)
+	if err != nil {
+		logger.Errorf("base64 decode error: %v", err)
+		return nil, err
+	}
+
+	decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, paramEncryptedDecoded)
+	if err != nil {
+		logger.Errorf("decryption failed: %v", err)
+		return nil, err
+	}
+
+	err = json.Unmarshal(decrypted, &data)
+	if err != nil {
+		return nil, err
+	}
+
+	return
+}

+ 1 - 0
internal/crypto/errors.go

@@ -6,4 +6,5 @@ var (
 	e                     = cosy.NewErrorScope("crypto")
 	ErrPlainTextEmpty     = e.New(50001, "plain text is empty")
 	ErrCipherTextTooShort = e.New(50002, "cipher text is too short")
+	ErrTimeout            = e.New(40401, "request timeout")
 )

+ 9 - 6
internal/kernel/boot.go

@@ -3,6 +3,10 @@ package kernel
 import (
 	"crypto/rand"
 	"encoding/hex"
+	"mime"
+	"path"
+	"runtime"
+
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/cache"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
@@ -17,10 +21,8 @@ import (
 	"github.com/uozi-tech/cosy"
 	sqlite "github.com/uozi-tech/cosy-driver-sqlite"
 	"github.com/uozi-tech/cosy/logger"
+	cModel "github.com/uozi-tech/cosy/model"
 	cSettings "github.com/uozi-tech/cosy/settings"
-	"mime"
-	"path"
-	"runtime"
 )
 
 func Boot() {
@@ -73,12 +75,13 @@ func recovery() {
 }
 
 func InitDatabase() {
+	cModel.ResolvedModels()
 	// Skip install
 	if settings.NodeSettings.SkipInstallation {
 		skipInstall()
 	}
 
-	if "" != cSettings.AppSettings.JwtSecret {
+	if cSettings.AppSettings.JwtSecret != "" {
 		db := cosy.InitDB(sqlite.Open(path.Dir(cSettings.ConfPath), settings.DatabaseSettings))
 		model.Use(db)
 		query.Init(db)
@@ -88,7 +91,7 @@ func InitDatabase() {
 }
 
 func InitNodeSecret() {
-	if "" == settings.NodeSettings.Secret {
+	if settings.NodeSettings.Secret == "" {
 		logger.Info("Secret is empty, generating...")
 		uuidStr := uuid.New().String()
 		settings.NodeSettings.Secret = uuidStr
@@ -102,7 +105,7 @@ func InitNodeSecret() {
 }
 
 func InitCryptoSecret() {
-	if "" == settings.CryptoSettings.Secret {
+	if settings.CryptoSettings.Secret == "" {
 		logger.Info("Secret is empty, generating...")
 
 		key := make([]byte, 32)

+ 46 - 0
internal/middleware/encrypted_params.go

@@ -0,0 +1,46 @@
+package middleware
+
+import (
+	"bytes"
+	"encoding/json"
+	"io"
+	"net/http"
+
+	"github.com/0xJacky/Nginx-UI/internal/crypto"
+	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
+)
+
+var (
+	e                       = cosy.NewErrorScope("middleware")
+	ErrInvalidRequestFormat = e.New(40000, "invalid request format")
+	ErrDecryptionFailed     = e.New(40001, "decryption failed")
+)
+
+func EncryptedParams() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// read the encrypted payload
+		var encryptedReq struct {
+			EncryptedParams string `json:"encrypted_params"`
+		}
+
+		if err := c.ShouldBindJSON(&encryptedReq); err != nil {
+			c.AbortWithStatusJSON(http.StatusBadRequest, ErrInvalidRequestFormat)
+			return
+		}
+
+		// decrypt the parameters
+		decryptedData, err := crypto.Decrypt(encryptedReq.EncryptedParams)
+		if err != nil {
+			c.AbortWithStatusJSON(http.StatusBadRequest, ErrDecryptionFailed)
+			return
+		}
+
+		// replace request body with decrypted data
+		newBody, _ := json.Marshal(decryptedData)
+		c.Request.Body = io.NopCloser(bytes.NewReader(newBody))
+		c.Request.ContentLength = int64(len(newBody))
+
+		c.Next()
+	}
+}

+ 8 - 8
internal/middleware/middleware.go

@@ -53,16 +53,16 @@ func AuthRequired() gin.HandlerFunc {
 			c.Set("ProxyNodeID", xNodeID)
 		}
 
+		if token := c.GetHeader("X-Node-Secret"); token != "" && token == settings.NodeSettings.Secret {
+			c.Set("Secret", token)
+			c.Next()
+			return
+		}
+
 		token := getToken(c)
 		if token == "" {
-			if token = c.GetHeader("X-Node-Secret"); token != "" && token == settings.NodeSettings.Secret {
-				c.Set("Secret", token)
-				c.Next()
-				return
-			} else {
-				abortWithAuthFailure()
-				return
-			}
+			abortWithAuthFailure()
+			return
 		}
 
 		u, ok := user.GetTokenUser(token)

+ 6 - 2
internal/middleware/proxy_ws.go

@@ -1,12 +1,13 @@
 package middleware
 
 import (
+	"net/http"
+
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
 	"github.com/pretty66/websocketproxy"
 	"github.com/spf13/cast"
 	"github.com/uozi-tech/cosy/logger"
-	"net/http"
 )
 
 func ProxyWs() gin.HandlerFunc {
@@ -26,7 +27,6 @@ func ProxyWs() gin.HandlerFunc {
 
 		env := query.Environment
 		environment, err := env.Where(env.ID.Eq(id)).First()
-
 		if err != nil {
 			logger.Error(err)
 			return
@@ -43,6 +43,10 @@ func ProxyWs() gin.HandlerFunc {
 
 		wp, err := websocketproxy.NewProxy(decodedUri, func(r *http.Request) error {
 			r.Header.Set("X-Node-Secret", environment.Token)
+			r.Header.Del("X-Node-ID")
+			queryValues := r.URL.Query()
+			queryValues.Del("x_node_id")
+			r.URL.RawQuery = queryValues.Encode()
 			return nil
 		})
 

+ 32 - 0
internal/nginx/nginx_directives.json

@@ -741,6 +741,11 @@
       "https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_ssl_certificate"
     ]
   },
+  "grpc_ssl_certificate_cache": {
+    "links": [
+      "https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_ssl_certificate_cache"
+    ]
+  },
   "grpc_ssl_certificate_key": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_ssl_certificate_key"
@@ -1241,6 +1246,11 @@
       "https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_disable"
     ]
   },
+  "keepalive_min_timeout": {
+    "links": [
+      "https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_min_timeout"
+    ]
+  },
   "keepalive_requests": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests",
@@ -2100,6 +2110,12 @@
       "https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_ssl_certificate"
     ]
   },
+  "proxy_ssl_certificate_cache": {
+    "links": [
+      "https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_certificate_cache",
+      "https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_ssl_certificate_cache"
+    ]
+  },
   "proxy_ssl_certificate_key": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_certificate_key",
@@ -2750,6 +2766,12 @@
       "https://nginx.org/en/docs/stream/ngx_stream_ssl_module.html#ssl_certificate"
     ]
   },
+  "ssl_certificate_cache": {
+    "links": [
+      "https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_cache",
+      "https://nginx.org/en/docs/stream/ngx_stream_ssl_module.html#ssl_certificate_cache"
+    ]
+  },
   "ssl_certificate_key": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key",
@@ -2821,6 +2843,11 @@
       "https://nginx.org/en/docs/stream/ngx_stream_ssl_module.html#ssl_key_log"
     ]
   },
+  "ssl_object_cache_inheritable": {
+    "links": [
+      "https://nginx.org/en/docs/ngx_core_module.html#ssl_object_cache_inheritable"
+    ]
+  },
   "ssl_ocsp": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ocsp",
@@ -3374,6 +3401,11 @@
       "https://nginx.org/en/docs/http/ngx_http_uwsgi_module.html#uwsgi_ssl_certificate"
     ]
   },
+  "uwsgi_ssl_certificate_cache": {
+    "links": [
+      "https://nginx.org/en/docs/http/ngx_http_uwsgi_module.html#uwsgi_ssl_certificate_cache"
+    ]
+  },
   "uwsgi_ssl_certificate_key": {
     "links": [
       "https://nginx.org/en/docs/http/ngx_http_uwsgi_module.html#uwsgi_ssl_certificate_key"

+ 2 - 0
router/routers.go

@@ -15,6 +15,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api/openai"
 	"github.com/0xJacky/Nginx-UI/api/public"
 	"github.com/0xJacky/Nginx-UI/api/settings"
+	"github.com/0xJacky/Nginx-UI/api/crypto"
 	"github.com/0xJacky/Nginx-UI/api/sites"
 	"github.com/0xJacky/Nginx-UI/api/streams"
 	"github.com/0xJacky/Nginx-UI/api/system"
@@ -42,6 +43,7 @@ func InitRouter() {
 	root := r.Group("/api")
 	{
 		public.InitRouter(root)
+		crypto.InitPublicRouter(root)
 		system.InitPublicRouter(root)
 		user.InitAuthRouter(root)
 

+ 9 - 0
template/block/vue-router-history-mode.conf

@@ -0,0 +1,9 @@
+# Nginx UI Template Start
+name = "Vue History Router"
+author = "@0xJacky"
+description = { en = "Vue Router History Mode Config", zh_CN = "Vue Router History 模式配置", zh_TW = "Vue Router History 模式配置" }
+# Nginx UI Template End
+
+location / {
+  try_files $uri $uri/ /index.html;
+}