Skip to content

Commit 45e8342

Browse files
Implemented dynamic URLs fetching for the Verifier App (eu-digital-green-certificates#50)
1 parent 07b8e9d commit 45e8342

File tree

10 files changed

+116
-38
lines changed

10 files changed

+116
-38
lines changed

app/src/main/java/dgca/verifier/app/android/data/Config.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,39 @@ import com.google.gson.annotations.SerializedName
2929
* and private policy url info.
3030
*/
3131
data class Config(
32-
@SerializedName("origin") val origin: String?,
33-
@SerializedName("versions") val versions: Map<String, Version>?,
32+
@SerializedName("origin") val origin: String?,
33+
@SerializedName("versions") val versions: Map<String, Version>?,
3434
) {
35-
fun mergeOrOverrideWith(config: Config): Config {
36-
return this
35+
private companion object {
36+
const val DEFAULT_VERSION_NAME = "default"
37+
const val STATUS_ENDPOINT_NAME = "status"
38+
const val UPDATE_ENDPOINT_NAME = "update"
3739
}
40+
41+
private fun getCurrentVersionOrUseDefault(versionName: String): Version? =
42+
versions?.get(versionName) ?: versions?.get(DEFAULT_VERSION_NAME)
43+
44+
45+
fun getContextUrl(versionName: String): String =
46+
getCurrentVersionOrUseDefault(versionName)?.contextEndpoint?.url ?: ""
47+
48+
fun getStatusUrl(versionName: String): String =
49+
getCurrentVersionOrUseDefault(versionName)?.endpoints?.get(STATUS_ENDPOINT_NAME)?.url ?: ""
50+
51+
52+
fun getUpdateUrl(versionName: String): String =
53+
getCurrentVersionOrUseDefault(versionName)?.endpoints?.get(UPDATE_ENDPOINT_NAME)?.url ?: ""
54+
3855
}
3956

4057
data class Endpoint(
41-
@SerializedName("url") val url: String?,
42-
@SerializedName("pubKeys") val pubKeys: Collection<String>?
58+
@SerializedName("url") val url: String?,
59+
@SerializedName("pubKeys") val pubKeys: Collection<String>?
4360
)
4461

4562
data class Version(
46-
@SerializedName("privacyUrl") val privacyUrl: String?,
47-
@SerializedName("context") val contextEndpoint: Endpoint?,
48-
@SerializedName("outdated") val outdated: Boolean?,
49-
@SerializedName("endpoints") val endpoints: Map<String, Endpoint>?
63+
@SerializedName("privacyUrl") val privacyUrl: String?,
64+
@SerializedName("context") val contextEndpoint: Endpoint?,
65+
@SerializedName("outdated") val outdated: Boolean?,
66+
@SerializedName("endpoints") val endpoints: Map<String, Endpoint>?
5067
)

app/src/main/java/dgca/verifier/app/android/data/ConfigRepositoryImpl.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,24 @@
2222

2323
package dgca.verifier.app.android.data
2424

25+
import dgca.verifier.app.android.BuildConfig
2526
import dgca.verifier.app.android.data.local.MutableConfigDataSource
27+
import dgca.verifier.app.android.data.remote.RemoteConfigDataSource
2628
import javax.inject.Inject
2729

2830
class ConfigRepositoryImpl @Inject constructor(
29-
private val localConfigDataSource: MutableConfigDataSource,
30-
private val remoteConfigDataSource: ConfigDataSource
31+
private val localConfigDataSource: MutableConfigDataSource,
32+
private val remoteConfigDataSource: RemoteConfigDataSource
3133
) : ConfigRepository {
3234
override fun local(): ConfigDataSource {
3335
return localConfigDataSource
3436
}
3537

36-
override fun getConfig(): Config = remoteConfigDataSource.getConfig().apply {
37-
localConfigDataSource.setConfig(this)
38+
override fun getConfig(): Config {
39+
return remoteConfigDataSource.getConfig(
40+
localConfigDataSource.getConfig().getContextUrl(BuildConfig.VERSION_NAME)
41+
).apply {
42+
localConfigDataSource.setConfig(this)
43+
}
3844
}
3945
}

app/src/main/java/dgca/verifier/app/android/data/VerifierRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import java.security.cert.Certificate
2626

2727
interface VerifierRepository {
2828

29-
suspend fun fetchCertificates(): Boolean?
29+
suspend fun fetchCertificates(statusUrl: String, updateUrl: String): Boolean?
3030

3131
suspend fun getCertificatesBy(kid: String): List<Certificate>
3232
}

app/src/main/java/dgca/verifier/app/android/data/VerifierRepositoryImpl.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,16 @@ class VerifierRepositoryImpl @Inject constructor(
4747
private val validCertList = mutableListOf<String>()
4848
private val mutex = Mutex()
4949

50-
override suspend fun fetchCertificates(): Boolean? {
50+
override suspend fun fetchCertificates(statusUrl: String, updateUrl: String): Boolean? {
5151
mutex.withLock {
5252
return execute {
53-
val response = apiService.getCertStatus()
53+
val response = apiService.getCertStatus(statusUrl)
5454
val body = response.body() ?: return@execute false
5555
validCertList.clear()
5656
validCertList.addAll(body)
5757

5858
val resumeToken = preferences.resumeToken
59-
fetchCertificate(resumeToken)
59+
fetchCertificate(updateUrl, resumeToken)
6060
db.keyDao().deleteAllExcept(validCertList.toTypedArray())
6161
return@execute true
6262
}
@@ -68,9 +68,9 @@ class VerifierRepositoryImpl @Inject constructor(
6868
.map { keyStoreCryptor.decrypt(it.key)?.base64ToX509Certificate()!! }
6969
}
7070

71-
private suspend fun fetchCertificate(resumeToken: Long) {
71+
private suspend fun fetchCertificate(url: String, resumeToken: Long) {
7272
val tokenFormatted = if (resumeToken == -1L) "" else resumeToken.toString()
73-
val response = apiService.getCertUpdate(tokenFormatted)
73+
val response = apiService.getCertUpdate(tokenFormatted, url)
7474

7575
if (!response.isSuccessful || response.code() == HttpURLConnection.HTTP_NO_CONTENT) {
7676
Timber.d("No content")
@@ -91,7 +91,7 @@ class VerifierRepositoryImpl @Inject constructor(
9191
newResumeToken?.let {
9292
val newToken = it.toLong()
9393
preferences.resumeToken = newToken
94-
fetchCertificate(newToken)
94+
fetchCertificate(url, newToken)
9595
}
9696
}
9797

app/src/main/java/dgca/verifier/app/android/data/remote/ApiService.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,19 @@ import retrofit2.Call
2828
import retrofit2.Response
2929
import retrofit2.http.GET
3030
import retrofit2.http.Header
31+
import retrofit2.http.Url
3132

3233
interface ApiService {
3334

34-
@GET("/context")
35-
fun context(): Call<Config>
35+
@GET
36+
fun context(@Url url: String): Call<Config>
3637

37-
@GET("/signercertificateUpdate")
38+
@GET
3839
suspend fun getCertUpdate(
39-
@Header("x-resume-token") contentRange: String
40+
@Header("x-resume-token") contentRange: String,
41+
@Url url: String
4042
): Response<ResponseBody>
4143

42-
@GET("/signercertificateStatus")
43-
suspend fun getCertStatus(): Response<List<String>>
44+
@GET
45+
suspend fun getCertStatus(@Url url: String): Response<List<String>>
4446
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* ---license-start
3+
* eu-digital-green-certificates / dgca-verifier-app-android
4+
* ---
5+
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
6+
* ---
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ---license-end
19+
*
20+
* Created by osarapulov on 5/17/21 8:23 AM
21+
*/
22+
23+
package dgca.verifier.app.android.data.remote
24+
25+
import dgca.verifier.app.android.data.Config
26+
import javax.inject.Inject
27+
28+
class DefaultRemoteConfigDataSource @Inject constructor(private val apiService: ApiService) :
29+
RemoteConfigDataSource {
30+
override fun getConfig(url: String): Config {
31+
return apiService.context(url).execute().body()!!
32+
}
33+
}

app/src/main/java/dgca/verifier/app/android/data/remote/RemoteConfigDataSource.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@
1717
* limitations under the License.
1818
* ---license-end
1919
*
20-
* Created by osarapulov on 5/17/21 8:23 AM
20+
* Created by osarapulov on 5/21/21 2:00 PM
2121
*/
2222

2323
package dgca.verifier.app.android.data.remote
2424

2525
import dgca.verifier.app.android.data.Config
26-
import dgca.verifier.app.android.data.ConfigDataSource
27-
import javax.inject.Inject
2826

29-
class RemoteConfigDataSource @Inject constructor(private val apiService: ApiService) : ConfigDataSource {
30-
override fun getConfig(): Config = apiService.context().execute().body()!!
27+
interface RemoteConfigDataSource {
28+
fun getConfig(url: String): Config
3129
}

app/src/main/java/dgca/verifier/app/android/di/RepositoryModule.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ import dagger.Binds
2626
import dagger.Module
2727
import dagger.hilt.InstallIn
2828
import dagger.hilt.components.SingletonComponent
29-
import dgca.verifier.app.android.data.*
29+
import dgca.verifier.app.android.data.ConfigRepository
30+
import dgca.verifier.app.android.data.ConfigRepositoryImpl
31+
import dgca.verifier.app.android.data.VerifierRepository
32+
import dgca.verifier.app.android.data.VerifierRepositoryImpl
3033
import dgca.verifier.app.android.data.local.LocalConfigDataSource
3134
import dgca.verifier.app.android.data.local.MutableConfigDataSource
35+
import dgca.verifier.app.android.data.remote.DefaultRemoteConfigDataSource
3236
import dgca.verifier.app.android.data.remote.RemoteConfigDataSource
3337
import javax.inject.Singleton
3438

@@ -46,7 +50,8 @@ abstract class RepositoryModule {
4650

4751
@Singleton
4852
@Binds
49-
abstract fun bindRemoteConfigDataSource(configDataSource: RemoteConfigDataSource): ConfigDataSource
53+
abstract fun bindRemoteConfigDataSource(configDataSourceDefault: DefaultRemoteConfigDataSource): RemoteConfigDataSource
54+
5055

5156
@Singleton
5257
@Binds

app/src/main/java/dgca/verifier/app/android/settings/SettingsViewModel.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@ import androidx.lifecycle.MutableLiveData
2727
import androidx.lifecycle.ViewModel
2828
import androidx.lifecycle.viewModelScope
2929
import dagger.hilt.android.lifecycle.HiltViewModel
30+
import dgca.verifier.app.android.BuildConfig
31+
import dgca.verifier.app.android.data.ConfigRepository
3032
import dgca.verifier.app.android.data.VerifierRepository
3133
import kotlinx.coroutines.Dispatchers
3234
import kotlinx.coroutines.launch
3335
import kotlinx.coroutines.withContext
3436
import javax.inject.Inject
3537

3638
@HiltViewModel
37-
class SettingsViewModel @Inject constructor(private val verifierRepository: VerifierRepository) :
38-
ViewModel() {
39+
class SettingsViewModel @Inject constructor(
40+
private val configRepository: ConfigRepository,
41+
private val verifierRepository: VerifierRepository
42+
) : ViewModel() {
3943

4044
private val _inProgress = MutableLiveData<Boolean>()
4145
val inProgress: LiveData<Boolean> = _inProgress
@@ -44,7 +48,12 @@ class SettingsViewModel @Inject constructor(private val verifierRepository: Veri
4448
viewModelScope.launch {
4549
_inProgress.value = true
4650
withContext(Dispatchers.IO) {
47-
verifierRepository.fetchCertificates()
51+
val config = configRepository.local().getConfig()
52+
val versionName = BuildConfig.VERSION_NAME
53+
verifierRepository.fetchCertificates(
54+
config.getStatusUrl(versionName),
55+
config.getUpdateUrl(versionName)
56+
)
4857
}
4958
_inProgress.value = false
5059
}

app/src/main/java/dgca/verifier/app/android/worker/LoadKeysWorker.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,27 @@ import androidx.work.CoroutineWorker
2828
import androidx.work.WorkerParameters
2929
import dagger.assisted.Assisted
3030
import dagger.assisted.AssistedInject
31+
import dgca.verifier.app.android.BuildConfig
32+
import dgca.verifier.app.android.data.ConfigRepository
3133
import dgca.verifier.app.android.data.VerifierRepository
3234
import timber.log.Timber
3335

3436
@HiltWorker
3537
class LoadKeysWorker @AssistedInject constructor(
3638
@Assisted context: Context,
3739
@Assisted workParams: WorkerParameters,
40+
private val configRepository: ConfigRepository,
3841
private val verifierRepository: VerifierRepository
3942
) : CoroutineWorker(context, workParams) {
4043

4144
override suspend fun doWork(): Result {
4245
Timber.d("key fetching start")
43-
val res = verifierRepository.fetchCertificates()
46+
val config = configRepository.local().getConfig()
47+
val versionName = BuildConfig.VERSION_NAME
48+
val res = verifierRepository.fetchCertificates(
49+
config.getStatusUrl(versionName),
50+
config.getUpdateUrl(versionName)
51+
)
4452
Timber.d("key fetching result: ${res == true}")
4553
return if (res == true) Result.success() else Result.retry()
4654
}

0 commit comments

Comments
 (0)