semplified the validity check process

This commit is contained in:
Gianmarco Pettinato 2021-09-26 17:30:42 +02:00
parent 71d7c0531d
commit e7cf6a1c2d
7 changed files with 108 additions and 38 deletions

View File

@ -1,7 +1,65 @@
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<typeof axios>;
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('CertificateDownloader', ()=>{
describe('getCertificates()',()=>{ describe('getCertificates()',()=>{
it('placeholder',()=>{ test('Testing getCertificates basic outcome: file loaded from local source and is still valid',async ()=>{
expect(false).toBe(false); 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));
// });
}); });
}); });

View File

@ -6,7 +6,7 @@ export class CertificateDownloader{
private readonly baseUrl = 'https://get.dgc.gov.it'; private readonly baseUrl = 'https://get.dgc.gov.it';
private readonly updateApi = '/v1/dgc/signercertificate/update' private readonly updateApi = '/v1/dgc/signercertificate/update'
private readonly statusApi = '/v1/dgc/signercertificate/status' 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 = 86400000;
// private readonly timeSpan = 1; // private readonly timeSpan = 1;
private certificatesCollection:{kid:string,certificate:string}[] = []; private certificatesCollection:{kid:string,certificate:string}[] = [];
@ -27,7 +27,8 @@ export class CertificateDownloader{
} }
return this.certificatesCollection; return this.certificatesCollection;
} catch (error) { } 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,'{}'); await fs.writeFile(this.keyStorage,'{}');
return this.getCertificates(); return this.getCertificates();
} }

View File

@ -30,8 +30,8 @@ describe('RuleDownloader', ()=>{
mock.restore(); mock.restore();
expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules)); expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules));
}); });
test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{ test('Testing getRules basic outcome: file loaded from local source is expired download a new one',async ()=>{
mockedAxios.get.mockResolvedValue(successResposnse); mockedAxios.get.mockResolvedValueOnce(successResposnse);
const date = Date.now() - 86400010; const date = Date.now() - 86400010;
mock({ mock({
'./rules.json': Buffer.from(JSON.stringify({rules:mockRules,lastupdateDate:date})) './rules.json': Buffer.from(JSON.stringify({rules:mockRules,lastupdateDate:date}))
@ -42,17 +42,11 @@ describe('RuleDownloader', ()=>{
mock.restore(); mock.restore();
expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules)); expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules));
}); });
test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{ // test('Testing getRules basic outcome: file loaded from local source and is still valid',async ()=>{
mock({}); // mockedAxios.get.mockResolvedValueOnce(successResposnse);
try { // expect(axios.get).not.toHaveBeenCalled();
mockedAxios.get.mockResolvedValue(successResposnse); // const rules = await ruleDownloader.getRules();
const rules = await ruleDownloader.getRules(); // expect(axios.get).toHaveBeenCalled();
mock.restore(); // });
expect(JSON.stringify(rules)).toBe(JSON.stringify(mockRules));
} catch (error) {
console.log(error);
}
});
}); });
}); });

View File

@ -32,9 +32,7 @@ export class RuleDownloader {
private async getSettings(): Promise<unknown[]>{ private async getSettings(): Promise<unknown[]>{
const response:AxiosResponse<unknown[]> = await axios.get(`${this.baseUrl}/v1/dgc/settings`); const response:AxiosResponse<unknown[]> = await axios.get(`${this.baseUrl}/v1/dgc/settings`);
const jsonData = response.data; const jsonData = response.data;
// this.rules = Rule.fromJSON(jsonData,{valueSets, validationClock:new Date().toISOString(),})
this.rules = jsonData; this.rules = jsonData;
// localStorage.setItem(this.keyStorage, JSON.stringify({rules:this.rules,lastupdateDate:Date.now()}));
const file = await fs.open(this.keyStorage,'w'); const file = await fs.open(this.keyStorage,'w');
await file.writeFile(JSON.stringify({rules:this.rules,lastupdateDate:Date.now()})); await file.writeFile(JSON.stringify({rules:this.rules,lastupdateDate:Date.now()}));
await file.close(); await file.close();

View File

@ -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);
});
});
});

View File

@ -1,4 +1,3 @@
import {DCC} from 'dcc-utils';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc'; import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone'; import timezone from 'dayjs/plugin/timezone';
@ -38,7 +37,6 @@ export class VaccineVerifier {
if(vaccineDiff <= 0){ if(vaccineDiff <= 0){
return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayComplete, this.vaccineEndDayComplete,inoculationDate); return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayComplete, this.vaccineEndDayComplete,inoculationDate);
} else { } else {
console.log('single dose');
return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayNotComplete, this.vaccineEndDayNotComplete,inoculationDate); return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayNotComplete, this.vaccineEndDayNotComplete,inoculationDate);
} }
} }
@ -80,20 +78,20 @@ export class VaccineVerifier {
this.settings = settings; this.settings = settings;
} }
public checkCertifcate(pass:DCC):checkResult { public checkCertifcate(pass:unknown):checkResult {
console.log(pass.payload); console.log(pass);
const payloadAndType = this.getPayloadAndType(pass); const certificateDataAndType = this.getCertificateData(pass);
const result: checkResult = this.functionSelector[payloadAndType.key](payloadAndType.payload); const result: checkResult = this.functionSelector[certificateDataAndType.key](certificateDataAndType.certificateData);
return result; return result;
} }
private getPayloadAndType(pass:DCC): {key:string,payload:unknown}{ private getCertificateData(pass:unknown): {key:string,certificateData:unknown}{
const result:{key:string,payload:unknown} = {key:'',payload:[]}; const result:{key:string,certificateData:unknown} = {key:'',certificateData:[]};
this.certTypes.forEach((key:string) => { this.certTypes.forEach((key:string) => {
if(pass.payload[key] != undefined){ if(pass[key] != undefined){
if((pass.payload[key] as unknown[]).length != 0){ if((pass[key] as unknown[]).length != 0){
result.key =(key); 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 { private getLogicValidityDays(validRulesSet:unknown[],startKey:string, endKey:string, inoculationDate: dayjs.Dayjs): checkResult {
const now = dayjs(); const now = dayjs();
console.log(validRulesSet);
const ruleStart = validRulesSet.find((elem:any)=>{return elem.name == startKey;}); const ruleStart = validRulesSet.find((elem:any)=>{return elem.name == startKey;});
const ruleEnd = validRulesSet.find((elem:any)=>{return elem.name == endKey;}); const ruleEnd = validRulesSet.find((elem:any)=>{return elem.name == endKey;});
const startValidity = inoculationDate.add(parseInt(ruleStart['value']),'days'); const startValidity = inoculationDate.add(parseInt(ruleStart['value']),'days');

View File

@ -23,14 +23,11 @@ export default class Verifier {
} }
async checkCertificate(certificate:string): Promise<unknown>{ async checkCertificate(certificate:string): Promise<unknown>{
console.log(certificate);
const dcc = await DCC.fromRaw(certificate); const dcc = await DCC.fromRaw(certificate);
console.log(dcc.payload);
let result:unknown = {}; let result:unknown = {};
result = await this.checkKey(dcc); result = await this.checkKey(dcc);
const vaccineVerifier = new VaccineVerifier(await this.ruleDownloader.getRules()); const vaccineVerifier = new VaccineVerifier(await this.ruleDownloader.getRules());
result = {signature: result, valid: vaccineVerifier.checkCertifcate(dcc)}; result = {signature: result, valid: vaccineVerifier.checkCertifcate(dcc.payload)};
console.log(result);
return result; return result;
} }