From 7f0da3565984e6c7f4611291462cc3341756e10d Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 9 Jan 2024 16:53:18 +0100 Subject: [PATCH] Mail validation in frontend and backend unified Pushed-by: Florian Scholdei Co-authored-by: Florian Scholdei --- gradle/changelog/mail_regex.yaml | 2 + .../java/sonia/scm/util/ValidationUtil.java | 4 +- .../sonia/scm/util/ValidationUtilTest.java | 41 ++++++++++++------- scm-ui/ui-components/src/validation.test.ts | 10 +++++ scm-ui/ui-components/src/validation.ts | 2 +- 5 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 gradle/changelog/mail_regex.yaml diff --git a/gradle/changelog/mail_regex.yaml b/gradle/changelog/mail_regex.yaml new file mode 100644 index 0000000000..cbc6e5a346 --- /dev/null +++ b/gradle/changelog/mail_regex.yaml @@ -0,0 +1,2 @@ +- type: fixed + description: Mail validation in front- and backend unified diff --git a/scm-core/src/main/java/sonia/scm/util/ValidationUtil.java b/scm-core/src/main/java/sonia/scm/util/ValidationUtil.java index 553fd09f96..91022a7fcd 100644 --- a/scm-core/src/main/java/sonia/scm/util/ValidationUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/ValidationUtil.java @@ -31,7 +31,7 @@ import java.util.regex.Pattern; public final class ValidationUtil { - private static final String REGEX_MAIL = "^[A-Za-z0-9][\\w.-]*@[A-Za-z0-9][\\w\\-\\.]*\\.[A-Za-z0-9][A-Za-z0-9-]+$"; + private static final String REGEX_MAIL = "^[a-z0-9!#$%&'*+\\/=?^_`{|}~\" -]+(?:\\.[a-z0-9!#$%&'*+\\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"; public static final String REGEX_NAME = "^(?:(?:[^:/?#;&=\\s@%\\\\][^:/?#;&=%\\\\]*[^:/?#;&=\\s%\\\\])|(?:[^:/?#;&=\\s@%\\\\]))$"; @@ -75,7 +75,7 @@ public final class ValidationUtil { * @return {@code true} if mail is valid */ public static boolean isMailAddressValid(String mail) { - return Util.isNotEmpty(mail) && mail.matches(REGEX_MAIL); + return Util.isNotEmpty(mail) && mail.toLowerCase().matches(REGEX_MAIL); } /** diff --git a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java index 2569e62f0c..1d6a51e048 100644 --- a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java +++ b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java @@ -87,7 +87,15 @@ class ValidationUtilTest { "s.sdorra@t.co", "s.sdorra@ucla.college", "s.sdorra@example.xn--p1ai", - "s.sdorra@scm.solutions" // issue 909 + "s.sdorra@scm.solutions", // issue 909 + "s'sdorra@scm.solutions", + "\"S Sdorra\"@scm.solutions", + "A@BC.DE", + "x@example.com", + "example@s.example", + "user.name+tag+sorting@example.com", + "name/surname@example.com", + "user%example.com@example.org" }) void shouldAcceptMailAddress(String value) { assertTrue(ValidationUtil.isMailAddressValid(value)); @@ -101,7 +109,10 @@ class ValidationUtilTest { "s.sdorra@ostfalia", "s.sdorra@@ostfalia.de", "s.sdorra@ ostfalia.de", - "s.sdorra @ostfalia.de" + "s.sdorra @ostfalia.de", + "s.sdorra@[ostfalia.de", + "abc.example.com", + "a@b@c@example.com" }) void shouldRejectMailAddress(String value) { assertFalse(ValidationUtil.isMailAddressValid(value)); @@ -180,19 +191,19 @@ class ValidationUtilTest { @ParameterizedTest @ValueSource(strings = { - "scm", - "scm-", - "scm_", - "s_cm", - "s-cm", - "s", - "sc", - ".hiddenrepo", - "b.", - "...", - "..c", - "d..", - "a..c" + "scm", + "scm-", + "scm_", + "s_cm", + "s-cm", + "s", + "sc", + ".hiddenrepo", + "b.", + "...", + "..c", + "d..", + "a..c" }) void shouldAcceptRepositoryName(String path) { assertTrue(ValidationUtil.isRepositoryNameValid(path)); diff --git a/scm-ui/ui-components/src/validation.test.ts b/scm-ui/ui-components/src/validation.test.ts index 19fce08baa..30472b8687 100644 --- a/scm-ui/ui-components/src/validation.test.ts +++ b/scm-ui/ui-components/src/validation.test.ts @@ -91,8 +91,12 @@ describe("test mail validation", () => { "@ostfalia.de", "s.sdorra@", "s.sdorra@ostfalia", + "s.sdorra@@ostfalia.de", "s.sdorra@ ostfalia.de", + "s.sdorra @ostfalia.de", "s.sdorra@[ostfalia.de", + "abc.example.com", + "a@b@c@example.com" ]; for (const mail of invalid) { it(`should return false for '${mail}'`, () => { @@ -112,6 +116,12 @@ describe("test mail validation", () => { "s.sdorra@scm.solutions", "s'sdorra@scm.solutions", '"S Sdorra"@scm.solutions', + "A@BC.DE", + "x@example.com", + "example@s.example", + "user.name+tag+sorting@example.com", + "name/surname@example.com", + "user%example.com@example.org" ]; for (const mail of valid) { it(`should return true for '${mail}'`, () => { diff --git a/scm-ui/ui-components/src/validation.ts b/scm-ui/ui-components/src/validation.ts index 7eadd60e16..910048cb3b 100644 --- a/scm-ui/ui-components/src/validation.ts +++ b/scm-ui/ui-components/src/validation.ts @@ -36,7 +36,7 @@ export const isBranchValid = (name: string) => { return branchRegex.test(name); }; -const mailRegex = /^[ -~]+@[A-Za-z0-9][\w\-.]*\.[A-Za-z0-9][A-Za-z0-9-]+$/; +const mailRegex = /^[a-z0-9!#$%&'*+\/=?^_`{|}~" -]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i; export const isMailValid = (mail: string) => { return mailRegex.test(mail);