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

Fix config default values not being used if protobuf is missing the data...

Fix config default values not being used if protobuf is missing the data structures (EXPOSUREAPP-3856) (#1649)

* Improve logging.

* Fix exposure detection config not using default values if protobuf structures are null.

* Fix key download config not using default values if protobuf structures are null.

Co-authored-by: default avatarRalf Gehrer <ralfgehrer@users.noreply.github.com>
parent a79cbe0b
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,7 @@ interface ExposureDetectionConfig { ...@@ -12,7 +12,7 @@ interface ExposureDetectionConfig {
val overallDetectionTimeout: Duration val overallDetectionTimeout: Duration
val exposureDetectionConfiguration: ExposureConfiguration val exposureDetectionConfiguration: ExposureConfiguration
val exposureDetectionParameters: ExposureDetectionParameters.ExposureDetectionParametersAndroid val exposureDetectionParameters: ExposureDetectionParameters.ExposureDetectionParametersAndroid?
interface Mapper : ConfigMapper<ExposureDetectionConfig> interface Mapper : ConfigMapper<ExposureDetectionConfig>
} }
...@@ -24,6 +24,8 @@ class AppConfigSource @Inject constructor( ...@@ -24,6 +24,8 @@ class AppConfigSource @Inject constructor(
if (localConfig != null && localConfig.isValid(timeStamper.nowUTC)) { if (localConfig != null && localConfig.isValid(timeStamper.nowUTC)) {
Timber.tag(TAG).d("Returning local config, still valid.") Timber.tag(TAG).d("Returning local config, still valid.")
return localConfig return localConfig
} else {
Timber.tag(TAG).d("Local app config was unavailable(${localConfig == null} or invalid.")
} }
val remoteConfig = remoteAppConfigSource.getConfigData() val remoteConfig = remoteAppConfigSource.getConfigData()
......
...@@ -12,7 +12,11 @@ import javax.inject.Inject ...@@ -12,7 +12,11 @@ import javax.inject.Inject
@Reusable @Reusable
class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionConfig.Mapper { class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionConfig.Mapper {
override fun map(rawConfig: AppConfig.ApplicationConfiguration): ExposureDetectionConfig { override fun map(rawConfig: AppConfig.ApplicationConfiguration): ExposureDetectionConfig {
val exposureParams = rawConfig.androidExposureDetectionParameters val exposureParams = if (rawConfig.hasAndroidExposureDetectionParameters()) {
rawConfig.androidExposureDetectionParameters
} else {
null
}
return ExposureDetectionConfigContainer( return ExposureDetectionConfigContainer(
exposureDetectionConfiguration = rawConfig.mapRiskScoreToExposureConfiguration(), exposureDetectionConfiguration = rawConfig.mapRiskScoreToExposureConfiguration(),
exposureDetectionParameters = exposureParams, exposureDetectionParameters = exposureParams,
...@@ -24,7 +28,7 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon ...@@ -24,7 +28,7 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon
data class ExposureDetectionConfigContainer( data class ExposureDetectionConfigContainer(
override val exposureDetectionConfiguration: ExposureConfiguration, override val exposureDetectionConfiguration: ExposureConfiguration,
override val exposureDetectionParameters: ExposureDetectionParametersAndroid, override val exposureDetectionParameters: ExposureDetectionParametersAndroid?,
override val maxExposureDetectionsPerUTCDay: Int, override val maxExposureDetectionsPerUTCDay: Int,
override val minTimeBetweenDetections: Duration, override val minTimeBetweenDetections: Duration,
override val overallDetectionTimeout: Duration override val overallDetectionTimeout: Duration
...@@ -33,23 +37,25 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon ...@@ -33,23 +37,25 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon
// If we are outside the valid data range, fallback to default value. // If we are outside the valid data range, fallback to default value.
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun ExposureDetectionParametersAndroid.overAllDetectionTimeout(): Duration = when { fun ExposureDetectionParametersAndroid?.overAllDetectionTimeout(): Duration =
overallTimeoutInSeconds > 3600 -> Duration.standardMinutes(15) if (this == null || overallTimeoutInSeconds > 3600 || overallTimeoutInSeconds <= 0) {
overallTimeoutInSeconds <= 0 -> Duration.standardMinutes(15) Duration.standardMinutes(15)
else -> Duration.standardSeconds(overallTimeoutInSeconds.toLong()) } else {
} Duration.standardSeconds(overallTimeoutInSeconds.toLong())
}
// If we are outside the valid data range, fallback to default value. // If we are outside the valid data range, fallback to default value.
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun ExposureDetectionParametersAndroid.maxExposureDetectionsPerDay(): Int = when { fun ExposureDetectionParametersAndroid?.maxExposureDetectionsPerDay(): Int =
maxExposureDetectionsPerInterval > 6 -> 6 if (this == null || maxExposureDetectionsPerInterval > 6 || maxExposureDetectionsPerInterval < 0) {
maxExposureDetectionsPerInterval < 0 -> 6 6
else -> maxExposureDetectionsPerInterval } else {
} maxExposureDetectionsPerInterval
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun ExposureDetectionParametersAndroid.minTimeBetweenExposureDetections(): Duration { fun ExposureDetectionParametersAndroid?.minTimeBetweenExposureDetections(): Duration {
val detectionsPerDay = maxExposureDetectionsPerDay() val detectionsPerDay = this.maxExposureDetectionsPerDay()
return if (detectionsPerDay == 0) { return if (detectionsPerDay == 0) {
Duration.standardDays(99) Duration.standardDays(99)
} else { } else {
......
...@@ -16,7 +16,11 @@ import javax.inject.Inject ...@@ -16,7 +16,11 @@ import javax.inject.Inject
@Reusable @Reusable
class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapper { class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapper {
override fun map(rawConfig: AppConfig.ApplicationConfiguration): KeyDownloadConfig { override fun map(rawConfig: AppConfig.ApplicationConfiguration): KeyDownloadConfig {
val rawParameters = rawConfig.androidKeyDownloadParameters val rawParameters = if (rawConfig.hasAndroidKeyDownloadParameters()) {
rawConfig.androidKeyDownloadParameters
} else {
null
}
return KeyDownloadConfigContainer( return KeyDownloadConfigContainer(
individualDownloadTimeout = rawParameters.individualTimeout(), individualDownloadTimeout = rawParameters.individualTimeout(),
...@@ -27,21 +31,25 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp ...@@ -27,21 +31,25 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp
} }
// If we are outside the valid data range, fallback to default value. // If we are outside the valid data range, fallback to default value.
private fun KeyDownloadParametersAndroid.individualTimeout(): Duration = when { private fun KeyDownloadParametersAndroid?.individualTimeout(): Duration =
downloadTimeoutInSeconds > 1800 -> Duration.standardSeconds(60) if (this == null || downloadTimeoutInSeconds > 1800 || downloadTimeoutInSeconds <= 0) {
downloadTimeoutInSeconds <= 0 -> Duration.standardSeconds(60) Duration.standardSeconds(60)
else -> Duration.standardSeconds(downloadTimeoutInSeconds.toLong()) } else {
} Duration.standardSeconds(downloadTimeoutInSeconds.toLong())
}
// If we are outside the valid data range, fallback to default value. // If we are outside the valid data range, fallback to default value.
private fun KeyDownloadParametersAndroid.overAllTimeout(): Duration = when { private fun KeyDownloadParametersAndroid?.overAllTimeout(): Duration =
overallTimeoutInSeconds > 1800 -> Duration.standardMinutes(8) if (this == null || overallTimeoutInSeconds > 1800 || overallTimeoutInSeconds <= 0) {
overallTimeoutInSeconds <= 0 -> Duration.standardMinutes(8) Duration.standardMinutes(8)
else -> Duration.standardSeconds(overallTimeoutInSeconds.toLong()) } else {
} Duration.standardSeconds(overallTimeoutInSeconds.toLong())
}
private fun KeyDownloadParametersAndroid.mapDayEtags(): List<RevokedKeyPackage.Day> = private fun KeyDownloadParametersAndroid?.mapDayEtags(): List<RevokedKeyPackage.Day> {
this.revokedDayPackagesList.mapNotNull { if (this == null) return emptyList()
return this.revokedDayPackagesList.mapNotNull {
try { try {
RevokedKeyPackage.Day( RevokedKeyPackage.Day(
etag = it.etag, etag = it.etag,
...@@ -53,9 +61,12 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp ...@@ -53,9 +61,12 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp
null null
} }
} }
}
private fun KeyDownloadParametersAndroid.mapHourEtags(): List<RevokedKeyPackage.Hour> = private fun KeyDownloadParametersAndroid?.mapHourEtags(): List<RevokedKeyPackage.Hour> {
this.revokedHourPackagesList.mapNotNull { if (this == null) return emptyList()
return this.revokedHourPackagesList.mapNotNull {
try { try {
RevokedKeyPackage.Hour( RevokedKeyPackage.Hour(
etag = it.etag, etag = it.etag,
...@@ -68,6 +79,7 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp ...@@ -68,6 +79,7 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp
null null
} }
} }
}
data class KeyDownloadConfigContainer( data class KeyDownloadConfigContainer(
override val individualDownloadTimeout: Duration, override val individualDownloadTimeout: Duration,
......
...@@ -132,9 +132,6 @@ class DefaultRiskLevels @Inject constructor() : RiskLevels { ...@@ -132,9 +132,6 @@ class DefaultRiskLevels @Inject constructor() : RiskLevels {
"Active tracing time ($activeTracingDurationInHours h) is above threshold " + "Active tracing time ($activeTracingDurationInHours h) is above threshold " +
"($durationTracingIsActiveThreshold h): $it" "($durationTracingIsActiveThreshold h): $it"
) )
if (it) {
Timber.tag(TAG).v("Active tracing time is not enough")
}
} }
} }
......
...@@ -4,6 +4,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode ...@@ -4,6 +4,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode
import de.rki.coronawarnapp.server.protocols.internal.AppConfig import de.rki.coronawarnapp.server.protocols.internal.AppConfig
import de.rki.coronawarnapp.server.protocols.internal.KeyDownloadParameters import de.rki.coronawarnapp.server.protocols.internal.KeyDownloadParameters
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import org.joda.time.Duration
import org.joda.time.LocalDate import org.joda.time.LocalDate
import org.joda.time.LocalTime import org.joda.time.LocalTime
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
...@@ -59,4 +60,17 @@ class DownloadConfigMapperTest : BaseTest() { ...@@ -59,4 +60,17 @@ class DownloadConfigMapperTest : BaseTest() {
} }
} }
} }
@Test
fun `if the protobuf data structures are null we return defaults`() {
val rawConfig = AppConfig.ApplicationConfiguration.newBuilder()
.build()
createInstance().map(rawConfig).apply {
revokedDayPackages shouldBe emptyList()
revokedHourPackages shouldBe emptyList()
overallDownloadTimeout shouldBe Duration.standardMinutes(8)
individualDownloadTimeout shouldBe Duration.standardSeconds(60)
}
}
} }
...@@ -17,8 +17,9 @@ class ExposureDetectionConfigMapperTest : BaseTest() { ...@@ -17,8 +17,9 @@ class ExposureDetectionConfigMapperTest : BaseTest() {
.setMinRiskScore(1) .setMinRiskScore(1)
.build() .build()
createInstance().map(rawConfig).apply { createInstance().map(rawConfig).apply {
// This is basically the old legacy config without the new hourly related data structures
exposureDetectionConfiguration shouldBe rawConfig.mapRiskScoreToExposureConfiguration() exposureDetectionConfiguration shouldBe rawConfig.mapRiskScoreToExposureConfiguration()
exposureDetectionParameters shouldBe rawConfig.androidExposureDetectionParameters exposureDetectionParameters shouldBe null
} }
} }
...@@ -77,4 +78,16 @@ class ExposureDetectionConfigMapperTest : BaseTest() { ...@@ -77,4 +78,16 @@ class ExposureDetectionConfigMapperTest : BaseTest() {
overallDetectionTimeout shouldBe Duration.standardMinutes(15) overallDetectionTimeout shouldBe Duration.standardMinutes(15)
} }
} }
@Test
fun `if protobuf is missing the datastructure we return defaults`() {
val rawConfig = AppConfig.ApplicationConfiguration.newBuilder()
.setMinRiskScore(1)
.build()
createInstance().map(rawConfig).apply {
overallDetectionTimeout shouldBe Duration.standardMinutes(15)
minTimeBetweenDetections shouldBe Duration.standardHours(24 / 6)
maxExposureDetectionsPerUTCDay shouldBe 6
}
}
} }
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