diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifier.kt new file mode 100644 index 0000000000000000000000000000000000000000..abd313609ebdd09320116af2a9a86fdeafb125c9 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifier.kt @@ -0,0 +1,76 @@ +package de.rki.coronawarnapp.eventregistration.checkins.qrcode + +import androidx.annotation.StringRes +import dagger.Reusable +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import javax.inject.Inject + +@Reusable +class TraceLocationVerifier @Inject constructor() { + @Suppress("ReturnCount") + fun verifyTraceLocation(protoQrCodePayload: TraceLocationOuterClass.QRCodePayload): VerificationResult { + val traceLocation = protoQrCodePayload.traceLocation() + + if (traceLocation.description.isEmpty()) { + return VerificationResult.Invalid.Description + } + + if (traceLocation.description.length > QR_CODE_DESCRIPTION_MAX_LENGTH) { + return VerificationResult.Invalid.Description + } + + if (traceLocation.description.lines().size > 1) { + return VerificationResult.Invalid.Description + } + + if (traceLocation.address.isEmpty()) { + return VerificationResult.Invalid.Address + } + + if (traceLocation.address.length > QR_CODE_ADDRESS_MAX_LENGTH) { + return VerificationResult.Invalid.Address + } + + if (traceLocation.address.lines().size > 1) { + return VerificationResult.Invalid.Address + } + + // If both are 0 do nothing else check start is smaller than end or return error + if (!( + protoQrCodePayload.locationData.startTimestamp == 0L && + protoQrCodePayload.locationData.endTimestamp == 0L + ) + ) { + if (protoQrCodePayload.locationData.startTimestamp > protoQrCodePayload.locationData.endTimestamp) { + return VerificationResult.Invalid.StartEndTime + } + } + + if (traceLocation.cryptographicSeed.size != CROWD_NOTIFIER_CRYPTO_SEED_LENGTH) { + return VerificationResult.Invalid.CryptographicSeed + } + + return VerificationResult.Valid( + VerifiedTraceLocation(protoQrCodePayload) + ) + } + + sealed class VerificationResult { + data class Valid(val verifiedTraceLocation: VerifiedTraceLocation) : VerificationResult() + + sealed class Invalid(@StringRes val errorTextRes: Int) : VerificationResult() { + object Description : Invalid(R.string.trace_location_checkins_qr_code_invalid_description) + object Address : Invalid(R.string.trace_location_checkins_qr_code_invalid_address) + object StartEndTime : Invalid(R.string.trace_location_checkins_qr_code_invalid_times) + object CryptographicSeed : + Invalid(R.string.trace_location_checkins_qr_code_invalid_cryptographic_seed) + } + } + + companion object { + private const val CROWD_NOTIFIER_CRYPTO_SEED_LENGTH = 16 + private const val QR_CODE_DESCRIPTION_MAX_LENGTH = 100 + private const val QR_CODE_ADDRESS_MAX_LENGTH = 100 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInEvent.kt index e39108ce29600a74f267bbf33eca0ed36ff2bb96..a8c0aba5198cd1c7f7bfa98a90e34dea8566ce5c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInEvent.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInEvent.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins +import androidx.annotation.StringRes import de.rki.coronawarnapp.eventregistration.checkins.CheckIn import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation @@ -11,6 +12,8 @@ sealed class CheckInEvent { data class ConfirmCheckIn(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent() + data class InvalidQrCode(@StringRes val errorTextRes: Int) : CheckInEvent() + data class ConfirmCheckInWithoutHistory(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent() data class EditCheckIn(val checkInId: Long, val position: Int) : CheckInEvent() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt index 5b9a042b7d75a2fabf76e7a0d616a15c71b204b5..d198e93cc2b4ac82228cc1215d73cec574e7fa7f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.provider.Settings import android.view.View import android.widget.Toast +import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.Toolbar import androidx.core.net.toUri @@ -16,6 +17,7 @@ import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DefaultItemAnimator +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.transition.Hold import com.google.android.material.transition.MaterialSharedAxis import de.rki.coronawarnapp.BuildConfig @@ -38,7 +40,6 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber -import java.lang.Exception import java.net.URLEncoder import javax.inject.Inject @@ -98,6 +99,8 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag ) } + is CheckInEvent.InvalidQrCode -> showInvalidQrCodeInformation(event.errorTextRes) + is CheckInEvent.ConfirmCheckInWithoutHistory -> doNavigate( CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragmentCleanHistory( verifiedTraceLocation = event.verifiedTraceLocation @@ -132,6 +135,13 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag } } + private fun showInvalidQrCodeInformation(@StringRes errorTextRes: Int) = + MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(R.string.errors_generic_headline) + setMessage(errorTextRes) + setPositiveButton(R.string.errors_generic_button_positive) { _, _ -> } + }.show() + private fun updateViews(items: List<CheckInsItem>) { checkInsAdapter.update(items) binding.apply { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt index f80b589f139c25a5a4f4c9f0d3811bc119e146aa..94c98114e6d18bbff7bd7932ba116ef723bb7684 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt @@ -9,7 +9,7 @@ import dagger.assisted.AssistedInject import de.rki.coronawarnapp.eventregistration.checkins.CheckIn import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeUriParser -import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation +import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocationVerifier import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler @@ -28,6 +28,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import timber.log.Timber +@Suppress("LongParameterList") class CheckInsViewModel @AssistedInject constructor( @Assisted private val savedState: SavedStateHandle, @Assisted private val deepLink: String?, @@ -37,7 +38,8 @@ class CheckInsViewModel @AssistedInject constructor( private val qrCodeUriParser: QRCodeUriParser, private val checkInsRepository: CheckInRepository, private val checkOutHandler: CheckOutHandler, - private val cameraPermissionProvider: CameraPermissionProvider + private val cameraPermissionProvider: CameraPermissionProvider, + private val traceLocationVerifier: TraceLocationVerifier ) : CWAViewModel(dispatcherProvider) { val events = SingleLiveEvent<CheckInEvent>() @@ -143,13 +145,16 @@ class CheckInsViewModel @AssistedInject constructor( try { Timber.i("uri: $uri") val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri) - val verifiedTraceLocation = VerifiedTraceLocation(qrCodePayload) - events.postValue( - if (cleanHistory) - CheckInEvent.ConfirmCheckInWithoutHistory(verifiedTraceLocation) - else - CheckInEvent.ConfirmCheckIn(verifiedTraceLocation) - ) + when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) { + is TraceLocationVerifier.VerificationResult.Valid -> events.postValue( + if (cleanHistory) + CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation) + else + CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation) + ) + is TraceLocationVerifier.VerificationResult.Invalid -> + events.postValue(CheckInEvent.InvalidQrCode(verifyResult.errorTextRes)) + } } catch (e: Exception) { Timber.d(e, "TraceLocation verification failed") e.report(ExceptionCategory.INTERNAL) diff --git a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml index 732c3f2c57841116a81ebae569f4bdc3f7defcef..758b6ca6e8c166dd4540c89b14c42010f5ffb433 100644 --- a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml @@ -259,4 +259,14 @@ <!-- XBUT: Organizer Flow : Title for save as template button --> <string name="trace_location_event_detail_save_as_template_button">"Als Vorlage verwenden"</string> + <!-- Qr Code Validation Messages --> + <!-- XTXT: My check-ins: qr code validation wrong description field --> + <string name="trace_location_checkins_qr_code_invalid_description">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_DESCRIPTION)."</string> + <!-- XTXT: My check-ins: qr code validation wrong address field --> + <string name="trace_location_checkins_qr_code_invalid_address">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_ADDRESS)."</string> + <!-- XTXT: My check-ins: qr code validation wrong start end time field --> + <string name="trace_location_checkins_qr_code_invalid_times">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_TIMESTAMPS)."</string> + <!-- XTXT: My check-ins: qr code validation wrong cryptographic seed field --> + <string name="trace_location_checkins_qr_code_invalid_cryptographic_seed">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_CRYPTO_SEED)."</string> + </resources> diff --git a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml index 453cda2241e0d14ef22be58292a245358b2cc354..9896181c86dbe91f97783d12c58501d797371a41 100644 --- a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml @@ -257,4 +257,14 @@ <!-- XBUT: Organizer Flow : Title for save as template button --> <string name="trace_location_event_detail_save_as_template_button">"Use as Template"</string> + <!-- Qr Code Validation Messages --> + <!-- XTXT: My check-ins: qr code validation wrong description field --> + <string name="trace_location_checkins_qr_code_invalid_description">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_DESCRIPTION)."</string> + <!-- XTXT: My check-ins: qr code validation wrong address field --> + <string name="trace_location_checkins_qr_code_invalid_address">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_ADDRESS)."</string> + <!-- XTXT: My check-ins: qr code validation wrong start end time field --> + <string name="trace_location_checkins_qr_code_invalid_times">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_TIMESTAMPS)."</string> + <!-- XTXT: My check-ins: qr code validation wrong cryptographic seed field --> + <string name="trace_location_checkins_qr_code_invalid_cryptographic_seed">"Ungültiger QR-Code verhindert das Einchecken. Die verantwortliche Stelle muss einen neuen QR-Code generieren (Fehlercode INVALID_CRYPTO_SEED)."</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeProvider.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..6d8df6b978065dd082d5a9d2825af00e11df9a88 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeProvider.kt @@ -0,0 +1,148 @@ +package de.rki.coronawarnapp.eventregistration.checkins.qrcode + +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import de.rki.coronawarnapp.util.toProtoByteString +import okio.ByteString.Companion.decodeBase64 +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import java.util.stream.Stream + +class InvalidQRCodeProvider : ArgumentsProvider { + private fun baseValidQrCodeBuilder(): TraceLocationOuterClass.QRCodePayload.Builder = + TraceLocationOuterClass.QRCodePayload.newBuilder() + .setVersion(1) + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ) + .setVendorData("CAEQARgK".decodeBase64()!!.toProtoByteString()) + .setLocationData( + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("Icecream Shop") + .setAddress("Main Street 1") + .setVersion(1) + .build() + ) + + private fun baseValidLocationData(): TraceLocationOuterClass.TraceLocation.Builder = + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("Icecream Shop") + .setAddress("Main Street 1") + .setVersion(1) + + override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> { + return Stream.of( + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setStartTimestamp(2687991) + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.StartEndTime + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setStartTimestamp(2687991) + .setEndTimestamp(2387991) + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.StartEndTime + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setDescription("") + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Description + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .clearDescription() + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Description + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setDescription((0..101).joinToString { "a" }) + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Description + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setDescription("A \n B") + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Description + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setAddress("") + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Address + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .clearAddress() + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Address + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setAddress((0..101).joinToString { "a" }) + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Address + ), + Arguments.of( + baseValidQrCodeBuilder() + .setLocationData( + baseValidLocationData() + .setAddress("A \n B") + .build() + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.Address + ), + Arguments.of( + baseValidQrCodeBuilder() + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed("WNlQ==".decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ).build(), + TraceLocationVerifier.VerificationResult.Invalid.CryptographicSeed + ) + ) + } + + companion object { + const val CRYPTOGRAPHIC_SEED = "zveDikIfwAXWqI6h4dWNlQ==" + const val PUB_KEY = + "OMTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9" + + "eq+voxQ1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UD" + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifierTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifierTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..1bc7865431213f233211fd4eecaa641f8cc16586 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocationVerifierTest.kt @@ -0,0 +1,32 @@ +package de.rki.coronawarnapp.eventregistration.checkins.qrcode + +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import io.kotest.matchers.shouldBe +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource +import testhelpers.BaseTest + +class TraceLocationVerifierTest : BaseTest() { + fun createInstance() = TraceLocationVerifier() + + @ParameterizedTest + @ArgumentsSource(ValidQRCodeProvider::class) + fun `Valid QR Codes`( + protoQrCodePayload: TraceLocationOuterClass.QRCodePayload + ) { + val validationResult = createInstance().verifyTraceLocation(protoQrCodePayload) + + (validationResult is TraceLocationVerifier.VerificationResult.Valid) shouldBe true + } + + @ParameterizedTest + @ArgumentsSource(InvalidQRCodeProvider::class) + fun `Invalid QR Codes`( + protoQrCodePayload: TraceLocationOuterClass.QRCodePayload, + expectedFailure: TraceLocationVerifier.VerificationResult.Invalid + ) { + val validationResult = createInstance().verifyTraceLocation(protoQrCodePayload) + + validationResult shouldBe expectedFailure + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidQRCodeProvider.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidQRCodeProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..bd08d284659adf109ec01c0b29834815631f01d1 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidQRCodeProvider.kt @@ -0,0 +1,104 @@ +package de.rki.coronawarnapp.eventregistration.checkins.qrcode + +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import de.rki.coronawarnapp.util.toProtoByteString +import okio.ByteString.Companion.decodeBase64 +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import java.util.stream.Stream + +class ValidQRCodeProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> { + return Stream.of( + Arguments.of( + TraceLocationOuterClass.QRCodePayload.newBuilder() + .setVersion(1) + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ) + .setVendorData("CAEQAg==".decodeBase64()!!.toProtoByteString()) + .setLocationData( + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("My Birthday Party") + .setAddress("at my place") + .setStartTimestamp(2687955) + .setEndTimestamp(2687991) + .setVersion(1) + .build() + ) + .build() + ), + Arguments.of( + TraceLocationOuterClass.QRCodePayload.newBuilder() + .setVersion(1) + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ) + .setVendorData("CAEQAg==".decodeBase64()!!.toProtoByteString()) + .setLocationData( + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("My Birthday Party") + .setAddress("at my place") + .setStartTimestamp(2687991) + .setEndTimestamp(2687991) + .setVersion(1) + .build() + ) + .build() + ), + Arguments.of( + TraceLocationOuterClass.QRCodePayload.newBuilder() + .setVersion(1) + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ) + .setVendorData("CAEQAg==".decodeBase64()!!.toProtoByteString()) + .setLocationData( + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("My Birthday Party") + .setAddress("at my place") + .setEndTimestamp(2687991) + .setVersion(1) + .build() + ) + .build() + ), + Arguments.of( + TraceLocationOuterClass.QRCodePayload.newBuilder() + .setVersion(1) + .setCrowdNotifierData( + TraceLocationOuterClass.CrowdNotifierData.newBuilder() + .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString()) + .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString()) + .setVersion(1) + ) + .setVendorData("CAEQARgK".decodeBase64()!!.toProtoByteString()) + .setLocationData( + TraceLocationOuterClass.TraceLocation.newBuilder() + .setDescription("Icecream Shop") + .setAddress("Main Street 1") + .setVersion(1) + .build() + ) + .build() + ) + ) + } + + companion object { + const val CRYPTOGRAPHIC_SEED = "zveDikIfwAXWqI6h4dWNlQ==" + const val PUB_KEY = + "OMTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9" + + "eq+voxQ1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UD" + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt index 1d0e83df047be9ac627d9f6da5b08c377055dadb..7efbed5de4b31e4457ff92bac769a757a49b9eaa 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle import de.rki.coronawarnapp.eventregistration.checkins.CheckIn import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeUriParser +import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocationVerifier import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.ActiveCheckInVH @@ -41,6 +42,7 @@ class CheckInsViewModelTest : BaseTest() { @MockK lateinit var checkInsRepository: CheckInRepository @MockK lateinit var checkOutHandler: CheckOutHandler @MockK lateinit var cameraPermissionProvider: CameraPermissionProvider + @MockK lateinit var traceLocationVerifier: TraceLocationVerifier @BeforeEach fun setup() { @@ -48,6 +50,8 @@ class CheckInsViewModelTest : BaseTest() { every { savedState.set(any(), any<String>()) } just Runs every { checkInsRepository.checkInsWithinRetention } returns flowOf() every { cameraPermissionProvider.deniedPermanently } returns flowOf(false) + every { traceLocationVerifier.verifyTraceLocation(any()) } returns + TraceLocationVerifier.VerificationResult.Valid(mockk()) } @Test @@ -186,6 +190,7 @@ class CheckInsViewModelTest : BaseTest() { checkInsRepository = checkInsRepository, checkOutHandler = checkOutHandler, cameraPermissionProvider = cameraPermissionProvider, + traceLocationVerifier = traceLocationVerifier, cleanHistory = false )