From 754fac42bba8a0fe1fc616fc3437b56413b48e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 30 Jul 2026 05:09:13 +0000 Subject: [PATCH] stop reading the owner's vnc password in the main process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The password lives in the owner's ~/.vnc, and the sidecar is the process that writes it — together with the rfbauth file x11vnc actually authenticates against. Officer read the plaintext half directly and answered with it before ever asking the sidecar, which is both a secret the proxy has no business opening and a way to hand out a password that no longer matches: if `passwd` went missing while `password` survived, officer kept serving the old plaintext and the desktop refused every login. `vnc:ensure-password` reconciles the pair, so ask it every time and delete the reader. Co-Authored-By: Claude Opus 4.8 --- src/servers/api/desktop/rest.ts | 12 ++++++------ src/servers/api/desktop/vnc-config.ts | 10 ---------- 2 files changed, 6 insertions(+), 16 deletions(-) delete mode 100644 src/servers/api/desktop/vnc-config.ts diff --git a/src/servers/api/desktop/rest.ts b/src/servers/api/desktop/rest.ts index 3cac087a..671b06a3 100644 --- a/src/servers/api/desktop/rest.ts +++ b/src/servers/api/desktop/rest.ts @@ -1,19 +1,19 @@ import { createRouter } from '../../create-router'; -import { getVncPassword } from './vnc-config'; import * as sidecar from '@@/sidecar-registry'; export const desktopRouter = createRouter(); // The desktop UI asks for the password before it can open the WebSocket — and that WebSocket is what // starts the VNC session. So this cannot wait for a session to exist: on a fresh install nothing has -// ever written the password, and answering "not configured" deadlocked the page permanently. Ask the -// sidecar to provision it instead; it owns the .vnc directory and the call is idempotent. +// ever written the password, and answering "not configured" deadlocked the page permanently. +// +// Officer does not read the password file itself. It lives in the owner's ~/.vnc, next to the rfbauth +// file x11vnc authenticates against, and the sidecar is the process that writes both — so it is the +// process that answers for them too. `vnc:ensure-password` is idempotent: it returns the existing +// pair when both files are already there, and provisions them when they are not. desktopRouter.get('/vnc-password', async (ctx) => { const user = ctx.get('user'); - const existing = await getVncPassword(user.email); - if (existing) return ctx.json({ password: existing }); - if (!sidecar.isVncConnected()) { return ctx.json({ error: 'VNC sidecar is not connected' }, 503); } diff --git a/src/servers/api/desktop/vnc-config.ts b/src/servers/api/desktop/vnc-config.ts deleted file mode 100644 index f808255f..00000000 --- a/src/servers/api/desktop/vnc-config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { join } from 'node:path'; -import { getOwnerHomeDir } from '@@/data-path'; - -const getVncDir = (email: string): string => join(getOwnerHomeDir(email), '.vnc'); - -export async function getVncPassword(email: string): Promise { - const file = Bun.file(join(getVncDir(email), 'password')); - if (!(await file.exists())) return null; - return (await file.text()).trim(); -}