diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml index 503e26cb4..4aa6a6a42 100644 --- a/core/i18n/lang/en.yaml +++ b/core/i18n/lang/en.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Failed to reload the firewall, {{ .err }}, manually r # mobile app ErrVerifyToken: 'Token verification failed. Reset and scan again.' ErrInvalidToken: 'Invalid token. Reset and scan again.' -ErrExpiredToken: 'Token expired. Reset and scan again.' +ErrExpiredToken: 'QR code is no longer valid. Generate a new one and scan again.' # command export Name: "Name" diff --git a/core/i18n/lang/es-ES.yaml b/core/i18n/lang/es-ES.yaml index a3f32a4c6..e3b02f563 100644 --- a/core/i18n/lang/es-ES.yaml +++ b/core/i18n/lang/es-ES.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Fallo al recargar el firewall, {{ .err }}, recargue e # aplicación móvil ErrVerifyToken: 'Error al verificar el token, por favor restablezca y escanee de nuevo.' ErrInvalidToken: 'Token inválido, por favor restablezca y escanee de nuevo.' -ErrExpiredToken: 'El token ha expirado, por favor restablezca y escanee de nuevo.' +ErrExpiredToken: 'El código QR ya no es válido. Genere uno nuevo y vuelva a escanearlo.' # exportación de comandos Name: "Nombre" diff --git a/core/i18n/lang/fa.yaml b/core/i18n/lang/fa.yaml index 54e4c9126..e4ea9a9bc 100644 --- a/core/i18n/lang/fa.yaml +++ b/core/i18n/lang/fa.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "بارگذاری مجدد دیواره آتش نام # برنامه موبایل ErrVerifyToken: 'تأیید توکن ناموفق بود. بازنشانی کرده و دوباره اسکن کنید.' ErrInvalidToken: 'توکن نامعتبر است. بازنشانی کرده و دوباره اسکن کنید.' -ErrExpiredToken: 'توکن منقضی شده است. بازنشانی کرده و دوباره اسکن کنید.' +ErrExpiredToken: 'کد QR دیگر معتبر نیست. یک کد جدید ایجاد و دوباره اسکن کنید.' # خروجی فرمان Name: "نام" diff --git a/core/i18n/lang/ja.yaml b/core/i18n/lang/ja.yaml index 18b49f784..17bac16ac 100644 --- a/core/i18n/lang/ja.yaml +++ b/core/i18n/lang/ja.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "ファイアウォールのリロードに失敗し # モバイルアプリ ErrVerifyToken: 'トークンの検証エラーです。リセット後、再度QRコードをスキャンしてください。' ErrInvalidToken: '無効なトークンです。リセット後、再度QRコードをスキャンしてください。' -ErrExpiredToken: 'トークンの有効期限が切れました。リセット後、再度QRコードをスキャンしてください。' +ErrExpiredToken: 'QRコードが無効になりました。再生成してからもう一度スキャンしてください。' # コマンドエクスポート Name: "名前" diff --git a/core/i18n/lang/ko.yaml b/core/i18n/lang/ko.yaml index 3d94235bd..4606b8d59 100644 --- a/core/i18n/lang/ko.yaml +++ b/core/i18n/lang/ko.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "방화벽 다시 로드 실패 {{ .err }}, 방화벽 # 모바일 앱 ErrVerifyToken: '토큰 검증 오류가 발생했습니다. 재설정 후 다시 스캔해 주세요.' ErrInvalidToken: '유효하지 않은 토큰입니다. 재설정 후 다시 스캔해 주세요.' -ErrExpiredToken: '토큰이 만료되었습니다. 재설정 후 다시 스캔해 주세요.' +ErrExpiredToken: 'QR 코드가 더 이상 유효하지 않습니다. 새로 생성한 후 다시 스캔해 주세요.' # 명령 내보내기 Name: "이름" diff --git a/core/i18n/lang/lo.yaml b/core/i18n/lang/lo.yaml index 1c6b07164..cf9060676 100644 --- a/core/i18n/lang/lo.yaml +++ b/core/i18n/lang/lo.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "ໂຫຼດໄຟຣ໌ວໍຄືນໃໝ່ບ # mobile app ErrVerifyToken: 'ການກວດສອບໂທເຄັນລົ້ມເຫຼວ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.' ErrInvalidToken: 'ໂທເຄັນບໍ່ຖືກຕ້ອງ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.' -ErrExpiredToken: 'ໂທເຄັນໝົດອາຍຸແລ້ວ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.' +ErrExpiredToken: 'ລະຫັດ QR ໃຊ້ບໍ່ໄດ້ແລ້ວ. ກະລຸນາສ້າງໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.' # command export Name: "ຊື່" diff --git a/core/i18n/lang/ms.yaml b/core/i18n/lang/ms.yaml index e724e2498..008f43cf9 100644 --- a/core/i18n/lang/ms.yaml +++ b/core/i18n/lang/ms.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Gagal memuat semula firewall, {{ .err }}, sila muat s # aplikasi mudah alih ErrVerifyToken: "Ralat pengesahan token, sila tetapkan semula dan imbas semula" ErrInvalidToken: "Token tidak sah, sila tetapkan semula dan imbas semula" -ErrExpiredToken: "Token telah tamat tempoh, sila tetapkan semula dan imbas semula" +ErrExpiredToken: 'Kod QR tidak lagi sah. Jana kod baharu dan imbas semula.' # eksport perintah Name: "Nama" diff --git a/core/i18n/lang/pt-BR.yaml b/core/i18n/lang/pt-BR.yaml index be80d94c7..d1e9dfd51 100644 --- a/core/i18n/lang/pt-BR.yaml +++ b/core/i18n/lang/pt-BR.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Falha ao recarregar o firewall, {{ .err }}, por favor # aplicativo móvel ErrVerifyToken: 'Erro de verificação do token, por favor, reinicie e escaneie novamente.' ErrInvalidToken: 'Token inválido, por favor, reinicie e escaneie novamente.' -ErrExpiredToken: 'O token expirou, por favor, reinicie e escaneie novamente.' +ErrExpiredToken: 'O código QR não é mais válido. Gere um novo e escaneie novamente.' # exportação de comandos Name: "Nome" diff --git a/core/i18n/lang/ru.yaml b/core/i18n/lang/ru.yaml index 5317e2b79..3cac24627 100644 --- a/core/i18n/lang/ru.yaml +++ b/core/i18n/lang/ru.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Не удалось перезагрузить фае # мобильное приложение ErrVerifyToken: 'шибка проверки токена, пожалуйста, сбросьте и отсканируйте снова.' ErrInvalidToken: 'Неверный токен, пожалуйста, сбросьте и отсканируйте снова.' -ErrExpiredToken: 'Токен истек, пожалуйста, сбросьте и отсканируйте снова.' +ErrExpiredToken: 'QR-код недействителен. Создайте новый и отсканируйте его снова.' # экспорт команд Name: "Название" diff --git a/core/i18n/lang/tr.yaml b/core/i18n/lang/tr.yaml index 57cba13e3..90afba460 100644 --- a/core/i18n/lang/tr.yaml +++ b/core/i18n/lang/tr.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "Güvenlik duvarını yeniden yükleme başarısız, { # mobil uygulama ErrVerifyToken: 'Token doğrulama hatası, lütfen sıfırlayın ve tekrar tarayın.' ErrInvalidToken: 'Geçersiz token, lütfen sıfırlayın ve tekrar tarayın.' -ErrExpiredToken: 'Token süresi dolmuş, lütfen sıfırlayın ve tekrar tarayın.' +ErrExpiredToken: 'QR kodu artık geçerli değil. Yeni bir kod oluşturup tekrar tarayın.' # komut dışa aktarma Name: "Ad" diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index 1322db706..33cf1e996 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "防火牆重載失敗,{{ .err }},請您手動重 # 行動端 ErrVerifyToken: '令牌驗證錯誤,請重設後再次掃碼' ErrInvalidToken: '無效的令牌,請重設後再次掃碼' -ErrExpiredToken: '令牌過期,請重設後再次掃碼' +ErrExpiredToken: '二維碼已失效,請重新產生後再次掃碼' # 命令匯出 Name: "名稱" diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml index 24be3d4b8..c3ffd792b 100644 --- a/core/i18n/lang/zh.yaml +++ b/core/i18n/lang/zh.yaml @@ -443,7 +443,7 @@ UpdatePortFirewallReload: "防火墙重载失败,{{ .err }},请您手动重 # 移动端 ErrVerifyToken: '令牌验证错误,请重置后再次扫码' ErrInvalidToken: '无效的令牌,请重置后再次扫码' -ErrExpiredToken: '令牌过期,请重置后再次扫码' +ErrExpiredToken: '二维码已失效,请重新生成后再次扫码' # 命令导出 Name: "名称" diff --git a/core/utils/ttlstore/ttlstore.go b/core/utils/ttlstore/ttlstore.go index 8c94af9b1..ca71fe592 100644 --- a/core/utils/ttlstore/ttlstore.go +++ b/core/utils/ttlstore/ttlstore.go @@ -5,6 +5,8 @@ import ( "time" ) +const maxIDGenerationAttempts = 32 + type Item[T any] struct { Value T ExpiresAt time.Time @@ -30,15 +32,41 @@ func New[T any](ttl time.Duration, maxEntries int, newID func() string) *Store[T } func (s *Store[T]) Set(value T) string { + return s.set(value, true) +} + +func (s *Store[T]) TrySet(value T) string { + return s.set(value, false) +} + +func (s *Store[T]) set(value T, evictOldest bool) string { s.mu.Lock() defer s.mu.Unlock() s.cleanupExpiredLocked() + itemID := "" + for range maxIDGenerationAttempts { + candidate := s.newID() + if candidate == "" { + continue + } + if _, exists := s.items[candidate]; exists { + continue + } + itemID = candidate + break + } + if itemID == "" { + return "" + } + if len(s.items) >= s.maxEntries { + if !evictOldest { + return "" + } s.removeOldestLocked() } - itemID := s.newID() s.items[itemID] = Item[T]{ Value: value, ExpiresAt: s.now().Add(s.ttl), diff --git a/frontend/src/layout/components/Sidebar/index.vue b/frontend/src/layout/components/Sidebar/index.vue index fdc422b54..7bc878026 100644 --- a/frontend/src/layout/components/Sidebar/index.vue +++ b/frontend/src/layout/components/Sidebar/index.vue @@ -194,7 +194,10 @@ function buildVisibleMenu(menu: RouteRecordRaw, showSet: Set): RouteReco const visibleChildren = children .map((item) => { - if ((item.name === 'Upage' || item.name === 'XApp') && (isIntl.value || (isEE.value && !isAdmin.value))) { + if (item.name === 'Upage' && (isIntl.value || (isEE.value && !isAdmin.value))) { + return null; + } + if (item.name === 'XApp' && isIntl.value) { return null; } return buildVisibleMenu(item, showSet);