Mealie anbinden: Passwort einmal, danach nur noch ein Dauertoken

Unter Einstellungen gibt es jetzt eine Karte "Mealie (Rezepte)": Adresse,
Benutzername, Passwort. Vorrania meldet sich damit EINMAL an
(POST /api/auth/token), laesst sich von Mealie ueber
POST /api/users/api-tokens ein Dauertoken ausstellen und verwirft das
Passwort sofort - es steht in keiner Zeile der Datenbank, in keiner
Antwort und in keinem Fehlertext. Wer sein Passwort gar nicht erst
eintippen will, haekelt "Ich gebe lieber selbst ein Token ein" an.

Das Token liegt NICHT in den Einstellungen: GET /settings liefert jedem
angemeldeten Nutzer alle Zeilen im Klartext. Eine Ausschlussliste dort
waere beim naechsten Geheimnis vergessen, deshalb eine eigene Tabelle ohne
jeden Leseweg - setzen, loeschen, und die Auskunft "ist gesetzt". Was
keinen Ausgang hat, kann nicht durchrutschen. Ein Test prueft genau das.

Der Dienst folgt services/oidc.py, nicht off.py: Bei Open Food Facts ist
"kein Treffer" der Normalfall und wird still zu None, hier ist "Mealie
antwortet nicht" ein Fehler, den der Nutzer sehen muss. Die Kennungen
trennen auch, was verschieden ist - ein falsches Passwort (400) ist etwas
anderes als ein weggetretener Server (502).

Mealie 1.x legt die Haushalts-Routen unter /api/groups/, 2.x unter
/api/households/. Erkannt wird das zur Laufzeit mit einer Anfrage und
dann eine Stunde gepuffert; ueber die Versionsnummer waere es unzuverlaessig,
die melden Installationen uneinheitlich.

Rezeptliste und -abgleich kommen als Naechstes; dies ist der Teil, mit dem
sich der Server ueberhaupt erst verbinden laesst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-02 12:54:43 +02:00
co-authored by Claude Opus 5
parent 37ab1ba47d
commit 7d8a54a3fc
9 changed files with 942 additions and 0 deletions
+25
View File
@@ -790,6 +790,31 @@ class Setting(Base):
value: Mapped[str] = mapped_column(String(255), nullable=False)
class IntegrationSecret(Base):
"""Zugangsgeheimnis für einen externen Dienst (heute: das Mealie-Dauertoken).
Bewusst **nicht** in :class:`Setting`: ``GET /settings`` liefert jedem
angemeldeten Nutzer alle Zeilen im Klartext. Eine Ausschlussliste dort wäre
beim nächsten Geheimnis vergessen. Diese Tabelle hat deshalb überhaupt
keinen Leseweg nach außen — setzen, löschen, und eine Auskunft „ist
gesetzt". Was keinen Ausgang hat, kann nicht durchrutschen.
Anders als bei :class:`ApiToken` muss der Klartext erhalten bleiben: Wir
legen ihn einem fremden Dienst vor, ein Hash nützte dort nichts. Er liegt
damit unverschlüsselt in der Datenbank — eine Verschlüsselung wäre Theater,
solange der Schlüssel daneben läge. Der Schutz ist: kein Leseweg, nur Admin
beim Setzen, nie in einer Antwort.
"""
__tablename__ = "integration_secrets"
service: Mapped[str] = mapped_column(String(32), primary_key=True)
secret: Mapped[str] = mapped_column(Text, nullable=False)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=_now, onupdate=_now
)
class Shop(Base):
"""Bezugsquelle / Geschäft, aus dem ein Gegenstand stammt ("gekauft bei").