diff --git a/app/(dashboard)/sse/page.tsx b/app/(dashboard)/sse/page.tsx index 89ec4288..ea6a8533 100644 --- a/app/(dashboard)/sse/page.tsx +++ b/app/(dashboard)/sse/page.tsx @@ -48,7 +48,14 @@ import { isSafeLocalFilePermissions, type ConfigFormState, } from "@/lib/sse/config" -import type { KmsConfigPayload, KmsKeyInfo, KmsKeyMetadata, KmsServiceStatusResponse } from "@/types/kms" +import { RekeyCard } from "@/components/sse/rekey-card" +import type { + KmsBackendCapabilities, + KmsConfigPayload, + KmsKeyInfo, + KmsKeyMetadata, + KmsServiceStatusResponse, +} from "@/types/kms" import { AlertDialog, AlertDialogAction, @@ -69,6 +76,7 @@ const ADVANCED_CONFIG_FIELDS = new Set([ "maxCachedKeys", "cacheTtlSeconds", ]) +const TLS_CONFIG_FIELDS = new Set(["caCertPath", "clientCertPath", "clientKeyPath"]) type KeyActionState = { type: "scheduleDelete" | "forceDelete" | "cancelDeletion" @@ -121,6 +129,7 @@ export default function SSEPage() { const message = useMessage() const { getKMSStatus, + getDetailedStatus, configureKMS, reconfigureKMS, clearCache, @@ -136,6 +145,7 @@ export default function SSEPage() { const [status, setStatus] = React.useState(null) const [statusError, setStatusError] = React.useState(null) + const [capabilities, setCapabilities] = React.useState(null) const statusRequestRef = React.useRef(0) const [formState, setFormState] = React.useState(INITIAL_FORM_STATE) const [baselineFormState, setBaselineFormState] = React.useState(INITIAL_FORM_STATE) @@ -145,6 +155,7 @@ export default function SSEPage() { const formStateRef = React.useRef(formState) const baselineFormStateRef = React.useRef(baselineFormState) const advancedSettingsRef = React.useRef(null) + const advancedTlsRef = React.useRef(null) const [loadingStatus, setLoadingStatus] = React.useState(false) const [refreshingStatus, setRefreshingStatus] = React.useState(false) const [submittingConfig, setSubmittingConfig] = React.useState(false) @@ -199,6 +210,8 @@ export default function SSEPage() { const hasConfiguration = !statusError && statusKind !== "NotConfigured" const localKmsConfigured = hasConfiguration && status?.backend_type === "Local" const hasStoredVaultCredentials = status?.config_summary?.backend_summary?.has_stored_credentials === true + const hasStoredCustomCa = status?.config_summary?.backend_summary?.has_custom_ca === true + const hasStoredClientIdentity = status?.config_summary?.backend_summary?.has_client_identity === true const hasStoredLocalMasterKey = status?.config_summary?.backend_summary?.has_master_key === true const hasStoredLocalFilePermissions = status?.config_summary?.backend_summary?.file_permissions != null const statusBadgeValue = @@ -330,10 +343,36 @@ export default function SSEPage() { loadKeys("", false).catch(() => undefined) }, [isRunning, loadKeys]) + // The capability matrix is only served while KMS is running, and only by + // newer servers. Absence means "unknown": no positioning badge, no rekey UI. + // status?.backend_type is a dependency because a reconfigure can swap the + // backend (and its capabilities) without ever leaving the Running state. + const runningBackendType = isRunning ? status?.backend_type : null + React.useEffect(() => { + if (!isRunning) { + setCapabilities(null) + return + } + let cancelled = false + getDetailedStatus() + .then((detailedStatus) => { + if (!cancelled) setCapabilities(detailedStatus.capabilities ?? null) + }) + .catch(() => { + if (!cancelled) setCapabilities(null) + }) + return () => { + cancelled = true + } + }, [getDetailedStatus, isRunning, runningBackendType]) + React.useEffect(() => { if (configFormErrorField && ADVANCED_CONFIG_FIELDS.has(configFormErrorField)) { advancedSettingsRef.current?.setAttribute("open", "") } + if (configFormErrorField && TLS_CONFIG_FIELDS.has(configFormErrorField)) { + advancedTlsRef.current?.setAttribute("open", "") + } }, [configFormErrorField]) React.useEffect(() => { @@ -557,6 +596,15 @@ export default function SSEPage() { if (!values.mountPath.trim()) { return { error: t("Please enter Vault transit mount path"), field: "transitMountPath" } } + const caCertPath = values.caCertPath.trim() + const clientCertPath = values.clientCertPath.trim() + const clientKeyPath = values.clientKeyPath.trim() + if (Boolean(clientCertPath) !== Boolean(clientKeyPath)) { + return { + error: t("The mTLS client certificate and private key paths must be provided together."), + field: clientCertPath ? "clientKeyPath" : "clientCertPath", + } + } return { payload: { @@ -576,6 +624,10 @@ export default function SSEPage() { } : {}), skip_tls_verify: values.skipTlsVerify, + // Older servers reject unknown fields, so blank TLS inputs must be + // omitted from the payload entirely instead of sent as empty values. + ...(caCertPath ? { ca_cert_path: caCertPath } : {}), + ...(clientCertPath ? { client_cert_path: clientCertPath, client_key_path: clientKeyPath } : {}), default_key_id: defaultKeyId || undefined, timeout_seconds: timeoutSeconds ?? 30, retry_attempts: retryAttempts ?? 3, @@ -988,6 +1040,11 @@ export default function SSEPage() { {loadingStatus ? t("Loading…") : getKmsStatusText()} + {capabilities?.production_supported === false ? ( + + {t("Development / testing backend — not supported for production")} + + ) : null} {getKmsStatusDescription()} {!statusError && status?.backend_type && ( @@ -1168,10 +1225,12 @@ export default function SSEPage() { {t("Unsupported KMS backend")} ) : null} - {t("Local filesystem")} + {t("Local filesystem (dev/testing only)")} {t("HashiCorp Vault KV2")} {t("HashiCorp Vault Transit Engine")} - {t("Static single-key (built-in)")} + + {t("Static single-key (built-in, dev/testing only)")} + @@ -1438,6 +1497,105 @@ export default function SSEPage() { {t("Skip TLS verification")} + +
+ + {t("Advanced TLS")} + + {t("Custom CA")} · {t("mTLS client identity")} + + + + {hasStoredCustomCa || hasStoredClientIdentity ? ( + + + {[ + hasStoredCustomCa ? t("Custom CA: configured") : null, + hasStoredClientIdentity ? t("mTLS client identity: configured") : null, + ] + .filter(Boolean) + .join(" · ")} + + + {t( + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.", + )} + + + ) : null} + + + + {t("CA Certificate Path")} + + updateFormState("caCertPath", event.target.value)} + autoComplete="off" + placeholder="/etc/rustfs/certs/vault-ca.pem" + spellCheck={false} + disabled={formDisabled} + aria-invalid={configFormErrorField === "caCertPath"} + aria-describedby={ + configFormErrorField === "caCertPath" ? "kms-config-error" : undefined + } + /> + + {t("PEM CA bundle trusted for the Vault connection.")} + + + + {t("Client Certificate Path")} + + updateFormState("clientCertPath", event.target.value)} + autoComplete="off" + placeholder="/etc/rustfs/certs/vault-client.pem" + spellCheck={false} + disabled={formDisabled} + aria-invalid={configFormErrorField === "clientCertPath"} + aria-describedby={ + configFormErrorField === "clientCertPath" ? "kms-config-error" : undefined + } + /> + + + {t("PEM client certificate presented to Vault for mTLS.")} + + + + + {t("Client Key Path")} + + updateFormState("clientKeyPath", event.target.value)} + autoComplete="off" + placeholder="/etc/rustfs/certs/vault-client.key" + spellCheck={false} + disabled={formDisabled} + aria-invalid={configFormErrorField === "clientKeyPath"} + aria-describedby={ + configFormErrorField === "clientKeyPath" ? "kms-config-error" : undefined + } + /> + + {t("PEM private key matching the client certificate.")} + + +

+ {t( + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.", + )} +

+
)} @@ -1856,6 +2014,8 @@ export default function SSEPage() { )} + + {isRunning && capabilities ? : null} diff --git a/components/sse/rekey-card.tsx b/components/sse/rekey-card.tsx new file mode 100644 index 00000000..d74be2db --- /dev/null +++ b/components/sse/rekey-card.tsx @@ -0,0 +1,333 @@ +"use client" + +import * as React from "react" +import { useTranslation } from "react-i18next" +import { RiRefreshLine } from "@remixicon/react" +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader } from "@/components/ui/card" +import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from "@/components/ui/field" +import { Input } from "@/components/ui/input" +import { Spinner } from "@/components/ui/spinner" +import { useSSE } from "@/hooks/use-sse" +import { useMessage } from "@/lib/feedback/message" +import { + buildRekeyStartRequest, + isRekeyAlreadyRunningError, + isRekeyNeverRanError, + isRekeyUnsupportedError, +} from "@/lib/sse/rekey" +import type { KmsRekeyJobSnapshot } from "@/types/kms" + +const POLL_INTERVAL_MS = 3000 + +function getRekeyStateBadgeVariant(state: KmsRekeyJobSnapshot["state"]) { + if (state === "running") return "secondary" as const + if (state === "cancelled") return "destructive" as const + return "outline" as const +} + +interface RekeyCardProps { + rewrapSupported: boolean +} + +export function RekeyCard({ rewrapSupported }: RekeyCardProps) { + const { t } = useTranslation() + const message = useMessage() + const { startRekey, getRekeyStatus, cancelRekey } = useSSE() + + const [snapshot, setSnapshot] = React.useState(null) + const [neverRan, setNeverRan] = React.useState(false) + const [statusErrorMessage, setStatusErrorMessage] = React.useState(null) + const [loadingSnapshot, setLoadingSnapshot] = React.useState(rewrapSupported) + const [startingSweep, setStartingSweep] = React.useState(false) + const [cancellingSweep, setCancellingSweep] = React.useState(false) + const [bucketsInput, setBucketsInput] = React.useState("") + const [prefixInput, setPrefixInput] = React.useState("") + const [confirmStartOpen, setConfirmStartOpen] = React.useState(false) + const requestRef = React.useRef(0) + + const refreshSnapshot = React.useCallback(async () => { + const requestId = ++requestRef.current + try { + const result = await getRekeyStatus() + if (requestId !== requestRef.current) return + setSnapshot(result) + setNeverRan(false) + setStatusErrorMessage(null) + } catch (error) { + if (requestId !== requestRef.current) return + if (isRekeyNeverRanError(error)) { + setSnapshot(null) + setNeverRan(true) + setStatusErrorMessage(null) + } else { + setStatusErrorMessage((error as Error).message || t("Failed to load rekey sweep status")) + } + } finally { + if (requestId === requestRef.current) setLoadingSnapshot(false) + } + }, [getRekeyStatus, t]) + + React.useEffect(() => { + if (!rewrapSupported) return + void refreshSnapshot() + }, [refreshSnapshot, rewrapSupported]) + + const isSweepRunning = snapshot?.state === "running" + + React.useEffect(() => { + if (!isSweepRunning) return + const intervalId = setInterval(() => { + void refreshSnapshot() + }, POLL_INTERVAL_MS) + return () => clearInterval(intervalId) + }, [isSweepRunning, refreshSnapshot]) + + const handleStartSweep = async () => { + setConfirmStartOpen(false) + setStartingSweep(true) + try { + const result = await startRekey(buildRekeyStartRequest(bucketsInput, prefixInput)) + requestRef.current++ + setSnapshot(result) + setNeverRan(false) + setStatusErrorMessage(null) + message.success(t("Rekey sweep started")) + } catch (error) { + if (isRekeyAlreadyRunningError(error)) { + message.warning(t("A rekey sweep is already running. Showing its progress.")) + await refreshSnapshot() + } else if (isRekeyUnsupportedError(error)) { + message.error(t("The configured KMS backend does not support rewrapping data-key envelopes.")) + } else { + message.error((error as Error).message || t("Failed to start rekey sweep")) + } + } finally { + setStartingSweep(false) + } + } + + const handleCancelSweep = async () => { + setCancellingSweep(true) + try { + const result = await cancelRekey() + requestRef.current++ + setSnapshot(result) + message.success(t("Rekey sweep cancellation requested")) + } catch (error) { + if (isRekeyNeverRanError(error)) { + setSnapshot(null) + setNeverRan(true) + } else { + message.error((error as Error).message || t("Failed to cancel rekey sweep")) + } + } finally { + setCancellingSweep(false) + } + } + + return ( + <> + + +
+
+

{t("Rekey Existing Objects")}

+ + {t( + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.", + )} + +
+ {rewrapSupported ? ( + + ) : null} +
+
+ + {!rewrapSupported ? ( + + {t("Not available for this backend")} + + {t("The configured KMS backend does not support rewrapping data-key envelopes.")} + + + ) : ( + <> + + + {t("Buckets")} + + setBucketsInput(event.target.value)} + autoComplete="off" + placeholder={t("Leave blank to sweep all buckets")} + spellCheck={false} + disabled={isSweepRunning || startingSweep} + /> + + + {t("Comma-separated bucket names. Leave blank to sweep all buckets.")} + + + + {t("Object Key Prefix")} + + setPrefixInput(event.target.value)} + autoComplete="off" + placeholder={t("Optional prefix such as photos/")} + spellCheck={false} + disabled={isSweepRunning || startingSweep} + /> + + {t("Only objects whose keys start with this prefix are swept.")} + + + +
+ {isSweepRunning ? ( + + ) : null} + +
+ + {statusErrorMessage ? ( + + {t("Failed to load rekey sweep status")} + {statusErrorMessage} + + ) : loadingSnapshot ? ( +
+ +
+ ) : neverRan ? ( +
+ {t("No rekey sweep has run yet")} +
+ ) : snapshot ? ( +
+
+ + {snapshot.state === "running" + ? t("Running") + : snapshot.state === "cancelled" + ? t("Sweep cancelled") + : t("Sweep completed")} + + {isSweepRunning && snapshot.current_bucket ? ( + + {t("Scanning bucket {bucket}", { bucket: snapshot.current_bucket })} + + ) : null} +
+
+
+

{t("Versions scanned")}

+

{snapshot.scanned}

+
+
+

{t("Rewrapped")}

+

{snapshot.rewrapped}

+
+
+

{t("Already current")}

+

{snapshot.already_current}

+
+
+

{t("Not applicable")}

+

{snapshot.not_applicable}

+
+
0 + ? "border border-destructive bg-destructive/10 p-3" + : "border bg-muted/40 p-3" + } + > +

0 ? "text-xs text-destructive" : "text-xs text-muted-foreground"}> + {t("Versions failed")} +

+

0 + ? "text-sm font-medium text-destructive" + : "text-sm font-medium text-foreground" + } + > + {snapshot.failed} +

+
+
+ {!isSweepRunning && snapshot.failed > 0 ? ( + + {t("Some object versions failed to rewrap")} + + {t( + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.", + )} + + + ) : null} +
+ ) : null} + + )} +
+
+ + + + + {t("Start Rekey Sweep")} + + {t( + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.", + )} + + + + {t("Cancel")} + {t("Start Rekey Sweep")} + + + + + ) +} diff --git a/hooks/use-sse.ts b/hooks/use-sse.ts index a952471e..89624fca 100644 --- a/hooks/use-sse.ts +++ b/hooks/use-sse.ts @@ -8,9 +8,12 @@ import type { KmsCreateKeyRequest, KmsCreateKeyResponse, KmsDeleteKeyOptions, + KmsDetailedStatusResponse, KmsKeyDetailResponse, KmsKeyListResponse, KmsMutationResponse, + KmsRekeyJobSnapshot, + KmsRekeyStartRequest, KmsServiceStatusResponse, KmsStartRequest, } from "@/types/kms" @@ -55,8 +58,23 @@ export function useSSE() { return (await api.post("/kms/clear-cache", {})) as KmsMutationResponse }, [api]) - const getDetailedStatus = useCallback(async () => { - return api.get("/kms/status") + const getDetailedStatus = useCallback(async (): Promise => { + return (await api.get("/kms/status")) as KmsDetailedStatusResponse + }, [api]) + + const startRekey = useCallback( + async (data: KmsRekeyStartRequest = {}): Promise => { + return (await api.post("/kms/keys/rekey", data)) as KmsRekeyJobSnapshot + }, + [api], + ) + + const getRekeyStatus = useCallback(async (): Promise => { + return (await api.get("/kms/keys/rekey/status", { dedupe: false })) as KmsRekeyJobSnapshot + }, [api]) + + const cancelRekey = useCallback(async (): Promise => { + return (await api.post("/kms/keys/rekey/cancel", {})) as KmsRekeyJobSnapshot }, [api]) const createKey = useCallback( @@ -129,6 +147,9 @@ export function useSSE() { getConfiguration, clearCache, getDetailedStatus, + startRekey, + getRekeyStatus, + cancelRekey, createKey, getKeyDetails, getKeyList, diff --git a/i18n/locales/ar-MA.json b/i18n/locales/ar-MA.json index 0bcd0d1b..829d8250 100644 --- a/i18n/locales/ar-MA.json +++ b/i18n/locales/ar-MA.json @@ -1109,7 +1109,6 @@ "Starting": "جارٍ البدء", "State": "الحالة", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "الحالة", "Status refreshed successfully": "تم تحديث الحالة بنجاح", "Stop": "إيقاف", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "لم تتبقَّ لديك رموز استرداد. أنشئ مجموعة جديدة لتتمكن من الدخول إذا فقدت تطبيق المصادقة.", "Your existing recovery codes will stop working.": "ستتوقف رموز الاسترداد الحالية عن العمل.", "Your previous recovery codes no longer work.": "رموز الاسترداد السابقة لم تعد تعمل.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "سيكون {account} محميًا بكلمة المرور وحدها، وستتوقف رموز الاسترداد عن العمل." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "سيكون {account} محميًا بكلمة المرور وحدها، وستتوقف رموز الاسترداد عن العمل.", + "Development / testing backend — not supported for production": "خلفية تطوير/اختبار — غير مدعومة للاستخدام في الإنتاج", + "Local filesystem (dev/testing only)": "نظام الملفات المحلي (للتطوير/الاختبار فقط)", + "Static single-key (built-in, dev/testing only)": "مفتاح فردي ثابت (مدمج، للتطوير/الاختبار فقط)", + "The mTLS client certificate and private key paths must be provided together.": "يجب توفير مساري شهادة عميل mTLS والمفتاح الخاص معًا.", + "Advanced TLS": "إعدادات TLS المتقدمة", + "Custom CA": "CA مخصص", + "mTLS client identity": "هوية عميل mTLS", + "Custom CA: configured": "CA مخصص: تم التكوين", + "mTLS client identity: configured": "هوية عميل mTLS: تم التكوين", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "مسارات TLS المخزنة لا تُعرض أبدًا. أعد إدخال المسارات للاحتفاظ بها؛ الحفظ مع حقول فارغة يزيل إعدادات TLS المخزنة.", + "CA Certificate Path": "مسار شهادة CA", + "PEM CA bundle trusted for the Vault connection.": "حزمة CA بصيغة PEM موثوقة لاتصال Vault.", + "Client Certificate Path": "مسار شهادة العميل", + "PEM client certificate presented to Vault for mTLS.": "شهادة عميل بصيغة PEM تُقدَّم إلى Vault من أجل mTLS.", + "Client Key Path": "مسار مفتاح العميل", + "PEM private key matching the client certificate.": "مفتاح خاص بصيغة PEM مطابق لشهادة العميل.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "تشير المسارات إلى ملفات PEM على عقدة خادم RustFS. في مجموعة متعددة العقد يجب أن يوجد المسار نفسه على كل عقدة.", + "Failed to load rekey sweep status": "فشل تحميل حالة مسح إعادة التشفير", + "Rekey sweep started": "بدأ مسح إعادة التشفير", + "A rekey sweep is already running. Showing its progress.": "مسح إعادة التشفير قيد التشغيل بالفعل. يتم عرض تقدمه.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "خلفية KMS المكوَّنة لا تدعم إعادة تغليف مظاريف مفاتيح البيانات.", + "Failed to start rekey sweep": "فشل بدء مسح إعادة التشفير", + "Rekey sweep cancellation requested": "طُلب إلغاء مسح إعادة التشفير", + "Failed to cancel rekey sweep": "فشل إلغاء مسح إعادة التشفير", + "Rekey Existing Objects": "إعادة تشفير الكائنات الموجودة", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "بعد تدوير المفتاح الرئيسي، أعد تغليف مظاريف مفاتيح البيانات للكائنات الموجودة إلى إصدار المفتاح الحالي.", + "Not available for this backend": "غير متاح لهذه الخلفية", + "Leave blank to sweep all buckets": "اتركه فارغًا لمسح جميع الحاويات", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "أسماء الحاويات مفصولة بفواصل. اتركه فارغًا لمسح جميع الحاويات.", + "Object Key Prefix": "بادئة مفتاح الكائن", + "Optional prefix such as photos/": "بادئة اختيارية مثل photos/", + "Only objects whose keys start with this prefix are swept.": "يتم مسح الكائنات التي تبدأ مفاتيحها بهذه البادئة فقط.", + "Cancel Sweep": "إلغاء المسح", + "Start Rekey Sweep": "بدء مسح إعادة التشفير", + "No rekey sweep has run yet": "لم يتم تشغيل أي مسح لإعادة التشفير بعد", + "Scanning bucket {bucket}": "جارٍ مسح الحاوية {bucket}", + "Rewrapped": "أُعيد تغليفها", + "Already current": "محدَّثة بالفعل", + "Not applicable": "غير قابل للتطبيق", + "Some object versions failed to rewrap": "فشلت إعادة تغليف بعض إصدارات الكائنات", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "المسح غير متأثر بالتكرار: شغِّله مرة أخرى لإعادة محاولة الإصدارات الفاشلة فقط. التفاصيل في سجل الخادم.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "يمسح هذا البيانات الوصفية لكل إصدار كائن محدد ويُصدر استدعاءات KMS لإعادة تغليف المظاريف القديمة. قد يستغرق ذلك وقتًا طويلًا في الحاويات الكبيرة.", + "Sweep completed": "اكتمل المسح", + "Sweep cancelled": "أُلغي المسح", + "Versions scanned": "الإصدارات الممسوحة", + "Versions failed": "الإصدارات الفاشلة" } diff --git a/i18n/locales/de-DE.json b/i18n/locales/de-DE.json index 65f03d14..5bd1fd72 100644 --- a/i18n/locales/de-DE.json +++ b/i18n/locales/de-DE.json @@ -1109,7 +1109,6 @@ "Starting": "Wird gestartet", "State": "Zustand", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Status", "Status refreshed successfully": "Status erfolgreich aktualisiert", "Stop": "Stopp", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Sie haben keine Wiederherstellungscodes mehr. Erzeugen Sie einen neuen Satz, um wieder hineinzukommen, wenn Sie Ihren Authenticator verlieren.", "Your existing recovery codes will stop working.": "Ihre bestehenden Wiederherstellungscodes funktionieren dann nicht mehr.", "Your previous recovery codes no longer work.": "Ihre vorherigen Wiederherstellungscodes funktionieren nicht mehr.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} wird dann nur noch durch das Passwort geschützt, und die Wiederherstellungscodes funktionieren nicht mehr." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} wird dann nur noch durch das Passwort geschützt, und die Wiederherstellungscodes funktionieren nicht mehr.", + "Development / testing backend — not supported for production": "Entwicklungs-/Test-Backend — nicht für den Produktionseinsatz unterstützt", + "Local filesystem (dev/testing only)": "Lokales Dateisystem (nur Entwicklung/Test)", + "Static single-key (built-in, dev/testing only)": "Statischer Einzelschlüssel (integriert, nur Entwicklung/Test)", + "The mTLS client certificate and private key paths must be provided together.": "Die Pfade für das mTLS-Client-Zertifikat und den privaten Schlüssel müssen zusammen angegeben werden.", + "Advanced TLS": "Erweiterte TLS-Einstellungen", + "Custom CA": "Benutzerdefinierte CA", + "mTLS client identity": "mTLS-Client-Identität", + "Custom CA: configured": "Benutzerdefinierte CA: konfiguriert", + "mTLS client identity: configured": "mTLS-Client-Identität: konfiguriert", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Gespeicherte TLS-Pfade werden nie angezeigt. Geben Sie die Pfade erneut ein, um sie zu behalten; das Speichern mit leeren Feldern entfernt die gespeicherten TLS-Einstellungen.", + "CA Certificate Path": "CA-Zertifikatspfad", + "PEM CA bundle trusted for the Vault connection.": "PEM-CA-Bundle, dem für die Vault-Verbindung vertraut wird.", + "Client Certificate Path": "Client-Zertifikatspfad", + "PEM client certificate presented to Vault for mTLS.": "PEM-Client-Zertifikat, das Vault für mTLS vorgelegt wird.", + "Client Key Path": "Client-Schlüsselpfad", + "PEM private key matching the client certificate.": "Privater PEM-Schlüssel, der zum Client-Zertifikat passt.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Die Pfade verweisen auf PEM-Dateien auf dem RustFS-Serverknoten. In einem Cluster mit mehreren Knoten muss derselbe Pfad auf jedem Knoten vorhanden sein.", + "Failed to load rekey sweep status": "Status des Rekey-Durchlaufs konnte nicht geladen werden", + "Rekey sweep started": "Rekey-Durchlauf gestartet", + "A rekey sweep is already running. Showing its progress.": "Ein Rekey-Durchlauf läuft bereits. Sein Fortschritt wird angezeigt.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Das konfigurierte KMS-Backend unterstützt das erneute Umhüllen von Datenschlüssel-Envelopes nicht.", + "Failed to start rekey sweep": "Rekey-Durchlauf konnte nicht gestartet werden", + "Rekey sweep cancellation requested": "Abbruch des Rekey-Durchlaufs angefordert", + "Failed to cancel rekey sweep": "Rekey-Durchlauf konnte nicht abgebrochen werden", + "Rekey Existing Objects": "Vorhandene Objekte neu verschlüsseln", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Nach der Rotation eines Master-Schlüssels die Datenschlüssel-Envelopes vorhandener Objekte auf die aktuelle Schlüsselversion umhüllen.", + "Not available for this backend": "Für dieses Backend nicht verfügbar", + "Leave blank to sweep all buckets": "Leer lassen, um alle Buckets zu durchlaufen", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Durch Kommas getrennte Bucket-Namen. Leer lassen, um alle Buckets zu durchlaufen.", + "Object Key Prefix": "Objektschlüssel-Präfix", + "Optional prefix such as photos/": "Optionales Präfix wie photos/", + "Only objects whose keys start with this prefix are swept.": "Nur Objekte, deren Schlüssel mit diesem Präfix beginnen, werden durchlaufen.", + "Cancel Sweep": "Durchlauf abbrechen", + "Start Rekey Sweep": "Rekey-Durchlauf starten", + "No rekey sweep has run yet": "Es wurde noch kein Rekey-Durchlauf ausgeführt", + "Scanning bucket {bucket}": "Bucket {bucket} wird durchsucht", + "Rewrapped": "Neu umhüllt", + "Already current": "Bereits aktuell", + "Not applicable": "Nicht anwendbar", + "Some object versions failed to rewrap": "Einige Objektversionen konnten nicht neu umhüllt werden", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Der Durchlauf ist idempotent: Führen Sie ihn erneut aus, um nur die fehlgeschlagenen Versionen zu wiederholen. Details stehen im Serverprotokoll.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Dabei werden die Metadaten jeder ausgewählten Objektversion durchsucht und KMS-Aufrufe ausgeführt, um veraltete Envelopes neu zu umhüllen. Bei großen Buckets kann dies lange dauern.", + "Sweep completed": "Durchlauf abgeschlossen", + "Sweep cancelled": "Durchlauf abgebrochen", + "Versions scanned": "Durchsuchte Versionen", + "Versions failed": "Fehlgeschlagene Versionen" } diff --git a/i18n/locales/en-US.json b/i18n/locales/en-US.json index a219004a..13821909 100644 --- a/i18n/locales/en-US.json +++ b/i18n/locales/en-US.json @@ -1109,7 +1109,6 @@ "Starting": "Starting", "State": "State", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Status", "Status refreshed successfully": "Status refreshed successfully", "Stop": "Stop", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.", "Your existing recovery codes will stop working.": "Your existing recovery codes will stop working.", "Your previous recovery codes no longer work.": "Your previous recovery codes no longer work.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} will be protected by its password alone, and the recovery codes will stop working." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} will be protected by its password alone, and the recovery codes will stop working.", + "Development / testing backend — not supported for production": "Development / testing backend — not supported for production", + "Local filesystem (dev/testing only)": "Local filesystem (dev/testing only)", + "Static single-key (built-in, dev/testing only)": "Static single-key (built-in, dev/testing only)", + "The mTLS client certificate and private key paths must be provided together.": "The mTLS client certificate and private key paths must be provided together.", + "Advanced TLS": "Advanced TLS", + "Custom CA": "Custom CA", + "mTLS client identity": "mTLS client identity", + "Custom CA: configured": "Custom CA: configured", + "mTLS client identity: configured": "mTLS client identity: configured", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.", + "CA Certificate Path": "CA Certificate Path", + "PEM CA bundle trusted for the Vault connection.": "PEM CA bundle trusted for the Vault connection.", + "Client Certificate Path": "Client Certificate Path", + "PEM client certificate presented to Vault for mTLS.": "PEM client certificate presented to Vault for mTLS.", + "Client Key Path": "Client Key Path", + "PEM private key matching the client certificate.": "PEM private key matching the client certificate.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.", + "Failed to load rekey sweep status": "Failed to load rekey sweep status", + "Rekey sweep started": "Rekey sweep started", + "A rekey sweep is already running. Showing its progress.": "A rekey sweep is already running. Showing its progress.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "The configured KMS backend does not support rewrapping data-key envelopes.", + "Failed to start rekey sweep": "Failed to start rekey sweep", + "Rekey sweep cancellation requested": "Rekey sweep cancellation requested", + "Failed to cancel rekey sweep": "Failed to cancel rekey sweep", + "Rekey Existing Objects": "Rekey Existing Objects", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.", + "Not available for this backend": "Not available for this backend", + "Leave blank to sweep all buckets": "Leave blank to sweep all buckets", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Comma-separated bucket names. Leave blank to sweep all buckets.", + "Object Key Prefix": "Object Key Prefix", + "Optional prefix such as photos/": "Optional prefix such as photos/", + "Only objects whose keys start with this prefix are swept.": "Only objects whose keys start with this prefix are swept.", + "Cancel Sweep": "Cancel Sweep", + "Start Rekey Sweep": "Start Rekey Sweep", + "No rekey sweep has run yet": "No rekey sweep has run yet", + "Scanning bucket {bucket}": "Scanning bucket {bucket}", + "Rewrapped": "Rewrapped", + "Already current": "Already current", + "Not applicable": "Not applicable", + "Some object versions failed to rewrap": "Some object versions failed to rewrap", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.", + "Sweep completed": "Sweep completed", + "Sweep cancelled": "Sweep cancelled", + "Versions scanned": "Versions scanned", + "Versions failed": "Versions failed" } diff --git a/i18n/locales/es-ES.json b/i18n/locales/es-ES.json index c94f164b..61aeed44 100644 --- a/i18n/locales/es-ES.json +++ b/i18n/locales/es-ES.json @@ -1109,7 +1109,6 @@ "Starting": "Iniciando", "State": "Estado", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Estado", "Status refreshed successfully": "Estado actualizado exitosamente", "Stop": "Detener", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "No te quedan códigos de recuperación. Genera un conjunto nuevo para poder volver a entrar si pierdes tu aplicación de autenticación.", "Your existing recovery codes will stop working.": "Tus códigos de recuperación actuales dejarán de funcionar.", "Your previous recovery codes no longer work.": "Tus códigos de recuperación anteriores ya no funcionan.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} quedará protegida solo por su contraseña y los códigos de recuperación dejarán de funcionar." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} quedará protegida solo por su contraseña y los códigos de recuperación dejarán de funcionar.", + "Development / testing backend — not supported for production": "Backend de desarrollo/pruebas — no compatible con producción", + "Local filesystem (dev/testing only)": "Sistema de archivos local (solo desarrollo/pruebas)", + "Static single-key (built-in, dev/testing only)": "Clave única estática (integrada, solo desarrollo/pruebas)", + "The mTLS client certificate and private key paths must be provided together.": "Las rutas del certificado de cliente mTLS y de la clave privada deben proporcionarse juntas.", + "Advanced TLS": "TLS avanzado", + "Custom CA": "CA personalizada", + "mTLS client identity": "Identidad de cliente mTLS", + "Custom CA: configured": "CA personalizada: configurada", + "mTLS client identity: configured": "Identidad de cliente mTLS: configurada", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Las rutas TLS almacenadas nunca se muestran. Vuelva a introducir las rutas para conservarlas; guardar con campos vacíos elimina la configuración TLS almacenada.", + "CA Certificate Path": "Ruta del certificado CA", + "PEM CA bundle trusted for the Vault connection.": "Paquete CA en formato PEM de confianza para la conexión con Vault.", + "Client Certificate Path": "Ruta del certificado de cliente", + "PEM client certificate presented to Vault for mTLS.": "Certificado de cliente en formato PEM presentado a Vault para mTLS.", + "Client Key Path": "Ruta de la clave de cliente", + "PEM private key matching the client certificate.": "Clave privada en formato PEM que coincide con el certificado de cliente.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Las rutas se refieren a archivos PEM en el nodo del servidor RustFS. En un clúster de varios nodos, la misma ruta debe existir en cada nodo.", + "Failed to load rekey sweep status": "Error al cargar el estado del barrido de recifrado", + "Rekey sweep started": "Barrido de recifrado iniciado", + "A rekey sweep is already running. Showing its progress.": "Ya hay un barrido de recifrado en ejecución. Mostrando su progreso.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "El backend KMS configurado no admite el reenvolvido de sobres de claves de datos.", + "Failed to start rekey sweep": "Error al iniciar el barrido de recifrado", + "Rekey sweep cancellation requested": "Cancelación del barrido de recifrado solicitada", + "Failed to cancel rekey sweep": "Error al cancelar el barrido de recifrado", + "Rekey Existing Objects": "Recifrar objetos existentes", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Después de rotar una clave maestra, reenvuelva los sobres de claves de datos de los objetos existentes a la versión de clave actual.", + "Not available for this backend": "No disponible para este backend", + "Leave blank to sweep all buckets": "Dejar en blanco para barrer todos los cubos", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Nombres de cubos separados por comas. Dejar en blanco para barrer todos los cubos.", + "Object Key Prefix": "Prefijo de clave de objeto", + "Optional prefix such as photos/": "Prefijo opcional como photos/", + "Only objects whose keys start with this prefix are swept.": "Solo se barren los objetos cuyas claves comienzan con este prefijo.", + "Cancel Sweep": "Cancelar barrido", + "Start Rekey Sweep": "Iniciar barrido de recifrado", + "No rekey sweep has run yet": "Aún no se ha ejecutado ningún barrido de recifrado", + "Scanning bucket {bucket}": "Barriendo el cubo {bucket}", + "Rewrapped": "Reenvueltos", + "Already current": "Ya actualizados", + "Not applicable": "No aplicable", + "Some object versions failed to rewrap": "Algunas versiones de objetos no se pudieron reenvolver", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "El barrido es idempotente: ejecútelo de nuevo para reintentar solo las versiones fallidas. Los detalles están en el registro del servidor.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Esto escanea los metadatos de cada versión de objeto seleccionada y emite llamadas KMS para reenvolver los sobres obsoletos. En cubos grandes puede tardar mucho tiempo.", + "Sweep completed": "Barrido completado", + "Sweep cancelled": "Barrido cancelado", + "Versions scanned": "Versiones barridas", + "Versions failed": "Versiones fallidas" } diff --git a/i18n/locales/fr-FR.json b/i18n/locales/fr-FR.json index 117eca61..fa6ef677 100644 --- a/i18n/locales/fr-FR.json +++ b/i18n/locales/fr-FR.json @@ -1109,7 +1109,6 @@ "Starting": "Démarrage", "State": "État", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Statut", "Status refreshed successfully": "Statut actualisé avec succès", "Stop": "Arrêter", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Vous n'avez plus de codes de récupération. Générez-en un nouveau jeu pour pouvoir revenir si vous perdez votre application d'authentification.", "Your existing recovery codes will stop working.": "Vos codes de récupération actuels cesseront de fonctionner.", "Your previous recovery codes no longer work.": "Vos anciens codes de récupération ne fonctionnent plus.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} ne sera plus protégé que par son mot de passe, et les codes de récupération cesseront de fonctionner." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} ne sera plus protégé que par son mot de passe, et les codes de récupération cesseront de fonctionner.", + "Development / testing backend — not supported for production": "Backend de développement/test — non pris en charge en production", + "Local filesystem (dev/testing only)": "Système de fichiers local (développement/test uniquement)", + "Static single-key (built-in, dev/testing only)": "Clé unique statique (intégrée, développement/test uniquement)", + "The mTLS client certificate and private key paths must be provided together.": "Les chemins du certificat client mTLS et de la clé privée doivent être fournis ensemble.", + "Advanced TLS": "TLS avancé", + "Custom CA": "CA personnalisée", + "mTLS client identity": "Identité client mTLS", + "Custom CA: configured": "CA personnalisée : configurée", + "mTLS client identity: configured": "Identité client mTLS : configurée", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Les chemins TLS enregistrés ne sont jamais affichés. Saisissez à nouveau les chemins pour les conserver ; enregistrer avec des champs vides supprime les paramètres TLS enregistrés.", + "CA Certificate Path": "Chemin du certificat CA", + "PEM CA bundle trusted for the Vault connection.": "Bundle CA au format PEM approuvé pour la connexion Vault.", + "Client Certificate Path": "Chemin du certificat client", + "PEM client certificate presented to Vault for mTLS.": "Certificat client au format PEM présenté à Vault pour mTLS.", + "Client Key Path": "Chemin de la clé client", + "PEM private key matching the client certificate.": "Clé privée au format PEM correspondant au certificat client.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Les chemins désignent des fichiers PEM sur le nœud du serveur RustFS. Dans un cluster multi-nœuds, le même chemin doit exister sur chaque nœud.", + "Failed to load rekey sweep status": "Échec du chargement du statut du balayage de rechiffrement", + "Rekey sweep started": "Balayage de rechiffrement démarré", + "A rekey sweep is already running. Showing its progress.": "Un balayage de rechiffrement est déjà en cours. Affichage de sa progression.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Le backend KMS configuré ne prend pas en charge le rechiffrement des enveloppes de clés de données.", + "Failed to start rekey sweep": "Échec du démarrage du balayage de rechiffrement", + "Rekey sweep cancellation requested": "Annulation du balayage de rechiffrement demandée", + "Failed to cancel rekey sweep": "Échec de l'annulation du balayage de rechiffrement", + "Rekey Existing Objects": "Rechiffrer les objets existants", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Après la rotation d'une clé maîtresse, rechiffrez les enveloppes de clés de données des objets existants vers la version de clé actuelle.", + "Not available for this backend": "Non disponible pour ce backend", + "Leave blank to sweep all buckets": "Laisser vide pour balayer tous les compartiments", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Noms de compartiments séparés par des virgules. Laisser vide pour balayer tous les compartiments.", + "Object Key Prefix": "Préfixe de clé d'objet", + "Optional prefix such as photos/": "Préfixe facultatif tel que photos/", + "Only objects whose keys start with this prefix are swept.": "Seuls les objets dont les clés commencent par ce préfixe sont balayés.", + "Cancel Sweep": "Annuler le balayage", + "Start Rekey Sweep": "Démarrer le balayage de rechiffrement", + "No rekey sweep has run yet": "Aucun balayage de rechiffrement n'a encore été exécuté", + "Scanning bucket {bucket}": "Balayage du compartiment {bucket}", + "Rewrapped": "Rechiffrés", + "Already current": "Déjà à jour", + "Not applicable": "Non applicable", + "Some object versions failed to rewrap": "Le rechiffrement de certaines versions d'objets a échoué", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Le balayage est idempotent : relancez-le pour ne réessayer que les versions en échec. Les détails figurent dans le journal du serveur.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Cette opération analyse les métadonnées de chaque version d'objet sélectionnée et émet des appels KMS pour rechiffrer les enveloppes obsolètes. Sur de grands compartiments, cela peut prendre beaucoup de temps.", + "Sweep completed": "Balayage terminé", + "Sweep cancelled": "Balayage annulé", + "Versions scanned": "Versions balayées", + "Versions failed": "Versions en échec" } diff --git a/i18n/locales/id-ID.json b/i18n/locales/id-ID.json index 3d56791a..6d1e076e 100644 --- a/i18n/locales/id-ID.json +++ b/i18n/locales/id-ID.json @@ -1109,7 +1109,6 @@ "Starting": "Memulai", "State": "Status", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Status", "Status refreshed successfully": "Status berhasil diperbarui", "Stop": "Hentikan", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Kode pemulihan Anda sudah habis. Buat set baru agar Anda tetap bisa masuk jika kehilangan autentikator.", "Your existing recovery codes will stop working.": "Kode pemulihan Anda yang ada akan berhenti berfungsi.", "Your previous recovery codes no longer work.": "Kode pemulihan Anda sebelumnya tidak berfungsi lagi.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} hanya akan dilindungi oleh kata sandinya, dan kode pemulihan akan berhenti berfungsi." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} hanya akan dilindungi oleh kata sandinya, dan kode pemulihan akan berhenti berfungsi.", + "Development / testing backend — not supported for production": "Backend pengembangan/pengujian — tidak didukung untuk produksi", + "Local filesystem (dev/testing only)": "Sistem berkas lokal (hanya pengembangan/pengujian)", + "Static single-key (built-in, dev/testing only)": "Kunci tunggal statis (bawaan, hanya pengembangan/pengujian)", + "The mTLS client certificate and private key paths must be provided together.": "Jalur sertifikat klien mTLS dan kunci privat harus diisi bersamaan.", + "Advanced TLS": "TLS Lanjutan", + "Custom CA": "CA Kustom", + "mTLS client identity": "Identitas klien mTLS", + "Custom CA: configured": "CA Kustom: dikonfigurasi", + "mTLS client identity: configured": "Identitas klien mTLS: dikonfigurasi", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Jalur TLS yang tersimpan tidak pernah ditampilkan. Masukkan kembali jalur untuk mempertahankannya; menyimpan dengan bidang kosong akan menghapus pengaturan TLS yang tersimpan.", + "CA Certificate Path": "Jalur Sertifikat CA", + "PEM CA bundle trusted for the Vault connection.": "Bundel CA berformat PEM yang dipercaya untuk koneksi Vault.", + "Client Certificate Path": "Jalur Sertifikat Klien", + "PEM client certificate presented to Vault for mTLS.": "Sertifikat klien berformat PEM yang disajikan ke Vault untuk mTLS.", + "Client Key Path": "Jalur Kunci Klien", + "PEM private key matching the client certificate.": "Kunci privat berformat PEM yang cocok dengan sertifikat klien.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Jalur merujuk ke berkas PEM pada node server RustFS. Dalam klaster multi-node, jalur yang sama harus ada di setiap node.", + "Failed to load rekey sweep status": "Gagal memuat status penyapuan rekey", + "Rekey sweep started": "Penyapuan rekey dimulai", + "A rekey sweep is already running. Showing its progress.": "Penyapuan rekey sudah berjalan. Menampilkan progresnya.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Backend KMS yang dikonfigurasi tidak mendukung pembungkusan ulang amplop kunci data.", + "Failed to start rekey sweep": "Gagal memulai penyapuan rekey", + "Rekey sweep cancellation requested": "Pembatalan penyapuan rekey diminta", + "Failed to cancel rekey sweep": "Gagal membatalkan penyapuan rekey", + "Rekey Existing Objects": "Rekey Objek yang Ada", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Setelah merotasi kunci utama, bungkus ulang amplop kunci data objek yang ada ke versi kunci saat ini.", + "Not available for this backend": "Tidak tersedia untuk backend ini", + "Leave blank to sweep all buckets": "Biarkan kosong untuk menyapu semua bucket", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Nama bucket dipisahkan koma. Biarkan kosong untuk menyapu semua bucket.", + "Object Key Prefix": "Prefiks Kunci Objek", + "Optional prefix such as photos/": "Prefiks opsional seperti photos/", + "Only objects whose keys start with this prefix are swept.": "Hanya objek yang kuncinya diawali prefiks ini yang disapu.", + "Cancel Sweep": "Batalkan Penyapuan", + "Start Rekey Sweep": "Mulai Penyapuan Rekey", + "No rekey sweep has run yet": "Belum ada penyapuan rekey yang dijalankan", + "Scanning bucket {bucket}": "Memindai bucket {bucket}", + "Rewrapped": "Dibungkus ulang", + "Already current": "Sudah terkini", + "Not applicable": "Tidak berlaku", + "Some object versions failed to rewrap": "Beberapa versi objek gagal dibungkus ulang", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Penyapuan ini idempoten: jalankan lagi untuk mencoba ulang hanya versi yang gagal. Detail ada di log server.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Ini memindai metadata setiap versi objek yang dipilih dan mengeluarkan panggilan KMS untuk membungkus ulang amplop yang kedaluwarsa. Pada bucket besar ini bisa memakan waktu lama.", + "Sweep completed": "Penyapuan selesai", + "Sweep cancelled": "Penyapuan dibatalkan", + "Versions scanned": "Versi dipindai", + "Versions failed": "Versi gagal" } diff --git a/i18n/locales/it-IT.json b/i18n/locales/it-IT.json index bf9c2f95..5a6ec1e6 100644 --- a/i18n/locales/it-IT.json +++ b/i18n/locales/it-IT.json @@ -1109,7 +1109,6 @@ "Starting": "Avvio in corso", "State": "Stato", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Stato", "Status refreshed successfully": "Stato aggiornato con successo", "Stop": "Ferma", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Non hai più codici di recupero. Generane un nuovo set per poter rientrare se perdi la tua app di autenticazione.", "Your existing recovery codes will stop working.": "I tuoi codici di recupero attuali smetteranno di funzionare.", "Your previous recovery codes no longer work.": "I tuoi codici di recupero precedenti non funzionano più.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} sarà protetta solo dalla password e i codici di recupero smetteranno di funzionare." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} sarà protetta solo dalla password e i codici di recupero smetteranno di funzionare.", + "Development / testing backend — not supported for production": "Backend di sviluppo/test — non supportato in produzione", + "Local filesystem (dev/testing only)": "File system locale (solo sviluppo/test)", + "Static single-key (built-in, dev/testing only)": "Chiave singola statica (integrata, solo sviluppo/test)", + "The mTLS client certificate and private key paths must be provided together.": "I percorsi del certificato client mTLS e della chiave privata devono essere forniti insieme.", + "Advanced TLS": "TLS avanzato", + "Custom CA": "CA personalizzata", + "mTLS client identity": "Identità client mTLS", + "Custom CA: configured": "CA personalizzata: configurata", + "mTLS client identity: configured": "Identità client mTLS: configurata", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "I percorsi TLS memorizzati non vengono mai visualizzati. Reinserire i percorsi per mantenerli; salvare con i campi vuoti rimuove le impostazioni TLS memorizzate.", + "CA Certificate Path": "Percorso del certificato CA", + "PEM CA bundle trusted for the Vault connection.": "Bundle CA in formato PEM considerato attendibile per la connessione a Vault.", + "Client Certificate Path": "Percorso del certificato client", + "PEM client certificate presented to Vault for mTLS.": "Certificato client in formato PEM presentato a Vault per mTLS.", + "Client Key Path": "Percorso della chiave client", + "PEM private key matching the client certificate.": "Chiave privata in formato PEM corrispondente al certificato client.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "I percorsi si riferiscono a file PEM sul nodo del server RustFS. In un cluster multi-nodo lo stesso percorso deve esistere su ogni nodo.", + "Failed to load rekey sweep status": "Impossibile caricare lo stato della scansione di rekey", + "Rekey sweep started": "Scansione di rekey avviata", + "A rekey sweep is already running. Showing its progress.": "Una scansione di rekey è già in esecuzione. Ne viene mostrato l'avanzamento.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Il backend KMS configurato non supporta il re-wrapping degli envelope delle chiavi dati.", + "Failed to start rekey sweep": "Impossibile avviare la scansione di rekey", + "Rekey sweep cancellation requested": "Richiesta di annullamento della scansione di rekey inviata", + "Failed to cancel rekey sweep": "Impossibile annullare la scansione di rekey", + "Rekey Existing Objects": "Rekey degli oggetti esistenti", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Dopo la rotazione di una chiave master, esegui il re-wrapping degli envelope delle chiavi dati degli oggetti esistenti alla versione corrente della chiave.", + "Not available for this backend": "Non disponibile per questo backend", + "Leave blank to sweep all buckets": "Lasciare vuoto per scansionare tutti i bucket", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Nomi di bucket separati da virgole. Lasciare vuoto per scansionare tutti i bucket.", + "Object Key Prefix": "Prefisso della chiave oggetto", + "Optional prefix such as photos/": "Prefisso facoltativo come photos/", + "Only objects whose keys start with this prefix are swept.": "Vengono scansionati solo gli oggetti le cui chiavi iniziano con questo prefisso.", + "Cancel Sweep": "Annulla scansione", + "Start Rekey Sweep": "Avvia scansione di rekey", + "No rekey sweep has run yet": "Nessuna scansione di rekey è stata ancora eseguita", + "Scanning bucket {bucket}": "Scansione del bucket {bucket} in corso", + "Rewrapped": "Ri-wrappati", + "Already current": "Già aggiornati", + "Not applicable": "Non applicabile", + "Some object versions failed to rewrap": "Il re-wrapping di alcune versioni degli oggetti non è riuscito", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "La scansione è idempotente: eseguila di nuovo per ritentare solo le versioni non riuscite. I dettagli sono nel log del server.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Questa operazione scansiona i metadati di ogni versione di oggetto selezionata ed emette chiamate KMS per ri-wrappare gli envelope obsoleti. Su bucket di grandi dimensioni può richiedere molto tempo.", + "Sweep completed": "Scansione completata", + "Sweep cancelled": "Scansione annullata", + "Versions scanned": "Versioni scansionate", + "Versions failed": "Versioni non riuscite" } diff --git a/i18n/locales/ja-JP.json b/i18n/locales/ja-JP.json index 0b391f72..e6796f3d 100644 --- a/i18n/locales/ja-JP.json +++ b/i18n/locales/ja-JP.json @@ -1109,7 +1109,6 @@ "Starting": "開始中", "State": "状態", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "ステータス", "Status refreshed successfully": "ステータスが正常に更新されました", "Stop": "停止", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "リカバリコードが残っていません。認証アプリを失っても復帰できるよう、新しく生成してください。", "Your existing recovery codes will stop working.": "現在のリカバリコードは使えなくなります。", "Your previous recovery codes no longer work.": "以前のリカバリコードは使用できなくなりました。", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} はパスワードのみで保護され、リカバリコードは使えなくなります。" + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} はパスワードのみで保護され、リカバリコードは使えなくなります。", + "Development / testing backend — not supported for production": "開発/テスト用バックエンド — 本番環境ではサポートされません", + "Local filesystem (dev/testing only)": "ローカルファイルシステム(開発/テスト専用)", + "Static single-key (built-in, dev/testing only)": "静的シングルキー(組み込み、開発/テスト専用)", + "The mTLS client certificate and private key paths must be provided together.": "mTLSクライアント証明書と秘密鍵のパスは同時に指定する必要があります。", + "Advanced TLS": "高度なTLS設定", + "Custom CA": "カスタムCA", + "mTLS client identity": "mTLSクライアントアイデンティティ", + "Custom CA: configured": "カスタムCA:設定済み", + "mTLS client identity: configured": "mTLSクライアントアイデンティティ:設定済み", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "保存されたTLSパスは表示されません。保持するにはパスを再入力してください。空欄のまま保存すると保存済みのTLS設定は削除されます。", + "CA Certificate Path": "CA証明書パス", + "PEM CA bundle trusted for the Vault connection.": "Vault接続で信頼されるPEM形式のCAバンドル。", + "Client Certificate Path": "クライアント証明書パス", + "PEM client certificate presented to Vault for mTLS.": "mTLSのためにVaultに提示されるPEM形式のクライアント証明書。", + "Client Key Path": "クライアント秘密鍵パス", + "PEM private key matching the client certificate.": "クライアント証明書に対応するPEM形式の秘密鍵。", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "パスはRustFSサーバーノード上のPEMファイルを指します。マルチノードクラスタでは、すべてのノードに同じパスが存在する必要があります。", + "Failed to load rekey sweep status": "リキースイープステータスの読み込みに失敗しました", + "Rekey sweep started": "リキースイープを開始しました", + "A rekey sweep is already running. Showing its progress.": "リキースイープはすでに実行中です。その進行状況を表示しています。", + "The configured KMS backend does not support rewrapping data-key envelopes.": "設定されているKMSバックエンドはデータキーエンベロープの再ラップをサポートしていません。", + "Failed to start rekey sweep": "リキースイープの開始に失敗しました", + "Rekey sweep cancellation requested": "リキースイープのキャンセルを要求しました", + "Failed to cancel rekey sweep": "リキースイープのキャンセルに失敗しました", + "Rekey Existing Objects": "既存オブジェクトのリキー", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "マスターキーのローテーション後、既存オブジェクトのデータキーエンベロープを現在のキーバージョンに再ラップします。", + "Not available for this backend": "このバックエンドでは利用できません", + "Leave blank to sweep all buckets": "空欄にするとすべてのバケットをスイープします", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "カンマ区切りのバケット名。空欄にするとすべてのバケットをスイープします。", + "Object Key Prefix": "オブジェクトキープレフィックス", + "Optional prefix such as photos/": "photos/ などのオプションのプレフィックス", + "Only objects whose keys start with this prefix are swept.": "キーがこのプレフィックスで始まるオブジェクトのみがスイープされます。", + "Cancel Sweep": "スイープをキャンセル", + "Start Rekey Sweep": "リキースイープを開始", + "No rekey sweep has run yet": "リキースイープはまだ実行されていません", + "Scanning bucket {bucket}": "バケット {bucket} をスキャン中", + "Rewrapped": "再ラップ済み", + "Already current": "最新の状態", + "Not applicable": "対象外", + "Some object versions failed to rewrap": "一部のオブジェクトバージョンの再ラップに失敗しました", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "スイープは冪等です。再度実行すると失敗したバージョンのみが再試行されます。詳細はサーバーログを参照してください。", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "選択したすべてのオブジェクトバージョンのメタデータをスキャンし、古いエンベロープを再ラップするためにKMS呼び出しを発行します。大きなバケットでは長時間かかる場合があります。", + "Sweep completed": "スイープが完了しました", + "Sweep cancelled": "スイープがキャンセルされました", + "Versions scanned": "スキャン済みバージョン", + "Versions failed": "失敗したバージョン" } diff --git a/i18n/locales/ko-KR.json b/i18n/locales/ko-KR.json index a09f4e11..dc006ad7 100644 --- a/i18n/locales/ko-KR.json +++ b/i18n/locales/ko-KR.json @@ -1109,7 +1109,6 @@ "Starting": "시작 중", "State": "상태", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "상태", "Status refreshed successfully": "상태가 성공적으로 새로고침됨", "Stop": "중지", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "남은 복구 코드가 없습니다. 인증 앱을 잃어버려도 로그인할 수 있도록 새로 생성하세요.", "Your existing recovery codes will stop working.": "기존 복구 코드는 더 이상 작동하지 않습니다.", "Your previous recovery codes no longer work.": "이전 복구 코드는 더 이상 작동하지 않습니다.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account}은(는) 비밀번호만으로 보호되며 복구 코드는 작동하지 않습니다." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account}은(는) 비밀번호만으로 보호되며 복구 코드는 작동하지 않습니다.", + "Development / testing backend — not supported for production": "개발/테스트 백엔드 — 프로덕션 환경은 지원되지 않습니다", + "Local filesystem (dev/testing only)": "로컬 파일 시스템 (개발/테스트 전용)", + "Static single-key (built-in, dev/testing only)": "정적 단일 키 (내장, 개발/테스트 전용)", + "The mTLS client certificate and private key paths must be provided together.": "mTLS 클라이언트 인증서와 개인 키 경로는 함께 제공해야 합니다.", + "Advanced TLS": "고급 TLS 설정", + "Custom CA": "사용자 지정 CA", + "mTLS client identity": "mTLS 클라이언트 ID", + "Custom CA: configured": "사용자 지정 CA: 구성됨", + "mTLS client identity: configured": "mTLS 클라이언트 ID: 구성됨", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "저장된 TLS 경로는 표시되지 않습니다. 유지하려면 경로를 다시 입력하세요. 빈 상태로 저장하면 저장된 TLS 설정이 제거됩니다.", + "CA Certificate Path": "CA 인증서 경로", + "PEM CA bundle trusted for the Vault connection.": "Vault 연결에서 신뢰하는 PEM 형식 CA 번들입니다.", + "Client Certificate Path": "클라이언트 인증서 경로", + "PEM client certificate presented to Vault for mTLS.": "mTLS를 위해 Vault에 제시되는 PEM 형식 클라이언트 인증서입니다.", + "Client Key Path": "클라이언트 키 경로", + "PEM private key matching the client certificate.": "클라이언트 인증서와 일치하는 PEM 형식 개인 키입니다.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "경로는 RustFS 서버 노드의 PEM 파일을 가리킵니다. 다중 노드 클러스터에서는 모든 노드에 동일한 경로가 있어야 합니다.", + "Failed to load rekey sweep status": "리키 스윕 상태 로드 실패", + "Rekey sweep started": "리키 스윕이 시작되었습니다", + "A rekey sweep is already running. Showing its progress.": "리키 스윕이 이미 실행 중입니다. 해당 진행 상황을 표시합니다.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "구성된 KMS 백엔드는 데이터 키 봉투 재래핑을 지원하지 않습니다.", + "Failed to start rekey sweep": "리키 스윕 시작 실패", + "Rekey sweep cancellation requested": "리키 스윕 취소가 요청되었습니다", + "Failed to cancel rekey sweep": "리키 스윕 취소 실패", + "Rekey Existing Objects": "기존 객체 리키", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "마스터 키 교체 후 기존 객체의 데이터 키 봉투를 현재 키 버전으로 재래핑합니다.", + "Not available for this backend": "이 백엔드에서는 사용할 수 없습니다", + "Leave blank to sweep all buckets": "비워 두면 모든 버킷을 스윕합니다", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "쉼표로 구분된 버킷 이름입니다. 비워 두면 모든 버킷을 스윕합니다.", + "Object Key Prefix": "객체 키 접두사", + "Optional prefix such as photos/": "photos/ 와 같은 선택적 접두사", + "Only objects whose keys start with this prefix are swept.": "키가 이 접두사로 시작하는 객체만 스윕됩니다.", + "Cancel Sweep": "스윕 취소", + "Start Rekey Sweep": "리키 스윕 시작", + "No rekey sweep has run yet": "아직 실행된 리키 스윕이 없습니다", + "Scanning bucket {bucket}": "버킷 {bucket} 스캔 중", + "Rewrapped": "재래핑됨", + "Already current": "이미 최신 상태", + "Not applicable": "해당 없음", + "Some object versions failed to rewrap": "일부 객체 버전의 재래핑에 실패했습니다", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "이 스윕은 멱등입니다. 다시 실행하면 실패한 버전만 재시도됩니다. 자세한 내용은 서버 로그를 확인하세요.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "선택한 모든 객체 버전의 메타데이터를 스캔하고 오래된 봉투를 재래핑하기 위해 KMS 호출을 실행합니다. 큰 버킷에서는 오래 걸릴 수 있습니다.", + "Sweep completed": "스윕 완료됨", + "Sweep cancelled": "스윕 취소됨", + "Versions scanned": "스캔된 버전", + "Versions failed": "실패한 버전" } diff --git a/i18n/locales/pt-BR.json b/i18n/locales/pt-BR.json index 4087c9c4..d249f0e0 100644 --- a/i18n/locales/pt-BR.json +++ b/i18n/locales/pt-BR.json @@ -1109,7 +1109,6 @@ "Starting": "Iniciando", "State": "Estado", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Status", "Status refreshed successfully": "Status atualizado com sucesso", "Stop": "Parar", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Você não tem mais códigos de recuperação. Gere um novo conjunto para conseguir entrar se perder seu autenticador.", "Your existing recovery codes will stop working.": "Seus códigos de recuperação atuais deixarão de funcionar.", "Your previous recovery codes no longer work.": "Seus códigos de recuperação anteriores não funcionam mais.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} ficará protegida apenas pela senha, e os códigos de recuperação deixarão de funcionar." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} ficará protegida apenas pela senha, e os códigos de recuperação deixarão de funcionar.", + "Development / testing backend — not supported for production": "Backend de desenvolvimento/teste — não suportado em produção", + "Local filesystem (dev/testing only)": "Sistema de arquivos local (somente desenvolvimento/teste)", + "Static single-key (built-in, dev/testing only)": "Chave única estática (integrada, somente desenvolvimento/teste)", + "The mTLS client certificate and private key paths must be provided together.": "Os caminhos do certificado de cliente mTLS e da chave privada devem ser fornecidos juntos.", + "Advanced TLS": "TLS avançado", + "Custom CA": "CA personalizada", + "mTLS client identity": "Identidade de cliente mTLS", + "Custom CA: configured": "CA personalizada: configurada", + "mTLS client identity: configured": "Identidade de cliente mTLS: configurada", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Os caminhos TLS armazenados nunca são exibidos. Insira novamente os caminhos para mantê-los; salvar com campos em branco remove as configurações TLS armazenadas.", + "CA Certificate Path": "Caminho do certificado CA", + "PEM CA bundle trusted for the Vault connection.": "Pacote CA em formato PEM confiável para a conexão com o Vault.", + "Client Certificate Path": "Caminho do certificado de cliente", + "PEM client certificate presented to Vault for mTLS.": "Certificado de cliente em formato PEM apresentado ao Vault para mTLS.", + "Client Key Path": "Caminho da chave de cliente", + "PEM private key matching the client certificate.": "Chave privada em formato PEM correspondente ao certificado de cliente.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Os caminhos referem-se a arquivos PEM no nó do servidor RustFS. Em um cluster com vários nós, o mesmo caminho deve existir em cada nó.", + "Failed to load rekey sweep status": "Falha ao carregar o status da varredura de rekey", + "Rekey sweep started": "Varredura de rekey iniciada", + "A rekey sweep is already running. Showing its progress.": "Uma varredura de rekey já está em execução. Exibindo seu progresso.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "O backend KMS configurado não oferece suporte ao reempacotamento de envelopes de chaves de dados.", + "Failed to start rekey sweep": "Falha ao iniciar a varredura de rekey", + "Rekey sweep cancellation requested": "Cancelamento da varredura de rekey solicitado", + "Failed to cancel rekey sweep": "Falha ao cancelar a varredura de rekey", + "Rekey Existing Objects": "Reencriptar objetos existentes", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Após a rotação de uma chave mestra, reempacote os envelopes de chaves de dados dos objetos existentes para a versão atual da chave.", + "Not available for this backend": "Não disponível para este backend", + "Leave blank to sweep all buckets": "Deixe em branco para varrer todos os baldes", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Nomes de baldes separados por vírgulas. Deixe em branco para varrer todos os baldes.", + "Object Key Prefix": "Prefixo da chave do objeto", + "Optional prefix such as photos/": "Prefixo opcional como photos/", + "Only objects whose keys start with this prefix are swept.": "Apenas objetos cujas chaves começam com este prefixo são varridos.", + "Cancel Sweep": "Cancelar varredura", + "Start Rekey Sweep": "Iniciar varredura de rekey", + "No rekey sweep has run yet": "Nenhuma varredura de rekey foi executada ainda", + "Scanning bucket {bucket}": "Varrendo o balde {bucket}", + "Rewrapped": "Reempacotados", + "Already current": "Já atualizados", + "Not applicable": "Não aplicável", + "Some object versions failed to rewrap": "Algumas versões de objetos falharam ao reempacotar", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "A varredura é idempotente: execute-a novamente para repetir apenas as versões com falha. Os detalhes estão no log do servidor.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Isso varre os metadados de cada versão de objeto selecionada e emite chamadas KMS para reempacotar envelopes desatualizados. Em baldes grandes, isso pode levar muito tempo.", + "Sweep completed": "Varredura concluída", + "Sweep cancelled": "Varredura cancelada", + "Versions scanned": "Versões varridas", + "Versions failed": "Versões com falha" } diff --git a/i18n/locales/ru-RU.json b/i18n/locales/ru-RU.json index bbda3010..50aa7df3 100644 --- a/i18n/locales/ru-RU.json +++ b/i18n/locales/ru-RU.json @@ -1109,7 +1109,6 @@ "Starting": "Запуск", "State": "Состояние", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Статус", "Status refreshed successfully": "Статус успешно обновлен", "Stop": "Остановить", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Коды восстановления закончились. Создайте новый набор, чтобы вернуться, если потеряете аутентификатор.", "Your existing recovery codes will stop working.": "Ваши текущие коды восстановления перестанут работать.", "Your previous recovery codes no longer work.": "Ваши предыдущие коды восстановления больше не работают.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} будет защищена только паролем, а коды восстановления перестанут работать." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} будет защищена только паролем, а коды восстановления перестанут работать.", + "Development / testing backend — not supported for production": "Бэкенд для разработки/тестирования — не поддерживается в производственной среде", + "Local filesystem (dev/testing only)": "Локальная файловая система (только для разработки/тестирования)", + "Static single-key (built-in, dev/testing only)": "Статический одиночный ключ (встроенный, только для разработки/тестирования)", + "The mTLS client certificate and private key paths must be provided together.": "Пути к клиентскому сертификату mTLS и закрытому ключу должны указываться вместе.", + "Advanced TLS": "Расширенные настройки TLS", + "Custom CA": "Пользовательский CA", + "mTLS client identity": "Клиентская идентичность mTLS", + "Custom CA: configured": "Пользовательский CA: настроен", + "mTLS client identity: configured": "Клиентская идентичность mTLS: настроена", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Сохранённые пути TLS никогда не отображаются. Введите пути повторно, чтобы сохранить их; сохранение с пустыми полями удалит сохранённые настройки TLS.", + "CA Certificate Path": "Путь к сертификату CA", + "PEM CA bundle trusted for the Vault connection.": "PEM-набор сертификатов CA, которому доверяет подключение к Vault.", + "Client Certificate Path": "Путь к клиентскому сертификату", + "PEM client certificate presented to Vault for mTLS.": "Клиентский сертификат в формате PEM, предъявляемый Vault для mTLS.", + "Client Key Path": "Путь к клиентскому ключу", + "PEM private key matching the client certificate.": "Закрытый ключ в формате PEM, соответствующий клиентскому сертификату.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Пути указывают на PEM-файлы на узле сервера RustFS. В многоузловом кластере одинаковый путь должен существовать на каждом узле.", + "Failed to load rekey sweep status": "Не удалось загрузить статус обхода перешифрования", + "Rekey sweep started": "Обход перешифрования запущен", + "A rekey sweep is already running. Showing its progress.": "Обход перешифрования уже выполняется. Отображается его ход.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Настроенный бэкенд KMS не поддерживает повторную упаковку конвертов ключей данных.", + "Failed to start rekey sweep": "Не удалось запустить обход перешифрования", + "Rekey sweep cancellation requested": "Запрошена отмена обхода перешифрования", + "Failed to cancel rekey sweep": "Не удалось отменить обход перешифрования", + "Rekey Existing Objects": "Перешифрование существующих объектов", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "После ротации мастер-ключа переупакуйте конверты ключей данных существующих объектов на текущую версию ключа.", + "Not available for this backend": "Недоступно для этого бэкенда", + "Leave blank to sweep all buckets": "Оставьте пустым, чтобы обойти все бакеты", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Имена бакетов через запятую. Оставьте пустым, чтобы обойти все бакеты.", + "Object Key Prefix": "Префикс ключа объекта", + "Optional prefix such as photos/": "Необязательный префикс, например photos/", + "Only objects whose keys start with this prefix are swept.": "Обрабатываются только объекты, ключи которых начинаются с этого префикса.", + "Cancel Sweep": "Отменить обход", + "Start Rekey Sweep": "Запустить обход перешифрования", + "No rekey sweep has run yet": "Обход перешифрования ещё не выполнялся", + "Scanning bucket {bucket}": "Сканирование бакета {bucket}", + "Rewrapped": "Переупаковано", + "Already current": "Уже актуальны", + "Not applicable": "Неприменимо", + "Some object versions failed to rewrap": "Не удалось переупаковать некоторые версии объектов", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Обход идемпотентен: запустите его снова, чтобы повторить только неудавшиеся версии. Подробности в журнале сервера.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Эта операция сканирует метаданные каждой выбранной версии объекта и выполняет вызовы KMS для переупаковки устаревших конвертов. Для больших бакетов это может занять много времени.", + "Sweep completed": "Обход завершён", + "Sweep cancelled": "Обход отменён", + "Versions scanned": "Просканировано версий", + "Versions failed": "Версий с ошибкой" } diff --git a/i18n/locales/tr-TR.json b/i18n/locales/tr-TR.json index af883fee..b2970e85 100644 --- a/i18n/locales/tr-TR.json +++ b/i18n/locales/tr-TR.json @@ -1109,7 +1109,6 @@ "Starting": "Başlatılıyor", "State": "Durum", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Durum", "Status refreshed successfully": "Durum başarıyla yenilendi", "Stop": "Durdur", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Hiç kurtarma kodunuz kalmadı. Doğrulayıcınızı kaybederseniz geri girebilmek için yeni bir set oluşturun.", "Your existing recovery codes will stop working.": "Mevcut kurtarma kodlarınız çalışmayı bırakacak.", "Your previous recovery codes no longer work.": "Önceki kurtarma kodlarınız artık çalışmıyor.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} yalnızca parolasıyla korunacak ve kurtarma kodları çalışmayı bırakacak." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} yalnızca parolasıyla korunacak ve kurtarma kodları çalışmayı bırakacak.", + "Development / testing backend — not supported for production": "Geliştirme/test backend'i — üretim ortamında desteklenmez", + "Local filesystem (dev/testing only)": "Yerel dosya sistemi (yalnızca geliştirme/test)", + "Static single-key (built-in, dev/testing only)": "Statik tek anahtar (yerleşik, yalnızca geliştirme/test)", + "The mTLS client certificate and private key paths must be provided together.": "mTLS istemci sertifikası ve özel anahtar yolları birlikte sağlanmalıdır.", + "Advanced TLS": "Gelişmiş TLS", + "Custom CA": "Özel CA", + "mTLS client identity": "mTLS istemci kimliği", + "Custom CA: configured": "Özel CA: yapılandırıldı", + "mTLS client identity: configured": "mTLS istemci kimliği: yapılandırıldı", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Kayıtlı TLS yolları hiçbir zaman görüntülenmez. Korumak için yolları yeniden girin; alanları boş bırakarak kaydetmek kayıtlı TLS ayarlarını kaldırır.", + "CA Certificate Path": "CA Sertifika Yolu", + "PEM CA bundle trusted for the Vault connection.": "Vault bağlantısı için güvenilen PEM biçiminde CA paketi.", + "Client Certificate Path": "İstemci Sertifika Yolu", + "PEM client certificate presented to Vault for mTLS.": "mTLS için Vault'a sunulan PEM biçiminde istemci sertifikası.", + "Client Key Path": "İstemci Anahtar Yolu", + "PEM private key matching the client certificate.": "İstemci sertifikasıyla eşleşen PEM biçiminde özel anahtar.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Yollar, RustFS sunucu düğümündeki PEM dosyalarını gösterir. Çok düğümlü bir kümede aynı yol her düğümde mevcut olmalıdır.", + "Failed to load rekey sweep status": "Rekey taraması durumu yüklenemedi", + "Rekey sweep started": "Rekey taraması başlatıldı", + "A rekey sweep is already running. Showing its progress.": "Bir rekey taraması zaten çalışıyor. İlerlemesi gösteriliyor.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Yapılandırılan KMS backend'i veri anahtarı zarflarının yeniden sarılmasını desteklemiyor.", + "Failed to start rekey sweep": "Rekey taraması başlatılamadı", + "Rekey sweep cancellation requested": "Rekey taramasının iptali istendi", + "Failed to cancel rekey sweep": "Rekey taraması iptal edilemedi", + "Rekey Existing Objects": "Mevcut Nesneleri Yeniden Anahtarla", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Bir ana anahtar döndürüldükten sonra, mevcut nesnelerin veri anahtarı zarflarını geçerli anahtar sürümüne yeniden sarın.", + "Not available for this backend": "Bu backend için kullanılamaz", + "Leave blank to sweep all buckets": "Tüm bucket'ları taramak için boş bırakın", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Virgülle ayrılmış bucket adları. Tüm bucket'ları taramak için boş bırakın.", + "Object Key Prefix": "Nesne Anahtarı Öneki", + "Optional prefix such as photos/": "photos/ gibi isteğe bağlı önek", + "Only objects whose keys start with this prefix are swept.": "Yalnızca anahtarları bu önekle başlayan nesneler taranır.", + "Cancel Sweep": "Taramayı İptal Et", + "Start Rekey Sweep": "Rekey Taramasını Başlat", + "No rekey sweep has run yet": "Henüz bir rekey taraması çalıştırılmadı", + "Scanning bucket {bucket}": "{bucket} bucket'ı taranıyor", + "Rewrapped": "Yeniden sarıldı", + "Already current": "Zaten güncel", + "Not applicable": "Uygulanamaz", + "Some object versions failed to rewrap": "Bazı nesne sürümleri yeniden sarılamadı", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Tarama idempotenttir: yalnızca başarısız sürümleri yeniden denemek için tekrar çalıştırın. Ayrıntılar sunucu günlüğündedir.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Bu işlem, seçilen her nesne sürümünün meta verilerini tarar ve güncel olmayan zarfları yeniden sarmak için KMS çağrıları yapar. Büyük bucket'larda bu uzun sürebilir.", + "Sweep completed": "Tarama tamamlandı", + "Sweep cancelled": "Tarama iptal edildi", + "Versions scanned": "Taranan sürümler", + "Versions failed": "Başarısız sürümler" } diff --git a/i18n/locales/vi-VN.json b/i18n/locales/vi-VN.json index 67d18f0f..e842ae54 100644 --- a/i18n/locales/vi-VN.json +++ b/i18n/locales/vi-VN.json @@ -1109,7 +1109,6 @@ "Starting": "Đang bắt đầu", "State": "Trạng thái", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "Trạng thái", "Status refreshed successfully": "Đã làm mới trạng thái thành công", "Stop": "Dừng", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "Bạn không còn mã phục hồi nào. Hãy tạo bộ mới để vẫn vào được nếu mất ứng dụng xác thực.", "Your existing recovery codes will stop working.": "Các mã phục hồi hiện có của bạn sẽ ngừng hoạt động.", "Your previous recovery codes no longer work.": "Các mã phục hồi trước đây của bạn không còn hoạt động.", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} sẽ chỉ được bảo vệ bằng mật khẩu, và các mã phục hồi sẽ ngừng hoạt động." + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} sẽ chỉ được bảo vệ bằng mật khẩu, và các mã phục hồi sẽ ngừng hoạt động.", + "Development / testing backend — not supported for production": "Backend phát triển/kiểm thử — không được hỗ trợ cho môi trường sản xuất", + "Local filesystem (dev/testing only)": "Hệ thống tệp cục bộ (chỉ dành cho phát triển/kiểm thử)", + "Static single-key (built-in, dev/testing only)": "Khóa đơn tĩnh (tích hợp, chỉ dành cho phát triển/kiểm thử)", + "The mTLS client certificate and private key paths must be provided together.": "Đường dẫn chứng chỉ máy khách mTLS và khóa riêng phải được cung cấp cùng nhau.", + "Advanced TLS": "TLS nâng cao", + "Custom CA": "CA tùy chỉnh", + "mTLS client identity": "Danh tính máy khách mTLS", + "Custom CA: configured": "CA tùy chỉnh: đã cấu hình", + "mTLS client identity: configured": "Danh tính máy khách mTLS: đã cấu hình", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "Đường dẫn TLS đã lưu không bao giờ được hiển thị. Nhập lại đường dẫn để giữ chúng; lưu với các trường trống sẽ xóa cài đặt TLS đã lưu.", + "CA Certificate Path": "Đường dẫn chứng chỉ CA", + "PEM CA bundle trusted for the Vault connection.": "Gói CA định dạng PEM được tin cậy cho kết nối Vault.", + "Client Certificate Path": "Đường dẫn chứng chỉ máy khách", + "PEM client certificate presented to Vault for mTLS.": "Chứng chỉ máy khách định dạng PEM được xuất trình cho Vault để dùng mTLS.", + "Client Key Path": "Đường dẫn khóa máy khách", + "PEM private key matching the client certificate.": "Khóa riêng định dạng PEM khớp với chứng chỉ máy khách.", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "Đường dẫn trỏ tới các tệp PEM trên nút máy chủ RustFS. Trong cụm nhiều nút, cùng một đường dẫn phải tồn tại trên mọi nút.", + "Failed to load rekey sweep status": "Tải trạng thái quét rekey thất bại", + "Rekey sweep started": "Đã bắt đầu quét rekey", + "A rekey sweep is already running. Showing its progress.": "Một quét rekey đang chạy. Đang hiển thị tiến trình của nó.", + "The configured KMS backend does not support rewrapping data-key envelopes.": "Backend KMS được cấu hình không hỗ trợ đóng gói lại phong bì khóa dữ liệu.", + "Failed to start rekey sweep": "Bắt đầu quét rekey thất bại", + "Rekey sweep cancellation requested": "Đã yêu cầu hủy quét rekey", + "Failed to cancel rekey sweep": "Hủy quét rekey thất bại", + "Rekey Existing Objects": "Rekey các đối tượng hiện có", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "Sau khi xoay vòng khóa chính, đóng gói lại phong bì khóa dữ liệu của các đối tượng hiện có sang phiên bản khóa hiện tại.", + "Not available for this backend": "Không khả dụng cho backend này", + "Leave blank to sweep all buckets": "Để trống để quét tất cả thùng chứa", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "Tên thùng chứa phân tách bằng dấu phẩy. Để trống để quét tất cả thùng chứa.", + "Object Key Prefix": "Tiền tố khóa đối tượng", + "Optional prefix such as photos/": "Tiền tố tùy chọn như photos/", + "Only objects whose keys start with this prefix are swept.": "Chỉ các đối tượng có khóa bắt đầu bằng tiền tố này mới được quét.", + "Cancel Sweep": "Hủy quét", + "Start Rekey Sweep": "Bắt đầu quét rekey", + "No rekey sweep has run yet": "Chưa có quét rekey nào được chạy", + "Scanning bucket {bucket}": "Đang quét thùng chứa {bucket}", + "Rewrapped": "Đã đóng gói lại", + "Already current": "Đã là mới nhất", + "Not applicable": "Không áp dụng", + "Some object versions failed to rewrap": "Một số phiên bản đối tượng không đóng gói lại được", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "Quét này có tính bất biến: chạy lại để chỉ thử lại các phiên bản thất bại. Chi tiết có trong nhật ký máy chủ.", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "Thao tác này quét siêu dữ liệu của mọi phiên bản đối tượng được chọn và thực hiện các lệnh gọi KMS để đóng gói lại các phong bì lỗi thời. Với thùng chứa lớn, việc này có thể mất nhiều thời gian.", + "Sweep completed": "Quét hoàn tất", + "Sweep cancelled": "Đã hủy quét", + "Versions scanned": "Phiên bản đã quét", + "Versions failed": "Phiên bản thất bại" } diff --git a/i18n/locales/zh-CN.json b/i18n/locales/zh-CN.json index 5caa8d90..30ea716e 100644 --- a/i18n/locales/zh-CN.json +++ b/i18n/locales/zh-CN.json @@ -1109,7 +1109,6 @@ "Starting": "启动中", "State": "状态", "Static key configuration": "Static key configuration", - "Static single-key (built-in)": "Static single-key (built-in)", "Status": "状态", "Status refreshed successfully": "状态刷新成功", "Stop": "停止", @@ -1884,5 +1883,51 @@ "You have no recovery codes left. Generate a new set so you can get back in if you lose your authenticator.": "你已没有剩余恢复码。请生成一组新的,以便在丢失验证器时仍能登录。", "Your existing recovery codes will stop working.": "你现有的恢复码将失效。", "Your previous recovery codes no longer work.": "你之前的恢复码已失效。", - "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} 将仅由密码保护,恢复码也将失效。" + "{account} will be protected by its password alone, and the recovery codes will stop working.": "{account} 将仅由密码保护,恢复码也将失效。", + "Development / testing backend — not supported for production": "开发/测试后端 — 不支持用于生产环境", + "Local filesystem (dev/testing only)": "本地文件系统(仅限开发/测试)", + "Static single-key (built-in, dev/testing only)": "静态单密钥(内置,仅限开发/测试)", + "The mTLS client certificate and private key paths must be provided together.": "mTLS 客户端证书与私钥路径必须同时填写。", + "Advanced TLS": "高级 TLS 设置", + "Custom CA": "自定义 CA", + "mTLS client identity": "mTLS 客户端身份", + "Custom CA: configured": "自定义 CA:已配置", + "mTLS client identity: configured": "mTLS 客户端身份:已配置", + "Stored TLS paths are never displayed. Re-enter the paths to keep them; saving with blank fields removes the stored TLS settings.": "已存储的 TLS 路径不会回显。若要保留请重新填写路径;留空保存将移除已存储的 TLS 设置。", + "CA Certificate Path": "CA 证书路径", + "PEM CA bundle trusted for the Vault connection.": "Vault 连接信任的 PEM 格式 CA 证书包。", + "Client Certificate Path": "客户端证书路径", + "PEM client certificate presented to Vault for mTLS.": "用于 mTLS、向 Vault 出示的 PEM 格式客户端证书。", + "Client Key Path": "客户端私钥路径", + "PEM private key matching the client certificate.": "与客户端证书匹配的 PEM 格式私钥。", + "Paths refer to PEM files on the RustFS server node. In a multi-node cluster the same path must exist on every node.": "路径指向 RustFS 服务器节点上的 PEM 文件。多节点集群中,每个节点上必须存在相同的路径。", + "Failed to load rekey sweep status": "加载重加密扫描状态失败", + "Rekey sweep started": "重加密扫描已启动", + "A rekey sweep is already running. Showing its progress.": "已有一个重加密扫描正在运行,正在显示其进度。", + "The configured KMS backend does not support rewrapping data-key envelopes.": "当前配置的 KMS 后端不支持重新封装数据密钥信封。", + "Failed to start rekey sweep": "启动重加密扫描失败", + "Rekey sweep cancellation requested": "已请求取消重加密扫描", + "Failed to cancel rekey sweep": "取消重加密扫描失败", + "Rekey Existing Objects": "重加密存量对象", + "After rotating a master key, rewrap the data-key envelopes of existing objects to the current key version.": "轮换主密钥后,将存量对象的数据密钥信封重新封装到当前密钥版本。", + "Not available for this backend": "当前后端不可用", + "Leave blank to sweep all buckets": "留空则扫描所有存储桶", + "Comma-separated bucket names. Leave blank to sweep all buckets.": "以逗号分隔的存储桶名称。留空则扫描所有存储桶。", + "Object Key Prefix": "对象键前缀", + "Optional prefix such as photos/": "可选前缀,例如 photos/", + "Only objects whose keys start with this prefix are swept.": "仅扫描键以此前缀开头的对象。", + "Cancel Sweep": "取消扫描", + "Start Rekey Sweep": "启动重加密扫描", + "No rekey sweep has run yet": "尚未执行过重加密扫描", + "Scanning bucket {bucket}": "正在扫描存储桶 {bucket}", + "Rewrapped": "已重新封装", + "Already current": "已是最新", + "Not applicable": "不适用", + "Some object versions failed to rewrap": "部分对象版本重新封装失败", + "The sweep is idempotent: run it again to retry only the failed versions. Details are in the server log.": "该扫描是幂等的:再次运行即可仅重试失败的版本。详情见服务器日志。", + "This scans the metadata of every selected object version and issues KMS calls to rewrap outdated envelopes. On large buckets this can take a long time.": "此操作将扫描所有选定对象版本的元数据,并发起 KMS 调用以重新封装过期的信封。存储桶规模较大时可能耗时很长。", + "Sweep completed": "扫描已完成", + "Sweep cancelled": "扫描已取消", + "Versions scanned": "已扫描版本", + "Versions failed": "失败版本" } diff --git a/lib/sse/config.ts b/lib/sse/config.ts index d28c6173..07d53c62 100644 --- a/lib/sse/config.ts +++ b/lib/sse/config.ts @@ -19,6 +19,9 @@ export type ConfigFormState = { kvMount: string keyPathPrefix: string skipTlsVerify: boolean + caCertPath: string + clientCertPath: string + clientKeyPath: string secretKey: string staticKeyId: string } @@ -40,6 +43,9 @@ export const INITIAL_FORM_STATE: ConfigFormState = { kvMount: "secret", keyPathPrefix: "rustfs/kms/keys", skipTlsVerify: false, + caCertPath: "", + clientCertPath: "", + clientKeyPath: "", secretKey: "", staticKeyId: "", } @@ -91,6 +97,11 @@ export function buildFormStateFromStatus(status: KmsServiceStatusResponse | null secretKey: "", staticKeyId: backendSummary?.key_id ?? "", skipTlsVerify: backendSummary?.skip_tls_verify ?? false, + // The status API only reports has_custom_ca / has_client_identity booleans + // and never echoes paths back, so these cannot be refilled from status. + caCertPath: "", + clientCertPath: "", + clientKeyPath: "", } } diff --git a/lib/sse/rekey.ts b/lib/sse/rekey.ts new file mode 100644 index 00000000..6165e71a --- /dev/null +++ b/lib/sse/rekey.ts @@ -0,0 +1,33 @@ +import type { KmsRekeyStartRequest } from "@/types/kms" + +// The rekey endpoints answer 404 in two distinct cases: an old server without +// the routes at all, and a supporting server that has simply never run a sweep +// (JSON body {"error": "no rekey sweep has run"}). Only the latter is a normal +// empty state; anything else means the feature is unavailable. +export function isRekeyNeverRanError(error: unknown): boolean { + if (!(error instanceof Error)) return false + const status = (error as Error & { status?: number }).status + return status === 404 && error.message.includes("no rekey sweep has run") +} + +export function isRekeyAlreadyRunningError(error: unknown): boolean { + return error instanceof Error && (error as Error & { status?: number }).status === 409 +} + +export function isRekeyUnsupportedError(error: unknown): boolean { + return error instanceof Error && (error as Error & { status?: number }).status === 501 +} + +// The server rejects unknown fields and treats a missing list as "all +// buckets", so empty inputs must be omitted entirely. +export function buildRekeyStartRequest(bucketsInput: string, prefixInput: string): KmsRekeyStartRequest { + const buckets = bucketsInput + .split(/[\s,]+/) + .map((bucket) => bucket.trim()) + .filter(Boolean) + const prefix = prefixInput.trim() + const request: KmsRekeyStartRequest = {} + if (buckets.length > 0) request.buckets = buckets + if (prefix) request.prefix = prefix + return request +} diff --git a/tests/lib/sse-config.test.ts b/tests/lib/sse-config.test.ts index 45882122..867308bc 100644 --- a/tests/lib/sse-config.test.ts +++ b/tests/lib/sse-config.test.ts @@ -44,6 +44,19 @@ test("buildFormStateFromStatus does not coerce NotConfigured or future backends assert.equal(buildFormStateFromStatus(statusWithBackend("FutureBackend")).backendType, "unsupported") }) +test("buildFormStateFromStatus never refills TLS paths because status only reports booleans", () => { + const status = statusWithBackend("VaultTransit") + const backendSummary = status.config_summary?.backend_summary + assert.ok(backendSummary) + backendSummary.has_custom_ca = true + backendSummary.has_client_identity = true + + const formState = buildFormStateFromStatus(status) + assert.equal(formState.caCertPath, "") + assert.equal(formState.clientCertPath, "") + assert.equal(formState.clientKeyPath, "") +}) + test("getFormSyncDecision refreshes clean forms when the server baseline changes", () => { const nextBaseline = { ...INITIAL_FORM_STATE, diff --git a/tests/lib/sse-kms-p1-safety.test.js b/tests/lib/sse-kms-p1-safety.test.js new file mode 100644 index 00000000..425744d0 --- /dev/null +++ b/tests/lib/sse-kms-p1-safety.test.js @@ -0,0 +1,49 @@ +import test from "node:test" +import assert from "node:assert/strict" +import fs from "node:fs" + +const pageSource = fs.readFileSync("app/(dashboard)/sse/page.tsx", "utf8") +const rekeyCardSource = fs.readFileSync("components/sse/rekey-card.tsx", "utf8") + +test("blank Vault TLS paths never reach the configure payload (old servers reject unknown fields)", () => { + assert.match(pageSource, /\.\.\.\(caCertPath \? \{ ca_cert_path: caCertPath \} : \{\}\)/) + assert.match( + pageSource, + /\.\.\.\(clientCertPath \? \{ client_cert_path: clientCertPath, client_key_path: clientKeyPath \} : \{\}\)/, + ) +}) + +test("mTLS client certificate and key are validated as a pair before submit", () => { + assert.match(pageSource, /Boolean\(clientCertPath\) !== Boolean\(clientKeyPath\)/) + assert.match(pageSource, /field: clientCertPath \? "clientKeyPath" : "clientCertPath"/) +}) + +test("the non-production badge renders only on an explicit false, never on a missing capability", () => { + assert.match(pageSource, /capabilities\?\.production_supported === false/) + assert.doesNotMatch(pageSource, /!capabilities\?\.production_supported/) +}) + +test("rekey UI is gated on a served capability matrix so old servers never see it", () => { + assert.match( + pageSource, + /\{isRunning && capabilities \? : null\}/, + ) +}) + +test("rekey card distinguishes the never-ran empty state and surfaces 409/501 responses distinctly", () => { + assert.match(rekeyCardSource, /isRekeyNeverRanError\(error\)/) + assert.match(rekeyCardSource, /isRekeyAlreadyRunningError\(error\)/) + assert.match(rekeyCardSource, /isRekeyUnsupportedError\(error\)/) + assert.match(rekeyCardSource, /No rekey sweep has run yet/) +}) + +test("failed rewraps point the operator at the idempotent re-run recovery", () => { + assert.match(rekeyCardSource, /snapshot\.failed > 0/) + assert.match(rekeyCardSource, /run it again to retry only the failed versions/) +}) + +test("polling runs only while a sweep is running and stops on terminal states", () => { + assert.match(rekeyCardSource, /const isSweepRunning = snapshot\?\.state === "running"/) + assert.match(rekeyCardSource, /if \(!isSweepRunning\) return/) + assert.match(rekeyCardSource, /clearInterval\(intervalId\)/) +}) diff --git a/tests/lib/sse-rekey.test.ts b/tests/lib/sse-rekey.test.ts new file mode 100644 index 00000000..cf17001c --- /dev/null +++ b/tests/lib/sse-rekey.test.ts @@ -0,0 +1,52 @@ +import test from "node:test" +import assert from "node:assert/strict" + +import { + buildRekeyStartRequest, + isRekeyAlreadyRunningError, + isRekeyNeverRanError, + isRekeyUnsupportedError, +} from "../../lib/sse/rekey" + +function httpError(status: number, message: string): Error { + const error = new Error(message) as Error & { status: number } + error.status = status + return error +} + +test("never-ran 404 with the server's empty-state body is a normal empty state", () => { + assert.equal(isRekeyNeverRanError(httpError(404, '{"error":"no rekey sweep has run"}')), true) +}) + +test("a 404 without the empty-state body means the feature is unavailable, not empty", () => { + assert.equal(isRekeyNeverRanError(httpError(404, "Not Found")), false) +}) + +test("non-404 statuses and non-Error values are never treated as the empty state", () => { + assert.equal(isRekeyNeverRanError(httpError(500, "no rekey sweep has run")), false) + assert.equal(isRekeyNeverRanError("no rekey sweep has run"), false) + assert.equal(isRekeyNeverRanError(null), false) +}) + +test("409 maps to already-running and 501 maps to unsupported, exclusively", () => { + const conflict = httpError(409, '{"error":"a rekey sweep is already running","job_id":"abc"}') + const unsupported = httpError(501, "the configured KMS backend does not support rewrapping data-key envelopes") + assert.equal(isRekeyAlreadyRunningError(conflict), true) + assert.equal(isRekeyUnsupportedError(conflict), false) + assert.equal(isRekeyUnsupportedError(unsupported), true) + assert.equal(isRekeyAlreadyRunningError(unsupported), false) +}) + +test("blank inputs build an empty request so the server sweeps every bucket", () => { + assert.deepEqual(buildRekeyStartRequest("", ""), {}) + assert.deepEqual(buildRekeyStartRequest(" ", " "), {}) +}) + +test("bucket lists split on commas and whitespace and drop empty segments", () => { + assert.deepEqual(buildRekeyStartRequest("b1, b2 b3,,", ""), { buckets: ["b1", "b2", "b3"] }) +}) + +test("a prefix is trimmed and only included when non-empty", () => { + assert.deepEqual(buildRekeyStartRequest("b1", " photos/ "), { buckets: ["b1"], prefix: "photos/" }) + assert.deepEqual(buildRekeyStartRequest("", "photos/"), { prefix: "photos/" }) +}) diff --git a/types/kms.ts b/types/kms.ts index d61b4175..a2d764e6 100644 --- a/types/kms.ts +++ b/types/kms.ts @@ -22,9 +22,37 @@ export interface KmsBackendSummary { kv_mount?: string | null key_path_prefix?: string | null skip_tls_verify?: boolean | null + has_custom_ca?: boolean | null + has_client_identity?: boolean | null key_id?: string | null } +// Capability matrix reported by newer servers. Older servers omit the whole +// object and individual flags, so every field must stay optional and absence +// must render as "unknown", never as false. +export interface KmsBackendCapabilities { + encrypt?: boolean + decrypt?: boolean + generate_data_key?: boolean + rotate?: boolean + enable_disable?: boolean + schedule_deletion?: boolean + versioning?: boolean + physical_delete?: boolean + update_key_metadata?: boolean + rewrap?: boolean + production_supported?: boolean +} + +// Response of GET /kms/status (only available while KMS is running). +export interface KmsDetailedStatusResponse { + backend_type?: string | null + backend_status?: string | null + cache_enabled?: boolean | null + default_key_id?: string | null + capabilities?: KmsBackendCapabilities | null +} + export interface KmsConfigSummary { backend_type?: KmsBackendType | null default_key_id?: string | null @@ -99,6 +127,11 @@ export interface KmsVaultKV2ConfigPayload { kv_mount?: string | null key_path_prefix?: string | null skip_tls_verify?: boolean + // Server-local PEM file paths. Older servers reject unknown fields, so only + // include these keys when the user actually filled them in. + ca_cert_path?: string + client_cert_path?: string + client_key_path?: string default_key_id?: string timeout_seconds?: number retry_attempts?: number @@ -114,6 +147,11 @@ export interface KmsVaultTransitConfigPayload { namespace?: string | null mount_path: string skip_tls_verify?: boolean + // Server-local PEM file paths. Older servers reject unknown fields, so only + // include these keys when the user actually filled them in. + ca_cert_path?: string + client_cert_path?: string + client_key_path?: string default_key_id?: string timeout_seconds?: number retry_attempts?: number @@ -199,3 +237,25 @@ export interface KmsDeleteKeyOptions { export interface KmsCancelDeletionRequest { key_id: string } + +export interface KmsRekeyStartRequest { + // Empty or missing means every bucket. + buckets?: string[] + prefix?: string +} + +export type KmsRekeyJobState = "running" | "completed" | "cancelled" + +// Wire shape of POST /kms/keys/rekey and GET /kms/keys/rekey/status. +// Counts are per object version. +export interface KmsRekeyJobSnapshot { + job_id: string + state: KmsRekeyJobState + buckets: string[] + current_bucket: string | null + scanned: number + rewrapped: number + already_current: number + not_applicable: number + failed: number +}