diff --git a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts index 096bf587..023c0978 100644 --- a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts +++ b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts @@ -24,16 +24,6 @@ describe('Server Tests', () => { server.close(); }); - test('POST /collaboration/api/reset-connections?room=[ROOM_ID] invalid origin', async () => { - const response = await request(app as any) - .post('/collaboration/api/reset-connections/?room=test-room') - .set('Origin', 'http://invalid-origin.com') - .send({ document_id: 'test-document' }); - - expect(response.status).toBe(403); - expect(response.body.error).toBe('CORS policy violation: Invalid Origin'); - }); - test('POST /collaboration/api/reset-connections?room=[ROOM_ID] with incorrect API key should return 403', async () => { const response = await request(app as any) .post('/collaboration/api/reset-connections/?room=test-room') diff --git a/src/frontend/servers/y-provider/package.json b/src/frontend/servers/y-provider/package.json index 3655fc75..c32d2e78 100644 --- a/src/frontend/servers/y-provider/package.json +++ b/src/frontend/servers/y-provider/package.json @@ -20,6 +20,7 @@ "@hocuspocus/server": "2.15.0", "@sentry/node": "8.45.1", "@sentry/profiling-node": "8.45.1", + "cors": "2.8.5", "express": "4.21.2", "express-ws": "5.0.2", "y-protocols": "1.0.6", @@ -27,6 +28,7 @@ }, "devDependencies": { "@hocuspocus/provider": "2.15.0", + "@types/cors": "2.8.17", "@types/express": "5.0.0", "@types/express-ws": "3.0.5", "@types/jest": "29.5.14", diff --git a/src/frontend/servers/y-provider/src/middlewares.ts b/src/frontend/servers/y-provider/src/middlewares.ts index 48e56895..30470eca 100644 --- a/src/frontend/servers/y-provider/src/middlewares.ts +++ b/src/frontend/servers/y-provider/src/middlewares.ts @@ -1,3 +1,4 @@ +import cors from 'cors'; import { NextFunction, Request, Response } from 'express'; import * as ws from 'ws'; @@ -7,26 +8,20 @@ import { Y_PROVIDER_API_KEY, } from '@/env'; -import { logger } from './utils'; - const VALID_API_KEYS = [COLLABORATION_SERVER_SECRET, Y_PROVIDER_API_KEY]; +const allowedOrigins = COLLABORATION_SERVER_ORIGIN.split(','); + +export const corsMiddleware = cors({ + origin: allowedOrigins, + methods: ['GET', 'POST'], + credentials: true, +}); export const httpSecurity = ( req: Request, res: Response, next: NextFunction, ): void => { - // Origin check - const origin = req.headers['origin']; - if (origin && COLLABORATION_SERVER_ORIGIN !== origin) { - logger('CORS policy violation: Invalid Origin', origin); - - res - .status(403) - .json({ error: 'CORS policy violation: Invalid Origin', origin }); - return; - } - // Secret API Key check // Note: Changing this header to Bearer token format will break backend compatibility with this microservice. const apiKey = req.headers['authorization']; @@ -45,9 +40,9 @@ export const wsSecurity = ( ): void => { // Origin check const origin = req.headers['origin']; - if (COLLABORATION_SERVER_ORIGIN !== origin) { + if (origin && !allowedOrigins.includes(origin)) { + ws.close(4001, 'Origin not allowed'); console.error('CORS policy violation: Invalid Origin', origin); - ws.close(); return; } diff --git a/src/frontend/servers/y-provider/src/servers/appServer.ts b/src/frontend/servers/y-provider/src/servers/appServer.ts index 6aefc4a4..80077bb8 100644 --- a/src/frontend/servers/y-provider/src/servers/appServer.ts +++ b/src/frontend/servers/y-provider/src/servers/appServer.ts @@ -10,7 +10,7 @@ import { collaborationWSHandler, convertMarkdownHandler, } from '../handlers'; -import { httpSecurity, wsSecurity } from '../middlewares'; +import { corsMiddleware, httpSecurity, wsSecurity } from '../middlewares'; import { routes } from '../routes'; import { logger } from '../utils'; @@ -24,6 +24,7 @@ import { logger } from '../utils'; export const initServer = () => { const { app } = expressWebsockets(express()); app.use(express.json()); + app.use(corsMiddleware); /** * Route to handle WebSocket connections diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 6301d577..3b8e24d1 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -4495,6 +4495,13 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78" integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q== +"@types/cors@2.8.17": + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + "@types/debug@^4.0.0": version "4.1.12" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" @@ -6064,6 +6071,14 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cors@2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -10224,7 +10239,7 @@ nwsapi@^2.2.12, nwsapi@^2.2.2: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== -object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -13187,7 +13202,7 @@ value-or-function@^4.0.0: resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-4.0.0.tgz#70836b6a876a010dc3a2b884e7902e9db064378d" integrity sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg== -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==