fix(api): honor EXTRA_TRUSTED_ORIGINS in CORS and requestWebOrigin
This commit is contained in:
parent
ac0384e49c
commit
75423579b7
@ -361,7 +361,7 @@ export async function createApp(
|
|||||||
"https://172.*:*",
|
"https://172.*:*",
|
||||||
"http://*.local:*",
|
"http://*.local:*",
|
||||||
"https://*.local:*",
|
"https://*.local:*",
|
||||||
...(process.env.EXTRA_TRUSTED_ORIGINS?.split(",").map((s) => s.trim()) ?? []),
|
...(env.extraTrustedOrigins ?? []),
|
||||||
],
|
],
|
||||||
beforeDeleteUser: async (userId) => {
|
beforeDeleteUser: async (userId) => {
|
||||||
const bots = await prisma.bot.findMany({
|
const bots = await prisma.bot.findMany({
|
||||||
@ -617,7 +617,11 @@ export async function createApp(
|
|||||||
actor,
|
actor,
|
||||||
signal: c.req.raw.signal,
|
signal: c.req.raw.signal,
|
||||||
userAgent: c.req.header("user-agent"),
|
userAgent: c.req.header("user-agent"),
|
||||||
webOrigin: requestWebOrigin(c.req.header("origin"), env.webOrigin),
|
webOrigin: requestWebOrigin(
|
||||||
|
c.req.header("origin"),
|
||||||
|
env.webOrigin,
|
||||||
|
env.extraTrustedOrigins,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (matched) return c.newResponse(response.body, response);
|
if (matched) return c.newResponse(response.body, response);
|
||||||
@ -1027,6 +1031,7 @@ export async function createApp(
|
|||||||
function isTrustedOrigin(origin: string, env: AppEnv) {
|
function isTrustedOrigin(origin: string, env: AppEnv) {
|
||||||
if (!origin) return true;
|
if (!origin) return true;
|
||||||
if (origin === env.webOrigin || origin === env.apiUrl || origin === env.authUrl) return true;
|
if (origin === env.webOrigin || origin === env.apiUrl || origin === env.authUrl) return true;
|
||||||
|
if (env.extraTrustedOrigins?.includes(origin)) return true;
|
||||||
if (origin.startsWith("rakazo://") || origin.startsWith("exp://")) return true;
|
if (origin.startsWith("rakazo://") || origin.startsWith("exp://")) return true;
|
||||||
try {
|
try {
|
||||||
const host = new URL(origin).hostname;
|
const host = new URL(origin).hostname;
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export interface AppEnv {
|
|||||||
authSecret: string;
|
authSecret: string;
|
||||||
authUrl: string;
|
authUrl: string;
|
||||||
webOrigin: string;
|
webOrigin: string;
|
||||||
|
extraTrustedOrigins: string[];
|
||||||
privacyPolicyUrl?: string;
|
privacyPolicyUrl?: string;
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
apiHost: string;
|
apiHost: string;
|
||||||
@ -109,6 +110,10 @@ export function loadEnv(source: NodeJS.ProcessEnv = process.env): AppEnv {
|
|||||||
authSecret,
|
authSecret,
|
||||||
authUrl: source.BETTER_AUTH_URL ?? source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
|
authUrl: source.BETTER_AUTH_URL ?? source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
|
||||||
webOrigin: source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
|
webOrigin: source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
|
||||||
|
extraTrustedOrigins: (source.EXTRA_TRUSTED_ORIGINS ?? "")
|
||||||
|
.split(",")
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter(Boolean),
|
||||||
privacyPolicyUrl: optional(source.PRIVACY_POLICY_URL),
|
privacyPolicyUrl: optional(source.PRIVACY_POLICY_URL),
|
||||||
apiUrl: source.API_URL ?? "http://127.0.0.1:3100",
|
apiUrl: source.API_URL ?? "http://127.0.0.1:3100",
|
||||||
apiHost: source.API_HOST ?? "127.0.0.1",
|
apiHost: source.API_HOST ?? "127.0.0.1",
|
||||||
|
|||||||
@ -25,4 +25,12 @@ describe("requestWebOrigin", () => {
|
|||||||
"https://evoo.example",
|
"https://evoo.example",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepts origins listed in extraTrustedOrigins", () => {
|
||||||
|
expect(
|
||||||
|
requestWebOrigin("https://host.example.ts.net:8443", configured, [
|
||||||
|
"https://host.example.ts.net:8443",
|
||||||
|
]),
|
||||||
|
).toBe("https://host.example.ts.net:8443");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,15 +14,20 @@ export function isLoopbackHost(host: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The web origin that browser-facing URLs (OAuth returns, screen links) should
|
/** The web origin that browser-facing URLs (OAuth returns, screen links) should
|
||||||
* point at for this request. A browser opened over a loopback or private-network
|
* point at for this request. A browser opened over a loopback, private-network,
|
||||||
* address gets its own origin back so a phone on the LAN is not sent to
|
* or explicitly trusted origin gets its own origin back so a phone on the LAN
|
||||||
* 127.0.0.1; any other caller gets the configured WEB_ORIGIN. */
|
* or Tailscale is not sent to 127.0.0.1; any other caller gets WEB_ORIGIN. */
|
||||||
export function requestWebOrigin(origin: string | undefined, webOrigin: string): string {
|
export function requestWebOrigin(
|
||||||
|
origin: string | undefined,
|
||||||
|
webOrigin: string,
|
||||||
|
extraTrustedOrigins: readonly string[] = [],
|
||||||
|
): string {
|
||||||
if (!origin) return webOrigin;
|
if (!origin) return webOrigin;
|
||||||
try {
|
try {
|
||||||
const url = new URL(origin);
|
const url = new URL(origin);
|
||||||
if (url.protocol !== "http:" && url.protocol !== "https:") return webOrigin;
|
if (url.protocol !== "http:" && url.protocol !== "https:") return webOrigin;
|
||||||
if (url.origin === new URL(webOrigin).origin) return url.origin;
|
if (url.origin === new URL(webOrigin).origin) return url.origin;
|
||||||
|
if (extraTrustedOrigins.includes(url.origin)) return url.origin;
|
||||||
return isPrivateOrLocalHost(url.hostname) ? url.origin : webOrigin;
|
return isPrivateOrLocalHost(url.hostname) ? url.origin : webOrigin;
|
||||||
} catch {
|
} catch {
|
||||||
return webOrigin;
|
return webOrigin;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user