diff --git a/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java b/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java index 0b7021a184749da8c2839057638eb4c2e17127ca..adef078e3b23ad57069dc625cfece3b864770f21 100644 --- a/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java +++ b/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java @@ -12,10 +12,9 @@ package org.eclipsefoundation.git.eca.config; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.eclipsefoundation.git.eca.dto.CommitValidationMessage; import org.eclipsefoundation.git.eca.dto.CommitValidationStatus; @@ -23,8 +22,6 @@ import io.quarkus.qute.TemplateExtension; @TemplateExtension public class EclipseQuteTemplateExtensions { - public static final Pattern EMAIL_OBFUSCATION_PATTERN = Pattern.compile("^(.).*?(@.*)$"); - public static final String EMAIL_OBFUSCATION_REPLACEMENT = "$1*****$2"; /** * Made to count nested errors in a list of commit status objects. @@ -37,8 +34,7 @@ public class EclipseQuteTemplateExtensions { } /** - * Formats and flattens a list of statuses to a list of errors encountered while - * validation a set of commits. + * Formats and flattens a list of statuses to a list of errors encountered while validation a set of commits. * * @param statuses a list of commit validation statuses to retrieve errors from * @return a list of flattened errors, or an empty list if (none are found. @@ -49,29 +45,54 @@ public class EclipseQuteTemplateExtensions { /** * <p> - * Obfuscates an email for public consumption, showing the first letter of the - * email address, and the domain of the address for identification, and - * stripping out the rest of the address. + * Obfuscates an email for public consumption, showing the first letter of the email address, and the domain of the + * address for identification, and stripping out the rest of the address. * </p> * * <p> * <strong>Example:</strong> <br /> * Source: sample.address+123@eclipse.org <br /> - * Output: s*****@eclipse.org + * Output: sample.address+123@ecl*pse DOT org * </p> * * @param email the address to obfuscate - * @return the obfuscated address, or empty string if (the string could not be - * parsed as an email address. + * @return the obfuscated address, or empty string if (the string could not be parsed as an email address. */ static String obfuscateEmail(String email) { - Matcher m = EMAIL_OBFUSCATION_PATTERN.matcher(email); - return m.matches() ? m.replaceAll(EMAIL_OBFUSCATION_REPLACEMENT) : ""; + if (StringUtils.isBlank(email)) { + return ""; + } + // split on the @ symbol + String[] emailParts = email.split("\\@"); + if (emailParts.length != 2) { + // valid emails will have 2 sections when split this way + return ""; + } + + String[] domainParts = emailParts[1].split("\\."); + if (domainParts.length < 2) { + // emails should have at least 2 parts here + return ""; + } + // the index in the middle of the first domain part of the email address + int middleIndexDomain = Math.floorDiv(domainParts[0].length(), 2); + + // build the obfuscated email address in the pattern defined in the block comment + StringBuilder sb = new StringBuilder(); + sb.append(emailParts[0]); + sb.append("@"); + sb.append(domainParts[0].substring(0, middleIndexDomain)); + sb.append('*'); + sb.append(domainParts[0].substring(middleIndexDomain + 1)); + for (int i = 1; i < domainParts.length; i++) { + sb.append(" DOT "); + sb.append(domainParts[i]); + } + return sb.toString(); } /** - * Standardized conversion of error codes into messages to be consumed - * downstream. + * Standardized conversion of error codes into messages to be consumed downstream. * * @param message the validation error to convert into a meaningful message * @return the message string for the given validation error. @@ -79,17 +100,21 @@ public class EclipseQuteTemplateExtensions { static String getMessageForError(CommitValidationMessage message) { String out = ""; if (message.getStatusCode() == -406) { - out = String.format("Committer does not have permission to push on behalf of another user (Legacy). (%s)", - EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); + out = String + .format("Committer does not have permission to push on behalf of another user (Legacy). (%s)", + EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); } else if (message.getStatusCode() == -405) { - out = String.format("Committer did not have a signed ECA on file. (%s)", - EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); + out = String + .format("Committer did not have a signed ECA on file. (%s)", + EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); } else if (message.getStatusCode() == -404) { - out = String.format("Author did not have a signed ECA on file. (%s)", - EclipseQuteTemplateExtensions.obfuscateEmail(message.getAuthorEmail())); + out = String + .format("Author did not have a signed ECA on file. (%s)", + EclipseQuteTemplateExtensions.obfuscateEmail(message.getAuthorEmail())); } else if (message.getStatusCode() == -403) { - out = String.format("Committer does not have permission to commit on specification projects. (%s)", - EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); + out = String + .format("Committer does not have permission to commit on specification projects. (%s)", + EclipseQuteTemplateExtensions.obfuscateEmail(message.getCommitterEmail())); } else if (message.getStatusCode() == -402) { out = "Sign-off not detected in the commit message (Legacy)."; } else if (message.getStatusCode() == -401) { diff --git a/src/test/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensionsTest.java b/src/test/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..988fc6b190010e1caeb0930585b6e9f692a85c51 --- /dev/null +++ b/src/test/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensionsTest.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2023 Eclipse Foundation + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Author: Martin Lowe <martin.lowe@eclipse-foundation.org> + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.git.eca.config; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import io.quarkus.test.junit.QuarkusTest; + +/** + * Tests for Qute template extensions + * + * @author Martin Lowe + * + */ +@QuarkusTest +class EclipseQuteTemplateExtensionsTest { + + /** + * Success cases where emails can be obfuscated and their expected output + * + * + * <ul> + * <li>Case 1: Standard address, no edge cases + * <li>Case 2: Address with email alias (+123) + * <li>Case 3: Multiple top-level domain parts + * </ul> + * + * @param input the value to be obfuscated + * @param expected the value that is expected out + */ + @ParameterizedTest + @CsvSource(value = { "sample@co.co,sample@c* DOT co", "sample.address+123@eclipse.org,sample.address+123@ecl*pse DOT org", + "sample@somecorp.co.co, sample@some*orp DOT co DOT co" }) + void obfuscateEmail_success(String input, String expected) { + Assertions.assertEquals(expected, EclipseQuteTemplateExtensions.obfuscateEmail(input)); + } + + /** + * Cases where a value can't be obfuscated and an empty string is returned. + * + * <ul> + * <li>Case 1: No @ symbol + * <li>Case 2: Null value + * <li>Case 3: Empty string + * <li>Case 4: No qualified domain (something.com) + * </ul> + * + * @param input the value to be obfuscated + * @param expected the value that is expected out + */ + @ParameterizedTest + @CsvSource(value = { "no-at-symbol.com,''", ",''", "'',''", "no-qualified-domain@wowee,''" }) + void obfuscateEmail_failure_invalidAddress(String input, String expected) { + Assertions.assertEquals(expected, EclipseQuteTemplateExtensions.obfuscateEmail(input)); + } +}