Skip to content

Instantly share code, notes, and snippets.

@dsoares
Last active June 29, 2021 11:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsoares/dbd784615defd8800e93e4df4c783ce1 to your computer and use it in GitHub Desktop.
Save dsoares/dbd784615defd8800e93e4df4c783ce1 to your computer and use it in GitHub Desktop.
Show COVID greenpass data
#!/usr/bin/python3
# Copyright 2021 Tobias Girstmair (https://gir.st). Consider this code GPLv3
# licensed.
# pip3 install flynn base45 PyPDF2 pyzbar Pillow
# dnf install zbar || apt install libzbar0
import sys
import glob
import json
import zlib
import flynn
import base45
import PyPDF2
from PIL import Image
from pyzbar import pyzbar
from datetime import datetime
from urllib.request import urlopen
sch = urlopen('https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-schema/release/1.3.0/DCC.combined-schema.json')
if len(sys.argv) < 2:
try:
infile = glob.glob("COVID-19-*-*-*.pdf")[0]
print(f"Warning: using file {found}, since not specified\n", file=sys.stderr)
except:
print(f"Usage: {sys.argv[0]} COVID-19-*-*-*.pdf", file=sys.stderr)
print(f"Usage: {sys.argv[0]} QR_CODE.png", file=sys.stderr)
sys.exit(1)
else:
infile = sys.argv[1]
if open(infile, "rb").read(4) == b"%PDF":
# extract QR code from PDF using hard-coded index, size and bit depth.
# This will only work with the official Austrian green pass PDFs.
pdf=PyPDF2.PdfFileReader(open(infile, "rb"))
qr_img = pdf.getPage(0)['/Resources']['/XObject']['/Im3']
qr_pil = Image.frombytes("1", (400,400), qr_img.getData())
else: # assume image
qr_pil = Image.open(infile)
# decode QR code into raw bytes:
qr_data_zlib_b45 = pyzbar.decode(qr_pil)[0].data
# strip header ('HC1:') and decompress data:
qr_data_zlib = base45.b45decode(qr_data_zlib_b45[4:])
# decompress:
qr_data = zlib.decompress(qr_data_zlib)
# decode cose document:
(_, (headers1, headers2, cbor_data, signature)) = flynn.decoder.loads(qr_data)
# decode cbor-encoded payload:
data = flynn.decoder.loads(cbor_data)
date = lambda ts: datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
print("QR Code Issuer :", data[1])
print("QR Code Expiry :", date(data[4]))
print("QR Code Generated :", date(data[6]))
glb_schema = json.load(sch)
def annotate(data, schema, level=0):
for key, value in data.items():
description = schema[key].get('title') or schema[key].get('description') or key
description, _, _ = description.partition(' - ')
if type(value) is dict:
print(' '*level, description)
_, _, sch_ref = schema[key]['$ref'].rpartition('/')
annotate(value, glb_schema['$defs'][sch_ref]['properties'], level+1)
elif type(value) is list:
print(' '*level, description)
_, _, sch_ref = schema[key]['items']['$ref'].rpartition('/')
for v in value:
annotate(v, glb_schema['$defs'][sch_ref]['properties'], level+1)
else: # value is scalar
print(' '*level, description, ':', value)
annotate(data[-260][1], glb_schema['properties'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment