From e0027b7668bb9e62b6c70af8507843b3e7f36475 Mon Sep 17 00:00:00 2001
From: Nicolas Meienberger
Date: Fri, 2 Jan 2026 17:37:38 +0100
Subject: [PATCH] refactor: code style and api client
---
app/client/api-client/types.gen.ts | 26 +++++++++++
.../repository-forms/rest-repository-form.tsx | 43 +++++++------------
app/client/modules/repositories/tabs/info.tsx | 42 ++++++++----------
app/server/utils/restic.ts | 29 +++++++------
4 files changed, 76 insertions(+), 64 deletions(-)
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(() => {});
}