102 lines
3.4 KiB
Go
102 lines
3.4 KiB
Go
package webui
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"mailgoserver/internal/db"
|
|
)
|
|
|
|
// createTestMailboxWithAppPasswordDAVOff is createTestMailboxWithAppPassword without the
|
|
// domain/mailbox CalDAV+CardDAV opt-ins — for tests that need to exercise the
|
|
// enablement gate itself rather than have it pre-satisfied.
|
|
func createTestMailboxWithAppPasswordDAVOff(t *testing.T, app *App, email string, domainID int64) int64 {
|
|
t.Helper()
|
|
mailboxID := createTestMailboxWithPassword(t, app, email, domainID, "portal-password-unused-1!")
|
|
hash, err := db.HashPassword(carddavTestAppPassword)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := app.DB.CreateAppPassword(mailboxID, "dav test", hash, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return mailboxID
|
|
}
|
|
|
|
// TestDAVDisabledByDefault confirms both protocols reject an otherwise-valid
|
|
// app-password login with 403 (not 401 — credentials are fine, the feature is just
|
|
// off) when neither the domain nor the mailbox has opted in, matching the requested
|
|
// default of "disabled for everyone."
|
|
func TestDAVDisabledByDefault(t *testing.T) {
|
|
app := newTestApp(t)
|
|
domains, _ := app.DB.ListDomains()
|
|
createTestMailboxWithAppPasswordDAVOff(t, app, "davoff@example.com", domains[0].ID)
|
|
srv := httptest.NewServer(app.Mux())
|
|
defer srv.Close()
|
|
|
|
for _, path := range []string{
|
|
"/caldav/davoff@example.com/calendars/default/",
|
|
"/carddav/davoff@example.com/addressbooks/default/",
|
|
} {
|
|
req, _ := http.NewRequest("PROPFIND", srv.URL+path, nil)
|
|
req.Header.Set("Depth", "0")
|
|
req.SetBasicAuth("davoff@example.com", carddavTestAppPassword)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp.Body.Close()
|
|
if resp.StatusCode != http.StatusForbidden {
|
|
t.Fatalf("%s: status=%d, want 403 (disabled by default)", path, resp.StatusCode)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestDAVRequiresBothDomainAndMailboxOptIn confirms neither the domain-wide admin
|
|
// switch nor the mailbox's own opt-in is sufficient alone — both must be on.
|
|
func TestDAVRequiresBothDomainAndMailboxOptIn(t *testing.T) {
|
|
app := newTestApp(t)
|
|
domains, _ := app.DB.ListDomains()
|
|
domainID := domains[0].ID
|
|
|
|
createTestMailboxWithAppPasswordDAVOff(t, app, "domainonly@example.com", domainID)
|
|
bothID := createTestMailboxWithAppPasswordDAVOff(t, app, "both@example.com", domainID)
|
|
|
|
if err := app.DB.SetDomainCalDAVEnabled(domainID, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := app.DB.SetMailboxDAVEnabled(bothID, true, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
srv := httptest.NewServer(app.Mux())
|
|
defer srv.Close()
|
|
propfind := func(email string) int {
|
|
req, _ := http.NewRequest("PROPFIND", srv.URL+"/caldav/"+email+"/calendars/default/", nil)
|
|
req.Header.Set("Depth", "0")
|
|
req.SetBasicAuth(email, carddavTestAppPassword)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp.Body.Close()
|
|
return resp.StatusCode
|
|
}
|
|
|
|
if got := propfind("domainonly@example.com"); got != http.StatusForbidden {
|
|
t.Fatalf("domain-only (mailbox not opted in): status=%d, want 403", got)
|
|
}
|
|
if got := propfind("both@example.com"); got != http.StatusMultiStatus {
|
|
t.Fatalf("domain+mailbox both on: status=%d, want 207", got)
|
|
}
|
|
|
|
// Now flip it around: mailbox opted in, but the domain-wide switch off.
|
|
if err := app.DB.SetDomainCalDAVEnabled(domainID, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := propfind("both@example.com"); got != http.StatusForbidden {
|
|
t.Fatalf("mailbox on but domain off: status=%d, want 403", got)
|
|
}
|
|
}
|