Document review fixes and harden mail actions
This commit is contained in:
parent
4f8a441d51
commit
21aa6e39e1
5 changed files with 101 additions and 3 deletions
|
|
@ -65,6 +65,9 @@ func RegisterRoutes(mux *http.ServeMux) {
|
|||
}
|
||||
|
||||
func mailSendHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !requireManager(w, r) {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -271,6 +271,9 @@ func archiveFolderSortKey(name string) string {
|
|||
}
|
||||
|
||||
func manualCopyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !requireManager(w, r) {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -17,13 +17,25 @@ func SendPlainMail(to []string, subject, body string) error {
|
|||
if strings.TrimSpace(cfg.Host) == "" || cfg.Port == 0 || strings.TrimSpace(cfg.From) == "" {
|
||||
return fmt.Errorf("forward_smtp ist nicht vollstaendig konfiguriert")
|
||||
}
|
||||
fromHeader, err := cleanMailHeader(cfg.From)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ungueltiger Absender: %w", err)
|
||||
}
|
||||
subjectHeader, err := cleanMailHeader(subject)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ungueltiger Betreff: %w", err)
|
||||
}
|
||||
toHeader, err := cleanMailHeader(strings.Join(to, ", "))
|
||||
if err != nil {
|
||||
return fmt.Errorf("ungueltiger Empfaenger: %w", err)
|
||||
}
|
||||
from := cfg.From
|
||||
if strings.TrimSpace(cfg.User) != "" {
|
||||
from = cfg.User
|
||||
}
|
||||
message := []byte("From: " + cfg.From + "\r\n" +
|
||||
"To: " + strings.Join(to, ", ") + "\r\n" +
|
||||
"Subject: " + subject + "\r\n" +
|
||||
message := []byte("From: " + fromHeader + "\r\n" +
|
||||
"To: " + toHeader + "\r\n" +
|
||||
"Subject: " + subjectHeader + "\r\n" +
|
||||
"Content-Type: text/plain; charset=utf-8\r\n" +
|
||||
"\r\n" + body)
|
||||
addr := net.JoinHostPort(cfg.Host, fmt.Sprint(cfg.Port))
|
||||
|
|
@ -37,6 +49,17 @@ func SendPlainMail(to []string, subject, body string) error {
|
|||
return sendStartTLS(addr, cfg.Host, auth, from, to, message)
|
||||
}
|
||||
|
||||
func cleanMailHeader(value string) (string, error) {
|
||||
cleaned := strings.TrimSpace(value)
|
||||
if cleaned == "" {
|
||||
return "", nil
|
||||
}
|
||||
if strings.ContainsAny(cleaned, "\r\n") {
|
||||
return "", fmt.Errorf("Header darf keine Zeilenumbrueche enthalten")
|
||||
}
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
func sendStartTLS(addr, host string, auth smtp.Auth, from string, to []string, message []byte) error {
|
||||
c, err := smtp.Dial(addr)
|
||||
if err != nil {
|
||||
|
|
|
|||
12
backend/09-smtp_test.go
Normal file
12
backend/09-smtp_test.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package backend
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCleanMailHeaderRejectsLineBreaks(t *testing.T) {
|
||||
if _, err := cleanMailHeader("Betreff\r\nBcc: attacker@example.com"); err == nil {
|
||||
t.Fatal("expected CRLF header injection to be rejected")
|
||||
}
|
||||
if got, err := cleanMailHeader(" Normaler Betreff "); err != nil || got != "Normaler Betreff" {
|
||||
t.Fatalf("cleanMailHeader returned %q, %v", got, err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue