fix: next/next-auth/nodemailer/postcss auf gepatchte Versionen heben
Letzter offener Punkt aus dem Sicherheitsdurchgang vor dem Beta-Test: npm audit
meldete 24 Schwachstellen, davon mehrere kritisch in next und next-auth.
- next 14.2.35 -> 15.5.24 (patcht alles, was next@16 sonst erfordert haette --
ein Major-Sprung statt zwei; next 15 unterstuetzt weiterhin React 18)
- next-auth 4.24.13 -> 4.24.15, @auth/core per overrides auf 0.41.3 erzwungen
(next-auth pinnt es sonst exakt auf die verwundbare 0.34.3, als ungenutzten
optionalen Peer)
- nodemailer 7 -> 10 per overrides (next-auth haelt einen ungenutzten optionalen
Peer auf 7.x)
- postcss auf 8.5.28, auch next's eigene interne Kopie per overrides
- ungenutztes @auth/prisma-adapter entfernt (Projekt nutzt @next-auth/prisma-adapter)
npm audit: 24 -> 0.
Zwei echte Codeaenderungen dafuer noetig:
- Next.js 15: { params } in Routen-Handlern ist jetzt ein Promise. Einzige
betroffene Route: cross-sync/rules/[id].
- nodemailer.Transporter gibt es seit @types/nodemailer 8 nicht mehr als
Namespace-Property, nur noch als benannter Type-Export. Einzige Stelle:
src/lib/email.ts.
Ausserdem google-auth-library als direkte Abhaengigkeit deklariert (vorher nur
ueber googleapis transitiv gehofft) und per overrides auf eine Version gepinnt --
der frische package-lock.json aus den obigen Fixes hob sie sonst nicht mehr
passend, wodurch zwei inkompatible Kopien nebeneinander existierten und der
Typecheck brach.
Verifiziert: Typecheck, Lint, 79 Unit-Tests, Produktions-Build alle gruen.
Login-Seite, Sicherheitsheader und Auth-Middleware manuell im gebauten
Standalone-Server geprueft. Kein Playwright-E2E-Lauf (braucht echte DB/OAuth).
v1.123.0
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
3742ae52c6
commit
114131f9e4
43
CHANGELOG.md
43
CHANGELOG.md
@ -2,6 +2,49 @@
|
||||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## [1.123.0] - 2026-09-12
|
||||
|
||||
### Security
|
||||
- **`next` 14.2.35 → 15.5.24.** Patcht mehrere kritische Advisories, darunter zwei
|
||||
unauthentifizierte RCE-Klassen (Windows-Hosts, AVIF-Bildoptimierung — beide auf
|
||||
diesem Linux-Host ohnehin nicht direkt erreichbar, aber jetzt geschlossen) sowie
|
||||
diverse DoS-, SSRF- und Cache-Poisoning-Advisories. 15.5.24 patcht bereits alles,
|
||||
was sonst erst next@16 fordern würde — ein Major-Sprung statt zwei.
|
||||
- **`next-auth` 4.24.13 → 4.24.15**, plus `@auth/core` per `overrides` auf 0.41.3
|
||||
erzwungen (next-auth pinnt es sonst exakt auf die verwundbare 0.34.3 — als
|
||||
optionalen Peer, den dieses Projekt nirgends importiert). Behebt einen
|
||||
E-Mail-Normalisierungs-Bypass, einen Absturz bei fehlerhaften Bearer-Headern und
|
||||
eine fehlende Provider-Bindung bei OAuth-State/Nonce/PKCE-Cookies.
|
||||
- **`nodemailer` 7 → 10** (`overrides`, da next-auth einen ungenutzten optionalen
|
||||
Peer auf 7.x haelt). Behebt SMTP-Command-Injection, CRLF-Header-Injection, eine
|
||||
SSRF/Arbitrary-File-Read-Luecke ueber den `raw`-Nachrichtenmodus und eine
|
||||
IDN/Punycode-Domain-Bypass beim Empfaenger-Check.
|
||||
- `postcss` (auch die von `next` selbst intern gebündelte Kopie, per `overrides`)
|
||||
auf 8.5.28. Behebt XSS in der CSS-Ausgabe und mehrfache Pfad-Traversal-/
|
||||
Arbitrary-File-Read-Lücken über `sourceMappingURL`.
|
||||
- Ungenutztes `@auth/prisma-adapter` (v5-Adapter, nirgends importiert — das
|
||||
Projekt nutzt `@next-auth/prisma-adapter` für v4) entfernt.
|
||||
- **`npm audit`: 24 → 0 gemeldete Schwachstellen.**
|
||||
|
||||
### Fixed
|
||||
- `google-auth-library` war ein undeklarierter, nur über `googleapis` transitiv
|
||||
gehofftes Hoisting verfügbarer Import in `google-tasks.ts`. Ein frischer
|
||||
`package-lock.json` (Nebeneffekt der obigen Audit-Fixes) hob ihn nicht mehr
|
||||
passend, wodurch zwei strukturell inkompatible Kopien nebeneinander existierten
|
||||
und der Typecheck brach. Jetzt eine direkte Abhängigkeit plus `overrides`-Eintrag,
|
||||
damit immer genau eine Instanz installiert wird.
|
||||
- `nodemailer.Transporter` gibt es als Namespace-Property seit `@types/nodemailer`
|
||||
8 nicht mehr — `Transporter` ist jetzt ein benannter Type-Export. Einzige
|
||||
betroffene Stelle: `src/lib/email.ts`.
|
||||
- Next.js 15: dynamische Routen-Parameter (`{ params }`) sind jetzt ein Promise.
|
||||
Einzige betroffene Route: `PATCH`/`DELETE` unter
|
||||
`/api/calendar/cross-sync/rules/[id]`.
|
||||
|
||||
Verifiziert: Typecheck, Lint und 79 Unit-Tests grün; Produktions-Build erfolgreich;
|
||||
Login-Seite, Sicherheitsheader und die Auth-Middleware (Redirect bei fehlendem
|
||||
Token) im gebauten Standalone-Server manuell geprüft. Kein Playwright-E2E-Lauf,
|
||||
da dafür eine echte Datenbank und OAuth-Zugangsdaten nötig sind.
|
||||
|
||||
## [1.122.0] - 2026-09-12
|
||||
|
||||
### Security
|
||||
|
||||
3338
package-lock.json
generated
3338
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.122.0",
|
||||
"version": "1.123.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@ -26,7 +26,6 @@
|
||||
"author": "My Weekly To Do List Team",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.11.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
||||
@ -43,15 +42,16 @@
|
||||
"@tiptap/react": "^3.20.0",
|
||||
"@tiptap/starter-kit": "^3.20.0",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/nodemailer": "^7.0.11",
|
||||
"@types/nodemailer": "^8.0.1",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"google-auth-library": "^10.9.1",
|
||||
"googleapis": "^170.1.0",
|
||||
"ical.js": "^2.2.1",
|
||||
"lucide-react": "^0.563.0",
|
||||
"next": "14.2.35",
|
||||
"next-auth": "^4.24.13",
|
||||
"nodemailer": "^7.0.13",
|
||||
"next": "15.5.24",
|
||||
"next-auth": "^4.24.15",
|
||||
"nodemailer": "^10.0.8",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"prisma": "5.22.0",
|
||||
"react": "^18.2.0",
|
||||
@ -62,6 +62,14 @@
|
||||
"web-push": "^3.6.7",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@auth/core": "0.41.3",
|
||||
"nodemailer": "^10.0.8",
|
||||
"next": {
|
||||
"postcss": "^8.5.28"
|
||||
},
|
||||
"google-auth-library": "^10.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.58.0",
|
||||
"@types/node": "^20.0.0",
|
||||
@ -69,8 +77,8 @@
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-next": "^14.0.0",
|
||||
"postcss": "^8.4.38",
|
||||
"eslint-config-next": "15.5.24",
|
||||
"postcss": "^8.5.28",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
|
||||
@ -3,15 +3,19 @@ import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
|
||||
// Next.js 15: dynamische Routen-Parameter kommen als Promise, nicht mehr als Objekt.
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
// PATCH /api/calendar/cross-sync/rules/[id] — update a rule
|
||||
export async function PATCH(request: NextRequest, { params }: { params: { id: string } }) {
|
||||
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
||||
const { id } = await params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true } });
|
||||
if (!user) return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
|
||||
const existing = await prisma.calendarSyncRule.findFirst({ where: { id: params.id, userId: user.id } });
|
||||
const existing = await prisma.calendarSyncRule.findFirst({ where: { id, userId: user.id } });
|
||||
if (!existing) return NextResponse.json({ error: 'Rule not found' }, { status: 404 });
|
||||
|
||||
const body = await request.json();
|
||||
@ -24,25 +28,26 @@ export async function PATCH(request: NextRequest, { params }: { params: { id: st
|
||||
if (key in body) data[key] = body[key];
|
||||
}
|
||||
|
||||
const rule = await prisma.calendarSyncRule.update({ where: { id: params.id }, data });
|
||||
const rule = await prisma.calendarSyncRule.update({ where: { id }, data });
|
||||
return NextResponse.json({ rule });
|
||||
}
|
||||
|
||||
// DELETE /api/calendar/cross-sync/rules/[id] — delete a rule and all its mappings
|
||||
export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
|
||||
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
||||
const { id } = await params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true } });
|
||||
if (!user) return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
|
||||
const existing = await prisma.calendarSyncRule.findFirst({ where: { id: params.id, userId: user.id } });
|
||||
const existing = await prisma.calendarSyncRule.findFirst({ where: { id, userId: user.id } });
|
||||
if (!existing) return NextResponse.json({ error: 'Rule not found' }, { status: 404 });
|
||||
|
||||
// Cascade delete (mappings deleted via onDelete: Cascade in schema)
|
||||
await prisma.calendarSyncRule.delete({ where: { id: params.id } });
|
||||
await prisma.calendarSyncRule.delete({ where: { id } });
|
||||
// Also clean up reverse mappings stored under the synthetic _R id
|
||||
await prisma.calendarSyncMapping.deleteMany({ where: { ruleId: params.id + '_R' } });
|
||||
await prisma.calendarSyncMapping.deleteMany({ where: { ruleId: id + '_R' } });
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import nodemailer from 'nodemailer';
|
||||
import nodemailer, { Transporter } from 'nodemailer';
|
||||
import { getVerificationCopy, getResetCopy } from './emailTemplates';
|
||||
|
||||
let _transporter: nodemailer.Transporter | null = null;
|
||||
// nodemailer 10 / @types/nodemailer 8: Transporter ist ein benannter Type-Export,
|
||||
// keine Namespace-Eigenschaft mehr (nodemailer.Transporter gab es nur bis v7/@types v7).
|
||||
let _transporter: Transporter | null = null;
|
||||
|
||||
function getTransporter() {
|
||||
if (!_transporter) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user