🔒️(y-provider) add cors middlewares
Add cors middlewares to y-provider server. It will control how clients connect to the server with http requests.
This commit is contained in:
@@ -24,16 +24,6 @@ describe('Server Tests', () => {
|
|||||||
server.close();
|
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 () => {
|
test('POST /collaboration/api/reset-connections?room=[ROOM_ID] with incorrect API key should return 403', async () => {
|
||||||
const response = await request(app as any)
|
const response = await request(app as any)
|
||||||
.post('/collaboration/api/reset-connections/?room=test-room')
|
.post('/collaboration/api/reset-connections/?room=test-room')
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@hocuspocus/server": "2.15.0",
|
"@hocuspocus/server": "2.15.0",
|
||||||
"@sentry/node": "8.45.1",
|
"@sentry/node": "8.45.1",
|
||||||
"@sentry/profiling-node": "8.45.1",
|
"@sentry/profiling-node": "8.45.1",
|
||||||
|
"cors": "2.8.5",
|
||||||
"express": "4.21.2",
|
"express": "4.21.2",
|
||||||
"express-ws": "5.0.2",
|
"express-ws": "5.0.2",
|
||||||
"y-protocols": "1.0.6",
|
"y-protocols": "1.0.6",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hocuspocus/provider": "2.15.0",
|
"@hocuspocus/provider": "2.15.0",
|
||||||
|
"@types/cors": "2.8.17",
|
||||||
"@types/express": "5.0.0",
|
"@types/express": "5.0.0",
|
||||||
"@types/express-ws": "3.0.5",
|
"@types/express-ws": "3.0.5",
|
||||||
"@types/jest": "29.5.14",
|
"@types/jest": "29.5.14",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import cors from 'cors';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import * as ws from 'ws';
|
import * as ws from 'ws';
|
||||||
|
|
||||||
@@ -7,26 +8,20 @@ import {
|
|||||||
Y_PROVIDER_API_KEY,
|
Y_PROVIDER_API_KEY,
|
||||||
} from '@/env';
|
} from '@/env';
|
||||||
|
|
||||||
import { logger } from './utils';
|
|
||||||
|
|
||||||
const VALID_API_KEYS = [COLLABORATION_SERVER_SECRET, Y_PROVIDER_API_KEY];
|
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 = (
|
export const httpSecurity = (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction,
|
next: NextFunction,
|
||||||
): void => {
|
): 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
|
// Secret API Key check
|
||||||
// Note: Changing this header to Bearer token format will break backend compatibility with this microservice.
|
// Note: Changing this header to Bearer token format will break backend compatibility with this microservice.
|
||||||
const apiKey = req.headers['authorization'];
|
const apiKey = req.headers['authorization'];
|
||||||
@@ -45,9 +40,9 @@ export const wsSecurity = (
|
|||||||
): void => {
|
): void => {
|
||||||
// Origin check
|
// Origin check
|
||||||
const origin = req.headers['origin'];
|
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);
|
console.error('CORS policy violation: Invalid Origin', origin);
|
||||||
ws.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
collaborationWSHandler,
|
collaborationWSHandler,
|
||||||
convertMarkdownHandler,
|
convertMarkdownHandler,
|
||||||
} from '../handlers';
|
} from '../handlers';
|
||||||
import { httpSecurity, wsSecurity } from '../middlewares';
|
import { corsMiddleware, httpSecurity, wsSecurity } from '../middlewares';
|
||||||
import { routes } from '../routes';
|
import { routes } from '../routes';
|
||||||
import { logger } from '../utils';
|
import { logger } from '../utils';
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ import { logger } from '../utils';
|
|||||||
export const initServer = () => {
|
export const initServer = () => {
|
||||||
const { app } = expressWebsockets(express());
|
const { app } = expressWebsockets(express());
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
app.use(corsMiddleware);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route to handle WebSocket connections
|
* Route to handle WebSocket connections
|
||||||
|
|||||||
@@ -4495,6 +4495,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78"
|
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78"
|
||||||
integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==
|
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":
|
"@types/debug@^4.0.0":
|
||||||
version "4.1.12"
|
version "4.1.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
|
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"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
||||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
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:
|
cosmiconfig@^7.0.0:
|
||||||
version "7.1.0"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
|
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"
|
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43"
|
||||||
integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==
|
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"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
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"
|
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-4.0.0.tgz#70836b6a876a010dc3a2b884e7902e9db064378d"
|
||||||
integrity sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==
|
integrity sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==
|
||||||
|
|
||||||
vary@~1.1.2:
|
vary@^1, vary@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||||
|
|||||||
Reference in New Issue
Block a user