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>
106 lines
3.8 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|