mirror of
https://github.com/documenso/documenso.git
synced 2026-08-25 15:52:29 +10:00
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
|
import { assertRateLimit } from '@documenso/lib/server-only/rate-limit/rate-limit-middleware';
|
|
import { qrSignatureCompleteRateLimit } from '@documenso/lib/server-only/rate-limit/rate-limits';
|
|
import { prisma } from '@documenso/prisma';
|
|
import { AnonymousVerificationTokenType } from '@prisma/client';
|
|
|
|
import { procedure } from '../../trpc';
|
|
import { ZCompleteQrSignatureRequestSchema, ZCompleteQrSignatureResponseSchema } from './complete-qr-signature.types';
|
|
|
|
/**
|
|
* NOTE: THIS IS A PUBLIC (UNAUTHENTICATED) PROCEDURE.
|
|
*
|
|
* Called from the mobile signing page to attach a drawn signature to a QR
|
|
* signature session. The desktop pad picks it up by polling `qr.get`.
|
|
*/
|
|
export const completeQrSignatureRoute = procedure
|
|
.input(ZCompleteQrSignatureRequestSchema)
|
|
.output(ZCompleteQrSignatureResponseSchema)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const { token, signature } = input;
|
|
|
|
const { ipAddress } = ctx.metadata.requestMetadata;
|
|
|
|
const rateLimitResult = await qrSignatureCompleteRateLimit.check({
|
|
ip: ipAddress ?? 'unknown',
|
|
identifier: token,
|
|
});
|
|
|
|
assertRateLimit(rateLimitResult);
|
|
|
|
const qrSignatureSession = await prisma.anonymousVerificationToken.findFirst({
|
|
where: {
|
|
token,
|
|
type: AnonymousVerificationTokenType.QR_SIGNATURE,
|
|
},
|
|
});
|
|
|
|
if (!qrSignatureSession) {
|
|
throw new AppError(AppErrorCode.NOT_FOUND, {
|
|
message: 'QR signature session not found or expired',
|
|
});
|
|
}
|
|
|
|
if (qrSignatureSession.expiresAt < new Date()) {
|
|
throw new AppError(AppErrorCode.EXPIRED_CODE, {
|
|
message: 'QR signature session has expired',
|
|
});
|
|
}
|
|
|
|
if (qrSignatureSession.value) {
|
|
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
|
message: 'A signature has already been submitted for this session',
|
|
});
|
|
}
|
|
|
|
const { count: updatedCount } = await prisma.anonymousVerificationToken.updateMany({
|
|
where: {
|
|
id: qrSignatureSession.id,
|
|
type: AnonymousVerificationTokenType.QR_SIGNATURE,
|
|
value: null,
|
|
},
|
|
data: {
|
|
value: signature,
|
|
},
|
|
});
|
|
|
|
if (updatedCount === 0) {
|
|
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
|
message: 'A signature has already been submitted for this session',
|
|
});
|
|
}
|
|
});
|