The filterdebug modal (web/ajax/modals/filterdebug.php) builds and EXPLAINs a
filter's events query but enforced no authorization beyond the global login
check, so any authenticated user could inspect the MySQL EXPLAIN for an
arbitrary stored filter (including one they don't own).
Add ZM\Filter::canView() mirroring canDelete()/canEdit(): System viewers can
inspect any filter, otherwise the user must own it; an unsaved/transient
filter (no Id, built from the requester's own request in this modal) is
viewable by the requester. Construct the filter up front in filterdebug.php
and return early when the current user can't view it.
Add tests/php/test_filter_canview.php covering owner/non-owner/system/unsaved
cases.
refs GHSA-28mv-hqxw-qw84
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>