feat: auditor sieht Mails ohne Tenant-Zuordnung
- auditor-Rolle sieht jetzt Mails wo tenant_id IS NULL und kein email_refs-Eintrag existiert (statt nur eigene Mails) - Neues storage.IsWithoutTenant() für effizienten Direktzugriff - Neues storage.GetAllIDsWithoutTenant() für Suche + ZIP-Export - Konsistente Prüfung in Search, GetMail, GetAttachment, GetRaw, Export Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+35
-6
@@ -356,8 +356,17 @@ func (s *Server) handleExportPDF(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// user and auditor: only own mails; domain_auditor: all tenant mails (no filter)
|
||||
if sess.Role == userstore.RoleUser || sess.Role == userstore.RoleAuditor {
|
||||
// auditor: only mails with no tenant assignment.
|
||||
if sess.Role == userstore.RoleAuditor {
|
||||
ok, err := s.store.IsWithoutTenant(r.Context(), id)
|
||||
if err != nil || !ok {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// user: only own mails; domain_auditor: all tenant mails (no filter)
|
||||
if sess.Role == userstore.RoleUser {
|
||||
u, err := s.users.GetByUsername(sess.Username)
|
||||
if err != nil || !mailBelongsToUser(pm, u.Email) {
|
||||
writeError(w, http.StatusForbidden, "access denied")
|
||||
@@ -437,9 +446,23 @@ func (s *Server) handleExportZIP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// User and Auditor: look up email once for per-mail access checks
|
||||
// Auditor: pre-load the set of no-tenant mail IDs for efficient per-mail checks.
|
||||
var auditorAllowed map[string]struct{}
|
||||
if sess.Role == userstore.RoleAuditor {
|
||||
ids, err := s.store.GetAllIDsWithoutTenant(r.Context())
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "tenant check failed")
|
||||
return
|
||||
}
|
||||
auditorAllowed = make(map[string]struct{}, len(ids))
|
||||
for _, aid := range ids {
|
||||
auditorAllowed[aid] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// User: look up email once for per-mail access checks.
|
||||
var userEmail string
|
||||
if sess.Role == userstore.RoleUser || sess.Role == userstore.RoleAuditor {
|
||||
if sess.Role == userstore.RoleUser {
|
||||
u, err := s.users.GetByUsername(sess.Username)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "user lookup failed")
|
||||
@@ -476,8 +499,14 @@ func (s *Server) handleExportZIP(w http.ResponseWriter, r *http.Request) {
|
||||
continue
|
||||
}
|
||||
|
||||
// user and auditor: only own mails; domain_auditor: all tenant mails (no filter)
|
||||
if (sess.Role == userstore.RoleUser || sess.Role == userstore.RoleAuditor) && !mailBelongsToUser(pm, userEmail) {
|
||||
// auditor: only mails with no tenant assignment.
|
||||
if auditorAllowed != nil {
|
||||
if _, ok := auditorAllowed[id]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// user: only own mails; domain_auditor: all tenant mails (no filter)
|
||||
if sess.Role == userstore.RoleUser && !mailBelongsToUser(pm, userEmail) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user