From e7cf6a1c2d6320fc095058add6652eb7e1663af4 Mon Sep 17 00:00:00 2001 From: Gianmarco Pettinato Date: Sun, 26 Sep 2021 17:30:42 +0200 Subject: [PATCH] semplified the validity check process --- .../CertificateDownloader.test.ts | 66 +++++++++++++++++-- .../CertificateDownloader.ts | 5 +- .../SettingsDownloader/RuleDownloader.spec.ts | 22 +++---- .../SettingsDownloader/RuleDownloader.ts | 2 - .../dgcVerifier/VaccineVerifier.spec.ts | 25 +++++++ src/Services/dgcVerifier/VaccineVerifier.ts | 21 +++--- src/Services/dgcVerifier/Verifier.ts | 5 +- 7 files changed, 108 insertions(+), 38 deletions(-) create mode 100644 src/Services/dgcVerifier/VaccineVerifier.spec.ts diff --git a/src/Services/SettingsDownloader/CertificateDownloader.test.ts b/src/Services/SettingsDownloader/CertificateDownloader.test.ts index 7b29075..8c4245a 100644 --- a/src/Services/SettingsDownloader/CertificateDownloader.test.ts +++ b/src/Services/SettingsDownloader/CertificateDownloader.test.ts @@ -1,7 +1,65 @@ -describe('CertificateDownloader',()=>{ + +import { CertificateDownloader } from './CertificateDownloader'; +import mock from 'mock-fs'; +import axios, { AxiosResponse } from 'axios'; +jest.mock('axios'); + +const certifcateDownloader = new CertificateDownloader(); +const testCetificate = 'MIICyzCCAnGgAwIBAgIBATAKBggqhkjOPQQDAjCBqTELMAkGA1UEBhMCREsxKTAnBgNVBAoMIFRoZSBEYW5pc2ggSGVhbHRoIERhdGEgQXV0aG9yaXR5MSkwJwYDVQQLDCBUaGUgRGFuaXNoIEhlYWx0aCBEYXRhIEF1dGhvcml0eTEcMBoGA1UEAwwTUFJPRF9DU0NBX0RHQ19ES18wMTEmMCQGCSqGSIb3DQEJARYXa29udGFrdEBzdW5kaGVkc2RhdGEuZGswHhcNMjEwNTE5MDk0NzI1WhcNMjMwNTIwMDk0NzI1WjCBqDELMAkGA1UEBhMCREsxKTAnBgNVBAoMIFRoZSBEYW5pc2ggSGVhbHRoIERhdGEgQXV0aG9yaXR5MSkwJwYDVQQLDCBUaGUgRGFuaXNoIEhlYWx0aCBEYXRhIEF1dGhvcml0eTEbMBkGA1UEAwwSUFJPRF9EU0NfREdDX0RLXzAxMSYwJAYJKoZIhvcNAQkBFhdrb250YWt0QHN1bmRoZWRzZGF0YS5kazBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAZnYGP1TkbHnF8WP9MTTTs6CTUWlZzDJh7OY4l6xr2gzstY8w1Dsr0fvicYH9PmLhsqef1AGNECIe'; +const kidHeader = 'NAyCKly+hCg='; +const testCollecion = [{kid:kidHeader,certificate:testCetificate}]; +let resumeToken = 2; +const allKids = ['NAyCKly+hCg=', '25QCxBrBJvA=', 'ODqaG8mnbro=', 'e4lH6I4iMIM=']; +const validKid = ['NAyCKly+hCg=']; +let responseCounter = 0; + +const mockedAxios = axios as jest.Mocked; +const axiosResponseCertificates = (data: any): AxiosResponse => { + console.log('axios mock ', data); + const status = (responseCounter < allKids.length -1)? 200 : 204; + return { + data: testCetificate, + status, + statusText: 'OK', + headers:{ + 'x-kid':allKids[responseCounter++], + 'x-resume-token':resumeToken++, + }, + config:{} + }; +}; + +const axioResponseValidKids: AxiosResponse = { + data: validKid, + status: 200, + statusText: 'OK', + headers:{}, + config:{} +}; + +describe('CertificateDownloader', ()=>{ describe('getCertificates()',()=>{ - it('placeholder',()=>{ - expect(false).toBe(false); + test('Testing getCertificates basic outcome: file loaded from local source and is still valid',async ()=>{ + mock({ + './cerificate_collection.json': Buffer.from(JSON.stringify({certificates:testCollecion,lastupdateDate:Date.now()})) + }); + const collection = await certifcateDownloader.getCertificates(); + mock.restore(); + expect(JSON.stringify(collection)).toBe(JSON.stringify(testCollecion)); }); + // test('Testing getRules basic outcome: file loaded from local source and is expired',async ()=>{ + // mockedAxios.get.mockResolvedValueOnce(axioResponseValidKids); + // mockedAxios.get.mockResolvedValueOnce(axiosResponseCertificates); + + // const date = Date.now() - 86400010; + // mock({ + // './cerificate_collection.json': Buffer.from(JSON.stringify({certificates:testCollecion,lastupdateDate:date})) + // }); + // expect(axios.get).not.toHaveBeenCalled(); + // const collection = await certifcateDownloader.getCertificates(); + // expect(axios.get).toHaveBeenCalled(); + // mock.restore(); + // expect(JSON.stringify(collection)).toBe(JSON.stringify(testCollecion)); + // }); }); -}); \ No newline at end of file +}); diff --git a/src/Services/SettingsDownloader/CertificateDownloader.ts b/src/Services/SettingsDownloader/CertificateDownloader.ts index bdf76b0..06aa647 100644 --- a/src/Services/SettingsDownloader/CertificateDownloader.ts +++ b/src/Services/SettingsDownloader/CertificateDownloader.ts @@ -6,7 +6,7 @@ export class CertificateDownloader{ private readonly baseUrl = 'https://get.dgc.gov.it'; private readonly updateApi = '/v1/dgc/signercertificate/update' private readonly statusApi = '/v1/dgc/signercertificate/status' - private readonly keyStorage = './cerificate_collection.json'; + private readonly keyStorage = './certificate_collection.json'; private readonly timeSpan = 86400000; // private readonly timeSpan = 1; private certificatesCollection:{kid:string,certificate:string}[] = []; @@ -27,7 +27,8 @@ export class CertificateDownloader{ } return this.certificatesCollection; } catch (error) { - if(error.message == 'ENOENT: no such file or directory, open \'rules.json\''){ + console.log(error.message); + if(error.message == 'ENOENT: no such file or directory, open \'./certificate_collection.json\''){ await fs.writeFile(this.keyStorage,'{}'); return this.getCertificates(); } diff --git a/src/Services/SettingsDownloader/RuleDownloader.spec.ts b/src/Services/SettingsDownloader/RuleDownloader.spec.ts index 2a73112..8b07874 100644 --- a/src/Services/SettingsDownloader/RuleDownloader.spec.ts +++ b/src/Services/SettingsDownloader/RuleDownloader.spec.ts @@ -30,8 +30,8 @@ describe('RuleDownloader', ()=>{ mock.restore(); expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules)); }); - test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{ - mockedAxios.get.mockResolvedValue(successResposnse); + test('Testing getRules basic outcome: file loaded from local source is expired download a new one',async ()=>{ + mockedAxios.get.mockResolvedValueOnce(successResposnse); const date = Date.now() - 86400010; mock({ './rules.json': Buffer.from(JSON.stringify({rules:mockRules,lastupdateDate:date})) @@ -42,17 +42,11 @@ describe('RuleDownloader', ()=>{ mock.restore(); expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules)); }); - test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{ - mock({}); - try { - mockedAxios.get.mockResolvedValue(successResposnse); - const rules = await ruleDownloader.getRules(); - mock.restore(); - expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules)); - } catch (error) { - console.log(error); - } - - }); + // test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{ + // mockedAxios.get.mockResolvedValueOnce(successResposnse); + // expect(axios.get).not.toHaveBeenCalled(); + // const rules = await ruleDownloader.getRules(); + // expect(axios.get).toHaveBeenCalled(); + // }); }); }); diff --git a/src/Services/SettingsDownloader/RuleDownloader.ts b/src/Services/SettingsDownloader/RuleDownloader.ts index ebd1752..fd9492e 100644 --- a/src/Services/SettingsDownloader/RuleDownloader.ts +++ b/src/Services/SettingsDownloader/RuleDownloader.ts @@ -32,9 +32,7 @@ export class RuleDownloader { private async getSettings(): Promise{ const response:AxiosResponse = await axios.get(`${this.baseUrl}/v1/dgc/settings`); const jsonData = response.data; - // this.rules = Rule.fromJSON(jsonData,{valueSets, validationClock:new Date().toISOString(),}) this.rules = jsonData; - // localStorage.setItem(this.keyStorage, JSON.stringify({rules:this.rules,lastupdateDate:Date.now()})); const file = await fs.open(this.keyStorage,'w'); await file.writeFile(JSON.stringify({rules:this.rules,lastupdateDate:Date.now()})); await file.close(); diff --git a/src/Services/dgcVerifier/VaccineVerifier.spec.ts b/src/Services/dgcVerifier/VaccineVerifier.spec.ts new file mode 100644 index 0000000..defe0c1 --- /dev/null +++ b/src/Services/dgcVerifier/VaccineVerifier.spec.ts @@ -0,0 +1,25 @@ +describe('VaccineVerifier',()=>{ + describe('checkCertifcate',()=>{ + it('Valid vaccine',()=>{ + expect(true).toBe(true); + }); + it('Expired vaccine',()=>{ + expect(true).toBe(true); + }); + it('Yet to be valid vaccine',()=>{ + expect(true).toBe(true); + }); + it('Test vaccine',()=>{ + expect(true).toBe(true); + }); + it('Expired Test',()=>{ + expect(true).toBe(true); + }); + it('Yet to be valid Test',()=>{ + expect(true).toBe(true); + }); + it('Positive Test',()=>{ + expect(true).toBe(true); + }); + }); +}); \ No newline at end of file diff --git a/src/Services/dgcVerifier/VaccineVerifier.ts b/src/Services/dgcVerifier/VaccineVerifier.ts index 78366d8..87d0cff 100644 --- a/src/Services/dgcVerifier/VaccineVerifier.ts +++ b/src/Services/dgcVerifier/VaccineVerifier.ts @@ -1,4 +1,3 @@ -import {DCC} from 'dcc-utils'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; @@ -38,7 +37,6 @@ export class VaccineVerifier { if(vaccineDiff <= 0){ return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayComplete, this.vaccineEndDayComplete,inoculationDate); } else { - console.log('single dose'); return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayNotComplete, this.vaccineEndDayNotComplete,inoculationDate); } } @@ -80,20 +78,20 @@ export class VaccineVerifier { this.settings = settings; } - public checkCertifcate(pass:DCC):checkResult { - console.log(pass.payload); - const payloadAndType = this.getPayloadAndType(pass); - const result: checkResult = this.functionSelector[payloadAndType.key](payloadAndType.payload); + public checkCertifcate(pass:unknown):checkResult { + console.log(pass); + const certificateDataAndType = this.getCertificateData(pass); + const result: checkResult = this.functionSelector[certificateDataAndType.key](certificateDataAndType.certificateData); return result; } - private getPayloadAndType(pass:DCC): {key:string,payload:unknown}{ - const result:{key:string,payload:unknown} = {key:'',payload:[]}; + private getCertificateData(pass:unknown): {key:string,certificateData:unknown}{ + const result:{key:string,certificateData:unknown} = {key:'',certificateData:[]}; this.certTypes.forEach((key:string) => { - if(pass.payload[key] != undefined){ - if((pass.payload[key] as unknown[]).length != 0){ + if(pass[key] != undefined){ + if((pass[key] as unknown[]).length != 0){ result.key =(key); - result.payload = (pass.payload[key][pass.payload[key].length -1]); + result.certificateData = (pass[key][pass[key].length -1]); } } }); @@ -108,7 +106,6 @@ export class VaccineVerifier { private getLogicValidityDays(validRulesSet:unknown[],startKey:string, endKey:string, inoculationDate: dayjs.Dayjs): checkResult { const now = dayjs(); - console.log(validRulesSet); const ruleStart = validRulesSet.find((elem:any)=>{return elem.name == startKey;}); const ruleEnd = validRulesSet.find((elem:any)=>{return elem.name == endKey;}); const startValidity = inoculationDate.add(parseInt(ruleStart['value']),'days'); diff --git a/src/Services/dgcVerifier/Verifier.ts b/src/Services/dgcVerifier/Verifier.ts index ef267e7..332570c 100644 --- a/src/Services/dgcVerifier/Verifier.ts +++ b/src/Services/dgcVerifier/Verifier.ts @@ -23,14 +23,11 @@ export default class Verifier { } async checkCertificate(certificate:string): Promise{ - console.log(certificate); const dcc = await DCC.fromRaw(certificate); - console.log(dcc.payload); let result:unknown = {}; result = await this.checkKey(dcc); const vaccineVerifier = new VaccineVerifier(await this.ruleDownloader.getRules()); - result = {signature: result, valid: vaccineVerifier.checkCertifcate(dcc)}; - console.log(result); + result = {signature: result, valid: vaccineVerifier.checkCertifcate(dcc.payload)}; return result; }