Commit 00f9b8f5 authored by stopcovid@lunabee.com's avatar stopcovid@lunabee.com
Browse files

Update to 3.1.5

- clea status balance
- Fix signal not visible when Covid positive
parent e02b12ba
......@@ -16,7 +16,6 @@ enum class EnvConstant {
override val baseUrl: String = "https://api.tousanticovid.gouv.fr"
override val certificateSha256: String = "sha256/xrPKKhmYeHgk4v57GcqYPrFpnI3f1FTmEfol9WIicaI="
override val cleaStatusBaseUrl: String = "https://s3.fr-par.scw.cloud/clea-batch/"
override val cleaStatusCertificateSha256: String = "sha256/LB5QyMD8qDE1y12jAq/yey1VpjsBbVfFNOblb7QyaR0="
override val cleaReportBaseUrl: String = "https://signal-api.tousanticovid.gouv.fr/"
override val cleaReportCertificateSha256: String = "sha256/tnjjbtuXZUSyK1uReQhvmtspPS7IUl95cs9G8RvfVUs="
override val analyticsBaseUrl: String = "https://analytics-api.tousanticovid.gouv.fr"
......@@ -30,7 +29,6 @@ enum class EnvConstant {
abstract val baseUrl: String
abstract val certificateSha256: String
abstract val cleaStatusBaseUrl: String
abstract val cleaStatusCertificateSha256: String
abstract val cleaReportBaseUrl: String
abstract val cleaReportCertificateSha256: String
abstract val analyticsBaseUrl: String
......@@ -38,4 +36,4 @@ enum class EnvConstant {
abstract val configFilename: String
abstract val calibrationFilename: String
abstract val serverPublicKey: String
}
\ No newline at end of file
}
......@@ -123,6 +123,8 @@ internal class ApiConfiguration(
val analyticsApiVersion: String,
@SerializedName("app.wallet.testCertificateValidityThresholds")
val testCertificateValidityThresholds: String,
@SerializedName("app.cleaUrls")
val cleaUrls: String?,
)
internal fun ApiConfiguration.toDomain(gson: Gson) = Configuration(
......@@ -191,4 +193,8 @@ internal fun ApiConfiguration.toDomain(gson: Gson) = Configuration(
isAnalyticsOn = isAnalyticsOn,
analyticsApiVersion = analyticsApiVersion,
testCertificateValidityThresholds = gson.fromJson(testCertificateValidityThresholds, object : TypeToken<List<Int>>() {}.type),
)
\ No newline at end of file
cleaUrls = gson.fromJson(
cleaUrls,
object : TypeToken<List<String>?>() {}.type
),
)
......@@ -64,4 +64,5 @@ class Configuration(
var isAnalyticsOn: Boolean,
var analyticsApiVersion: String,
var testCertificateValidityThresholds: List<Int>,
)
\ No newline at end of file
val cleaUrls: List<String>,
)
......@@ -44,6 +44,19 @@ object RetrofitClient {
.build().create(clazz)
}
internal fun <T> getService(
context: Context,
baseUrl: String,
clazz: Class<T>,
onProgressUpdate: ((Float) -> Unit)? = null,
): T {
return Retrofit.Builder()
.baseUrl(baseUrl.toHttpUrl())
.addConverterFactory(MoshiConverterFactory.create())
.client(getDefaultOKHttpClient(context, baseUrl, null, onProgressUpdate))
.build().create(clazz)
}
internal fun <T> getFileService(context: Context, baseUrl: String, certificateSHA256: String, clazz: Class<T>): T {
return Retrofit.Builder()
.baseUrl(baseUrl.toHttpUrl())
......@@ -54,7 +67,7 @@ object RetrofitClient {
fun getDefaultOKHttpClient(
context: Context,
url: String,
certificateSHA256: String,
certificateSHA256: String?,
onProgressUpdate: ((Float) -> Unit)? = null,
): OkHttpClient {
val requireTls12 = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
......@@ -64,7 +77,7 @@ object RetrofitClient {
if (!BuildConfig.DEBUG) {
connectionSpecs(listOf(requireTls12))
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N && certificateSHA256 != null) {
certificatePinner(
CertificatePinner.Builder()
.add(url.toHttpUrl().host, certificateSHA256)
......
......@@ -18,17 +18,15 @@ class CleaDataSource(
val context: Context,
cleaReportBaseUrl: String,
cleaReportCertificateSha256: String,
cleaStatusBaseUrl: String,
cleaStatusCertificateSha256: String,
private val cleaStatusFallbackBaseUrl: String,
) : RemoteCleaDataSource {
private var filesDir = context.filesDir
private var cleaStatusApi: CleaStatusApi = RetrofitClient.getService(
context,
cleaStatusBaseUrl,
cleaStatusCertificateSha256,
CleaStatusApi::class.java
private fun getCleaStatusApi(cleaStatusBaseUrl: String): CleaStatusApi = RetrofitClient.getService(
context = context,
baseUrl = cleaStatusBaseUrl,
clazz = CleaStatusApi::class.java,
)
private var cleaReportApi: CleaReportApi = RetrofitClient.getService(
......@@ -49,9 +47,9 @@ class CleaDataSource(
}
}
override suspend fun cleaClusterIndex(apiVersion: String): RobertResultData<ClusterIndex> {
override suspend fun cleaClusterIndex(apiVersion: String, cleaStatusBaseUrl: String?): RobertResultData<ClusterIndex> {
val result = RequestHelper.tryCatchRequestData(context, filesDir, apiVersion, null) {
cleaStatusApi.getClusterIndex(apiVersion)
getCleaStatusApi(cleaStatusBaseUrl ?: cleaStatusFallbackBaseUrl).getClusterIndex(apiVersion)
}
return when (result) {
is RobertResultData.Success -> RobertResultData.Success(result.data.toDomain())
......@@ -59,13 +57,18 @@ class CleaDataSource(
}
}
override suspend fun cleaClusterList(apiVersion: String, iteration: String, clusterPrefix: String): RobertResultData<List<Cluster>> {
override suspend fun cleaClusterList(
apiVersion: String,
iteration: String,
clusterPrefix: String,
cleaStatusBaseUrl: String?
): RobertResultData<List<Cluster>> {
val result = RequestHelper.tryCatchRequestData(context, filesDir, apiVersion, null) {
cleaStatusApi.getClusterList(apiVersion, iteration, clusterPrefix)
getCleaStatusApi(cleaStatusBaseUrl ?: cleaStatusFallbackBaseUrl).getClusterList(apiVersion, iteration, clusterPrefix)
}
return when (result) {
is RobertResultData.Success -> RobertResultData.Success(result.data.mapNotNull { it.toDomain() })
is RobertResultData.Failure -> RobertResultData.Failure(result.error)
}
}
}
\ No newline at end of file
}
......@@ -106,7 +106,7 @@ class RobertManagerImpl(
calibrationDataSource,
serverPublicKey
)
private val cleaRepository = CleaRepository(cleaDataSource)
private val cleaRepository = CleaRepository(cleaDataSource, localKeystoreDataSource)
private var _configuration: Configuration = remoteServiceRepository.loadConfig(application.getAppContext())
override val configuration: Configuration
......
......@@ -9,6 +9,11 @@ import com.lunabeestudio.robert.model.RobertResultData
interface RemoteCleaDataSource {
suspend fun wreportClea(cleaApiVersion: String, token: String, pivotDate: Long, venueQrCodeList: List<VenueQrCode>): RobertResult
suspend fun cleaClusterIndex(apiVersion: String): RobertResultData<ClusterIndex>
suspend fun cleaClusterList(apiVersion: String, iteration: String, clusterPrefix: String): RobertResultData<List<Cluster>>
suspend fun cleaClusterIndex(apiVersion: String, cleaStatusBaseUrl: String?): RobertResultData<ClusterIndex>
suspend fun cleaClusterList(
apiVersion: String,
iteration: String,
clusterPrefix: String,
cleaStatusBaseUrl: String?
): RobertResultData<List<Cluster>>
}
\ No newline at end of file
......@@ -3,21 +3,25 @@ package com.lunabeestudio.robert.repository
import com.lunabeestudio.domain.model.Cluster
import com.lunabeestudio.domain.model.ClusterIndex
import com.lunabeestudio.domain.model.VenueQrCode
import com.lunabeestudio.robert.datasource.LocalKeystoreDataSource
import com.lunabeestudio.robert.datasource.RemoteCleaDataSource
import com.lunabeestudio.robert.model.RobertResult
import com.lunabeestudio.robert.model.RobertResultData
class CleaRepository(
private val cleaDataSource: RemoteCleaDataSource
private val cleaDataSource: RemoteCleaDataSource,
private val localKeystoreDataSource: LocalKeystoreDataSource,
) {
suspend fun wreportClea(cleaApiVersion: String, token: String, pivotDateNTP: Long, venueQrCodeList: List<VenueQrCode>): RobertResult =
cleaDataSource.wreportClea(cleaApiVersion, token, pivotDateNTP, venueQrCodeList)
suspend fun cleaClusterIndex(cleaApiVersion: String): RobertResultData<ClusterIndex> =
cleaDataSource.cleaClusterIndex(cleaApiVersion)
suspend fun cleaClusterIndex(cleaApiVersion: String): RobertResultData<ClusterIndex> {
return cleaDataSource.cleaClusterIndex(cleaApiVersion, getRandomCleaStatusBaseUrl())
}
suspend fun cleaClusterList(cleaApiVersion: String, iteration: String, prefix: String): RobertResultData<List<Cluster>> =
cleaDataSource.cleaClusterList(cleaApiVersion, iteration, prefix)
cleaDataSource.cleaClusterList(cleaApiVersion, iteration, prefix, getRandomCleaStatusBaseUrl())
private fun getRandomCleaStatusBaseUrl(): String? = localKeystoreDataSource.configuration?.cleaUrls?.randomOrNull()
}
\ No newline at end of file
......@@ -43,8 +43,8 @@ android {
applicationId "fr.gouv.android.stopcovid"
minSdkVersion 21
targetSdkVersion 30
versionCode 244
versionName "3.1.4"
versionCode 252
versionName "3.1.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
......
......@@ -2,11 +2,11 @@
"config": [
{
"name": "lastUpdate",
"value": "29 april 2021"
"value": "5 June 2021"
},
{
"name": "version",
"value": 49
"value": 57
},
{
"name": "versionCalibrationBle",
......@@ -32,6 +32,10 @@
"name": "app.analyticsApiVersion",
"value": "v1"
},
{
"name" : "app.cleaUrls",
"value" : ["https://s3.fr-par.scw.cloud/clea-batch/"]
},
{
"name" : "app.ameliUrl",
"value" : "https://declare.ameli.fr/tousanticovid/t/%@/"
......@@ -115,7 +119,7 @@
},
{
"name": "app.displayRecordVenues",
"value": false
"value": true
},
{
"name": "app.displayPrivateEvent",
......@@ -175,12 +179,20 @@
},
{
"name": "app.venuesRetentionPeriod",
"value": 14
"value": 15
},
{
"name": "app.dataRetentionPeriod",
"value": 14
},
{
"name": "app.covidPlusWarning",
"value": 14
},
{
"name": "app.covidPlusNoTracing",
"value": 60
},
{
"name": "app.preSymptomsSpan",
"value": 2
......@@ -203,11 +215,11 @@
},
{
"name": "app.checkStatusFrequency",
"value": 6.0
"value": 12.0
},
{
"name": "app.minStatusRetryDuration",
"value": 0.6
"value": 3.0
},
{
"name": "app.appAvailability",
......
......@@ -145,7 +145,6 @@ class StopCovid : Application(), LifecycleObserver, RobertApplication, Isolation
EnvConstant.Prod.cleaReportBaseUrl,
EnvConstant.Prod.cleaReportCertificateSha256,
EnvConstant.Prod.cleaStatusBaseUrl,
EnvConstant.Prod.cleaStatusCertificateSha256
),
BouncyCastleCryptoDataSource(),
ConfigDataSource,
......
......@@ -459,8 +459,7 @@ class ProximityFragment : TimeMainFragment() {
}
// Venue items
if (!isSick && robertManager.configuration.displayRecordVenues) {
if (robertManager.configuration.displayRecordVenues) {
addVenueItems(items)
addSectionSeparator(items)
}
......
......@@ -51,7 +51,6 @@ class VenueQRCodeFragment : QRCodeFragment() {
val venueVersion = args.venueVersion
when {
robertManager.isSick -> findNavControllerOrNull()?.navigateUp()
!robertManager.isRegistered -> findNavControllerOrNull()?.safeNavigate(
VenueQRCodeFragmentDirections.actionVenueQrCodeFragmentToCaptchaFragment(
CaptchaNextFragment.Venue,
......
package com.lunabeestudio.stopcovid.manager
import android.content.SharedPreferences
import android.net.Uri
import android.net.UrlQuerySanitizer
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
......@@ -54,12 +55,18 @@ object WalletManager {
}
fun extractCertificateCodeFromUrl(urlValue: String): String {
val sanitizer = UrlQuerySanitizer()
sanitizer.registerParameter("v") {
it // Do nothing since there are plenty of non legal characters in this value
var code = Uri.parse(urlValue).fragment
if (code == null) { // Try the old way
val sanitizer = UrlQuerySanitizer()
sanitizer.registerParameter("v") {
it // Do nothing since there are plenty of non legal characters in this value
}
sanitizer.parseUrl(sanitizer.unescape(urlValue))
code = sanitizer.getValue("v")
}
sanitizer.parseUrl(sanitizer.unescape(urlValue))
return sanitizer.getValue("v") ?: throw WalletCertificateMalformedException()
return code ?: throw WalletCertificateMalformedException()
}
fun verifyCertificateCodeValue(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment