diff --git a/Makefile b/Makefile index bee23e3a..3892e689 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ test: export DATABASE_URL=$(LOCAL_DB) test: export NEVER_LOAD_DOTENV=1 test: export UNSAFE_SKIP_AUTH=1 test: export FIREBASE_PROJECT_ID=mock-proj +test: export CORS_ALLOW_ORIGINS=http://localhost:3000,https://localhost:5173 test: dev-db cd server/src; ENV_FILE=../.env.dev bun test cd ./test; ENV_FILE=../server/.env.dev bun test diff --git a/server/.env.sample b/server/.env.sample index bb0e5bca..55763721 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -3,10 +3,8 @@ # below can be used for docker db created via `make dev-db` DATABASE_URL=postgres://user:password@localhost:5432/database -# Application origins -SERVER_ORIGIN=http://localhost:3000 -WEB_ORIGIN=http://localhost:5173 -MOBILE_ORIGIN=http://localhost:8081 +# CORS allow origins, separated by "," | no space is allowed before/after "," +CORS_ALLOW_ORIGINS=http://localhost:3000,http://localhost:5173 # Firebase FIREBASE_PROJECT_ID=project-id diff --git a/server/src/index.ts b/server/src/index.ts index de19b304..a32aa9e2 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -3,6 +3,7 @@ import express from "express"; import csrf from "./lib/cross-origin/block-unknown-origin"; import cors from "./lib/cross-origin/multi-origin-cors"; import { initializeSocket } from "./lib/socket/socket"; +import { allUrlMustBeValid, panic } from "./lib/utils"; import chatRoutes from "./router/chat"; import coursesRoutes from "./router/courses"; import matchesRoutes from "./router/matches"; @@ -17,14 +18,15 @@ const app = express(); app.set("query parser", "simple"); const port = 3000; -const allowedOrigins = [ - process.env.SERVER_ORIGIN ?? "http://localhost:3000", // delete this fallback when you think everyone has updated their .env - process.env.WEB_ORIGIN, - process.env.MOBILE_ORIGIN, - process.env.WEB_ORIGIN_BUILD, -]; +const allowedOrigins = ( + process.env.CORS_ALLOW_ORIGINS || panic("env CORS_ALLOW_ORIGINS is missing") +) + .split(",") + .filter((s) => s); // ignore empty string (trailing comma?) +allUrlMustBeValid(allowedOrigins); + export const corsOptions = { - origins: allowedOrigins.filter((s) => s != null).filter((s) => s), // ignore empty string too + origins: allowedOrigins, methods: ["GET", "HEAD", "POST", "PUT", "DELETE"], credentials: true, }; diff --git a/server/src/lib/utils.ts b/server/src/lib/utils.ts new file mode 100644 index 00000000..8eddd99d --- /dev/null +++ b/server/src/lib/utils.ts @@ -0,0 +1,14 @@ +export function panic(reason: string): never { + throw new Error(`function panic() called for reason: "${reason}"`); +} + +export function allUrlMustBeValid(urls: string[]) { + for (const url of urls) { + try { + new URL(url); + } catch (err) { + console.error(err); + throw err; + } + } +}