feat: support 2fa for document completion (#2063)

Adds support for 2FA when completing a document, also adds support for
using email for 2FA when no authenticator has been associated with the
account.
This commit is contained in:
Lucas Smith
2025-10-06 16:17:54 +11:00
committed by GitHub
parent 3467317271
commit 995bc9c362
31 changed files with 1300 additions and 260 deletions

View File

@ -40,6 +40,11 @@ export const ZDocumentAuditLogTypeSchema = z.enum([
'DOCUMENT_TITLE_UPDATED', // When the document title is updated.
'DOCUMENT_EXTERNAL_ID_UPDATED', // When the document external ID is updated.
'DOCUMENT_MOVED_TO_TEAM', // When the document is moved to a team.
// ACCESS AUTH 2FA events.
'DOCUMENT_ACCESS_AUTH_2FA_REQUESTED', // When ACCESS AUTH 2FA is requested.
'DOCUMENT_ACCESS_AUTH_2FA_VALIDATED', // When ACCESS AUTH 2FA is successfully validated.
'DOCUMENT_ACCESS_AUTH_2FA_FAILED', // When ACCESS AUTH 2FA validation fails.
]);
export const ZDocumentAuditLogEmailTypeSchema = z.enum([
@ -487,6 +492,42 @@ export const ZDocumentAuditLogEventDocumentRecipientRejectedSchema = z.object({
}),
});
/**
* Event: Document recipient requested a 2FA token.
*/
export const ZDocumentAuditLogEventDocumentRecipientRequested2FAEmailSchema = z.object({
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ACCESS_AUTH_2FA_REQUESTED),
data: z.object({
recipientEmail: z.string(),
recipientName: z.string(),
recipientId: z.number(),
}),
});
/**
* Event: Document recipient validated a 2FA token.
*/
export const ZDocumentAuditLogEventDocumentRecipientValidated2FAEmailSchema = z.object({
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ACCESS_AUTH_2FA_VALIDATED),
data: z.object({
recipientEmail: z.string(),
recipientName: z.string(),
recipientId: z.number(),
}),
});
/**
* Event: Document recipient failed to validate a 2FA token.
*/
export const ZDocumentAuditLogEventDocumentRecipientFailed2FAEmailSchema = z.object({
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ACCESS_AUTH_2FA_FAILED),
data: z.object({
recipientEmail: z.string(),
recipientName: z.string(),
recipientId: z.number(),
}),
});
/**
* Event: Document sent.
*/
@ -627,6 +668,9 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
ZDocumentAuditLogEventDocumentViewedSchema,
ZDocumentAuditLogEventDocumentRecipientCompleteSchema,
ZDocumentAuditLogEventDocumentRecipientRejectedSchema,
ZDocumentAuditLogEventDocumentRecipientRequested2FAEmailSchema,
ZDocumentAuditLogEventDocumentRecipientValidated2FAEmailSchema,
ZDocumentAuditLogEventDocumentRecipientFailed2FAEmailSchema,
ZDocumentAuditLogEventDocumentSentSchema,
ZDocumentAuditLogEventDocumentTitleUpdatedSchema,
ZDocumentAuditLogEventDocumentExternalIdUpdatedSchema,

View File

@ -37,6 +37,7 @@ const ZDocumentAuthPasswordSchema = z.object({
const ZDocumentAuth2FASchema = z.object({
type: z.literal(DocumentAuth.TWO_FACTOR_AUTH),
token: z.string().min(4).max(10),
method: z.enum(['email', 'authenticator']).default('authenticator').optional(),
});
/**
@ -55,9 +56,12 @@ export const ZDocumentAuthMethodsSchema = z.discriminatedUnion('type', [
*
* Must keep these two in sync.
*/
export const ZDocumentAccessAuthSchema = z.discriminatedUnion('type', [ZDocumentAuthAccountSchema]);
export const ZDocumentAccessAuthSchema = z.discriminatedUnion('type', [
ZDocumentAuthAccountSchema,
ZDocumentAuth2FASchema,
]);
export const ZDocumentAccessAuthTypesSchema = z
.enum([DocumentAuth.ACCOUNT])
.enum([DocumentAuth.ACCOUNT, DocumentAuth.TWO_FACTOR_AUTH])
.describe('The type of authentication required for the recipient to access the document.');
/**
@ -89,9 +93,10 @@ export const ZDocumentActionAuthTypesSchema = z
*/
export const ZRecipientAccessAuthSchema = z.discriminatedUnion('type', [
ZDocumentAuthAccountSchema,
ZDocumentAuth2FASchema,
]);
export const ZRecipientAccessAuthTypesSchema = z
.enum([DocumentAuth.ACCOUNT])
.enum([DocumentAuth.ACCOUNT, DocumentAuth.TWO_FACTOR_AUTH])
.describe('The type of authentication required for the recipient to access the document.');
/**