diff --git a/DGCAVerifier/BusinessRules/Internal/RecoveryValidityCheck.swift b/DGCAVerifier/BusinessRules/Internal/RecoveryValidityCheck.swift index 5f9d2ac..dea6268 100644 --- a/DGCAVerifier/BusinessRules/Internal/RecoveryValidityCheck.swift +++ b/DGCAVerifier/BusinessRules/Internal/RecoveryValidityCheck.swift @@ -37,8 +37,26 @@ struct RecoveryValidityCheck { guard let recoveryValidFromDate = validFrom.toRecoveryDate else { return .notValid } guard let recoveryValidUntilDate = validUntil.toRecoveryDate else { return .notValid } - guard let recoveryStartDays = getStartDays(from: hcert ) else { return .notGreenPass } - guard let recoveryEndDays = getEndDays(from: hcert) else { return .notGreenPass } + var start: Int? + var end: Int? + + let scanMode: String = Store.get(key: .scanMode) ?? "" + switch scanMode { + case Constants.scanMode2G: + start = getStartDays(from: hcert) + end = getEndDays(from: hcert) + case Constants.scanMode3G: + start = getStartDays3G(from: hcert) + end = getEndDays3G(from: hcert) + case Constants.scanModeBooster: + start = getStartDays(from: hcert) + end = getEndDays(from: hcert) + default: + return .notValid + } + + guard let recoveryStartDays = start else { return .notGreenPass } + guard let recoveryEndDays = end else { return .notGreenPass } guard let validityStart = recoveryValidFromDate.add(recoveryStartDays, ofType: .day) else { return .notValid } let validityEnd = recoveryValidUntilDate @@ -48,19 +66,42 @@ struct RecoveryValidityCheck { let recoveryStatus = Validator.validate(currentDate, from: validityStart, to: validityEnd, extendedTo: validityExtension) - let scanMode: String = Store.get(key: .scanMode) ?? "" guard scanMode != Constants.scanModeBooster else { return recoveryStatus == .valid ? .verificationIsNeeded : recoveryStatus } return recoveryStatus } + private func getStartDays3G(from hcert: HCert) -> Int? { + let isITCode = hcert.countryCode == Constants.ItalyCountryCode + let startDaysConfig: String + if isSpecialRecovery(hcert: hcert){ + startDaysConfig = Constants.recoverySpecialStartDays + } + else { + startDaysConfig = isITCode ? Constants.recoveryStartDays_IT : Constants.recoveryStartDays_NOT_IT + } + return getValue(for: startDaysConfig)?.intValue + } + + private func getEndDays3G(from hcert: HCert) -> Int? { + let isITCode = hcert.countryCode == Constants.ItalyCountryCode + let startDaysConfig: String + if isSpecialRecovery(hcert: hcert){ + startDaysConfig = Constants.recoverySpecialEndDays + } + else { + startDaysConfig = isITCode ? Constants.recoveryEndDays_IT : Constants.recoveryEndDays_NOT_IT + } + return getValue(for: startDaysConfig)?.intValue + } + private func getStartDays(from hcert: HCert) -> Int? { - let startDaysConfig = isSpecialRecovery(hcert: hcert) ? Constants.recoverySpecialStartDays : Constants.recoveryStartDays + let startDaysConfig = isSpecialRecovery(hcert: hcert) ? Constants.recoverySpecialStartDays : Constants.recoveryStartDays_IT return getValue(for: startDaysConfig)?.intValue } private func getEndDays(from hcert: HCert) -> Int? { - let endDaysConfig = isSpecialRecovery(hcert: hcert) ? Constants.recoverySpecialEndDays : Constants.recoveryEndDays + let endDaysConfig = isSpecialRecovery(hcert: hcert) ? Constants.recoverySpecialEndDays : Constants.recoveryEndDays_IT return getValue(for: endDaysConfig)?.intValue } diff --git a/DGCAVerifier/BusinessRules/Internal/VaccineValidityCheck.swift b/DGCAVerifier/BusinessRules/Internal/VaccineValidityCheck.swift index d4f51d9..e4a3d65 100644 --- a/DGCAVerifier/BusinessRules/Internal/VaccineValidityCheck.swift +++ b/DGCAVerifier/BusinessRules/Internal/VaccineValidityCheck.swift @@ -1,20 +1,20 @@ /* * license-start - * + * * Copyright (C) 2021 Ministero della Salute 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. -*/ + */ // // VaccineValidityCheck.swift @@ -27,84 +27,218 @@ import Foundation import SwiftDGC struct VaccineValidityCheck { - - typealias Validator = MedicalRulesValidator - - private var allowedVaccinationInCountry: [String: [String]] { - [Constants.SputnikVacineCode: [Constants.sanMarinoCode]] - } - - func isVaccineDateValid(_ hcert: HCert) -> Status { - guard let currentDoses = hcert.currentDosesNumber else { return .notValid } - guard let totalDoses = hcert.totalDosesNumber else { return .notValid } - guard currentDoses > 0 else { return .notValid } - guard totalDoses > 0 else { return .notValid } - let lastDose = currentDoses >= totalDoses - - guard let product = hcert.medicalProduct else { return .notValid } - guard isValid(for: product) else { return .notValid } - guard let countryCode = hcert.countryCode else { return .notValid } - guard isAllowedVaccination(for: product, fromCountryWithCode: countryCode) else { return .notValid } - - guard let start = getStartDays(for: product, lastDose) else { return .notGreenPass } - guard let end = getEndDays(for: product, lastDose) else { return .notGreenPass } - - guard let dateString = hcert.vaccineDate else { return .notValid } - guard let date = dateString.toVaccineDate else { return .notValid } - guard let validityStart = date.add(start, ofType: .day) else { return .notValid } - guard let validityEnd = date.add(end, ofType: .day)?.startOfDay else { return .notValid } - - guard let currentDate = Date.startOfDay else { return .notValid } - - let isJJ = hcert.medicalProduct == Constants.JeJVacineCode - let isJJBooster = isJJ && isaJJBoosterDose(current: currentDoses, total: totalDoses) - let fromDate = isJJBooster ? date : validityStart - - let result = Validator.validate(currentDate, from: fromDate, to: validityEnd) - - guard result == .valid else { return result } - - let scanMode: String = Store.get(key: .scanMode) ?? "" - if scanMode == Constants.scanModeBooster { - let isaBoosterDose = currentDoses > totalDoses || - currentDoses >= Constants.boosterMinimumDosesNumber || isJJBooster + + typealias Validator = MedicalRulesValidator + + private var allowedVaccinationInCountry: [String: [String]] { + [Constants.SputnikVacineCode: [Constants.sanMarinoCode]] + } + + struct CertificatePreconditions { + let currentDoses: Int + let totalDoses: Int + let medicalProduct: String + let vaccineDate: Date + let countryCode: String + + var isIT: Bool { + return self.countryCode.uppercased() == Constants.ItalyCountryCode + } + + var isJJ: Bool { + return self.medicalProduct == Constants.JeJVacineCode + } + + var isJJBooster: Bool { + return self.isJJ && (self.currentDoses >= Constants.jjBoosterMinimumDosesNumber) + } + + var isNonJJBooster: Bool { + return !self.isJJ && (self.currentDoses >= Constants.boosterMinimumDosesNumber) + } + + var isCurrentDoseIncomplete: Bool { + return self.currentDoses < self.totalDoses + } + + var isCurrentDoseComplete: Bool { + return self.currentDoses == self.totalDoses + } + + /// Valid booster dose JJ or any other + var isCurrentDoseBooster: Bool { + return (self.currentDoses > self.totalDoses) || (isJJBooster || self.isNonJJBooster) + } + } + + func checkPreconditions(_ hcert: HCert) -> CertificatePreconditions? { + guard let currentDoses = hcert.currentDosesNumber, currentDoses > 0 else { return nil } + guard let totalDoses = hcert.totalDosesNumber, totalDoses > 0 else { return nil } + guard let vaccineDate = hcert.vaccineDate?.toVaccineDate else { return nil } + guard let medicalProduct = hcert.medicalProduct else { return nil } + guard isValid(for: medicalProduct) else { return nil } + guard let countryCode = hcert.countryCode else { return nil } + guard isAllowedVaccination(for: medicalProduct, fromCountryWithCode: countryCode) else { return nil } + + return CertificatePreconditions(currentDoses: currentDoses, totalDoses: totalDoses, medicalProduct: medicalProduct, vaccineDate: vaccineDate, countryCode: countryCode) + } + + func checkCertificateDate(_ preconditions: CertificatePreconditions) -> Status { + let scanMode: String = Store.get(key: .scanMode) ?? "" + + guard let start = getStartDays(scanMode: scanMode, preconditions: preconditions) else { return .notValid } + guard let end = getEndDays(scanMode: scanMode, preconditions: preconditions) else { return .notValid } + + guard let validityStart = preconditions.vaccineDate.add(start, ofType: .day) else { return .notValid } + guard let validityEnd = preconditions.vaccineDate.add(end, ofType: .day)?.startOfDay else { return .notValid } + + guard let currentDate = Date.startOfDay else { return .notValid } + + // J&J booster is immediately valid + let fromDate = preconditions.isJJBooster ? preconditions.vaccineDate : validityStart + + return Validator.validate(currentDate, from: fromDate, to: validityEnd) + } + + func isScanModeBooster() -> Bool { + let scanMode: String = Store.get(key: .scanMode) ?? "" + return scanMode == Constants.scanModeBooster + } + + func checkBooster(_ preconditions: CertificatePreconditions) -> Status { + if preconditions.isCurrentDoseBooster { return . valid } + + return preconditions.isCurrentDoseComplete ? .verificationIsNeeded : .notValid + } + + func isVaccineValid(_ hcert: HCert) -> Status { + guard let preconditions = checkPreconditions(hcert) else { return .notValid } + let result = checkCertificateDate(preconditions) + + guard result == .valid else { return result } + + guard !isScanModeBooster() else { + return checkBooster(preconditions) + } + + return result + } + + private func isaJJBoosterDose(current: Int, total: Int) -> Bool { + return current >= Constants.jjBoosterMinimumDosesNumber + } + + private func isAllowedVaccination(for medicalProduct: String, fromCountryWithCode countryCode: String) -> Bool { + if let allowedCountries = allowedVaccinationInCountry[medicalProduct] { + return allowedCountries.contains(countryCode) + } + return true + } + + private func isValid(for medicalProduct: String) -> Bool { + // Vaccine code not included in settings -> not a valid vaccine for Italy + let name = Constants.vaccineCompleteEndDays + return getValue(for: name, type: medicalProduct) != nil + } + + private func getStartDays(scanMode: String, preconditions: CertificatePreconditions) -> Int? { + switch(scanMode) { + case Constants.scanMode3G: + if preconditions.isCurrentDoseBooster { + let settingName: String = preconditions.isIT ? Constants.vaccineBoosterStartDays_IT : Constants.vaccineBoosterStartDays_NOT_IT + return self.getValue(for: settingName)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteStartDays, type: preconditions.medicalProduct)?.intValue + } - if isaBoosterDose { return . valid } - return lastDose ? .verificationIsNeeded : .notValid - } + if preconditions.isJJ { + let settingName = Constants.vaccineCompleteStartDays + return self.getValue(for: settingName, type: preconditions.medicalProduct)?.intValue + } + let settingName = preconditions.isIT ? Constants.vaccineCompleteStartDays_IT : Constants.vaccineCompleteStartDays_NOT_IT + return self.getValue(for: settingName)?.intValue + + case Constants.scanMode2G: + if preconditions.isCurrentDoseBooster { + return self.getValue(for: Constants.vaccineBoosterStartDays_IT)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteStartDays, type: preconditions.medicalProduct)?.intValue + } + + if preconditions.isJJ { + let settingName = Constants.vaccineCompleteStartDays + return self.getValue(for: settingName, type: preconditions.medicalProduct)?.intValue + } + return self.getValue(for: Constants.vaccineCompleteStartDays_IT)?.intValue + case Constants.scanModeBooster: + if preconditions.isCurrentDoseBooster { + return self.getValue(for: Constants.vaccineBoosterStartDays_IT)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteStartDays, type: preconditions.medicalProduct)?.intValue + } + + if preconditions.isJJ { + let settingName = Constants.vaccineCompleteStartDays + return self.getValue(for: settingName, type: preconditions.medicalProduct)?.intValue + } + return self.getValue(for: Constants.vaccineCompleteStartDays_IT)?.intValue + default: + return nil + } + } + + private func getEndDays(scanMode: String, preconditions: CertificatePreconditions) -> Int? { + switch(scanMode) { + case Constants.scanMode3G: + if preconditions.isCurrentDoseBooster { + let settingName: String = preconditions.isIT ? Constants.vaccineBoosterEndDays_IT : Constants.vaccineBoosterEndDays_NOT_IT + return self.getValue(for: settingName)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteEndDays, type: preconditions.medicalProduct)?.intValue + } + + let settingName = preconditions.isIT ? Constants.vaccineCompleteEndDays_IT : Constants.vaccineCompleteEndDays_NOT_IT + return self.getValue(for: settingName)?.intValue + case Constants.scanMode2G: + if preconditions.isCurrentDoseBooster { + return self.getValue(for: Constants.vaccineBoosterEndDays_IT)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteEndDays, type: preconditions.medicalProduct)?.intValue + } + + return self.getValue(for: Constants.vaccineCompleteEndDays_IT)?.intValue + case Constants.scanModeBooster: + if preconditions.isCurrentDoseBooster { + return self.getValue(for: Constants.vaccineBoosterEndDays_IT)?.intValue + } + + if preconditions.isCurrentDoseIncomplete { + return self.getValue(for: Constants.vaccineIncompleteEndDays, type: preconditions.medicalProduct)?.intValue + } + + return self.getValue(for: Constants.vaccineCompleteEndDays_IT)?.intValue + default: + return nil + } + } + + private func getValue(for name: String, type: String) -> String? { + return LocalData.getSetting(from: name, type: type) + } + + private func getValue(for name: String) -> String? { + return LocalData.getSetting(from: name) + } - return result - } - - private func isaJJBoosterDose(current: Int, total: Int) -> Bool { - return current > total || (current == total && current >= Constants.jjBoosterMinimumDosesNumber) - } - - private func isAllowedVaccination(for medicalProduct: String, fromCountryWithCode countryCode: String) -> Bool { - if let allowedCountries = allowedVaccinationInCountry[medicalProduct] { - return allowedCountries.contains(countryCode) - } - return true - } - - private func isValid(for medicalProduct: String) -> Bool { - // Vaccine code not included in settings -> not a valid vaccine for Italy - let name = Constants.vaccineCompleteEndDays - return getValue(for: name, type: medicalProduct) != nil - } - - private func getStartDays(for medicalProduct: String, _ isLastDose: Bool) -> Int? { - let name = isLastDose ? Constants.vaccineCompleteStartDays : Constants.vaccineIncompleteStartDays - return getValue(for: name, type: medicalProduct)?.intValue - } - - private func getEndDays(for medicalProduct: String, _ isLastDose: Bool) -> Int? { - let name = isLastDose ? Constants.vaccineCompleteEndDays : Constants.vaccineIncompleteEndDays - return getValue(for: name, type: medicalProduct)?.intValue - } - - private func getValue(for name: String, type: String) -> String? { - return LocalData.getSetting(from: name, type: type) - } - } + diff --git a/DGCAVerifier/BusinessRules/MedicalRulesValidator.swift b/DGCAVerifier/BusinessRules/MedicalRulesValidator.swift index 88f2c5b..6c23dcf 100644 --- a/DGCAVerifier/BusinessRules/MedicalRulesValidator.swift +++ b/DGCAVerifier/BusinessRules/MedicalRulesValidator.swift @@ -37,7 +37,7 @@ struct MedicalRulesValidator: Validator { return testValidityCheck.isTestValid(hCert) case .vaccine: let vaccineValidityCheck = VaccineValidityCheck() - return vaccineValidityCheck.isVaccineDateValid(hCert) + return vaccineValidityCheck.isVaccineValid(hCert) case .recovery: let recoveryValidityCheck = RecoveryValidityCheck() return recoveryValidityCheck.isRecoveryValid(hCert) diff --git a/DGCAVerifier/Models/Constants.swift b/DGCAVerifier/Models/Constants.swift index efb06d6..a9b7fc9 100644 --- a/DGCAVerifier/Models/Constants.swift +++ b/DGCAVerifier/Models/Constants.swift @@ -38,6 +38,16 @@ struct Constants { static let vaccineIncompleteEndDays = "vaccine_end_day_not_complete" static let vaccineCompleteStartDays = "vaccine_start_day_complete" static let vaccineCompleteEndDays = "vaccine_end_day_complete" + + static let vaccineCompleteStartDays_IT = "vaccine_start_day_complete_IT" + static let vaccineCompleteEndDays_IT = "vaccine_end_day_complete_IT" + static let vaccineCompleteStartDays_NOT_IT = "vaccine_start_day_complete_NOT_IT" + static let vaccineCompleteEndDays_NOT_IT = "vaccine_end_day_complete_NOT_IT" + static let vaccineBoosterStartDays_IT = "vaccine_start_day_booster_IT" + static let vaccineBoosterEndDays_IT = "vaccine_end_day_booster_IT" + static let vaccineBoosterStartDays_NOT_IT = "vaccine_start_day_booster_NOT_IT" + static let vaccineBoosterEndDays_NOT_IT = "vaccine_end_day_booster_NOT_IT" + static let JeJVacineCode = "EU/1/20/1525" static let SputnikVacineCode = "Sputnik-V" static let sanMarinoCode = "SM" @@ -45,6 +55,10 @@ struct Constants { // RecoveryValidityCheck static let recoveryStartDays = "recovery_cert_start_day" static let recoveryEndDays = "recovery_cert_end_day" + static let recoveryStartDays_IT = "recovery_cert_start_day_IT" + static let recoveryEndDays_IT = "recovery_cert_end_day_IT" + static let recoveryStartDays_NOT_IT = "recovery_cert_start_day_NOT_IT" + static let recoveryEndDays_NOT_IT = "recovery_cert_end_day_NOT_IT" static let recoverySpecialStartDays = "recovery_pv_cert_start_day" static let recoverySpecialEndDays = "recovery_pv_cert_end_day" static let OID_RECOVERY = "1.3.6.1.4.1.1847.2021.1.3" diff --git a/DGCAVerifierTests/HCertGenerator.swift b/DGCAVerifierTests/HCertGenerator.swift new file mode 100644 index 0000000..553e031 --- /dev/null +++ b/DGCAVerifierTests/HCertGenerator.swift @@ -0,0 +1,47 @@ +// +// PayloadGenerator.swift +// VerificaC19 +// +// Created by Johnny Bueti on 28/01/22. +// + +import Foundation +@testable import VerificaC19 +@testable import SwiftDGC +import SwiftyJSON + +/// Provides helper functions that generate dummy QRCode digital green certificates that carry the provided characteristics, aimed at unit testing. +internal class PayloadGenerator { + + /// A manually generated vaccine payload used as base to generate a customizable `HCert`. + private static let dummyVaccinePayload = "HC1:6BFOXN%TS3DHPVO13J /G-/2YRVA.Q/R82JD2FCJG96V75DOW%IY17EIHY P8L6IWM$S4U45P84HW6U/4:84LC6 YM::QQHIZC4.OI1RM8ZA.A5:S9MKN4NN3F85QNCY0O%0VZ001HOC9JU0D0HT0HB2PL/IB*09B9LW4T*8+DCMH0LDK2%KI*V AQ2%KYZPQV6YP8722XOE7:8IPC2L4U/6H1D31BLOETI0K/4VMA/.6LOE:/8IL882B+SGK*R3T3+7A.N88J4R$F/MAITHW$P7S3-G9++9-G9+E93ZM$96TV6QRR 1JI7JSTNCA7G6MXYQYYQQKRM64YVQB95326FW4AJOMKMV35U:7-Z7QT499RLHPQ15O+4/Z6E 6U963X7$8Q$HMCP63HU$*GT*Q3-Q4+O7F6E%CN4D74DWZJ$7K+ CZEDB2M$9C1QD7+2K3475J%6VAYCSP0VSUY8WU9SG43A-RALVMO8+-VD2PRPTB7S015SSFW/BE1S1EV*2Q396Q*4TVNAZHJ7N471FPL-CA+2KG-6YPPB7C%40F18N4" + + /// A manually generated test payload used as base to generate a customizable `HCert`. + private static let dummyTestPayload = "HC1:6BFOXN%TS3DHPVO13J /G-/2YRVA.Q/R8H:I2FCJG9AE1O/CGJ9-J3P+GY P8L6IWM$S4U45P84HW6U/4:84LC6 YM::QQHIZC4.OI:OIG/Q80PWW2G%89-8CNNM3LO%0WA46+8F/8A.A94LVZ0H*AYZ0MKNAB5S.8%*8Z95NEL6T98VA8YISLV423VLJ0JBIFT/1541TS+0C4TV*C*K5-ZVMHFIFT.HBC77PM5LXK$4JSZ4P:45/GK%I74J9.SXTC69TQ0SG JK423UJ*IBLOIWHSJZI+EBI.CHFTQMCA.SF*SSMCU3TNQ4TR9Y$H5%HTR9C/P0Q3%*JMY54W1XYH9W1OH6NFEYY57Q4UYQD*O%+Q.SQBDO3KLB75EHPSGO0IQOGOE34L/5R3FOKEH-BK2L88LNUMD78*7LMIAK/BGP95MG/IC3DAF:F6LF7E9Y7M-CI73A3 9-QDSRD1PC6LFE1KEJC%:CMNSQ98N:21 2O*4R60NM8JI0EUGP$I/XK$M8ZQE6YB9M66P8N31TMC3FD5I7NZLDMOCY7H6UPC9A7I*-E Y7-XPZP5CWQXAUHO6O5M1-V1ENE*N +2:ONETEKTFV5ENQMHZF.+E:OUL4NLEQY$HPMGP2G/20165T1" + + /// A manually generated recovery payload used as base to generate a customizable `HCert`. + private static let dummyRecoveryPayload = "HC1:6BFOXN%TS3DHPVO13J /G-/2YRVA.Q/R8WRU2FCAH9BDF%188WA.*RXU7IJ6W*PP+PDPIGOK-*GN*Q:XJR-GM%O-RQOTAF/8X*G3M9FQH+4J/-K$+CY73JC3MD3IFTKJ3SZ4P:45/GZW4:.AY731MF7FN6LBHKBCAJPF71M3.FJZIJ09B*KNQ579PJMD3+476J3:NB3N5XW49+20CMAHLW 70SO:GOLIROGOAQ5ZU4RKCSHGX2M5C9HHB%LGJZII7JSTNCA7G6MXYQYYQQKRM64YVQB95326FW4AJOMKMV35U:7-Z7QT499RLHPQ15O+4/Z6E 6U963X7$8Q$HMCP63HU$*GT*Q3-Q4+O7F6E%CN4D74DWZJ$7K+ CZEDB2M$9C1QD7+2*KUQFCOYA73A-MG*VM%UUY$MW5LM+GW*1.Q5$Y7M-FSYLJF3*TRJY9R.8VBQA65%UVLXFTYVN T$WM3 UJ16F:S0CLRVJAD7KOB1GV+20RT8S0" + + /// A manually generated revocation payload used as base to generate a customizable `HCert`. + /// It internally returns the dummy vaccine payload. + private static var dummyRevocationPayload: String { + return self.dummyVaccinePayload + } + + /// A customizable `HCert` generated from the dummy base payload. + private static var dummyHCert: HCert { + var hcert: HCert? = HCert(from: self.dummyVaccinePayload) + let bodyString: String = "{\"4\": 1628553600, \"6\": 1620926082, \"1\": \"Ministero della Salute\", \"-260\": {\"1\": {\"ver\": \"1.0.0\", \"dob\": \"1977-06-16\", \"v\": [{\"ma\": \"ORG-100030215\", \"sd\": 2, \"dt\": \"2021-06-08\", \"co\": \"IT\", \"ci\": \"01IT67DA8332EF2C4E6780ABA5DF078A018E#0\", \"mp\": \"EU/1/20/1528\", \"is\": \"Ministero della Salute\", \"tg\": \"840539006\", \"vp\": \"1119349007\", \"dn\": 2}], \"nam\": {\"gnt\": \"MARILU