mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 18:31:33 +00:00
fix: make RDP drive redirection writable on the stock deployment (#1333)
* fix: make RDP drive redirection writable on the stock deployment The default drive-path was /drive on the guacd side, which the official guacd image cannot create as its non-root user, so every upload was refused with guacd's raw "FAIL (CANNOT OPEN)" ack. Default to GUACD_DRIVE_PATH (set to the shared termix-data volume in compose) with one folder per user, and explain guacd's refusal in the file browser. * style: format RDP drive settings
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
parentPath,
|
||||
saveBlobAs,
|
||||
uploadFile,
|
||||
describeUploadError,
|
||||
type RemoteFileEntry,
|
||||
} from "./guacamole-filesystem.ts";
|
||||
|
||||
@@ -76,9 +77,9 @@ export function GuacamoleFileBrowser({
|
||||
toast.success(t("guacamole.files.uploaded", { name: file.name }));
|
||||
} catch (err) {
|
||||
toast.error(
|
||||
err instanceof Error
|
||||
? err.message
|
||||
: t("guacamole.files.uploadFailed", { name: file.name }),
|
||||
describeUploadError(err, (key) =>
|
||||
t(`guacamole.files.${key}`, { name: file.name }),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
setBusyName(null);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describeUploadError } from "./guacamole-filesystem";
|
||||
|
||||
const t = (key: string) => `#${key}`;
|
||||
|
||||
describe("describeUploadError", () => {
|
||||
it("explains guacd's refusal to open the target file as a drive-folder problem", () => {
|
||||
expect(describeUploadError(new Error("FAIL (CANNOT OPEN)"), t)).toBe(
|
||||
"#driveNotWritable",
|
||||
);
|
||||
expect(describeUploadError(new Error("FAIL (NO FS)"), t)).toBe(
|
||||
"#driveUnavailable",
|
||||
);
|
||||
});
|
||||
|
||||
it("passes other messages through and falls back for unknown errors", () => {
|
||||
expect(describeUploadError(new Error("disk full"), t)).toBe("disk full");
|
||||
expect(describeUploadError(undefined, t)).toBe("#uploadFailed");
|
||||
});
|
||||
});
|
||||
@@ -163,3 +163,22 @@ export function saveBlobAs(blob: Blob, filename: string): void {
|
||||
link.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns an upload failure into something a user can act on. guacd answers a
|
||||
* refused stream with an ack like "FAIL (CANNOT OPEN)" - accurate, but it
|
||||
* means "the drive folder isn't writable", which is what people need to hear.
|
||||
*/
|
||||
export function describeUploadError(
|
||||
error: unknown,
|
||||
t: (key: "driveNotWritable" | "driveUnavailable" | "uploadFailed") => string,
|
||||
): string {
|
||||
const message = error instanceof Error ? error.message : "";
|
||||
if (/cannot open|can't open|permission denied/i.test(message)) {
|
||||
return t("driveNotWritable");
|
||||
}
|
||||
if (/no fs/i.test(message)) {
|
||||
return t("driveUnavailable");
|
||||
}
|
||||
return message || t("uploadFailed");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user