mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-06-23 04:59:37 -04:00
Merge branch 'master' into patch-180448
This commit is contained in:
@@ -13,7 +13,7 @@ Build-Depends: debhelper, sphinx-doc, dh-linktree, dh-apache2
|
||||
,ffmpeg
|
||||
,net-tools
|
||||
,libbz2-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libcurl4-gnutls-dev | libcurl4-openssl-dev | libcurl4-nss-dev
|
||||
,libturbojpeg0-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||
,libpcre2-dev
|
||||
|
||||
@@ -14,7 +14,7 @@ Build-Depends: debhelper (>= 11), sphinx-doc, python3-sphinx, python3-sphinx-rtd
|
||||
,arp-scan
|
||||
,net-tools, iproute2
|
||||
,libbz2-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libcurl4-gnutls-dev | libcurl4-openssl-dev | libcurl4-nss-dev
|
||||
,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev
|
||||
,libturbojpeg0-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||
@@ -47,7 +47,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||
,libswscale9|libswscale8|libswscale7|libswscale6|libswscale5|libswscale4
|
||||
,libswresample6|libswresample5|libswresample4|libswresample3|libswresample2
|
||||
,ffmpeg
|
||||
,libcurl4, libcurl4-gnutls-dev
|
||||
,libdatetime-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
|
||||
,libdbd-mysql-perl
|
||||
,libphp-serialization-perl
|
||||
|
||||
@@ -24,7 +24,7 @@ class ZM_Object {
|
||||
$table = $class::$table;
|
||||
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($IdOrRow));
|
||||
if (!$row) {
|
||||
Error("Unable to load $class record for Id=$IdOrRow");
|
||||
Warning("Unable to load $class record for Id=$IdOrRow");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -424,7 +424,7 @@ function htmlOptions($options, $values) {
|
||||
$has_selected = false;
|
||||
foreach ( $options as $value=>$option ) {
|
||||
$disabled = 0;
|
||||
$text = '';
|
||||
$text = $class = '';
|
||||
if ( is_array($option) ) {
|
||||
|
||||
if ( isset($option['Name']) )
|
||||
@@ -435,6 +435,9 @@ function htmlOptions($options, $values) {
|
||||
if ( isset($option['disabled']) ) {
|
||||
$disabled = $option['disabled'];
|
||||
}
|
||||
if ( isset($option['class']) ) {
|
||||
$class = $option['class'];
|
||||
}
|
||||
} else if ( is_object($option) ) {
|
||||
$text = $option->Name();
|
||||
} else {
|
||||
@@ -450,6 +453,7 @@ function htmlOptions($options, $values) {
|
||||
$options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'.
|
||||
($selected?' selected="selected"':'').
|
||||
($disabled?' disabled="disabled"':'').
|
||||
($class?' class="'.htmlspecialchars($class, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"':'').
|
||||
'>'.htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'</option>'.PHP_EOL;
|
||||
} # end foreach options
|
||||
if ( $values and ((!is_array($values)) or count($values) ) and ! $has_selected ) {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.monitor-added {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.chosen-container {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ function streamCmdPlay(action) {
|
||||
}
|
||||
}
|
||||
|
||||
function streamCmdStop(action) {
|
||||
function streamCmdStop() {
|
||||
monitorStream.onplay = false; //Without this line, "onPlay" is triggered immediately due to "if (this.onplay) this.onplay();" in MonitorStream.js
|
||||
//setButtonState('pauseBtn', 'inactive');
|
||||
//setButtonState('playBtn', 'unavail');
|
||||
@@ -221,9 +221,8 @@ function streamCmdStop(action) {
|
||||
setButtonState('slowRevBtn', 'unavail');
|
||||
setButtonState('fastRevBtn', 'unavail');
|
||||
}
|
||||
if (action) {
|
||||
monitorStream.stop();
|
||||
}
|
||||
monitorStream.stop();
|
||||
|
||||
//setButtonState('stopBtn', 'unavail');
|
||||
//setButtonState('playBtn', 'active');
|
||||
setButtonStateWatch('playBtn', 'inactive');
|
||||
@@ -1063,7 +1062,7 @@ function initPage() {
|
||||
|
||||
function stopPlayback() {
|
||||
idleTimeoutTriggered = true;
|
||||
streamCmdStop(true);
|
||||
streamCmdStop();
|
||||
const cycle_was = cycle;
|
||||
cyclePause();
|
||||
let ayswModal = $j('#AYSWModal');
|
||||
@@ -1359,7 +1358,7 @@ function monitorChangeStreamChannel() {
|
||||
monitorStream.currentChannelStream = streamChannel;
|
||||
setCookie('zmStreamChannel', streamChannel);
|
||||
if ((monitorStream.activePlayer) && (-1 !== monitorStream.activePlayer.indexOf('go2rtc') || -1 !== monitorStream.activePlayer.indexOf('rtsp2web'))) {
|
||||
streamCmdStop(true);
|
||||
streamCmdStop();
|
||||
setTimeout(function() {
|
||||
monitorStream.start(streamChannel);
|
||||
onPlay();
|
||||
@@ -1375,7 +1374,7 @@ function changePlayer() {
|
||||
if (monitorStream.audioMotion && monitorStream.audioMotion.destroy) monitorStream.audioMotion.destroy();
|
||||
|
||||
monitorStream.destroyVolumeSlider();
|
||||
streamCmdStop(true); // takes care of button state and calls stream.kill()
|
||||
streamCmdStop(); // takes care of button state and calls stream.kill()
|
||||
console.log('setting to ', $j('#player').val());
|
||||
monitorStream.setPlayer($j('#player').val());
|
||||
setChannelStream();
|
||||
|
||||
@@ -169,15 +169,32 @@ if (!isset($_REQUEST['step']) || ($_REQUEST['step'] == '1')) {
|
||||
}
|
||||
}
|
||||
|
||||
$detcameras = probeCameras('');
|
||||
foreach ($detcameras as $camera) {
|
||||
if (preg_match('|([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|', $camera['monitor']['Host'], $matches)) {
|
||||
$ip = $matches[1];
|
||||
$monitors = dbFetchAll('SELECT Path FROM Monitors WHERE Deleted=false');
|
||||
$monitorHosts = [];
|
||||
if ($monitors) {
|
||||
foreach ($monitors as $monitor) {
|
||||
$_host = parse_url($monitor['Path'], PHP_URL_HOST);
|
||||
if ($_host) {
|
||||
$monitorHosts[] = $_host;
|
||||
}
|
||||
}
|
||||
$host = $ip;
|
||||
}
|
||||
$monitorHosts = array_unique($monitorHosts);
|
||||
|
||||
$detcameras = probeCameras('');
|
||||
usort($detcameras, function($a, $b) {
|
||||
return strcasecmp(parse_url($a['monitor']['Host'], PHP_URL_HOST) ?: '', parse_url($b['monitor']['Host'], PHP_URL_HOST) ?: '');
|
||||
});
|
||||
foreach ($detcameras as $camera) {
|
||||
$host = parse_url($camera['monitor']['Host'], PHP_URL_HOST);
|
||||
$sourceDesc = base64_encode(json_encode($camera['monitor']));
|
||||
$sourceString = $camera['model'].' @ '.$host.' using version '.$camera['monitor']['SOAP'];
|
||||
$cameras[$sourceDesc] = $sourceString;
|
||||
$sourceString = htmlspecialchars($camera['model'].' @ '.$host.' using version '.$camera['monitor']['SOAP']);
|
||||
|
||||
if ($host && in_array($host, $monitorHosts, true)) {
|
||||
$cameras[$sourceDesc] = ['Name'=> $sourceString, 'class'=> 'monitor-added'];
|
||||
} else {
|
||||
$cameras[$sourceDesc] = $sourceString;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($cameras) <= 0)
|
||||
|
||||
@@ -231,6 +231,13 @@ if ( empty($_REQUEST['path']) ) {
|
||||
ZM\Error('Event '.$_REQUEST['eid'].' Not found');
|
||||
return;
|
||||
}
|
||||
// Per-event ACL: coarse Events/Snapshots role isn't enough, must also check
|
||||
// monitor-level permission (GHSA-vj5r-pc2v-gfwv). 404 to avoid leaking the id.
|
||||
if (!$Event->canView()) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
ZM\Warning('Event '.$_REQUEST['eid'].' access denied');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $_REQUEST['fid'] == 'objdetect' ) {
|
||||
// if animation file is found, return that, else return image
|
||||
@@ -418,6 +425,13 @@ if ( empty($_REQUEST['path']) ) {
|
||||
ZM\Error('Event ' . $Frame->EventId() . ' Not Found');
|
||||
return;
|
||||
}
|
||||
// Per-event ACL: see GHSA-vj5r-pc2v-gfwv. The frame id is user-supplied so the
|
||||
// event/monitor it resolves to may be one the user is denied from viewing.
|
||||
if (!$Event->canView()) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
ZM\Warning('Event '.$Frame->EventId().' access denied via frame '.$_REQUEST['fid']);
|
||||
return;
|
||||
}
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
|
||||
} # end if have eid
|
||||
|
||||
|
||||
@@ -22,6 +22,14 @@ if (!$Event->Id()) {
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
die('Event not found');
|
||||
}
|
||||
// Per-event ACL: coarse canView('Events') isn't enough — the user may be denied
|
||||
// access to the monitor that owns this event (GHSA-vj5r-pc2v-gfwv). Return the
|
||||
// same 404 as a missing event so the id isn't leaked.
|
||||
if (!$Event->canView()) {
|
||||
ZM\Warning('Event '.$_REQUEST['eid'].' HLS access denied');
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
die('Event not found');
|
||||
}
|
||||
|
||||
$m3u8_path = $Event->Path() . '/index.m3u8';
|
||||
|
||||
|
||||
@@ -40,15 +40,27 @@ $mode = (!empty($_REQUEST['mode'])) ? $_REQUEST['mode'] : '';
|
||||
|
||||
$Event = null;
|
||||
|
||||
if ( ! empty($_REQUEST['eid']) ) {
|
||||
$Event = new ZM\Event($_REQUEST['eid']);
|
||||
if (!empty($_REQUEST['file'])) {
|
||||
$path = $Event->Path().'/'.basename($_REQUEST['file']);
|
||||
} else {
|
||||
$path = $Event->Path().'/'.$Event->DefaultVideo();
|
||||
$event_id = !empty($_REQUEST['eid']) ? $_REQUEST['eid']
|
||||
: (!empty($_REQUEST['event_id']) ? $_REQUEST['event_id'] : null);
|
||||
|
||||
if ($event_id !== null) {
|
||||
$Event = new ZM\Event($event_id);
|
||||
// Validate the event actually loaded — the constructor silently produces an
|
||||
// empty object for unknown ids. Without this check view_video previously
|
||||
// returned HTTP 200 with an empty body for nonexistent ids.
|
||||
if (!$Event->Id()) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
ZM\Error('Event '.$event_id.' Not found');
|
||||
die();
|
||||
}
|
||||
// Per-event ACL: coarse canView('Events') isn't enough — the user may be
|
||||
// denied access to the monitor that owns this event (GHSA-vj5r-pc2v-gfwv).
|
||||
// 404 matches the missing-event response so the id isn't leaked.
|
||||
if (!$Event->canView()) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
ZM\Warning('Event '.$event_id.' access denied');
|
||||
die();
|
||||
}
|
||||
} else if ( ! empty($_REQUEST['event_id']) ) {
|
||||
$Event = new ZM\Event($_REQUEST['event_id']);
|
||||
if (!empty($_REQUEST['file'])) {
|
||||
$path = $Event->Path().'/'.basename($_REQUEST['file']);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user