Added JS version

This commit is contained in:
GG 2021-05-24 17:38:28 -04:00
parent e0cd5e84ff
commit 48625efa93
3 changed files with 182 additions and 0 deletions

62
CovidQR-JS/covid-qr-decode.js Executable file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env node
//
// Author: Guillaume Gagnon
// Licence: Apache 2.0
//
// Extract all payloads included in the Covid QR provided by the Quebec government (Preuve/passeport de vaccination)
// Note: The public key do not seems to be provided by the government at this point.
// Hence, it is not possible to validate QR authenticity at the time being.
// Public keys should be available here later on:
// https://covid19.quebec.ca/PreuveVaccinaleApi/issuer/.well-known/jwks.json
// This script has been built using this very nice and detailed HOWTO:
// https://github.com/dvci/health-cards-walkthrough/blob/main/SMART%20Health%20Cards.ipynb
//
// Also, more info about the SMART Health Cards Framework can be found here:
// https://smarthealth.cards/
const fs = require('fs');
var jsQR = require('jsqr');
var PNG = require('pngjs').PNG;
var jose = require('node-jose');
var base64url = require("base64url");
var zlib = require("zlib");
// Extract RAW QR from picture
imageData = PNG.sync.read(fs.readFileSync('./QR.png'))
const scannedQR = jsQR(new Uint8ClampedArray(imageData.data.buffer), imageData.width, imageData.height)
console.log("RAW QR DATA:")
console.log(scannedQR.data)
console.log("")
// Extract JWS
const scannedJWS = scannedQR
.chunks
.filter(chunk => chunk.type === "numeric")[0] // Grab the numeric chunk
.text.match(/(..?)/g) // Split into groups of 2 numeric characters each of which represent a single JWS char
.map(num => String.fromCharCode(parseInt(num, 10) + 45)).join('') // Convert from numeric encoding to JWS
console.log("JWS DATA:")
console.log(scannedJWS)
console.log("")
// Extract JWS Header
JWSHeaders = base64url.decode(scannedJWS.split(".")[0])
console.log("JWS HEAD:")
console.log(JWSHeaders)
console.log("")
// Extract payload
JWSPayload = scannedJWS.split(".")[1]
const payload = Buffer.from(JWSPayload, "base64");
zlib.inflateRaw(payload, function (err, decompressedResult) {
scannedResult = decompressedResult.toString("utf8");
console.log(scannedResult)
//const entries = JSON.parse(scannedResult) // Uncomment this bloc if you want to "beautify" the json output
// .vc.credentialSubject.fhirBundle.entry
// .map(entry => console.log(JSON.stringify(entry, null, 2)))
});

98
CovidQR-JS/package-lock.json generated Normal file
View File

@ -0,0 +1,98 @@
{
"name": "covid-qr-decode",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"base64url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A=="
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"jsqr": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
},
"node-jose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-jose/-/node-jose-2.0.0.tgz",
"integrity": "sha512-j8zoFze1gijl8+DK/dSXXqX7+o2lMYv1XS+ptnXgGV/eloQaqq1YjNtieepbKs9jBS4WTnMOqyKSaQuunJzx0A==",
"requires": {
"base64url": "^3.0.1",
"buffer": "^5.5.0",
"es6-promise": "^4.2.8",
"lodash": "^4.17.15",
"long": "^4.0.0",
"node-forge": "^0.10.0",
"pako": "^1.0.11",
"process": "^0.11.10",
"uuid": "^3.3.3"
}
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"pngjs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"zlib": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz",
"integrity": "sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA="
}
}
}

22
CovidQR-JS/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "covid-qr-decode",
"version": "1.0.0",
"description": "",
"main": "covid-qr-decode.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Guillaume Gagnon",
"license": "Apache-2.0",
"bin": {
"hello": "./covid-qr-decode.js"
},
"dependencies": {
"base64url": "^3.0.1",
"jsqr": "^1.4.0",
"node-jose": "^2.0.0",
"pngjs": "^6.0.0",
"zlib": "^1.0.5"
}
}