Files
pd-guard/src/main/java/ru/pdguard/mask/Masker.java
T

86 lines
4.8 KiB
Java

package ru.pdguard.mask;
import org.springframework.stereotype.Component;
import ru.pdguard.detect.PdTypes;
import java.util.Map;
import java.util.function.UnaryOperator;
/**
* Превращает найденное значение в замену согласно настройкам системы.
*
* <p>Тип, для которого вид маски не задан, скрывается звёздочками целиком —
* безопасное поведение по умолчанию для вновь добавленных правил.
*/
@Component
public class Masker {
private static final UnaryOperator<String> EDGES = v -> Strategies.keepEdges(v, 2, 2);
private static final UnaryOperator<String> SHORT_SERIES = v -> Strategies.keepEdges(v, 0, 2);
private static final Map<String, UnaryOperator<String>> BY_TYPE = Map.ofEntries(
Map.entry(PdTypes.EMAIL, Strategies::email),
Map.entry(PdTypes.PHONE, EDGES),
Map.entry(PdTypes.CARD, EDGES),
Map.entry(PdTypes.INN, EDGES),
Map.entry(PdTypes.SNILS, EDGES),
Map.entry(PdTypes.PASSPORT, EDGES),
Map.entry(PdTypes.DRIVER_LICENSE, EDGES),
Map.entry(PdTypes.DEPT_CODE, EDGES),
// У этих документов серия короткая — две цифры или две буквы. Оставь мы
// первые два знака, серия оказалась бы открыта целиком, поэтому видны
// только последние. У паспорта РФ и водительского удостоверения серия
// из четырёх знаков, там открывается половина.
Map.entry(PdTypes.FOREIGN_PASSPORT, SHORT_SERIES),
Map.entry(PdTypes.MILITARY_ID, SHORT_SERIES),
Map.entry(PdTypes.BIRTH_CERTIFICATE, SHORT_SERIES),
Map.entry(PdTypes.MEDICAL_POLICY, EDGES),
Map.entry(PdTypes.CARDHOLDER, Strategies::initials),
Map.entry(PdTypes.FIO, Strategies::initials),
// Код проверки и пин-код не показываем даже частично: у них слишком
// мало знаков, чтобы открывать хотя бы один.
Map.entry(PdTypes.CVV, Strategies::stars),
Map.entry(PdTypes.PIN, Strategies::stars),
Map.entry(PdTypes.PASSPORT_ISSUER, Strategies::stars),
// У дат сохраняем разделители: модель видит, что это дата, но не какая.
Map.entry(PdTypes.BIRTH_DATE, Strategies::starsKeepingPunctuation),
Map.entry(PdTypes.PASSPORT_DATE, Strategies::starsKeepingPunctuation),
Map.entry(PdTypes.DATE, Strategies::starsKeepingPunctuation),
Map.entry(PdTypes.ADDRESS_COUNTRY, Strategies::stars),
Map.entry(PdTypes.ADDRESS_POSTCODE, Strategies::stars),
Map.entry(PdTypes.ADDRESS_CITY, Strategies::stars),
Map.entry(PdTypes.ADDRESS_STREET, Strategies::stars),
Map.entry(PdTypes.ADDRESS_HOUSE, Strategies::stars),
Map.entry(PdTypes.ADDRESS_FLAT, Strategies::stars),
Map.entry(PdTypes.ADDRESS_REGION, Strategies::stars),
Map.entry(PdTypes.ADDRESS_DISTRICT, Strategies::stars),
Map.entry(PdTypes.BIRTH_PLACE, Strategies::stars),
Map.entry(PdTypes.CITIZENSHIP, Strategies::stars),
Map.entry(PdTypes.ACCOUNT_NUMBER, EDGES),
Map.entry(PdTypes.OGRN, EDGES),
Map.entry(PdTypes.OGRNIP, EDGES),
Map.entry(PdTypes.KPP, EDGES),
// Срок действия карты — разделитель виден, сам месяц/год нет.
Map.entry(PdTypes.CARD_EXPIRY, Strategies::starsKeepingPunctuation),
Map.entry(PdTypes.BIK, Strategies::stars),
Map.entry(PdTypes.INCOME, Strategies::stars),
Map.entry(PdTypes.BIOMETRIC, Strategies::stars)
);
public String mask(String type, String value, MaskMode mode, MaskContext context) {
return switch (mode) {
case MASK -> BY_TYPE.getOrDefault(type, Strategies::stars).apply(value);
// STRICT игнорирует BY_TYPE целиком — ни один тип не открывает края
// и ФИО не превращается в инициалы, только сплошные звёздочки.
case STRICT -> Strategies.stars(value);
case TOKEN -> context.resolve(type, value, (t, n) -> "[" + t + "_" + n + "]");
case SYNTHETIC -> context.resolve(type, value, (t, n) -> Synthetic.forType(t, value, n));
};
}
}