Files
pd-guard/src/main/java/ru/pdguard/config/SystemPolicy.java
T
Максименко Никита Владимирович 573d94cca8 refactor: подтянуть Legal NER, переформатировать код и добавить тесты
Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
2026-09-23 22:02:45 +03:00

97 lines
5.2 KiB
Java

package ru.pdguard.config;
import java.util.Set;
import ru.pdguard.detect.PdTypes;
import ru.pdguard.mask.MaskMode;
/**
* Правила обработки для одной системы-потребителя.
*
* @param name имя системы; им же разделяется хранилище соответствий, чтобы одна система не могла
* достать данные другой
* @param enabled разрешено ли системе обращаться в модуль
* @param demask выполняется ли для системы обратное преобразование
* @param maskMode вид замены: звёздочки, токен или синтетическое значение
* @param types типы ПД к маскированию; {@code "*"} — все известные
* @param key общий секрет системы; задан — заголовок {@code X-System-Key} обязан совпасть, иначе
* имя системы можно было бы просто назвать. Только знаки ASCII: заголовки HTTP передаются в
* Latin-1, и кириллица в ключе до сервиса доедет искажённой
* @param requireCompanion типы, которые маскируются только вместе с ПД другого типа: пин-код сам по
* себе безвреден, пин-код рядом с номером карты — уже нет; то же для даты без якорного слова,
* места рождения («Нижний Новгород» в рассказе о городе — не адрес клиента) и страны («цены
* выросли в Казахстане» — не гражданство). Сюда же банковские реквизиты — счёт, БИК, ОГРН,
* ОГРНИП, КПП: сами по себе они опознают организацию или счёт, а не человека, и в перечне типов
* из задания их нет. Рядом с именем клиента они становятся его данными и маскируются. Сюда же
* доход и биометрия. Сумма заработка без человека — статистика («доход домохозяйств вырос до 74
* 500 руб»), а не персональные данные. Биометрия же в тексте не встречается вовсе: это шаблон в
* базе, и правило маскирует лишь само упоминание, то есть слово, а не данные. Чувствителен
* здесь факт, что биометрию сдал названный человек, — а он и существует только при имени рядом
*/
public record SystemPolicy(
String name,
boolean enabled,
boolean demask,
MaskMode maskMode,
Set<String> types,
Set<String> requireCompanion,
String key) {
public static final String ALL = "*";
/** Имя политики по умолчанию; оно же разделяет хранилище для запросов без заголовка. */
public static final String DEFAULT_NAME = "default";
/** Политика по умолчанию: маскируем всё, что умеем, обратное преобразование включено. */
public static final SystemPolicy DEFAULT =
new SystemPolicy(
DEFAULT_NAME,
true,
true,
MaskMode.MASK,
Set.of(ALL),
Set.of(
PdTypes.CVV,
PdTypes.PIN,
PdTypes.DATE,
PdTypes.BIRTH_PLACE,
PdTypes.ADDRESS_COUNTRY,
PdTypes.ACCOUNT_NUMBER,
PdTypes.BIK,
PdTypes.OGRN,
PdTypes.OGRNIP,
PdTypes.KPP,
PdTypes.INCOME,
PdTypes.BIOMETRIC),
null);
public SystemPolicy {
types = Set.copyOf(types);
requireCompanion = Set.copyOf(requireCompanion);
}
/** Политика только для перечисленных типов, с остальными настройками по умолчанию. */
public static SystemPolicy forTypes(String... types) {
return new SystemPolicy(
DEFAULT_NAME, true, true, MaskMode.MASK, Set.of(types), DEFAULT.requireCompanion(), null);
}
/** Совпадает ли предъявленный ключ. Ключ не задан — проверка не применяется. */
public boolean accepts(String presentedKey) {
if (key == null || key.isBlank()) {
return true;
}
return java.security.MessageDigest.isEqual(
key.getBytes(java.nio.charset.StandardCharsets.UTF_8),
(presentedKey == null ? "" : presentedKey)
.getBytes(java.nio.charset.StandardCharsets.UTF_8));
}
public boolean allows(String type) {
return types.contains(ALL) || types.contains(type);
}
public boolean needsCompanion(String type) {
return requireCompanion.contains(type);
}
}