Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
97 lines
5.2 KiB
Java
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);
|
|
}
|
|
}
|