Same reasoning as the existing CVV/PIN/DATE entries: a bare mention
("Экскурсия в Нижний Новгород", "цены выросли в Казахстане") isn't
personal data on its own, only alongside some other PD that ties it to
a specific person. The mechanism was already generic — this only adds
two more types to the default set.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
163 lines
7.2 KiB
Java
163 lines
7.2 KiB
Java
package ru.pdguard;
|
||
|
||
import org.junit.jupiter.api.Test;
|
||
import org.junit.jupiter.api.io.TempDir;
|
||
import ru.pdguard.config.SystemPolicy;
|
||
import ru.pdguard.core.PayloadStore;
|
||
import ru.pdguard.core.Pipeline;
|
||
import ru.pdguard.detect.RuleRegistry;
|
||
import ru.pdguard.mask.Masker;
|
||
|
||
import java.util.UUID;
|
||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||
|
||
/** Типы ПД, которые опознаются только рядом с якорным словом. */
|
||
class ContextDetectionTest {
|
||
|
||
private final Pipeline pipeline =
|
||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
||
|
||
private String mask(String text) {
|
||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||
}
|
||
|
||
private void assertHidden(String text, String secret) {
|
||
String masked = mask(text);
|
||
assertFalse(masked.contains(secret), "не замаскировано: «" + secret + "» в ответе «" + masked + "»");
|
||
}
|
||
|
||
@Test
|
||
void masksPassportInEveryNotation() {
|
||
assertHidden("Паспорт 4509 123456 выдан давно", "4509 123456");
|
||
assertHidden("паспорт гражданина РФ 45 09 123456", "45 09 123456");
|
||
assertHidden("ПАСПОРТ 4509123456", "4509123456");
|
||
assertHidden("Серия 4509 номер 123456", "4509");
|
||
assertHidden("серии 45 09 № 123456", "123456");
|
||
}
|
||
|
||
@Test
|
||
void masksPassportSeriesAndNumberSplitByWords() {
|
||
String masked = mask("Документ: серия 4509 номер 123456, выдан отделом");
|
||
assertTrue(masked.contains("серия "), masked);
|
||
assertTrue(masked.contains("номер "), masked);
|
||
assertFalse(masked.contains("4509"), masked);
|
||
assertFalse(masked.contains("123456"), masked);
|
||
}
|
||
|
||
@Test
|
||
void masksDepartmentCode() {
|
||
assertHidden("Код подразделения 770-001", "770-001");
|
||
assertHidden("к/п 770001", "770001");
|
||
}
|
||
|
||
@Test
|
||
void masksIssuingAuthorityButNotTheDateAfterIt() {
|
||
String masked = mask("Паспорт выдан ОУФМС России по г. Москве 12.05.2015");
|
||
assertFalse(masked.contains("ОУФМС"), masked);
|
||
assertFalse(masked.contains("12.05.2015"), masked);
|
||
assertTrue(masked.contains("**.**.****"), "дата маскируется отдельно от органа выдачи: " + masked);
|
||
}
|
||
|
||
@Test
|
||
void masksDriverLicense() {
|
||
assertHidden("Водительское удостоверение 9902 123456", "9902 123456");
|
||
assertHidden("в/у 99 02 123456", "99 02 123456");
|
||
}
|
||
|
||
@Test
|
||
void masksCitizenship() {
|
||
assertHidden("Гражданство: РФ", "РФ");
|
||
assertHidden("гражданство Республики Беларусь", "Беларусь");
|
||
assertHidden("Гражданин России обратился", "России");
|
||
}
|
||
|
||
@Test
|
||
void masksBirthPlace() {
|
||
// Место рождения — тип из requireCompanion: без другого ПД рядом не маскируется
|
||
// («Нижний Новгород» в рассказе о городе не должен теряться), поэтому в тесте
|
||
// на распознавание якоря рядом добавлен телефон.
|
||
assertHidden("Место рождения: город Тверь, проживает в Москве, тел. +7 916 123-45-67", "город Тверь");
|
||
assertHidden("Родился в Нижнем Новгороде, тел. +7 916 123-45-67", "Нижнем Новгороде");
|
||
}
|
||
|
||
@Test
|
||
void doesNotMaskBirthPlaceWithoutAnyOtherPersonalData() {
|
||
String text = "Экскурсия в Нижний Новгород перенесена на май";
|
||
assertEquals(text, mask(text), "место рождения без другого ПД рядом не маскируется");
|
||
}
|
||
|
||
@Test
|
||
void masksBirthPlaceWhenOtherPersonalDataIsAlsoPresent() {
|
||
assertHidden("Место рождения: город Тверь, ИНН 770301234550", "город Тверь");
|
||
}
|
||
|
||
@Test
|
||
void doesNotMaskCountryWithoutAnyOtherPersonalData() {
|
||
String text = "Цены на нефть выросли в Казахстане в этом квартале";
|
||
assertEquals(text, mask(text), "страна без другого ПД рядом не маскируется");
|
||
}
|
||
|
||
@Test
|
||
void masksCountryWhenOtherPersonalDataIsAlsoPresent() {
|
||
assertHidden("Страна проживания Казахстан, ИНН 770301234550", "Казахстан");
|
||
}
|
||
|
||
@Test
|
||
void masksCardholderName() {
|
||
assertHidden("Держатель карты IVAN PETROV", "IVAN PETROV");
|
||
assertHidden("cardholder: PETR SIDOROV", "PETR SIDOROV");
|
||
}
|
||
|
||
@Test
|
||
void masksSecurityCodeAndPinCompletely() {
|
||
String masked = mask("Карта 4111 1111 1111 1111, CVV 123, пин-код 4321");
|
||
assertFalse(masked.contains("123,"), masked);
|
||
assertFalse(masked.contains("4321"), masked);
|
||
assertTrue(masked.contains("***"), masked);
|
||
}
|
||
|
||
@Test
|
||
void doesNotMaskPinWithoutAnyOtherPersonalData() {
|
||
String text = "Пин-код 1234 введён неверно";
|
||
assertEquals(text, mask(text), "одиночный пин-код персональными данными не является");
|
||
}
|
||
|
||
@Test
|
||
void masksPinWhenCardNumberIsAlsoPresent() {
|
||
assertHidden("Пин-код 1234 от карты 4111 1111 1111 1111", "1234 от");
|
||
}
|
||
|
||
@Test
|
||
void anchorWordsAreCaseInsensitive() {
|
||
assertHidden("ПАСПОРТ СЕРИЯ 4509 НОМЕР 123456", "123456");
|
||
assertHidden("гРаЖдАнСтВо РФ, паспорт 4509 123456", "4509 123456");
|
||
}
|
||
|
||
@Test
|
||
void complexSentenceKeepsSurroundingWords() {
|
||
String original = "Клиент, паспорт 4509 123456 выдан ОУФМС по г. Москве, "
|
||
+ "код подразделения 770-001, ИНН 770301234550, телефон +7 916 123-45-67";
|
||
String masked = mask(original);
|
||
|
||
assertTrue(masked.startsWith("Клиент, паспорт "), masked);
|
||
assertTrue(masked.contains("код подразделения"), masked);
|
||
assertTrue(masked.contains("телефон"), masked);
|
||
assertFalse(masked.contains("4509 123456"), masked);
|
||
assertFalse(masked.contains("770301234550"), masked);
|
||
}
|
||
|
||
@Test
|
||
void unmaskingRestoresComplexSentence() {
|
||
String original = "Паспорт 4509 123456, выдан ОУФМС России по г. Москве, "
|
||
+ "код подразделения 770-001, гражданство РФ, CVV 123, карта 4111 1111 1111 1111";
|
||
String id = "complex-1";
|
||
|
||
String masked = pipeline.process(original, id, SystemPolicy.DEFAULT);
|
||
assertFalse(masked.contains("4509 123456"), masked);
|
||
assertEquals(original, pipeline.process(masked, id, SystemPolicy.DEFAULT));
|
||
}
|
||
}
|