./discourse-setup setzt SMTP-Benutzernamen an den Anfang des SMTP-Passworts

Von LLM/KI generierte Empfehlungen

Unten ist ein kleiner Patch, der:

  • sed nicht mehr verwendet
  • eine prozentkodierte SMTP_URL erstellt
  • containers/app.yml über Ruby’s YAML (Psych) bearbeitet, sodass YAML-Anführungszeichen/Escaping von einem echten Parser behandelt werden
  • die SMTP-Variablen pro Schlüssel löscht, um Widersprüche zu vermeiden

Anwenden mit git apply -p0 im discourse_docker-Repository.


Patch 1 -

discourse-setup

(SMTP mit Ruby YAML schreiben, nicht mit sed)

--- a/discourse-setup
+++ b/discourse-setup
@@ -867,6 +867,77 @@ write_smtp_settings() {
   local app_yml="containers/app.yml"
   [[ -f "$app_yml" ]] || die "Cannot find $app_yml. Did you run bootstrap?"

+  # URL-kodierte SMTP_URL mit Python-Standardbibliothek erstellen (keine Shell-Escaping-Spielchen)
+  urlencode() {
+    python3 - <<'PY'
+import sys, urllib.parse
+print(urllib.parse.quote(sys.stdin.read().strip(), safe='._~-'))
+PY
+  }
+
+  # WICHTIG: Variablen ohne Backslash-Veränderung lesen
+  # (diese stammen aus früheren Prompts; stellen Sie einfach sicher, dass -r zur Prompt-Zeit verwendet wird)
+  local addr="$smtp_address"
+  local port="$smtp_port"
+  local user_enc pass_enc
+  user_enc="$(printf '%s' "$smtp_user"     | urlencode)"
+  pass_enc="$(printf '%s' "$smtp_password" | urlencode)"
+  local smtp_url="smtp://${user_enc}:${pass_enc}@${addr}:${port}"
+
+  # Ruby verwenden, um YAML sicher zu laden/modifizieren/dumpen (tötet 3 Ebenen des Escapings)
+  ruby - <<'RUBY' "$app_yml" "$smtp_url"
+require "yaml"
+require "psych"
+path, url = ARGV
+doc = YAML.safe_load(File.read(path), permitted_classes: [], aliases: true) || {}
+
+# Sicherstellen, dass die oberste Struktur ein Hash ist und env enthält
+unless doc.is_a?(Hash)
+  abort "containers/app.yml parst nicht zu einem Hash"
+end
+doc["env"] ||= {}
+env = doc["env"]
+
+# Einzelzeilige SMTP_URL schreiben; pro Schlüssel entfernte Variablen, um Konflikte zu vermeiden
+env["SMTP_URL"] = url
+%w[DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_PORT DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD].each { |k| env.delete(k) }
+
+# Zurückschreiben. (Psych bewahrt Zeichenketten sicher kodiert, wie benötigt.)
+File.write(path, Psych.dump(doc))
+RUBY
+
+  # Schnelle Integritätsprüfung für das klassische Fehlschlagen "Passwort mit Benutzernamen als Präfix"
+  python3 - <<'PY'
+import re, sys
+y = open("containers/app.yml","r",encoding="utf-8").read()
+m = re.search(r'^\\s*SMTP_URL:\\s*(?:\"|\\')?([^\\r\\n\"\\']+)', y, re.M)
+assert m, "SMTP_URL nach dem Schreiben fehlt"
+creds = m.group(1).split('@',1)[0].split('://',1)[-1]
+assert ":" in creds, "SMTP_URL-Anmeldedaten fehlen ':'"
+u, p = creds.split(':',1)
+assert not p.startswith(u), "Passwort scheint mit Benutzernamen als Präfix versehen zu sein"
+print("SMTP_URL sieht vernünftig aus.")
+PY
+}
+
-  # Schreibe SMTP-Einträge pro Schlüssel (Adresse/Port/Benutzername/Passwort)
-  # (Legacy: durchgeführt über sed-Substitutionen)
-  # HINWEIS: Historisch fragil bei Sonderzeichen
-  update_setting_yaml "DISCOURSE_SMTP_ADDRESS"  "$smtp_address"
-  update_setting_yaml "DISCOURSE_SMTP_PORT"     "$smtp_port"
-  update_setting_yaml "DISCOURSE_SMTP_USER_NAME" "$smtp_user"
-  update_setting_yaml "DISCOURSE_SMTP_PASSWORD" "$smtp_password"
-}
+  # (Legacy-Schreibvorgänge pro Schlüssel zugunsten von SMTP_URL über YAML entfernt)
+}

dann Patch 2 -

templates/web.template.yml

(um den sichereren Weg zu dokumentieren)

--- a/templates/web.template.yml
+++ b/templates/web.template.yml
@@ -68,6 +68,14 @@ params:
   DISCOURSE_SMTP_ENABLE_START_TLS: true
   #DISCOURSE_NOTIFICATION_EMAIL: noreply@example.com

+  ## Bevorzugte einzeilige SMTP-Konfiguration (gesetzt durch discourse-setup):
+  ## URL-kodieren Sie Benutzername und Passwort; Beispiel:
+  ##   SMTP_URL: "smtp://user%40example.com:p%40ss%3Aword@smtp.example.com:587"
+  ##
+  #SMTP_URL:
+
   ## Wenn Sie SMTP_URL nicht verwenden können, können Sie stattdessen Variablen pro Schlüssel setzen.
   ## Beachten Sie, dass die Bearbeitung dieser Zeilen mit Shell-Tools fragil sein kann, wenn Werte enthalten
   ## Zeichen wie @, :, /, ", \, oder Zeilenumbrüche.

Warum das funktioniert (und was es vermeidet)
• Bash-Ebene: Wir interpolieren nur einfache Variablen; Geheimnisse werden über stdin/argv an Python/Ruby übergeben, nicht über sed-Regexes oder Shell-Evals.
• Sed-Ebene: vollständig entfernt.
• YAML-Ebene: Ruby/Psych behandelt Anführungszeichen und Escaping ordnungsgemäß; keine handgefertigten Anführungszeichen.
• SMTP-Anmeldedaten: %-Kodierung in SMTP_URL ist der richtige Ort, um Sonderzeichen für die Authentifizierung zu kodieren.

Wenn Sie lieber Variablen pro Schlüssel beibehalten möchten, kann ich Ihnen einen Schwester-Patch geben, der denselben Ruby-YAML-Ansatz verwendet, um DISCOURSE_SMTP_* direkt zu setzen (immer noch kein sed), aber der SMTP_URL-Weg ist der sauberste, da es sich um einen Schlüssel, einen Schreibvorgang und einen Kodierungsschritt handelt.