diff --git a/common/src/main/java/org/fao/geonet/utils/EmailUtil.java b/common/src/main/java/org/fao/geonet/utils/EmailUtil.java new file mode 100644 index 00000000000..36b10254fb6 --- /dev/null +++ b/common/src/main/java/org/fao/geonet/utils/EmailUtil.java @@ -0,0 +1,52 @@ +//============================================================================= +//=== Copyright (C) 2001-2025 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.utils; + +public class EmailUtil { + private static final String OWASP_EMAIL_REGEX = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; + private static final java.util.regex.Pattern OWASP_EMAIL_PATTERN = java.util.regex.Pattern.compile(OWASP_EMAIL_REGEX); + + private EmailUtil() { + throw new UnsupportedOperationException(); + } + + /** + * Checks if a string contains a valid email address format. + * + * @param emailAddress Value to validate. + * @return true if the value contains a valid email address format, otherwise false. + */ + public static boolean isValidEmailAddress(String emailAddress) { + return OWASP_EMAIL_PATTERN.matcher(emailAddress).matches(); + } + + /** + * Checks if a string contains valid email link with the format: mailto:emailaddress + * @param link + * @return + */ + public static boolean isValidEmailLink(final String link) { + return link.startsWith("mailto:") && EmailUtil.isValidEmailAddress(link.replace("mailto:", "")); + } +} diff --git a/common/src/test/java/org/fao/geonet/utils/EmailUtilTest.java b/common/src/test/java/org/fao/geonet/utils/EmailUtilTest.java new file mode 100644 index 00000000000..07a4bcd1ac8 --- /dev/null +++ b/common/src/test/java/org/fao/geonet/utils/EmailUtilTest.java @@ -0,0 +1,58 @@ +//============================================================================= +//=== Copyright (C) 2001-2025 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.utils; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class EmailUtilTest { + @Test + public void testEmailAddress() { + assertEquals(true, EmailUtil.isValidEmailAddress("test@domain.com")); + + assertEquals(true, EmailUtil.isValidEmailAddress("test.user@domain.com")); + + assertEquals(true, EmailUtil.isValidEmailAddress("test.user@domain.subdomain.com")); + + assertEquals(false, EmailUtil.isValidEmailAddress("test.user")); + + assertEquals(false, EmailUtil.isValidEmailAddress("test.user@domain")); + } + + @Test + public void testEmailLink() { + assertEquals(true, EmailUtil.isValidEmailLink("mailto:test@domain.com")); + + assertEquals(true, EmailUtil.isValidEmailLink("mailto:test.user@domain.com")); + + assertEquals(true, EmailUtil.isValidEmailLink("mailto:test.user@domain.subdomain.com")); + + assertEquals(false, EmailUtil.isValidEmailLink("test.user@domain.com")); + + assertEquals(false, EmailUtil.isValidEmailLink("mailto:test.user")); + + assertEquals(false, EmailUtil.isValidEmailLink("mailto:test.user@domain")); + } +} diff --git a/services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java b/services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java index 14da2d9e93c..1884e080b71 100644 --- a/services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java +++ b/services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java @@ -45,6 +45,7 @@ import org.fao.geonet.repository.UserGroupRepository; import org.fao.geonet.repository.page.PageRepository; import org.fao.geonet.repository.specification.UserGroupSpecs; +import org.fao.geonet.utils.EmailUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -58,6 +59,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -619,15 +621,16 @@ private void fillContent(final MultipartFile data, page.setData(content.getBytes()); } else if (page.getData() == null) { // Check the link, unless it refers to a file uploaded to the page, that contains the original file name. - if (StringUtils.isNotBlank(link) && !UrlUtils.isValidRedirectUrl(link)) { - throw new IllegalArgumentException("The link provided is not valid"); - } else { + // The link should be a valid URL or mailto address + if (StringUtils.isNotBlank(link) && (UrlUtils.isValidRedirectUrl(link) || EmailUtil.isValidEmailLink(link))) { page.setLink(link); + } else { + throw new IllegalArgumentException("The link provided is not valid"); } } - } + /** * Check is the user is in designated group to access the static page when page permission level is set to GROUP * @param us Current User Session diff --git a/services/src/main/java/org/fao/geonet/api/users/validation/UserRegisterDtoValidator.java b/services/src/main/java/org/fao/geonet/api/users/validation/UserRegisterDtoValidator.java index f22d7cc821f..3d291b2d8c7 100644 --- a/services/src/main/java/org/fao/geonet/api/users/validation/UserRegisterDtoValidator.java +++ b/services/src/main/java/org/fao/geonet/api/users/validation/UserRegisterDtoValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2024 Food and Agriculture Organization of the + * Copyright (C) 2001-2025 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -27,6 +27,7 @@ import org.fao.geonet.api.users.model.UserRegisterDto; import org.fao.geonet.constants.Params; import org.fao.geonet.repository.UserRepository; +import org.fao.geonet.utils.EmailUtil; import org.springframework.util.StringUtils; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; @@ -37,8 +38,6 @@ * */ public class UserRegisterDtoValidator implements Validator { - private static final String OWASP_EMAIL_REGEX = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; - private static final java.util.regex.Pattern OWASP_EMAIL_PATTERN = java.util.regex.Pattern.compile(OWASP_EMAIL_REGEX); @Override public boolean supports(Class clazz) { @@ -55,7 +54,7 @@ public void validate(Object target, Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "field.required", Params.EMAIL + " is required"); - if (StringUtils.hasLength(userRegisterDto.getEmail()) && !OWASP_EMAIL_PATTERN.matcher(userRegisterDto.getEmail()).matches()) { + if (StringUtils.hasLength(userRegisterDto.getEmail()) && !EmailUtil.isValidEmailAddress(userRegisterDto.getEmail())) { errors.rejectValue("email", "field.notvalid", "Email address is not valid"); }