mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-03 07:55:22 -04:00
CakePHP's Model::set() takes the record id from a primary key in the data passed to save(). edit() authorized the id in the URL and then saved the request body, so Zone[Id]=<other> in the body wrote to that other zone, past the per-monitor check just added. add() could likewise update an existing row instead of creating one. Add AppController::pinRequestId(), which drops the primary key from the request data and sets the model id, and use it in these edits (pinned to the URL id) and adds (cleared). Frames and EventData edit() never set the model id at all, so a body without an Id inserted a new row rather than updating; pinning fixes that too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
209 lines
6.8 KiB
PHP
209 lines
6.8 KiB
PHP
<?php
|
|
App::uses('AppController', 'Controller');
|
|
require_once __DIR__ .'/../../../includes/Event.php';
|
|
/**
|
|
* EventData Controller
|
|
*
|
|
* @property EventData $EventData
|
|
*/
|
|
class EventDataController extends AppController {
|
|
|
|
/**
|
|
* Components
|
|
*
|
|
* @var array
|
|
*/
|
|
public $components = array('RequestHandler');
|
|
|
|
public function beforeFilter() {
|
|
parent::beforeFilter();
|
|
global $user;
|
|
# We already tested for auth in appController, so we just need to test for specific permission
|
|
$canView = (!$user) || ($user->Events() != 'None');
|
|
if (!$canView) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Event_Data mutation requires Events=Edit (beforeFilter only guarantees
|
|
# Events != None) plus the per-monitor ACL on the row being changed, so a
|
|
# user denied a monitor cannot alter that monitor's event data by Id.
|
|
private function requireEventDataEdit($id) {
|
|
global $user;
|
|
if ( $user and ($user->Events() != 'Edit') ) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
$allowedMonitors = ($user and $user->unviewableMonitorIds()) ? $user->viewableMonitorIds() : null;
|
|
if ( $allowedMonitors !== null ) {
|
|
$this->EventData->recursive = -1;
|
|
$row = $this->EventData->find('first', array(
|
|
'conditions' => array($this->EventData->alias.'.'.$this->EventData->primaryKey => $id),
|
|
));
|
|
$monitorId = $row ? $row[$this->EventData->alias]['MonitorId'] : null;
|
|
if ( !in_array($monitorId, $allowedMonitors) ) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
}
|
|
}
|
|
|
|
# Event_Data being added or re-pointed names its event and monitor in the request
|
|
# data. Require edit on that event and access to that monitor, or a user could
|
|
# attach data to a denied monitor's event.
|
|
private function requireRequestEventDataEdit($required) {
|
|
$data = $this->request->data;
|
|
if (isset($data['EventData']) and is_array($data['EventData'])) $data = $data['EventData'];
|
|
if (!isset($data['EventId'])) {
|
|
if ($required) throw new BadRequestException(__('EventId is required'));
|
|
} else {
|
|
$this->loadModel('Event');
|
|
$this->Event->recursive = -1;
|
|
$event = $this->Event->find('first', array('conditions' => array('Event.Id' => $data['EventId'])));
|
|
if (!$event) {
|
|
throw new NotFoundException(__('Invalid event'));
|
|
}
|
|
$event = new ZM\Event($event['Event']);
|
|
if (!$event->canEdit()) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
}
|
|
if (isset($data['MonitorId'])) {
|
|
global $user;
|
|
$allowedMonitors = ($user and $user->unviewableMonitorIds()) ? $user->viewableMonitorIds() : null;
|
|
if ($allowedMonitors !== null and !in_array($data['MonitorId'], $allowedMonitors)) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* index method
|
|
*
|
|
* @return void
|
|
*/
|
|
public function index() {
|
|
$this->EventData->recursive = -1;
|
|
if ( $this->request->params['named'] ) {
|
|
$this->FilterComponent = $this->Components->load('Filter');
|
|
$conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
|
|
} else {
|
|
$conditions = array();
|
|
}
|
|
|
|
# Event_Data carries its own MonitorId, so the per-monitor ACL that
|
|
# EventsController applies via Event.MonitorId can be applied directly here.
|
|
# Without it any user with Events != None reads event data for cameras they
|
|
# are explicitly denied.
|
|
global $user;
|
|
$allowedMonitors = ($user and $user->unviewableMonitorIds()) ? $user->viewableMonitorIds() : array();
|
|
if ( count($allowedMonitors) ) {
|
|
$conditions[] = array($this->EventData->alias.'.MonitorId' => $allowedMonitors);
|
|
}
|
|
|
|
$find_array = array(
|
|
'conditions' => &$conditions,
|
|
);
|
|
$event_data = $this->EventData->find('all', $find_array);
|
|
$this->set(array(
|
|
'event_data' => $event_data,
|
|
'_serialize' => array('event_data')
|
|
));
|
|
}
|
|
|
|
/**
|
|
* view method
|
|
*
|
|
* @throws NotFoundException
|
|
* @param string $id
|
|
* @return void
|
|
*/
|
|
public function view($id = null) {
|
|
$this->EventData->recursive = -1;
|
|
if (!$this->EventData->exists($id)) {
|
|
throw new NotFoundException(__('Invalid event data'));
|
|
}
|
|
global $user;
|
|
$allowedMonitors = ($user and $user->unviewableMonitorIds()) ? $user->viewableMonitorIds() : array();
|
|
$conditions = array($this->EventData->alias.'.'.$this->EventData->primaryKey => $id);
|
|
if ( count($allowedMonitors) ) {
|
|
$conditions[$this->EventData->alias.'.MonitorId'] = $allowedMonitors;
|
|
}
|
|
$event_data = $this->EventData->find('first', array('conditions' => $conditions));
|
|
if ( !$event_data ) {
|
|
# exists() above proved the row is present, so an empty result here means
|
|
# the per-monitor ACL filtered it out: the caller is denied this monitor.
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
$this->set(array(
|
|
'event_data' => $event_data,
|
|
'_serialize' => array('event_data')
|
|
));
|
|
}
|
|
|
|
/**
|
|
* add method
|
|
*
|
|
* @return void
|
|
*/
|
|
public function add() {
|
|
if ($this->request->is('post')) {
|
|
global $user;
|
|
if ($user and ($user->Events() != 'Edit')) {
|
|
throw new UnauthorizedException(__('Insufficient Privileges'));
|
|
}
|
|
$this->requireRequestEventDataEdit(true);
|
|
$this->pinRequestId($this->EventData, null);
|
|
$this->EventData->create();
|
|
if ($this->EventData->save($this->request->data)) {
|
|
}
|
|
}
|
|
$events = $this->EventData->Event->find('list');
|
|
$this->set(compact('events'));
|
|
}
|
|
|
|
/**
|
|
* edit method
|
|
*
|
|
* @throws NotFoundException
|
|
* @param string $id
|
|
* @return void
|
|
*/
|
|
public function edit($id = null) {
|
|
if (!$this->EventData->exists($id)) {
|
|
throw new NotFoundException(__('Invalid event_data'));
|
|
}
|
|
$this->requireEventDataEdit($id);
|
|
if ($this->request->is(array('post', 'put'))) {
|
|
$this->pinRequestId($this->EventData, $id);
|
|
$this->requireRequestEventDataEdit(false);
|
|
if ($this->EventData->save($this->request->data)) {
|
|
}
|
|
} else {
|
|
$options = array('conditions' => array($this->EventData->alias.'.'.$this->EventData->primaryKey => $id));
|
|
$this->request->data = $this->EventData->find('first', $options);
|
|
}
|
|
$events = $this->EventData->Event->find('list');
|
|
$this->set(compact('events'));
|
|
}
|
|
|
|
/**
|
|
* delete method
|
|
*
|
|
* @throws NotFoundException
|
|
* @param string $id
|
|
* @return void
|
|
*/
|
|
public function delete($id = null) {
|
|
$this->EventData->id = $id;
|
|
if (!$this->EventData->exists()) {
|
|
throw new NotFoundException(__('Invalid event_data'));
|
|
}
|
|
$this->request->allowMethod('post', 'delete');
|
|
$this->requireEventDataEdit($id);
|
|
if ($this->EventData->delete()) {
|
|
return $this->flash(__('The event_data has been deleted.'), array('action' => 'index'));
|
|
} else {
|
|
return $this->flash(__('The event_data could not be deleted. Please, try again.'), array('action' => 'index'));
|
|
}
|
|
}}
|