feat: add support for a cacert configuration as well as allowing the user to skip tls validation
This commit is contained in:
parent
2c786dfb35
commit
07e68b9fe7
5 changed files with 85 additions and 0 deletions
|
|
@ -9,6 +9,8 @@ import {
|
||||||
} from "../../../../components/ui/form";
|
} from "../../../../components/ui/form";
|
||||||
import { Input } from "../../../../components/ui/input";
|
import { Input } from "../../../../components/ui/input";
|
||||||
import { SecretInput } from "../../../../components/ui/secret-input";
|
import { SecretInput } from "../../../../components/ui/secret-input";
|
||||||
|
import { Textarea } from "../../../../components/ui/textarea";
|
||||||
|
import { Checkbox } from "../../../../components/ui/checkbox";
|
||||||
import type { RepositoryFormValues } from "../create-repository-form";
|
import type { RepositoryFormValues } from "../create-repository-form";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -74,6 +76,43 @@ export const RestRepositoryForm = ({ form }: Props) => {
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="cacert"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>CA Certificate (Optional)</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Textarea
|
||||||
|
placeholder="-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
|
||||||
|
rows={6}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
Custom CA certificate for self-signed certificates (PEM format). https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html#rest-server
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="insecureTls"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4">
|
||||||
|
<FormControl>
|
||||||
|
<Checkbox checked={field.value ?? false} onCheckedChange={field.onChange} />
|
||||||
|
</FormControl>
|
||||||
|
<div className="space-y-1 leading-none">
|
||||||
|
<FormLabel>Skip TLS Certificate Verification</FormLabel>
|
||||||
|
<FormDescription>
|
||||||
|
Disable TLS certificate verification. This is insecure and should only be used for testing. To trust a self-signed certificate without skipping verification, paste the CA certificate in the CA Certificate field.
|
||||||
|
</FormDescription>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,30 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
|
||||||
{repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"}
|
{repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{repository.type === "rest" && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-muted-foreground">CA Certificate</div>
|
||||||
|
<p className="mt-1 text-sm">
|
||||||
|
{repository.config.cacert ? (
|
||||||
|
<span className="text-green-500">configured</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-muted-foreground">not configured</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-muted-foreground">TLS Certificate Validation</div>
|
||||||
|
<p className="mt-1 text-sm">
|
||||||
|
{repository.config.insecureTls ? (
|
||||||
|
<span className="text-red-500">disabled</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-green-500">enabled</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ export const restRepositoryConfigSchema = type({
|
||||||
username: "string?",
|
username: "string?",
|
||||||
password: "string?",
|
password: "string?",
|
||||||
path: "string?",
|
path: "string?",
|
||||||
|
cacert: "string?",
|
||||||
|
insecureTls: "boolean?",
|
||||||
}).and(baseRepositoryConfigSchema);
|
}).and(baseRepositoryConfigSchema);
|
||||||
|
|
||||||
export const sftpRepositoryConfigSchema = type({
|
export const sftpRepositoryConfigSchema = type({
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ const encryptConfig = async (config: RepositoryConfig): Promise<RepositoryConfig
|
||||||
if (config.password) {
|
if (config.password) {
|
||||||
encryptedConfig.password = await cryptoUtils.sealSecret(config.password);
|
encryptedConfig.password = await cryptoUtils.sealSecret(config.password);
|
||||||
}
|
}
|
||||||
|
if (config.cacert) {
|
||||||
|
encryptedConfig.cacert = await cryptoUtils.sealSecret(config.cacert);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "sftp":
|
case "sftp":
|
||||||
encryptedConfig.privateKey = await cryptoUtils.sealSecret(config.privateKey);
|
encryptedConfig.privateKey = await cryptoUtils.sealSecret(config.privateKey);
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,15 @@ export const buildEnv = async (config: RepositoryConfig) => {
|
||||||
if (config.password) {
|
if (config.password) {
|
||||||
env.RESTIC_REST_PASSWORD = await cryptoUtils.resolveSecret(config.password);
|
env.RESTIC_REST_PASSWORD = await cryptoUtils.resolveSecret(config.password);
|
||||||
}
|
}
|
||||||
|
if (config.cacert) {
|
||||||
|
const decryptedCert = await cryptoUtils.resolveSecret(config.cacert);
|
||||||
|
const certPath = path.join("/tmp", `rest-server-cacert-${crypto.randomBytes(8).toString("hex")}.pem`);
|
||||||
|
await fs.writeFile(certPath, decryptedCert, { mode: 0o600 });
|
||||||
|
env.RESTIC_CACERT = certPath;
|
||||||
|
}
|
||||||
|
if (config.insecureTls) {
|
||||||
|
env._REST_INSECURE_TLS = "true";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "sftp": {
|
case "sftp": {
|
||||||
|
|
@ -876,6 +885,10 @@ export const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record
|
||||||
} else if (config.backend === "gcs" && env.GOOGLE_APPLICATION_CREDENTIALS) {
|
} else if (config.backend === "gcs" && env.GOOGLE_APPLICATION_CREDENTIALS) {
|
||||||
await fs.unlink(env.GOOGLE_APPLICATION_CREDENTIALS).catch(() => {});
|
await fs.unlink(env.GOOGLE_APPLICATION_CREDENTIALS).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.backend === "rest" && env.RESTIC_CACERT) {
|
||||||
|
await fs.unlink(env.RESTIC_CACERT).catch(() => {});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addCommonArgs = (args: string[], env: Record<string, string>) => {
|
export const addCommonArgs = (args: string[], env: Record<string, string>) => {
|
||||||
|
|
@ -884,6 +897,10 @@ export const addCommonArgs = (args: string[], env: Record<string, string>) => {
|
||||||
if (env._SFTP_SSH_ARGS) {
|
if (env._SFTP_SSH_ARGS) {
|
||||||
args.push("-o", `sftp.args=${env._SFTP_SSH_ARGS}`);
|
args.push("-o", `sftp.args=${env._SFTP_SSH_ARGS}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (env._REST_INSECURE_TLS === "true") {
|
||||||
|
args.push("--insecure-tls");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const restic = {
|
export const restic = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue