mirror of
https://github.com/documenso/documenso.git
synced 2025-11-15 09:12:02 +10:00
feat: add envelope editor
This commit is contained in:
@ -7,7 +7,7 @@ import { DOCUMENSO_ENCRYPTION_KEY } from '../../../constants/crypto';
|
||||
const ISSUER = 'Documenso Email 2FA';
|
||||
|
||||
export type GenerateTwoFactorCredentialsFromEmailOptions = {
|
||||
documentId: number;
|
||||
envelopeId: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
@ -18,14 +18,14 @@ export type GenerateTwoFactorCredentialsFromEmailOptions = {
|
||||
* @returns Object containing the token and the 6-digit code
|
||||
*/
|
||||
export const generateTwoFactorCredentialsFromEmail = ({
|
||||
documentId,
|
||||
envelopeId,
|
||||
email,
|
||||
}: GenerateTwoFactorCredentialsFromEmailOptions) => {
|
||||
if (!DOCUMENSO_ENCRYPTION_KEY) {
|
||||
throw new Error('Missing DOCUMENSO_ENCRYPTION_KEY');
|
||||
}
|
||||
|
||||
const identity = `email-2fa|v1|email:${email}|id:${documentId}`;
|
||||
const identity = `email-2fa|v1|email:${email}|id:${envelopeId}`;
|
||||
|
||||
const secret = hmac(sha256, DOCUMENSO_ENCRYPTION_KEY, identity);
|
||||
|
||||
|
||||
@ -3,17 +3,17 @@ import { generateHOTP } from 'oslo/otp';
|
||||
import { generateTwoFactorCredentialsFromEmail } from './generate-2fa-credentials-from-email';
|
||||
|
||||
export type GenerateTwoFactorTokenFromEmailOptions = {
|
||||
documentId: number;
|
||||
envelopeId: string;
|
||||
email: string;
|
||||
period?: number;
|
||||
};
|
||||
|
||||
export const generateTwoFactorTokenFromEmail = async ({
|
||||
email,
|
||||
documentId,
|
||||
envelopeId,
|
||||
period = 30_000,
|
||||
}: GenerateTwoFactorTokenFromEmailOptions) => {
|
||||
const { secret } = generateTwoFactorCredentialsFromEmail({ email, documentId });
|
||||
const { secret } = generateTwoFactorCredentialsFromEmail({ email, envelopeId });
|
||||
|
||||
const counter = Math.floor(Date.now() / period);
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { AccessAuth2FAEmailTemplate } from '@documenso/email/templates/access-auth-2fa';
|
||||
@ -11,6 +12,7 @@ import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app';
|
||||
import { AppError, AppErrorCode } from '../../../errors/app-error';
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
|
||||
import { createDocumentAuditLogData } from '../../../utils/document-audit-logs';
|
||||
import { unsafeBuildEnvelopeIdQuery } from '../../../utils/envelope';
|
||||
import { renderEmailWithI18N } from '../../../utils/render-email-with-i18n';
|
||||
import { getEmailContext } from '../../email/get-email-context';
|
||||
import { TWO_FACTOR_EMAIL_EXPIRATION_MINUTES } from './constants';
|
||||
@ -18,13 +20,19 @@ import { generateTwoFactorTokenFromEmail } from './generate-2fa-token-from-email
|
||||
|
||||
export type Send2FATokenEmailOptions = {
|
||||
token: string;
|
||||
documentId: number;
|
||||
envelopeId: string;
|
||||
};
|
||||
|
||||
export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmailOptions) => {
|
||||
const document = await prisma.document.findFirst({
|
||||
export const send2FATokenEmail = async ({ token, envelopeId }: Send2FATokenEmailOptions) => {
|
||||
const envelope = await prisma.envelope.findFirst({
|
||||
where: {
|
||||
id: documentId,
|
||||
...unsafeBuildEnvelopeIdQuery(
|
||||
{
|
||||
type: 'envelopeId',
|
||||
id: envelopeId,
|
||||
},
|
||||
EnvelopeType.DOCUMENT,
|
||||
),
|
||||
recipients: {
|
||||
some: {
|
||||
token,
|
||||
@ -47,13 +55,13 @@ export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmail
|
||||
},
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
if (!envelope) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Document not found',
|
||||
});
|
||||
}
|
||||
|
||||
const [recipient] = document.recipients;
|
||||
const [recipient] = envelope.recipients;
|
||||
|
||||
if (!recipient) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
@ -62,7 +70,7 @@ export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmail
|
||||
}
|
||||
|
||||
const twoFactorTokenToken = await generateTwoFactorTokenFromEmail({
|
||||
documentId,
|
||||
envelopeId,
|
||||
email: recipient.email,
|
||||
});
|
||||
|
||||
@ -70,9 +78,9 @@ export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmail
|
||||
emailType: 'RECIPIENT',
|
||||
source: {
|
||||
type: 'team',
|
||||
teamId: document.teamId,
|
||||
teamId: envelope.teamId,
|
||||
},
|
||||
meta: document.documentMeta,
|
||||
meta: envelope.documentMeta,
|
||||
});
|
||||
|
||||
const i18n = await getI18nInstance(emailLanguage);
|
||||
@ -80,7 +88,7 @@ export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmail
|
||||
const subject = i18n._(msg`Your two-factor authentication code`);
|
||||
|
||||
const template = createElement(AccessAuth2FAEmailTemplate, {
|
||||
documentTitle: document.title,
|
||||
documentTitle: envelope.title,
|
||||
userName: recipient.name,
|
||||
userEmail: recipient.email,
|
||||
code: twoFactorTokenToken,
|
||||
@ -110,7 +118,7 @@ export const send2FATokenEmail = async ({ token, documentId }: Send2FATokenEmail
|
||||
await tx.documentAuditLog.create({
|
||||
data: createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ACCESS_AUTH_2FA_REQUESTED,
|
||||
documentId: document.id,
|
||||
envelopeId: envelope.id,
|
||||
data: {
|
||||
recipientEmail: recipient.email,
|
||||
recipientName: recipient.name,
|
||||
|
||||
@ -3,7 +3,7 @@ import { generateHOTP } from 'oslo/otp';
|
||||
import { generateTwoFactorCredentialsFromEmail } from './generate-2fa-credentials-from-email';
|
||||
|
||||
export type ValidateTwoFactorTokenFromEmailOptions = {
|
||||
documentId: number;
|
||||
envelopeId: string;
|
||||
email: string;
|
||||
code: string;
|
||||
period?: number;
|
||||
@ -11,13 +11,13 @@ export type ValidateTwoFactorTokenFromEmailOptions = {
|
||||
};
|
||||
|
||||
export const validateTwoFactorTokenFromEmail = async ({
|
||||
documentId,
|
||||
envelopeId,
|
||||
email,
|
||||
code,
|
||||
period = 30_000,
|
||||
window = 1,
|
||||
}: ValidateTwoFactorTokenFromEmailOptions) => {
|
||||
const { secret } = generateTwoFactorCredentialsFromEmail({ email, documentId });
|
||||
const { secret } = generateTwoFactorCredentialsFromEmail({ email, envelopeId });
|
||||
|
||||
let now = Date.now();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user