Files
documenso/packages/ee/server-only/lib/reregister-email-domain.ts
T
ephraimduncan 138d663c25 chore: merge main, resolve biome formatting conflicts
Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
2026-05-12 11:46:11 +00:00

93 lines
2.7 KiB
TypeScript

import { DeleteEmailIdentityCommand } from '@aws-sdk/client-sesv2';
import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
import { prisma } from '@documenso/prisma';
import { EmailDomainStatus } from '@prisma/client';
import { getSesClient, verifyDomainWithDKIM } from './create-email-domain';
type ReregisterEmailDomainOptions = {
emailDomainId: string;
};
/**
* Re-register an email domain in SES using the same DKIM key pair.
*
* This deletes the existing SES identity and recreates it with the same
* selector and private key, so the user does not need to update their DNS records.
*
* Permission is assumed to be checked in the caller.
*/
export const reregisterEmailDomain = async ({ emailDomainId }: ReregisterEmailDomainOptions) => {
const encryptionKey = DOCUMENSO_ENCRYPTION_KEY;
if (!encryptionKey) {
throw new Error('Missing DOCUMENSO_ENCRYPTION_KEY');
}
const emailDomain = await prisma.emailDomain.findUnique({
where: {
id: emailDomainId,
},
});
if (!emailDomain) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Email domain not found',
});
}
const sesClient = getSesClient();
// Delete the existing SES identity, ignoring if it no longer exists.
await sesClient
.send(
new DeleteEmailIdentityCommand({
EmailIdentity: emailDomain.domain,
}),
)
.catch((err) => {
if (err.name === 'NotFoundException') {
return;
}
throw err;
});
// Decrypt the stored private key.
const decryptedPrivateKeyBytes = symmetricDecrypt({
key: encryptionKey,
data: emailDomain.privateKey,
});
const decryptedPrivateKey = new TextDecoder().decode(decryptedPrivateKeyBytes);
// The selector field in the DB is the full record name (e.g. "documenso-orgid._domainkey.example.com").
// We need to extract just the selector part (before "._domainkey.").
const selectorParts = emailDomain.selector.split('._domainkey.');
const selector = selectorParts[0];
if (!selector) {
throw new AppError(AppErrorCode.UNKNOWN_ERROR, {
message: 'Could not extract selector from email domain record',
});
}
// Recreate the SES identity with the same DKIM key pair.
await verifyDomainWithDKIM(emailDomain.domain, selector, decryptedPrivateKey);
// Reset status to PENDING and update lastVerifiedAt.
const updatedEmailDomain = await prisma.emailDomain.update({
where: {
id: emailDomainId,
},
data: {
status: EmailDomainStatus.PENDING,
lastVerifiedAt: new Date(),
},
});
return updatedEmailDomain;
};