72 lines
2.6 KiB
Python
72 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Erzeugt das VAPID-Schlüsselpaar für Web Push.
|
|
|
|
python3 tools/vapid-keys.py
|
|
|
|
VAPID ("Voluntary Application Server Identification") ist die Art, wie
|
|
sich dieser Server gegenüber den Push-Diensten der Browserhersteller
|
|
ausweist. Das Schlüsselpaar gehört dir - es ist kein Konto bei Google
|
|
oder Apple nötig und es fließen keine Daten an Dritte, außer der
|
|
verschlüsselten Nachricht selbst.
|
|
|
|
Der öffentliche Schlüssel geht an den Browser, der private bleibt auf dem
|
|
Server. Wird der private Schlüssel getauscht, verlieren alle bestehenden
|
|
Anmeldungen ihre Gültigkeit und müssen erneuert werden - deshalb einmal
|
|
erzeugen und dann in Ruhe lassen.
|
|
|
|
Läuft ohne Zusatzpakete: `cryptography` ist bereits eine Abhängigkeit
|
|
des Backends.
|
|
"""
|
|
|
|
import base64
|
|
import sys
|
|
|
|
try:
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
from cryptography.hazmat.primitives import serialization
|
|
except ImportError:
|
|
print(
|
|
"Das Paket 'cryptography' fehlt. Entweder im Container ausführen:\n"
|
|
" docker compose exec api python3 tools/vapid-keys.py\n"
|
|
"oder lokal installieren: pip install cryptography",
|
|
file=sys.stderr,
|
|
)
|
|
raise SystemExit(1)
|
|
|
|
|
|
def b64(data: bytes) -> str:
|
|
"""base64url ohne Auffüllzeichen - so verlangen es Web Push und JWT."""
|
|
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
|
|
|
|
|
|
def main() -> int:
|
|
key = ec.generate_private_key(ec.SECP256R1())
|
|
|
|
# Privater Schlüssel: die 32 Byte des Skalars, nicht das PEM-Format.
|
|
# py_vapid nimmt diese Form direkt an.
|
|
private_value = key.private_numbers().private_value
|
|
private_bytes = private_value.to_bytes(32, "big")
|
|
|
|
# Öffentlicher Schlüssel: unkomprimierter Punkt, 65 Byte (0x04 + X + Y).
|
|
# Genau diese Form erwartet der Browser als applicationServerKey.
|
|
public_bytes = key.public_key().public_bytes(
|
|
encoding=serialization.Encoding.X962,
|
|
format=serialization.PublicFormat.UncompressedPoint,
|
|
)
|
|
|
|
print("# In die .env übernehmen. Vorhandene Zeilen ERSETZEN, nicht")
|
|
print("# ergänzen: Bei doppelten Einträgen nimmt Docker Compose den")
|
|
print("# letzten - und das ist oft die leere Vorlagenzeile.\n")
|
|
print(f"VAPID_PRIVATE_KEY={b64(private_bytes)}")
|
|
print(f"VAPID_PUBLIC_KEY={b64(public_bytes)}")
|
|
print("# Kontaktadresse für die Push-Dienste - bei Problemen melden sie sich dort.")
|
|
print("VAPID_SUBJECT=mailto:admin@example.de")
|
|
print()
|
|
print("# Der private Schlüssel gehört NICHT ins Versionsverwaltungssystem.")
|
|
print("# Ein Wechsel entwertet alle bestehenden Anmeldungen.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|