My-Weekly-ToDo-List/src/app/api/calendar/synology/connect/route.ts
mARTin 3e19ebe85a fix: security hardening, Prisma singleton, tsconfig cleanup
- tsconfig: remove deprecated downlevelIteration (es2017 has native iterators),
  change moduleResolution from node to bundler
- auth: set allowDangerousEmailAccountLinking=false on all OAuth providers,
  restrict debug mode to development only
- prisma: replace new PrismaClient() with singleton import in 10 API routes
  to prevent connection pool exhaustion
- goal API: validate user-supplied quote URLs to block SSRF (private IPs,
  non-http(s) schemes)
- email: guard DEV verification/reset link console.logs behind NODE_ENV check

v1.98.0
2026-04-20 19:52:47 +02:00

88 lines
3.1 KiB
TypeScript

import { NextResponse } from 'next/server';
import { validateCredentials } from '@/lib/synology-calendar';
import { getServerSession } from 'next-auth';
import { authOptions } from "@/lib/auth";
import { prisma } from '@/lib/prisma';
export async function POST(req: Request) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await req.json();
const { serverUrl, username, password } = body;
if (!serverUrl || !username || !password) {
return NextResponse.json(
{ error: 'Server URL, username, and password are required' },
{ status: 400 }
);
}
// Validate credentials and get calendars
const calendars = await validateCredentials(serverUrl, username, password);
// Find user
const user = await prisma.user.findUnique({
where: { email: session.user.email }
});
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}
// Check if connection already exists and update it, otherwise create new
const existingConnection = await prisma.calendarConnection.findFirst({
where: {
userId: user.id,
provider: 'synology'
}
});
let connection;
if (existingConnection) {
connection = await prisma.calendarConnection.update({
where: { id: existingConnection.id },
data: {
accessToken: `${username}:${password}`,
refreshToken: serverUrl, // Use refreshToken field to store the server URL since Basic Auth doesn't need refresh tokens
calendars: calendars.map(cal => ({
id: cal.id,
title: cal.title,
isPrimary: cal.isPrimary,
selected: true // Default to selected
})) as any,
updatedAt: new Date()
}
});
} else {
connection = await prisma.calendarConnection.create({
data: {
userId: user.id,
provider: 'synology',
accessToken: `${username}:${password}`,
refreshToken: serverUrl,
calendars: calendars.map(cal => ({
id: cal.id,
title: cal.title,
isPrimary: cal.isPrimary,
backgroundColor: cal.color || undefined,
selected: true
})) as any
}
});
}
return NextResponse.json({ success: true, connection });
} catch (error: any) {
console.error('Error connecting Synology Calendar:', error);
return NextResponse.json(
{ error: error.message || 'Failed to connect Synology Calendar' },
{ status: 500 }
);
}
}