first working version
This commit is contained in:
parent
d8a836aa90
commit
0c5d06cfc1
3294
cerificate_collection.json
Normal file
3294
cerificate_collection.json
Normal file
File diff suppressed because it is too large
Load Diff
119
package-lock.json
generated
119
package-lock.json
generated
@ -9,7 +9,9 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.4",
|
||||
"body-parser": "^1.19.0",
|
||||
"dayjs": "^1.10.7",
|
||||
"dcc-utils": "^0.2.0",
|
||||
"express": "^4.17.1",
|
||||
"jsrsasign": "^10.4.0",
|
||||
@ -2533,6 +2535,19 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/cli-tools/node_modules/node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/cli-types": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-6.0.0.tgz",
|
||||
@ -3653,6 +3668,14 @@
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/b64-lite": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/b64-lite/-/b64-lite-1.4.0.tgz",
|
||||
@ -4720,9 +4743,7 @@
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
|
||||
"integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
"integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig=="
|
||||
},
|
||||
"node_modules/dcc-utils": {
|
||||
"version": "0.2.0",
|
||||
@ -6098,6 +6119,25 @@
|
||||
"integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.4",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
|
||||
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -8182,6 +8222,19 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/metro/node_modules/node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/metro/node_modules/rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@ -8400,19 +8453,6 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-hkdf-sync": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-hkdf-sync/-/node-hkdf-sync-1.0.0.tgz",
|
||||
@ -13961,6 +14001,16 @@
|
||||
"integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -14723,6 +14773,14 @@
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"b64-lite": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/b64-lite/-/b64-lite-1.4.0.tgz",
|
||||
@ -15569,9 +15627,7 @@
|
||||
"dayjs": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
|
||||
"integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
"integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig=="
|
||||
},
|
||||
"dcc-utils": {
|
||||
"version": "0.2.0",
|
||||
@ -16681,6 +16737,11 @@
|
||||
"integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==",
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.4",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
|
||||
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -18073,6 +18134,16 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@ -18559,16 +18630,6 @@
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node-hkdf-sync": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-hkdf-sync/-/node-hkdf-sync-1.0.0.tgz",
|
||||
|
@ -9,7 +9,9 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.4",
|
||||
"body-parser": "^1.19.0",
|
||||
"dayjs": "^1.10.7",
|
||||
"dcc-utils": "^0.2.0",
|
||||
"express": "^4.17.1",
|
||||
"jsrsasign": "^10.4.0",
|
||||
|
1
rules.json
Normal file
1
rules.json
Normal file
@ -0,0 +1 @@
|
||||
{"rules":[{"name":"vaccine_end_day_complete","type":"EU/1/20/1525","value":"365"},{"name":"vaccine_start_day_complete","type":"EU/1/20/1525","value":"15"},{"name":"vaccine_end_day_not_complete","type":"EU/1/20/1525","value":"365"},{"name":"vaccine_start_day_not_complete","type":"EU/1/20/1525","value":"15"},{"name":"vaccine_end_day_complete","type":"EU/1/21/1529","value":"365"},{"name":"vaccine_start_day_complete","type":"EU/1/21/1529","value":"0"},{"name":"vaccine_end_day_not_complete","type":"EU/1/21/1529","value":"84"},{"name":"vaccine_start_day_not_complete","type":"EU/1/21/1529","value":"15"},{"name":"vaccine_end_day_complete","type":"EU/1/20/1507","value":"365"},{"name":"vaccine_start_day_complete","type":"EU/1/20/1507","value":"0"},{"name":"vaccine_end_day_not_complete","type":"EU/1/20/1507","value":"42"},{"name":"vaccine_start_day_not_complete","type":"EU/1/20/1507","value":"15"},{"name":"vaccine_end_day_complete","type":"EU/1/20/1528","value":"365"},{"name":"vaccine_start_day_complete","type":"EU/1/20/1528","value":"0"},{"name":"vaccine_end_day_not_complete","type":"EU/1/20/1528","value":"42"},{"name":"vaccine_start_day_not_complete","type":"EU/1/20/1528","value":"15"},{"name":"rapid_test_start_hours","type":"GENERIC","value":"0"},{"name":"rapid_test_end_hours","type":"GENERIC","value":"48"},{"name":"molecular_test_start_hours","type":"GENERIC","value":"0"},{"name":"molecular_test_end_hours","type":"GENERIC","value":"48"},{"name":"recovery_cert_start_day","type":"GENERIC","value":"0"},{"name":"recovery_cert_end_day","type":"GENERIC","value":"180"},{"name":"ios","type":"APP_MIN_VERSION","value":"1.1.0"},{"name":"android","type":"APP_MIN_VERSION","value":"1.1.0"}],"lastupdateDate":1632418898529}
|
@ -1,10 +1,14 @@
|
||||
import { Request, Response } from 'express';
|
||||
import Verifier from '../../../utils/dgcVerifier/Verifier';
|
||||
import Verifier from '../../utils/dgcVerifier/Verifier';
|
||||
let verifier:Verifier;
|
||||
Verifier.instanceVerifier().then((ver)=>verifier=ver).catch(console.error);
|
||||
Verifier.instanceVerifier().then((ver:Verifier)=>verifier=ver).catch(console.error);
|
||||
|
||||
export const get = (req: Request, res: Response):void => {
|
||||
const cert = req.body;
|
||||
const result = verifier.checkCertificate(cert);
|
||||
res.status(200).send({'data':result});
|
||||
export const get = async (req: Request, res: Response):Promise<void> => {
|
||||
const cert = req.body['key'];
|
||||
try {
|
||||
const result = await verifier.checkCertificate(cert);
|
||||
res.status(200).send(result);
|
||||
} catch (error) {
|
||||
res.status(200).send({message:'unsigned certificate',error});
|
||||
}
|
||||
};
|
@ -10,7 +10,7 @@ export default class GreenApi implements API {
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
setupApi():void {
|
||||
setupApi(): void {
|
||||
this.router.post('/green',middleware.canGet,controller.get);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
|
||||
export const canGet = (req: Request, res: Response, next: NextFunction):void => {
|
||||
|
||||
return next();
|
||||
};
|
@ -6,8 +6,8 @@ export const setupApis = (application: Express):void => {
|
||||
const exampleApi = new GreenApi(router);
|
||||
|
||||
exampleApi.setupApi();
|
||||
|
||||
application.use('/api', router);
|
||||
console.log('inited');
|
||||
};
|
||||
|
||||
export interface API {
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { setupApis } from './api';
|
||||
import express from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
|
||||
const app = express();
|
||||
|
||||
app.set('port', process.env.PORT || 3000);
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
import './api';
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded());
|
||||
setupApis(app);
|
||||
|
||||
export default app;
|
@ -1,5 +1,4 @@
|
||||
import app from './app';
|
||||
|
||||
const server = app.listen(app.get('port'), () => {
|
||||
console.log(
|
||||
'App is running at http://localhost:%d in %s mode',
|
||||
|
@ -1,30 +1,39 @@
|
||||
import { response } from 'express';
|
||||
import fs from 'fs/promises';
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
export class CertificateDownloader{
|
||||
// static instance: 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 timeSpan = 86400000;
|
||||
private cerficateCollection:string[] = [];
|
||||
private currentValidKids = [];
|
||||
// private readonly timeSpan = 86400000;
|
||||
private readonly timeSpan = 1;
|
||||
private cerficateCollection:unknown = {};
|
||||
private currentValidKids:string[] = [];
|
||||
|
||||
public constructor(){
|
||||
this.getCertificates();
|
||||
}
|
||||
|
||||
public async getCertificates(): Promise<string[]> {
|
||||
const file = await fs.open(this.keyStorage,'r');
|
||||
const data = await file.readFile();
|
||||
const savedData = JSON.parse( data.toString() || '{}');
|
||||
if(savedData.lastupdateDate == null || Date.now() - savedData?.lastupdateDate > this.timeSpan){
|
||||
this.getAllCertificate()
|
||||
.then(() => { console.log('could not read the certificates from the local file'); return this.cerficateCollection; })
|
||||
.catch(console.error);
|
||||
public async getCertificates(): Promise<unknown> {
|
||||
let data = '{}';
|
||||
try {
|
||||
const file = await fs.open(this.keyStorage,'r');
|
||||
data = (await file.readFile()).toString('utf-8');
|
||||
await file.close();
|
||||
const savedData = JSON.parse( data || '{}');
|
||||
// if(savedData.lastupdateDate == null || Date.now() - savedData?.lastupdateDate > this.timeSpan){
|
||||
// await this.getAllCertificate();
|
||||
// } else {
|
||||
this.cerficateCollection = savedData.certificates;
|
||||
// }
|
||||
return this.cerficateCollection;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if(error.errno == -2){
|
||||
await fs.writeFile(this.keyStorage,'{}');
|
||||
} else {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
console.log('cerficates collection is valid loading from local source');
|
||||
this.cerficateCollection = savedData.certificates;
|
||||
return this.cerficateCollection;
|
||||
}
|
||||
|
||||
// public static getCertificateDownloader():CertificateDownloader{
|
||||
@ -34,45 +43,54 @@ export class CertificateDownloader{
|
||||
// return CertificateDownloader.instance;
|
||||
// }
|
||||
|
||||
async getAllCertificate(): Promise<void> {
|
||||
this.cerficateCollection = {};
|
||||
const response:AxiosResponse<JSON> = (await axios.get('https://raw.githubusercontent.com/lovasoa/sanipasse/master/src/assets/Digital_Green_Certificate_Signing_Keys.json'));
|
||||
if(response.status == 200){
|
||||
console.log(response.data);
|
||||
this.cerficateCollection = response.data;
|
||||
console.log(response);
|
||||
const lastupdateDate = Date.now();
|
||||
const file = await fs.open(this.keyStorage,'w');
|
||||
file.writeFile(JSON.stringify({'certificates':this.cerficateCollection, lastupdateDate}));
|
||||
console.log(this.cerficateCollection);
|
||||
await file.close();
|
||||
}else{
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
// async getAllCertificate(): Promise<void> {
|
||||
// this.cerficateCollection = {};
|
||||
// const response = (await fetch('https://raw.githubusercontent.com/lovasoa/sanipasse/master/src/assets/Digital_Green_Certificate_Signing_Keys.json'));
|
||||
// if(response.ok){
|
||||
// this.cerficateCollection = await response.json();
|
||||
// console.log(response);
|
||||
// const lastupdateDate = Date.now();
|
||||
// const file = await fs.open(this.keyStorage,'rw');
|
||||
// file.writeFile(JSON.stringify({'certificates':this.cerficateCollection, lastupdateDate}));
|
||||
// }else{
|
||||
// throw new Error(response.statusText);
|
||||
// let exit = false;
|
||||
// let headers = {};
|
||||
// this.cerficateCollection = [];
|
||||
// while(!exit){
|
||||
// // const response = await fetch(this.baseUrl+this.updateApi,{headers});
|
||||
// const response:AxiosResponse = await axios.get(this.baseUrl+this.updateApi,{headers});
|
||||
// // console.log(response.headers);
|
||||
// headers = {'X-RESUME-TOKEN': response.headers['x-resume-token']};
|
||||
// const currentKid:string = response.headers['x-kid'];
|
||||
// if(this.currentValidKids.includes(currentKid)){
|
||||
// // console.log('=========AGGIUNG===========');
|
||||
// const cert = `-----BEGIN CERTIFICATE-----${response.data}-----END CERTIFICATE-----`;
|
||||
// // console.log(cert);
|
||||
// this.cerficateCollection.push(cert);
|
||||
// }
|
||||
// exit = (response.status !== 200);
|
||||
// }
|
||||
// const lastupdateDate = Date.now();
|
||||
// const file = await fs.open(this.keyStorage,'w');
|
||||
// file.writeFile(JSON.stringify({'certificates':this.cerficateCollection, lastupdateDate}));
|
||||
// console.log(this.cerficateCollection);
|
||||
// await file.close();
|
||||
// }
|
||||
|
||||
async getAllCertificate(): Promise<void> {
|
||||
let exit = false;
|
||||
let headers = {};
|
||||
this.cerficateCollection = [];
|
||||
while(!exit){
|
||||
const response = await fetch(this.baseUrl+this.updateApi,{headers});
|
||||
headers = {'X-RESUME-TOKEN': response.headers.get('X-RESUME-TOKEN')};
|
||||
const currentKid:string = response.headers.get('X-KID') || '';
|
||||
if(this.currentValidKids.includes(currentKid as never)){
|
||||
const cert = await response.text();
|
||||
this.cerficateCollection.push('-----BEGIN CERTIFICATE-----\n' + cert + '-----END CERTIFICATE-----');
|
||||
}
|
||||
exit = (response.status !== 200);
|
||||
}
|
||||
const lastupdateDate = Date.now();
|
||||
const file = await fs.open(this.keyStorage,'rw');
|
||||
file.writeFile(JSON.stringify({'certificates':this.cerficateCollection, lastupdateDate}));
|
||||
}
|
||||
|
||||
async updateKids(): Promise<void> {
|
||||
try {
|
||||
const resp = await fetch(this.baseUrl+this.statusApi);
|
||||
this.currentValidKids = await resp.json();
|
||||
} catch (error) {
|
||||
console.log('could not get keyChild ', error);
|
||||
}
|
||||
}
|
||||
// async updateKids(): Promise<void> {
|
||||
// try {
|
||||
// const resp = await axios.get(this.baseUrl+this.statusApi);
|
||||
// this.currentValidKids = await resp.data as string[];
|
||||
// } catch (error) {
|
||||
// console.log('could not get keyChild ', error);
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,34 +1,49 @@
|
||||
import fs from 'fs/promises';
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
export class RuleDownloader {
|
||||
static instance: RuleDownloader;
|
||||
private readonly baseUrl = 'https://get.dgc.gov.it';
|
||||
private readonly timeSpan = 86400000;
|
||||
private readonly keyStorage = 'rules'
|
||||
// private readonly timeSpan = 1;
|
||||
private readonly keyStorage = 'rules.json'
|
||||
// private readonly timeSpan = 1000;
|
||||
public rules:unknown = {}
|
||||
public rules:unknown[] = []
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
constructor(){
|
||||
this.getRules();
|
||||
}
|
||||
constructor(){}
|
||||
|
||||
public getRules(): unknown {
|
||||
const savedData = JSON.parse(localStorage.getItem(this.keyStorage) || '{}');
|
||||
if(savedData.lastupdateDate == null || Date.now() - savedData?.lastupdateDate > this.timeSpan){
|
||||
this.getSettings()
|
||||
.then(() => { console.log('could not read the certificates from the local file'); return this.rules; })
|
||||
.catch(console.error);
|
||||
public async getRules(): Promise<unknown[]> {
|
||||
let data = '{}';
|
||||
try {
|
||||
const file = await fs.open(this.keyStorage,'r');
|
||||
data = (await file.readFile()).toString('utf-8');
|
||||
await file.close();
|
||||
const savedData = JSON.parse(data);
|
||||
if(savedData.lastupdateDate == null || Date.now() - savedData?.lastupdateDate > this.timeSpan){
|
||||
await this.getSettings();
|
||||
} else {
|
||||
this.rules = savedData.rules;
|
||||
}
|
||||
return this.rules;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if(error.code == 'ENONET'){
|
||||
await fs.writeFile(this.keyStorage,'{}');
|
||||
} else {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
console.log('cerficates collection is valid loading from local source');
|
||||
// console.log(dataRead.certificates);
|
||||
this.rules = savedData.certificates;
|
||||
return this.rules;
|
||||
}
|
||||
|
||||
private async getSettings(): Promise<unknown>{
|
||||
const response = await fetch(`${this.baseUrl}/v1/dgc/settings`);
|
||||
const jsonData = await response.json();
|
||||
private async getSettings(): Promise<unknown[]>{
|
||||
const response:AxiosResponse<unknown[]> = 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()}));
|
||||
// localStorage.setItem(this.keyStorage, JSON.stringify({rules:this.rules,lastupdateDate:Date.now()}));
|
||||
const file = await fs.open(this.keyStorage,'w');
|
||||
file.writeFile(JSON.stringify({rules:this.rules,lastupdateDate:Date.now()}));
|
||||
await file.close();
|
||||
return jsonData;
|
||||
}
|
||||
}
|
129
src/utils/dgcVerifier/VaccineVerifier.ts
Normal file
129
src/utils/dgcVerifier/VaccineVerifier.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import {DCC} from 'dcc-utils';
|
||||
import dayjs from 'dayjs';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import timezone from 'dayjs/plugin/timezone';
|
||||
|
||||
interface checkResult {
|
||||
valid: boolean;
|
||||
message: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export class VaccineVerifier {
|
||||
private readonly vaccineStartDayNotComplete = 'vaccine_start_day_not_complete';
|
||||
private readonly vaccineEndDayNotComplete = 'vaccine_end_day_not_complete';
|
||||
private readonly vaccineStartDayComplete = 'vaccine_start_day_complete';
|
||||
private readonly vaccineEndDayComplete = 'vaccine_end_day_complete';
|
||||
private readonly recoveryCertStartDay = 'recovery_cert_start_day';
|
||||
private readonly recoveryCertEndDay = 'recovery_cert_end_day';
|
||||
private readonly rapidTestStartHour = 'rapid_test_start_hours';
|
||||
private readonly rapidTestEndHour = 'rapid_test_end_hours';
|
||||
private readonly molecularTestStartHour = 'molecular_test_start_hours';
|
||||
private readonly molecularTestEndHour = 'molecular_test_end_hours';
|
||||
private readonly positiveTest = '260373001';
|
||||
private readonly negativeTest = '260415000';
|
||||
private readonly rapidTest = 'LP217198-3'; // RAT, Rapid Antigen Test
|
||||
private readonly molecularTest = 'LP6464-4'; // NAAT, Nucleic Acid Amplification Test
|
||||
|
||||
settings=[];
|
||||
certTypes=['r','v','t',]
|
||||
|
||||
private checkVaccine = (payload:any):checkResult => {
|
||||
const inoculationDate = dayjs(payload.dt);
|
||||
const validRulesSet = this.getRulesSet(payload.mp);
|
||||
const vaccineDiff = payload.sd - payload.dn;
|
||||
const baseRuleIndex = validRulesSet.findIndex((elem:any)=>{ return elem.name == this.vaccineEndDayComplete;});
|
||||
if( baseRuleIndex == -1)
|
||||
return {valid:false, message:'Invaild set of rules check with operator', type:'vaccine'};
|
||||
if(vaccineDiff <= 0){
|
||||
return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayComplete, this.vaccineEndDayComplete,inoculationDate);
|
||||
} else {
|
||||
return this.getLogicValidityDays(validRulesSet, this.vaccineStartDayNotComplete, this.vaccineEndDayNotComplete,inoculationDate);
|
||||
}
|
||||
}
|
||||
|
||||
private checkRecovery = (payload:any):checkResult => {
|
||||
const now = dayjs();
|
||||
const dateFrom = dayjs(payload.df);
|
||||
const dateEnd = dayjs(payload.du);
|
||||
if(now.isAfter(dateFrom) && now.isBefore(dateEnd)){
|
||||
return{valid:true, message:'Certificate is valid', type:'recovery'};
|
||||
}
|
||||
return {valid:false, message:'toimplement', type:'recovery'};
|
||||
}
|
||||
|
||||
private checkTest = (payload:any):checkResult => {
|
||||
const validRulesSet = this.getRulesSet('GENERIC');
|
||||
const testType = payload.tt;
|
||||
if(payload.tr === this.positiveTest)
|
||||
return {valid:false, message:'The test detected the virus',type:'test'};
|
||||
const collectionDateTime = dayjs.tz(payload.sc,'UTC').tz(dayjs.tz.guess());
|
||||
if(testType == this.rapidTest){
|
||||
return this.getLogicValidityHours(validRulesSet,this.rapidTestStartHour,this.rapidTestEndHour,collectionDateTime);
|
||||
}
|
||||
if(testType == this.molecularTest){
|
||||
return this.getLogicValidityHours(validRulesSet,this.molecularTestStartHour,this.molecularTestEndHour,collectionDateTime);
|
||||
}
|
||||
return {valid:false, message:'unknown test type',type:'test'};
|
||||
}
|
||||
|
||||
private functionSelector = {
|
||||
'v':this.checkVaccine,
|
||||
'r':this.checkRecovery,
|
||||
't':this.checkTest
|
||||
}
|
||||
|
||||
constructor(settings:unknown[]) {
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
private getPayloadAndType(pass:DCC): {key:string,payload:unknown}{
|
||||
const result:{key:string,payload:unknown} = {key:'',payload:[]};
|
||||
this.certTypes.forEach((key:string) => {
|
||||
if(pass.payload[key] != undefined){
|
||||
if((pass.payload[key] as unknown[]).length != 0){
|
||||
result.key =(key);
|
||||
result.payload = (pass.payload[key][pass.payload[key].length -1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private getRulesSet(type:string): unknown[]{
|
||||
return this.settings.filter((rule:unknown)=>{
|
||||
return rule['type'] = type;
|
||||
});
|
||||
}
|
||||
|
||||
private getLogicValidityDays(validRulesSet:unknown[],startKey:string, endKey:string, inoculationDate: dayjs.Dayjs): checkResult {
|
||||
const now = dayjs();
|
||||
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');
|
||||
const endValidity = inoculationDate.add(parseInt(ruleEnd['value']),'days');
|
||||
if(startValidity.isAfter(now)) return {valid:false, message:'Certificate not yet valid', type:'vaccine'};
|
||||
if(now.isAfter(endValidity)) return {valid:false, message:'Certificate not more valid', type:'vaccine'};
|
||||
return {valid:true, message:'Certificate is valid', type:'vaccine'};
|
||||
}
|
||||
|
||||
private getLogicValidityHours(validRulesSet:unknown[],startKey:string, endKey:string, inoculationDate: dayjs.Dayjs): checkResult {
|
||||
const now = dayjs();
|
||||
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']),'hours');
|
||||
const endValidity = inoculationDate.add(parseInt(ruleEnd['value']),'hours');
|
||||
if(startValidity.isAfter(now)) return {valid:false, message:'Certificate not yet valid', type:'test'};
|
||||
if(now.isAfter(endValidity)) return {valid:false, message:'Certificate not more valid', type:'test'};
|
||||
return {valid:true, message:'Certificate is valid', type:'test'};
|
||||
}
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
import { CertificateDownloader } from './CertificateDownloader';
|
||||
import { RuleDownloader } from './RuleDownloader';
|
||||
import { VaccineVerifier } from './VaccineVerifier';
|
||||
import {DCC} from 'dcc-utils';
|
||||
import jsrsasign from 'jsrsasign';
|
||||
|
||||
export default class Verifier {
|
||||
static instance: Verifier|undefined = undefined;
|
||||
private certDownloader: CertificateDownloader;
|
||||
private ruleDownloader: RuleDownloader;
|
||||
private certificateList: string[] = [];
|
||||
|
||||
private constructor(){
|
||||
this.certDownloader = new CertificateDownloader();
|
||||
this.ruleDownloader = new RuleDownloader();
|
||||
@ -17,21 +15,19 @@ export default class Verifier {
|
||||
public static async instanceVerifier(): Promise<Verifier>{
|
||||
if (Verifier.instance == undefined){
|
||||
Verifier.instance = new Verifier();
|
||||
Verifier.instance.certificateList = await Verifier.instance.certDownloader.getCertificates();
|
||||
await Verifier.instance.certDownloader.getCertificates();
|
||||
await Verifier.instance.ruleDownloader.getRules();
|
||||
|
||||
}
|
||||
return Verifier.instance;
|
||||
}
|
||||
|
||||
async checkCertificate(certificate:string): Promise<unknown>{
|
||||
console.log(certificate);
|
||||
const dcc = await DCC.fromRaw(certificate);
|
||||
let result: unknown;
|
||||
this.certificateList.forEach(async (cert: string) => {
|
||||
const verifier = jsrsasign.KEYUTIL.getKey(cert);
|
||||
if (typeof verifier == typeof jsrsasign.KJUR.crypto.ECDSA ){
|
||||
const xyCoord = (verifier as jsrsasign.KJUR.crypto.ECDSA).getPublicKeyXYHex();
|
||||
result = await dcc.checkSignature(xyCoord);
|
||||
}
|
||||
});
|
||||
let result = await dcc.checkSignatureWithKeysList(await this.certDownloader.getCertificates());
|
||||
const vaccineVerifier = new VaccineVerifier(await this.ruleDownloader.getRules());
|
||||
result = {signature: result, valid:vaccineVerifier.checkCertifcate(dcc)};
|
||||
console.log(result);
|
||||
return result;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
|
Loading…
Reference in New Issue
Block a user