fix: decrypt volume config before trying to mount volume
This commit is contained in:
parent
89d347cbc7
commit
deedf2a203
4 changed files with 25 additions and 21 deletions
|
|
@ -32,3 +32,7 @@ export const mapVolumeConfigSecrets = async (
|
|||
export const encryptVolumeConfig = async (config: BackendConfig): Promise<BackendConfig> => {
|
||||
return await mapVolumeConfigSecrets(config, cryptoUtils.sealSecret);
|
||||
};
|
||||
|
||||
export const decryptVolumeConfig = async (config: BackendConfig): Promise<BackendConfig> => {
|
||||
return await mapVolumeConfigSecrets(config, cryptoUtils.resolveSecret);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { volumeConfigSchema, type BackendConfig } from "~/schemas/volumes";
|
|||
import { getOrganizationId } from "~/server/core/request-context";
|
||||
import { isNodeJSErrnoException } from "~/server/utils/fs";
|
||||
import { asShortId, type ShortId } from "~/server/utils/branded";
|
||||
import { encryptVolumeConfig } from "./volume-config-secrets";
|
||||
import { decryptVolumeConfig, encryptVolumeConfig } from "./volume-config-secrets";
|
||||
|
||||
type EnsureHealthyVolumeResult =
|
||||
| {
|
||||
|
|
@ -80,7 +80,7 @@ const createVolume = async (name: string, backendConfig: BackendConfig) => {
|
|||
throw new InternalServerError("Failed to create volume");
|
||||
}
|
||||
|
||||
const backend = createVolumeBackend(created);
|
||||
const backend = createVolumeBackend({ ...created, config: await decryptVolumeConfig(created.config) });
|
||||
const { error, status } = await backend.mount();
|
||||
|
||||
await db
|
||||
|
|
@ -114,7 +114,7 @@ const mountVolume = async (shortId: ShortId) => {
|
|||
throw new NotFoundError("Volume not found");
|
||||
}
|
||||
|
||||
const backend = createVolumeBackend(volume);
|
||||
const backend = createVolumeBackend({ ...volume, config: await decryptVolumeConfig(volume.config) });
|
||||
await backend.unmount();
|
||||
const { error, status } = await backend.mount();
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ const updateVolume = async (shortId: ShortId, volumeData: UpdateVolumeBody) => {
|
|||
}
|
||||
|
||||
if (configChanged) {
|
||||
const backend = createVolumeBackend(updated);
|
||||
const backend = createVolumeBackend({ ...updated, config: await decryptVolumeConfig(updated.config) });
|
||||
const { error, status } = await backend.mount();
|
||||
await db
|
||||
.update(volumesTable)
|
||||
|
|
@ -235,18 +235,16 @@ const updateVolume = async (shortId: ShortId, volumeData: UpdateVolumeBody) => {
|
|||
const testConnection = async (backendConfig: BackendConfig) => {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "zerobyte-test-"));
|
||||
try {
|
||||
const encryptedConfig = await encryptVolumeConfig(backendConfig);
|
||||
|
||||
const mockVolume = {
|
||||
id: 0,
|
||||
shortId: asShortId("test"),
|
||||
name: "test-connection",
|
||||
path: tempDir,
|
||||
config: encryptedConfig,
|
||||
config: backendConfig,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
lastHealthCheck: Date.now(),
|
||||
type: encryptedConfig.backend,
|
||||
type: backendConfig.backend,
|
||||
status: "unmounted" as const,
|
||||
lastError: null,
|
||||
provisioningId: null,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import * as fs from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { spawn } from "node:child_process";
|
||||
|
|
@ -10,8 +11,9 @@ import { withTimeout } from "../timeout";
|
|||
import type { BackendConfig, VolumeBackend } from "../types";
|
||||
import { executeUnmount } from "./utils";
|
||||
|
||||
const getPrivateKeyPath = (mountPath: string) => path.join(SSH_KEYS_DIR, `${path.basename(mountPath)}.key`);
|
||||
const getKnownHostsPath = (mountPath: string) => path.join(SSH_KEYS_DIR, `${path.basename(mountPath)}.known_hosts`);
|
||||
const getMountPathHash = (mountPath: string) => createHash("sha256").update(mountPath).digest("hex").slice(0, 16);
|
||||
const getPrivateKeyPath = (mountPath: string) => path.join(SSH_KEYS_DIR, `${getMountPathHash(mountPath)}.key`);
|
||||
const getKnownHostsPath = (mountPath: string) => path.join(SSH_KEYS_DIR, `${getMountPathHash(mountPath)}.known_hosts`);
|
||||
|
||||
const runSshfs = async (args: string[], password?: string) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
|
|
@ -138,7 +140,6 @@ const mount = async (config: BackendConfig, mountPath: string) => {
|
|||
|
||||
const args = [`${config.username}@${config.host}:${config.path || ""}`, mountPath, "-o", options.join(",")];
|
||||
if (config.password) args.push("-o", "password_stdin");
|
||||
|
||||
logger.info(`Executing sshfs: sshfs ${args.join(" ")}`);
|
||||
await runSshfs(args, config.password);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,18 +16,19 @@ export const listVolumeFiles = async (
|
|||
) => {
|
||||
const volumePath = getVolumePath(volume);
|
||||
const requestedPath = subPath ? path.join(volumePath, subPath) : volumePath;
|
||||
const normalizedPath = path.normalize(requestedPath);
|
||||
const relative = path.relative(volumePath, normalizedPath);
|
||||
|
||||
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
||||
throw new Error("Invalid path");
|
||||
}
|
||||
|
||||
const pageSize = Math.min(Math.max(limit, 1), MAX_PAGE_SIZE);
|
||||
const startOffset = Math.max(offset, 0);
|
||||
|
||||
try {
|
||||
const dirents = await fs.readdir(normalizedPath, { withFileTypes: true });
|
||||
const realVolumeRoot = await fs.realpath(volumePath);
|
||||
const realRequestedPath = await fs.realpath(requestedPath);
|
||||
const relative = path.relative(realVolumeRoot, realRequestedPath);
|
||||
|
||||
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
||||
throw new Error("Invalid path");
|
||||
}
|
||||
|
||||
const dirents = await fs.readdir(realRequestedPath, { withFileTypes: true });
|
||||
|
||||
dirents.sort((a, b) => {
|
||||
const aIsDir = a.isDirectory();
|
||||
|
|
@ -45,11 +46,11 @@ export const listVolumeFiles = async (
|
|||
const entries = (
|
||||
await Promise.all(
|
||||
paginatedDirents.map(async (dirent) => {
|
||||
const fullPath = path.join(normalizedPath, dirent.name);
|
||||
const fullPath = path.join(realRequestedPath, dirent.name);
|
||||
|
||||
try {
|
||||
const stats = await fs.stat(fullPath);
|
||||
const relativePath = path.relative(volumePath, fullPath);
|
||||
const relativePath = path.relative(realVolumeRoot, fullPath);
|
||||
|
||||
return {
|
||||
name: dirent.name,
|
||||
|
|
|
|||
Loading…
Reference in a new issue