./discourse-setup שם המשתמש של SMTP בתחילת סיסמת ה-SMTP

LLM/AI -generated recommendations

להלן תיקון קצר ש:

  • מפסיק להשתמש ב-sed
  • בונה SMTP_URL מקודד באחוזים
  • עורך את containers/app.yml באמצעות Ruby’s YAML (Psych), כך שציטוט/בריחה של YAML מטופלים על ידי מנתח אמיתי
  • מוחק את משתני ה-SMTP לכל מפתח כדי למנוע סתירות

החל באמצעות git apply -p0 במאגר discourse_docker.


תיקון 1 -

discourse-setup

(כותב SMTP באמצעות Ruby YAML, לא 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?"

+  # Build a URL-encoded SMTP_URL using Python stdlib (no shell escaping games)
+  urlencode() {
+    python3 - <<'PY'
+import sys, urllib.parse
+print(urllib.parse.quote(sys.stdin.read().strip(), safe='._~-'))
+PY
+  }
+
+  # IMPORTANT: read vars without backslash mangling
+  # (these come from earlier prompts; just ensure -r is used at prompt time)
+  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}"
+
+  # Use Ruby to safely load/modify/dump YAML (kills 3 layers of escaping)
+  ruby - <<'RUBY' "$app_yml" "$smtp_url"
+require "yaml"
+require "psych"
+path, url = ARGV
+doc = YAML.safe_load(File.read(path), permitted_classes: [], aliases: true) || {}
+
+# Ensure top-level structure is a Hash and has env
+unless doc.is_a?(Hash)
+  abort "containers/app.yml does not parse to a Hash"
+end
+doc["env"] ||= {}
+env = doc["env"]
+
+# Write single-line SMTP_URL; remove per-key vars to avoid conflicts
+env["SMTP_URL"] = url
+%w[DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_PORT DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD].each { |k| env.delete(k) }
+
+# Dump back. (Psych preserves strings safely quoted as needed.)
+File.write(path, Psych.dump(doc))
+RUBY
+
+  # quick sanity check for the classic "password prefixed by username" failure
+  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 missing after write"
+creds = m.group(1).split('@',1)[0].split('://',1)[-1]
+assert ":" in creds, "SMTP_URL creds missing ':'"
+u, p = creds.split(':',1)
+assert not p.startswith(u), "Password appears prefixed by username"
+print("SMTP_URL looks sane.")
+PY
+}
+
-  # Write per-key SMTP entries (address/port/username/password)
-  # (legacy: performed via sed substitutions)
-  # NOTE: historically fragile with special chars
-  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 per-key writes removed in favor of SMTP_URL via YAML)
+}

ואז תיקון 2 -

templates/web.template.yml

(כדי לתעד את הנתיב הבטוח יותר)

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

+  ## Preferred single-line SMTP configuration (set by discourse-setup):
+  ## URL-encode username & password; example:
+  ##   SMTP_URL: "smtp://user%40example.com:p%40ss%3Aword@smtp.example.com:587"
+  ##
+  #SMTP_URL:
+
   ## If you cannot use SMTP_URL, you may set per-key variables instead.
   ## Beware that editing those lines with shell tools can be fragile if values include
   ## characters like @, :, /, ", \, or newlines.

למה זה עובד (ומה זה נמנע)
• שכבת bash: אנו רק משלבים משתנים פשוטים; סודות מועברים לפייתון/רובי דרך stdin/argv, לא דרך ביטויי sed או הערכות shell.
• שכבת sed: הוסרה לחלוטין.
• שכבת YAML: Ruby/Psych מטפלת בציטוט ובבריחה כראוי; אין ציטוטים שנעשו ידנית.
• אישורי SMTP: קידוד % ב-SMTP_URL הוא המקום הנכון לקודד תווים מיוחדים לאימות.

אם אתה מעדיף לשמור על משתנים לכל מפתח, אני יכול לתת לך תיקון אחות שמשתמש באותה גישת Ruby-YAML כדי להגדיר ישירות את DISCOURSE_SMTP_* (עדיין ללא sed), אבל נתיב ה-SMTP_URL הוא הנקי ביותר מכיוון שהוא מפתח אחד, כתיבה אחת, שלב קידוד אחד.