feat: add qr signatures

This commit is contained in:
David Nguyen
2026-08-18 11:49:15 +10:00
parent 779de01fe8
commit 9825ea88b1
99 changed files with 1686 additions and 48 deletions
@@ -1,4 +1,5 @@
import { prisma } from '@documenso/prisma';
import { AnonymousVerificationTokenType } from '@prisma/client';
import { generateAuthenticationOptions } from '@simplewebauthn/server';
import { DateTime } from 'luxon';
@@ -24,12 +25,14 @@ export const createPasskeySigninOptions = async ({ sessionId }: CreatePasskeySig
id: sessionId,
},
update: {
type: AnonymousVerificationTokenType.PASSKEY,
token: challenge,
expiresAt: DateTime.now().plus({ minutes: 2 }).toJSDate(),
createdAt: new Date(),
},
create: {
id: sessionId,
type: AnonymousVerificationTokenType.PASSKEY,
token: challenge,
expiresAt: DateTime.now().plus({ minutes: 2 }).toJSDate(),
createdAt: new Date(),
@@ -31,6 +31,7 @@ export type CreateDocumentMetaOptions = {
typedSignatureEnabled?: boolean;
uploadSignatureEnabled?: boolean;
drawSignatureEnabled?: boolean;
qrSignatureEnabled?: boolean;
language?: SupportedLanguageCodes;
requestMetadata: ApiRequestMetadata;
};
@@ -53,6 +54,7 @@ export const updateDocumentMeta = async ({
typedSignatureEnabled,
uploadSignatureEnabled,
drawSignatureEnabled,
qrSignatureEnabled,
language,
requestMetadata,
}: CreateDocumentMetaOptions) => {
@@ -132,6 +134,7 @@ export const updateDocumentMeta = async ({
typedSignatureEnabled,
uploadSignatureEnabled,
drawSignatureEnabled,
qrSignatureEnabled,
language,
},
});
@@ -47,6 +47,7 @@ export const ZEnvelopeForSigningResponse = z.object({
typedSignatureEnabled: true,
uploadSignatureEnabled: true,
drawSignatureEnabled: true,
qrSignatureEnabled: true,
allowDictateNextSigner: true,
language: true,
}),
@@ -72,6 +72,21 @@ export const reportSenderRateLimit = createRateLimit({
window: '7d',
});
// ---- Signature (QR mobile handoff) ----
export const qrSignatureCreateRateLimit = createRateLimit({
action: 'signature.qr-create',
max: 20,
window: '15m',
});
export const qrSignatureCompleteRateLimit = createRateLimit({
action: 'signature.qr-complete',
max: 20,
globalMax: 60,
window: '15m',
});
// ---- Billing ----
export const syncSubscriptionRateLimit = createRateLimit({
@@ -112,6 +112,7 @@ export type CreateDocumentFromTemplateOptions = {
typedSignatureEnabled?: boolean;
uploadSignatureEnabled?: boolean;
drawSignatureEnabled?: boolean;
qrSignatureEnabled?: boolean;
envelopeExpirationPeriod?: TEnvelopeExpirationPeriod | null;
};
@@ -540,6 +541,7 @@ export const createDocumentFromTemplate = async ({
typedSignatureEnabled: override?.typedSignatureEnabled ?? template.documentMeta?.typedSignatureEnabled,
uploadSignatureEnabled: override?.uploadSignatureEnabled ?? template.documentMeta?.uploadSignatureEnabled,
drawSignatureEnabled: override?.drawSignatureEnabled ?? template.documentMeta?.drawSignatureEnabled,
qrSignatureEnabled: override?.qrSignatureEnabled ?? template.documentMeta?.qrSignatureEnabled,
allowDictateNextSigner: override?.allowDictateNextSigner ?? template.documentMeta?.allowDictateNextSigner,
envelopeExpirationPeriod: override?.envelopeExpirationPeriod ?? template.documentMeta?.envelopeExpirationPeriod,
},
@@ -46,6 +46,7 @@ export const generateSampleWebhookPayload = (event: WebhookTriggerEvents, webhoo
typedSignatureEnabled: true,
uploadSignatureEnabled: true,
drawSignatureEnabled: true,
qrSignatureEnabled: true,
language: 'en',
distributionMethod: DocumentDistributionMethod.EMAIL,
emailSettings: null,