feat: implement cache layer, CSP improvements, and database performance optimizations

- Add Redis cache implementation with LRU eviction
- Enhance Content Security Policy with nonce generation
- Optimize database queries with connection pooling
- Add cache invalidation API endpoints
- Improve security monitoring performance
This commit is contained in:
2025-07-12 04:44:50 +02:00
parent 7a3eabccd9
commit e1abedb148
56 changed files with 6881 additions and 7040 deletions

View File

@ -66,11 +66,12 @@ export async function GET(request: NextRequest) {
await securityAuditLogger.logPlatformAdmin(
"security_alerts_access",
AuditOutcome.SUCCESS,
context,
undefined,
{
alertCount: alerts.length,
filters: query,
...context,
metadata: {
alertCount: alerts.length,
filters: query,
},
}
);
@ -85,7 +86,7 @@ export async function GET(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid query parameters", details: error.errors },
{ error: "Invalid query parameters", details: error.issues },
{ status: 400 }
);
}
@ -101,7 +102,7 @@ export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user || !session.user.isPlatformUser) {
if (!session?.user || !session.user.isPlatformUser || !session.user.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
@ -123,9 +124,10 @@ export async function POST(request: NextRequest) {
await securityAuditLogger.logPlatformAdmin(
"security_alert_acknowledged",
AuditOutcome.SUCCESS,
context,
undefined,
{ alertId }
{
...context,
metadata: { alertId },
}
);
return NextResponse.json({ success: true });
@ -137,7 +139,7 @@ export async function POST(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid request", details: error.errors },
{ error: "Invalid request", details: error.issues },
{ status: 400 }
);
}

View File

@ -55,13 +55,14 @@ export async function GET(request: NextRequest) {
await securityAuditLogger.logPlatformAdmin(
"security_data_export",
AuditOutcome.SUCCESS,
context,
undefined,
{
exportType: query.type,
format: query.format,
timeRange,
dataSize: data.length,
...context,
metadata: {
exportType: query.type,
format: query.format,
timeRange,
dataSize: data.length,
},
}
);
@ -77,7 +78,7 @@ export async function GET(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid query parameters", details: error.errors },
{ error: "Invalid query parameters", details: error.issues },
{ status: 400 }
);
}

View File

@ -8,10 +8,19 @@ import {
securityAuditLogger,
} from "@/lib/securityAuditLogger";
import {
AlertChannel,
type AlertSeverity,
type MonitoringConfig,
securityMonitoring,
} from "@/lib/securityMonitoring";
// Type for partial config updates that allows optional nested properties
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
type ConfigUpdate = DeepPartial<MonitoringConfig>;
const metricsQuerySchema = z.object({
startDate: z.string().datetime().optional(),
endDate: z.string().datetime().optional(),
@ -34,9 +43,7 @@ const configUpdateSchema = z.object({
alerting: z
.object({
enabled: z.boolean().optional(),
channels: z
.array(z.enum(["EMAIL", "WEBHOOK", "SLACK", "DISCORD", "PAGERDUTY"]))
.optional(),
channels: z.array(z.nativeEnum(AlertChannel)).optional(),
suppressDuplicateMinutes: z.number().min(1).max(1440).optional(),
escalationTimeoutMinutes: z.number().min(5).max(1440).optional(),
})
@ -107,7 +114,7 @@ export async function GET(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid query parameters", details: error.errors },
{ error: "Invalid query parameters", details: error.issues },
{ status: 400 }
);
}
@ -132,19 +139,35 @@ export async function POST(request: NextRequest) {
}
const body = await request.json();
const config = configUpdateSchema.parse(body);
const validatedConfig = configUpdateSchema.parse(body);
const context = await createAuditContext(request, session);
// Build the config update object with proper type safety
const configUpdate: ConfigUpdate = {};
if (validatedConfig.thresholds) {
configUpdate.thresholds = validatedConfig.thresholds;
}
if (validatedConfig.alerting) {
configUpdate.alerting = validatedConfig.alerting;
}
if (validatedConfig.retention) {
configUpdate.retention = validatedConfig.retention;
}
// Update monitoring configuration
securityMonitoring.updateConfig(config);
securityMonitoring.updateConfig(configUpdate);
// Log configuration change
await securityAuditLogger.logPlatformAdmin(
"security_monitoring_config_update",
AuditOutcome.SUCCESS,
context,
undefined,
{ configChanges: config }
{
...context,
metadata: { configChanges: validatedConfig },
}
);
return NextResponse.json({
@ -156,7 +179,7 @@ export async function POST(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid configuration", details: error.errors },
{ error: "Invalid configuration", details: error.issues },
{ status: 400 }
);
}

View File

@ -11,10 +11,11 @@ import {
type AlertType,
type SecurityMetrics,
securityMonitoring,
type ThreatLevel,
} from "@/lib/securityMonitoring";
const threatAnalysisSchema = z.object({
ipAddress: z.string().ip().optional(),
ipAddress: z.string().optional(),
userId: z.string().uuid().optional(),
timeRange: z
.object({
@ -39,9 +40,10 @@ export async function POST(request: NextRequest) {
interface ThreatAnalysisResults {
ipThreatAnalysis?: {
ipAddress: string;
threatLevel: number;
threatLevel: ThreatLevel;
isBlacklisted: boolean;
riskFactors: string[];
recommendations: string[];
};
timeRangeAnalysis?: {
timeRange: { start: Date; end: Date };
@ -111,11 +113,12 @@ export async function POST(request: NextRequest) {
await securityAuditLogger.logPlatformAdmin(
"threat_analysis_performed",
AuditOutcome.SUCCESS,
context,
undefined,
{
analysisType: Object.keys(analysis),
threatLevel: results.overallThreatLandscape?.currentThreatLevel,
...context,
metadata: {
analysisType: Object.keys(analysis),
threatLevel: results.overallThreatLandscape?.currentThreatLevel,
},
}
);
@ -125,7 +128,7 @@ export async function POST(request: NextRequest) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid request", details: error.errors },
{ error: "Invalid request", details: error.issues },
{ status: 400 }
);
}