Commit 1434925a authored by Hyene's avatar Hyene
Browse files

version 2.0.0 / build 78

parent 408a94ed
## 1.11.1-69
## 2.0.0-78
#### Fix
* **mode Opérateur de transport:** rajout d'un message spécifique
## 2.0.0-77
#### Features
* **Nouveau mode:** • 3 modes de vérification TAC Verif (activités), TAC Verif+ (Professionnels de Santé), OT (Opérateurs de Transport)
* **Gestion 3ème dose:** Ajout des règles de gestion pour la 3ème, désactivée niveau back au moment de la livraison de l'app
#### Fix
* **Synchronisation:** meilleur gestion de l'enchainement des appels
* **Résultats:**
- Reprise des correctifs sur les librairies EU
## 1.11.1-69 (2021-10-14)
#### Fix
* **Général:**
......
......@@ -8,7 +8,7 @@ Ce code est développé par IN Groupe et publié sous une licence propre à IN G
Usage et fonctionnalité
-------------------
Le code ainsi publié est celui de l'application TousAntiCovid Verif dont l'usage est strictement réservé aux personnes habilitées et services autorisée dans le cadre de la Loi de Sortie de l'Etat d'Urgence Sanitaire du 2 juin 2021, article 1 et de ces décrets d'applications [https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000043618403](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000043618403)
Le code ainsi publié est celui de l'application TAC Verif dont l'usage est strictement réservé aux personnes habilitées et services autorisée dans le cadre de la Loi de Sortie de l'Etat d'Urgence Sanitaire du 2 juin 2021, article 1 et de ces décrets d'applications [https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000043618403](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000043618403)
Cette application dispose de deux modes de fonctionnement :
......@@ -70,3 +70,10 @@ ___MIT___
*Component*: The Bouncy Castle Crypto Package For Java
*License Text URL*: [https://github.com/bcgit/bc-java/blob/master/LICENSE.html](https://github.com/bcgit/bc-java/blob/master/LICENSE.html)
*Source Code*: [https://github.com/bcgit/bc-java](https://github.com/bcgit/bc-java)
*Component*: World Country Data
*License Text URL*: [https://github.com/blongho/worldCountryData/blob/master/LICENSE.txt](https://github.com/blongho/worldCountryData/blob/master/LICENSE.txt)
*Source Code*: [https://github.com/blongho/worldCountryData](https://github.com/blongho/worldCountryData)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
plugins {
id("com.android.application")
id("kotlin-android")
id("kotlin-kapt")
}
android {
compileSdkVersion 30
compileSdkVersion 31
defaultConfig {
applicationId "com.ingroupe.verify.anticovid"
minSdkVersion 23
targetSdkVersion 30
versionCode 69
versionName "1.11.1"
targetSdkVersion 31
versionCode 78
versionName "2.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildFeatures {
viewBinding true
......@@ -19,7 +23,7 @@ android {
prod {
dimension = "environment"
resValue "string", "app_name", "TAC Verif"
buildConfigField "Boolean", "BLOCK_SCREENSHOT", "true"
buildConfigField "Boolean", "WITH_CHECK_HELP", "false"
buildConfigField "String", "ENDPOINT_URL", "\"https://XXX.com\""
buildConfigField "String", "KC_PUBLICKEY", "\"XXX\""
buildConfigField "String", "PERSISTENT_TOKEN", "\"XXX\""
......@@ -41,7 +45,6 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
pickFirst 'META-INF/AL2.0'
......@@ -68,7 +71,7 @@ dependencies {
api "com.scandit.datacapture:core:6.9.2"
api "com.scandit.datacapture:barcode:6.9.2"
def work_version = "2.6.0"
def work_version = "2.7.0"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
......@@ -103,6 +106,7 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation project(path: ':dgca-decoder')
implementation project(path: ':dgc-engine')
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
......@@ -110,6 +114,23 @@ dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3'
// Room
def room_version = "2.3.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor "androidx.room:room-compiler:$room_version"
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$room_version")
// optional - Kotlin Extensions and Coroutines support for Room
implementation("androidx.room:room-ktx:$room_version")
// RxAndroid
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
implementation 'com.github.blongho:worldCountryData:1.5.2'
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.13.2'
// Optional -- Robolectric environment
......@@ -117,4 +138,18 @@ dependencies {
// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:2.21.0'
testImplementation "io.mockk:mockk:1.10.2"
// Jupiter
testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.0"
testImplementation "org.junit.jupiter:junit-jupiter-engine:5.8.0"
testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.0"
testImplementation "org.junit.vintage:junit-vintage-engine:5.8.0"
}
tasks.withType(Test) {
useJUnitPlatform()
testLogging {
exceptionFormat "full"
events "started", "skipped", "passed", "failed"
showStandardStreams true
}
}
\ No newline at end of file
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.ingroupe.verify.anticovid.dev",
"variantName": "devRelease",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 73,
"versionName": "2.0.0",
"outputFile": "app-dev-release.apk"
}
]
}
\ No newline at end of file
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.ingroupe.verify.anticovid.preprod",
"variantName": "preprodRelease",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 78,
"versionName": "2.0.0",
"outputFile": "app-preprod-release.apk"
}
]
}
\ No newline at end of file
......@@ -147,3 +147,15 @@
-keep class sun.** { *; }
-keep class javax.** { *; }
-keep class com.blongho.** {*;}
-keep interface com.blongho.**
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keeppackagenames com.blongho.country_data
-keepclassmembers class com.blongho.country_data.* {
public *;
}
-keep class com.blongho.country_data.R$*{
*;
}
\ No newline at end of file
package com.ingroupe.verify.anticovid
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
Assert.assertEquals("com.ingroupe.verify.anticovid.dev", appContext.packageName)
}
}
\ No newline at end of file
package com.ingroupe.verify.anticovid
/*
* ---license-start
* eu-digital-green-certificates / dgca-verifier-app-android
* ---
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
* ---
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ---license-end
*
* Created by osarapulov on 8/2/21 9:21 AM
*/
import androidx.room.Room
import androidx.test.InstrumentationRegistry
//import androidx.test.core.app.ApplicationProvider
import androidx.test.runner.AndroidJUnit4
import com.fasterxml.jackson.databind.ObjectMapper
import com.ingroupe.verify.anticovid.data.local.rules.EngineDatabase
import com.ingroupe.verify.anticovid.data.local.rules.RuleWithDescriptionsLocal
import com.ingroupe.verify.anticovid.data.local.rules.RulesDao
import com.ingroupe.verify.anticovid.data.local.rules.toRuleWithDescriptionLocal
import dgca.verifier.app.engine.data.RuleCertificateType
import dgca.verifier.app.engine.data.source.remote.rules.RuleRemote
import dgca.verifier.app.engine.data.source.remote.rules.toRule
//import org.apache.commons.io.IOUtils
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
@RunWith(AndroidJUnit4::class)
internal class RulesDaoTest {
private lateinit var rulesDao: RulesDao
private lateinit var db: EngineDatabase
private val objectMapper = ObjectMapper().apply { this.findAndRegisterModules() }
companion object {
const val RULE_JSON_FILE_NAME = "rule.json"
const val RULE_WITH_REGION_JSON_FILE_NAME = "rule_with_region.json"
}
private fun fetchRule(fileName: String): RuleRemote {
val ruleExampleIs: InputStream =
javaClass.classLoader!!.getResourceAsStream(fileName)
val ruleJson = ruleExampleIs.bufferedReader().use(BufferedReader::readText)
return objectMapper.readValue(ruleJson, RuleRemote::class.java)
}
@Before
fun createDb() {
val context = InstrumentationRegistry.getTargetContext()
db = Room.inMemoryDatabaseBuilder(
context, EngineDatabase::class.java
).build()
rulesDao = db.rulesDao()
}
@After
@Throws(IOException::class)
fun closeDb() {
db.close()
}
@Test
@Throws(Exception::class)
fun testInsert() {
val rule = fetchRule(RULE_JSON_FILE_NAME).toRule()
val expected: RuleWithDescriptionsLocal = rule.toRuleWithDescriptionLocal()
rulesDao.insertAll(listOf(expected))
assertTrue(
rulesDao.getRulesWithDescriptionsBy(
rule.countryCode,
rule.validTo.plusDays(1),
rule.type,
rule.ruleCertificateType,
RuleCertificateType.GENERAL
).isEmpty()
)
val actual = rulesDao.getRulesWithDescriptionsBy(
rule.countryCode,
rule.validTo.minusMinutes(1),
rule.type,
rule.ruleCertificateType,
RuleCertificateType.GENERAL
)
assertTrue(actual.size == 1)
assertEquals(expected.rule.copy(ruleId = 1), actual[0].rule)
assertEquals(2, actual[0].descriptions.size)
expected.descriptions.forEachIndexed { index, descriptionLocal ->
assertEquals(
descriptionLocal.copy(
descriptionId = (index + 1).toLong(),
ruleContainerId = 1
), actual[0].descriptions[index]
)
}
}
@Test
@Throws(Exception::class)
fun testInsertRuleWithRegion() {
val ruleRemote = fetchRule(RULE_WITH_REGION_JSON_FILE_NAME).toRule()
val expected: RuleWithDescriptionsLocal = ruleRemote.toRuleWithDescriptionLocal()
rulesDao.insertAll(listOf(expected))
assertTrue(
rulesDao.getRulesWithDescriptionsBy(
ruleRemote.countryCode,
ruleRemote.validTo.plusDays(1),
ruleRemote.type,
ruleRemote.ruleCertificateType,
RuleCertificateType.GENERAL
).isEmpty()
)
val actual = rulesDao.getRulesWithDescriptionsBy(
ruleRemote.countryCode,
ruleRemote.validTo.minusMinutes(1),
ruleRemote.type,
ruleRemote.ruleCertificateType,
RuleCertificateType.GENERAL
)
assertTrue(actual.size == 1)
assertEquals(expected.rule.copy(ruleId = 1), actual[0].rule)
expected.descriptions.forEachIndexed { index, descriptionLocal ->
assertEquals(
descriptionLocal.copy(
descriptionId = (index + 1).toLong(),
ruleContainerId = 1
), actual[0].descriptions[index]
)
}
}
@Test
@Throws(Exception::class)
fun testDelete() {
val ruleRemote = fetchRule(RULE_JSON_FILE_NAME).toRule()
val expected: RuleWithDescriptionsLocal = ruleRemote.toRuleWithDescriptionLocal()
rulesDao.insertAll(listOf(expected))
assertEquals(1, rulesDao.getAll().size)
assertEquals(2, rulesDao.getDescriptionAll().size)
rulesDao.deleteRulesBy(listOf(ruleRemote.identifier))
assertEquals(0, rulesDao.getAll().size)
assertEquals(0, rulesDao.getDescriptionAll().size)
}
@Test
@Throws(Exception::class)
fun testDeleteAllExcept() {
val identifierFirst = "identifierFirst"
val identifierSecond = "identifierSecond"
val ruleFirst = fetchRule(RULE_JSON_FILE_NAME).toRule().copy(identifier = identifierFirst)
val ruleSecond = fetchRule(RULE_JSON_FILE_NAME).toRule().copy(identifier = identifierSecond)
val ruleWithDescriptionsLocalFirst: RuleWithDescriptionsLocal =
ruleFirst.toRuleWithDescriptionLocal()
val ruleWithDescriptionsLocalSecond: RuleWithDescriptionsLocal =
ruleSecond.toRuleWithDescriptionLocal()
rulesDao.insertAll(listOf(ruleWithDescriptionsLocalFirst, ruleWithDescriptionsLocalSecond))
assertEquals(2, rulesDao.getAll().size)
rulesDao.deleteAllExcept(arrayOf(identifierSecond))
val rulesLocalActual = rulesDao.getAll()
assertEquals(1, rulesLocalActual.size)
assertEquals(identifierSecond, rulesLocalActual.first().identifier)
}
}
\ No newline at end of file
package com.ingroupe.verify.anticovid
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.fasterxml.jackson.databind.ObjectMapper
import dgca.verifier.app.decoder.getJsonDataFromAsset
import dgca.verifier.app.engine.CertLogicEngine
import dgca.verifier.app.engine.DefaultAffectedFieldsDataRetriever
import dgca.verifier.app.engine.DefaultCertLogicEngine
import dgca.verifier.app.engine.DefaultJsonLogicValidator
import dgca.verifier.app.engine.Result
import dgca.verifier.app.engine.data.CertificateType
import dgca.verifier.app.engine.data.ExternalParameter
import dgca.verifier.app.engine.data.source.remote.rules.RuleRemote
import dgca.verifier.app.engine.data.source.remote.rules.toRule
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.BufferedReader
import java.io.InputStream
import java.time.ZonedDateTime
@RunWith(AndroidJUnit4::class)
internal class ValidateTest {
private lateinit var engine: CertLogicEngine
private val objectMapper = ObjectMapper().apply { this.findAndRegisterModules() }
companion object {
const val SCHEMA_JSON_FILE_NAME = "schema.json"
const val RULE_JSON_FILE_NAME = "rule.json"
const val HCERT_JSON = "{\"nam\":{\"gn\":\"John\",\"gnt\":\"JOHN\",\"fnt\":\"DOE\",\"fn\":\"DOE\"},\"t\":[{\"tr\":\"260415000\",\"tg\":\"840539006\",\"sc\":\"2021-07-27T08:10:00Z\",\"is\":\"CNAM\",\"tc\":\"test\",\"co\":\"FR\",\"ci\":\"URN:UVCI:V1:FR:71O714J2U5AKX30BOPF1BUN5TB\",\"ma\":\"autotest\",\"tt\":\"970970\"}],\"ver\":\"1.2.1\",\"dob\":\"1980-01-30\"}"
}
private fun fetchRule(fileName: String): RuleRemote {
val ruleExampleIs: InputStream =
javaClass.classLoader!!.getResourceAsStream(fileName)
val ruleJson = ruleExampleIs.bufferedReader().use(BufferedReader::readText)
return objectMapper.readValue(ruleJson, RuleRemote::class.java)
}
@Before
fun create() {
val context = InstrumentationRegistry.getTargetContext()
val schemaIs: InputStream =
javaClass.classLoader!!.getResourceAsStream(SCHEMA_JSON_FILE_NAME)
val schemaJson = schemaIs.bufferedReader().use(BufferedReader::readText)
val jsonSchema = getJsonDataFromAsset(context, schemaJson) ?: ""
engine = DefaultCertLogicEngine(
DefaultAffectedFieldsDataRetriever(ObjectMapper().readTree(jsonSchema), ObjectMapper()),
DefaultJsonLogicValidator()
)
}
@Test
@Throws(Exception::class)
fun testValidationWithDateKO() {
val rule = fetchRule(RULE_JSON_FILE_NAME).toRule()
val externalParameter = ExternalParameter(
validationClock = ZonedDateTime.now(),
valueSets = mapOf(),
countryCode = "FR",
exp = ZonedDateTime.now(),
iat = ZonedDateTime.now(),
issuerCountryCode = "FR",
kid = "",
region = "",
)
val actual = engine.validate(
CertificateType.TEST,
"1.2.1",
listOf(rule),
externalParameter,
HCERT_JSON
)
Assert.assertTrue(actual.size == 1)
Assert.assertEquals(Result.FAIL, actual[0].result)
}
@Test
@Throws(Exception::class)
fun testValidationWithDateOK() {
val rule = fetchRule(RULE_JSON_FILE_NAME).toRule()
val externalParameter = ExternalParameter(
validationClock = ZonedDateTime.parse("2021-07-29T08:10:00Z"),
valueSets = mapOf(),
countryCode = "FR",
exp = ZonedDateTime.now(),
iat = ZonedDateTime.now(),
issuerCountryCode = "FR",
kid = "",
region = "",
)
val actual = engine.validate(
CertificateType.TEST,
"1.2.1",
listOf(rule),
externalParameter,
HCERT_JSON
)
Assert.assertTrue(actual.size == 1)
Assert.assertEquals(Result.PASSED, actual[0].result)
}
}
\ No newline at end of file
{
"Identifier": "GR-SE-0001",
"Type": "Acceptance",
"Country": "SE",
"Version": "1.0.0",
"SchemaVersion": "1.0.0",
"Engine": "CERTLOGIC",
"EngineVersion": "0.7.5",
"CertificateType": "General",
"Description": [
{
"lang": "en",
"desc": "The positive NAA test result (e.g., PCR) must be no older than 6 months."
},
{
"lang": "sv",
"desc": "Ett positivt NAA test resultat (ex PCR) får inte vara äldre än 6 månader"
}
],
"ValidFrom": "2021-07-05T20:27:25Z",
"ValidTo": "2021-07-19T20:27:25Z",
"AffectedFields": [
"r.0",
"r.0.fr"
],
"Logic": {
"if": [
{
"===": [
{
"var": "payload.t.0.tt"
},
"970970"
]
},
{
"before": [
{
"plusTime": [
{
"var": "external.validationClock"
},
0,
"day"
]
},
{
"plusTime": [
{
"var": "payload.t.0.sc"
},
72,
"hour"
]