Neuer BenachrichtigungTransport hinter der Aktor-URL "Benachrichtigung": push schickt an alle angemeldeten Geraete (homeMesh.push_abos), mail ueber den SMTP-Zugang aus der config.ini. Ein Abo, das der Push-Dienst mit 404 oder 410 ablehnt, wird geloescht statt weiter angeschrieben. Daneben hoert der Runner auf benachrichtigung/# - darueber schickt die Probe aus den Einstellungen, ohne dass die Weboberflaeche verschluesseln muesste. Zugestellt wird im Haupttakt, nicht im MQTT-Faden. pywebpush, py_vapid und http_ece liegen wie die uebrigen Fremdpakete im Ordner, nicht in site-packages; transports.py haengt ihn an den Suchpfad. Das Schluesselpaar erzeugt vapid_erzeugen.py und bleibt ausserhalb des Git. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Einmalig: das VAPID-Schluesselpaar fuer Web Push erzeugen.
|
|
|
|
Der private Schluessel bleibt auf der NAS (der Runner unterschreibt damit
|
|
jede Nachricht), der oeffentliche geht in den Browser - er steckt im Abo und
|
|
laesst sich nicht missbrauchen. Beide landen in push_vapid.json neben
|
|
skoda.conf: ausserhalb des Web-Roots, aber fuer die Weboberflaeche lesbar,
|
|
die den oeffentlichen Teil braucht.
|
|
|
|
Vorhandene Schluessel werden NICHT ueberschrieben - alle bestehenden Abos
|
|
haengen daran und waeren sonst wertlos.
|
|
"""
|
|
import base64
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
ORDNER = "/volume1/homes/wagner/SolarManager"
|
|
ZIEL = os.path.join(ORDNER, "push_vapid.json")
|
|
sys.path.insert(0, ORDNER)
|
|
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
|
|
|
|
def b64(roh):
|
|
return base64.urlsafe_b64encode(roh).rstrip(b"=").decode("ascii")
|
|
|
|
|
|
if os.path.exists(ZIEL):
|
|
with open(ZIEL) as f:
|
|
vorhanden = json.load(f)
|
|
print("existiert schon, unveraendert:", vorhanden.get("public_key", "")[:16] + "…")
|
|
sys.exit(0)
|
|
|
|
schluessel = ec.generate_private_key(ec.SECP256R1())
|
|
privat = schluessel.private_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PrivateFormat.PKCS8,
|
|
encryption_algorithm=serialization.NoEncryption()).decode("ascii")
|
|
oeffentlich = schluessel.public_key().public_bytes(
|
|
encoding=serialization.Encoding.X962,
|
|
format=serialization.PublicFormat.UncompressedPoint)
|
|
|
|
with open(ZIEL, "w") as f:
|
|
json.dump({
|
|
"public_key": b64(oeffentlich),
|
|
"private_key_pem": privat,
|
|
# Wen die Push-Dienste bei Problemen erreichen. Muss eine mailto- oder
|
|
# https-Adresse sein, sonst lehnen manche Dienste ab.
|
|
"subject": "mailto:m0w1337@gmail.com",
|
|
}, f, indent=2)
|
|
os.chmod(ZIEL, 0o644)
|
|
print("neu erzeugt:", b64(oeffentlich))
|