From e9e7635467001f29fbbf2828b6285c4351bf1f34 Mon Sep 17 00:00:00 2001
From: Mohamed <mohamed.metwalli@sap.com>
Date: Wed, 10 Mar 2021 17:49:30 +0100
Subject: [PATCH] Event verification (EXPOSUREAPP-5423) (#2524)

* Basic setup

* Test verification

* Update DefaultQRCodeVerifierTest.kt

* Invert boolean to reflect method name

* Adjustments to prepare for refactoring of "Verificationkeys" class.

* Add more tests and modify encoded event data

* Update ConfirmCheckInViewModelTest.kt

* Consider warning case

* Add test cases for warning

* Fix test

* Show error

* Add todo

* lint

* Move time warnings into result

* Update ConfirmCheckInViewModelTest.kt

Co-authored-by: Matthias Urhahn <matthias.urhahn@sap.com>
---
 .../qrcode/DefaultQRCodeVerifierTest.kt       | 107 ++++++++++++++++++
 .../deviceForTesters/res/values/strings.xml   |   2 +-
 .../EventRegistrationModule.kt                |   8 +-
 .../checkins/qrcode/DefaultQRCodeVerifier.kt  |  42 +++++++
 .../checkins/qrcode/EventQRCode.kt            |  10 --
 .../qrcode/InvalidQRCodeDataException.kt      |   6 +
 .../qrcode/InvalidQRCodeSignatureException.kt |   6 +
 .../checkins/qrcode/QRCodeException.kt        |   6 +
 .../checkins/qrcode/QRCodeVerifier.kt         |   2 +-
 .../checkins/qrcode/QRCodeVerifyResult.kt     |  15 +++
 .../checkin/ConfirmCheckInFragment.kt         |  11 +-
 .../checkin/ConfirmCheckInViewModel.kt        |  36 +++---
 .../checkin/ConfirmCheckInViewModelTest.kt    |  24 ++--
 13 files changed, 220 insertions(+), 55 deletions(-)
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifier.kt
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/EventQRCode.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifyResult.kt

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest.kt
new file mode 100644
index 000000000..a87914a5e
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest.kt
@@ -0,0 +1,107 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.environment.EnvironmentSetup
+import de.rki.coronawarnapp.util.security.SignatureValidation
+import io.kotest.assertions.throwables.shouldNotThrowAny
+import io.kotest.assertions.throwables.shouldThrow
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Instant
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import testhelpers.BaseTestInstrumentation
+
+@RunWith(JUnit4::class)
+class DefaultQRCodeVerifierTest : BaseTestInstrumentation() {
+
+    @MockK lateinit var environmentSetup: EnvironmentSetup
+    private lateinit var qrCodeVerifier: QRCodeVerifier
+
+    @Before
+    fun setUp() {
+        MockKAnnotations.init(this)
+        every { environmentSetup.appConfigVerificationKey } returns PUB_KEY
+        qrCodeVerifier = DefaultQRCodeVerifier(SignatureValidation(environmentSetup))
+    }
+
+    @Test
+    fun verifyEventSuccess() = runBlockingTest {
+        val time = 2687960 * 1_000L
+        val instant = Instant.ofEpochMilli(time)
+        shouldNotThrowAny {
+            val verifyResult = qrCodeVerifier.verify(ENCODED_EVENT)
+            verifyResult.apply {
+                singedTraceLocation.event.description shouldBe "CWA Launch Party"
+                verifyResult.isBeforeStartTime(instant) shouldBe false
+                verifyResult.isAfterEndTime(instant) shouldBe false
+            }
+        }
+    }
+
+    @Test
+    fun verifyEventStartTimeWaning() = runBlockingTest {
+        val time = 2687940 * 1_000L
+        val instant = Instant.ofEpochMilli(time)
+        shouldNotThrowAny {
+            val verifyResult = qrCodeVerifier.verify(ENCODED_EVENT)
+            verifyResult.apply {
+                singedTraceLocation.event.description shouldBe "CWA Launch Party"
+            }
+            verifyResult.isBeforeStartTime(instant) shouldBe true
+            verifyResult.isAfterEndTime(instant) shouldBe false
+        }
+    }
+
+    @Test
+    fun verifyEventEndTimeWarning() = runBlockingTest {
+        val instant = Instant.now()
+        shouldNotThrowAny {
+            val verifyResult = qrCodeVerifier.verify(ENCODED_EVENT)
+            verifyResult.apply {
+                singedTraceLocation.event.description shouldBe "CWA Launch Party"
+            }
+            verifyResult.isBeforeStartTime(instant) shouldBe false
+            verifyResult.isAfterEndTime(instant) shouldBe true
+        }
+    }
+
+    @Test
+    fun verifyEventWithInvalidKey() = runBlockingTest {
+        every { environmentSetup.appConfigVerificationKey } returns INVALID_PUB_KEY
+        shouldThrow<InvalidQRCodeSignatureException> {
+            qrCodeVerifier.verify(ENCODED_EVENT)
+        }
+    }
+
+    @Test
+    fun eventHasMalformedData() = runBlockingTest {
+        shouldThrow<InvalidQRCodeDataException> {
+            qrCodeVerifier.verify(INVALID_ENCODED_EVENT)
+        }
+    }
+
+    companion object {
+
+        private const val INVALID_PUB_KEY = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg" +
+            "3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+
+        private const val PUB_KEY = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEafIKZOiRPuJWjKOUmKv7OTJWTyii" +
+            "4oCQLcGn3FgYoLQaJIvAM3Pl7anFDPPY/jxfqqrLyGc0f6hWQ9JPR3QjBw=="
+
+        private const val INVALID_ENCODED_EVENT =
+            "BIPEY33SMVWSA2LQON2W2IDEN5WG64RAONUXIIDBNVSXILBAMNXRBCM4UQARRKM6UQASAHRKCC7CTDWGQ" +
+                "4JCO7RVZSWVIMQK4UPA.GBCAEIA7TEORBTUA25QHBOCWT26BCA5PORBS2E4FFWMJ3U" +
+                "U3P6SXOL7SHUBCA7UEZBDDQ2R6VRJH7WBJKVF7GZYJA6YMRN27IPEP7NKGGJSWX3XQ"
+
+        private const val ENCODED_EVENT =
+            "BIYAUEDBZY6EIWF7QX6JOKSRPAGEB3H7CIIEGV2BEBGGC5LOMNUCAUDBOJ2" +
+                "HSGGTQ6SACIHXQ6SACKA6CJEDARQCEEAPHGEZ5JI2K2T422L5U3SMZY5DGC" +
+                "PUZ2RQACAYEJ3HQYMAFFBU2SQCEEAJAUCJSQJ7WDM675MCMOD3L2UL7ECJU" +
+                "7TYERH23B746RQTABO3CTI="
+    }
+}
diff --git a/Corona-Warn-App/src/deviceForTesters/res/values/strings.xml b/Corona-Warn-App/src/deviceForTesters/res/values/strings.xml
index 8a8f0e4c7..414ff9334 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/values/strings.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/values/strings.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <string name="qr_code_input" translatable="false">"HTTPS://CORONAWARN.APP/E1/BIPEY33SMVWSA2LQON2W2IDEN5WG64RAONUXIIDBNVSXILBAMNXRBCM4UQARRKM6UQASAHRKCC7CTDWGQ4JCO7RVZSWVIMQK4UPA.GBCAEIA7TEORBTUA25QHBOCWT26BCA5PORBS2E4FFWMJ3UU3P6SXOL7SHUBCA7UEZBDDQ2R6VRJH7WBJKVF7GZYJA6YMRN27IPEP7NKGGJSWX3XQ"</string>
+    <string name="qr_code_input" translatable="false">"HTTPS://CORONAWARN.APP/E1/BIYAUEDBZY6EIWF7QX6JOKSRPAGEB3H7CIIEGV2BEBGGC5LOMNUCAUDBOJ2HSGGTQ6SACIHXQ6SACKA6CJEDARQCEEAPHGEZ5JI2K2T422L5U3SMZY5DGCPUZ2RQACAYEJ3HQYMAFFBU2SQCEEAJAUCJSQJ7WDM675MCMOD3L2UL7ECJU7TYERH23B746RQTABO3CTI="</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
index b9234ea0f..93780e4dd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
@@ -1,9 +1,13 @@
 package de.rki.coronawarnapp.eventregistration
 
+import dagger.Binds
 import dagger.Module
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.DefaultQRCodeVerifier
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeVerifier
 
 @Suppress("EmptyClassBlock")
 @Module
-class EventRegistrationModule {
-    // TODO
+abstract class EventRegistrationModule {
+    @Binds
+    abstract fun qrCodeVerifier(qrCodeVerifier: DefaultQRCodeVerifier): QRCodeVerifier
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifier.kt
new file mode 100644
index 000000000..e0f2dc582
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifier.kt
@@ -0,0 +1,42 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.eventregistration.common.decodeBase32
+import de.rki.coronawarnapp.server.protocols.internal.evreg.SignedEventOuterClass
+import de.rki.coronawarnapp.util.security.SignatureValidation
+import timber.log.Timber
+import javax.inject.Inject
+
+class DefaultQRCodeVerifier @Inject constructor(
+    private val signatureValidation: SignatureValidation
+) : QRCodeVerifier {
+
+    override suspend fun verify(encodedEvent: String): QRCodeVerifyResult {
+        Timber.tag(TAG).v("Verifying: %s", encodedEvent)
+
+        val signedEvent = try {
+            SignedEventOuterClass.SignedEvent.parseFrom(encodedEvent.decodeBase32().toByteArray())
+        } catch (e: Exception) {
+            throw InvalidQRCodeDataException(cause = e, message = "QR-code data could not be parsed.")
+        }
+        Timber.tag(TAG).d("Parsed to signed event: %s", signedEvent)
+
+        val isValid = try {
+            signatureValidation.hasValidSignature(
+                signedEvent.event.toByteArray(),
+                sequenceOf(signedEvent.signature.toByteArray())
+            )
+        } catch (e: Exception) {
+            throw InvalidQRCodeDataException(cause = e, message = "Verification failed.")
+        }
+
+        if (!isValid) {
+            throw InvalidQRCodeSignatureException(message = "QR-code did not match signature.")
+        }
+
+        return QRCodeVerifyResult(signedEvent)
+    }
+
+    companion object {
+        private const val TAG = "DefaultQRCodeVerifier"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/EventQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/EventQRCode.kt
deleted file mode 100644
index 69edb248e..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/EventQRCode.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package de.rki.coronawarnapp.eventregistration.checkins.qrcode
-
-import org.joda.time.Instant
-
-data class EventQRCode(
-    val guid: String,
-    val description: String? = null,
-    val start: Instant? = null,
-    val end: Instant? = null,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt
new file mode 100644
index 000000000..935e86b31
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+class InvalidQRCodeDataException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : QRCodeException(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt
new file mode 100644
index 000000000..eae77689d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+class InvalidQRCodeSignatureException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : QRCodeException(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
new file mode 100644
index 000000000..1fb4c881a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+open class QRCodeException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifier.kt
index 910b6237e..8e7e2452d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifier.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifier.kt
@@ -2,5 +2,5 @@ package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
 interface QRCodeVerifier {
 
-    suspend fun verify(code: EventQRCode): Boolean
+    suspend fun verify(encodedEvent: String): QRCodeVerifyResult
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifyResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifyResult.kt
new file mode 100644
index 000000000..239d4dab1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeVerifyResult.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.server.protocols.internal.evreg.SignedEventOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import org.joda.time.Instant
+
+data class QRCodeVerifyResult(
+    val singedTraceLocation: SignedEventOuterClass.SignedEvent
+) {
+    fun isBeforeStartTime(now: Instant): Boolean =
+        singedTraceLocation.event.start != 0 && singedTraceLocation.event.start > now.seconds
+
+    fun isAfterEndTime(now: Instant): Boolean =
+        singedTraceLocation.event.end != 0 && singedTraceLocation.event.end < now.seconds
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInFragment.kt
index c1389bd41..cb50a2092 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInFragment.kt
@@ -39,12 +39,13 @@ class ConfirmCheckInFragment : Fragment(R.layout.fragment_confrim_check_in), Aut
         }
 
         // TODO bind data to actual UI
-        viewModel.eventData.observe2(this) {
+        viewModel.verifyResult.observe2(this) {
+            val event = it.singedTraceLocation.event
             with(binding) {
-                eventGuid.text = "GUID: %s".format(it.guid)
-                startTime.text = "Start time: %s".format(it.start)
-                endTime.text = "End time: %s".format(it.end)
-                description.text = "Description: %s".format(it.description)
+                eventGuid.text = "GUID: %s".format(event.guid)
+                startTime.text = "Start time: %s".format(event.start)
+                endTime.text = "End time: %s".format(event.end)
+                description.text = "Description: %s".format(event.description)
             }
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModel.kt
index 011f3d4b5..6708ebe00 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModel.kt
@@ -3,25 +3,30 @@ package de.rki.coronawarnapp.ui.eventregistration.checkin
 import androidx.lifecycle.MutableLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.eventregistration.checkins.qrcode.EventQRCode
-import de.rki.coronawarnapp.eventregistration.common.decodeBase32
-import de.rki.coronawarnapp.server.protocols.internal.evreg.EventOuterClass
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeVerifier
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeVerifyResult
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import org.joda.time.Instant
+import timber.log.Timber
 
-class ConfirmCheckInViewModel @AssistedInject constructor() : CWAViewModel() {
-    private val eventLiveData = MutableLiveData<EventQRCode>()
-    val eventData = eventLiveData
+class ConfirmCheckInViewModel @AssistedInject constructor(
+    private val qrCodeVerifier: QRCodeVerifier
+) : CWAViewModel() {
+    private val internalVerifyResult = MutableLiveData<QRCodeVerifyResult>()
+    val verifyResult = internalVerifyResult
     val navigationEvents = SingleLiveEvent<ConfirmCheckInEvent>()
 
     fun decodeEvent(encodedEvent: String) = launch {
-        // TODO Verify event(EXPOSUREAPP-5423)
-        //  and finalise event parsing logic
-        val decodedEventString = encodedEvent.split(".")[0].decodeBase32()
-        val parseEvent = EventOuterClass.Event.parseFrom(decodedEventString.toByteArray())
-        eventLiveData.postValue(parseEvent.toEventQrCode())
+        // TODO this logic should moved from here. Here user should confirm event only
+        try {
+            internalVerifyResult.postValue(qrCodeVerifier.verify(encodedEvent))
+        } catch (e: Exception) {
+            Timber.d(e)
+            e.report(ExceptionCategory.INTERNAL)
+        }
     }
 
     fun onClose() {
@@ -32,13 +37,6 @@ class ConfirmCheckInViewModel @AssistedInject constructor() : CWAViewModel() {
         navigationEvents.value = ConfirmCheckInEvent.ConfirmEvent
     }
 
-    private fun EventOuterClass.Event.toEventQrCode() = EventQRCode(
-        guid = String(guid.toByteArray()),
-        description = description,
-        start = Instant.ofEpochMilli(start.toLong()),
-        end = Instant.ofEpochMilli(end.toLong())
-    )
-
     @AssistedFactory
     interface Factory : SimpleCWAViewModelFactory<ConfirmCheckInViewModel>
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModelTest.kt
index bb02e9962..7b9cc3973 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/checkin/ConfirmCheckInViewModelTest.kt
@@ -1,8 +1,9 @@
 package de.rki.coronawarnapp.ui.eventregistration.checkin
 
-import de.rki.coronawarnapp.eventregistration.checkins.qrcode.EventQRCode
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeVerifier
 import io.kotest.matchers.shouldBe
-import org.joda.time.Instant
+import io.mockk.MockKAnnotations
+import io.mockk.impl.annotations.MockK
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 
@@ -16,23 +17,12 @@ class ConfirmCheckInViewModelTest : BaseTest() {
 
     private lateinit var viewModel: ConfirmCheckInViewModel
 
+    @MockK lateinit var qrCodeVerifier: QRCodeVerifier
+
     @BeforeEach
     fun setUp() {
-        viewModel = ConfirmCheckInViewModel()
-    }
-
-    @Test
-    fun decodeEvent() {
-        val decodedEvent =
-            "BIPEY33SMVWSA2LQON2W2IDEN5WG64RAONUXIIDBNVSXILBAMNXRBCM4UQARRKM6UQASAHRKCC7CTDWGQ4JCO7RVZSWVIMQK4UPA" +
-                ".GBCAEIA7TEORBTUA25QHBOCWT26BCA5PORBS2E4FFWMJ3UU3P6SXOL7SHUBCA7UEZBDDQ2R6VRJH7WBJKVF7GZYJA6YMRN27IPEP7NKGGJSWX3XQ"
-        viewModel.decodeEvent(decodedEvent)
-        viewModel.eventData.getOrAwaitValue() shouldBe EventQRCode(
-            guid = "Lorem ipsum dolor sit amet, co",
-            description = "",
-            start = Instant.parse("1970-01-01T00:44:50.857Z"),
-            end = Instant.parse("1970-01-01T00:00:00.030Z")
-        )
+        MockKAnnotations.init(this)
+        viewModel = ConfirmCheckInViewModel(qrCodeVerifier)
     }
 
     @Test
-- 
GitLab