mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat: add support for REST server
This commit is contained in:
@@ -41,6 +41,7 @@ const defaultValuesForType = {
|
|||||||
gcs: { backend: "gcs" as const, compressionMode: "auto" as const },
|
gcs: { backend: "gcs" as const, compressionMode: "auto" as const },
|
||||||
azure: { backend: "azure" as const, compressionMode: "auto" as const },
|
azure: { backend: "azure" as const, compressionMode: "auto" as const },
|
||||||
rclone: { backend: "rclone" as const, compressionMode: "auto" as const },
|
rclone: { backend: "rclone" as const, compressionMode: "auto" as const },
|
||||||
|
rest: { backend: "rest" as const, compressionMode: "auto" as const },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateRepositoryForm = ({
|
export const CreateRepositoryForm = ({
|
||||||
@@ -126,6 +127,7 @@ export const CreateRepositoryForm = ({
|
|||||||
<SelectItem value="r2">Cloudflare R2</SelectItem>
|
<SelectItem value="r2">Cloudflare R2</SelectItem>
|
||||||
<SelectItem value="gcs">Google Cloud Storage</SelectItem>
|
<SelectItem value="gcs">Google Cloud Storage</SelectItem>
|
||||||
<SelectItem value="azure">Azure Blob Storage</SelectItem>
|
<SelectItem value="azure">Azure Blob Storage</SelectItem>
|
||||||
|
<SelectItem value="rest">REST Server</SelectItem>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<SelectItem disabled={!capabilities.rclone} value="rclone">
|
<SelectItem disabled={!capabilities.rclone} value="rclone">
|
||||||
@@ -546,6 +548,67 @@ export const CreateRepositoryForm = ({
|
|||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{watchedBackend === "rest" && (
|
||||||
|
<>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="url"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>REST Server URL</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="http://192.168.1.30:8000" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>URL of the REST server.</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="path"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Repository Path (Optional)</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="my-backup-repo" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Path to the repository on the REST server (leave empty for root).</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="username"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Username (Optional)</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="username" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Username for REST server authentication.</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="password"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Password (Optional)</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input type="password" placeholder="••••••••" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Password for REST server authentication.</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{mode === "update" && (
|
{mode === "update" && (
|
||||||
<Button type="submit" className="w-full" loading={loading}>
|
<Button type="submit" className="w-full" loading={loading}>
|
||||||
Save Changes
|
Save Changes
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Database, HardDrive, Cloud } from "lucide-react";
|
import { Database, HardDrive, Cloud, Server } from "lucide-react";
|
||||||
import type { RepositoryBackend } from "~/schemas/restic";
|
import type { RepositoryBackend } from "~/schemas/restic";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -14,6 +14,8 @@ export const RepositoryIcon = ({ backend, className = "h-4 w-4" }: Props) => {
|
|||||||
return <Cloud className={className} />;
|
return <Cloud className={className} />;
|
||||||
case "gcs":
|
case "gcs":
|
||||||
return <Cloud className={className} />;
|
return <Cloud className={className} />;
|
||||||
|
case "rest":
|
||||||
|
return <Server className={className} />;
|
||||||
default:
|
default:
|
||||||
return <Database className={className} />;
|
return <Database className={className} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const REPOSITORY_BACKENDS = {
|
|||||||
gcs: "gcs",
|
gcs: "gcs",
|
||||||
azure: "azure",
|
azure: "azure",
|
||||||
rclone: "rclone",
|
rclone: "rclone",
|
||||||
|
rest: "rest",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type RepositoryBackend = keyof typeof REPOSITORY_BACKENDS;
|
export type RepositoryBackend = keyof typeof REPOSITORY_BACKENDS;
|
||||||
@@ -59,12 +60,21 @@ export const rcloneRepositoryConfigSchema = type({
|
|||||||
path: "string",
|
path: "string",
|
||||||
}).and(baseRepositoryConfigSchema);
|
}).and(baseRepositoryConfigSchema);
|
||||||
|
|
||||||
|
export const restRepositoryConfigSchema = type({
|
||||||
|
backend: "'rest'",
|
||||||
|
url: "string",
|
||||||
|
username: "string?",
|
||||||
|
password: "string?",
|
||||||
|
path: "string?",
|
||||||
|
}).and(baseRepositoryConfigSchema);
|
||||||
|
|
||||||
export const repositoryConfigSchema = s3RepositoryConfigSchema
|
export const repositoryConfigSchema = s3RepositoryConfigSchema
|
||||||
.or(r2RepositoryConfigSchema)
|
.or(r2RepositoryConfigSchema)
|
||||||
.or(localRepositoryConfigSchema)
|
.or(localRepositoryConfigSchema)
|
||||||
.or(gcsRepositoryConfigSchema)
|
.or(gcsRepositoryConfigSchema)
|
||||||
.or(azureRepositoryConfigSchema)
|
.or(azureRepositoryConfigSchema)
|
||||||
.or(rcloneRepositoryConfigSchema);
|
.or(rcloneRepositoryConfigSchema)
|
||||||
|
.or(restRepositoryConfigSchema);
|
||||||
|
|
||||||
export type RepositoryConfig = typeof repositoryConfigSchema.infer;
|
export type RepositoryConfig = typeof repositoryConfigSchema.infer;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ const encryptConfig = async (config: RepositoryConfig): Promise<RepositoryConfig
|
|||||||
case "azure":
|
case "azure":
|
||||||
encryptedConfig.accountKey = await cryptoUtils.encrypt(config.accountKey);
|
encryptedConfig.accountKey = await cryptoUtils.encrypt(config.accountKey);
|
||||||
break;
|
break;
|
||||||
|
case "rest":
|
||||||
|
if (config.username) {
|
||||||
|
encryptedConfig.username = await cryptoUtils.encrypt(config.username);
|
||||||
|
}
|
||||||
|
if (config.password) {
|
||||||
|
encryptedConfig.password = await cryptoUtils.encrypt(config.password);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return encryptedConfig as RepositoryConfig;
|
return encryptedConfig as RepositoryConfig;
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ const buildRepoUrl = (config: RepositoryConfig): string => {
|
|||||||
return `azure:${config.container}:/`;
|
return `azure:${config.container}:/`;
|
||||||
case "rclone":
|
case "rclone":
|
||||||
return `rclone:${config.remote}:${config.path}`;
|
return `rclone:${config.remote}:${config.path}`;
|
||||||
|
case "rest": {
|
||||||
|
const path = config.path ? `/${config.path}` : "";
|
||||||
|
return `rest:${config.url}${path}`;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error(`Unsupported repository backend: ${JSON.stringify(config)}`);
|
throw new Error(`Unsupported repository backend: ${JSON.stringify(config)}`);
|
||||||
}
|
}
|
||||||
@@ -133,6 +137,15 @@ const buildEnv = async (config: RepositoryConfig) => {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "rest": {
|
||||||
|
if (config.username) {
|
||||||
|
env.RESTIC_REST_USERNAME = await cryptoUtils.decrypt(config.username);
|
||||||
|
}
|
||||||
|
if (config.password) {
|
||||||
|
env.RESTIC_REST_PASSWORD = await cryptoUtils.decrypt(config.password);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
|
|||||||
Reference in New Issue
Block a user