Files
SolarManager/vapid_erzeugen.py
T
adminandClaude Opus 5 35382a6ae1 Benachrichtigungen: Web Push und E-Mail als Kanaele der Automatiken
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>
2026-09-21 08:37:08 +02:00

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))