refactor(signing-2fa): simplify server-side and UI code for external 2FA

- Extract throwVerificationError helper in verify-signing-two-factor-token.ts
- Extract throwIssuanceDenied helper in issue-signing-two-factor-token.ts
- Eliminate duplicated attemptsRemaining state in UI component
- Use imported SIGNING_2FA_VERIFY_REASON_CODES constants
- Add statusQuery.refetch() after failed verify for single source of truth
- Fix TypeScript control flow with explicit returns after throws
This commit is contained in:
ephraimduncan
2026-02-10 12:39:13 +00:00
parent f1c91c4951
commit bd56929db1
34 changed files with 2406 additions and 21 deletions
+58
View File
@@ -430,6 +430,9 @@ model Envelope {
envelopeAttachments EnvelopeAttachment[]
signingTwoFactorTokens SigningTwoFactorToken[]
signingSessionTwoFactorProofs SigningSessionTwoFactorProof[]
@@index([type])
@@index([status])
@@index([userId])
@@ -588,6 +591,9 @@ model Recipient {
fields Field[]
signatures Signature[]
signingTwoFactorTokens SigningTwoFactorToken[]
signingSessionTwoFactorProofs SigningSessionTwoFactorProof[]
@@index([token])
@@index([email])
@@index([envelopeId])
@@ -1076,3 +1082,55 @@ model Counter {
id String @id
value Int
}
enum SigningTwoFactorTokenStatus {
ACTIVE
CONSUMED
REVOKED
EXPIRED
}
model SigningTwoFactorToken {
id String @id @default(cuid())
recipientId Int
envelopeId String
tokenHash String
tokenSalt String
status SigningTwoFactorTokenStatus @default(ACTIVE)
expiresAt DateTime
consumedAt DateTime?
revokedAt DateTime?
attempts Int @default(0)
attemptLimit Int @default(5)
issuedByApiTokenId Int?
createdAt DateTime @default(now())
recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
envelope Envelope @relation(fields: [envelopeId], references: [id], onDelete: Cascade)
@@index([recipientId, envelopeId, status])
@@index([envelopeId])
}
model SigningSessionTwoFactorProof {
id String @id @default(cuid())
sessionId String
recipientId Int
envelopeId String
verifiedAt DateTime @default(now())
expiresAt DateTime
recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
envelope Envelope @relation(fields: [envelopeId], references: [id], onDelete: Cascade)
@@unique([sessionId, recipientId, envelopeId])
@@index([recipientId, envelopeId])
@@index([expiresAt])
}