139 lines
5.0 KiB
Go
139 lines
5.0 KiB
Go
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)
|
|
}
|
|
}
|