feat(FN-2930): merge fusion/fn-2930

- test(FN-2930): complete Step 2 — add auth redirect rewrite coverage
- feat(FN-2930): complete Step 1 — rewrite OAuth redirect_uri host
- feat(FN-2928): merge fusion/fn-2928

Fusion-Task-Id: FN-2930
This commit is contained in:
Fusion
2026-04-29 00:44:33 -07:00
committed by gsxdsm
parent 43c5d91c0a
commit f04333672c
2 changed files with 125 additions and 1 deletions

View File

@@ -37,6 +37,50 @@ export const registerAuthRoutes: ApiRouteRegistrar = (ctx) => {
*/
const loginInProgress = new Map<string, AbortController>();
function isSecureRequest(req: { secure?: boolean; headers?: Record<string, string | string[] | undefined> }): boolean {
const forwardedProto = req.headers?.["x-forwarded-proto"];
const normalizedProto = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
return Boolean(req.secure) || normalizedProto === "https";
}
function rewriteRedirectUri(authUrl: string, reqHost: string, secure: boolean): string {
const trimmedHost = reqHost.trim();
if (!trimmedHost) {
return authUrl;
}
let authUrlObj: URL;
try {
authUrlObj = new URL(authUrl);
} catch {
return authUrl;
}
const redirectUri = authUrlObj.searchParams.get("redirect_uri");
if (!redirectUri) {
return authUrl;
}
let redirectUriUrl: URL;
try {
redirectUriUrl = new URL(redirectUri);
} catch {
return authUrl;
}
if (redirectUriUrl.hostname !== "localhost" && redirectUriUrl.hostname !== "127.0.0.1") {
return authUrl;
}
const hostUrl = new URL(`http://${trimmedHost}`);
redirectUriUrl.hostname = hostUrl.hostname;
redirectUriUrl.port = hostUrl.port;
redirectUriUrl.protocol = secure ? "https:" : "http:";
authUrlObj.searchParams.set("redirect_uri", redirectUriUrl.toString());
return authUrlObj.toString();
}
/**
* GET /api/auth/status
* Returns list of all providers with their authentication status and type.
@@ -325,7 +369,11 @@ export const registerAuthRoutes: ApiRouteRegistrar = (ctx) => {
const authInfo = await authUrlPromise;
clearTimeout(timeout);
res.json({ url: authInfo.url, instructions: authInfo.instructions });
const reqHost = req.get("host");
const rewrittenUrl = reqHost ? rewriteRedirectUri(authInfo.url, reqHost, isSecureRequest(req)) : authInfo.url;
res.json({ url: rewrittenUrl, instructions: authInfo.instructions });
} catch (err: unknown) {
if (err instanceof ApiError) {
throw err;