Files
freeCodeCamp/api/src/plugins/cors.ts
2025-09-19 13:28:06 +05:30

49 lines
1.7 KiB
TypeScript

import { FastifyPluginCallback } from 'fastify';
import fp from 'fastify-plugin';
import { HOME_LOCATION } from '../utils/env.js';
import { allowedOrigins } from '../utils/allowed-origins.js';
const cors: FastifyPluginCallback = (fastify, _options, done) => {
fastify.options('*', (_req, reply) => {
void reply.send();
});
fastify.addHook('onRequest', async (req, reply) => {
const logger = fastify.log.child({ req });
const origin = req.headers.origin;
if (origin && allowedOrigins.includes(origin)) {
logger.debug(`Allowing access to origin: ${origin}`);
void reply.header('Access-Control-Allow-Origin', origin);
} else {
// TODO: Discuss if this is the correct approach. Standard practice is to
// reflect one of a list of allowed origins and handle development
// separately. If we switch to that approach we can replace use
// @fastify/cors instead.
void reply.header('Access-Control-Allow-Origin', HOME_LOCATION);
if (origin && !req.url?.startsWith('/status/')) {
logger.info(`Received request from disallowed origin: ${origin}`);
} else {
logger.debug(`Unknown or missing origin: ${origin}`);
}
}
void reply
.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Csrf-Token, Coderoad-User-Token, Exam-Environment-Authorization-Token'
)
.header('Access-Control-Allow-Credentials', true)
// These 4 are the only methods we use
.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE')
// Vary: Origin to prevent cache poisoning
// TODO: do we need Vary: Accept-Encoding?
.header('Vary', 'Origin, Accept-Encoding');
});
done();
};
export default fp(cors);