fix: remove 302 redirect, serve page directly with embedded token
The previous fix (84e0caa) embedded the token in HTML but still did a
302 redirect on first visit. This meant:
1. Phone opens URL with ?token=xxx
2. Server redirects to / (token stripped from URL)
3. redirected request has no token, buildHTML gets undefined
4. Token never embedded in the page
Also the old code passed the server's secret 'token' variable instead of
the URL parameter 'providedToken' — a security issue.
Fix: Remove the redirect entirely. Serve the HTML page directly on first
visit with Set-Cookie header (no Location redirect). Pass the actual
providedToken from the URL to buildHTML so it gets embedded correctly.
The JS includes the token in the WebSocket URL, so auth works even if
the cookie isn't available.
This commit is contained in:
parent
84e0caa1d3
commit
e15f841036
|
|
@ -103,20 +103,17 @@ export function startServer(pi: ExtensionAPI, ctx: ExtensionContext): Promise<Re
|
|||
return;
|
||||
}
|
||||
|
||||
// If authenticated via token (first visit), issue a session cookie and redirect to clean URL
|
||||
// If authenticated via token (first visit), register a session cookie but serve the
|
||||
// page directly — don't redirect. The token is embedded in the HTML so the JS
|
||||
// can include it in the WebSocket URL. Avoids cookie/redirect issues on mobile.
|
||||
let extraHeaders: Record<string, string> = {};
|
||||
if (!hasValidSession && hasValidToken) {
|
||||
pruneExpiredSessions();
|
||||
const sessionId = generateSessionId();
|
||||
validSessions.set(sessionId, Date.now() + SESSION_TTL_MS);
|
||||
res.writeHead(302, {
|
||||
"Set-Cookie": `${SESSION_COOKIE}=${sessionId}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400`,
|
||||
Location: "/",
|
||||
});
|
||||
res.end();
|
||||
return;
|
||||
extraHeaders["Set-Cookie"] = `${SESSION_COOKIE}=${sessionId}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400`;
|
||||
}
|
||||
|
||||
// Valid session cookie — serve the page
|
||||
const nonce = randomBytes(16).toString("base64");
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/html; charset=utf-8",
|
||||
|
|
@ -125,8 +122,9 @@ export function startServer(pi: ExtensionAPI, ctx: ExtensionContext): Promise<Re
|
|||
"Referrer-Policy": "no-referrer",
|
||||
"Content-Security-Policy":
|
||||
`default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; base-uri 'none'`,
|
||||
...extraHeaders,
|
||||
});
|
||||
res.end(buildHTML(nonce, token));
|
||||
res.end(buildHTML(nonce, hasValidToken ? providedToken : undefined));
|
||||
} else {
|
||||
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
res.end("Not found");
|
||||
|
|
@ -329,16 +327,15 @@ export function startServerTailscale(pi: ExtensionAPI, ctx: ExtensionContext): P
|
|||
return;
|
||||
}
|
||||
|
||||
// If authenticated via token (first visit), register a session cookie but serve the
|
||||
// page directly — don't redirect. The token is embedded in the HTML so the JS
|
||||
// can include it in the WebSocket URL. Avoids cookie/redirect issues on mobile.
|
||||
let extraHeaders: Record<string, string> = {};
|
||||
if (!hasValidSession && hasValidToken) {
|
||||
pruneExpiredSessions();
|
||||
const sessionId = generateSessionId();
|
||||
validSessions.set(sessionId, Date.now() + SESSION_TTL_MS);
|
||||
res.writeHead(302, {
|
||||
"Set-Cookie": `${SESSION_COOKIE}=${sessionId}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400`,
|
||||
Location: "/",
|
||||
});
|
||||
res.end();
|
||||
return;
|
||||
extraHeaders["Set-Cookie"] = `${SESSION_COOKIE}=${sessionId}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400`;
|
||||
}
|
||||
|
||||
const nonce = randomBytes(16).toString("base64");
|
||||
|
|
@ -349,8 +346,9 @@ export function startServerTailscale(pi: ExtensionAPI, ctx: ExtensionContext): P
|
|||
"Referrer-Policy": "no-referrer",
|
||||
"Content-Security-Policy":
|
||||
`default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; base-uri 'none'`,
|
||||
...extraHeaders,
|
||||
});
|
||||
res.end(buildHTML(nonce, token));
|
||||
res.end(buildHTML(nonce, hasValidToken ? providedToken : undefined));
|
||||
} else {
|
||||
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
res.end("Not found");
|
||||
|
|
|
|||
Loading…
Reference in New Issue