diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index 3658276cd..3291ab090 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -50,6 +50,7 @@ import type { AppSettingsResponse } from "@/Types/Settings"; import { stepFieldsFor, monitorStepCount, + isDockerTlsUrl, type MonitorFormData, } from "@/Validation/monitor"; import { FormNumberField } from "@/Components/inputs/forms/FormNumberField"; @@ -66,6 +67,14 @@ const httpMethodOptions = HttpMethods.map((method) => ({ label: method, })); +const PEM_FIELD_ROWS = 6; + +// Hides the pasted key while the field is not focused. Ignored by browsers +// without -webkit-text-security, which then show the key as plain text. +const maskedInputSx = { + "&:not(.Mui-focused) textarea": { WebkitTextSecurity: "disc" }, +}; + interface GeneralSettingsConfig { urlLabel: string; urlPlaceholder: string; @@ -300,6 +309,7 @@ const CreateMonitorPage = () => { const showStep = (step: number) => isEditMode || currentStep === step; const watchedType = watch("type") as MonitorType; + const watchedUrl = watch("url") as string; const watchedMethod = watch("method") as HttpMethod | undefined; const watchedProxyMode = watch("proxyMode") as ProxyMode | undefined; const watchedUseAdvancedMatching = watch("useAdvancedMatching") as boolean; @@ -334,6 +344,8 @@ const CreateMonitorPage = () => { [watchedType, t] ); + const pemInputSx = { fontFamily: theme.typography.fontFamilyMonospace }; + const { post, loading: isCreating } = usePost(); const { patch, loading: isUpdating } = usePatch(); const isSubmitting = isCreating || isUpdating; @@ -689,6 +701,64 @@ const CreateMonitorPage = () => { /> )} + {showStep(0) && watchedType === "docker" && isDockerTlsUrl(watchedUrl) && ( + + + + + + + {t("pages.createMonitor.form.dockerTls.option.ignoreTls.description")} + + + } + /> + )} + {showStep(1) && ( supported games list for protocol details.", "pagespeed": "Track page load performance, Core Web Vitals, and optimization scores for your website.", "grpc": "Enter the hostname and port of the gRPC server, optionally specify a service name for the health check, and add a display name.", @@ -834,6 +834,29 @@ "description": "This will permanently delete all monitoring history, statistics, and check data for your team. This action cannot be undone.", "confirm": "Yes, clear all stats" } + }, + "dockerTls": { + "title": "TLS credentials", + "description": "Connect to a remote Docker daemon over mutual TLS. Paste the PEM files you would pass to docker --tlsverify. The client key is encrypted before it is stored and is never shown again.", + "option": { + "ca": { + "label": "CA certificate", + "placeholder": "-----BEGIN CERTIFICATE-----" + }, + "cert": { + "label": "Client certificate", + "placeholder": "-----BEGIN CERTIFICATE-----" + }, + "key": { + "label": "Client key", + "placeholder": "-----BEGIN PRIVATE KEY-----", + "stored": "A key is stored. Leave blank to keep it." + }, + "ignoreTls": { + "label": "Ignore TLS/SSL errors", + "description": "Skips verifying the daemon's certificate, so the CA certificate becomes optional. The client certificate and key are still required because the daemon verifies them." + } + } } } },