Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make email regex reasonable #2157

Merged
merged 6 commits into from
May 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 64 additions & 34 deletions deno/lib/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,70 +39,97 @@ test("failing validations", () => {
});

test("email validations", () => {
const email = z.string().email();
email.parse("[email protected]");
expect(() => email.parse("asdf")).toThrow();
expect(() => email.parse("@lkjasdf.com")).toThrow();
expect(() => email.parse("asdf@sdf.")).toThrow();
expect(() => email.parse("[email protected]")).toThrow();
expect(() => email.parse("[email protected]")).toThrow();
expect(() => email.parse("asdf@-a(sdf.com")).toThrow();
expect(() => email.parse("[email protected](")).toThrow();
expect(() =>
email.parse("pawan.anand@%9y83&#$%R&#$%R&%#$R%%^^%5rw3ewe.d.d.aaaa.wef.co")
).toThrow();
});

test("more email validations", () => {
const validEmails = [
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`test/[email protected]`,
`[email protected]`,
`" "@example.org`,
`"john..doe"@example.org`,
`[email protected]`,
`"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`,
`user%[email protected]`,
`[email protected]`,
`postmaster@[123.123.123.123]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
];
const invalidEmails = [
// no "printable characters"
// `user%[email protected]`,
// `[email protected]`,
// `test/[email protected]`,

// double @
`francois@@etu.inp-n7.fr`,
// do not support quotes
`"email"@domain.com`,
`"e asdf sadf ?<>ail"@domain.com`,
`" "@example.org`,
`"john..doe"@example.org`,
`"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`,

// do not support IPv4
`[email protected]`,
`email@[123.123.123.123]`,
`[email protected]`,
`user@[68.185.127.196]`,
`ipv4@[85.129.96.247]`,
`valid@[79.208.229.53]`,
`valid@[255.255.255.255]`,
`valid@[255.0.55.2]`,
`valid@[255.0.55.2]`,

// do not support ipv6
`hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`,
`bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`,
`jsmith@[IPv6:2001:db8::1]`,
`postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`,
`postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
];
const invalidEmails = [

// microsoft test cases
`plainaddress`,
`#@%^%#$@#$@#.com`,
`@domain.com`,
`Joe Smith &lt;[email protected]&gt;`,
`email.domain.com`,
`email@[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`あいうえお@domain.com`,
`[email protected] (Joe Smith)`,
`email@domain`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`Abc.example.com`,
`A@b@[email protected]`,
`[email protected]`,
`a"b(c)d,e:f;g<h>i[j\k][email protected]`,
`just"not"[email protected]`,
`this is"not\[email protected]`,
`this\ still\"not\\[email protected]`,

// random
`i_like_underscore@but_its_not_allowed_in_this_part.example.com`,
`QA[icon]CHOCOLATE[icon]@test.com`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`invalid@[1.1.1.-1]`,
`invalid@[68.185.127.196.55]`,
`temp@[192.168.1]`,
Expand All @@ -121,13 +148,16 @@ test("more email validations", () => {
`[email protected]`,
];
const emailSchema = z.string().email();

expect(
validEmails.every((email) => emailSchema.safeParse(email).success)
validEmails.every((email) => {
return emailSchema.safeParse(email).success;
})
).toBe(true);
expect(
invalidEmails.every(
(email) => emailSchema.safeParse(email).success === false
)
invalidEmails.every((email) => {
return emailSchema.safeParse(email).success === false;
})
).toBe(true);
});

Expand Down
17 changes: 14 additions & 3 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,17 @@ const uuidRegex =
//old email regex
// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i;
// eslint-disable-next-line

// const emailRegex =
// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/;
// const emailRegex =
// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
// const emailRegex =
// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
const emailRegex =
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]\.?([A-Za-z0-9-]+\.)*([A-Za-z0-9-])*[A-Za-z0-9]))$/;
/^([A-Z0-9_+-]+\.?)*[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;
// const emailRegex =
// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i;

// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression
const emojiRegex = /^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u;

Expand Down Expand Up @@ -4174,7 +4182,10 @@ export class ZodPromise<T extends ZodTypeAny> extends ZodType<
//////////////////////////////////////////////

export type Refinement<T> = (arg: T, ctx: RefinementCtx) => any;
export type SuperRefinement<T> = (arg: T, ctx: RefinementCtx) => void | Promise<void>;
export type SuperRefinement<T> = (
arg: T,
ctx: RefinementCtx
) => void | Promise<void>;

export type RefinementEffect<T> = {
type: "refinement";
Expand Down
128 changes: 128 additions & 0 deletions playground.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,130 @@
import { z } from "./src";
z;

const validEmails = [
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
];
const invalidEmails = [
// no "printable characters"
// `user%[email protected]`,
// `[email protected]`,
// `test/[email protected]`,

// double @
`francois@@etu.inp-n7.fr`,

// do not support quotes
`"email"@domain.com`,
`"e asdf sadf ?<>ail"@domain.com`,
`" "@example.org`,
`"john..doe"@example.org`,
`"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`,

// do not support IPv4
`[email protected]`,
`email@[123.123.123.123]`,
`[email protected]`,
`user@[68.185.127.196]`,
`ipv4@[85.129.96.247]`,
`valid@[79.208.229.53]`,
`valid@[255.255.255.255]`,
`valid@[255.0.55.2]`,
`valid@[255.0.55.2]`,

// do not support ipv6
`hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`,
`bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`,
`jsmith@[IPv6:2001:db8::1]`,
`postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`,
`postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`,

// microsoft test cases
`plainaddress`,
`#@%^%#$@#$@#.com`,
`@domain.com`,
`Joe Smith &lt;[email protected]&gt;`,
`email.domain.com`,
`email@[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`あいうえお@domain.com`,
`[email protected] (Joe Smith)`,
`email@domain`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`Abc.example.com`,
`A@b@[email protected]`,
`[email protected]`,
`a"b(c)d,e:f;g<h>i[j\k][email protected]`,
`just"not"[email protected]`,
`this is"not\[email protected]`,
`this\ still\"not\\[email protected]`,

// random
`i_like_underscore@but_its_not_allowed_in_this_part.example.com`,
`QA[icon]CHOCOLATE[icon]@test.com`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`invalid@[1.1.1.-1]`,
`invalid@[68.185.127.196.55]`,
`temp@[192.168.1]`,
`temp@[9.18.122.]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`[email protected]`,
`invalid@[256.2.2.48]`,
`invalid@[256.2.2.48]`,
`invalid@[999.465.265.1]`,
`jkibbey4@[IPv6:82c4:19a8::70a9:2aac:557::ea69:d985:28d]`,
`mlivesay3@[9952:143f:b4df:2179:49a1:5e82:b92e:6b6]`,
`gbacher0@[IPv6:bc37:4d3f:5048:2e26:37cc:248e:df8e:2f7f:af]`,
`invalid@[IPv6:5348:4ed3:5d38:67fb:e9b:acd2:c13:192.168.256.1]`,
];

const emailSchema = z.string().email();
console.log(
validEmails.every((email) => {
const val = emailSchema.safeParse(email).success;
if (!val) console.log(`fail`, email);
return val;
})
);
// for (const email of validEmails) {
// console.log("good", email);
// emailSchema.parse(email);
// }
for (const email of invalidEmails) {
try {
emailSchema.parse(email);
console.log(`PASS`, email);
} catch (_) {}
}
Loading