Skip to content
Snippets Groups Projects
Unverified Commit 6c3eec08 authored by chris-cwa's avatar chris-cwa Committed by GitHub
Browse files

Dcc Server (EXPOSUREAPP-7504) (#3347)


* Extend corona test data structures with digital covid certificate related properties.
+Some additional wiring, plumbing and tests for future PRs.

* LINTs

* Adjust TestRegistrationRequest to supply dcc consent and DOB on test registration.

* Remove explicit assignment, defaults are sufficient.

* A few additional unit tests to check defaults.

* DateOfBirthKey calculation, draft 1

* Fix date parser pattern.

* wip

* Adjust padding calculation to take the new dobHash into account.
Some refactoring to make it less complicated to adjust for future changes.

* klint, ofc.

* TestCertificate repo, draft1.

* DGC -> dcc

* TestCertificateRepository, draft 2

* TestCertificateRepository, draft 3

* TestCertificateRepository, draft 4

* Unit tests, draft 1.

* Add new app config parameters and implement delay mechanism.

* Unit tests, draft 2

* dcc server

* merge 2.4
add di module

* clean up

* fix exception

* add server environment

* fix test

Co-authored-by: default avatarMatthias Urhahn <matthias.urhahn@sap.com>
Co-authored-by: default avatarMohamed Metwalli <mohamed.metwalli@sap.com>
Co-authored-by: default avatarChilja Gossow <49635654+chiljamgossow@users.noreply.github.com>
parent ff3f543e
No related branches found
No related tags found
No related merge requests found
Showing
with 165 additions and 16 deletions
package de.rki.coronawarnapp.covidcertificate.server
import com.google.gson.annotations.SerializedName
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
interface CovidCertificateApiV1 {
data class PublicKeyUploadRequest(
@SerializedName("registrationToken") val registrationToken: String,
@SerializedName("publicKey") val publicKey: String
)
@POST("/version/v1/publicKey")
suspend fun sendPublicKey(
@Body requestBody: PublicKeyUploadRequest
)
data class ComponentsRequest(
@SerializedName("registrationToken") val registrationToken: String,
)
data class ComponentsResponse(
@SerializedName("dek") val dek: String,
@SerializedName("dcc") val dcc: String
)
@POST("/version/v1/publicKey")
suspend fun getComponents(
@Body requestBody: ComponentsRequest
): Response<ComponentsResponse>
}
package de.rki.coronawarnapp.covidcertificate.server
import dagger.Module
import dagger.Provides
import dagger.Reusable
import de.rki.coronawarnapp.environment.covidcertificate.DCCHttpClient
import de.rki.coronawarnapp.environment.covidcertificate.DCCServerUrl
import okhttp3.OkHttpClient
import retrofit2.Retrofit
@Module
class CovidCertificateModule {
@Reusable
@Provides
fun apiV1(
@DCCHttpClient httpClient: OkHttpClient,
@DCCServerUrl url: String,
): CovidCertificateApiV1 {
return Retrofit.Builder()
.client(httpClient)
.baseUrl(url)
.build()
.create(CovidCertificateApiV1::class.java)
}
}
package de.rki.coronawarnapp.covidcertificate.server package de.rki.coronawarnapp.covidcertificate.server
import dagger.Lazy
import dagger.Reusable import dagger.Reusable
import de.rki.coronawarnapp.coronatest.type.RegistrationToken import de.rki.coronawarnapp.coronatest.type.RegistrationToken
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.encryption.rsa.RSAKey import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@Reusable @Reusable
class CovidCertificateServer @Inject constructor() { class CovidCertificateServer @Inject constructor(
private val dccApi: Lazy<CovidCertificateApiV1>,
private val dispatcherProvider: DispatcherProvider
) {
private val api: CovidCertificateApiV1
get() = dccApi.get()
suspend fun registerPublicKeyForTest( suspend fun registerPublicKeyForTest(
testRegistrationToken: RegistrationToken, testRegistrationToken: RegistrationToken,
publicKey: RSAKey.Public, publicKey: RSAKey.Public,
) { ): Unit = withContext(dispatcherProvider.IO) {
Timber.tag(TAG).v("registerPublicKeyForTest(token=%s, key=%s)", testRegistrationToken, publicKey) Timber.tag(TAG).v("registerPublicKeyForTest(token=%s, key=%s)", testRegistrationToken, publicKey)
throw NotImplementedError() api.sendPublicKey(
requestBody = CovidCertificateApiV1.PublicKeyUploadRequest(
registrationToken = testRegistrationToken,
publicKey = publicKey.base64
)
)
} }
@Throws(DccException::class)
suspend fun requestCertificateForTest( suspend fun requestCertificateForTest(
testRegistrationToken: RegistrationToken, testRegistrationToken: RegistrationToken,
): TestCertificateComponents { ): TestCertificateComponents = withContext(dispatcherProvider.IO) {
Timber.tag(TAG).v("requestCertificateForTest(token=%s)", testRegistrationToken) Timber.tag(TAG).v("requestCertificateForTest(token=%s)", testRegistrationToken)
throw NotImplementedError() val response = api.getComponents(
requestBody = CovidCertificateApiV1.ComponentsRequest(testRegistrationToken)
)
// TODO replace with InvalidTestCertificateException + correct error codes
if (response.code() == 202) throw DccException()
val result = response.body() ?: throw DccException()
TestCertificateComponents(
dataEncryptionKeyBase64 = result.dek,
encryptedCoseTestCertificateBase64 = result.dcc
)
} }
companion object { companion object {
......
package de.rki.coronawarnapp.covidcertificate.server
class DccException : Exception()
...@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.environment ...@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.environment
import dagger.Module import dagger.Module
import de.rki.coronawarnapp.environment.bugreporting.BugReportingServerModule import de.rki.coronawarnapp.environment.bugreporting.BugReportingServerModule
import de.rki.coronawarnapp.environment.covidcertificate.DCCModule
import de.rki.coronawarnapp.environment.datadonation.DataDonationCDNModule import de.rki.coronawarnapp.environment.datadonation.DataDonationCDNModule
import de.rki.coronawarnapp.environment.download.DownloadCDNModule import de.rki.coronawarnapp.environment.download.DownloadCDNModule
import de.rki.coronawarnapp.environment.submission.SubmissionCDNModule import de.rki.coronawarnapp.environment.submission.SubmissionCDNModule
...@@ -13,7 +14,8 @@ import de.rki.coronawarnapp.environment.verification.VerificationCDNModule ...@@ -13,7 +14,8 @@ import de.rki.coronawarnapp.environment.verification.VerificationCDNModule
SubmissionCDNModule::class, SubmissionCDNModule::class,
VerificationCDNModule::class, VerificationCDNModule::class,
DataDonationCDNModule::class, DataDonationCDNModule::class,
BugReportingServerModule::class BugReportingServerModule::class,
DCCModule::class
] ]
) )
class EnvironmentModule class EnvironmentModule
...@@ -7,6 +7,7 @@ import com.google.gson.JsonObject ...@@ -7,6 +7,7 @@ import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY 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.DATA_DONATION
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DCC
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD
import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SAFETYNET_API_KEY import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SAFETYNET_API_KEY
...@@ -37,7 +38,8 @@ class EnvironmentSetup @Inject constructor( ...@@ -37,7 +38,8 @@ class EnvironmentSetup @Inject constructor(
DATA_DONATION("DATA_DONATION_CDN_URL"), DATA_DONATION("DATA_DONATION_CDN_URL"),
LOG_UPLOAD("LOG_UPLOAD_SERVER_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") CROWD_NOTIFIER_PUBLIC_KEY("CROWD_NOTIFIER_PUBLIC_KEY"),
DCC("DCC_SERVER_URL"),
} }
enum class Type(val rawKey: String) { enum class Type(val rawKey: String) {
...@@ -135,6 +137,9 @@ class EnvironmentSetup @Inject constructor( ...@@ -135,6 +137,9 @@ class EnvironmentSetup @Inject constructor(
val logUploadServerUrl: String val logUploadServerUrl: String
get() = getEnvironmentValue(LOG_UPLOAD).asString get() = getEnvironmentValue(LOG_UPLOAD).asString
val dccServerUrl: String
get() = getEnvironmentValue(DCC).asString
companion object { companion object {
private const val PKEY_CURRENT_ENVINROMENT = "environment.current" private const val PKEY_CURRENT_ENVINROMENT = "environment.current"
} }
......
package de.rki.coronawarnapp.environment.covidcertificate
import javax.inject.Qualifier
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class DCCHttpClient
package de.rki.coronawarnapp.environment.covidcertificate
import dagger.Module
import dagger.Provides
import dagger.Reusable
import de.rki.coronawarnapp.environment.BaseEnvironmentModule
import de.rki.coronawarnapp.environment.EnvironmentSetup
import de.rki.coronawarnapp.http.HttpClientDefault
import okhttp3.OkHttpClient
import javax.inject.Singleton
@Module
class DCCModule : BaseEnvironmentModule() {
@Reusable
@DCCHttpClient
@Provides
fun dccHttpClient(@HttpClientDefault defaultHttpClient: OkHttpClient): OkHttpClient =
defaultHttpClient.newBuilder().build()
@Singleton
@DCCServerUrl
@Provides
fun dccServerUrl(environment: EnvironmentSetup): String {
val url = environment.dccServerUrl
return requireValidUrl(url)
}
}
package de.rki.coronawarnapp.environment.covidcertificate
import javax.inject.Qualifier
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class DCCServerUrl
...@@ -14,6 +14,7 @@ import de.rki.coronawarnapp.bugreporting.BugReportingSharedModule ...@@ -14,6 +14,7 @@ import de.rki.coronawarnapp.bugreporting.BugReportingSharedModule
import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger
import de.rki.coronawarnapp.coronatest.CoronaTestModule import de.rki.coronawarnapp.coronatest.CoronaTestModule
import de.rki.coronawarnapp.coronatest.server.VerificationModule import de.rki.coronawarnapp.coronatest.server.VerificationModule
import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateModule
import de.rki.coronawarnapp.datadonation.DataDonationModule import de.rki.coronawarnapp.datadonation.DataDonationModule
import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule
...@@ -81,6 +82,7 @@ import javax.inject.Singleton ...@@ -81,6 +82,7 @@ import javax.inject.Singleton
PresenceTracingModule::class, PresenceTracingModule::class,
CoronaTestModule::class, CoronaTestModule::class,
VaccinationModule::class, VaccinationModule::class,
CovidCertificateModule::class,
] ]
) )
interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> { interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
......
...@@ -68,6 +68,7 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -68,6 +68,7 @@ class EnvironmentSetupTest : BaseTest() {
dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}" dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}"
logUploadServerUrl shouldBe "https://logupload-${env.rawKey}" logUploadServerUrl shouldBe "https://logupload-${env.rawKey}"
crowdNotifierPublicKey shouldBe "123_abc-${env.rawKey}" crowdNotifierPublicKey shouldBe "123_abc-${env.rawKey}"
dccServerUrl shouldBe "https://dcc-${env.rawKey}"
} }
} }
} }
...@@ -127,7 +128,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -127,7 +128,8 @@ class EnvironmentSetupTest : BaseTest() {
EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL" EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL"
EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY" EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY"
EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY.rawKey shouldBe "CROWD_NOTIFIER_PUBLIC_KEY" EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY.rawKey shouldBe "CROWD_NOTIFIER_PUBLIC_KEY"
EnvironmentSetup.EnvKey.values().size shouldBe 9 EnvironmentSetup.EnvKey.DCC.rawKey shouldBe "DCC_SERVER_URL"
EnvironmentSetup.EnvKey.values().size shouldBe 10
} }
companion object { companion object {
...@@ -152,7 +154,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -152,7 +154,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-PROD", "VACCINATION_CDN_URL": "https://vaccination-PROD",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-PROD",
"DCC_SERVER_URL": "https://dcc-PROD"
}, },
"DEV": { "DEV": {
"USE_EUR_KEY_PKGS" : false, "USE_EUR_KEY_PKGS" : false,
...@@ -164,7 +167,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -164,7 +167,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-DEV", "VACCINATION_CDN_URL": "https://vaccination-DEV",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-DEV",
"DCC_SERVER_URL": "https://dcc-DEV"
}, },
"INT": { "INT": {
"USE_EUR_KEY_PKGS" : false, "USE_EUR_KEY_PKGS" : false,
...@@ -176,7 +180,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -176,7 +180,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-INT", "VACCINATION_CDN_URL": "https://vaccination-INT",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-INT",
"DCC_SERVER_URL": "https://dcc-INT"
}, },
"WRU": { "WRU": {
"USE_EUR_KEY_PKGS" : false, "USE_EUR_KEY_PKGS" : false,
...@@ -189,7 +194,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -189,7 +194,8 @@ class EnvironmentSetupTest : BaseTest() {
"SAFETYNET_API_KEY": "placeholder-WRU", "SAFETYNET_API_KEY": "placeholder-WRU",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU",
"DCC_SERVER_URL": "https://dcc-WRU"
}, },
"WRU-XD": { "WRU-XD": {
"USE_EUR_KEY_PKGS" : true, "USE_EUR_KEY_PKGS" : true,
...@@ -201,7 +207,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -201,7 +207,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-WRU-XD", "VACCINATION_CDN_URL": "https://vaccination-WRU-XD",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XD",
"DCC_SERVER_URL": "https://dcc-WRU-XD"
}, },
"WRU-XA": { "WRU-XA": {
"USE_EUR_KEY_PKGS" : true, "USE_EUR_KEY_PKGS" : true,
...@@ -213,7 +220,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -213,7 +220,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-WRU-XA", "VACCINATION_CDN_URL": "https://vaccination-WRU-XA",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XA",
"DCC_SERVER_URL": "https://dcc-WRU-XA"
}, },
"TESTER-MOCK": { "TESTER-MOCK": {
"USE_EUR_KEY_PKGS" : true, "USE_EUR_KEY_PKGS" : true,
...@@ -225,7 +233,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -225,7 +233,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-TESTER-MOCK", "VACCINATION_CDN_URL": "https://vaccination-TESTER-MOCK",
"SAFETYNET_API_KEY": "placeholder-TESTER-MOCK", "SAFETYNET_API_KEY": "placeholder-TESTER-MOCK",
"PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-TESTER-MOCK", "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-TESTER-MOCK",
"CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-TESTER-MOCK" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-TESTER-MOCK",
"DCC_SERVER_URL": "https://dcc-TESTER-MOCK"
}, },
"LOCAL": { "LOCAL": {
"USE_EUR_KEY_PKGS" : true, "USE_EUR_KEY_PKGS" : true,
...@@ -237,7 +246,8 @@ class EnvironmentSetupTest : BaseTest() { ...@@ -237,7 +246,8 @@ class EnvironmentSetupTest : BaseTest() {
"VACCINATION_CDN_URL": "https://vaccination-LOCAL", "VACCINATION_CDN_URL": "https://vaccination-LOCAL",
"SAFETYNET_API_KEY": "placeholder-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" "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-LOCAL",
"DCC_SERVER_URL": "https://dcc-LOCAL"
} }
} }
""" """
......
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