setup: Ubuntu GNOME-on-Xorg desktop + setup.sh hardening
setup-desktop.sh now installs ubuntu-desktop + gdm3 + x11vnc and forces the Xorg session (WaylandEnable=false) with auto-login — x11vnc can only mirror an Xorg :0, not Wayland. vnc-manager.ts resolves the X authority from the GDM per-session path (/run/user/<uid>/gdm/Xauthority) with a ~/.Xauthority fallback. setup.sh fixes: - desktop step gates on `dpkg -s ubuntu-desktop` (was the decommissioned officer-vnc service, which never matched so setup-desktop re-ran every time) - remove Pi (install, --list-models validation, verification check) - export GOPATH before the cliamp build so `go install` lands where it's checked even when Go was already present this run - write PUBLIC_BUILD_ENV=production and quote all .env values - guard the interactive .env block behind a TTY check so non-interactive runs skip cleanly instead of aborting on read EOF under set -e - restart systemd-logind only when a key actually changed - sed prefix-strip instead of `tr -d` (which deletes characters, not a prefix) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,19 @@ const MIRROR_DISPLAY_NUM = 0;
|
||||
const MIRROR_PORT = 5900;
|
||||
const READY_TIMEOUT_MS = 5000;
|
||||
|
||||
// x11vnc reads :0's cookie from the logged-in user's own .Xauthority, so no root is needed.
|
||||
// While the greeter owns :0 the cookie lives in lightdm's file instead and mirroring fails.
|
||||
const XAUTHORITY = join(process.env.HOME ?? '', '.Xauthority');
|
||||
// x11vnc reads :0's cookie from the logged-in user's X authority, so no root is needed. Where that
|
||||
// cookie lives depends on the display manager: GDM (Ubuntu GNOME on Xorg) keeps it in the per-session
|
||||
// dir /run/user/<uid>/gdm/Xauthority; LightDM (or a manual startx) uses the classic ~/.Xauthority. Try
|
||||
// the GDM path first, then fall back. While the greeter owns :0 the user's cookie doesn't exist yet and
|
||||
// mirroring fails until someone is logged in.
|
||||
function resolveXauthority(): string | null {
|
||||
const uid = typeof process.getuid === 'function' ? process.getuid() : null;
|
||||
const candidates = [
|
||||
uid != null ? `/run/user/${uid}/gdm/Xauthority` : null,
|
||||
join(process.env.HOME ?? '', '.Xauthority'),
|
||||
].filter((p): p is string => Boolean(p));
|
||||
return candidates.find((p) => existsSync(p)) ?? null;
|
||||
}
|
||||
|
||||
type MirrorSession = {
|
||||
email: string;
|
||||
@@ -99,8 +109,9 @@ export async function startSession(params: VncStartParams): Promise<{ port: numb
|
||||
const homeDir = getHomeDirForRole(params.email, params.role);
|
||||
const passwdFile = await ensureVncPassword(homeDir);
|
||||
|
||||
if (!existsSync(XAUTHORITY)) {
|
||||
throw new Error(`No X authority at ${XAUTHORITY} — nobody is logged in on ${MIRROR_DISPLAY}`);
|
||||
const xauthority = resolveXauthority();
|
||||
if (!xauthority) {
|
||||
throw new Error(`No X authority found (GDM or ~/.Xauthority) — nobody is logged in on ${MIRROR_DISPLAY}`);
|
||||
}
|
||||
|
||||
const proc = Bun.spawn({
|
||||
@@ -109,7 +120,7 @@ export async function startSession(params: VncStartParams): Promise<{ port: numb
|
||||
'-display',
|
||||
MIRROR_DISPLAY,
|
||||
'-auth',
|
||||
XAUTHORITY,
|
||||
xauthority,
|
||||
'-rfbport',
|
||||
String(MIRROR_PORT),
|
||||
'-rfbauth',
|
||||
|
||||
Reference in New Issue
Block a user