fix(email): add dns validation of email addresses

This commit is contained in:
Hampus Kraft
2026-02-19 19:33:55 +00:00
parent 3cc07f5e9f
commit 17306abec6
11 changed files with 432 additions and 2 deletions

View File

@@ -19,7 +19,10 @@
import {Config} from '@fluxer/api/src/Config';
import type {IDonationRepository} from '@fluxer/api/src/donation/IDonationRepository';
import type {IEmailDnsValidationService} from '@fluxer/api/src/infrastructure/IEmailDnsValidationService';
import {Logger} from '@fluxer/api/src/Logger';
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
import {DonationAmountInvalidError} from '@fluxer/errors/src/domains/donation/DonationAmountInvalidError';
import {StripeError} from '@fluxer/errors/src/domains/payment/StripeError';
import {StripePaymentNotAvailableError} from '@fluxer/errors/src/domains/payment/StripePaymentNotAvailableError';
@@ -32,6 +35,7 @@ export class DonationCheckoutService {
constructor(
private stripe: Stripe | null,
private donationRepository: IDonationRepository,
private emailDnsValidationService: IEmailDnsValidationService,
) {}
async createCheckout(params: {
@@ -48,6 +52,11 @@ export class DonationCheckoutService {
throw new DonationAmountInvalidError();
}
const hasValidDns = await this.emailDnsValidationService.hasValidDnsRecords(params.email);
if (!hasValidDns) {
throw InputValidationError.fromCode('email', ValidationErrorCodes.INVALID_EMAIL_ADDRESS);
}
const isRecurring = params.interval !== null;
const existingDonor = await this.donationRepository.findDonorByEmail(params.email);

View File

@@ -21,9 +21,12 @@ import {randomBytes} from 'node:crypto';
import {Config} from '@fluxer/api/src/Config';
import type {IDonationRepository} from '@fluxer/api/src/donation/IDonationRepository';
import {DonorMagicLinkToken} from '@fluxer/api/src/donation/models/DonorMagicLinkToken';
import type {IEmailDnsValidationService} from '@fluxer/api/src/infrastructure/IEmailDnsValidationService';
import {Logger} from '@fluxer/api/src/Logger';
import {DONATION_MAGIC_LINK_EXPIRY_MS} from '@fluxer/constants/src/DonationConstants';
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
import type {IEmailService} from '@fluxer/email/src/IEmailService';
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
import {DonationMagicLinkExpiredError} from '@fluxer/errors/src/domains/donation/DonationMagicLinkExpiredError';
import {DonationMagicLinkInvalidError} from '@fluxer/errors/src/domains/donation/DonationMagicLinkInvalidError';
import {DonationMagicLinkUsedError} from '@fluxer/errors/src/domains/donation/DonationMagicLinkUsedError';
@@ -32,9 +35,15 @@ export class DonationMagicLinkService {
constructor(
private donationRepository: IDonationRepository,
private emailService: IEmailService,
private emailDnsValidationService: IEmailDnsValidationService,
) {}
async sendMagicLink(email: string): Promise<void> {
const hasValidDns = await this.emailDnsValidationService.hasValidDnsRecords(email);
if (!hasValidDns) {
throw InputValidationError.fromCode('email', ValidationErrorCodes.INVALID_EMAIL_ADDRESS);
}
const donor = await this.donationRepository.findDonorByEmail(email);
if (!donor) {
Logger.info({email}, 'Donation magic link requested for unknown donor');