diff --git a/src/main/java/ru/pdguard/detect/Validators.java b/src/main/java/ru/pdguard/detect/Validators.java
index 48f6679..6bc195a 100644
--- a/src/main/java/ru/pdguard/detect/Validators.java
+++ b/src/main/java/ru/pdguard/detect/Validators.java
@@ -124,7 +124,8 @@ public final class Validators {
/**
* Дата в числовой записи при любом порядке частей: {@code 12.05.1985},
- * {@code 05/12/1985}, {@code 1985-05-12}. Отсекает похожие по форме
+ * {@code 05/12/1985}, {@code 1985-05-12}, {@code 15 03 1990}, а также день
+ * и месяц без года: {@code 15 03}, {@code 15/03}. Отсекает похожие по форме
* последовательности вроде {@code 192.168.1}.
*/
public static boolean date(String value) {
@@ -135,7 +136,12 @@ public final class Validators {
return true;
}
}
- String[] parts = value.split("[.\\-/]");
+ String[] parts = value.split("[.\\-/\\s]+");
+ if (parts.length == 2) {
+ int a = Integer.parseInt(parts[0]);
+ int b = Integer.parseInt(parts[1]);
+ return (a >= 1 && a <= 31 && b >= 1 && b <= 12) || (b >= 1 && b <= 31 && a >= 1 && a <= 12);
+ }
if (parts.length != 3) {
return false;
}
diff --git a/src/test/java/ru/pdguard/LeakDiagTest.java b/src/test/java/ru/pdguard/LeakDiagTest.java
new file mode 100644
index 0000000..8a98a3d
--- /dev/null
+++ b/src/test/java/ru/pdguard/LeakDiagTest.java
@@ -0,0 +1,80 @@
+package ru.pdguard;
+
+import org.junit.jupiter.api.Test;
+import ru.pdguard.config.SystemPolicy;
+import ru.pdguard.core.PayloadStore;
+import ru.pdguard.core.Pipeline;
+import ru.pdguard.detect.RuleRegistry;
+import ru.pdguard.detect.Span;
+import ru.pdguard.mask.Masker;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Проверка утечек из датасета {@code leak-dataset.txt}.
+ *
+ *
Датасет собран из логов pd-guard-node-logs.txt: это уникальные тексты, в
+ * которых узел не нашёл ПД ({@code найдено={}}), хотя маркер персональных данных
+ * в тексте есть. Тест прогоняет каждый текст через {@link Pipeline} и требует,
+ * чтобы детекция нашла хотя бы одно ПД из перечня типов.
+ */
+class LeakDiagTest {
+
+ private static final String DATASET = "/leak-dataset.txt";
+
+ @Test
+ void checkLeaks() {
+ Pipeline p = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
+ List leaks = readDataset();
+
+ int fixed = 0;
+ List remaining = new ArrayList<>();
+ for (String raw : leaks) {
+ List spans = p.findPersonalData(raw, SystemPolicy.DEFAULT);
+ boolean found = spans.stream().anyMatch(s -> s.type().equals(RuleRegistry.FIO)
+ || s.type().equals(RuleRegistry.BIRTH_DATE) || s.type().equals(RuleRegistry.PASSPORT_DATE)
+ || s.type().equals(RuleRegistry.CVV) || s.type().equals(RuleRegistry.PIN)
+ || s.type().equals(RuleRegistry.INN) || s.type().equals(RuleRegistry.PHONE)
+ || s.type().equals(RuleRegistry.CARD) || s.type().equals(RuleRegistry.DRIVER_LICENSE)
+ || s.type().equals(RuleRegistry.CITIZENSHIP) || s.type().equals(RuleRegistry.BIRTH_PLACE));
+ if (found) {
+ fixed++;
+ } else {
+ remaining.add(raw);
+ }
+ }
+ System.out.println("Всего утечек: " + leaks.size() + ", исправлено: " + fixed + ", осталось: " + remaining.size());
+ for (String raw : remaining) {
+ System.out.println(" ОСТАЛОСЬ: " + raw);
+ }
+ assertTrue(remaining.size() <= leaks.size() / 2, "осталось слишком много утечек: " + remaining.size());
+ }
+
+ private static List readDataset() {
+ List lines = new ArrayList<>();
+ try (InputStream in = LeakDiagTest.class.getResourceAsStream(DATASET)) {
+ if (in == null) {
+ throw new IllegalStateException("Датасет не найден в сборке: " + DATASET);
+ }
+ try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = r.readLine()) != null) {
+ if (!line.isBlank()) {
+ lines.add(line);
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ return lines;
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/leak-dataset.txt b/src/test/resources/leak-dataset.txt
new file mode 100644
index 0000000..5a73db0
--- /dev/null
+++ b/src/test/resources/leak-dataset.txt
@@ -0,0 +1,168 @@
+Pin 1029 записан на обороте карты.
+Адрес фактического проживания совпадает с адресом регистрации.
+Анна-Мария
+Анна/Мария
+В ГРАФЕ «ОТЧЕСТВО ДОВЕРЕННОГО ЛИЦА» УКАЗАНО: ПЕТРОВИЧ
+В анкете заемщика указана дата рождения: 15 Mмм 1990.
+В анкете заемщика указана дата рождения: 15-ЯНВ-1990.
+В анкете клиента указано отчество: Иванович/Петрович.
+В анкете на открытие счета в поле «Гражданство» указано: Российская Федерация.
+В анкете на открытие счета в поле «Место рождения» указано: г. Москва.
+В анкете поручителя указано место рождения: Новосибирск.
+В анкете указана дата рождения (день и месяц): 15 03.
+В анкете указана дата рождения (день и месяц): 15 ЯНВ.
+В анкете указана дата рождения (день и месяц): 15 янв.
+В анкете указана дата рождения (день и месяц): 15-ЯНВ.
+В анкете указана дата рождения (день и месяц): 15-Янв.
+В графе «Отчество поручителя» указано: Петрович.
+В договоре вклада указана дата выдачи паспорта: 15-января-2010.
+В досье клиента указана дата рождения: 15-янв-90.
+В досье созаемщика указана дата выдачи паспорта: 15 Mмм 10.
+В журнале транзакций по карте сохранен CVV код 654.
+В заявлении дата рождения указана словами: пятнадцатое марта тысяча девятьсот девяностого года.
+В заявлении клиента указана дата рождения: 15-января-90.
+В заявлении на кредит указана дата выдачи паспорта: 15 янв 2010.
+В заявлении на перевыпуск указан номер карты: 4276380012345678.
+В заявлении указана дата рождения: 15 Mмм.
+В карточке вкладчика указано место рождения: село Верхние Лихоборы, Московская область.
+В карточке клиента указана дата рождения: 15 янв 90.
+В карточке клиента указана дата рождения: 15-Янв-1990.
+В кредитной заявке указано гражданство: российское.
+В кредитной заявке указано место рождения: г. Сочи, Краснодарский край.
+В личном кабинете пользователя указан телефон 79267778899.
+В обращении клиента указан номер карты: 4276-3800-1234-5678, операция не распознана.
+В обращении указано: «мой пин-код 1357, карта заблокирована».
+В справке банка указана дата рождения (день и месяц): 15/03.
+В справке банка указана дата рождения клиента: 15 января 90.
+В справке указана дата рождения (день и месяц): 15-янв.
+В тестовом контуре используется карта с сививи 777.
+В форме интернет-эквайринга клиент ввел cvv 456 для оплаты.
+В электронной анкете банка указана дата рождения: 15 03 1990.
+ГРАЖДАНСТВО: РОССИЙСКАЯ ФЕДЕРАЦИЯ. ОПЕРАЦИЯ ОДОБРЕНА СЛУЖБОЙ КОМПЛАЕНС-БЕЗОПАСНОСТИ
+Гражданство бенефициара по договору страхования: Соединенные Штаты Америки.
+Гражданство поручителя по договору: Российская Федерация/Армения.
+Дата выдачи паспорта бенефициара: 15 Января 10.
+Дата выдачи паспорта бенефициара: 15-Янв-10.
+Дата выдачи паспорта вкладчика: 10-03-15.
+Дата выдачи паспорта вкладчика: 15 03 10.
+Дата выдачи паспорта доверенного лица: 03-15-10.
+Дата выдачи паспорта доверенного лица: 15-Января-10.
+Дата выдачи паспорта заемщика: 03/15/10.
+Дата выдачи паспорта заемщика: 15-ЯНВАРЯ-10.
+Дата выдачи паспорта клиента: 03.15.10.
+Дата выдачи паспорта клиента: 15-янв-2010.
+Дата выдачи паспорта наследника по вкладу: 15 ЯНВАРЯ 10.
+Дата выдачи паспорта поручителя: 15 ЯНВ 10.
+Дата выдачи паспорта поручителя: 15-ЯНВ-10.
+Дата выдачи паспорта представителя клиента: 10.03.15.
+Дата рождения бенефициара по договору: 1990/03/15.
+Дата рождения бенефициара по счету: 15-Января-1990.
+Дата рождения держателя карты: 03.15.1990.
+Дата рождения заемщика по кредитному договору: 15 Января 1990.
+Дата рождения клиента (день и месяц): 15 ЯНВАРЯ.
+Дата рождения клиента (день и месяц): 15 Января.
+Дата рождения клиента (день и месяц): 15 января.
+Дата рождения клиента (день и месяц): 15-ЯНВАРЯ.
+Дата рождения клиента (день и месяц): 15-Января.
+Дата рождения клиента (день и месяц): 15-января.
+Дата рождения клиента в анкете: 15 ЯНВАРЯ 1990.
+Дата рождения клиента в досье: 15 ЯНВ 1990.
+Дата рождения клиента в кредитной заявке: 15-ЯНВАРЯ-1990.
+Дата рождения клиента-нерезидента: 03-15-1990.
+Дата рождения наследника по вкладу: 1990.03.15.
+Дата рождения подписанта договора: 1990-03-15.
+Держатель ввёл пин-код 7777 трижды неверно.
+Для завершения платежа в мобильном приложении введите CVV код 321.
+Для тестовой карты в анкете указан цвв 000.
+ЗАКЛАДАТЕЛЬ СЕЙФОВОЙ ЯЧЕЙКИ: ИВАНОВ
+ИВАН
+ИВАН И.
+ИВАНОВ
+ИВАНОВ И.
+ИВАНОВИВАНПЕТРОВИЧ
+ИНН: 7712 3456 7859, указан в заявлении.
+Иван
+Иван И.
+Иванов
+Иванов И.
+ИвановИванПетрович
+Иванова/Петрова
+Иванович-Петрович
+Иванович/Петрович
+Имя владельца счета указано как: Анна/Мария.
+Имя держателя карты не указано в заявлении.
+КЛИЕНТ ИВАН ЗАПРОСИЛ ПЕРЕВЫПУСК КАРТЫ
+КЛИЕНТ ИВАН И. ОФОРМИЛ ДЕБЕТОВУЮ КАРТУ
+Карта заблокирована по запросу через контактный центр.
+Клиент передал письмо с указанием ПИН 9087 и реквизитов карты.
+Клиент подтвердил онлайн-операцию, указав CVV 111.
+Клиент сообщил ПИН-код карты 2468 в телефонном разговоре.
+Клиент указал следующий орган выдачи: Паспортно-визовая служба УВД Московского района.
+Комментарий оператора: клиент назвал пин 8642 для подтверждения операции.
+МЕСТО РОЖДЕНИЯ: Г. ЕКАТЕРИНБУРГ. АНКЕТА ПРОВЕРЕНА СЛУЖБОЙ БЕЗОПАСНОСТИ БАНКА
+Место рождения бенефициара по договору страхования: г. Алма-Ата, Республика Казахстан.
+НОМЕР КАРТЫ: 5469400012345678. ОБРАЩЕНИЕ ЗАРЕГИСТРИРОВАНО В СИСТЕМЕ
+Новый ПИН-код: 5555, установлен 12.05.2024.
+Номер платежной карты клиента: 4276 3800 1234 5678, срок действия карты истек.
+Операция отклонена: проверьте правильность кода на обороте карты 789.
+Отправитель СБП: ИвановИванПетрович, сумма 5 000,00 руб.
+Отчество доверенного лица: Иванович-Петрович.
+Ошибка авторизации платежа: код 258 неверно введен CVV.
+ПЕТРОВИЧ
+ПЕТРОВИЧ И.
+ПИН первой карты: 1234, ПИН второй карты: 5678.
+ПИН-КОД: 7890
+ПИН-код - 1234
+ПИН-код «1234»
+ПИН: 5678
+ПЛАТЕЛЬЩИК: ИВАНОВ И. ОПЕРАЦИЯ ПРИНЯТА ОТДЕЛЕНИЕМ № 1
+ПОЛУЧАТЕЛЬ ПЕРЕВОДА: ИВАНОВИВАНПЕТРОВИЧ
+ПОРУЧИТЕЛЬ ПО ДОГОВОРУ: ПЕТРОВИЧ И.
+Паспорт заёмщика 4509 123456, паспорт поручителя 7710 654321.
+Паспортно-визовая служба УВД Московского района
+Петрович
+Петрович И.
+Пин Код: 1234
+Пин-код карты: 1234
+Получатель платежа: Иванов.
+Получатель платежа: Иванова/Петрова.
+Поручитель по кредиту: Петрович И.
+Последние 4 цифры номера карты: 1234.
+При оформлении виртуальной карты в поле CVV указан код 123.
+При оформлении ипотечного договора место рождения г. Казань подтверждено паспортом клиента.
+Система зафиксировала три неудачные попытки ввода CVV кода 999.
+Срок действия карты истекает в конце месяца.
+УФМС России по Московской области выдало паспорт гражданину.
+в графе «отчество созаемщика» указано: петрович
+в досье клиента прописано гражданство: российская федерация, статус налогового резидента присвоен
+в досье клиента прописано место рождения: г. самара, гражданство подтверждено документом
+доверенное лицо по вкладу: иванов и.
+доверенность оформлена на: иван петрович и., срок действия один год
+заявитель обращения: и. иван петрович, запрос справки по счету
+заявка на рефинансирование от: иван петрович
+и. иван петрович
+иван
+иван и.
+иван иванов
+иван иванов петрович
+иван петрович
+иван петрович и.
+иванов
+иванов и.
+иванов и. п.
+иванов петрович
+ивановиванпетрович
+клиент иван и. запросил выписку по депозиту
+отправитель перевода: иван иванов
+отправитель перевода: ивановиванпетрович
+петрович
+петрович и.
+пин 3456
+пин-код(1234)
+пин-код=1234
+плательщик перевода указан: иванов
+плательщик перевода: иван иванов петрович, счет 40817810000000000002
+подателем заявки на кредит указано: иван
+получатель наличных в кассе: иванов и. п.
+поручитель по договору: иванов петрович
+созаемщик по договору: петрович и.