diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt index 6edc4ce1bfc13a6d94b5924234ad29e1a46a0e0c..8df09af8ffafd6d9552386dc904678db695ca0f8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt @@ -19,4 +19,8 @@ object SubmissionConstants { val REGISTRATION_TOKEN_URL = "$VERSIONED_VERIFICATION_CDN_URL/$REGISTRATION_TOKEN" val TEST_RESULT_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TEST_RESULT" val TAN_REQUEST_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TAN" + + const val MAX_QR_CODE_LENGTH = 150 + const val MAX_GUID_LENGTH = 80 + const val GUID_SEPARATOR = '?' } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt index d8f6e09debf07b86cbd8394b677744797ae8ab38..a521fd889a30a356a5b905d3a111868d73d3d201 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt @@ -70,17 +70,20 @@ object SubmissionService { ) } - /** - * extracts the GUID from [scanResult]. Returns null if it does not match the required pattern - */ - fun extractGUID(scanResult: String): String? { - val potentialGUID = scanResult.substringAfterLast("?", "") - return if (potentialGUID.isEmpty()) - null - else - potentialGUID + fun containsValidGUID(scanResult: String): Boolean { + if (scanResult.length > SubmissionConstants.MAX_QR_CODE_LENGTH || + scanResult.count { it == SubmissionConstants.GUID_SEPARATOR } != 1 + ) + return false + + val potentialGUID = extractGUID(scanResult) + + return !(potentialGUID.isEmpty() || potentialGUID.length > SubmissionConstants.MAX_GUID_LENGTH) } + fun extractGUID(scanResult: String): String = + scanResult.substringAfterLast(SubmissionConstants.GUID_SEPARATOR, "") + fun storeTestGUID(guid: String) = LocalData.testGUID(guid) fun deleteTestGUID() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt index 22b63d2d9bb3d827f9d70225c4d0677354dbb239..c18d49a015360e7b4747526b6a323afe69dd88cc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt @@ -10,21 +10,13 @@ class SubmissionTanViewModel : ViewModel() { companion object { private val TAG: String? = SubmissionTanViewModel::class.simpleName - - private const val TAN_LENGTH = 7 - private val EXCLUDED_TAN_CHARS = listOf('0', 'O', 'I', '1') - private val VALID_TAN_CHARS = - ('a'..'z') - .plus('A'..'Z') - .plus('0'..'9') - .minus(EXCLUDED_TAN_CHARS) } val tan = MutableLiveData<String?>(null) val isValidTanFormat = Transformations.map(tan) { - it != null && it.length == TAN_LENGTH && it.all { c -> VALID_TAN_CHARS.contains(c) } + it != null && it.length == TanConstants.MAX_LENGTH } fun storeTeletan() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt new file mode 100644 index 0000000000000000000000000000000000000000..b6be13be81def6ec21f396f0b89f278cdeb9fd6a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.ui.submission + +object TanConstants { + const val MAX_LENGTH = 7 + val ALPHA_NUMERIC_CHARS = ('a'..'z').plus('A'..'Z').plus('0'..'9') +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt index d1a251846533df73987b224954ebc59757d4869c..70cc48b6833364f5303cc7d9d7549f2962e58e7f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.ui.submission import android.content.Context import android.os.Handler +import android.text.InputFilter import android.util.AttributeSet import android.view.inputmethod.InputMethodManager import android.widget.FrameLayout @@ -22,6 +23,15 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att private const val KEYBOARD_TRIGGER_DELAY = 100L } + private val whitespaceFilter = + InputFilter { source, _, _, _, _, _ -> source.filter { !it.isWhitespace() } } + private val alphaNumericFilter = InputFilter { source, _, _, _, _, _ -> + source.filter { + TanConstants.ALPHA_NUMERIC_CHARS.contains(it) + } + } + private val lengthFilter = InputFilter.LengthFilter(TanConstants.MAX_LENGTH) + var listener: ((String?) -> Unit)? = null private var tan: String? = null @@ -29,6 +39,8 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att init { inflate(context, R.layout.view_tan_input, this) + tan_input_edittext.filters = arrayOf(whitespaceFilter, alphaNumericFilter, lengthFilter) + // register listener tan_input_edittext.doOnTextChanged { text, _, _, _ -> updateTan(text) } setOnClickListener { showKeyboard() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt index e11b0c577f2ced767c9ea732ac430550e8225f6e..de2bb9f5066be22b2fe90cd43af268fde93c8df7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt @@ -43,8 +43,8 @@ class SubmissionViewModel : ViewModel() { executeRequestWithState(SubmissionRepository::refreshUIState, _uiStateState) fun validateAndStoreTestGUID(scanResult: String) { - val guid = SubmissionService.extractGUID(scanResult) - if (guid != null) { + if (SubmissionService.containsValidGUID(scanResult)) { + val guid = SubmissionService.extractGUID(scanResult) SubmissionService.storeTestGUID(guid) _scanStatus.value = ScanStatus.SUCCESS } else { diff --git a/Corona-Warn-App/src/main/res/values/integers.xml b/Corona-Warn-App/src/main/res/values/integers.xml deleted file mode 100644 index 92946c0300b8e1b29406a31cb354488e3ee17a5a..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/values/integers.xml +++ /dev/null @@ -1,3 +0,0 @@ -<resources> - <integer name="submission_tan_length">7</integer> -</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 0c76b91ea02df883d2a761e17c29a407d4701258..a432847122a6688184292273818607f3a2764f71 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -575,7 +575,7 @@ <!-- XHED: Page title for TAN submission pge --> <string name="submission_tan_title">TAN Eingabe</string> <!-- YTXT: Body text for the tan submission page --> - <string name="submission_tan_body">Die TAN ist 7-stellig und Groß- und Kleinschreibung muss nicht beachtet werden.</string> + <string name="submission_tan_body">Die TAN ist 7-stellig und Groß- und Kleinschreibung muss beachtet werden.\n\nGeben Sie bitte die Ihnen mitgeteilte TAN ein:</string> <!-- XBUT: Submit TAN button --> <string name="submission_tan_button_text">Weiter</string> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index d520458a6634dfe737b3583cb0f49c77ddb55902..285842c941ed470778d627f6579b51f3755c3ced 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -238,7 +238,6 @@ <item name="android:alpha">0</item> <item name="android:background">@null</item> <item name="android:inputType">textPassword</item> - <item name="android:maxLength">@integer/submission_tan_length</item> <item name="android:singleLine">true</item> </style> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt index ed2a111ce2ac1afc9406a23de54c672464b10a62..2d2b758bba3dcca74c0cdc311bd1bfd6b27c0a5b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt @@ -1,25 +1,33 @@ package de.rki.coronawarnapp.service.submission import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.nullValue import org.hamcrest.MatcherAssert.assertThat import org.junit.Test class SubmissionServiceTest { @Test - fun extractGUID() { + fun containsValidGUID() { // valid val guid = "123456-12345678-1234-4DA7-B166-B86D85475064" assertThat( - SubmissionService.extractGUID("https://bs-sd.de/covid-19/?$guid"), - equalTo(guid) + SubmissionService.containsValidGUID("https://bs-sd.de/covid-19/?$guid"), + equalTo(true) ) // invalid assertThat( - SubmissionService.extractGUID("https://no-guid-here"), - nullValue() + SubmissionService.containsValidGUID("https://no-guid-here"), + equalTo(false) + ) + } + + @Test + fun extractGUID() { + val guid = "123456-12345678-1234-4DA7-B166-B86D85475064" + assertThat( + SubmissionService.extractGUID("https://bs-sd.de/covid-19/?$guid"), + equalTo(guid) ) } }