run.py 5.94 KB
Newer Older
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-
from __future__ import print_function

import sys
import json
from verify_ehc import *
from datetime import datetime, timedelta
import time
import pyzbar.pyzbar as pyzbar
import numpy as np
import cv2
Bernhard Heinloth's avatar
Bernhard Heinloth committed
12
import unicodedata
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
13

Bernhard Heinloth's avatar
Bernhard Heinloth committed
14
15
16
17
18
19
20
21
22
23
24
# Webcam 
# device (X = /dev/videoX)
WEBCAM_DEVICE = 0
WEBCAM_WIDTH = 1280
WEBCAM_HEIGHT = 720
WINDOW_NAME = 'CovPass Check'


cap = cv2.VideoCapture(WEBCAM_DEVICE)
cap.set(cv2.CAP_PROP_FRAME_WIDTH,WEBCAM_WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT,WEBCAM_HEIGHT)
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
25
26
font_simplex = cv2.FONT_HERSHEY_SIMPLEX
font_duplex = cv2.FONT_HERSHEY_DUPLEX
Bernhard Heinloth's avatar
Bernhard Heinloth committed
27
cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL)
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
28
29
30

qrcodes={}
process=[]
31
uniqusers=[]
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
32
33
34
35
36
37
38
39
40
41
42
43
validusers=0
EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)

print("Downloading...")
certs_table: Dict[str, CertList] = {}
certs: Optional[CertList] = download_ehc_certs(['DE', 'AT', 'SE', 'GB', 'NL'], certs_table);
if not certs:
    print("empty trust list!")
    sys.exit(1)

print("Ready...")

Bernhard Heinloth's avatar
Bernhard Heinloth committed
44
45
46
47
48
49
normalize_mapping = [ ('Ä', 'Ae'), ('Ö', 'Oe'), ('Ü', 'Ue'), ('ä', 'ae'), ('ö', 'oe'), ('ü', 'ue'), ('ß', 'ss') ]
def normalize(s):
    for f, t in normalize_mapping:
       s = s.replace(f, t)
    return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn').strip()

Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def validate(ehc_msg, ehc_payload):
    try:
        issued_at = EPOCH + timedelta(seconds=ehc_payload[6])

        expires_at_int = ehc_payload.get(4)
        if expires_at_int is not None and datetime.utcnow() > datetime(1970, 1, 1) + timedelta(seconds=expires_at_int):
            print('Expired!')
            return False;

        if certs is not None:
            return verify_ehc(ehc_msg, issued_at, certs, False)
    except:
        print('Failed', sys.exc_info())
    return False

Bernhard Heinloth's avatar
Bernhard Heinloth committed
65
66
67
68
69
70
71
allowed=[]
if len(sys.argv) > 1:
    with open(sys.argv[1], "r") as data:
        for line in data.readlines():
            allowed.append(normalize(line).split(";"))
    print("Only allowed person")

Bernhard Heinloth's avatar
Bernhard Heinloth committed
72
73
74
75
if not cap.isOpened():
    cap.open(WEBCAM_DEVICE)

while cap.isOpened():
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Our operations on the frame come here
    im = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    decodedObjects = pyzbar.decode(im)

    for decodedObject in decodedObjects: 
         # Check barcode
        if decodedObject.type == 'QRCODE':

            # Is qr code known?
            qrcode = decodedObject.data.decode('ascii')
            if qrcode in qrcodes:
                if qrcodes[qrcode]['valid']:
90
                    if qrcodes[ehc_code]['unique'] and (len(allowed) == 0 or qrcodes[ehc_code]['allowed']):
Bernhard Heinloth's avatar
Bernhard Heinloth committed
91
92
93
                        color = (119,155,0)
                    else:
                        color = (19,147,201)
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
                else:
                    color = (41,20,141)
                text = qrcodes[qrcode]['name']
            else:
                # Add to process list
                process.append(qrcode)
                color = (101,56,0)
                text = '???'

            points = decodedObject.polygon
            # If the points do not form a quad, find convex hull
            if len(points) > 4 : 
                hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32))
                hull = list(map(tuple, np.squeeze(hull)))
            else:
                hull = points;
            # Number of points in the convex hull
            n = len(hull)
            # Draw the convext hull
            for j in range(0,n):
               cv2.line(frame, hull[j], hull[ (j+1) % n], color, 3)
            # Text
            x = decodedObject.rect.left
            y = decodedObject.rect.top
            cv2.putText(frame, text, (x, y - 10), font_simplex, 1, color, 2, cv2.LINE_AA)

    # Full counter
    cv2.putText(frame, str(validusers), (10, 60), cv2.FONT_HERSHEY_DUPLEX, 2, (119,155,0), 4, cv2.LINE_AA)
    # Display the resulting frame
Bernhard Heinloth's avatar
Bernhard Heinloth committed
123
    cv2.imshow(WINDOW_NAME, frame)
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
124
125
126
127
128
129
130
131

    # Check unprocessed qr codes
    for ehc_code in process:
        print("New qr code", ehc_code)
        qrcodes[ehc_code] = {}
        try:
            ehc_msg = decode_ehc(ehc_code)
            ehc_payload = cbor2.loads(ehc_msg.payload)
Bernhard Heinloth's avatar
Bernhard Heinloth committed
132
133
134
            gn = normalize(ehc_payload[-260][1]['nam']['gn'])
            fn = normalize(ehc_payload[-260][1]['nam']['fn'])
            qrcodes[ehc_code]['name'] = gn + ' ' + fn
135
136
137
138
139
140
141
142
            uid = ehc_payload[-260][1]['nam']['fnt'] + '<<<' + ehc_payload[-260][1]['nam']['gnt']  + '<<<<' + ehc_payload[-260][1]['dob']
            qrcodes[ehc_code]['uid'] = uid
            if uid in uniqusers:
                print(uid, "not unique!")
                qrcodes[ehc_code]['unique'] = False
            else:
                uniqusers.append(uid)
                qrcodes[ehc_code]['unique'] = True
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
143
144
            qrcodes[ehc_code]['valid'] = validate(ehc_msg, ehc_payload)
            if qrcodes[ehc_code]['valid']:
Bernhard Heinloth's avatar
Bernhard Heinloth committed
145
146
147
148
149
150
151
152
153
154
155
156
157
                if len(allowed) > 0:
                    qrcodes[ehc_code]['allowed'] = False
                    gnt = ehc_payload[-260][1]['nam']['gnt'].replace('<',' ')
                    fnt = ehc_payload[-260][1]['nam']['fnt'].replace('<',' ')
                    for a in allowed:
                        if (fn in a[0] and gn in a[1]) or (fnt in a[0].upper() and gnt in a[1].upper()):
                            qrcodes[ehc_code]['allowed'] = True
                            break
                if len(allowed) == 0 or qrcodes[ehc_code]['allowed']:
                    validusers = validusers + 1
                    print(qrcodes[ehc_code]['name'], file=sys.stderr)
                else:
                    print(qrcodes[ehc_code]['name'], "(but not in list)", file=sys.stderr)
Bernhard Heinloth's avatar
Init  
Bernhard Heinloth committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
        except:
            qrcodes[ehc_code]['valid'] = False
            if not 'name' in qrcodes[ehc_code]:
                qrcodes[ehc_code]['name'] = '(Invalid EHC QR)'
            print('Failed', sys.exc_info())
    process.clear()

    key = cv2.waitKey(1)
    if key & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()