diff --git a/app/client/api-client/types.gen.ts b/app/client/api-client/types.gen.ts index 9146e070..44b2b3c5 100644 --- a/app/client/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -838,7 +838,9 @@ export type ListRepositoriesResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -917,7 +919,9 @@ export type CreateRepositoryData = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -1058,7 +1062,9 @@ export type GetRepositoryResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -1164,7 +1170,9 @@ export type UpdateRepositoryResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -1487,7 +1495,9 @@ export type ListBackupSchedulesResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -1749,7 +1759,9 @@ export type GetBackupScheduleResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -1992,7 +2004,9 @@ export type GetBackupScheduleForVolumeResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -2211,6 +2225,7 @@ export type GetScheduleNotificationsResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2310,6 +2325,7 @@ export type UpdateScheduleNotificationsResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2420,7 +2436,9 @@ export type GetScheduleMirrorsResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -2526,7 +2544,9 @@ export type UpdateScheduleMirrorsResponses = { } | { backend: 'rest'; url: string; + cacert?: string; customPassword?: string; + insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; @@ -2646,6 +2666,7 @@ export type ListNotificationDestinationsResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2716,6 +2737,7 @@ export type CreateNotificationDestinationData = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2785,6 +2807,7 @@ export type CreateNotificationDestinationResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2901,6 +2924,7 @@ export type GetNotificationDestinationResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -2971,6 +2995,7 @@ export type UpdateNotificationDestinationData = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; @@ -3050,6 +3075,7 @@ export type UpdateNotificationDestinationResponses = { priority: 'default' | 'high' | 'low' | 'max' | 'min'; topic: string; type: 'ntfy'; + accessToken?: string; password?: string; serverUrl?: string; username?: string; diff --git a/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx b/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx index 4317f98d..287519fb 100644 --- a/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx +++ b/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx @@ -13,6 +13,7 @@ import { Textarea } from "../../../../components/ui/textarea"; import { Checkbox } from "../../../../components/ui/checkbox"; import { Tooltip, TooltipContent, TooltipTrigger } from "../../../../components/ui/tooltip"; import type { RepositoryFormValues } from "../create-repository-form"; +import { cn } from "~/client/lib/utils"; type Props = { form: UseFormReturn; @@ -52,25 +53,20 @@ export const RestRepositoryForm = ({ form }: Props) => { disabled={!!cacert} onCheckedChange={(checked) => { field.onChange(checked); - if (checked) { - form.setValue("cacert", ""); - } }} /> - {cacert && ( - -

- This option is disabled because a CA certificate is provided. Remove the CA certificate to skip - TLS validation instead. -

-
- )} + +

+ This option is disabled because a CA certificate is provided. Remove the CA certificate to skip TLS + validation instead. +

+
- Skip TLS Certificate Verification + Skip TLS certificate verification Disable TLS certificate verification if rest server is https and uses a self-signed certificate. This is insecure and should only be used for testing. @@ -94,28 +90,19 @@ export const RestRepositoryForm = ({ form }: Props) => { rows={6} disabled={insecureTls} {...field} - value={insecureTls ? "" : field.value} - onChange={(e) => { - field.onChange(e); - if (e.target.value) { - form.setValue("insecureTls", false); - } - }} />
- {insecureTls && ( - -

- CA certificate is disabled because TLS validation is being skipped. Uncheck "Skip TLS Certificate - Verification" to provide a custom CA certificate. -

-
- )} + +

+ CA certificate is disabled because TLS validation is being skipped. Uncheck "Skip TLS Certificate + Verification" to provide a custom CA certificate. +

+
- Custom CA certificate for self-signed certificates (PEM format).{" "} + Custom CA certificate for self-signed certificates (PEM format).  { {repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"}

- {repository.type === "rest" && "cacert" in repository.config && ( - <> -
-
CA Certificate
-

- {repository.config.cacert ? ( - configured - ) : ( - not configured - )} -

-
-
-
TLS Certificate Validation
-

- {"insecureTls" in repository.config && repository.config.insecureTls ? ( - disabled - ) : ( - enabled - )} -

-
- + {repository.config.backend === "rest" && repository.config.cacert && ( +
+
CA Certificate
+

+ configured +

+
+ )} + {repository.config.backend === "rest" && "insecureTls" in repository.config && ( +
+
TLS Certificate Validation
+

+ {repository.config.insecureTls ? ( + disabled + ) : ( + enabled + )} +

+
)} diff --git a/app/server/utils/restic.ts b/app/server/utils/restic.ts index b7044c46..f7670b09 100644 --- a/app/server/utils/restic.ts +++ b/app/server/utils/restic.ts @@ -157,7 +157,7 @@ export const buildEnv = async (config: RepositoryConfig) => { } if (config.cacert) { const decryptedCert = await cryptoUtils.resolveSecret(config.cacert); - const certPath = path.join("/tmp", `rest-server-cacert-${crypto.randomBytes(8).toString("hex")}.pem`); + const certPath = path.join("/tmp", `zerobyte-cacert-${crypto.randomBytes(8).toString("hex")}.pem`); await fs.writeFile(certPath, decryptedCert, { mode: 0o600 }); env.RESTIC_CACERT = certPath; } @@ -855,8 +855,8 @@ const copy = async ( const res = await safeSpawn({ command: "restic", args, env }); - await cleanupTemporaryKeys(sourceConfig, sourceEnv); - await cleanupTemporaryKeys(destConfig, destEnv); + await cleanupTemporaryKeys(sourceEnv); + await cleanupTemporaryKeys(destEnv); const { stdout, stderr } = res; @@ -872,17 +872,20 @@ const copy = async ( }; }; -export const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record) => { - if (config.backend === "sftp") { - if (env._SFTP_KEY_PATH) { - await fs.unlink(env._SFTP_KEY_PATH).catch(() => {}); - } - if (env._SFTP_KNOWN_HOSTS_PATH) { - await fs.unlink(env._SFTP_KNOWN_HOSTS_PATH).catch(() => {}); - } - } else if (config.isExistingRepository && config.customPassword && env.RESTIC_PASSWORD_FILE) { +export const cleanupTemporaryKeys = async (env: Record) => { + if (env._SFTP_KEY_PATH) { + await fs.unlink(env._SFTP_KEY_PATH).catch(() => {}); + } + + if (env._SFTP_KNOWN_HOSTS_PATH) { + await fs.unlink(env._SFTP_KNOWN_HOSTS_PATH).catch(() => {}); + } + + if (env.RESTIC_PASSWORD_FILE) { await fs.unlink(env.RESTIC_PASSWORD_FILE).catch(() => {}); - } else if (config.backend === "gcs" && env.GOOGLE_APPLICATION_CREDENTIALS) { + } + + if (env.GOOGLE_APPLICATION_CREDENTIALS) { await fs.unlink(env.GOOGLE_APPLICATION_CREDENTIALS).catch(() => {}); }