mirror of
https://github.com/documenso/documenso.git
synced 2025-11-19 03:01:59 +10:00
Merge branch 'main' into feat/add-attachments-reworked
This commit is contained in:
@ -0,0 +1,94 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { TWO_FACTOR_EMAIL_EXPIRATION_MINUTES } from '@documenso/lib/server-only/2fa/email/constants';
|
||||
import { send2FATokenEmail } from '@documenso/lib/server-only/2fa/email/send-2fa-token-email';
|
||||
import { DocumentAuth } from '@documenso/lib/types/document-auth';
|
||||
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { procedure } from '../trpc';
|
||||
import {
|
||||
ZAccessAuthRequest2FAEmailRequestSchema,
|
||||
ZAccessAuthRequest2FAEmailResponseSchema,
|
||||
} from './access-auth-request-2fa-email.types';
|
||||
|
||||
export const accessAuthRequest2FAEmailRoute = procedure
|
||||
.input(ZAccessAuthRequest2FAEmailRequestSchema)
|
||||
.output(ZAccessAuthRequest2FAEmailResponseSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { token } = input;
|
||||
|
||||
const user = ctx.user;
|
||||
|
||||
// Get document and recipient by token
|
||||
const document = await prisma.document.findFirst({
|
||||
where: {
|
||||
recipients: {
|
||||
some: {
|
||||
token,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: {
|
||||
recipients: {
|
||||
where: {
|
||||
token,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: 'Document not found',
|
||||
});
|
||||
}
|
||||
|
||||
const [recipient] = document.recipients;
|
||||
|
||||
const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({
|
||||
documentAuth: document.authOptions,
|
||||
recipientAuth: recipient.authOptions,
|
||||
});
|
||||
|
||||
if (!derivedRecipientAccessAuth.includes(DocumentAuth.TWO_FACTOR_AUTH)) {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: '2FA is not required for this document',
|
||||
});
|
||||
}
|
||||
|
||||
// if (user && recipient.email !== user.email) {
|
||||
// throw new TRPCError({
|
||||
// code: 'UNAUTHORIZED',
|
||||
// message: 'User does not match recipient',
|
||||
// });
|
||||
// }
|
||||
|
||||
const expiresAt = DateTime.now().plus({ minutes: TWO_FACTOR_EMAIL_EXPIRATION_MINUTES });
|
||||
|
||||
await send2FATokenEmail({
|
||||
token,
|
||||
documentId: document.id,
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
expiresAt: expiresAt.toJSDate(),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error sending access auth 2FA email:', error);
|
||||
|
||||
if (error instanceof TRPCError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: 'Failed to send 2FA email',
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZAccessAuthRequest2FAEmailRequestSchema = z.object({
|
||||
token: z.string().min(1),
|
||||
});
|
||||
|
||||
export const ZAccessAuthRequest2FAEmailResponseSchema = z.object({
|
||||
success: z.boolean(),
|
||||
expiresAt: z.date(),
|
||||
});
|
||||
|
||||
export type TAccessAuthRequest2FAEmailRequest = z.infer<
|
||||
typeof ZAccessAuthRequest2FAEmailRequestSchema
|
||||
>;
|
||||
export type TAccessAuthRequest2FAEmailResponse = z.infer<
|
||||
typeof ZAccessAuthRequest2FAEmailResponseSchema
|
||||
>;
|
||||
@ -78,14 +78,7 @@ export const ZCreateDocumentTemporaryRequestSchema = z.object({
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.refine(
|
||||
(recipients) => {
|
||||
const emails = recipients.map((recipient) => recipient.email);
|
||||
|
||||
return new Set(emails).size === emails.length;
|
||||
},
|
||||
{ message: 'Recipients must have unique emails' },
|
||||
)
|
||||
.optional(),
|
||||
meta: z
|
||||
.object({
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { router } from '../trpc';
|
||||
import { accessAuthRequest2FAEmailRoute } from './access-auth-request-2fa-email';
|
||||
import { createDocumentRoute } from './create-document';
|
||||
import { createDocumentTemporaryRoute } from './create-document-temporary';
|
||||
import { deleteDocumentRoute } from './delete-document';
|
||||
@ -40,6 +41,10 @@ export const documentRouter = router({
|
||||
getDocumentByToken: getDocumentByTokenRoute,
|
||||
findDocumentsInternal: findDocumentsInternalRoute,
|
||||
|
||||
accessAuth: router({
|
||||
request2FAEmail: accessAuthRequest2FAEmailRoute,
|
||||
}),
|
||||
|
||||
auditLog: {
|
||||
find: findDocumentAuditLogsRoute,
|
||||
download: downloadDocumentAuditLogsRoute,
|
||||
|
||||
Reference in New Issue
Block a user