test: Verschlüsselung und Kalendermodelle absichern

Sieben Tests für die Tokenverschlüsselung: Rückweg, Umlaute, verschiedene
Chiffren bei gleichem Klartext, und dass eine Veränderung am Chiffrat null
ergibt statt Unsinn.

Der Integrationstest deckt jetzt auch ab, dass dasselbe Konto mit
verschiedenen Kalendern erlaubt ist, ein Upsert den Termin aktualisiert
statt zu doppeln, und ein Bereich das Löschen seines Standard-Kalenderkontos
überlebt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 18:12:05 +02:00
co-authored by Claude Opus 5
parent d8d3227c82
commit df50627a20
2 changed files with 174 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
/**
* Die Verschlüsselung liegt in src/server, weil sie AUTH_SECRET braucht.
* Für den Test wird die Umgebung ersetzt und "server-only" auf ein leeres
* Modul umgebogen — sonst bricht der Import außerhalb einer Serverumgebung ab.
*/
vi.mock('server-only', () => ({}))
vi.mock('@/server/umgebung', () => ({
umgebung: () => ({ AUTH_SECRET: 'test-geheimnis-fuer-die-ableitung-1234567890' }),
}))
const { entschluesseln, schluesselVergessen, verschluesseln } =
await import('@/server/krypto')
describe('verschluesseln und entschluesseln', () => {
beforeEach(() => {
schluesselVergessen()
})
it('gibt zurück, was hineinging', () => {
const klartext = 'ya29.beispiel-aktualisierungstoken'
expect(entschluesseln(verschluesseln(klartext))).toBe(klartext)
})
it('kommt mit Umlauten und langen Texten zurecht', () => {
const klartext = 'Rückgabewert mit Umlauten: äöüß — ' + 'x'.repeat(4000)
expect(entschluesseln(verschluesseln(klartext))).toBe(klartext)
})
it('erzeugt bei gleichem Text verschiedene Chiffren', () => {
// Sonst ließe sich an der Datenbank ablesen, welche Konten dasselbe
// Token tragen.
expect(verschluesseln('gleich')).not.toBe(verschluesseln('gleich'))
})
it('lässt den Klartext nicht durchscheinen', () => {
expect(verschluesseln('geheim')).not.toContain('geheim')
})
it('gibt für nichts auch nichts zurück', () => {
expect(entschluesseln(null)).toBeNull()
})
it('weist Veränderungen ab, statt Unsinn zu liefern', () => {
const chiffre = verschluesseln('unverändert')
const teile = chiffre.split(':')
// Ein Bit im Inhalt kippen.
const inhalt = Buffer.from(teile[3] ?? '', 'base64url')
inhalt[0] = (inhalt[0] ?? 0) ^ 0x01
teile[3] = inhalt.toString('base64url')
expect(entschluesseln(teile.join(':'))).toBeNull()
})
it('weist eine fremde Form ab', () => {
expect(entschluesseln('einfach nur Text')).toBeNull()
expect(entschluesseln('v2:a:b:c')).toBeNull()
expect(entschluesseln('v1:zu:wenige')).toBeNull()
})
})