headscale: share the invite's https link, drop the deep link

This commit is contained in:
2026-08-06 00:48:45 +00:00
parent 91ed90893d
commit 5f6377ac33
2 changed files with 18 additions and 7 deletions
+14 -2
View File
@@ -95,13 +95,25 @@ async function relay(res: Response | string, wrap: (body: Record<string, unknown
return Response.json(wrap(body));
}
/** `POST /_officer/enroll/invites` — mint an invite. The response carries the link, and only this once. */
/**
* `POST /_officer/enroll/invites` — mint an invite. The response carries the link, and only this once.
*
* `url` is an ordinary HTTPS link to a page on the server's own domain, which bounces into the app; the
* companion also returns `deepLink`, the `officer-offscale://` scheme that page redirects to. That one is
* dropped here rather than passed on: it carries the same claim token in its fragment, and a second copy of
* a single-use credential in the browser is a second chance to leak it. Nothing on our side opens it.
*/
async function create(creds: HeadscaleServerCredentials, ctx: OfficerContext): Promise<Response> {
const input = parseCreate(await readJson(ctx.req));
if (input instanceof Response) return input;
const res = await callCompanion(creds, { path: INVITES_PATH, method: 'POST', body: input });
return relay(res, (body) => ({ available: true, invite: body.invite ?? body }));
return relay(res, (body) => {
const raw = body.invite ?? body;
const invite = raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : {};
const { deepLink: _deepLink, ...rest } = invite;
return { available: true, invite: rest };
});
}
/**