Files
zoneminder/web/includes/actions/group.php
T
Isaac ConnorandClaude Opus 5.5 7c09ebd9e2 fix: require edit on each monitor a group change moves
Group membership feeds per-monitor access through Groups_Permissions, but
the classic group actions and the Groups API checked only the global
Groups permission. A Groups editor could add a monitor they are denied to
a group they have access through, or remove it from, or delete, the group
that denies it.

Add Group::canEditMembership() and require it, in both the classic UI and
the API, for every monitor added to or removed from a group, for all of a
group's monitors when it is re-parented, and for all of them when it is
deleted. The API also pins the record id and omits monitors the user may
not view from the groups it lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 17:54:25 -04:00

62 lines
2.6 KiB
PHP

<?php
//
// ZoneMinder web action file
// Copyright (C) 2019 ZoneMinder LLC
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Group edit actions
# Changing a group's monitors also needs edit on each monitor moved, checked below.
if ( !canEdit('Groups') ) {
ZM\Warning('Need group edit permissions to edit groups');
return;
}
if ( $action == 'save' ) {
$group_id = null;
if ( !empty($_REQUEST['gid']) )
$group_id = $_REQUEST['gid'];
$group = new ZM\Group($group_id);
$new_ids = isset($_REQUEST['newGroup']['MonitorIds']) ? array_map('intval', (array)$_REQUEST['newGroup']['MonitorIds']) : array();
$old_ids = $group->Id() ? dbFetchAll('SELECT `MonitorId` FROM `Groups_Monitors` WHERE `GroupId`=?', 'MonitorId', array($group->Id())) : array();
$moved = array_merge(array_diff($old_ids, $new_ids), array_diff($new_ids, $old_ids));
$new_parent = ($_REQUEST['newGroup']['ParentId'] == '' ? null : $_REQUEST['newGroup']['ParentId']);
// Re-parenting moves every monitor of this group and its children between ancestors.
if ($group->Id() and ($new_parent != $group->ParentId())) $moved = array_merge($moved, $group->MonitorIds());
if (!ZM\Group::canEditMembership($moved)) {
ZM\Warning('Need edit permission on every monitor moved into or out of a group');
return;
}
$group->save(
array(
'Name'=> $_REQUEST['newGroup']['Name'],
'ParentId'=>( $_REQUEST['newGroup']['ParentId'] == '' ? null : $_REQUEST['newGroup']['ParentId'] ),
)
);
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
$group_id = $group->Id();
if ($group_id and isset($_REQUEST['newGroup']['MonitorIds'])) {
foreach ( $new_ids as $mid ) {
dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid));
}
}
ZM\AuditAction((!empty($_REQUEST['gid']) ? 'update' : 'create'), 'group', $group->Id(), 'Name: '.$_REQUEST['newGroup']['Name']);
$redirect = '?view=groups';
}
?>