feat: enhance security, performance, and stability

This commit introduces a range of improvements across the application:

- **Security:**
  - Adds authentication to the CSP metrics endpoint.
  - Hardens CSP bypass detection regex to prevent ReDoS attacks.
  - Improves CORS headers for the CSP metrics API.
  - Adds filtering for acknowledged alerts in security monitoring.

- **Performance:**
  - Optimizes database connection pooling for NeonDB.
  - Improves session fetching with abort controller.

- **Stability:**
  - Adds error handling to the tRPC demo component.
  - Fixes type inconsistencies in session data mapping.

- **Docs & DX:**
  - Ignores  files in git.
  - Fixes a token placeholder in the documentation.
This commit is contained in:
2025-07-12 01:03:52 +02:00
parent 314326400e
commit 7a3eabccd9
9 changed files with 173 additions and 97 deletions

View File

@ -45,10 +45,18 @@ export async function GET(request: NextRequest) {
const context = await createAuditContext(request, session);
// Get alerts based on filters
const alerts = securityMonitoring.getActiveAlerts(
let alerts = securityMonitoring.getActiveAlerts(
query.severity as AlertSeverity
);
// Apply acknowledged filter if provided
if (query.acknowledged !== undefined) {
const showAcknowledged = query.acknowledged === "true";
alerts = alerts.filter((alert) =>
showAcknowledged ? alert.acknowledged : !alert.acknowledged
);
}
// Apply pagination
const limit = query.limit || 50;
const offset = query.offset || 0;

View File

@ -1,12 +1,19 @@
import { type NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { cspMonitoring } from "@/lib/csp-monitoring";
import { rateLimiter } from "@/lib/rateLimiter";
import { extractClientIP, rateLimiter } from "@/lib/rateLimiter";
export async function GET(request: NextRequest) {
try {
// Authentication check for security metrics endpoint
const session = await getServerSession(authOptions);
if (!session?.user || !session.user.isPlatformUser) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Rate limiting for metrics endpoint
const ip =
request.ip || request.headers.get("x-forwarded-for") || "unknown";
const ip = extractClientIP(request);
const rateLimitResult = await rateLimiter.check(
`csp-metrics:${ip}`,
30, // 30 requests
@ -102,9 +109,11 @@ export async function OPTIONS() {
return new NextResponse(null, {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Origin":
process.env.ALLOWED_ORIGINS || "https://livedash.notso.ai",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Credentials": "true",
},
});
}

View File

@ -51,11 +51,11 @@ function mapPrismaSessionToChatSession(prismaSession: {
country: prismaSession.country ?? null,
ipAddress: prismaSession.ipAddress ?? null,
sentiment: prismaSession.sentiment ?? null,
messagesSent: prismaSession.messagesSent ?? undefined, // Use undefined if ChatSession expects number | undefined
messagesSent: prismaSession.messagesSent ?? null, // Maintain consistency with other nullable fields
avgResponseTime: prismaSession.avgResponseTime ?? null,
escalated: prismaSession.escalated ?? undefined,
forwardedHr: prismaSession.forwardedHr ?? undefined,
initialMsg: prismaSession.initialMsg ?? undefined,
escalated: prismaSession.escalated,
forwardedHr: prismaSession.forwardedHr,
initialMsg: prismaSession.initialMsg ?? null,
fullTranscriptUrl: prismaSession.fullTranscriptUrl ?? null,
summary: prismaSession.summary ?? null, // New field
transcriptContent: null, // Not available in Session model