Skip to content
Snippets Groups Projects
Unverified Commit dd3341db authored by Lukas Lechner's avatar Lukas Lechner Committed by GitHub
Browse files

Add Crowd Notifier Public Key for different environments (EXPOSUREAPP-6118) (#2729)


* Add CrowdNotifier Public Key to Environment

* Store cnPublicKey for created trace locations

* Remove cryptographic seed logic from trace location mapper

Co-authored-by: default avatarMohamed <mohamed.metwalli@sap.com>
parent 6fa2c266
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,7 @@ import androidx.core.content.edit
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DATA_DONATION
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD
......@@ -36,7 +37,8 @@ class EnvironmentSetup @Inject constructor(
DATA_DONATION("DATA_DONATION_CDN_URL"),
QRCODE_POSTER_TEMPLATE("QRCODE_POSTER_TEMPLATE_URL"),
LOG_UPLOAD("LOG_UPLOAD_SERVER_URL"),
SAFETYNET_API_KEY("SAFETYNET_API_KEY")
SAFETYNET_API_KEY("SAFETYNET_API_KEY"),
CROWD_NOTIFIER_PUBLIC_KEY("CROWD_NOTIFIER_PUBLIC_KEY")
}
enum class Type(val rawKey: String) {
......@@ -128,6 +130,9 @@ class EnvironmentSetup @Inject constructor(
val safetyNetApiKey: String
get() = getEnvironmentValue(SAFETYNET_API_KEY).asString
val crowdNotifierPublicKey: String
get() = getEnvironmentValue(CROWD_NOTIFIER_PUBLIC_KEY).asString
val logUploadServerUrl: String
get() = getEnvironmentValue(LOG_UPLOAD).asString
......
package de.rki.coronawarnapp.eventregistration.checkins.qrcode
import android.os.Parcelable
import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
import de.rki.coronawarnapp.eventregistration.storage.entity.TraceLocationEntity
import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
import kotlinx.parcelize.Parcelize
import okio.ByteString
import okio.ByteString.Companion.decodeBase64
import okio.ByteString.Companion.toByteString
import org.joda.time.Instant
import java.security.SecureRandom
const val TRACE_LOCATION_VERSION = 1
......@@ -23,7 +20,7 @@ data class TraceLocation(
val endDate: Instant?,
val defaultCheckInLengthInMinutes: Int?,
val cryptographicSeed: ByteString,
val cnPublicKey: String = "hardcoded public key TODO: replace with real one",
val cnPublicKey: String,
val version: Int = TRACE_LOCATION_VERSION,
) : Parcelable {
......@@ -46,14 +43,3 @@ fun TraceLocationEntity.toTraceLocation() = TraceLocation(
cnPublicKey = cnPublicKey,
version = version
)
fun TraceLocationUserInput.toTraceLocation(secureRandom: SecureRandom) = TraceLocation(
type = type,
description = description,
address = address,
startDate = startDate,
endDate = endDate,
defaultCheckInLengthInMinutes = defaultCheckInLengthInMinutes,
// cryptographic seed is a sequence of 16 random bytes
cryptographicSeed = ByteArray(16).apply { secureRandom.nextBytes(this) }.toByteString()
)
package de.rki.coronawarnapp.eventregistration.events
import de.rki.coronawarnapp.environment.EnvironmentSetup
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.toTraceLocation
import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
import okio.ByteString
import okio.ByteString.Companion.toByteString
import java.security.SecureRandom
import javax.inject.Inject
import javax.inject.Singleton
......@@ -10,10 +12,28 @@ import javax.inject.Singleton
@Singleton
class TraceLocationCreator @Inject constructor(
private val repository: TraceLocationRepository,
private val secureRandom: SecureRandom
private val secureRandom: SecureRandom,
private val environmentSetup: EnvironmentSetup
) {
suspend fun createTraceLocation(traceLocationUserInput: TraceLocationUserInput): TraceLocation {
return repository.addTraceLocation(traceLocationUserInput.toTraceLocation(secureRandom))
val cnPublicKey = environmentSetup.crowdNotifierPublicKey
// cryptographic seed is a sequence of 16 random bytes
val cryptographicSeed = ByteArray(16).apply { secureRandom.nextBytes(this) }.toByteString()
val traceLocation = traceLocationUserInput.toTraceLocation(cryptographicSeed, cnPublicKey)
return repository.addTraceLocation(traceLocation)
}
}
fun TraceLocationUserInput.toTraceLocation(cryptographicSeed: ByteString, cnPublicKey: String) = TraceLocation(
type = type,
description = description,
address = address,
startDate = startDate,
endDate = endDate,
defaultCheckInLengthInMinutes = defaultCheckInLengthInMinutes,
cryptographicSeed = cryptographicSeed,
cnPublicKey = cnPublicKey
)
......@@ -68,6 +68,7 @@ class EnvironmentSetupTest : BaseTest() {
dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}"
logUploadServerUrl shouldBe "https://logupload-${env.rawKey}"
qrCodePosterTemplateCdnUrl shouldBe "https://qrcodepostertemplate-${env.rawKey}"
crowdNotifierPublicKey shouldBe "123_abc-${env.rawKey}"
}
}
}
......@@ -126,7 +127,8 @@ class EnvironmentSetupTest : BaseTest() {
EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL"
EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY"
EnvironmentSetup.EnvKey.QRCODE_POSTER_TEMPLATE.rawKey shouldBe "QRCODE_POSTER_TEMPLATE_URL"
EnvironmentSetup.EnvKey.values().size shouldBe 9
EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY.rawKey shouldBe "CROWD_NOTIFIER_PUBLIC_KEY"
EnvironmentSetup.EnvKey.values().size shouldBe 10
}
companion object {
......@@ -149,7 +151,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-PROD",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-PROD",
"SAFETYNET_API_KEY": "placeholder-PROD",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-PROD"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-PROD",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-PROD"
},
"DEV": {
"USE_EUR_KEY_PKGS" : false,
......@@ -160,7 +163,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-DEV",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-DEV",
"SAFETYNET_API_KEY": "placeholder-DEV",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-DEV"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-DEV",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-DEV"
},
"INT": {
"USE_EUR_KEY_PKGS" : false,
......@@ -171,7 +175,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-INT",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-INT",
"SAFETYNET_API_KEY": "placeholder-INT",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-INT"
},
"WRU": {
"USE_EUR_KEY_PKGS" : false,
......@@ -183,7 +188,8 @@ class EnvironmentSetupTest : BaseTest() {
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-WRU",
"SAFETYNET_API_KEY": "placeholder-WRU",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU",
"CREATE_TRACELOCATION_URL": "https://tracelocation-WRU"
"CREATE_TRACELOCATION_URL": "https://tracelocation-WRU",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU"
},
"WRU-XD": {
"USE_EUR_KEY_PKGS" : true,
......@@ -194,7 +200,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-WRU-XD",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-WRU-XD",
"SAFETYNET_API_KEY": "placeholder-WRU-XD",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XD"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XD",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XD"
},
"WRU-XA": {
"USE_EUR_KEY_PKGS" : true,
......@@ -205,7 +212,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-WRU-XA",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-WRU-XA",
"SAFETYNET_API_KEY": "placeholder-WRU-XA",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XA"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XA",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XA"
},
"LOCAL": {
"USE_EUR_KEY_PKGS" : true,
......@@ -216,7 +224,8 @@ class EnvironmentSetupTest : BaseTest() {
"LOG_UPLOAD_SERVER_URL": "https://logupload-LOCAL",
"QRCODE_POSTER_TEMPLATE_URL": "https://qrcodepostertemplate-LOCAL",
"SAFETYNET_API_KEY": "placeholder-LOCAL",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-LOCAL"
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-LOCAL",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-LOCAL"
}
}
"""
......
package de.rki.coronawarnapp.eventregistration.checkins.qrcode
import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
import de.rki.coronawarnapp.eventregistration.events.toTraceLocation
import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import okio.ByteString.Companion.decodeHex
import okio.ByteString.Companion.toByteString
import okio.ByteString.Companion.encode
import org.joda.time.Instant
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.security.SecureRandom
import kotlin.random.Random
internal class TraceLocationUserInputToTraceLocationMapperTest {
@MockK private lateinit var secureRandom: SecureRandom
@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
......@@ -25,12 +19,6 @@ internal class TraceLocationUserInputToTraceLocationMapperTest {
@Test
fun toTraceLocation() {
every { secureRandom.nextBytes(any()) } answers {
val byteArray = arg<ByteArray>(0)
Random(0).nextBytes(byteArray)
}
TraceLocationUserInput(
type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT,
description = "Top Secret Private Event",
......@@ -38,7 +26,7 @@ internal class TraceLocationUserInputToTraceLocationMapperTest {
startDate = Instant.parse("2020-01-01T14:00:00.000Z"),
endDate = Instant.parse("2020-01-01T18:00:00.000Z"),
defaultCheckInLengthInMinutes = 180
).toTraceLocation(secureRandom) shouldBe TraceLocation(
).toTraceLocation("cryptographicSeed".encode(), "cnPublicKey123") shouldBe TraceLocation(
id = 0,
type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT,
description = "Top Secret Private Event",
......@@ -46,8 +34,8 @@ internal class TraceLocationUserInputToTraceLocationMapperTest {
startDate = Instant.parse("2020-01-01T14:00:00.000Z"),
endDate = Instant.parse("2020-01-01T18:00:00.000Z"),
defaultCheckInLengthInMinutes = 180,
cryptographicSeed = "2cc2b48c50aefe53b3974ed91e6b4ea9".decodeHex().toByteArray().toByteString(),
cnPublicKey = "hardcoded public key TODO: replace with real one"
cryptographicSeed = "cryptographicSeed".encode(),
cnPublicKey = "cnPublicKey123"
)
}
}
package de.rki.coronawarnapp.eventregistration.events
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.toTraceLocation
import de.rki.coronawarnapp.environment.EnvironmentSetup
import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.RelaxedMockK
import kotlinx.coroutines.test.runBlockingTest
import okio.ByteString.Companion.decodeHex
import okio.ByteString.Companion.toByteString
import org.joda.time.Instant
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
import java.security.SecureRandom
import kotlin.random.Random
internal class TraceLocationCreatorTest : BaseTest() {
@MockK lateinit var repository: TraceLocationRepository
@RelaxedMockK lateinit var secureRandom: SecureRandom
@MockK private lateinit var environmentSetup: EnvironmentSetup
@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
every { environmentSetup.crowdNotifierPublicKey } returns "cnPublicKey123"
every { secureRandom.nextBytes(any()) } answers {
val byteArray = arg<ByteArray>(0)
Random(0).nextBytes(byteArray)
}
}
private fun createInstance() = TraceLocationCreator(repository, secureRandom)
private fun createInstance() = TraceLocationCreator(repository, secureRandom, environmentSetup)
@Test
fun `createTraceLocation() should return traceLocation and store it in repository when everything works fine`() =
......@@ -41,7 +52,10 @@ internal class TraceLocationCreatorTest : BaseTest() {
defaultCheckInLengthInMinutes = 180
)
val expectedTraceLocation = userInput.toTraceLocation(secureRandom)
val expectedTraceLocation = userInput.toTraceLocation(
cryptographicSeed = "2cc2b48c50aefe53b3974ed91e6b4ea9".decodeHex().toByteArray().toByteString(),
cnPublicKey = "cnPublicKey123"
)
coEvery { repository.addTraceLocation(any()) } returns expectedTraceLocation
......
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