This is an Implementation of the Protocol used to generate Event-Location QR-Codes for the CoronaWarnApp (CWA) as described in Corona-Warn-App: Documentation – Event Registration - Summary.
This is not an official implementation – use it at your own risk (as far as that's possible, these days…).
The Interface described in the Document is implemented, the undocumented Pieces (Public Key Value, Seed Length, Versions etc.) have been taken from the Open Source iOS Client Application. As Far as I know the Interface has been fully implemented, but without an actual positive Corona Test there is no way to do an End-to-End verification.
The Library is not yet packaged as pip and so cwa-directory should be copied over to your project manually.
Useas follows:
#!/usr/bin/env python3
import io
from datetime import datetime, timedelta, timezone
import cwa
import qrcode.image.svg
eventDescription = cwa.CwaEventDescription()
eventDescription.locationDescription = 'Zuhause'
eventDescription.locationAddress = 'Gau-Odernheim'
eventDescription.startDateTime = datetime.now(timezone.utc)
eventDescription.endDateTime = datetime.now(timezone.utc) + timedelta(days=2)
eventDescription.locationType = cwa.lowlevel.LOCATION_TYPE_PERMANENT_WORKPLACE
eventDescription.defaultCheckInLengthInMinutes = 4 * 60
qr = cwa.generateQrCode(eventDescription)
# Render QR-Code to PNG-File
img = qr.make_image(fill_color="black", back_color="white")
img.save('example.png')
print("generated example.png")
# Render QR-Code to PNG BytesIO-Object for further usage
img_bytes = io.BytesIO()
img.save(img_bytes)
print(len(img_bytes.getvalue()), " bytes of png")
# Render QR-Code to SVG-File
svg = qr.make_image(image_factory=qrcode.image.svg.SvgPathFillImage)
svg.save('example.svg')
# Render QR-Code to SVG BytesIO-Object for further usage
svg_bytes = io.BytesIO()
svg.save(svg_bytes)
print(len(svg_bytes.getvalue()), " bytes of svg")
locationDescription
: Description of the Location, Optional, String, max 100 CharacterslocationAddress
: Address of the Location, Optional, String, max 100 CharactersstartDateTime
: Start of the Event, Optional, datetime in UTCendDateTime
: End of the Event, Optional, datetime in UTClocationType
: Type of the Location, Optional, one ofcwa.lowlevel.LOCATION_TYPE_UNSPECIFIED
= 0cwa.lowlevel.LOCATION_TYPE_PERMANENT_OTHER
= 1cwa.lowlevel.LOCATION_TYPE_TEMPORARY_OTHER
= 2cwa.lowlevel.LOCATION_TYPE_PERMANENT_RETAIL
= 3cwa.lowlevel.LOCATION_TYPE_PERMANENT_FOOD_SERVICE
= 4cwa.lowlevel.LOCATION_TYPE_PERMANENT_CRAFT
= 5cwa.lowlevel.LOCATION_TYPE_PERMANENT_WORKPLACE
= 6cwa.lowlevel.LOCATION_TYPE_PERMANENT_EDUCATIONAL_INSTITUTION
= 7cwa.lowlevel.LOCATION_TYPE_PERMANENT_PUBLIC_BUILDING
= 8cwa.lowlevel.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT
= 9cwa.lowlevel.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY
= 10cwa.lowlevel.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT
= 11cwa.lowlevel.LOCATION_TYPE_TEMPORARY_WORSHIP_SERVICE
= 12
defaultCheckInLengthInMinutes
: Default Checkout-Time im Minutes, OptionalrandomSeed
: Specific Seed, 16 Bytes, Optional, leave Empty if unsure, see Below for Explanation
To Mitigate Profiling of Venues, each QR-Code contains a 16 Bytes long random Seed Value, that makes each Code even with the same Data unique. This Way a Location can generate a fresh QR-Code each day and avoid the Risk of being tracked.
But sometimes it is Important to be able to re-generate the exact same Code ie. from a Database or other deterministic Sourcers. If this is important to you, you can specify your own 16-Bytes in the randomSeed
Parameter of the CwaEventDescription
Object. You can easily generate it with secrets.token_bytes(16)
.
This Library is targeted to Python 3, however there is a Backport to Python 2 available at https://github.com/MaZderMind/cwa-qr/tree/py2