]>
git.gir.st - greenpass.git/blob - greenpass.py
3 # Copyright 2021 Tobias Girstmair (https://gir.st). Consider this code GPLv3
6 # pip3 install flynn base45 PyPDF2 pyzbar
7 # dnf install zbar || apt install libzbar0
17 from pyzbar
import pyzbar
18 from datetime
import datetime
19 from urllib
.request
import urlopen
21 sch
= urlopen('https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-schema/release/1.3.0/DCC.combined-schema.json')
25 infile
= glob
.glob("COVID-19-*-*-*.pdf")[0]
26 print(f
"Warning: using file {found}, since not specified\n", file=sys
.stderr
)
28 print(f
"Usage: {sys.argv[0]} COVID-19-*-*-*.pdf", file=sys
.stderr
)
29 print(f
"Usage: {sys.argv[0]} QR_CODE.png", file=sys
.stderr
)
34 if open(infile
, "rb").read(4) == b
"%PDF":
35 # extract QR code from PDF using hard-coded index, size and bit depth.
36 # This will only work with the official Austrian green pass PDFs.
37 pdf
=PyPDF2
.PdfFileReader(open(infile
, "rb"))
38 qr_img
= pdf
.getPage(0)['/Resources']['/XObject']['/Im3']
39 qr_pil
= Image
.frombytes("1", (400,400), qr_img
.getData())
41 qr_pil
= Image
.open(infile
)
43 # decode QR code into raw bytes:
44 qr_data_zlib_b45
= pyzbar
.decode(qr_pil
)[0].data
46 # strip header ('HC1:') and decompress data:
47 qr_data_zlib
= base45
.b45decode(qr_data_zlib_b45
[4:])
49 qr_data
= zlib
.decompress(qr_data_zlib
)
51 # decode cose document:
52 (_
, (headers1
, headers2
, cbor_data
, signature
)) = flynn
.decoder
.loads(qr_data
)
53 # decode cbor-encoded payload:
54 data
= flynn
.decoder
.loads(cbor_data
)
56 date
= lambda ts
: datetime
.utcfromtimestamp(ts
).strftime('%Y-%m-%d %H:%M:%S')
57 print("QR Code Issuer :", data
[1])
58 print("QR Code Expiry :", date(data
[4]))
59 print("QR Code Generated :", date(data
[6]))
61 glb_schema
= json
.load(sch
)
63 def annotate(data
, schema
, level
=0):
64 for key
, value
in data
.items():
65 description
= schema
[key
].get('title') or schema
[key
].get('description') or key
66 description
, _
, _
= description
.partition(' - ')
67 if type(value
) is dict:
68 print(' '*level
, description
)
69 _
, _
, sch_ref
= schema
[key
]['$ref'].rpartition('/')
70 annotate(value
, glb_schema
['$defs'][sch_ref
]['properties'], level
+1)
71 elif type(value
) is list:
72 print(' '*level
, description
)
73 _
, _
, sch_ref
= schema
[key
]['items']['$ref'].rpartition('/')
75 annotate(v
, glb_schema
['$defs'][sch_ref
]['properties'], level
+1)
76 else: # value is scalar
77 print(' '*level
, description
, ':', value
)
79 annotate(data
[-260][1], glb_schema
['properties'])