diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt index b753f30df1c058f28895e797933d93c78edd28f0..5d9d4d09f61d5e230380fa7528c5e13b45db1018 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt @@ -13,6 +13,7 @@ import de.rki.coronawarnapp.bugreporting.censors.presencetracing.CheckInsCensor import de.rki.coronawarnapp.bugreporting.censors.presencetracing.TraceLocationCensor import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor +import de.rki.coronawarnapp.bugreporting.censors.submission.PcrTeleTanCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RatProfileCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RatQrCodeCensor @@ -83,6 +84,10 @@ class BugReportingSharedModule { @IntoSet fun pcrQrCodeCensor(censor: PcrQrCodeCensor): BugCensor = censor + @Provides + @IntoSet + fun pcrTeleTanCensor(censor: PcrTeleTanCensor): BugCensor = censor + @Provides @IntoSet fun ratQrCodeCensor(censor: RatQrCodeCensor): BugCensor = censor diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrTeleTanCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrTeleTanCensor.kt new file mode 100644 index 0000000000000000000000000000000000000000..bcfe7cf9d7556ac96db54cd8119c4a76a4d3a18f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrTeleTanCensor.kt @@ -0,0 +1,37 @@ +package de.rki.coronawarnapp.bugreporting.censors.submission + +import dagger.Reusable +import de.rki.coronawarnapp.bugreporting.censors.BugCensor +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import javax.inject.Inject + +@Reusable +class PcrTeleTanCensor @Inject constructor() : BugCensor { + + override suspend fun checkLog(message: String): BugCensor.CensorContainer? = mutex.withLock { + if (transientTeleTans.isEmpty()) return null + + var container = BugCensor.CensorContainer(message) + + transientTeleTans.forEach { + container = container.censor(it, PLACEHOLDER + it.takeLast(3)) + } + + return container.nullIfEmpty() + } + + companion object { + private val mutex = Mutex() + private val transientTeleTans = mutableSetOf<String>() + suspend fun addTan(tan: String) = mutex.withLock { + transientTeleTans.add(tan) + } + + suspend fun clearTans() = mutex.withLock { + transientTeleTans.clear() + } + + private const val PLACEHOLDER = "#######" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt index f92627014da54b10669180614e0d2f6847fa5ad1..71c530b2fd4043bb06f86ba62dc4d0ad07a782d9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.asLiveData import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.bugreporting.censors.submission.PcrTeleTanCensor import de.rki.coronawarnapp.coronatest.tan.CoronaTestTAN import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.exception.ExceptionCategory @@ -53,6 +54,8 @@ class SubmissionTanViewModel @AssistedInject constructor( } launch { + PcrTeleTanCensor.addTan(teletan.value) + val pcrTestAlreadyStored = submissionRepository.testForType(CoronaTest.Type.PCR).first() if (pcrTestAlreadyStored != null) { val coronaTestTAN = CoronaTestTAN.PCR(tan = teletan.value) diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrTeleTanCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrTeleTanCensorTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..d73e7020504d6b190ec502d15e5d48db2bdf0f5b --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrTeleTanCensorTest.kt @@ -0,0 +1,81 @@ +package de.rki.coronawarnapp.bugreporting.censors + +import de.rki.coronawarnapp.bugreporting.censors.submission.PcrTeleTanCensor +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class PcrTeleTanCensorTest : BaseTest() { + + private val testTans = listOf( + "WF894R5XX5", + "XJYNJU3MTB", + "2MU6N6JRE5", + "ZX3EWW4JX7", + "5ARBA4W2NC", + "FQEKD78DVC", + "WBNNPG3HGF", + "E856RHPKY9", + ) + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + } + + @AfterEach + fun teardown() { + runBlocking { PcrTeleTanCensor.clearTans() } + } + + private fun createInstance() = PcrTeleTanCensor() + + @Test + fun `censoring replaces the logline message`() = runBlockingTest { + val instance = createInstance() + + testTans.forEach { + PcrTeleTanCensor.addTan(it) + val toCensor = "I'm a shy teletan: $it" + instance.checkLog(toCensor)!! + .compile()!!.censored shouldBe "I'm a shy teletan: #######${it.takeLast(3)}" + } + } + + @Test + fun `censoring replaces the logline message - multiple instances`() = runBlockingTest { + testTans.forEach { + PcrTeleTanCensor.addTan(it) + val toCensor = "I'm a shy teletan: $it" + createInstance().checkLog(toCensor)!! + .compile()!!.censored shouldBe "I'm a shy teletan: #######${it.takeLast(3)}" + } + } + + @Test + fun `censoring returns null if there is no match`() = runBlockingTest { + val instance = createInstance() + + testTans.map { it.substring(2) }.forEach { + PcrTeleTanCensor.addTan(it) + val toCensor = "I'm a shy teletan: $it" + instance.checkLog(toCensor)!! + .compile()!!.censored shouldBe "I'm a shy teletan: #######${it.takeLast(3)}" + } + } + + @Test + fun `censoring aborts if no teletan was set`() = runBlockingTest { + val instance = createInstance() + + testTans.forEach { + val toCensor = "I'm a shy teletan: $it" + instance.checkLog(toCensor) shouldBe null + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt index d5dda05755932614abcc4a6cc540828f3a50a50a..cb7254f771638c6772d4acd0e1d1c32d6c572ed9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.coronatest.type.pcr +import de.rki.coronawarnapp.bugreporting.censors.submission.PcrTeleTanCensor import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode import de.rki.coronawarnapp.coronatest.server.CoronaTestResult import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.PCR_INVALID @@ -27,9 +28,11 @@ import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runBlockingTest import org.joda.time.Duration import org.joda.time.Instant +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -82,6 +85,11 @@ class PCRProcessorTest : BaseTest() { } } + @AfterEach + fun teardown() { + runBlocking { PcrTeleTanCensor.clearTans() } + } + fun createInstance() = PCRProcessor( timeStamper = timeStamper, submissionService = submissionService,