Files
mailgoserver/internal/webui/webmail_blocklist_test.go
T

139 lines
5.0 KiB
Go
Raw Normal View History

2026-08-15 21:49:25 +01:00
package webui
import (
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"strings"
"testing"
)
// TestWebmailMarkAsJunkAddsToBlocklistNotRules reproduces the intended behavior
// change: "Mark as Junk" used to create a filter rule (mark_as_spam action); it now
// adds the sender to the mailbox's own Blocklist ("junk" allowblock entries) instead,
// leaving the Rules list untouched.
func TestWebmailMarkAsJunkAddsToBlocklistNotRules(t *testing.T) {
app := newTestApp(t)
mux := app.Mux()
domains, _ := app.DB.ListDomains()
mailboxID := createTestMailboxWithPassword(t, app, "junker@example.com", domains[0].ID, "junker-password-1!")
cookie := webmailLoginSession(t, app, mailboxID)
uid := storeTestMessage(t, app, mailboxID, "INBOX", "spammer@example.com", "buy now", "body")
req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/INBOX/"+strconv.FormatInt(uid, 10)+"/mark-junk", nil)
req.AddCookie(cookie)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
if rec.Code != http.StatusFound {
t.Fatalf("mark as junk: status=%d body=%s", rec.Code, rec.Body.String())
}
junked, err := app.DB.IsJunked(mailboxID, "spammer@example.com")
if err != nil || !junked {
t.Fatalf("expected spammer@example.com added to the blocklist, junked=%v err=%v", junked, err)
}
rules, err := app.DB.ListRulesForMailbox(mailboxID)
if err != nil {
t.Fatal(err)
}
if len(rules) != 0 {
t.Fatalf("expected no filter rule created (blocklist replaces the old rule-based flow), got %+v", rules)
}
msgs, err := app.DB.ListMessagesInFolder(mailboxID, "Junk")
if err != nil || len(msgs) != 1 {
t.Fatalf("expected the message itself moved to Junk, got %d (err=%v)", len(msgs), err)
}
}
// TestWebmailBlocklistAddAndRemove exercises the self-service Blocklist/Whitelist
// page's add+remove flow for both list types.
func TestWebmailBlocklistAddAndRemove(t *testing.T) {
app := newTestApp(t)
mux := app.Mux()
domains, _ := app.DB.ListDomains()
mailboxID := createTestMailboxWithPassword(t, app, "lister@example.com", domains[0].ID, "lister-password-1!")
cookie := webmailLoginSession(t, app, mailboxID)
add := func(pattern, listType string) *httptest.ResponseRecorder {
form := url.Values{"pattern": {pattern}, "list_type": {listType}}
req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/blocklist/add", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(cookie)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
return rec
}
if rec := add("bad@example.com", "junk"); rec.Code != http.StatusFound {
t.Fatalf("add junk: status=%d", rec.Code)
}
if rec := add("good@example.com", "allow"); rec.Code != http.StatusFound {
t.Fatalf("add allow: status=%d", rec.Code)
}
entries, err := app.DB.ListAllowBlock(mailboxID)
if err != nil || len(entries) != 2 {
t.Fatalf("expected 2 entries, got %d (err=%v)", len(entries), err)
}
// "block" (admin's hard-reject list) must not be settable from this self-service
// endpoint.
if rec := add("someone@example.com", "block"); rec.Code != http.StatusFound {
t.Fatalf("status=%d", rec.Code)
}
entries, err = app.DB.ListAllowBlock(mailboxID)
if err != nil || len(entries) != 2 {
t.Fatalf("expected 'block' rejected (still 2 entries), got %d (err=%v)", len(entries), err)
}
var junkID int64
for _, e := range entries {
if e.ListType == "junk" {
junkID = e.ID
}
}
rmReq := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/blocklist/"+strconv.FormatInt(junkID, 10)+"/remove", nil)
rmReq.AddCookie(cookie)
rmRec := httptest.NewRecorder()
mux.ServeHTTP(rmRec, rmReq)
if rmRec.Code != http.StatusFound {
t.Fatalf("remove: status=%d", rmRec.Code)
}
remaining, err := app.DB.ListAllowBlock(mailboxID)
if err != nil || len(remaining) != 1 || remaining[0].ListType != "allow" {
t.Fatalf("expected only the allow entry left, got %+v (err=%v)", remaining, err)
}
}
// TestWebmailBlocklistScopedToOwnMailbox confirms one mailbox owner can't remove
// another mailbox's blocklist entry by guessing its ID.
func TestWebmailBlocklistScopedToOwnMailbox(t *testing.T) {
app := newTestApp(t)
mux := app.Mux()
domains, _ := app.DB.ListDomains()
victimID := createTestMailboxWithPassword(t, app, "victim3@example.com", domains[0].ID, "victim-password-1!")
attackerID := createTestMailboxWithPassword(t, app, "attacker3@example.com", domains[0].ID, "attacker-password-1!")
entryID, err := app.DB.AddAllowBlockEntry(victimID, "junk", "spam@example.com")
if err != nil {
t.Fatal(err)
}
attackerCookie := webmailLoginSession(t, app, attackerID)
req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/blocklist/"+strconv.FormatInt(entryID, 10)+"/remove", nil)
req.AddCookie(attackerCookie)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
if rec.Code != http.StatusFound {
t.Fatalf("status=%d", rec.Code)
}
stillThere, err := app.DB.ListAllowBlock(victimID)
if err != nil || len(stillThere) != 1 {
t.Fatalf("expected the victim's entry untouched, got %d (err=%v)", len(stillThere), err)
}
}