diff --git a/entrypoints/popup/utils.ts b/entrypoints/popup/utils.ts index c1fd4f0..aa9af8d 100644 --- a/entrypoints/popup/utils.ts +++ b/entrypoints/popup/utils.ts @@ -56,12 +56,26 @@ export function filterAliasesForAccount( /** Creates a plus-addressed alias (user+tag@domain), or null if the base email is malformed. */ export function generateAlias(baseEmail: string, tag: string): string | null { - const parts = baseEmail.trim().split("@"); + const normalizedEmail = baseEmail.trim(); + const normalizedTag = tag.trim(); + const parts = normalizedEmail.split("@"); if (parts.length !== 2) return null; const [username, domain] = parts; - if (!username || !domain) return null; - return `${username}+${tag}@${domain}`; + if (!username || !domain || !domain.includes(".")) return null; + + // A plus tag becomes part of the email local-part. Whitespace, an @ sign, + // or control characters would create an address that cannot be safely used + // in forms and could also introduce a second domain separator. + if ( + !normalizedTag || + /[\\s@]/.test(normalizedTag) || + /[\\u0000-\\u001f\\u007f]/.test(normalizedTag) + ) { + return null; + } + + return `${username}+${normalizedTag}@${domain}`; } export type RandomFormat = diff --git a/tests/popup/utils.test.ts b/tests/popup/utils.test.ts index c36ee7e..ff095e3 100644 --- a/tests/popup/utils.test.ts +++ b/tests/popup/utils.test.ts @@ -160,6 +160,28 @@ describe("generateAlias", () => { "user+private-mail-abc1@gmail.com", ); }); + + it("trims surrounding whitespace from tags", () => { + expect(generateAlias("user@gmail.com", " shopping ")).toBe( + "user+shopping@gmail.com", + ); + }); + + it("rejects an empty tag", () => { + expect(generateAlias("user@gmail.com", " ")).toBeNull(); + }); + + it("rejects tags containing whitespace", () => { + expect(generateAlias("user@gmail.com", "project alpha")).toBeNull(); + }); + + it("rejects tags containing an @ sign", () => { + expect(generateAlias("user@gmail.com", "shop@example.com")).toBeNull(); + }); + + it("rejects a base email without a routable domain", () => { + expect(generateAlias("user@localhost", "tag")).toBeNull(); + }); }); // ─── generateRandomString ────────────────────────────────────────────────────