CredentialMasker.java

package org.egothor.methodatlas.emit;

/**
 * Masks credential values for safe inclusion in reports.
 *
 * <p>Values longer than {@code 2 * CLEAR_EDGE} characters keep their first and
 * last {@link #CLEAR_EDGE} characters in cleartext; the middle portion is
 * replaced with bullet characters ({@code •}). Shorter values are fully masked.
 * The returned string always has the same length as the input.</p>
 *
 * @since 4.1.0
 */
public final class CredentialMasker {

    /** Number of leading/trailing clear characters retained for long values. */
    private static final int CLEAR_EDGE = 4;

    /** Bullet used to replace masked characters. */
    private static final char BULLET = '•';

    private CredentialMasker() {
        // utility class
    }

    /**
     * Masks {@code value}, preserving its length. Values longer than
     * {@code 2 * CLEAR_EDGE} keep their first and last {@value #CLEAR_EDGE}
     * characters; shorter values are fully masked.
     *
     * @param value raw value; never {@code null}
     * @return masked value of equal length
     */
    public static String mask(final String value) {
        final int len = value.length();
        if (len <= CLEAR_EDGE * 2) {
            return String.valueOf(BULLET).repeat(len);
        }
        final int middleLen = len - CLEAR_EDGE * 2;
        final StringBuilder sb = new StringBuilder(len);
        sb.append(value, 0, CLEAR_EDGE)
          .append(String.valueOf(BULLET).repeat(middleLen))
          .append(value, len - CLEAR_EDGE, len);
        return sb.toString();
    }
}