🔒️ Block temporary inboxes (#1602)

This commit is contained in:
Luke Vella 2025-03-03 18:27:52 +00:00 committed by GitHub
parent cf9ab1b265
commit 35c3d0bb4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 86 additions and 1 deletions

View file

@ -30,6 +30,7 @@
"editVotes": "Edit votes",
"email": "Email",
"emailNotAllowed": "This email is not allowed.",
"temporaryEmailNotAllowed": "Temporary or disposable email addresses are not allowed.",
"emailPlaceholder": "jessie.smith@example.com",
"exportToCsv": "Export to CSV",
"guest": "Guest",

View file

@ -51,6 +51,14 @@ export function RegisterNameForm() {
message: t("emailNotAllowed"),
});
break;
case "temporaryEmailNotAllowed":
form.setError("email", {
message: t("temporaryEmailNotAllowed", {
defaultValue:
"Temporary or disposable email addresses are not allowed.",
}),
});
break;
case "userAlreadyExists":
form.setError("email", {
message: t("userAlreadyExists"),

View file

@ -0,0 +1,65 @@
// List of common temporary/disposable email domains
export const temporaryEmailDomains = [
"10minutemail.com",
"temp-mail.org",
"fakeinbox.com",
"tempinbox.com",
"mailinator.com",
"guerrillamail.com",
"guerrillamail.net",
"guerrillamail.org",
"sharklasers.com",
"grr.la",
"yopmail.com",
"yopmail.fr",
"yopmail.net",
"cool.fr.nf",
"jetable.org",
"nospam.ze.tc",
"nomail.xl.cx",
"mega.zik.dj",
"speed.1s.fr",
"courriel.fr.nf",
"moncourrier.fr.nf",
"monemail.fr.nf",
"monmail.fr.nf",
"tempr.email",
"discard.email",
"discardmail.com",
"throwawaymail.com",
"trashmail.com",
"mailnesia.com",
"mailnull.com",
"maildrop.cc",
"getairmail.com",
"getnada.com",
"emailondeck.com",
"emailfake.com",
"mohmal.com",
"tempmail.ninja",
"temp-mail.io",
"disposable-email.com",
"tempmailaddress.com",
"tempail.com",
"tempemail.co",
"tempmail.plus",
"burnermail.io",
"spamgourmet.com",
"mytemp.email",
"incognitomail.com",
"mintemail.com",
"tempmailo.com",
"temporary-mail.net",
"mailto.plus",
"ethereal.mail",
];
/**
* Checks if an email domain is a known temporary/disposable email service
*/
export const isTemporaryEmail = (email: string): boolean => {
const domain = email.split("@")[1]?.toLowerCase();
if (!domain) return false;
return temporaryEmailDomains.includes(domain);
};

View file

@ -6,6 +6,7 @@ import { z } from "zod";
import { isEmailBlocked } from "@/auth/helpers/is-email-blocked";
import { mergeGuestsIntoUser } from "@/auth/helpers/merge-user";
import { isTemporaryEmail } from "@/auth/helpers/temp-email-domains";
import { getEmailClient } from "@/utils/emails";
import { createToken, decryptToken } from "@/utils/session";
@ -42,12 +43,22 @@ export const auth = router({
ctx,
}): Promise<
| { ok: true; token: string }
| { ok: false; reason: "userAlreadyExists" | "emailNotAllowed" }
| {
ok: false;
reason:
| "userAlreadyExists"
| "emailNotAllowed"
| "temporaryEmailNotAllowed";
}
> => {
if (isEmailBlocked?.(input.email)) {
return { ok: false, reason: "emailNotAllowed" };
}
if (isTemporaryEmail(input.email)) {
return { ok: false, reason: "temporaryEmailNotAllowed" };
}
const user = await prisma.user.findUnique({
select: {
id: true,