diff --git a/pages/api/graphql.js b/pages/api/graphql.js index ca01363..0a90711 100644 --- a/pages/api/graphql.js +++ b/pages/api/graphql.js @@ -10,6 +10,7 @@ const beeline = require("honeycomb-beeline")({ const { ApolloServer } = require("../../src/server/lib/apollo-server-vercel"); const { config } = require("../../src/server"); +const { applyCORSHeaders } = require("../../src/server/cors"); const crypto = require("crypto"); const server = new ApolloServer(config); @@ -48,13 +49,13 @@ function deterministicSampler(traceId, sampleRate) { } async function handle(req, res) { - // CAREFUL! We here allow any website to use our GraphQL API, so our data can - // be more useful to the public. Using the * wildcard means that, in modern - // browsers, requests should be sent without credentials. Additionally, we - // don't store credentials in cookies; the client is responsible for setting - // an Authorization header. So, I don't think there's any CSRF danger here. - // But, let's be careful and make sure this continues to be true! - res.setHeader("Access-Control-Allow-Origin", "*"); + // Apply CORS headers, to allow Classic DTI to request this. + // If this is an OPTIONS request asking for CORS info, return an empty + // response with just the CORS headers applied. + applyCORSHeaders(req, res); + if (req.method === "OPTIONS") { + return res.status(204).end(); + } await serverHandler(req, res); diff --git a/pages/api/validPetPoses.js b/pages/api/validPetPoses.js index 6014825..2f3838f 100644 --- a/pages/api/validPetPoses.js +++ b/pages/api/validPetPoses.js @@ -6,6 +6,7 @@ const beeline = require("honeycomb-beeline")({ : "Dress to Impress (2020, dev)", serviceName: "impress-2020-gql-server", }); +import { applyCORSHeaders } from "../../src/server/cors"; import connectToDb from "../../src/server/db"; import { getPoseFromPetState, normalizeRow } from "../../src/server/util"; @@ -103,6 +104,14 @@ async function getDistinctPetStates(db) { } async function handle(req, res) { + // Apply CORS headers, to allow Classic DTI to request this. + // If this is an OPTIONS request asking for CORS info, return an empty + // response with just the CORS headers applied. + applyCORSHeaders(req, res); + if (req.method === "OPTIONS") { + return res.status(204).end(); + } + const buffer = await getValidPetPoses(); // Cache for 1 hour, and allow the CDN cache to serve copies up to an diff --git a/src/server/cors.js b/src/server/cors.js new file mode 100644 index 0000000..2f0bd74 --- /dev/null +++ b/src/server/cors.js @@ -0,0 +1,14 @@ +const ALLOWED_CORS_ORIGINS = [ + "https://beta.impress.openneo.net", + "https://impress.openneo.net", + "http://localhost:3000", +]; + +export function applyCORSHeaders(req, res) { + const origin = req.headers["origin"]; + if (ALLOWED_CORS_ORIGINS.includes(origin)) { + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Methods", "*"); + res.setHeader("Access-Control-Allow-Headers", "*"); + } +}