diff --git a/components/replication/new-form.tsx b/components/replication/new-form.tsx index baace19..3380f6a 100644 --- a/components/replication/new-form.tsx +++ b/components/replication/new-form.tsx @@ -7,6 +7,7 @@ import { RiAddLine, RiDeleteBinLine } from "@remixicon/react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Switch } from "@/components/ui/switch" +import { Textarea } from "@/components/ui/textarea" import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Field, FieldContent, FieldError, FieldLabel } from "@/components/ui/field" @@ -14,6 +15,7 @@ import { useBucket } from "@/hooks/use-bucket" import { useMessage } from "@/lib/feedback/message" import { getBytes, randomUUID } from "@/lib/functions" import { isMissingBucketConfiguration, normalizeReplicationRulesForRolelessConfig } from "@/lib/bucket-configuration" +import { buildBucketReplicationTlsPayload, type BucketReplicationTlsMode } from "@/lib/bucket-replication-tls" interface ReplicationNewFormProps { open: boolean @@ -39,6 +41,8 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } const [level, setLevel] = useState("1") const [endpoint, setEndpoint] = useState("") const [tls, setTls] = useState(false) + const [tlsMode, setTlsMode] = useState("verify") + const [caCertPem, setCaCertPem] = useState("") const [accessKey, setAccessKey] = useState("") const [secretKey, setSecretKey] = useState("") const [bucket, setBucket] = useState("") @@ -61,6 +65,7 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } accessKey?: string secretKey?: string timecheck?: string + caCertPem?: string }>({}) const modeOptions = useMemo( @@ -84,6 +89,8 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } setLevel("1") setEndpoint("") setTls(false) + setTlsMode("verify") + setCaCertPem("") setAccessKey("") setSecretKey("") setBucket("") @@ -134,6 +141,9 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } if (modeType === "async" && Number(timecheck) < 1) { errors.timecheck = t("Please enter valid health check interval") } + if (tls && tlsMode === "custom-ca" && !caCertPem.trim()) { + errors.caCertPem = t("Custom CA certificate is required") + } setFieldErrors(errors) const firstErrorId = errors.endpoint ? "replication-endpoint" @@ -145,7 +155,9 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } ? "replication-secret-key" : errors.timecheck ? "replication-health-check-interval" - : null + : errors.caCertPem + ? "replication-ca-certificate" + : null if (firstErrorId) document.getElementById(firstErrorId)?.focus() return !firstErrorId } @@ -161,6 +173,7 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } setSaveError("") let remoteTargetSaved = false try { + const tlsConfig = buildBucketReplicationTlsPayload(tls, tlsMode, caCertPem) const config: Record = { sourcebucket: bucketName, endpoint, @@ -171,6 +184,8 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } }, targetbucket: bucket, secure: tls, + skipTlsVerify: tlsConfig.skipTlsVerify, + caCertPem: tlsConfig.caCertPem, region, path: "auto", api: "s3v4", @@ -566,9 +581,91 @@ export function ReplicationNewForm({ open, onOpenChange, bucketName, onSuccess } {t("Enable secure transport when connecting to endpoint.")}
+ {t("Paste the CA certificate in PEM format.")} +
+ {t("Certificate verification is disabled. Only use this for trusted networks.")} +