fix(PROJ-54): Listenansicht/Pagination für Rolle "user" korrigieren
Filtert die Mails des Nutzers (From/To/Cc/Bcc) jetzt serverseitig via req.AnyAddress vor LIMIT/OFFSET im Index, statt wie bisher per Post-Filter nach der Paginierung. total und totalPages stimmen damit mit den tatsächlich sichtbaren Treffern überein.
This commit is contained in:
@@ -87,6 +87,20 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// PROJ-54: For user role, restrict results to mails the user is involved
|
||||
// in (From/To/CC/BCC) at the INDEX level — before LIMIT/OFFSET — so that
|
||||
// Total and pagination reflect the user's own mails, not the full
|
||||
// tenant/global result set. Email comes from the JWT session — no DB
|
||||
// lookup needed. If email is missing, block all results (fail-safe).
|
||||
if sess.Role == userstore.RoleUser {
|
||||
userEmailFilter := strings.ToLower(sess.Email)
|
||||
if userEmailFilter == "" {
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{"total": 0, "hits": []interface{}{}})
|
||||
return
|
||||
}
|
||||
req.AnyAddress = userEmailFilter
|
||||
}
|
||||
|
||||
// PROJ-21 Phase 4: Use per-tenant index when available; fall back to
|
||||
// global index + post-filter when the tenant index manager is not wired.
|
||||
// auditor always uses the global index — they see no-tenant mails only,
|
||||
@@ -164,18 +178,6 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// SEC: For user role, restrict results to mails the user is involved in
|
||||
// (From, To, or CC). Email comes from the JWT session — no DB lookup needed.
|
||||
// If email is missing, block all results (fail-safe).
|
||||
var userEmailFilter string
|
||||
if sess.Role == userstore.RoleUser {
|
||||
userEmailFilter = strings.ToLower(sess.Email)
|
||||
if userEmailFilter == "" {
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{"total": 0, "hits": []interface{}{}})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Batch-load thread info and received_at fallback for all hits
|
||||
hitIDs := make([]string, len(result.Hits))
|
||||
for i, h := range result.Hits {
|
||||
@@ -201,14 +203,6 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
|
||||
eh.Date = t.UTC().Format(time.RFC3339)
|
||||
}
|
||||
eh.HasAttachments = len(pm.Attachments) > 0
|
||||
|
||||
// User isolation: skip mails the user is not involved in.
|
||||
if userEmailFilter != "" && !mailBelongsToUser(pm, userEmailFilter) {
|
||||
continue
|
||||
}
|
||||
} else if userEmailFilter != "" {
|
||||
// If mail can't be parsed, deny access to user role.
|
||||
continue
|
||||
}
|
||||
// Auditor isolation: skip mails that belong to a tenant.
|
||||
if auditorAllowedIDs != nil {
|
||||
|
||||
Reference in New Issue
Block a user