diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt index fe31b111213737dbfc4e4fa7645e8950bf0b28ef..9a85a5416babe7fab493a861ffb35bb737753397 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt @@ -46,7 +46,7 @@ open class InvalidHealthCertificateException( override fun toHumanReadableError(context: Context): HumanReadableError { return HumanReadableError( - description = errorMessage.get(context) + "/n/n$errorCode" + description = errorMessage.get(context) + " ($errorCode)" ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt index 360301b1c893587a41a7087834bce0335e694cb6..29cec2e55dc52617bfd9e1fc1f5459e800356fac 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt @@ -8,13 +8,12 @@ import de.rki.coronawarnapp.util.ui.LazyString class InvalidTestCertificateException(errorCode: ErrorCode) : InvalidHealthCertificateException(errorCode) { override fun toHumanReadableError(context: Context): HumanReadableError { return HumanReadableError( - description = errorMessage.get(context) + "\n\n$errorCode" + description = errorMessage.get(context) + " ($errorCode)" ) } override val errorMessage: LazyString get() = when (errorCode) { - ErrorCode.AES_DECRYPTION_FAILED, ErrorCode.RSA_DECRYPTION_FAILED, ErrorCode.HC_COSE_MESSAGE_INVALID, @@ -26,6 +25,13 @@ class InvalidTestCertificateException(errorCode: ErrorCode) : InvalidHealthCerti context.getString(ERROR_MESSAGE_TRY_AGAIN) } + ErrorCode.HC_BASE45_DECODING_FAILED, + ErrorCode.HC_BASE45_ENCODING_FAILED, + ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED, + ErrorCode.HC_ZLIB_COMPRESSION_FAILED -> CachedString { context -> + context.getString(ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE) + } + else -> super.errorMessage } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt index 0309cf245d76dacde5d04e28cd98d98cefa03ec6..4254cd9b3c11eeb6427b40c4e0d182cddcc7d9c2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt @@ -11,7 +11,7 @@ class InvalidVaccinationCertificateException(errorCode: ErrorCode) : InvalidHeal var errorCodeString = errorCode.toString() errorCodeString = if (errorCodeString.startsWith(PREFIX_VC)) errorCodeString else PREFIX_VC + errorCodeString return HumanReadableError( - description = errorMessage.get(context) + "\n\n$errorCodeString" + description = errorMessage.get(context) + " ($errorCodeString)" ) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccParser.kt index 78fe73ea1dbe98c0981582aa2640eb7b2017f3a8..d4456a57f06a6e551811a181f9cfb6c22c29bee7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccParser.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccParser.kt @@ -3,7 +3,6 @@ package de.rki.coronawarnapp.covidcertificate.test import com.google.gson.Gson import com.upokecenter.cbor.CBORObject import dagger.Reusable -import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_DGC import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_HCERT @@ -19,37 +18,45 @@ import javax.inject.Inject class TestCertificateDccParser @Inject constructor( @BaseGson private val gson: Gson, ) { - fun parse(map: CBORObject): TestCertificateDccV1 = try { - val certificate: TestCertificateDccV1 = map[keyHCert]?.run { + map[keyHCert]?.run { this[keyEuDgcV1]?.run { toCertificate() } ?: throw InvalidTestCertificateException(HC_CWT_NO_DGC) } ?: throw InvalidTestCertificateException(HC_CWT_NO_HCERT) - - certificate.validate() - } catch (e: InvalidHealthCertificateException) { + } catch (e: InvalidTestCertificateException) { throw e } catch (e: Throwable) { throw InvalidTestCertificateException(HC_CBOR_DECODING_FAILED) } + @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") private fun TestCertificateDccV1.validate(): TestCertificateDccV1 { if (testCertificateData.isNullOrEmpty()) { throw InvalidTestCertificateException(NO_TEST_ENTRY) } - // Force date parsing + // check for non null (Gson does not enforce it) & force date parsing + version!! + nameData.familyNameStandardized!! dateOfBirth testCertificateData.forEach { it.testResultAt it.sampleCollectedAt + it.certificateIssuer!! + it.countryOfTest!! + it.targetId!! + it.testCenter!! + it.testResult!! + it.testType!! } return this } private fun CBORObject.toCertificate() = try { val json = ToJSONString() - gson.fromJson<TestCertificateDccV1>(json) + gson.fromJson<TestCertificateDccV1>(json).validate() + } catch (e: InvalidTestCertificateException) { + throw e } catch (e: Throwable) { Timber.e(e) throw InvalidTestCertificateException(JSON_SCHEMA_INVALID) diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt index 0fa2e01caf16a8d470df2468c735bbb70b5894ab..8d8b76c47dfd4d0a818602db4013f74c5b7982d6 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt @@ -113,9 +113,16 @@ class TestCertificateQRCodeExtractorTest : BaseTest() { } @Test - fun `certificate missing fails with VC_NO_VACCINATION_ENTRY`() { + fun `vaccination certificate fails with NO_TEST_ENTRY`() { shouldThrow<InvalidTestCertificateException> { extractor.extract(VaccinationQrCodeTestData.certificateMissing) }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.NO_TEST_ENTRY } + + @Test + fun `null values fail with JSON_SCHEMA_INVALID`() { + shouldThrow<InvalidTestCertificateException> { + extractor.extract(TestData.qrCodeMssingValues) + }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java index 035f48b7fe2036720e96144612b0d65a776e2609..d1cab7986ed9589691167a7a27bdc82652826277 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java @@ -17,4 +17,6 @@ public class TestData { public static String qrCodeTestCertificate = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH+VEIOOP-IARC$E08WAN$6%W0AT4V22F/8X*G3M9BM9Z0BFU2P4JY73JC3KD34LT7A3523*BBXSJ$IJGX8R/S+:KLD3JJ3.+IJYCDN0TA3RK37MBZD3K%I17JLXKB6J57TJK57ALD-I3 28XGL4LQ/SLE50$499TVU1PK9PYLPN1VUU8C1VTE5ZM376 IE2IML07Z ESF6C.M1EE*2NY*6UJE4:6Q56FPEXM6IS6-Q64Y6N$E.%66PP33M19V2+PFQ51C5EWAC1A.GUQ$9WC54FQ68ENV0XTCM*4CZKHKB-43.E3KD3OAJA70:ZH/O1:O1AT1NQ1 WUQRENS431TN$IK.G47HB%0WT072HFHN/SNP.0FVV/SN7Y431TCRV$.PTW5CL52U50$EZ*N4IU4FKCPACPI2YUFJ6LX3+KG% BTVB3UQFJ6GL28LHXOAYJAUVPQRHIY1* HOQ1PRAAUICO1 IGBY05*H%XGU-PNQCSJ1A+3HJ5VBQR6G/:DS3GH9FW-SAOPNRFBYMBPJEODEN6%99SLNS9KKFC$OKT1GVKJTCW.IIX2S3V0$1D243B/J.H1RJVN01HI7T.H"; public static String cborObject = "a4041a60bc9f38061a60b9fc3801624154390103a101a4617481a962736374323032312d30322d32305431323a33343a35365a626d6164313233326274746a4c503231373139382d336274637754657374696e672063656e746572205669656e6e61203162636f624154626369783155524e3a555643493a30313a41543a37314545323535394445333843364246373330344642363541314134353145432333626973781b4d696e6973747279206f66204865616c74682c20417573747269616274676938343035333930303662747269323630343135303030636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e322e3163646f626a313939382d30322d3236"; + + public static String qrCodeMssingValues = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH0 MIOO6+IRKULA7GJLH1WU9T+QI6M8SA3/-2E%5TR5RVBFVAPUB1VCSWC%PDGZKBTC$JC6VCQVD. CL%2VTAQPIAK2K.C*/C/QDEZI8NBMZIVZJ4RLUTIT0KXRS*IJCSIYYKN63QR35VA2TBQMISVBYIJ33M+ZJ::A4O2OVPX0QON9Y46PK9$-0BZIKYJGCC:H3J1D1I3-*TW CXBDW33::SGKD2YC29DHSTY5TMGSR.CK.C2YC6YCBKDZJC9VC..DAVC55MVIJGDB0D48UJ06J9UBSVAXCIF4LEIIPBJ7OICWK%5BBS22T9PF5RBQ746B46O1N646BQ99Q9O$B ZJY1B QTOD3CQSP$SR$S3NDC9UOD3Y.TJET9G3DZI65BDM1F0J*XI-XIFRLL:F*ZR/MV$CT:Z2 /KU%CW.4WV2L4L$XKV7J$%25I3IC33835AL5:4A930JBB8G0 O4POY.6/IIYTE5NJJD2E9O%Q5G9WARD:QFMUU9K79LG-H9%K5.6MRXPDW5V$3/UR83LIBF2IVO7GXD9R$OB9MXUNTIDX 6-Z1YCN+VDKS0F5UV/H"; }