From 27b1b37d5b0f549aa55680acf4cdd7ab471483b3 Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:43:36 -0500 Subject: [PATCH 01/15] added opt_use_api --- .../lib/ZoneMinder/ConfigData.pm.in | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 7fff3d62e..9a065f8cf 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -357,7 +357,23 @@ our @options = type => $types{boolean}, category => "system", }, - # PP - Google reCaptcha settings + { + name => "ZM_OPT_USE_API", + default => "yes", + description => "Enable ZoneMinder APIs", + help => qqq(" + ZoneMinder now features a new API using which 3rd party + applications can interact with ZoneMinder data. It is + STRONGLY recommended that you enable authentication along + with APIs. Note that the APIs return sensitive data like + Monitor access details which are configured as JSON objects. + Which is why we recommend you enabling authentication, especially + if you are exposing your ZM instance on the Internet. + "), + type => $types{boolean}, + category => "system", + }, +# PP - Google reCaptcha settings { name => "ZM_OPT_USE_GOOG_RECAPTCHA", default => "no", @@ -410,6 +426,7 @@ our @options = type => $types {string}, category => "system", }, + { name => "ZM_DIR_EVENTS", From 028c9b956c59185421b4e4707e2b8a4a55a78c09 Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:44:02 -0500 Subject: [PATCH 02/15] check for opt_use_api, also pull in user roles support --- web/api/app/Controller/AppController.php | 51 +++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index 1d85115e8..8494aaa6c 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -58,14 +58,63 @@ class AppController extends Controller { // Also checking to do this only if ZM_OPT_USE_AUTH is on public function beforeFilter() { $this->loadModel('Config'); + + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_API')); + $config = $this->Config->find('first', $options); + $zmOptApi = $config['Config']['Value']; + + if ($zmOptApi !='1') + { + throw new UnauthorizedException(__('API Disabled')); + return; + } + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')); $config = $this->Config->find('first', $options); $zmOptAuth = $config['Config']['Value']; if (!$this->Session->Read('user.Username') && ($zmOptAuth=='1')) { - throw new NotFoundException(__('Not Authenticated')); + throw new UnauthorizedException(__('Not Authenticated')); return; } + // PP #1155 fixes + else + { + $this->loadModel('User'); + $loggedinUser = $this->Session->Read('user.Username'); + $isEnabled = $this->Session->Read('user.Enabled'); + // PP - this will likely never happen as if its + // not enabled, login will fail and Not Auth will be returned + // however, keeping this here for now + if ($isEnabled != "1" && $zmOptAuth=="1") + { + throw new UnauthorizedException(__('User is not enabled')); + return; + } + + if ($zmOptAuth=='1') + { + $options = array ('conditions' => array ('User.Username' => $loggedinUser)); + $userMonitors = $this->User->find('first', $options); + $this->Session->Write('allowedMonitors',$userMonitors['User']['MonitorIds']); + $this->Session->Write('streamPermission',$userMonitors['User']['Stream']); + $this->Session->Write('eventPermission',$userMonitors['User']['Events']); + $this->Session->Write('controlPermission',$userMonitors['User']['Control']); + $this->Session->Write('systemPermission',$userMonitors['User']['System']); + $this->Session->Write('monitorPermission',$userMonitors['User']['Monitors']); + } + else // if auth is not on, you can do everything + { + //$userMonitors = $this->User->find('first', $options); + $this->Session->Write('allowedMonitors',''); + $this->Session->Write('streamPermission','View'); + $this->Session->Write('eventPermission','Edit'); + $this->Session->Write('controlPermission','Edit'); + $this->Session->Write('systemPermission','Edit'); + $this->Session->Write('monitorPermission','Edit'); + } + } + } From f56688e7c2e1012dd002866d5c5a6b5a334a1fb4 Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:44:16 -0500 Subject: [PATCH 03/15] initial user role support --- web/api/app/Controller/EventsController.php | 130 +++++++++++++++----- 1 file changed, 96 insertions(+), 34 deletions(-) diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 988c19110..e82e7844e 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -14,6 +14,18 @@ class EventsController extends AppController { */ public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator'); +//# PP #1155 +public function beforeFilter() { + parent::beforeFilter(); + $canView = $this->Session->Read('eventPermission'); + if ($canView =='None') + { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + +} + /** * index method * @@ -22,6 +34,19 @@ class EventsController extends AppController { */ public function index() { $this->Event->recursive = -1; + + //PP #1155 + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + + if (!empty($allowedMonitors)) + { + $mon_options = array('Event.MonitorId' => $allowedMonitors); + } + else + { + $mon_options=''; + } + if ($this->request->params['named']) { $this->FilterComponent = $this->Components->load('Filter'); @@ -49,14 +74,15 @@ class EventsController extends AppController { 'limit' => '100', 'order' => array('StartTime', 'MaxScore'), 'paramType' => 'querystring', - 'conditions' => $conditions + // PP #1155 + 'conditions' => array (array($conditions, $mon_options)) ); $events = $this->Paginator->paginate('Event'); // For each event, get its thumbnail data (path, width, height) foreach ($events as $key => $value) { - // PP - $thumbData = $this->createThumbnail($value['Event']['Id']); - $thumbData =""; + //$thumbData = $this->createThumbnail($value['Event']['Id']); + $thumbData = ""; $events[$key]['thumbData'] = $thumbData; } @@ -71,41 +97,56 @@ class EventsController extends AppController { * @param string $id * @return void */ - public function view($id = null) { - $this->loadModel('Config'); - $configs = $this->Config->find('list', array( - 'fields' => array('Name', 'Value'), - 'conditions' => array('Name' => array('ZM_DIR_EVENTS')) - )); + public function view($id = null) +{ + $this->loadModel('Config'); + $configs = $this->Config->find('list', array( + 'fields' => array('Name', 'Value'), + 'conditions' => array('Name' => array('ZM_DIR_EVENTS')) + )); - $this->Event->recursive = 1; - if (!$this->Event->exists($id)) { - throw new NotFoundException(__('Invalid event')); - } - $options = array('conditions' => array('Event.' . $this->Event->primaryKey => $id)); - $event = $this->Event->find('first', $options); + $this->Event->recursive = 1; + if (!$this->Event->exists($id)) { + throw new NotFoundException(__('Invalid event')); + } - $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/'; - $event['Event']['BasePath'] = $path; + //PP #1155 + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); - # Get the previous and next events for any monitor - $this->Event->id = $id; + if (!empty($allowedMonitors)) + { + $mon_options = array('Event.MonitorId' => $allowedMonitors); + } + else + { + $mon_options=''; + } + + $options = array('conditions' => array(array('Event.' . $this->Event->primaryKey => $id), $mon_options)); + $event = $this->Event->find('first', $options); + + $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/'; + $event['Event']['BasePath'] = $path; + + # Get the previous and next events for any monitor + $this->Event->id = $id; $event_neighbors = $this->Event->find('neighbors'); - $event['Event']['Next'] = $event_neighbors['next']['Event']['Id']; - $event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id']; + $event['Event']['Next'] = $event_neighbors['next']['Event']['Id']; + $event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id']; - # Also get the previous and next events for the same monitor - $event_monitor_neighbors = $this->Event->find('neighbors', array( + # Also get the previous and next events for the same monitor + $event_monitor_neighbors = $this->Event->find('neighbors', array( 'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId']) - )); - $event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id']; - $event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id']; + )); + $event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id']; + $event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id']; + + $this->set(array( + 'event' => $event, + '_serialize' => array('event') + )); + } - $this->set(array( - 'event' => $event, - '_serialize' => array('event') - )); - } /** * add method @@ -113,6 +154,14 @@ class EventsController extends AppController { * @return void */ public function add() { + + //PP - #1155 + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + if ($this->request->is('post')) { $this->Event->create(); if ($this->Event->save($this->request->data)) { @@ -131,6 +180,14 @@ class EventsController extends AppController { * @return void */ public function edit($id = null) { + + //PP - #1155 + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + $this->Event->id = $id; if (!$this->Event->exists($id)) { @@ -157,15 +214,20 @@ class EventsController extends AppController { * @return void */ public function delete($id = null) { + //PP - #1155 + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } $this->Event->id = $id; if (!$this->Event->exists()) { throw new NotFoundException(__('Invalid event')); } $this->request->allowMethod('post', 'delete'); if ($this->Event->delete()) { - // PP - lets make sure the frame table entry is removed too - $this->loadModel('Frame'); - $this->Frame->delete(); + //$this->loadModel('Frame'); + //$this->Event->Frame->delete(); return $this->flash(__('The event has been deleted.'), array('action' => 'index')); } else { return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index')); From e812398fb9244967ae74d57babc242b2f1815624 Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:44:39 -0500 Subject: [PATCH 04/15] initial user role support --- web/api/app/Controller/HostController.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index ee5ecd30f..2e2c49551 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -101,7 +101,10 @@ class HostController extends AppController { function getVersion() { $version = Configure::read('ZM_VERSION'); - $apiversion = Configure::read('ZM_API_VERSION'); + // PP - not going to use the ZM_API_VERSION + // requires recompilation and dependency on ZM upgrade + //$apiversion = Configure::read('ZM_API_VERSION'); + $apiversion = '1.0'; $this->set(array( 'version' => $version, From b4fdaa9b4d032b9b62285738bab1bb1ffc058c1c Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:44:46 -0500 Subject: [PATCH 05/15] initial user role support --- web/api/app/Controller/MonitorsController.php | 68 +++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 3aeb31aa8..d13ed3a31 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -16,6 +16,20 @@ class MonitorsController extends AppController { */ public $components = array('Paginator', 'RequestHandler'); + +//# PP #1155 +public function beforeFilter() { + parent::beforeFilter(); + $canView = $this->Session->Read('monitorPermission'); + if ($canView =='None') + { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + +} + + /** * index method * @@ -23,7 +37,18 @@ class MonitorsController extends AppController { */ public function index() { $this->Monitor->recursive = 0; - $monitors = $this->Monitor->find('all'); + //PP #1155 + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + + if (!empty($allowedMonitors)) + { + $options = array('conditions'=>array('Monitor.Id'=> $allowedMonitors)); + } + else + { + $options=''; + } + $monitors = $this->Monitor->find('all',$options); $this->set(array( 'monitors' => $monitors, '_serialize' => array('monitors') @@ -42,7 +67,22 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - $options = array('conditions' => array('Monitor.' . $this->Monitor->primaryKey => $id)); + //PP #1155 + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + if (!empty($allowedMonitors)) + { + $restricted = array('Monitor.' . $this->Monitor->primaryKey => $allowedMonitors); + } + else + { + $restricted = ''; + } + + $options = array('conditions' => array( + array('Monitor.' . $this->Monitor->primaryKey => $id), + $restricted + ) + ); $monitor = $this->Monitor->find('first', $options); $this->set(array( 'monitor' => $monitor, @@ -57,6 +97,14 @@ class MonitorsController extends AppController { */ public function add() { if ($this->request->is('post')) { + + //PP - #1155 + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthotizedException(__('Insufficient privileges')); + return; + } + $this->Monitor->create(); if ($this->Monitor->save($this->request->data)) { $this->daemonControl($this->Monitor->id, 'start', $this->request->data); @@ -78,7 +126,12 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - + //PP - #1155 + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } if ($this->Monitor->save($this->request->data)) { $message = 'Saved'; } else { @@ -90,8 +143,7 @@ class MonitorsController extends AppController { '_serialize' => array('message') )); // PP - restart this monitor after change - $this->daemonControl($this->Monitor->id, 'restart', $this->request->data); - + $this->daemonControl($this->Monitor->id, 'restart', $this->request->data); } /** @@ -106,6 +158,12 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists()) { throw new NotFoundException(__('Invalid monitor')); } + //PP - #1155 + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } $this->request->allowMethod('post', 'delete'); $this->daemonControl($this->Monitor->id, 'stop'); From c4461c328eddb5a82f1dc5755ab8a955bee86333 Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sat, 19 Dec 2015 17:45:03 -0500 Subject: [PATCH 06/15] initial user role support --- web/api/app/Model/User.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 web/api/app/Model/User.php diff --git a/web/api/app/Model/User.php b/web/api/app/Model/User.php new file mode 100644 index 000000000..9d9dd7f85 --- /dev/null +++ b/web/api/app/Model/User.php @@ -0,0 +1,32 @@ + Date: Sat, 19 Dec 2015 18:36:38 -0500 Subject: [PATCH 07/15] PP - Gone,flitted away, Taken the starts from the night and sun, From the day! Gone, and a cloud in my heart. - Tennyson --- web/api/app/Controller/AppController.php | 8 ++++---- .../app/Controller/Component/ImageComponent.php | 2 +- web/api/app/Controller/ConfigsController.php | 2 +- web/api/app/Controller/EventsController.php | 16 ++++++++-------- web/api/app/Controller/HostController.php | 2 +- web/api/app/Controller/MonitorsController.php | 14 +++++++------- web/api/app/Model/User.php | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index 8494aaa6c..d961269d3 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -34,7 +34,7 @@ class AppController extends Controller { use CrudControllerTrait; public $components = [ - 'Session', // PP - We are going to use SessionHelper to check PHP session vars + 'Session', // We are going to use SessionHelper to check PHP session vars 'RequestHandler', 'Crud.Crud' => [ 'actions' => [ @@ -49,7 +49,7 @@ class AppController extends Controller { ] ]; - //PP - Global beforeFilter function + // Global beforeFilter function //Zoneminder sets the username session variable // to the logged in user. If this variable is set // then you are logged in @@ -77,13 +77,13 @@ class AppController extends Controller { throw new UnauthorizedException(__('Not Authenticated')); return; } - // PP #1155 fixes + // #1155 fixes else { $this->loadModel('User'); $loggedinUser = $this->Session->Read('user.Username'); $isEnabled = $this->Session->Read('user.Enabled'); - // PP - this will likely never happen as if its + // this will likely never happen as if its // not enabled, login will fail and Not Auth will be returned // however, keeping this here for now if ($isEnabled != "1" && $zmOptAuth=="1") diff --git a/web/api/app/Controller/Component/ImageComponent.php b/web/api/app/Controller/Component/ImageComponent.php index 68a254031..f8ed7a533 100644 --- a/web/api/app/Controller/Component/ImageComponent.php +++ b/web/api/app/Controller/Component/ImageComponent.php @@ -48,7 +48,7 @@ class ImageComponent extends Component { $imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath; //$thumbFile = ZM_DIR_EVENTS."/".$thumbPath; $thumbFile = $thumbPath; - // PP: This segment of code results in errors when trying to get Events API + // This segment of code results in errors when trying to get Events API // This actually seems to be generating images for the angular UI web view // and should not be a part of the API anyway // I've commented it so events APIs continue to work diff --git a/web/api/app/Controller/ConfigsController.php b/web/api/app/Controller/ConfigsController.php index e70978246..48f50ae8e 100644 --- a/web/api/app/Controller/ConfigsController.php +++ b/web/api/app/Controller/ConfigsController.php @@ -15,7 +15,7 @@ class ConfigsController extends AppController { public $components = array('RequestHandler'); /** - * PP - resolves the issue of not returning all config parameters + * resolves the issue of not returning all config parameters * refer https://github.com/ZoneMinder/ZoneMinder/issues/953 * index method * diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index e82e7844e..28bef7a64 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -14,7 +14,7 @@ class EventsController extends AppController { */ public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator'); -//# PP #1155 +//#1155 public function beforeFilter() { parent::beforeFilter(); $canView = $this->Session->Read('eventPermission'); @@ -35,7 +35,7 @@ public function beforeFilter() { public function index() { $this->Event->recursive = -1; - //PP #1155 + // #1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -64,7 +64,7 @@ public function beforeFilter() { $this->Paginator->settings = array( // https://github.com/ZoneMinder/ZoneMinder/issues/995 // 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'], - // PP - 25 events per page which is what the above + // 25 events per page which is what the above // default is, is way too low for an API // changing this to 100 so we don't kill ZM // with many event APIs. In future, we can @@ -74,7 +74,7 @@ public function beforeFilter() { 'limit' => '100', 'order' => array('StartTime', 'MaxScore'), 'paramType' => 'querystring', - // PP #1155 + // #1155 'conditions' => array (array($conditions, $mon_options)) ); $events = $this->Paginator->paginate('Event'); @@ -110,7 +110,7 @@ public function beforeFilter() { throw new NotFoundException(__('Invalid event')); } - //PP #1155 + // #1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -155,7 +155,7 @@ public function beforeFilter() { */ public function add() { - //PP - #1155 + // - #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -181,7 +181,7 @@ public function beforeFilter() { */ public function edit($id = null) { - //PP - #1155 + // - #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -214,7 +214,7 @@ public function beforeFilter() { * @return void */ public function delete($id = null) { - //PP - #1155 + //- #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index 2e2c49551..57b210a7e 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -101,7 +101,7 @@ class HostController extends AppController { function getVersion() { $version = Configure::read('ZM_VERSION'); - // PP - not going to use the ZM_API_VERSION + // not going to use the ZM_API_VERSION // requires recompilation and dependency on ZM upgrade //$apiversion = Configure::read('ZM_API_VERSION'); $apiversion = '1.0'; diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index d13ed3a31..3d493762f 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -17,7 +17,7 @@ class MonitorsController extends AppController { public $components = array('Paginator', 'RequestHandler'); -//# PP #1155 +//# 1155 public function beforeFilter() { parent::beforeFilter(); $canView = $this->Session->Read('monitorPermission'); @@ -37,7 +37,7 @@ public function beforeFilter() { */ public function index() { $this->Monitor->recursive = 0; - //PP #1155 + //#1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -67,7 +67,7 @@ public function beforeFilter() { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - //PP #1155 + //#1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) { @@ -98,7 +98,7 @@ public function beforeFilter() { public function add() { if ($this->request->is('post')) { - //PP - #1155 + //- #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthotizedException(__('Insufficient privileges')); @@ -126,7 +126,7 @@ public function beforeFilter() { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - //PP - #1155 + //- #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -142,7 +142,7 @@ public function beforeFilter() { 'message' => $message, '_serialize' => array('message') )); - // PP - restart this monitor after change + // - restart this monitor after change $this->daemonControl($this->Monitor->id, 'restart', $this->request->data); } @@ -158,7 +158,7 @@ public function beforeFilter() { if (!$this->Monitor->exists()) { throw new NotFoundException(__('Invalid monitor')); } - //PP - #1155 + // #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); diff --git a/web/api/app/Model/User.php b/web/api/app/Model/User.php index 9d9dd7f85..c0392f51d 100644 --- a/web/api/app/Model/User.php +++ b/web/api/app/Model/User.php @@ -1,7 +1,7 @@ Date: Sat, 19 Dec 2015 19:04:27 -0500 Subject: [PATCH 08/15] removed issue # --- web/api/app/Controller/AppController.php | 1 - web/api/app/Controller/EventsController.php | 7 ------- web/api/app/Controller/MonitorsController.php | 6 ------ web/api/app/Model/User.php | 1 - 4 files changed, 15 deletions(-) diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index d961269d3..5b39597b3 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -77,7 +77,6 @@ class AppController extends Controller { throw new UnauthorizedException(__('Not Authenticated')); return; } - // #1155 fixes else { $this->loadModel('User'); diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 28bef7a64..ef569cd7b 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -14,7 +14,6 @@ class EventsController extends AppController { */ public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator'); -//#1155 public function beforeFilter() { parent::beforeFilter(); $canView = $this->Session->Read('eventPermission'); @@ -35,7 +34,6 @@ public function beforeFilter() { public function index() { $this->Event->recursive = -1; - // #1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -74,7 +72,6 @@ public function beforeFilter() { 'limit' => '100', 'order' => array('StartTime', 'MaxScore'), 'paramType' => 'querystring', - // #1155 'conditions' => array (array($conditions, $mon_options)) ); $events = $this->Paginator->paginate('Event'); @@ -110,7 +107,6 @@ public function beforeFilter() { throw new NotFoundException(__('Invalid event')); } - // #1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -155,7 +151,6 @@ public function beforeFilter() { */ public function add() { - // - #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -181,7 +176,6 @@ public function beforeFilter() { */ public function edit($id = null) { - // - #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -214,7 +208,6 @@ public function beforeFilter() { * @return void */ public function delete($id = null) { - //- #1155 if ($this->Session->Read('eventPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 3d493762f..9ab7461f9 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -17,7 +17,6 @@ class MonitorsController extends AppController { public $components = array('Paginator', 'RequestHandler'); -//# 1155 public function beforeFilter() { parent::beforeFilter(); $canView = $this->Session->Read('monitorPermission'); @@ -37,7 +36,6 @@ public function beforeFilter() { */ public function index() { $this->Monitor->recursive = 0; - //#1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) @@ -67,7 +65,6 @@ public function beforeFilter() { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - //#1155 $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); if (!empty($allowedMonitors)) { @@ -98,7 +95,6 @@ public function beforeFilter() { public function add() { if ($this->request->is('post')) { - //- #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthotizedException(__('Insufficient privileges')); @@ -126,7 +122,6 @@ public function beforeFilter() { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - //- #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); @@ -158,7 +153,6 @@ public function beforeFilter() { if (!$this->Monitor->exists()) { throw new NotFoundException(__('Invalid monitor')); } - // #1155 if ($this->Session->Read('systemPermission') != 'Edit') { throw new UnauthorizedException(__('Insufficient privileges')); diff --git a/web/api/app/Model/User.php b/web/api/app/Model/User.php index c0392f51d..8ef18d131 100644 --- a/web/api/app/Model/User.php +++ b/web/api/app/Model/User.php @@ -1,7 +1,6 @@ Date: Sun, 20 Dec 2015 11:22:12 -0500 Subject: [PATCH 09/15] update paths to /usr/share/zoneminder/www and /usr/lib/zoneminder/cgi-bin --- distros/debian_cmake/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/debian_cmake/rules b/distros/debian_cmake/rules index aa0501ab1..4bdc7cb0c 100755 --- a/distros/debian_cmake/rules +++ b/distros/debian_cmake/rules @@ -17,9 +17,9 @@ override_dh_auto_configure: -DZM_SOCKDIR=/var/run/zm \ -DZM_TMPDIR=/var/tmp/zm \ -DZM_LOGDIR=/var/log/zm \ - -DZM_WEBDIR=/usr/share/zoneminder \ + -DZM_WEBDIR=/usr/share/zoneminder/www \ -DZM_CONTENTDIR=/var/cache/zoneminder \ - -DZM_CGIDIR=/usr/lib/cgi-bin \ + -DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ -DCMAKE_INSTALL_SYSCONFDIR=etc/zm From 4ef35c8c7081f58b87d163528dbef2e25949a298 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 20 Dec 2015 11:23:01 -0500 Subject: [PATCH 10/15] No need for a cgi-bin link --- distros/debian_cmake/links | 1 - 1 file changed, 1 deletion(-) diff --git a/distros/debian_cmake/links b/distros/debian_cmake/links index 9715ee428..5560a100a 100644 --- a/distros/debian_cmake/links +++ b/distros/debian_cmake/links @@ -1,4 +1,3 @@ var/cache/zoneminder/events usr/share/zoneminder/events var/cache/zoneminder/images usr/share/zoneminder/images var/cache/zoneminder/temp usr/share/zoneminder/temp -usr/lib/cgi-bin usr/share/zoneminder/cgi-bin From 9743bad13f6d8b9af510ca1c808de042b412e759 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 20 Dec 2015 12:21:18 -0500 Subject: [PATCH 11/15] Add a valid config if a person is using mod_fcgid instead of mod_php --- distros/ubuntu1204/apache.conf | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/distros/ubuntu1204/apache.conf b/distros/ubuntu1204/apache.conf index 965c67f86..262db423f 100644 --- a/distros/ubuntu1204/apache.conf +++ b/distros/ubuntu1204/apache.conf @@ -1,9 +1,21 @@ Alias /zm /usr/share/zoneminder/www - - php_flag register_globals off - Options Indexes FollowSymLinks - - DirectoryIndex index.php - - + + + Options +ExecCGI + AllowOverride All + AddHandler fcgid-script .php + FCGIWrapper /usr/bin/php5-cgi + Order allow,deny + Allow from all + + + + + php_flag register_globals off + Options Indexes FollowSymLinks + + DirectoryIndex index.php + + + From f4debc203d4f21838650c584a99b4a3c31c29ea2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 20 Dec 2015 12:23:40 -0500 Subject: [PATCH 12/15] Only run zmupdate.pl if the mysql db is located here --- distros/ubuntu1504_cmake/zoneminder.postinst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/distros/ubuntu1504_cmake/zoneminder.postinst b/distros/ubuntu1504_cmake/zoneminder.postinst index 4d2da7331..82b256e6b 100644 --- a/distros/ubuntu1504_cmake/zoneminder.postinst +++ b/distros/ubuntu1504_cmake/zoneminder.postinst @@ -2,6 +2,8 @@ set -e +. /etc/zm/zm.conf + if [ "$1" = "configure" ]; then chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm @@ -15,9 +17,13 @@ if [ "$1" = "configure" ]; then # Ensure zoneminder is stopped deb-systemd-invoke stop zoneminder.service || exit $? - echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql - # Run the ZoneMinder update tool - zmupdate.pl --nointeractive + if [ "$ZM_DB_HOST" = "localhost" ]; then + echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + # Run the ZoneMinder update tool + zmupdate.pl --nointeractive + else + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + fi; fi From 6ccf36bc770768c147e558636c7d24542d5d172f Mon Sep 17 00:00:00 2001 From: arjunrc Date: Sun, 20 Dec 2015 14:55:48 -0500 Subject: [PATCH 13/15] updated mobile app info --- docs/userguide/mobile.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/userguide/mobile.rst b/docs/userguide/mobile.rst index fe8d6e418..b6feb805d 100644 --- a/docs/userguide/mobile.rst +++ b/docs/userguide/mobile.rst @@ -3,16 +3,17 @@ Mobile Devices Here are some options for using ZoneMinder on Mobile devices: -Using the existing web console -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop -* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it - Third party mobile clients ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * zmNinja (`source code `__, needs APIs to be installed to work) - * Currently in free beta testing for iOS and Android. Will be in app/play store as soon as ZM 1.29 is launched -* zmView (limited, free) and zmView Pro (more features, paid) - `website `__ + * Available in App Store and Play Store - `website `__ +* zmView (limited, free) and zmView Pro (more features, paid) + * Available in App Store and Play Store, relies on ZM skins `website `__ + +Using the existing web console +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop +* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it. **Note however that 1.29 is the last release that will support the mobile skin. It's use is deprecated** Discontinued clients ^^^^^^^^^^^^^^^^^^^^ From b33c0764fe4eefb72121efbc8a399d7736195f40 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 21 Dec 2015 12:59:52 -0500 Subject: [PATCH 14/15] update to new cgi-bin path --- distros/debian_cmake/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/debian_cmake/install b/distros/debian_cmake/install index 9e8953409..1bd76421f 100644 --- a/distros/debian_cmake/install +++ b/distros/debian_cmake/install @@ -1,5 +1,5 @@ usr/bin -usr/lib/cgi-bin +usr/lib/zoneminder/cgi-bin usr/share/man usr/share/perl5/ZoneMinder usr/share/perl5/ZoneMinder.pm From abda4411e94be1caca88b8840452e8a8db2030f2 Mon Sep 17 00:00:00 2001 From: SteveGilvarry Date: Wed, 23 Dec 2015 19:34:31 +1100 Subject: [PATCH 15/15] Revert to Default Theme, RTD will use their own and local builds default sphinx theme --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 109161b24..9bda5df7b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,8 +101,8 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#html_theme = 'default' -html_theme = 'sphinx_rtd_theme' +html_theme = 'default' +#html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the