Added JS version
This commit is contained in:
parent
e0cd5e84ff
commit
48625efa93
|
@ -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)))
|
||||
});
|
|
@ -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="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue