feat(legal): imprint & privacy notices, "Über MindSift"

- LEGAL_IMPRINT_/LEGAL_PRIVACY_ URL and Markdown (inline or *_FILE);
  only http(s) URLs accepted
- /auth/status exposes legal info; public GET /legal/{imprint|privacy}
- Links on login/setup screen and in the settings footer: URL opens a new
  tab, Markdown a reading modal; hidden when nothing is configured
- "Über MindSift" modal (version, license, repository) in settings and help
- Docs and compose/env examples

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-28 23:10:27 +01:00
1 parent a62b204e14
commit d6c70d7a8e
17 files changed
+318 -2

No files matched your search

+43
View File
@@ -27,6 +27,43 @@ type Config struct {
SMTPTLS bool
// SMTPSkipVerify accepts self-signed or mismatching certificates (internal mail servers)
SMTPSkipVerify bool
// Legal notices (Impressum, Datenschutz): an external URL and/or Markdown text, shown even before login
Legal LegalTexts
}
type LegalTexts struct {
ImprintURL, ImprintContent string
PrivacyURL, PrivacyContent string
}
// legalContent reads Markdown from NAME or, for longer texts, from the file named in NAME_FILE.
func legalContent(name string) string {
if v := strings.TrimSpace(os.Getenv(name)); v != "" {
return v
}
if path := strings.TrimSpace(os.Getenv(name + "_FILE")); path != "" {
data, err := os.ReadFile(path)
if err != nil {
slog.Warn("Rechtstext konnte nicht gelesen werden", "variable", name+"_FILE", "error", err)
return ""
}
return strings.TrimSpace(string(data))
}
return ""
}
// legalURL accepts only http(s) links, so a misconfiguration cannot inject javascript: URLs.
func legalURL(name string) string {
v := strings.TrimSpace(os.Getenv(name))
if v == "" {
return ""
}
if !strings.HasPrefix(v, "https://") && !strings.HasPrefix(v, "http://") {
slog.Warn("Rechtstext-URL ignoriert: nur http(s) erlaubt", "variable", name)
return ""
}
return v
}
func Load() *Config {
@@ -81,6 +118,12 @@ func Load() *Config {
SMTPFrom: smtpFrom,
SMTPTLS: smtpTLS,
SMTPSkipVerify: smtpSkipVerify,
Legal: LegalTexts{
ImprintURL: legalURL("LEGAL_IMPRINT_URL"),
ImprintContent: legalContent("LEGAL_IMPRINT_CONTENT"),
PrivacyURL: legalURL("LEGAL_PRIVACY_URL"),
PrivacyContent: legalContent("LEGAL_PRIVACY_CONTENT"),
},
}
}