CORS implemented in a static manner: unable to configure on another machine
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
GEMINI_API_KEY="AIzaSyDke9H2NhiG6rBwxT0qrdYgnNoNZm_0j58"
|
||||
ENCRYPTION_KEY=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
|
||||
ENCRYPTION_KEY=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
|
||||
CORS_ORIGIN=http://localhost:3000
|
||||
@@ -7,7 +7,8 @@
|
||||
"start": "ts-node src/index.ts",
|
||||
"dev": "nodemon src/index.ts",
|
||||
"build": "tsc",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"lint": "eslint src/**/*.ts"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@@ -21,22 +22,15 @@
|
||||
"@types/supertest": "^6.0.3",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/ws": "^8.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"eslint": "^8.56.0",
|
||||
"jest": "^27.4.3",
|
||||
"nodemon": "^2.0.15",
|
||||
"supertest": "^7.1.4",
|
||||
"ts-jest": "^27.1.0",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.5.2",
|
||||
"eslint": "^8.56.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ts-node src/index.ts",
|
||||
"dev": "nodemon src/index.ts",
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"lint": "eslint src/**/*.ts"
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.1.0",
|
||||
|
||||
@@ -20,7 +20,21 @@ const server = http.createServer(app);
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
const allowedOrigins = process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : [];
|
||||
|
||||
const corsOptions = {
|
||||
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
||||
// Allow same-origin requests (origin is undefined) and requests from the whitelisted origins
|
||||
if (!origin || allowedOrigins.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
console.warn(`CORS: Blocked request from origin: ${origin}`);
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
|
||||
// Public API Routes
|
||||
app.use('/api/auth', authRouter);
|
||||
|
||||
118
backend/tests/cors.test.ts
Normal file
118
backend/tests/cors.test.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import cors from 'cors';
|
||||
|
||||
// Mock the express request, response, and next function
|
||||
const mockRequest = (origin: string | undefined) => {
|
||||
return { header: (name: string) => (name === 'Origin' ? origin : undefined) } as Request;
|
||||
};
|
||||
|
||||
const mockResponse = () => {
|
||||
const res: Partial<Response> = {};
|
||||
res.setHeader = jest.fn().mockReturnValue(res as Response);
|
||||
res.status = jest.fn().mockReturnValue(res as Response);
|
||||
res.json = jest.fn().mockReturnValue(res as Response);
|
||||
return res as Response;
|
||||
};
|
||||
|
||||
const mockNext = () => jest.fn() as NextFunction;
|
||||
|
||||
describe('CORS Middleware Configuration', () => {
|
||||
const OLD_ENV = process.env;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules(); // Most important - it clears the cache
|
||||
process.env = { ...OLD_ENV }; // Make a copy
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
process.env = OLD_ENV; // Restore old environment
|
||||
});
|
||||
|
||||
test('should allow a request from the configured CORS_ORIGIN', () => {
|
||||
process.env.CORS_ORIGIN = 'http://allowed.com';
|
||||
const corsOptions = {
|
||||
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
||||
if (!origin || process.env.CORS_ORIGIN?.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
};
|
||||
const corsMiddleware = cors(corsOptions);
|
||||
const req = mockRequest('http://allowed.com');
|
||||
const res = mockResponse();
|
||||
const next = mockNext();
|
||||
|
||||
corsMiddleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalledWith();
|
||||
expect(next).not.toHaveBeenCalledWith(expect.any(Error));
|
||||
});
|
||||
|
||||
test('should block a request from an unlisted origin', () => {
|
||||
process.env.CORS_ORIGIN = 'http://allowed.com';
|
||||
const corsOptions = {
|
||||
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
||||
if (!origin || process.env.CORS_ORIGIN?.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
};
|
||||
const corsMiddleware = cors(corsOptions);
|
||||
const req = mockRequest('http://denied.com');
|
||||
const res = mockResponse();
|
||||
const next = mockNext();
|
||||
|
||||
corsMiddleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalledWith(new Error('Not allowed by CORS'));
|
||||
});
|
||||
|
||||
test('should block a cross-origin request if CORS_ORIGIN is not set (default same-origin)', () => {
|
||||
delete process.env.CORS_ORIGIN;
|
||||
const corsOptions = {
|
||||
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
||||
// In a real scenario, an empty CORS_ORIGIN would mean only same-origin is allowed.
|
||||
// This is simulated by checking if origin exists and is not in the (non-existent) whitelist.
|
||||
if (!origin || process.env.CORS_ORIGIN?.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
};
|
||||
const corsMiddleware = cors(corsOptions);
|
||||
const req = mockRequest('http://any-origin.com');
|
||||
const res = mockResponse();
|
||||
const next = mockNext();
|
||||
|
||||
corsMiddleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalledWith(new Error('Not allowed by CORS'));
|
||||
});
|
||||
|
||||
test('should allow a same-origin request if CORS_ORIGIN is not set', () => {
|
||||
delete process.env.CORS_ORIGIN;
|
||||
const corsOptions = {
|
||||
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
||||
if (!origin || process.env.CORS_ORIGIN?.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
};
|
||||
const corsMiddleware = cors(corsOptions);
|
||||
const req = mockRequest(undefined); // A same-origin request has no Origin header
|
||||
const res = mockResponse();
|
||||
const next = mockNext();
|
||||
|
||||
corsMiddleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalledWith();
|
||||
expect(next).not.toHaveBeenCalledWith(expect.any(Error));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user