Auto-commit 2026-05-02 09:37
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
import { WebSocketServer, WebSocket } from 'ws';
|
||||
import { CallAnalysisEngine, CallEvent, Anomaly, SentimentAnalysis, AnalysisResult } from '../../src/lib/inference/call-analysis-engine';
|
||||
import { jwtVerify, SignJWT } from 'jose';
|
||||
|
||||
export type AlertType =
|
||||
| 'anomaly'
|
||||
@@ -50,14 +51,29 @@ export interface SubscriberSession {
|
||||
|
||||
const DEFAULT_CONFIG: Required<AlertServerConfig> = {
|
||||
port: 8088,
|
||||
enableAuth: false,
|
||||
jwtSecret: '',
|
||||
enableAuth: true,
|
||||
jwtSecret: process.env.ALERT_SERVER_JWT_SECRET || '',
|
||||
allowedOrigins: ['http://localhost:3000'],
|
||||
alertCooldownMs: 5000,
|
||||
maxSubscribers: 100,
|
||||
enableCallCorrelation: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* JWT verification helper
|
||||
*/
|
||||
async function verifyJWT(token: string, secret: string): Promise<any | null> {
|
||||
try {
|
||||
const decoded = await jwtVerify(token, new TextEncoder().encode(secret), {
|
||||
algorithms: ['HS256'],
|
||||
});
|
||||
return decoded;
|
||||
} catch (error) {
|
||||
console.error('[AlertServer] JWT verification failed:', (error as Error).message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class AlertServer {
|
||||
private wss: WebSocketServer | null = null;
|
||||
private config: Required<AlertServerConfig>;
|
||||
@@ -92,15 +108,36 @@ export class AlertServer {
|
||||
private handleConnection(ws: WebSocket, req: import('http').IncomingMessage): void {
|
||||
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
||||
const sessionId = url.searchParams.get('sessionId') || `sub-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||
const userId = url.searchParams.get('userId') || undefined;
|
||||
let userId = url.searchParams.get('userId') || undefined;
|
||||
const callId = url.searchParams.get('callId') || undefined;
|
||||
|
||||
// Origin validation
|
||||
const origin = req.headers.origin;
|
||||
if (origin && !this.config.allowedOrigins.includes(origin)) {
|
||||
ws.close(1008, 'Origin not allowed');
|
||||
return;
|
||||
}
|
||||
|
||||
// JWT Authentication (if enabled)
|
||||
if (this.config.enableAuth && this.config.jwtSecret) {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
ws.close(4001, 'Missing or invalid JWT token');
|
||||
return;
|
||||
}
|
||||
|
||||
const token = authHeader.substring(7);
|
||||
const decoded = verifyJWT(token, this.config.jwtSecret);
|
||||
|
||||
if (!decoded) {
|
||||
ws.close(4002, 'Invalid or expired JWT token');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract user ID from token if present
|
||||
userId = (decoded as any).sub || userId;
|
||||
}
|
||||
|
||||
if (this.subscribers.size >= this.config.maxSubscribers) {
|
||||
ws.close(1013, 'Too many subscribers');
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user