refactor(sftp-backend): use node spawn to properly send password stdin instead of echo
Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
This commit is contained in:
parent
0e5438897c
commit
ffc43e0c25
2 changed files with 44 additions and 11 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { $ } from "bun";
|
||||
import { spawn } from "node:child_process";
|
||||
import { OPERATION_TIMEOUT } from "../../../core/constants";
|
||||
import { cryptoUtils } from "../../../utils/crypto";
|
||||
import { toMessage } from "../../../utils/errors";
|
||||
|
|
@ -93,20 +93,52 @@ const mount = async (config: BackendConfig, mountPath: string) => {
|
|||
|
||||
logger.debug(`Mounting SFTP volume ${mountPath}...`);
|
||||
|
||||
let result: $.ShellOutput;
|
||||
const runSshfs = async (mountArgs: string[], password?: string) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const child = spawn("sshfs", mountArgs, { stdio: ["pipe", "pipe", "pipe"] });
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stderr.setEncoding("utf8");
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
stdout += data;
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
stderr += data;
|
||||
});
|
||||
|
||||
child.on("error", (error) => {
|
||||
reject(new Error(`Failed to start sshfs: ${error.message}`));
|
||||
});
|
||||
|
||||
child.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const errorMsg = stderr.trim() || stdout.trim() || "Unknown error";
|
||||
reject(new Error(`Failed to mount SFTP volume: ${errorMsg}`));
|
||||
});
|
||||
|
||||
if (password) {
|
||||
child.stdin.write(password);
|
||||
}
|
||||
child.stdin.end();
|
||||
});
|
||||
};
|
||||
|
||||
if (config.password) {
|
||||
const password = await cryptoUtils.resolveSecret(config.password);
|
||||
args.push("-o", "password_stdin");
|
||||
logger.info(`Executing sshfs: echo "******" | sshfs ${args.join(" ")}`);
|
||||
result = await $`echo ${password} | sshfs ${args}`.nothrow();
|
||||
logger.info(`Executing sshfs: sshfs ${args.join(" ")}`);
|
||||
await runSshfs(args, password);
|
||||
} else {
|
||||
logger.info(`Executing sshfs: sshfs ${args.join(" ")}`);
|
||||
result = await $`sshfs ${args}`.nothrow();
|
||||
}
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
const errorMsg = result.stderr.toString() || result.stdout.toString() || "Unknown error";
|
||||
throw new Error(`Failed to mount SFTP volume: ${errorMsg}`);
|
||||
await runSshfs(args);
|
||||
}
|
||||
|
||||
logger.info(`SFTP volume at ${mountPath} mounted successfully.`);
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ const mount = async (config: BackendConfig, path: string) => {
|
|||
if (config.username && config.password) {
|
||||
const password = await cryptoUtils.resolveSecret(config.password);
|
||||
const secretsFile = "/etc/davfs2/secrets";
|
||||
const secretsContent = `${source} ${config.username} ${password}\n`;
|
||||
const entry = [source, config.username, password].map((value) => value.replace(/[\r\n\t\s]+/g, " ")).join(" ");
|
||||
const secretsContent = `${entry}\n`;
|
||||
await fs.appendFile(secretsFile, secretsContent, { mode: 0o600 });
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue