Encrypt the notification channels' credentials at rest

The Gotify and ntfy tokens, the SMTP password and the webhook secret were stored
as plain text in the settings table. They are now encrypted with the same key as
integration credentials (CREDENTIALS_ENCRYPTION_KEY), marked with an "enc:v1:"
prefix. Settings are decrypted when read and encrypted when written, so nothing
else changes; values saved before this are converted at startup.

An edit that doesn't touch a credential keeps its stored ciphertext, so a wrong or
missing key (which reads as empty) can't be made permanent by an unrelated edit.
Without a key new credentials fall back to plain storage, and the startup warning,
.env.example and the Privacy page say so.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
bobbanandClaude Sonnet 5.5 committed 2026-10-05 00:53:07 +02:00
1 parent 86dfa9ae2e
commit f246410f24
5 files changed
+121 -9

No files matched your search

+4 -3
View File
@@ -5,9 +5,10 @@ APP_BASE_URL=https://homelab.example.lan
# node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
SESSION_SECRET=change-me-to-a-random-64-char-hex-string
# 32-byte (64 hex char) key used to encrypt stored integration API tokens at
# rest (AES-256-GCM). Generate the same way as SESSION_SECRET. Losing/changing
# this key makes previously-stored integration credentials unreadable.
# 32-byte (64 hex char) key used to encrypt stored integration API tokens, and the
# notification channels' credentials (Gotify/ntfy tokens, SMTP password, webhook
# secret), at rest (AES-256-GCM). Generate the same way as SESSION_SECRET.
# Losing/changing this key makes those stored credentials unreadable.
CREDENTIALS_ENCRYPTION_KEY=change-me-to-a-random-64-char-hex-string
# Port docker-compose publishes on the host (container always listens on 3000).