Kontrolle: Bestaetigen per Link prueft Token und Ablauf in der Sperre erneut
Ein Token-Tausch durch die Erinnerung zwischen Pruefung und Sperre ergibt 404 wie bei einem ungueltigen Link; das Portal ist nicht betroffen. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c2245b6905
commit
b6c1d81342
3 files changed
+32
-4
No files matched your search
@@ -9,12 +9,12 @@ import { createWriteLimiter } from '../services/writeLimiter.js'
|
||||
import { findAuftragByTokenHash } from '../services/auftraege/auftragStore.js'
|
||||
import { lesePdf } from '../services/auftraege/ablage.js'
|
||||
import { oeffentlicheAnsicht } from '../services/auftraege/auftragSicht.js'
|
||||
import { bestaetigeAuftrag, GESPERRT_MELDUNG } from '../services/auftraege/bestaetigung.js'
|
||||
import { bestaetigeAuftrag, GESPERRT_MELDUNG, UNGUELTIGER_LINK } from '../services/auftraege/bestaetigung.js'
|
||||
import { AuftragError, sendeFehler } from '../services/auftraege/fehler.js'
|
||||
import { auftraegeAktiv } from '../services/auftraege/schalter.js'
|
||||
import { hashToken } from '../services/auftraege/token.js'
|
||||
|
||||
const UNGUELTIG = 'Dieser Link ist ungültig oder abgelaufen.'
|
||||
const UNGUELTIG = UNGUELTIGER_LINK
|
||||
const HAEKCHEN = 'Bitte bestätigen Sie den Auftrag mit dem Häkchen.'
|
||||
const ZU_VIELE = 'Zu viele Anfragen. Bitte später erneut versuchen.'
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export const GESPERRT_MELDUNG = {
|
||||
storniert: 'Diese Auftragsbestätigung wurde storniert.',
|
||||
widerrufen: 'Diese Auftragsbestätigung wurde widerrufen.',
|
||||
}
|
||||
export const UNGUELTIGER_LINK = 'Dieser Link ist ungültig oder abgelaufen.'
|
||||
const NICHT_BESTAETIGBAR = 'Diese Auftragsbestätigung kann nicht bestätigt werden.'
|
||||
const NICHT_GEFUNDEN = 'Auftragsbestätigung nicht gefunden.'
|
||||
const GESPERRT_STATUS = ['entwurf', 'ersetzt', 'storniert', 'widerrufen']
|
||||
@@ -39,6 +40,14 @@ export async function bestaetigeAuftrag(auftrag, { ueber, fruehbeginn, jetzt = n
|
||||
if (!frisch) throw new AuftragError(404, NICHT_GEFUNDEN)
|
||||
const lage = bestaetigungsLage(frisch)
|
||||
if (lage === 'gesperrt') throw new AuftragError(409, GESPERRT_MELDUNG[frisch.status] ?? NICHT_BESTAETIGBAR)
|
||||
if (ueber === 'link') {
|
||||
// Die Route hat Token und Ablauf auf einem Stand ausserhalb der Sperre geprueft; eine Erinnerung (Token-Tausch) kann
|
||||
// dazwischen gelaufen sein: dann gilt der alte Link nicht mehr, wie bei jedem ungueltigen Link (404)
|
||||
const bis = frisch.tokenGueltigBis ? Date.parse(frisch.tokenGueltigBis) : Number.NaN
|
||||
if (!frisch.tokenHash || frisch.tokenHash !== auftrag.tokenHash || !Number.isFinite(bis) || jetzt.getTime() > bis) {
|
||||
throw new AuftragError(404, UNGUELTIGER_LINK)
|
||||
}
|
||||
}
|
||||
if (lage === 'bestaetigt') return { aktuell: frisch, bestaetigtJetzt: false }
|
||||
const privat = frisch.kunde?.kundenart === 'privat'
|
||||
const patch = {
|
||||
|
||||
@@ -3,13 +3,13 @@ import assert from 'node:assert/strict'
|
||||
import { startAppwriteMock } from './support/appwriteMock.js'
|
||||
import { useTestEnv } from './support/testEnv.js'
|
||||
import { mailSink } from './support/mailSink.js'
|
||||
import { AUFTRAEGE_DATETIMES, AUFTRAEGE_SCHEMA, abDokument, kunde } from './auftraegeBestaetigungHilfe.js'
|
||||
import { AUFTRAEGE_DATETIMES, AUFTRAEGE_SCHEMA, UNGUELTIG, TOKEN_NEU, abDokument, kunde } from './auftraegeBestaetigungHilfe.js'
|
||||
|
||||
// bestaetigung.js: Bestätigen (idempotent, unter Sperre) und Widerrufen einer AB; Mails über die Senke
|
||||
const aw = await startAppwriteMock({ schema: AUFTRAEGE_SCHEMA, datetimes: AUFTRAEGE_DATETIMES, defaultLimit: 25 })
|
||||
useTestEnv({ appwriteUrl: aw.url, stripeUrl: 'http://127.0.0.1:1' })
|
||||
const { config } = await import('../server/config.js')
|
||||
const { auftragToDoc, getAuftrag } = await import('../server/services/auftraege/auftragStore.js')
|
||||
const { auftragToDoc, getAuftrag, updateAuftrag } = await import('../server/services/auftraege/auftragStore.js')
|
||||
const { AuftragError } = await import('../server/services/auftraege/fehler.js')
|
||||
const { FRUEHBEGINN_FASSUNG, FRUEHBEGINN_TEXT } = await import('../server/services/auftraege/texte.js')
|
||||
const { sperreAuftrag } = await import('../server/services/auftraege/konstanten.js')
|
||||
@@ -174,6 +174,25 @@ test('bestaetigeAuftrag: ungültiger Weg oder Zeitpunkt wirft TypeError, unbekan
|
||||
assert.equal(sink.sent.length, 0)
|
||||
})
|
||||
|
||||
test('bestaetigeAuftrag über den Link: ein Token-Tausch (Erinnerung) oder Ablauf zwischen Prüfung und Sperre ergibt 404 wie bei ungültigem Link', async () => {
|
||||
const alt = seed()
|
||||
const nichtsGeaendert = async () => {
|
||||
assert.equal((await getAuftrag('ab1')).status, 'versendet')
|
||||
assert.equal(sink.sent.length, 0)
|
||||
}
|
||||
// die Erinnerung tauscht den Token, nachdem die Route den alten geprüft hat
|
||||
const { hashToken } = await import('../server/services/auftraege/token.js')
|
||||
await updateAuftrag('ab1', { tokenHash: hashToken(TOKEN_NEU) })
|
||||
await assert.rejects(bestaetigeAuftrag(alt, { ueber: 'link', fruehbeginn: false, jetzt: JETZT }), (err) => err instanceof AuftragError && err.status === 404 && err.message === UNGUELTIG)
|
||||
await nichtsGeaendert()
|
||||
// der Link ist inzwischen abgelaufen
|
||||
await updateAuftrag('ab1', { tokenHash: alt.tokenHash, tokenGueltigBis: '2026-10-07T08:29:59.000Z' })
|
||||
await assert.rejects(bestaetigeAuftrag(alt, { ueber: 'link', fruehbeginn: false, jetzt: JETZT }), (err) => err instanceof AuftragError && err.status === 404 && err.message === UNGUELTIG)
|
||||
await nichtsGeaendert()
|
||||
// das Portal braucht keinen Link: dort zaehlt der Token nicht
|
||||
assert.equal((await bestaetigeAuftrag(alt, { ueber: 'portal', fruehbeginn: false, jetzt: JETZT })).status, 'bestaetigt')
|
||||
})
|
||||
|
||||
// gesendet am 06.10.2026 12:00 Berlin: die Frist endet am 20.10.2026 um 24 Uhr (= 21:59:59,999 UTC)
|
||||
const FRIST_ENDE = new Date('2026-10-20T21:59:59.999Z')
|
||||
|
||||
|
||||
Reference in new issue
Block a user