package webui import ( "bytes" "mime/multipart" "net/http" "net/http/httptest" "net/url" "strconv" "strings" "testing" "mailgoserver/internal/mailview" ) // TestWebmailComposeSendLocalDelivery confirms a composed message reaches another // local mailbox's INBOX with the right content, and a copy lands in the sender's own // Sent folder — the core send/receive round trip. func TestWebmailComposeSendLocalDelivery(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() domainID := domains[0].ID senderID := createTestMailboxWithPassword(t, app, "sender@example.com", domainID, "sender-password-1!") recipientID := createTestMailboxWithPassword(t, app, "recipient@example.com", domainID, "recipient-password-1!") cookie := webmailLoginSession(t, app, senderID) form := url.Values{ "to": {"recipient@example.com"}, "subject": {"Hello there"}, "body_html": {"This is the message body."}, } req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/compose", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusFound { t.Fatalf("compose send: status=%d body=%s", rec.Code, rec.Body.String()) } recipientMsgs, err := app.DB.ListMessagesInFolder(recipientID, "INBOX") if err != nil { t.Fatal(err) } if len(recipientMsgs) != 1 { t.Fatalf("expected 1 message in recipient's INBOX, got %d", len(recipientMsgs)) } if recipientMsgs[0].CachedSubject != "Hello there" { t.Errorf("recipient subject = %q", recipientMsgs[0].CachedSubject) } senderSent, err := app.DB.ListMessagesInFolder(senderID, "Sent") if err != nil { t.Fatal(err) } if len(senderSent) != 1 { t.Fatalf("expected 1 message in sender's Sent folder, got %d", len(senderSent)) } // Recipient can actually read it via the message view. recipientCookie := webmailLoginSession(t, app, recipientID) viewReq := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/INBOX/"+strconv.FormatInt(recipientMsgs[0].ID, 10), nil) viewReq.AddCookie(recipientCookie) viewRec := httptest.NewRecorder() mux.ServeHTTP(viewRec, viewReq) if viewRec.Code != http.StatusOK { t.Fatalf("view message: status=%d", viewRec.Code) } if !strings.Contains(viewRec.Body.String(), "This is the message body.") { t.Error("expected the message body in the rendered view") } // It's also recorded in the admin email log for visibility. logs, _ := app.DB.ListEmailLogsPage(0, 10) found := false for _, l := range logs { if l.Subject == "Hello there" && l.MailFrom == "sender@example.com" { found = true } } if !found { t.Error("expected the webmail send to show up in the admin email log") } } // TestWebmailMessageHTMLBodyIsSanitized confirms a malicious HTML body (e.g. from a // received message, not something webmail's own plain-text compose can produce) never // reaches the page unsanitized — this is the actual stored-XSS defense. func TestWebmailMessageHTMLBodyIsSanitized(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "victim@example.com", domains[0].ID, "victim-password-1!") raw := "From: attacker@evil.example\r\nTo: victim@example.com\r\nSubject: gotcha\r\n" + "Content-Type: text/html\r\n\r\n" + `
hello