Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The `osc_eyevinn_intercom_manager` resource requires these variables:
| `SMB_APIKEY` | When set, provide this API key for the Symphony Media Bridge (optional) |
| `DB_CONNECTION_STRING` | DB connection string (default: `mongodb://localhost:27017/intercom-manager`). Supports MongoDB (`mongodb://`) and CouchDB (`http://`/`https://`) |
| `PUBLIC_HOST` | Hostname for frontend application for generating URLs to share (default: `http://localhost:8000`) |
| `CORS_ORIGIN` | Comma-separated list of allowed CORS origins, e.g. `http://localhost:5173,http://localhost:5174`. When unset, CORS is disabled. Required for local development when the frontend runs on a different port |
| `CORS_ORIGIN` | Comma-separated list of allowed CORS origins, e.g. `http://localhost:5173,http://localhost:5174`. When unset, CORS is disabled. Required for local development when the frontend runs on a different port |
| `WHIP_AUTH_KEY` | When set, WHIP and WHEP endpoints require a `Bearer` token matching this key (optional) |
| `ENDPOINT_IDLE_TIMEOUT_S` | Idle timeout in seconds for SMB endpoints (default: `60`) |
| `OSC_ACCESS_TOKEN` | Personal Access Token from OSC for link sharing and reauthenticating (optional) |
Expand Down
25 changes: 20 additions & 5 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,28 @@ export default async (opts: ApiOptions) => {
contentSecurityPolicy: false // CSP managed per-deployment
});

// register the cors plugin, configure it for better security
// Dynamic CORS: permissive for WHIP/WHEP routes, restrictive for everything else
const corsOrigin = process.env.CORS_ORIGIN;
api.register(cors, {
origin: corsOrigin ? corsOrigin.split(',') : false,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['Content-Type', 'Location', 'ETag', 'Link']
delegator: (req, callback) => {
const url = req.url || '';
if (url.startsWith('/api/v1/whip') || url.startsWith('/api/v1/whep')) {
callback(null, {
origin: '*',
methods: ['POST', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['Content-Type', 'Location', 'ETag', 'Link'],
preflightContinue: true
});
} else {
callback(null, {
origin: corsOrigin ? corsOrigin.split(',') : false,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['Content-Type', 'Location', 'ETag', 'Link']
});
}
}
});

await api.register(fastifyRateLimit, {
Expand Down
4 changes: 2 additions & 2 deletions src/api_productions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ const apiProductions: FastifyPluginCallback<ApiProductionsOptions> = (
sessionId: (s._id ?? '').toString(),
endpointId: s.endpointId,
name: s.name,
isActive: s.isWhip ? true : s.isActive,
isActive: !!s.isActive,
isWhip: s.isWhip
}));

Expand Down Expand Up @@ -945,7 +945,7 @@ const apiProductions: FastifyPluginCallback<ApiProductionsOptions> = (
sessionId: s._id.toString(),
endpointId: s.endpointId,
name: s.name,
isActive: s.isWhip ? true : !!s.isActive,
isActive: !!s.isActive,
isWhip: !!s.isWhip
}));

Expand Down
14 changes: 0 additions & 14 deletions src/api_whep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ export const apiWhep: FastifyPluginCallback<ApiWhepOptions> = (
) => {
const productionManager = opts.productionManager;

// Permissive CORS for WHEP routes (external clients)
fastify.addHook('onSend', async (request, reply) => {
reply.header('Access-Control-Allow-Origin', '*');
reply.header(
'Access-Control-Allow-Methods',
'POST, DELETE, PATCH, OPTIONS'
);
reply.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
reply.header(
'Access-Control-Expose-Headers',
'Content-Type, Location, ETag, Link'
);
});

fastify.addContentTypeParser(
'application/sdp',
{ parseAs: 'string' },
Expand Down
14 changes: 0 additions & 14 deletions src/api_whip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ export const apiWhip: FastifyPluginCallback<ApiWhipOptions> = (
) => {
const productionManager = opts.productionManager;

// Permissive CORS for WHIP routes (external clients like OBS, GStreamer)
fastify.addHook('onSend', async (request, reply) => {
reply.header('Access-Control-Allow-Origin', '*');
reply.header(
'Access-Control-Allow-Methods',
'POST, DELETE, PATCH, OPTIONS'
);
reply.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
reply.header(
'Access-Control-Expose-Headers',
'Content-Type, Location, ETag, Link'
);
});

fastify.addContentTypeParser(
'application/sdp',
{ parseAs: 'string' },
Expand Down
Loading
Loading