Skip to content
Snippets Groups Projects
Unverified Commit 84f66c81 authored by Matthias Urhahn's avatar Matthias Urhahn Committed by GitHub
Browse files

Remove GSON footguns. (#2921)


GSON uses unsafeinit and will initialize a data class without any "val some = thing" being initialized that are in the class body.

Co-authored-by: default avatarAlex Paulescu <alex.paulescu@gmail.com>
parent f09dde61
No related branches found
No related tags found
No related merge requests found
Showing
with 70 additions and 56 deletions
...@@ -47,14 +47,16 @@ class CoronaTestStorage @Inject constructor( ...@@ -47,14 +47,16 @@ class CoronaTestStorage @Inject constructor(
gson.fromJson<Set<PCRCoronaTest>>(raw, typeTokenPCR).onEach { gson.fromJson<Set<PCRCoronaTest>>(raw, typeTokenPCR).onEach {
Timber.tag(TAG).v("PCR loaded: %s", it) Timber.tag(TAG).v("PCR loaded: %s", it)
requireNotNull(it.identifier) requireNotNull(it.identifier)
requireNotNull(it.type) { "PCR type should not be null, GSON footgun." }
} }
} }
val raTests: Set<RACoronaTest> = run { val raTests: Set<RACoronaTest> = run {
val raw = prefs.getString(PKEY_DATA_RA, null) ?: return@run emptySet() val raw = prefs.getString(PKEY_DATA_RA, null) ?: return@run emptySet()
gson.fromJson<Set<RACoronaTest>>(raw, typeTokenRA).onEach { gson.fromJson<Set<RACoronaTest>>(raw, typeTokenRA).onEach {
Timber.tag(TAG).v("PCR loaded: %s", it) Timber.tag(TAG).v("RA loaded: %s", it)
requireNotNull(it.identifier) requireNotNull(it.identifier)
requireNotNull(it.type) { "RA type should not be null, GSON footgun." }
} }
} }
......
...@@ -42,27 +42,27 @@ data class PCRCoronaTest( ...@@ -42,27 +42,27 @@ data class PCRCoronaTest(
@Transient override val lastError: Throwable? = null, @Transient override val lastError: Throwable? = null,
) : CoronaTest { ) : CoronaTest {
@Transient override val type: CoronaTest.Type
override val type: CoronaTest.Type = CoronaTest.Type.PCR get() = CoronaTest.Type.PCR
@Transient override val isPositive: Boolean
override val isPositive: Boolean = testResult == CoronaTestResult.PCR_POSITIVE get() = testResult == CoronaTestResult.PCR_POSITIVE
@Transient override val isPending: Boolean
override val isPending: Boolean = testResult == CoronaTestResult.PCR_OR_RAT_PENDING get() = testResult == CoronaTestResult.PCR_OR_RAT_PENDING
@Transient override val isSubmissionAllowed: Boolean
override val isSubmissionAllowed: Boolean = isPositive && !isSubmitted get() = isPositive && !isSubmitted
@Transient val state: State
val state: State = when (testResult) { get() = when (testResult) {
CoronaTestResult.PCR_OR_RAT_PENDING -> State.PENDING CoronaTestResult.PCR_OR_RAT_PENDING -> State.PENDING
CoronaTestResult.PCR_NEGATIVE -> State.NEGATIVE CoronaTestResult.PCR_NEGATIVE -> State.NEGATIVE
CoronaTestResult.PCR_POSITIVE -> State.POSITIVE CoronaTestResult.PCR_POSITIVE -> State.POSITIVE
CoronaTestResult.PCR_INVALID -> State.INVALID CoronaTestResult.PCR_INVALID -> State.INVALID
CoronaTestResult.PCR_REDEEMED -> State.REDEEMED CoronaTestResult.PCR_REDEEMED -> State.REDEEMED
else -> throw IllegalArgumentException("Invalid PCR test state $testResult") else -> throw IllegalArgumentException("Invalid PCR test state $testResult")
} }
enum class State { enum class State {
PENDING, PENDING,
......
...@@ -2,6 +2,12 @@ package de.rki.coronawarnapp.coronatest.type.rapidantigen ...@@ -2,6 +2,12 @@ package de.rki.coronawarnapp.coronatest.type.rapidantigen
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.PCR_OR_RAT_PENDING
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.RAT_INVALID
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.RAT_NEGATIVE
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.RAT_PENDING
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.RAT_POSITIVE
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.RAT_REDEEMED
import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.coronatest.type.CoronaTest
import de.rki.coronawarnapp.coronatest.type.RegistrationToken import de.rki.coronawarnapp.coronatest.type.RegistrationToken
import de.rki.coronawarnapp.coronatest.type.TestIdentifier import de.rki.coronawarnapp.coronatest.type.TestIdentifier
...@@ -55,27 +61,26 @@ data class RACoronaTest( ...@@ -55,27 +61,26 @@ data class RACoronaTest(
@Transient override val lastError: Throwable? = null, @Transient override val lastError: Throwable? = null,
) : CoronaTest { ) : CoronaTest {
@Transient override val type: CoronaTest.Type
override val type: CoronaTest.Type = CoronaTest.Type.RAPID_ANTIGEN get() = CoronaTest.Type.RAPID_ANTIGEN
fun getState(nowUTC: Instant) = when (testResult) { fun getState(nowUTC: Instant) = when (testResult) {
CoronaTestResult.PCR_OR_RAT_PENDING -> State.PENDING PCR_OR_RAT_PENDING -> State.PENDING
CoronaTestResult.RAT_NEGATIVE -> State.NEGATIVE RAT_NEGATIVE -> State.NEGATIVE
CoronaTestResult.RAT_POSITIVE -> State.POSITIVE RAT_POSITIVE -> State.POSITIVE
CoronaTestResult.RAT_INVALID -> State.INVALID RAT_INVALID -> State.INVALID
CoronaTestResult.RAT_REDEEMED -> State.REDEEMED RAT_REDEEMED -> State.REDEEMED
else -> throw IllegalArgumentException("Invalid RAT test state $testResult") else -> throw IllegalArgumentException("Invalid RAT test state $testResult")
} }
@Transient override val isPositive: Boolean
override val isPositive: Boolean = testResult == CoronaTestResult.RAT_POSITIVE get() = testResult == RAT_POSITIVE
@Transient override val isPending: Boolean
override val isPending: Boolean = get() = setOf(PCR_OR_RAT_PENDING, RAT_PENDING).contains(testResult)
testResult == CoronaTestResult.PCR_OR_RAT_PENDING || testResult == CoronaTestResult.RAT_PENDING
@Transient override val isSubmissionAllowed: Boolean
override val isSubmissionAllowed: Boolean = isPositive && !isSubmitted get() = isPositive && !isSubmitted
enum class State { enum class State {
PENDING, PENDING,
......
...@@ -14,11 +14,11 @@ data class OneTimePassword( ...@@ -14,11 +14,11 @@ data class OneTimePassword(
val time: Instant = Instant.now() val time: Instant = Instant.now()
) { ) {
@Transient val edusOneTimePassword: EdusOtp.EDUSOneTimePassword
val edusOneTimePassword: EdusOtp.EDUSOneTimePassword = EdusOtp.EDUSOneTimePassword.newBuilder() get() = EdusOtp.EDUSOneTimePassword.newBuilder()
.setOtp(uuid.toString()) .setOtp(uuid.toString())
.build() .build()
@Transient val payloadForRequest: ByteArray
val payloadForRequest: ByteArray = edusOneTimePassword.toByteArray() get() = edusOneTimePassword.toByteArray()
} }
...@@ -5,6 +5,6 @@ import java.util.Locale ...@@ -5,6 +5,6 @@ import java.util.Locale
data class LocationCode( data class LocationCode(
private val rawIdentifier: String private val rawIdentifier: String
) { ) {
@Transient val identifier: String
val identifier: String = rawIdentifier.toUpperCase(Locale.ROOT) get() = rawIdentifier.toUpperCase(Locale.ROOT)
} }
...@@ -41,8 +41,8 @@ data class CachedKeyInfo( ...@@ -41,8 +41,8 @@ data class CachedKeyInfo(
isDownloadComplete = false isDownloadComplete = false
) )
@Transient val fileName: String
val fileName: String = "$id.zip" get() = "$id.zip"
fun toDownloadUpdate(etag: String): DownloadUpdate = DownloadUpdate( fun toDownloadUpdate(etag: String): DownloadUpdate = DownloadUpdate(
id = id, id = id,
......
...@@ -31,8 +31,8 @@ data class TraceWarningPackageMetadata( ...@@ -31,8 +31,8 @@ data class TraceWarningPackageMetadata(
createdAt = createdAt, createdAt = createdAt,
) )
@Transient val fileName: String
val fileName: String = "$packageId.bin" get() = "$packageId.bin"
companion object { companion object {
fun calcluateId( fun calcluateId(
......
...@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.coronatest.storage ...@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.coronatest.storage
import android.content.Context import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import de.rki.coronawarnapp.coronatest.server.CoronaTestResult import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
import de.rki.coronawarnapp.coronatest.type.CoronaTest
import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
import de.rki.coronawarnapp.util.serialization.SerializationModule import de.rki.coronawarnapp.util.serialization.SerializationModule
...@@ -114,10 +115,13 @@ class CoronaTestStorageTest : BaseTest() { ...@@ -114,10 +115,13 @@ class CoronaTestStorageTest : BaseTest() {
] ]
""".toComparableJsonPretty() """.toComparableJsonPretty()
instance.coronaTests.single() shouldBe pcrTest.copy( instance.coronaTests.single().apply {
lastError = null, this shouldBe pcrTest.copy(
isProcessing = false lastError = null,
) isProcessing = false
)
type shouldBe CoronaTest.Type.PCR
}
} }
@Test @Test
...@@ -153,10 +157,13 @@ class CoronaTestStorageTest : BaseTest() { ...@@ -153,10 +157,13 @@ class CoronaTestStorageTest : BaseTest() {
] ]
""".toComparableJsonPretty() """.toComparableJsonPretty()
instance.coronaTests.single() shouldBe raTest.copy( instance.coronaTests.single().apply {
lastError = null, this shouldBe raTest.copy(
isProcessing = false lastError = null,
) isProcessing = false
)
type shouldBe CoronaTest.Type.RAPID_ANTIGEN
}
} }
@Test @Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment