Files
archivmail/internal/api/user_address_rules_test.go
patrickandClaude Sonnet 5.5 5248a177ce feat(PROJ-87,PROJ-90): Zusatzadressen pro User und Sichtbarkeit aller Mails eigener IMAP-Konten
Rolle user sieht zusätzlich Mails mit Zusatzadressen (PROJ-87) und alle Mails
von IMAP-Konten, deren owner dem User im selben Tenant entspricht (PROJ-90).
Liste, Nachprüfung und Detailzugriff nutzen dieselbe Regel (mailAccess).
Index: Token imapacct<id> in rcpt_addr, Reindex für Bestandsmails nötig.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 12:10:57 +01:00

106 lines
3.8 KiB
Go

package api
import (
"net/http"
"strings"
"testing"
"archivmail/internal/auth"
"archivmail/internal/userstore"
)
func TestNormalizeExtraAddress(t *testing.T) {
valid := map[string]string{
"alias@example.com": "alias@example.com",
" Team-Box@Example.ORG ": "team-box@example.org",
"max.muster+tag@ex-ample.com": "max.muster+tag@ex-ample.com",
"a_b@sub.example.com": "a_b@sub.example.com",
}
for in, want := range valid {
got, err := normalizeExtraAddress(in)
if err != nil || got != want {
t.Errorf("%q: got %q, %v; want %q", in, got, err, want)
}
}
invalid := []string{
"", " ", "example.com", "@example.com", "alias@", "alias@localhost",
"*@example.com", "alias?@example.com", "al*ias@example.com", "alias@*.example.com",
"Alias <alias@example.com>", "a@example.com, b@example.com", "a@example.com;b@example.com",
`"a b"@example.com`, "a b@example.com", "a@b@example.com", "alias@.example.com",
"alias@example.com.", "alias@example..com", "-@example.com", "...@example.com",
"alias@exämple.com", "ali\nas@example.com", "%@example.com", "(alias)@example.com",
strings.Repeat("a", 250) + "@example.com",
}
for _, in := range invalid {
if got, err := normalizeExtraAddress(in); err == nil {
t.Errorf("%q: expected error, got %q", in, got)
}
}
}
func TestExtraAddressRoleAllowed(t *testing.T) {
tid := int64(1)
tests := []struct {
role string
tenant *int64
want bool
}{
{userstore.RoleSuperAdmin, nil, true},
{userstore.RoleDomainAdmin, &tid, true},
{userstore.RoleAdmin, &tid, true},
{userstore.RoleDomainAdmin, nil, false},
{userstore.RoleAdmin, nil, false},
{userstore.RoleUser, &tid, false},
{userstore.RoleAuditor, &tid, false},
{userstore.RoleAuditor, nil, false},
{userstore.RoleDomainAuditor, &tid, false},
{"", nil, false},
}
for _, tt := range tests {
sess := &auth.Session{Role: tt.role, TenantID: tt.tenant}
if got := extraAddressRoleAllowed(sess); got != tt.want {
t.Errorf("role %q tenant %v: got %v, want %v", tt.role, tt.tenant, got, tt.want)
}
}
}
func TestExtraAddressTargetStatus(t *testing.T) {
t1, t2 := int64(1), int64(2)
user1 := &userstore.User{ID: 10, Role: userstore.RoleUser, TenantID: &t1}
user2 := &userstore.User{ID: 20, Role: userstore.RoleUser, TenantID: &t2}
userNone := &userstore.User{ID: 30, Role: userstore.RoleUser}
auditor1 := &userstore.User{ID: 40, Role: userstore.RoleAuditor, TenantID: &t1}
super := &auth.Session{Role: userstore.RoleSuperAdmin}
dom1 := &auth.Session{Role: userstore.RoleDomainAdmin, TenantID: &t1}
usr := &auth.Session{Role: userstore.RoleUser, TenantID: &t1}
domAud := &auth.Session{Role: userstore.RoleDomainAuditor, TenantID: &t1}
tests := []struct {
name string
sess *auth.Session
target *userstore.User
adding bool
want int
}{
{"superadmin tenant 1", super, user1, true, 0},
{"superadmin other tenant", super, user2, true, 0},
{"superadmin tenant-less user", super, userNone, true, 0},
{"domain admin same tenant", dom1, user1, true, 0},
{"domain admin other tenant", dom1, user2, false, http.StatusNotFound},
{"domain admin tenant-less user", dom1, userNone, true, http.StatusNotFound},
{"domain admin unknown user", dom1, nil, false, http.StatusNotFound},
{"role user", usr, user1, false, http.StatusForbidden},
{"domain auditor", domAud, user1, false, http.StatusForbidden},
{"add to non-user role", dom1, auditor1, true, http.StatusBadRequest},
{"list non-user role", dom1, auditor1, false, 0},
{"foreign tenant hides role", dom1, &userstore.User{ID: 50, Role: userstore.RoleAuditor, TenantID: &t2}, true, http.StatusNotFound},
}
for _, tt := range tests {
if got := extraAddressTargetStatus(tt.sess, tt.target, tt.adding); got != tt.want {
t.Errorf("%s: got %d, want %d", tt.name, got, tt.want)
}
}
}