package webui import ( "net/http" "net/http/httptest" "strconv" "strings" "testing" "time" "mailgoserver/internal/db" ) // 1x1 transparent PNG, base64-encoded — a minimal real image for the attachment part. const testPNGBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" func buildTestMIMEMessageWithImage() string { boundary := "testboundary123" return strings.Join([]string{ "From: attacker@evil.example", "To: victim@example.com", "Subject: Free money", "MIME-Version: 1.0", "Content-Type: multipart/mixed; boundary=\"" + boundary + "\"", "", "--" + boundary, `Content-Type: text/html; charset="UTF-8"`, "", "
Click here to claim your prize.
", "", "--" + boundary, "Content-Type: image/png", "Content-Transfer-Encoding: base64", `Content-Disposition: attachment; filename="lure.png"`, "", testPNGBase64, "", "--" + boundary + "--", }, "\r\n") } // TestViewMessageContentRendersHTMLAndAttachmentInlineForStoredContent confirms that // when a log's message_body holds a full raw message (the new default for a // quarantined/opted-in message — see session.go's storeContent), the "View Full // Message" page actually renders the real HTML body and offers the attachment inline // (as a data: URI, no separate file/route needed) — not just a plain-text dump, and // not silently dropping the image the way the old text-only capture always did. func TestViewMessageContentRendersHTMLAndAttachmentInlineForStoredContent(t *testing.T) { app := newTestApp(t) mux := app.Mux() cookie := loginSession(t, app) logID, err := app.DB.InsertEmailLog(db.EmailLog{ MessageID: "test-msg-id", Timestamp: time.Now(), PeerIP: "203.0.113.5", MailFrom: "attacker@evil.example", ToAddress: "victim@example.com", Subject: "Free money", EmailHeaders: "From: attacker@evil.example\nSubject: Free money", MessageBody: buildTestMIMEMessageWithImage(), Status: "failed", }) if err != nil { t.Fatal(err) } req := httptest.NewRequest(http.MethodGet, Prefix+"/msg/content/"+strconv.FormatInt(logID, 10), nil) req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d: %s", rec.Code, rec.Body.String()) } body := rec.Body.String() if !strings.Contains(body, "Click") || !strings.Contains(body, "here") { t.Errorf("expected the sanitized HTML body rendered, got:\n%s", body) } if !strings.Contains(body, "data:image/png;base64,") { t.Error("expected the attachment rendered inline as a data: URI") } if !strings.Contains(body, "lure.png") { t.Error("expected the attachment's filename shown") } // This is fetched into a modal on the logs page, not navigated to directly — it // must be a bare fragment, not a full page with the dashboard's own nav/sidebar. if strings.Contains(body, "