Skip to content

Conversation

@n3rdc4ptn
Copy link
Member

Is based on the branch of the PR #359

closes #359

@n3rdc4ptn n3rdc4ptn marked this pull request as ready for review November 10, 2025 08:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds CORS (Cross-Origin Resource Sharing) support to the Fastify server, introduces additional Content Security Policy (CSP) directives, and configures HSTS (HTTP Strict Transport Security). The changes aim to improve security by properly controlling cross-origin requests and enforcing HTTPS connections.

  • Adds @fastify/cors plugin with configurable allowed origins
  • Introduces new environment variable ALLOWED_CORS_ORIGINS for CORS configuration
  • Enhances CSP with explicit defaultSrc, styleSrc, and imgSrc directives
  • Configures HSTS with 1-year max-age and subdomain inclusion
  • Disables sourcemaps in production builds

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
server.ts Adds CORS plugin registration with origin validation, enhances CSP directives, and configures HSTS
server/config/env.ts Adds ALLOWED_CORS_ORIGINS to the environment schema
package.json Adds @fastify/cors dependency version 11.1.0
package-lock.json Includes lock file entry for @fastify/cors dependency
.env.template Documents the new ALLOWED_CORS_ORIGINS configuration option
vite.config.js Disables sourcemaps in production for security/performance

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error(`Origin ${origin} not allowed by CORS policy`), false);
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the @fastify/cors documentation, when the origin callback passes an Error object, it will throw the error and close the connection. For denied CORS requests, it's more appropriate to use callback(null, false) which will result in a proper CORS error response without throwing an exception. The current implementation will cause the server to throw an error for invalid origins rather than gracefully denying the request.

Suggested change
callback(new Error(`Origin ${origin} not allowed by CORS policy`), false);
callback(null, false);

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +79
// @ts-ignore
const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS
? // @ts-ignore
fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim())
: // @ts-ignore
[fastify.config.POST_LOGIN_REDIRECT]; // Fallback to POST_LOGIN_REDIRECT
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Multiple @ts-ignore comments are used (lines 74, 76, 78) to suppress TypeScript errors when accessing fastify.config. Consider adding proper type definitions for the config object in the envPlugin or using // @ts-expect-error with explanatory comments instead, which will fail if the error no longer exists in future TypeScript versions.

Copilot uses AI. Check for mistakes.
Comment on lines 69 to 89
fastify.register(cors, {
origin: isLocalDev
? true // Allow all origins in local development
: (origin, callback) => {
// In production, validate against allowed origins
// @ts-ignore
const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS
? // @ts-ignore
fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim())
: // @ts-ignore
[fastify.config.POST_LOGIN_REDIRECT]; // Fallback to POST_LOGIN_REDIRECT

if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error(`Origin ${origin} not allowed by CORS policy`), false);
}
},
methods: ['GET', 'HEAD', 'POST', 'PATCH', 'DELETE'],
credentials: true, // Required for cookie-based sessions
});
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CORS plugin is registered before envPlugin (line 92), which means fastify.config will be undefined when the CORS origin validation callback executes. This will cause runtime errors when trying to access fastify.config.ALLOWED_CORS_ORIGINS and fastify.config.POST_LOGIN_REDIRECT.

Move the CORS registration block (lines 69-89) to after line 92 where envPlugin is registered, so that fastify.config is available when the CORS configuration needs it.

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +77
const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS
? // @ts-ignore
fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim())
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback logic doesn't properly handle the case where ALLOWED_CORS_ORIGINS is set to an empty string or contains only whitespace. An empty string will be split into [''], which means a request with an empty string as the origin will be considered valid.

Consider adding a check for empty/whitespace-only strings:

const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS?.trim()
  ? fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim()).filter((o) => o)
  : [fastify.config.POST_LOGIN_REDIRECT];
Suggested change
const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS
? // @ts-ignore
fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim())
const allowedOrigins = fastify.config.ALLOWED_CORS_ORIGINS && fastify.config.ALLOWED_CORS_ORIGINS.trim()
? // @ts-ignore
fastify.config.ALLOWED_CORS_ORIGINS.split(',').map((o) => o.trim()).filter((o) => o)

Copilot uses AI. Check for mistakes.
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The imgSrc directive includes 'https:' which allows loading images from any HTTPS source. This is overly permissive and could be a security concern. Consider specifying explicit trusted domains instead of allowing all HTTPS sources, or document why this broad permission is necessary.

Suggested change
imgSrc: ["'self'", 'data:', 'https:'],
// Restrict imgSrc to trusted domains only. Add more domains as needed.
imgSrc: ["'self'", 'data:'],

Copilot uses AI. Check for mistakes.

build: {
sourcemap: true,
sourcemap: process.env.NODE_ENV !== 'production',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also changed here: #359

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants