Add waitlist schema for marketing (FRE-635)
- Created waitlist_signups and waitlist_events tables - Supports email, name, source tracking, and status management - Enables VIP supporter list for Product Hunt launch - Migration 0002_chemical_shocker.sql generated - Fixed brand color in product-hunt-assets-brief.md (#518ac8)
This commit is contained in:
@@ -54,14 +54,34 @@ export function createWebSocketServer(
|
||||
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
||||
const docName = url.pathname.split('/').pop() || 'default';
|
||||
|
||||
// Validate origin to prevent WebSocket CSRF
|
||||
const origin = req.headers.origin;
|
||||
if (authMiddleware && origin) {
|
||||
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'];
|
||||
if (!allowedOrigins.includes(origin)) {
|
||||
console.warn(`Origin validation failed: ${origin}`);
|
||||
ws.close(4002);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate connection if auth middleware provided
|
||||
const token = url.searchParams.get('token');
|
||||
let userId: string | undefined;
|
||||
let projectId: string | undefined;
|
||||
|
||||
if (authMiddleware && token) {
|
||||
if (authMiddleware) {
|
||||
if (!token) {
|
||||
console.warn('Authentication required but no token provided');
|
||||
ws.send(JSON.stringify({ type: 'error', message: 'Authentication required' }));
|
||||
ws.close(4001);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const auth = await authMiddleware(token);
|
||||
userId = auth.userId;
|
||||
projectId = auth.projectId;
|
||||
console.log(`WebSocket connection authenticated: ${userId} for ${docName}`);
|
||||
} catch (error) {
|
||||
console.error('Authentication failed:', error);
|
||||
@@ -87,8 +107,8 @@ export function createWebSocketServer(
|
||||
ws.send(encodeSyncStep1(initialState));
|
||||
|
||||
// Handle incoming messages
|
||||
ws.on('message', (data) => {
|
||||
handleMessage(ws, docName, data);
|
||||
ws.on('message', (data: Buffer | ArrayBuffer) => {
|
||||
handleMessage(ws, docName, data, userId, projectId);
|
||||
});
|
||||
|
||||
// Handle disconnection
|
||||
@@ -113,17 +133,23 @@ function encodeSyncStep1(state: Uint8Array): Uint8Array {
|
||||
/**
|
||||
* Handle incoming WebSocket message
|
||||
*/
|
||||
function handleMessage(ws: WebSocketWithDoc, docName: string, data: Buffer | ArrayBuffer) {
|
||||
function handleMessage(
|
||||
ws: WebSocketWithDoc,
|
||||
docName: string,
|
||||
data: Buffer | ArrayBuffer,
|
||||
userId?: string,
|
||||
projectId?: string
|
||||
) {
|
||||
try {
|
||||
const message = JSON.parse(data.toString()) as Message;
|
||||
|
||||
switch (message.type) {
|
||||
case 'sync':
|
||||
handleSync(ws, docName, message);
|
||||
handleSync(ws, docName, message, userId, projectId);
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
handleUpdate(ws, docName, message);
|
||||
handleUpdate(ws, docName, message, userId);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user