| @ -1,253 +0,0 @@ | |||
| <!doctype html> | |||
| <head> | |||
| <link rel="stylesheet" href="css/style.verify.css"> | |||
| <link rel="shortcut icon" href="https://www.pathcheck.org/hubfs/Favicon.png"> | |||
| <title>Certificate Verifier</title> | |||
| </head> | |||
| <body> | |||
| <div class="center"> | |||
| <div class="full-div"> | |||
| <div id="pre-verify-section"> | |||
| <h1>Certificate Verifier</h1> | |||
| <div id="reader" style="margin-top: 10px;margin-bottom: 10px;"></div> | |||
| <h2>Or Paste the Code here:</h2> | |||
| <textarea id="qr-verify" rows="10" style="width:100%;" placeholder="cred:type:version:signature:pubkey:payload"></textarea> | |||
| <br><br> | |||
| <div class="center-in-div"> | |||
| <button class="qr-btn" onclick="verifyQRCode()">Verify</button> | |||
| </div> | |||
| </div> | |||
| <br><br> | |||
| <div id="post-verify-section" style="display: none;"> | |||
| <div class="card center-in-div"> | |||
| <h1 id="qr-verify-title" style="text-align: center;"></h1> | |||
| <canvas style="padding:0px 50px" id="qr"></canvas><br/> | |||
| <h1 id="qr-verify-name" style="text-align: center;"></h1> | |||
| <h2 id="qr-verify-verified" style="text-align: center;"></h2> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <script src="js/qrcode.min.js"></script> | |||
| <script src="js/elliptic.min.js"></script> | |||
| <script src="js/sha256.js"></script> | |||
| <script src="js/asn1.min.js"></script> | |||
| <script src="js/base32.min.js"></script> | |||
| <script src="js/html5-qrcode.min.js"></script> | |||
| <script src="js/pcf.js"></script> | |||
| <script src="js/jszip.min.js"></script> | |||
| <script src="js/divoc.min.js"></script> | |||
| <script> | |||
| function e(elem) { return document.getElementById(elem); } | |||
| var html5QrcodeScanner = new Html5QrcodeScanner("reader", { fps: 10, qrbox: 350 }, /* verbose= */ true); | |||
| const monthNames = [ " ", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; | |||
| function parseDate(str) { | |||
| if(!/^(\d){8}$/.test(str)) return "invalid date"; | |||
| var y = str.substr(0,4), | |||
| m = str.substr(4,2), | |||
| d = str.substr(6,2); | |||
| return monthNames[parseInt(m)] + ' ' + d + ', ' + y; | |||
| } | |||
| function parseISODate(str) { | |||
| const d = new Date(str); | |||
| return monthNames[parseInt(d.getMonth()+1)] + ' ' + d.getDate() + ', ' + d.getFullYear(); | |||
| } | |||
| function verifyQRCode() { | |||
| let qr = e("qr-verify").value; | |||
| let uri = qr.substring(qr.indexOf("CRED:")); | |||
| if (uri !== "" && uri != null && uri.startsWith("CRED:")) { | |||
| e("pre-verify-section").style.display = 'none'; | |||
| e("post-verify-section").style.display = ''; | |||
| const [schema, type, version, signatureBase32NoPad, pubKeyLink, payload] = PCF.parseURI(uri); | |||
| const result = PCF.downloadKeyVerify(pubKeyLink, payload, signatureBase32NoPad); | |||
| const fields = PCF.getPayloadFields(payload); | |||
| let params = {margin:0, width:700, errorCorrectionLevel: 'M', color: {dark: '#3654DD' }}; | |||
| QRCode.toCanvas(e('qr'), uri, params, function (error) { | |||
| if (result) { | |||
| const imgDim={width:150,height:150}; //logo dimention | |||
| var context = e('qr').getContext('2d'); | |||
| var imageObj = new Image(); | |||
| imageObj.src = './img/ok-256.png'; | |||
| imageObj.onload = function() { | |||
| context.drawImage(imageObj, | |||
| e('qr').width / 2 - imgDim.width / 2 +1, | |||
| e('qr').height / 2 - imgDim.height / 2,imgDim.width,imgDim.height); | |||
| }; | |||
| } | |||
| }); | |||
| if (result == null) { | |||
| e('qr-verify-verified').innerHTML = "Unable to Verify"; | |||
| } else if (result) { | |||
| e('qr-verify-verified').innerHTML = 'Signed by ' + pubKeyLink + ' on ' + parseDate(fields['date'] ? fields['date'] : fields['issuanceDate']); | |||
| } else { | |||
| e('qr-verify-verified').innerHTML = "Credential Invalid"; | |||
| } | |||
| if (type == 'BADGE') { | |||
| e('qr-verify-title').innerHTML = "COVID-19 Vaccine Record" | |||
| e('qr-verify-name').innerHTML = fields['name'] + "<br>"; | |||
| e('qr-verify-name').innerHTML += parseDate(fields['dob']) + "<br>"; | |||
| } | |||
| if (type == 'STATUS') { | |||
| e('qr-verify-title').innerHTML = "COVID-19 Pass" | |||
| e('qr-verify-name').innerHTML = "Status: " + (fields['status'] === '2' ? "Vaccinated" : "Not Vaccinated") + "<br />"; | |||
| e('qr-verify-name').innerHTML += "Initials: " + fields['initials'] + "<br>"; | |||
| } | |||
| if (type == 'PASSKEY') { | |||
| e('qr-verify-name').innerHTML = "PassKey for: " + fields['name'] + "<br>"; | |||
| e('qr-verify-name').innerHTML += "DoB: " + parseDate(fields['dob']); | |||
| } | |||
| if (type == 'LIBERTY') { | |||
| e('qr-verify-title').innerHTML = "COVID-19 Pass" | |||
| e('qr-verify-name').innerHTML = fields['credentialSubject.subject.name.given'] + " " + fields['credentialSubject.subject.name.family'] + "<br>"; | |||
| e('qr-verify-name').innerHTML += fields['credentialSubject.subject.birthDate']; | |||
| } | |||
| if (type == 'COWIN') { | |||
| e('qr-verify-title').innerHTML = "COVID-19 Vaccine Record" | |||
| e('qr-verify-name').innerHTML = fields['credentialSubject.name'] + "<br>"; | |||
| e('qr-verify-name').innerHTML += fields['credentialSubject.age'] + "yrs old"; | |||
| } | |||
| } else if (uri !== "" && uri != null && (uri.startsWith("{") || uri.startsWith("PK"))) { | |||
| if (uri.startsWith("PK")) { | |||
| unZipVerifyDisplayDIVOC(uri); | |||
| } else { | |||
| // Make sure it's not encoded. | |||
| let json = ''; | |||
| if (uri.includes("%22")) { | |||
| json = JSON.parse(decodeURIComponent(uri)) | |||
| } else { | |||
| json = JSON.parse(uri); | |||
| } | |||
| verifyDisplayDIVOC(json); | |||
| } | |||
| } else { | |||
| e('qr-verify-verified').innerHTML = "Certificate not found. "; | |||
| } | |||
| } | |||
| function unZipVerifyDisplayDIVOC(data) { | |||
| var zip = new JSZip(); | |||
| zip.loadAsync(data).then((contents) => { | |||
| console.log(contents); | |||
| return contents.files["certificate.json"].async('text') | |||
| }).then(function (contents) { | |||
| console.log(contents); | |||
| verifyDisplayDIVOC(JSON.parse(contents)); | |||
| }).catch(err => { | |||
| console.log(err); | |||
| } | |||
| ); | |||
| } | |||
| function verifyDisplayDIVOC(json) { | |||
| DIVOC.verify(json).then(result => { | |||
| let params = {margin:0, width:700, errorCorrectionLevel: 'L', color: {dark: '#3654DD' }}; | |||
| var zip = new JSZip(); | |||
| zip.file("certificate.json", JSON.stringify(json), { | |||
| compression: "DEFLATE", | |||
| compressionOptions: { | |||
| level: 9 | |||
| } | |||
| }); | |||
| zip.generateAsync({type: "binarystring"}).then(function (bin) { | |||
| QRCode.toCanvas(e('qr'), bin, params, function (error) { | |||
| if (result) { | |||
| const imgDim={width:150,height:150}; //logo dimention | |||
| var context = e('qr').getContext('2d'); | |||
| var imageObj = new Image(); | |||
| imageObj.src = './img/ok-256.png'; | |||
| imageObj.onload = function() { | |||
| context.drawImage(imageObj, | |||
| e('qr').width / 2 - imgDim.width / 2 +1, | |||
| e('qr').height / 2 - imgDim.height / 2,imgDim.width,imgDim.height); | |||
| }; | |||
| } | |||
| }); | |||
| }); | |||
| if (result == null) { | |||
| e('qr-verify-verified').innerHTML = "Unable to Verify"; | |||
| } else if (result) { | |||
| e('qr-verify-verified').innerHTML = 'Signed by ' + json.evidence[0].facility.name + ' on ' + parseISODate(json.issuanceDate); | |||
| } else { | |||
| e('qr-verify-verified').innerHTML = "Credential Invalid"; | |||
| } | |||
| e('qr-verify-title').innerHTML = "COVID-19 Vaccine Record" | |||
| e('qr-verify-name').innerHTML = json.credentialSubject.name + "<br>"; | |||
| e('qr-verify-name').innerHTML += json.credentialSubject.age + "yrs old"; | |||
| e("pre-verify-section").style.display = 'none'; | |||
| e("post-verify-section").style.display = ''; | |||
| }); | |||
| } | |||
| function onScanSuccess(qrMessage) { | |||
| html5QrcodeScanner.clear(); | |||
| if (qrMessage !== "" && qrMessage != null) { | |||
| let uri = qrMessage.substring(qrMessage.indexOf("CRED:")); | |||
| e("qr-verify").value = uri; | |||
| verifyQRCode(); | |||
| } | |||
| } | |||
| function onScanFailure(error) { | |||
| console.warn(`QR error = ${error}`); | |||
| } | |||
| function getQueryVariable(variable) { | |||
| var query = window.location.search.substring(1); | |||
| var vars = query.split('&'); | |||
| for (var i = 0; i < vars.length; i++) { | |||
| var pair = vars[i].split('='); | |||
| if (pair[0] == variable) { | |||
| return pair[1]; | |||
| } | |||
| } | |||
| console.log('Query variable %s not found', variable); | |||
| } | |||
| </script> | |||
| <script> | |||
| // Starting Scanner | |||
| html5QrcodeScanner.render(onScanSuccess, onScanFailure); | |||
| // Loading URI from qr parameter. | |||
| const queryString = window.location.search; | |||
| const qr = getQueryVariable("qr") | |||
| if (qr !== "" && qr != null) { | |||
| uri = qr.substring(qr.indexOf("CRED:")); | |||
| console.log(uri); | |||
| e("qr-verify").value = uri; | |||
| verifyQRCode(); | |||
| } | |||
| </script> | |||
| </body> | |||
| </html> | |||