StaticDataService.kt 6.67 KB
Newer Older
Hyene's avatar
Hyene committed
1 2 3 4 5 6
package com.ingroupe.verify.anticovid.service.document

import android.content.Context
import android.util.Base64
import android.util.Log
import com.ingroupe.verify.anticovid.R
Elephant's avatar
Elephant committed
7
import com.ingroupe.verify.anticovid.common.Constants
Hyene's avatar
Hyene committed
8 9 10
import com.ingroupe.verify.anticovid.service.document.enums.ErrorDocEnum
import com.ingroupe.verify.anticovid.service.barcode.Barcode2DDocService
import com.ingroupe.verify.anticovid.service.document.model.*
Hyene's avatar
Hyene committed
11
import com.ingroupe.verify.anticovid.synchronization.elements.CertificateDcc
Hyene's avatar
Hyene committed
12 13
import dgca.verifier.app.decoder.base45.DefaultBase45Service
import dgca.verifier.app.decoder.cbor.DefaultCborService
Hyene's avatar
Hyene committed
14
import dgca.verifier.app.decoder.cbor.GreenCertificateData
Hyene's avatar
Hyene committed
15 16 17
import dgca.verifier.app.decoder.compression.DefaultCompressorService
import dgca.verifier.app.decoder.cose.DefaultCoseService
import dgca.verifier.app.decoder.cose.VerificationCryptoService
Elephant's avatar
Elephant committed
18
import dgca.verifier.app.decoder.getJsonDataFromAsset
Hyene's avatar
Hyene committed
19
import dgca.verifier.app.decoder.model.ActivityDCC
Hyene's avatar
Hyene committed
20 21 22 23
import dgca.verifier.app.decoder.model.GreenCertificate
import dgca.verifier.app.decoder.model.VerificationResult
import dgca.verifier.app.decoder.prefixvalidation.DefaultPrefixValidationService
import dgca.verifier.app.decoder.schema.DefaultSchemaValidator
Hyene's avatar
Hyene committed
24
import dgca.verifier.app.decoder.services.X509
Hyene's avatar
Hyene committed
25 26 27
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
Hyene's avatar
Hyene committed
28 29 30 31 32 33 34


class StaticDataService {

    companion object {
        const val TAG = "StaticDataService"

Hyene's avatar
Hyene committed
35
        private val headersUsed = arrayOf("01", "02", "07", "08")
Hyene's avatar
Hyene committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

        fun getBarcode2DDoc(encoded2DDoc: String, context: Context): DocumentStatic2ddocResult? {
            try {
                val barcode2DDoc: DocumentStatic2ddocResult = Barcode2DDocService.getBarcode2DDoc(encoded2DDoc, context)
                if (DocumentStatic2ddocResult.barcode2DDocNotNull(barcode2DDoc)) {
                    addDocumentTypeToHeaderFields(barcode2DDoc)
                    removeHeaderFields(barcode2DDoc)
                    addSignatureTo2DDoc(barcode2DDoc, context)
                    return barcode2DDoc
                }
            } catch (e: Exception) {
                Log.e(TAG, ErrorDocEnum.ERR02.message, e)
            }
            return null
        }

        private fun addDocumentTypeToHeaderFields(barcode2DDoc: DocumentStatic2ddocResult) {
            val field = DocumentFieldResult()
            field.name = "00"
            field.label = "Type de document"
            field.value = barcode2DDoc.message!!.label
            barcode2DDoc.header!!.fields?.add(0, field)
        }
        private fun removeHeaderFields(barcode2DDoc: DocumentStatic2ddocResult) {
            barcode2DDoc.header?. let { zoneDto ->
                val newFields = arrayListOf<DocumentFieldResult>()
                zoneDto.fields?.forEach { field ->
                    if(field.name !in headersUsed) {
                        newFields.add(field)
                    }
                }
                zoneDto.fields = newFields
            }
        }

        private fun addSignatureTo2DDoc(barcode2DDocDto: DocumentStaticResult, context: Context) {
            val signature = DocumentSignatureResult()
            signature.isValid = barcode2DDocDto.hasValidSignature
            signature.status = context.getString(if (barcode2DDocDto.hasValidSignature) R.string.result_valid else R.string.result_invalid)
            barcode2DDocDto.signature = signature
        }

        @ExperimentalUnsignedTypes
Hyene's avatar
Hyene committed
79 80 81
        fun getDcc(
            encodedDcc: String,
            context: Context,
Elephant's avatar
Elephant committed
82
            mappedDynamicData: MutableMap<String, String>,
Hyene's avatar
Hyene committed
83 84
            dccFormat: Constants.DccFormat,
            controlTimeOT: ZonedDateTime?
Hyene's avatar
Hyene committed
85
        ): DocumentStaticDccResult {
Hyene's avatar
Hyene committed
86 87

            val verificationResult = VerificationResult()
Elephant's avatar
Elephant committed
88
            val plainInput = DefaultPrefixValidationService(dccFormat.prefix).decode(encodedDcc, verificationResult)
Hyene's avatar
Hyene committed
89
            val compressedCose = DefaultBase45Service().decode(plainInput, verificationResult)
Hyene's avatar
Hyene committed
90
            val cose = checkNotNull(DefaultCompressorService().decode(compressedCose, verificationResult))
Hyene's avatar
Hyene committed
91
            val coseData = checkNotNull(DefaultCoseService().decode(cose, verificationResult))
Elephant's avatar
Elephant committed
92 93 94 95

            val jsonSchema = getJsonDataFromAsset(context, dccFormat.jsonSchemaAssetFileName) ?: ""

            DefaultSchemaValidator(jsonSchema).validate(coseData.cbor, verificationResult)
Hyene's avatar
Hyene committed
96
            if (!verificationResult.isSchemaValid) {
Hyene's avatar
Hyene committed
97
                mappedDynamicData["anomaly"] = context.getString(R.string.result_anomaly_dcc_schema)
Hyene's avatar
Hyene committed
98 99 100
            }

            val kid = checkNotNull(coseData.kid)
Hyene's avatar
Hyene committed
101
            val base64EncodedKid = Base64.encodeToString(kid, Base64.NO_WRAP)
Hyene's avatar
Hyene committed
102 103
            val greenCertificateData: GreenCertificateData = checkNotNull(DefaultCborService().decodeData(coseData.cbor, verificationResult))
            val greenCertificate: GreenCertificate = checkNotNull(greenCertificateData.greenCertificate)
Hyene's avatar
Hyene committed
104

Hyene's avatar
Hyene committed
105
            val certificate = CertificateDcc.getDccCertificate(base64EncodedKid, context)
Hyene's avatar
Hyene committed
106
            val signature = DocumentSignatureResult()
Hyene's avatar
Hyene committed
107 108 109 110 111 112 113
            if (certificate == null) {
                signature.isValid = false
                signature.status = context.getString(R.string.result_invalid)
            } else {
                val utcZoneId: ZoneId = ZoneId.ofOffset("", ZoneOffset.UTC).normalized()
                val expirationTime: ZonedDateTime? =
                    certificate.notAfter.toInstant().atZone(utcZoneId)
Hyene's avatar
Hyene committed
114 115
                val controlTime: ZonedDateTime = controlTimeOT?: ZonedDateTime.now().withZoneSameInstant(utcZoneId)
                if (expirationTime != null && controlTime.isAfter(expirationTime)) {
Hyene's avatar
Hyene committed
116 117 118 119 120 121 122
                    signature.isValid = false
                    signature.status = context.getString(R.string.result_anomaly_certificate_expired)
                } else {
                    VerificationCryptoService(X509()).validate(cose, certificate, verificationResult)
                    signature.isValid = verificationResult.coseVerified
                    signature.status = context.getString(if (verificationResult.coseVerified) R.string.result_valid else R.string.result_invalid)
                }
Hyene's avatar
Hyene committed
123
            }
Hyene's avatar
Hyene committed
124

Hyene's avatar
Hyene committed
125 126 127
            //Specific France for the Activity DCC
            if (DocumentStaticDccResult.getResourceType(greenCertificate) == DocumentStaticDccResult.DccType.DCC_ACTIVITY) {
                greenCertificate.activity = ActivityDCC(greenCertificateData.expirationTime, greenCertificateData.issuedAt)
Hyene's avatar
Hyene committed
128
            }
Hyene's avatar
Hyene committed
129

Hyene's avatar
Hyene committed
130
            val result = DocumentStaticDccResult(greenCertificateData, signature, base64EncodedKid, greenCertificateData.issuedAt, greenCertificateData.expirationTime)
Hyene's avatar
Hyene committed
131 132 133 134 135
            result.hasValidSignature = verificationResult.coseVerified
            return result
        }
    }
}