Merge branch 'master' into storageareas

Conflicts:
	docs/installationguide/ubuntu.rst
This commit is contained in:
Isaac Connor 2015-12-20 11:19:44 -05:00
commit 27597c3401
21 changed files with 782 additions and 78 deletions

3
docs/_static/zmstyle.css vendored Normal file
View File

@ -0,0 +1,3 @@
img {
border: 1px solid black !important;
}

View File

@ -1,13 +0,0 @@
@import url("default.css");
div.admonition-note {
border-top: 2px solid red;
border-bottom: 2px solid red;
border-left: 2px solid red;
border-right: 2px solid red;
background-color: #ff6347
}
img {
border: 1px solid black !important;
}

View File

@ -15,6 +15,9 @@
import sys import sys
import os import os
def setup(app):
app.add_stylesheet('zmstyle.css')
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
@ -51,9 +54,9 @@ copyright = u'2014, https://github.com/ZoneMinder/ZoneMinder/graphs/contributors
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '1.28.1' #version = '1.28.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '1.28.1' #release = '1.28.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
@ -98,14 +101,15 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
html_theme = 'default' #html_theme = 'default'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a 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 # further. For a list of options available for each theme, see the
# documentation. # documentation.
html_theme_options = { #html_theme_options = {
"stickysidebar": "true" # "stickysidebar": "true"
} #}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = [] #html_theme_path = []
@ -130,7 +134,7 @@ html_theme_options = {
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static'] html_static_path = ['_static']
html_style='zmstyles.css' #html_style='zmstyles.css'
# Add any extra paths that contain custom files (such as robots.txt or # Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied # .htaccess) here, relative to this directory. These files are copied

View File

@ -0,0 +1,477 @@
Ubuntu
======
.. contents::
Easy Way: Install ZoneMinder from a package (Ubuntu 15.x+)
-----------------------------------------------------------
These instructions are for a brand new ubuntu 15.04 system which does not have ZM installed.
**Step 1**: Make sure we add the correct packages
::
sudo add-apt-repository ppa:iconnor/zoneminder
sudo apt-get update
if you don't have mysql already installed:
::
sudo apt-get install mysql-server
This will ask you to set up a master password for the DB (you are asked for the mysql root password when installing mysql server).
**Step 2**: Install ZoneMinder
::
sudo apt-get install zoneminder
**Step 3**: Configure the Database
::
sudo mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql
mysql -uroot -p -e "grant select,insert,update,delete,create,alter,index,lock tables on zm.* to 'zmuser'@localhost identified by 'zmpass';"
You don't really need this, but no harm (needed if you are upgrading)
::
sudo /usr/bin/zmupdate.pl
**Step 4**: Configure systemd to recognize ZoneMinder and configure Apache correctly:
::
sudo systemctl enable zoneminder
sudo a2enconf zoneminder
sudo a2enmod cgi
sudo chown -R www-data:www-data /usr/share/zoneminder/
We need this for API routing to work:
::
sudo a2enmod rewrite
This is probably a bug with iconnor's PPA as of Oct 3, 2015 with package 1.28.107. After installing, ``zm.conf`` does not have the right read permissions, so we need to fix that. This may go away in future PPA releases:
::
sudo chown www-data:www-data /etc/zm/zm.conf
We also need to install php5-gd (as of 1.28.107, this is not installed)
::
sudo apt-get install php5-gd
**Step 5**: Edit Timezone in PHP
::
vi /etc/php5/apache2/php.ini
Look for [Date] and inside it you will see a date.timezone
that is commented. remove the comment and specific your timezone.
Please make sure the timezone is valid (see this: http://php.net/manual/en/timezones.php)
In my case:
::
date.timezone = America/New_York
**Step 6**: Restart services
::
sudo service apache2 reload
sudo systemctl restart zoneminder
**Step 7: make sure live streaming works**: Make sure you can view Monitor streams:
startup ZM console in your browser, go to ``Options->Path`` and make sure ``PATH_ZMS`` is set to ``/zm/cgi-bin/nph-zms`` and restart ZM (you should not need to do this for packages, as this should automatically work)
**Step 8**: If you have changed your DB login/password from zmuser/zmpass, the API won't know about it
If you changed the DB password **after** installing ZM, the APIs will not be able to connect to the DB.
If you have, go to ``zoneminder/www/api/app/Config`` & Edit ``database.php``
There is a class there called ``DATABASE_CONFIG`` - change the ``$default`` array to reflect your new details. Example:
::
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'mynewDBusername',
'password' => 'mynewDBpassword'
'database' => 'zm',
'prefix' => '',
//'encoding' => 'utf8',
);
You are done. Lets proceed to make sure everything works:
Making sure ZM and APIs work:
1. open up a browser and go to ``http://localhost/zm`` - should bring up ZM
2. (OPTIONAL - just for peace of mind) open up a tab and go to ``http://localhost/zm/api`` - should bring up a screen showing CakePHP version with some green color boxes. Green is good. If you see red, or you don't see green, there may be a problem (should not happen). Ignore any warnings in yellow saying "DebugKit" not installed. You don't need it
3. open up a tab in the same browser and go to ``http://localhost/zm/api/host/getVersion.json``
If it responds with something like:
::
{
"version": "1.28.107",
"apiversion": "1.28.107.1"
}
**Then your APIs are working**
Make sure ZM and APIs work with security:
1. Enable OPT_AUTH in ZM
2. Log out of ZM in browser
3. Open a NEW tab in the SAME BROWSER (important) and go to ``http://localhost/zm/api/host/getVersion.json`` - should give you "Unauthorized" along with a lot more of text
4. Go to another tab in the SAME BROWSER (important) and log into ZM
5. Repeat step 3 and it should give you the ZM and API version
**Congrats** your installation is complete
Easy Way: Install ZoneMinder from a package (Ubuntu 14.x)
-----------------------------------------------------------
**These instructions are for a brand new ubuntu 14.x system which does not have ZM installed.**
**Step 1:** Install ZoneMinder
::
sudo add-apt-repository ppa:iconnor/zoneminder
sudo apt-get update
sudo apt-get install zoneminder
(just press OK for the prompts you get)
**Step 2:** Set up DB
::
sudo mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql
mysql -uroot -p -e "grant select,insert,update,delete,create,alter,index,lock tables on zm.* to 'zmuser'@localhost identified by 'zmpass';"
**Step 3:** Set up Apache
::
sudo a2enconf zoneminder
sudo a2enmod rewrite
sudo a2enmod cgi
**Step 4:**:Some tweaks that will be needed:
Edit /etc/init.d/zoneminder:
add a ``sleep 10`` right after line 25 that reads ``echo -n "Starting $prog:"``
(The reason we need this sleep is to make sure ZM starts after mysqld starts)
As of Oct 3 2015, zm.conf is not readable by ZM. This is likely a bug and will go away in the next package
::
sudo chown www-data:www-data /etc/zm/zm.conf
**Step 5**: If you have changed your DB login/password
If you changed the DB password **after** installing ZM, the APIs will not be able to connect to the DB.
If you have, go to zoneminder/www/api/app/Config & Edit ``database.php``
There is a class there called ``DATABASE_CONFIG`` - change the ``$default`` array to reflect your new details. Example:
::
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'mynewDBusername',
'password' => 'mynewDBpassword'
'database' => 'zm',
'prefix' => '',
//'encoding' => 'utf8',`
);
We also need to install php5-gd (as of 1.28.107, this is not installed)
::
sudo apt-get install php5-gd
**Step 6**: Edit Timezone in PHP
vi /etc/php5/apache2/php.ini
Look for [Date] and inside it you will see a date.timezone
that is commented. remove the comment and specific your timezone.
Please make sure the timezone is valid (see [this](http://php.net/manual/en/timezones.php))
In my case:
::
date.timezone = America/New_York
**Step 7: make sure live streaming works**: Make sure you can view Monitor streams:
startup ZM console in your browser, go to ``Options->Path`` and make sure ``PATH_ZMS`` is set to ``/zm/cgi-bin/nph-zms`` and restart ZM (you should not need to do this for packages, as this should automatically work)
restart:
::
sudo service apache2 restart
/etc/init.d/zoneminder restart
**Step 8**: Making sure ZM and APIs work: (optional - only if you need APIs)
1. open up a browser and go to ``http://localhost/zm`` - should bring up ZM
2. (OPTIONAL - just for peace of mind) open up a tab and go to ``http://localhost/zm/api`` - should bring up a screen showing CakePHP version with some green color boxes. Green is good. If you see red, or you don't see green, there may be a problem (should not happen). Ignore any warnings in yellow saying "DebugKit" not installed. You don't need it
3. open up a tab in the same browser and go to ``http://localhost/zm/api/host/getVersion.json``
If it responds with something like:
::
{
"version": "1.28.107",
"apiversion": "1.28.107.1"
}
Then your APIs are working
Make sure you can view Monitor View:
1. Open up ZM, configure your monitors and verify you can view Monitor feeds.
2. If not, open up ZM console in your browser, go to ``Options->Path`` and make sure ``PATH_ZMS`` is set to ``/zm/cgi-bin/nph-zms`` and restart ZM (you should not need to do this for packages, as this should automatically work)
Make sure ZM and APIs work with security:
1. Enable OPT_AUTH in ZM
2. Log out of ZM in browser
3. Open a NEW tab in the SAME BROWSER (important) and go to ``http://localhost/zm/api/host/getVersion.json`` - should give you "Unauthorized" along with a lot more of text
4. Go to another tab in the SAME BROWSER (important) and log into ZM
5. Repeat step 3 and it should give you the ZM and API version
**Congrats** Your installation is complete
Harder Way: Build Package From Source
-------------------------------------------
(These instructions assume installation from source on a ubuntu 15.x+ system)
**Step 1:** First make sure you have the needed tools
::
sudo apt-get update
sudo apt-get install cmake git
**Step 2:** Next up make sure you have all the dependencies
::
sudo apt-get install apache2 mysql-server php5 php5-mysql build-essential libmysqlclient-dev libssl-dev libbz2-dev libpcre3-dev libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libpcre3 libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm automake autoconf libjpeg8-dev libjpeg8 apache2 libapache2-mod-php5 php5-cli libphp-serialization-perl libgnutls-dev libjpeg8-dev libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libv4l-dev libtool ffmpeg libnetpbm10-dev libavdevice-dev libmime-lite-perl dh-autoreconf dpatch policykit-1 libpolkit-gobject-1-dev libextutils-pkgconfig-perl libcurl3 libvlc-dev libcurl4-openssl-dev curl php5-gd
(you are asked for the mysql root password when installing mysql server - put in a password that you'd like).
**Step 3:** Download ZoneMinder source code and compile+install:
::
git clone https://github.com/ZoneMinder/ZoneMinder.git
cd ZoneMinder/
git submodule init
git submodule update
cmake .
make
sudo make install
**Step 4:** Now make sure your symlinks to events and images are set correctly:
::
sudo ./zmlinkcontent.sh
**Step 5:** Now lets make sure ZM has DB permissions to write to the DB:
::
mysql -uroot -p -e "grant select,insert,update,delete,create,alter,index,lock tables on zm.* to 'zmuser'@localhost identified by 'zmpass';"
**Step 6:** Now lets create the DB & its tables that ZM needs
::
mysql -uroot -p <db/zm_create.sql
**Step 7:** Now we need to make sure Ubuntu 15 is able to start/stop zoneminder via systemd:
::
sudo cp distros/ubuntu1504_cmake/zoneminder.service /lib/systemd/system
edit **/lib/systemd/system/zoneminder.service** file
* rename **/usr/bin/zmpkg** to **/usr/local/bin/zmpkg** everywhere
(The step above is needed because when you compile from source, it installs to /usr/local/instead of /usr/)
**Step 8:** Now lets make sure systemd recognizes this file
::
sudo systemctl daemon-reload
sudo systemctl enable zoneminder.service
**Step 9:** Now lets work on Zoneminder's apache configuration:
::
sudo cp distros/ubuntu1504_cmake/conf/apache2/zoneminder.conf /etc/apache2/conf-available/
sudo a2enconf zoneminder
sudo a2enmod cgi
sudo a2enmod rewrite
sudo service apache2 reload
**Step 10:** Edit /etc/apache2/conf-available/zoneminder.conf and change **all** occurrences of:
* **/usr/lib/zoneminder/cgi-bin** to **/usr/local/libexec/zoneminder/cgi-bin**
* **/usr/share/zoneminder** to **/usr/local/share/zoneminder**
After editing your /etc/apache2/conf-available/zoneminder.conf should look like:
::
ScriptAlias /zm/cgi-bin "/usr/local/libexec/zoneminder/cgi-bin"
<Directory "/usr/local/libexec/zoneminder/cgi-bin">
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AllowOverride All
Require all granted
</Directory>
Alias /zm /usr/local/share/zoneminder/www
<Directory /usr/local/share/zoneminder/www>
php_flag register_globals off
Options Indexes FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
<Directory /usr/local/share/zoneminder/www/api>
AllowOverride All
</Directory>
**Step 11:** Now lets make sure ZM can read/write to the zoneminder directory:
::
sudo chown -R www-data:www-data /usr/local/share/zoneminder/
**Step 12:** Make sure you can view Monitor View
1. Open up ZM, configure your monitors and verify you can view Monitor feeds
2. If not, open up ZM console in your browser, go to ``Options->Path`` and make sure ``PATH_ZMS`` is set to ``/zm/cgi-bin/nph-zms`` and restart ZM
**Step 13**: Edit Timezone in PHP
vi /etc/php5/apache2/php.ini
Look for [Date] and inside it you will see a date.timezone
that is commented. remove the comment and specific your timezone.
Please make sure the timezone is valid (see http://php.net/manual/en/timezones.php)
In my case:
::
date.timezone = America/New_York
**Step 14:** Finally, lets make a config change to apache (needed for htaccess overrides to work for APIs)
Edit /etc/apache2/apache2.conf and add this:
::
<Directory /usr/local/share>
AllowOverride All
Require all granted
</Directory>
Restart apache
::
sudo service apache2 reload
You are done. Lets proceed to make sure everything works:
Making sure ZM and APIs work:
1. open up a browser and go to ``http://localhost/zm`` - should bring up ZM
2. (OPTIONAL - just for peace of mind) open up a tab and go to ``http://localhost/zm/api`` - should bring up a screen showing CakePHP version with some green color boxes. Green is good. If you see red, or you don't see green, there may be a problem (should not happen). Ignore any warnings in yellow saying "DebugKit" not installed. You don't need it
3. open up a tab in the same browser and go to ``http://localhost/zm/api/host/getVersion.json``
If it responds with something like:
::
{
"version": "1.28.107",
"apiversion": "1.28.107.1"
}
Then your APIs are working
Make sure ZM and APIs work with security:
1. Enable OPT_AUTH in ZM
2. Log out of ZM in browser
3. Open a NEW tab in the SAME BROWSER (important) and go to ``http://localhost/zm/api/host/getVersion.json`` - should give you "Unauthorized" along with a lot more of text
4. Go to another tab in the SAME BROWSER (important) and log into ZM
5. Repeat step 3 and it should give you the ZM and API version
**Congrats** your installation is complete
Suggested changes to MySQL (Optional but recommended)
------------------------------------------------------
For most of you Zoneminder will run just fine with the default MySQL settings. There are a couple of settings that may, in time, provide beneficial especially if you have a number of cameras and many events with a lot of files. One setting we recommend is the "innodb_file_per_table" This will be a default setting in MySQL 5.6 but should be added in MySQL 5.5 which comes with Ubuntu 14.04. A description can be found here: http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html
To add "innodb_file_per_table" edit the my.cnf file:
``vi /etc/mysql/my.cnf``
Under [mysqld] add
``innodb_file_per_table``
Save and exit.
Restart MySQL
``service mysql restart``

View File

@ -357,6 +357,22 @@ our @options =
type => $types{boolean}, type => $types{boolean},
category => "system", category => "system",
}, },
{
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 # PP - Google reCaptcha settings
{ {
name => "ZM_OPT_USE_GOOG_RECAPTCHA", name => "ZM_OPT_USE_GOOG_RECAPTCHA",
@ -411,6 +427,7 @@ our @options =
category => "system", category => "system",
}, },
{ {
name => "ZM_DIR_EVENTS", name => "ZM_DIR_EVENTS",
default => "events", default => "events",

View File

@ -71,7 +71,7 @@ void RemoteCamera::Initialise()
} }
mNeedAuth = false; mNeedAuth = false;
mAuthenticator = new Authenticator(username,password); mAuthenticator = new zm::Authenticator(username,password);
struct addrinfo hints; struct addrinfo hints;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));

View File

@ -50,7 +50,7 @@ protected:
// fill required fields and set needAuth // fill required fields and set needAuth
// subsequent requests can set the required authentication header. // subsequent requests can set the required authentication header.
bool mNeedAuth; bool mNeedAuth;
Authenticator* mAuthenticator; zm::Authenticator* mAuthenticator;
protected: protected:
struct addrinfo *hp; struct addrinfo *hp;

View File

@ -306,7 +306,7 @@ int RemoteCameraHttp::GetResponse()
std::string Header = header; std::string Header = header;
mAuthenticator->checkAuthResponse(Header); mAuthenticator->checkAuthResponse(Header);
if ( mAuthenticator->auth_method() == AUTH_DIGEST ) { if ( mAuthenticator->auth_method() == zm::AUTH_DIGEST ) {
Debug( 2, "Need Digest Authentication" ); Debug( 2, "Need Digest Authentication" );
request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version ); request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version );
request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION ); request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION );
@ -750,7 +750,7 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
Debug(2, "Checking for digest auth in %s", authenticate_header ); Debug(2, "Checking for digest auth in %s", authenticate_header );
mAuthenticator->checkAuthResponse(Header); mAuthenticator->checkAuthResponse(Header);
if ( mAuthenticator->auth_method() == AUTH_DIGEST ) { if ( mAuthenticator->auth_method() == zm::AUTH_DIGEST ) {
Debug( 2, "Need Digest Authentication" ); Debug( 2, "Need Digest Authentication" );
request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version ); request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version );
request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION ); request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION );

View File

@ -203,9 +203,9 @@ RtspThread::RtspThread( int id, RtspMethod method, const std::string &protocol,
mNeedAuth = false; mNeedAuth = false;
StringVector parts = split(auth,":"); StringVector parts = split(auth,":");
if (parts.size() > 1) if (parts.size() > 1)
mAuthenticator = new Authenticator(parts[0], parts[1]); mAuthenticator = new zm::Authenticator(parts[0], parts[1]);
else else
mAuthenticator = new Authenticator(parts[0], ""); mAuthenticator = new zm::Authenticator(parts[0], "");
} }
RtspThread::~RtspThread() RtspThread::~RtspThread()

View File

@ -66,7 +66,7 @@ private:
// subsequent requests can set the required authentication header. // subsequent requests can set the required authentication header.
bool mNeedAuth; bool mNeedAuth;
int respCode; int respCode;
Authenticator* mAuthenticator; zm::Authenticator* mAuthenticator;
std::string mHttpSession; ///< Only for RTSP over HTTP sessions std::string mHttpSession; ///< Only for RTSP over HTTP sessions

View File

@ -24,6 +24,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
namespace zm {
Authenticator::Authenticator(std::string &username, std::string password) { Authenticator::Authenticator(std::string &username, std::string password) {
#ifdef HAVE_GCRYPT_H #ifdef HAVE_GCRYPT_H
// Special initialisation for libgcrypt // Special initialisation for libgcrypt
@ -227,3 +229,5 @@ void Authenticator::checkAuthResponse(std::string &response) {
Debug( 2, "Didn't find auth line in %s", authLine.c_str()); Debug( 2, "Didn't find auth line in %s", authLine.c_str());
} }
} }
} // namespace zm

View File

@ -32,6 +32,8 @@
#include <openssl/md5.h> #include <openssl/md5.h>
#endif // HAVE_GCRYPT_H || HAVE_LIBCRYPTO #endif // HAVE_GCRYPT_H || HAVE_LIBCRYPTO
namespace zm {
enum AuthMethod { AUTH_UNDEFINED = 0, AUTH_BASIC = 1, AUTH_DIGEST = 2 }; enum AuthMethod { AUTH_UNDEFINED = 0, AUTH_BASIC = 1, AUTH_DIGEST = 2 };
class Authenticator { class Authenticator {
public: public:
@ -62,4 +64,6 @@ private:
int nc; int nc;
}; };
} // namespace zm
#endif // ZM_RTSP_AUTH_H #endif // ZM_RTSP_AUTH_H

View File

@ -34,7 +34,7 @@ class AppController extends Controller {
use CrudControllerTrait; use CrudControllerTrait;
public $components = [ 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', 'RequestHandler',
'Crud.Crud' => [ 'Crud.Crud' => [
'actions' => [ 'actions' => [
@ -49,7 +49,7 @@ class AppController extends Controller {
] ]
]; ];
//PP - Global beforeFilter function // Global beforeFilter function
//Zoneminder sets the username session variable //Zoneminder sets the username session variable
// to the logged in user. If this variable is set // to the logged in user. If this variable is set
// then you are logged in // then you are logged in
@ -58,15 +58,63 @@ class AppController extends Controller {
// Also checking to do this only if ZM_OPT_USE_AUTH is on // Also checking to do this only if ZM_OPT_USE_AUTH is on
public function beforeFilter() { public function beforeFilter() {
$this->loadModel('Config'); $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')); $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH'));
$config = $this->Config->find('first', $options); $config = $this->Config->find('first', $options);
$zmOptAuth = $config['Config']['Value']; $zmOptAuth = $config['Config']['Value'];
if (!$this->Session->Read('user.Username') && ($zmOptAuth=='1')) if (!$this->Session->Read('user.Username') && ($zmOptAuth=='1'))
{ {
throw new NotFoundException(__('Not Authenticated')); throw new UnauthorizedException(__('Not Authenticated'));
return;
}
else
{
$this->loadModel('User');
$loggedinUser = $this->Session->Read('user.Username');
$isEnabled = $this->Session->Read('user.Enabled');
// 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; 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');
}
}
} }
} }

View File

@ -48,7 +48,7 @@ class ImageComponent extends Component {
$imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath; $imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath;
//$thumbFile = ZM_DIR_EVENTS."/".$thumbPath; //$thumbFile = ZM_DIR_EVENTS."/".$thumbPath;
$thumbFile = $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 // This actually seems to be generating images for the angular UI web view
// and should not be a part of the API anyway // and should not be a part of the API anyway
// I've commented it so events APIs continue to work // I've commented it so events APIs continue to work

View File

@ -15,7 +15,7 @@ class ConfigsController extends AppController {
public $components = array('RequestHandler'); 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 * refer https://github.com/ZoneMinder/ZoneMinder/issues/953
* index method * index method
* *

View File

@ -14,6 +14,17 @@ class EventsController extends AppController {
*/ */
public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator'); public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('eventPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/** /**
* index method * index method
* *
@ -23,6 +34,18 @@ class EventsController extends AppController {
public function index() { public function index() {
$this->Event->recursive = -1; $this->Event->recursive = -1;
$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']) { if ($this->request->params['named']) {
$this->FilterComponent = $this->Components->load('Filter'); $this->FilterComponent = $this->Components->load('Filter');
$conditions = $this->FilterComponent->buildFilter($this->request->params['named']); $conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
@ -39,7 +62,7 @@ class EventsController extends AppController {
$this->Paginator->settings = array( $this->Paginator->settings = array(
// https://github.com/ZoneMinder/ZoneMinder/issues/995 // https://github.com/ZoneMinder/ZoneMinder/issues/995
// 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'], // '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 // default is, is way too low for an API
// changing this to 100 so we don't kill ZM // changing this to 100 so we don't kill ZM
// with many event APIs. In future, we can // with many event APIs. In future, we can
@ -49,13 +72,13 @@ class EventsController extends AppController {
'limit' => '100', 'limit' => '100',
'order' => array('StartTime', 'MaxScore'), 'order' => array('StartTime', 'MaxScore'),
'paramType' => 'querystring', 'paramType' => 'querystring',
'conditions' => $conditions 'conditions' => array (array($conditions, $mon_options))
); );
$events = $this->Paginator->paginate('Event'); $events = $this->Paginator->paginate('Event');
// For each event, get its thumbnail data (path, width, height) // For each event, get its thumbnail data (path, width, height)
foreach ($events as $key => $value) { foreach ($events as $key => $value) {
// PP - $thumbData = $this->createThumbnail($value['Event']['Id']); //$thumbData = $this->createThumbnail($value['Event']['Id']);
$thumbData = ""; $thumbData = "";
$events[$key]['thumbData'] = $thumbData; $events[$key]['thumbData'] = $thumbData;
@ -71,7 +94,8 @@ class EventsController extends AppController {
* @param string $id * @param string $id
* @return void * @return void
*/ */
public function view($id = null) { public function view($id = null)
{
$this->loadModel('Config'); $this->loadModel('Config');
$configs = $this->Config->find('list', array( $configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'), 'fields' => array('Name', 'Value'),
@ -82,7 +106,19 @@ class EventsController extends AppController {
if (!$this->Event->exists($id)) { if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event')); throw new NotFoundException(__('Invalid event'));
} }
$options = array('conditions' => array('Event.' . $this->Event->primaryKey => $id));
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
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); $event = $this->Event->find('first', $options);
$path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/'; $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
@ -107,12 +143,20 @@ class EventsController extends AppController {
)); ));
} }
/** /**
* add method * add method
* *
* @return void * @return void
*/ */
public function add() { public function add() {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->request->is('post')) { if ($this->request->is('post')) {
$this->Event->create(); $this->Event->create();
if ($this->Event->save($this->request->data)) { if ($this->Event->save($this->request->data)) {
@ -131,6 +175,13 @@ class EventsController extends AppController {
* @return void * @return void
*/ */
public function edit($id = null) { public function edit($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id; $this->Event->id = $id;
if (!$this->Event->exists($id)) { if (!$this->Event->exists($id)) {
@ -157,15 +208,19 @@ class EventsController extends AppController {
* @return void * @return void
*/ */
public function delete($id = null) { public function delete($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id; $this->Event->id = $id;
if (!$this->Event->exists()) { if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event')); throw new NotFoundException(__('Invalid event'));
} }
$this->request->allowMethod('post', 'delete'); $this->request->allowMethod('post', 'delete');
if ($this->Event->delete()) { if ($this->Event->delete()) {
// PP - lets make sure the frame table entry is removed too //$this->loadModel('Frame');
$this->loadModel('Frame'); //$this->Event->Frame->delete();
$this->Frame->delete();
return $this->flash(__('The event has been deleted.'), array('action' => 'index')); return $this->flash(__('The event has been deleted.'), array('action' => 'index'));
} else { } else {
return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index')); return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index'));

View File

@ -101,7 +101,10 @@ class HostController extends AppController {
function getVersion() { function getVersion() {
$version = Configure::read('ZM_VERSION'); $version = Configure::read('ZM_VERSION');
$apiversion = Configure::read('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';
$this->set(array( $this->set(array(
'version' => $version, 'version' => $version,

View File

@ -16,6 +16,19 @@ class MonitorsController extends AppController {
*/ */
public $components = array('Paginator', 'RequestHandler'); public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/** /**
* index method * index method
* *
@ -23,7 +36,17 @@ class MonitorsController extends AppController {
*/ */
public function index() { public function index() {
$this->Monitor->recursive = 0; $this->Monitor->recursive = 0;
$monitors = $this->Monitor->find('all'); $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( $this->set(array(
'monitors' => $monitors, 'monitors' => $monitors,
'_serialize' => array('monitors') '_serialize' => array('monitors')
@ -42,7 +65,21 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists($id)) { if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor')); throw new NotFoundException(__('Invalid monitor'));
} }
$options = array('conditions' => array('Monitor.' . $this->Monitor->primaryKey => $id)); $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); $monitor = $this->Monitor->find('first', $options);
$this->set(array( $this->set(array(
'monitor' => $monitor, 'monitor' => $monitor,
@ -57,6 +94,13 @@ class MonitorsController extends AppController {
*/ */
public function add() { public function add() {
if ($this->request->is('post')) { if ($this->request->is('post')) {
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthotizedException(__('Insufficient privileges'));
return;
}
$this->Monitor->create(); $this->Monitor->create();
if ($this->Monitor->save($this->request->data)) { if ($this->Monitor->save($this->request->data)) {
$this->daemonControl($this->Monitor->id, 'start', $this->request->data); $this->daemonControl($this->Monitor->id, 'start', $this->request->data);
@ -78,7 +122,11 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists($id)) { if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor')); throw new NotFoundException(__('Invalid monitor'));
} }
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->Monitor->save($this->request->data)) { if ($this->Monitor->save($this->request->data)) {
$message = 'Saved'; $message = 'Saved';
} else { } else {
@ -89,9 +137,8 @@ class MonitorsController extends AppController {
'message' => $message, 'message' => $message,
'_serialize' => array('message') '_serialize' => array('message')
)); ));
// PP - restart this monitor after change // - 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 +153,11 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists()) { if (!$this->Monitor->exists()) {
throw new NotFoundException(__('Invalid monitor')); throw new NotFoundException(__('Invalid monitor'));
} }
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->request->allowMethod('post', 'delete'); $this->request->allowMethod('post', 'delete');
$this->daemonControl($this->Monitor->id, 'stop'); $this->daemonControl($this->Monitor->id, 'stop');

View File

@ -0,0 +1,31 @@
<?php
App::uses('AppModel', 'Model');
/**
* User Model
*
*/
class User extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Users';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Display field
*
* @var string
*/
public $displayField = 'Name';
}

View File

@ -910,7 +910,16 @@ $OLANG = array(
"Enable this option to tell ZoneMinder to use this URL. Disable this option to ignore the ". "Enable this option to tell ZoneMinder to use this URL. Disable this option to ignore the ".
"value from the camera and use the value as entered in the monitor configuration~~~~". "value from the camera and use the value as entered in the monitor configuration~~~~".
"Generally this should be enabled. However, there are cases where the camera can get its". "Generally this should be enabled. However, there are cases where the camera can get its".
"own URL incorrect, such as when the camera is streaming through a firewall" "own URL incorrect, such as when the camera is streaming through a firewall"),
'OPTIONS_MAXFPS' => array(
'Help' => "This field has certain limitations when used for non-local devices.~~ ".
"Failure to adhere to these limitations will cause a delay in live video, irregular frame skipping, ".
"and missed events~~".
"For streaming IP cameras, do not use this field to reduce the frame rate. Set the frame rate in the".
" camera, instead. You can, however, use a value that is slightly higher than the frame rate in the camera. ".
"In this case, this helps keep the cpu from being overtaxed in the event of a network problem.~~".
"Some, mostly older, IP cameras support snapshot mode. In this case ZoneMinder is actively polling the camera ".
"for new images. In this case, it is safe to use thie field."
), ),
// 'LANG_DEFAULT' => array( // 'LANG_DEFAULT' => array(

View File

@ -711,9 +711,19 @@ switch ( $tab )
</td> </td>
</tr> </tr>
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($newMonitor['AnalysisFPS']) ?>" size="6"/></td></tr> <tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($newMonitor['AnalysisFPS']) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('MaximumFPS') ?></td><td><input type="text" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?></td><td><input type="text" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>" size="6"/></td></tr>
<?php <?php
if ( $newMonitor['Type'] != "Local" && $newMonitor['Type'] != "File" )
{
?>
<tr><td><?php echo translate('MaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td></tr>
<?php
} else {
?>
<tr><td><?php echo translate('MaximumFPS') ?></td><td><input type="text" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>" size="5"/></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?></td><td><input type="text" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>" size="5"/></td></tr>
<?php
}
if ( ZM_FAST_IMAGE_BLENDS ) if ( ZM_FAST_IMAGE_BLENDS )
{ {
?> ?>