From ee3a0c1fd112faa74a4dda359122f4d9138872c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 09:55:32 -0500 Subject: [PATCH 01/35] fix validateForm running on monitor cancel due to lack of type=button on cancel button --- web/index.php | 2 +- web/skins/classic/views/js/monitor.js.php | 4 ++-- web/skins/classic/views/monitor.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/index.php b/web/index.php index 5190fad65..40b387c02 100644 --- a/web/index.php +++ b/web/index.php @@ -224,7 +224,7 @@ if ( ZM_OPT_USE_AUTH and !isset($user) ) { Logger::Debug('Redirecting to login'); $view = 'login'; $request = null; -} else if ( ZM_SHOW_PRIVACY && ($action != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { +} else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { Logger::Debug('Redirecting to privacy'); $view = 'privacy'; $request = null; diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 82127dd8e..6bb6f73ff 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -133,9 +133,9 @@ function validateForm( form ) { if ( errors.length ) { alert( errors.join( "\n" ) ); - return( false ); + return false; } - return( true ); + return true; } function updateLinkedMonitors( element ) { diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index af770eb79..59e4ca04f 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -108,8 +108,8 @@ if ( ! $monitor ) { 'EventPrefix' => 'Event-', 'AnalysisFPSLimit' => '', 'AnalysisUpdateDelay' => 0, - 'MaxFPS' => '30', - 'AlarmMaxFPS' => '30', + 'MaxFPS' => null, + 'AlarmMaxFPS' => null, 'FPSReportInterval' => 100, 'RefBlendPerc' => 6, 'AlarmRefBlendPerc' => 6, @@ -1044,7 +1044,7 @@ if ( $monitor->Type() == 'Local' ) {
- +
From e2fc0ea25d521ab1a1120f6b676f411f33546bd2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 10:22:42 -0500 Subject: [PATCH 02/35] Increase navbar refresh times. 5 seconds is way too fast --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index fa7b86079..ff5b6ea33 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -3035,7 +3035,7 @@ our @options = ( }, { name => 'ZM_WEB_H_REFRESH_NAVBAR', - default => '5', + default => '60', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. @@ -3308,7 +3308,7 @@ our @options = ( }, { name => 'ZM_WEB_M_REFRESH_NAVBAR', - default => '15', + default => '120', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. @@ -3581,7 +3581,7 @@ our @options = ( }, { name => 'ZM_WEB_L_REFRESH_NAVBAR', - default => '35', + default => '180', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. From 0eb1efff8b4cfe87efef27776c9cdacb0d8243d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 13:48:38 -0500 Subject: [PATCH 03/35] fix eslint errors --- web/skins/classic/views/js/events.js | 10 +++++----- web/skins/classic/views/js/montagereview.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index f105b4cf7..b594faa20 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -162,12 +162,12 @@ function initPage() { if ( window.history.length == 1 ) { $j('#controls').children().eq(0).html(''); } - $j('.colThumbnail img').each(function(){ - this.addEventListener('mouseover',thumbnail_onmouseover,false); - this.addEventListener('mouseout',thumbnail_onmouseout,false); + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); }); - $j('input[name=markEids\\[\\]]').each(function(){ - this.addEventListener('click',configureButton,false); + $j('input[name=markEids\\[\\]]').each(function() { + this.addEventListener('click', configureButton, false); }); } diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index b50d59996..f21b59baa 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -936,7 +936,7 @@ function initPage() { console.log("No canvas found for monitor " + monitor_id); continue; } - monitor_canvas.addEventListener('click',clickMonitor,false); + monitor_canvas.addEventListener('click', clickMonitor, false); } setSpeed(speedIndex); //setFit(fitMode); // will redraw From 2dc935b488e2935add61bfafefd88230a41b9851 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Fri, 8 Feb 2019 13:49:00 -0500 Subject: [PATCH 04/35] added object detection frame rendering (#2505) --- web/views/image.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/web/views/image.php b/web/views/image.php index d9b740059..baa8b94cb 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -77,7 +77,17 @@ if ( empty($_REQUEST['path']) ) { return; } - if ( $_REQUEST['fid'] == 'alarm' ) { + if ( $_REQUEST['fid'] == 'objdetect' ) { + $Event = new Event($_REQUEST['eid']); + $path = $Event->Path().'/objdetect.jpg'; + unset($Event); # we don't want event object related processing later for this case + if ( !file_exists($path)) { + header('HTTP/1.0 404 Not Found'); + Fatal("File ".$path." does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + } + + } + else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), array('order'=>'FrameId ASC')); @@ -220,6 +230,7 @@ if ( empty($_REQUEST['path']) ) { } } +# we now load the actual image to send $scale = 0; if ( !empty($_REQUEST['scale']) ) { if ( is_numeric($_REQUEST['scale']) ) { From e36ac1b87295f7442054b919694c10d443d64eff Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Fri, 8 Feb 2019 21:54:23 -0800 Subject: [PATCH 05/35] Add a polyfill for NodeList.prototype.forEach --- web/skins/classic/js/skin.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c78853608..3cbb99e49 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -126,6 +126,11 @@ function createPopup( url, name, tag, width, height ) { } } +// Polyfill for NodeList.prototype.forEach on IE. +if (window.NodeList && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = Array.prototype.forEach; +} + window.addEventListener("DOMContentLoaded", function onSkinDCL() { document.querySelectorAll("form.validateFormOnSubmit").forEach(function(el) { el.addEventListener("submit", function onSubmit(evt) { From 0b38e72f882aea7006dac01d3348f2465bcc8c09 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 01:16:32 -0800 Subject: [PATCH 06/35] view=download: Remove inline event handlers and fix arbitrary URL/XSS usage. Fixes #2441 --- web/ajax/event.php | 2 +- web/includes/functions.php | 1 + web/skins/classic/views/download.php | 17 +++++++++++++---- web/skins/classic/views/js/download.js | 5 ++++- web/skins/classic/views/js/download.js.php | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 04ebca9ad..9d8a85438 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -84,7 +84,7 @@ if ( canView( 'Events' ) ) { $exportStructure = 'flat'; $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; if ( $exportFile = exportEvents( $exportIds, false, false, false, $exportVideo, false, $exportFormat, $exportStructure ) ) - ajaxResponse( array( 'exportFile'=>$exportFile ) ); + ajaxResponse( array( 'exportFormat'=>$exportFormat ) ); else ajaxError( 'Export Failed' ); break; diff --git a/web/includes/functions.php b/web/includes/functions.php index a9cf815b4..2a024fe5a 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -53,6 +53,7 @@ function CSPHeaders($view, $nonce) { case 'controlcap': case 'cycle': case 'donate': + case 'download': case 'error': case 'function': case 'log': diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 4cd46ad6f..5535df36a 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -44,6 +44,15 @@ if (isset($_SESSION['montageReviewFilter'])) { //Handles montageReview filter #Logger::Debug("NO montageReviewFilter"); } +$exportFormat = ''; +if (isset($_REQUEST['exportFormat'])) { + if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { + Error("Invalid exportFormat"); + return; + } + $exportFormat = $_REQUEST['exportFormat']; +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Download') ); @@ -88,15 +97,15 @@ if ( !empty($_REQUEST['eid']) ) { - + - + - + - + diff --git a/web/skins/classic/views/js/download.js b/web/skins/classic/views/js/download.js index c5a179466..483f21d5b 100644 --- a/web/skins/classic/views/js/download.js +++ b/web/skins/classic/views/js/download.js @@ -14,7 +14,7 @@ function exportProgress() { } function exportResponse( respObj, respText ) { - window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) ); + window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFormat='+respObj.exportFormat+'&generated='+((respObj.result=='Ok')?1:0) ); } function exportEvent( form ) { @@ -33,6 +33,9 @@ function initPage() { if ( exportReady ) { startDownload.pass( exportFile ).delay( 1500 ); } + document.getElementById('exportButton').addEventListener("click", function onClick(evt) { + exportEvent(this.form); + }); } window.addEventListener( 'DOMContentLoaded', initPage ); diff --git a/web/skins/classic/views/js/download.js.php b/web/skins/classic/views/js/download.js.php index 8e47bd2f6..3501fc711 100644 --- a/web/skins/classic/views/js/download.js.php +++ b/web/skins/classic/views/js/download.js.php @@ -14,6 +14,6 @@ var eidParm = 'eid='; ?> var exportReady = ; -var exportFile = ''; +var exportFile = '?view=archive&type='; var exportProgressString = ''; From 61f6a92cc050f3db831f04c3c19f8f2d52cbe08e Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 01:37:32 -0800 Subject: [PATCH 07/35] view=download: Validate the eid parameter to avoid XSS. Fixes #2442 --- web/skins/classic/views/download.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 5535df36a..cd3b6c71d 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -47,12 +47,20 @@ if (isset($_SESSION['montageReviewFilter'])) { //Handles montageReview filter $exportFormat = ''; if (isset($_REQUEST['exportFormat'])) { if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { - Error("Invalid exportFormat"); + Error('Invalid exportFormat'); return; } $exportFormat = $_REQUEST['exportFormat']; } +if (!empty($_REQUEST['eid'])) { + $Event = new Event( $_REQUEST['eid'] ); + if (!$Event->Id) { + Error('Invalid event id'); + return; + } +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Download') ); @@ -72,8 +80,7 @@ if ( !empty($_REQUEST['eid']) ) { ?> DiskSpace() ); + echo 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() ); } else if ( !empty($_REQUEST['eids']) ) { $total_size = 0; foreach ( $_REQUEST['eids'] as $eid ) { @@ -126,7 +133,7 @@ if ( !empty($_REQUEST['eid']) ) { } if ( !empty($_REQUEST['generated']) ) { ?> - + From 02f09aad7f4ff50f1dd113c964f10d8e675da916 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:01:26 -0800 Subject: [PATCH 08/35] view=export: Remove inline event handlers and fix arbitrary URL/XSS usage. Fixes #2443 --- web/ajax/event.php | 2 +- web/includes/functions.php | 1 + web/skins/classic/views/export.php | 11 +++++++++-- web/skins/classic/views/js/export.js | 5 ++++- web/skins/classic/views/js/export.js.php | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 9d8a85438..4eed2e832 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -71,7 +71,7 @@ if ( canView( 'Events' ) ) { $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; if ( $exportFile = exportEvents( $exportIds, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat ) ) - ajaxResponse( array( 'exportFile'=>$exportFile ) ); + ajaxResponse( array( 'exportFormat'=>$exportFormat ) ); else ajaxError( 'Export Failed' ); break; diff --git a/web/includes/functions.php b/web/includes/functions.php index 2a024fe5a..4aea38a60 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -55,6 +55,7 @@ function CSPHeaders($view, $nonce) { case 'donate': case 'download': case 'error': + case 'export': case 'function': case 'log': case 'logout': diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 0565f6231..d1b5d0413 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -38,6 +38,13 @@ if ( isset($_SESSION['export']) ) { $_REQUEST['exportFormat'] = $_SESSION['export']['format']; } +if (isset($_REQUEST['exportFormat'])) { + if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { + Error('Invalid exportFormat'); + return; + } +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Export') ); @@ -97,7 +104,7 @@ if ( !empty($_REQUEST['eid']) ) { - + - + diff --git a/web/skins/classic/views/js/export.js b/web/skins/classic/views/js/export.js index 899256b34..df15a2ef6 100644 --- a/web/skins/classic/views/js/export.js +++ b/web/skins/classic/views/js/export.js @@ -29,7 +29,7 @@ function exportProgress() { } function exportResponse( respObj, respText ) { - window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) ); + window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFormat='+respObj.exportFormat+'&generated='+((respObj.result=='Ok')?1:0) ); } function exportEvent( form ) { @@ -49,6 +49,9 @@ function initPage() { if ( exportReady ) { startDownload.pass( exportFile ).delay( 1500 ); } + document.getElementById('exportButton').addEventListener('click', function onClick() { + exportEvent(this.form); + }); } window.addEventListener( 'DOMContentLoaded', initPage ); diff --git a/web/skins/classic/views/js/export.js.php b/web/skins/classic/views/js/export.js.php index fd9d64dc5..26abb64cf 100644 --- a/web/skins/classic/views/js/export.js.php +++ b/web/skins/classic/views/js/export.js.php @@ -14,6 +14,6 @@ var eidParm = 'eid='; ?> var exportReady = ; -var exportFile = ''; +var exportFile = '?view=archive&type='; var exportProgressString = ''; From 98e0a0d2c56a06d3d82ca9cf4578865a821d9baf Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:16:37 -0800 Subject: [PATCH 09/35] Don't output Fatal(...) error messages unless debugging is on to avoid leaking info. Fixes #2459 --- web/includes/logger.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/includes/logger.php b/web/includes/logger.php index 8bc81fb97..b3048bc1a 100644 --- a/web/includes/logger.php +++ b/web/includes/logger.php @@ -455,7 +455,10 @@ function Error( $string ) { function Fatal( $string ) { Logger::fetch()->logPrint( Logger::FATAL, $string ); - die( htmlentities($string) ); + if (Logger::fetch()->debugOn()) { + echo(htmlentities($string)); + } + exit(1); } function Panic( $string ) { From fa6716a64b7481677b0d8d73d460200e60429410 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:28:40 -0800 Subject: [PATCH 10/35] console: Escape source column output to prevent XSS. Fixes #2452 --- web/skins/classic/views/console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index aa909700e..6270b60ac 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -308,7 +308,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { Name(); ?> '. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.$Monitor->Source().'', canEdit('Monitors') ).''; + echo ''. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.validHtmlStr($Monitor->Source()).'', canEdit('Monitors') ).''; if ( $show_storage_areas ) { ?> Name(); } ?> From 7b0ee8a6a22576b66c341ee6f09668852769cbb6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 14:05:50 -0800 Subject: [PATCH 11/35] group: Escape group name in heading. Fixes #2454 --- web/skins/classic/views/group.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index 9ccbd112c..eafb4683c 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -34,7 +34,7 @@ xhtmlHeaders(__FILE__, translate('Group').' - '.$newGroup->Name());
From c8066919ff159a121436862781eb7d1aaa81fb01 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 14:14:46 -0800 Subject: [PATCH 12/35] functions.php: Esacepe textContent in htmlOptions() --- web/includes/functions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 4aea38a60..a3723c635 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -496,7 +496,6 @@ function makePopupButton( $url, $winName, $winSize, $buttonValue, $condition=1, } function htmlSelect( $name, $contents, $values, $behaviours=false ) { - $behaviourText = ''; if ( !empty($behaviours) ) { if ( is_array($behaviours) ) { @@ -537,7 +536,7 @@ function htmlOptions($contents, $values) { $options_html .= ""; + ">".htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).""; } return $options_html; } From b2a97ee190c6dc3e30b9c36b9c33c33348dde4d6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:10:42 -0800 Subject: [PATCH 13/35] frame.php: Fix multiple XSS from 'show' and 'scale' parameters and enforce CSP. Fixes #2448, fixes #2449, and fixes #2447. --- web/includes/functions.php | 1 + web/skins/classic/css/base/views/frame.css | 5 ---- web/skins/classic/css/classic/views/frame.css | 5 ---- web/skins/classic/css/dark/views/frame.css | 5 ---- web/skins/classic/views/frame.php | 23 ++++++++++--------- web/skins/classic/views/js/frame.js | 8 ++++++- web/skins/classic/views/js/frame.js.php | 2 +- 7 files changed, 21 insertions(+), 28 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index a3723c635..85e3b022c 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -56,6 +56,7 @@ function CSPHeaders($view, $nonce) { case 'download': case 'error': case 'export': + case 'frame': case 'function': case 'log': case 'logout': diff --git a/web/skins/classic/css/base/views/frame.css b/web/skins/classic/css/base/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/base/views/frame.css +++ b/web/skins/classic/css/base/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/css/classic/views/frame.css b/web/skins/classic/css/classic/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/classic/views/frame.css +++ b/web/skins/classic/css/classic/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/css/dark/views/frame.css b/web/skins/classic/css/dark/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/dark/views/frame.css +++ b/web/skins/classic/css/dark/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index 931951056..ae69fecba 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -51,14 +51,15 @@ $lastFid = $maxFid; $alarmFrame = $Frame->Type()=='Alarm'; if ( isset( $_REQUEST['scale'] ) ) { - $scale = $_REQUEST['scale']; + $scale = validNum($_REQUEST['scale']); } else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) { - $scale = $_COOKIE['zmWatchScale'.$Monitor->Id()]; + $scale = validNum($_COOKIE['zmWatchScale'.$Monitor->Id()]); } else if ( isset( $_COOKIE['zmWatchScale'] ) ) { - $scale = $_COOKIE['zmWatchScale']; + $scale = validNum($_COOKIE['zmWatchScale']); } else { $scale = max( reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); } +$scale = $scale ?: "auto"; $imageData = $Event->getImageSrc( $frame, $scale, 0 ); if ( ! $imageData ) { @@ -67,7 +68,7 @@ if ( ! $imageData ) { } $show = 'capt'; -if ( isset($_REQUEST['show']) ) { +if (isset($_REQUEST['show']) && in_array($_REQUEST['show'], array('capt', 'anal'))) { $show = $_REQUEST['show']; } else if ( $imageData['hasAnalImage'] ) { $show = 'anal'; @@ -89,9 +90,9 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id()." - ".$Frame->Frame
Id().'&fid='.$Frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?> - +
-
+

Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?>

@@ -103,19 +104,19 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id()." - ".$Frame->Frame ', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) ); } ?> -<?php echo $Frame->EventId().FrameId() ?>" class=""/> +<?php echo $Frame->EventId().FrameId() ?>" class=""/>

FrameId() > 1 ) { ?> - - + + FrameId() < $maxFid ) { ?> - - + +

diff --git a/web/skins/classic/views/js/frame.js b/web/skins/classic/views/js/frame.js index e0401c7c7..03058ff8a 100644 --- a/web/skins/classic/views/js/frame.js +++ b/web/skins/classic/views/js/frame.js @@ -30,4 +30,10 @@ function changeScale() { }); } -if (scale == 'auto') $j(document).ready(changeScale); +if (scale == 'auto') { + $j(document).ready(changeScale); +} + +document.addEventListener('DOMContentLoaded', function onDCL() { + document.getElementById('scale').addEventListener('change', changeScale); +}); diff --git a/web/skins/classic/views/js/frame.js.php b/web/skins/classic/views/js/frame.js.php index c9b3f2eea..572587f82 100644 --- a/web/skins/classic/views/js/frame.js.php +++ b/web/skins/classic/views/js/frame.js.php @@ -1,3 +1,3 @@ -var scale = ''; +var scale = ''; var SCALE_BASE = ; From 70e59ed546474bf18b9af2040d0ed732dce835bc Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:19:15 -0800 Subject: [PATCH 14/35] filter.php: Escape the filter name on output. Fixes #2455 --- web/skins/classic/views/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index fab68941c..b74c4fd58 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -188,7 +188,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )

- +

From dd37808ef790a77100845c2c3c3bb28d9038950f Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:24:13 -0800 Subject: [PATCH 15/35] filter.php: Escape AutoExecuteCmd before output to prevent XSS. Fixes #2461 --- web/skins/classic/views/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index b74c4fd58..53b7f588c 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -385,7 +385,7 @@ if ( ZM_OPT_MESSAGE ) {

AutoExecute() ) { ?> checked="checked"/> - +

From bb75dad091bfa35af49467fede06adb972ed0545 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:35:55 -0800 Subject: [PATCH 16/35] filter.php: Escape filter query term value to avoid XSS. Fixes #2462 --- web/skins/classic/views/filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 53b7f588c..cba9ad3e3 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -281,13 +281,13 @@ for ( $i=0; $i < count($terms); $i++ ) { } else { ?>

- + - + From 254b7286b4d2654b95080a175c44195667e42ea8 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 16:41:54 -0800 Subject: [PATCH 17/35] monitor.php: Escape SignalCheckColour to prevent XSS. Fixes #2451 --- web/includes/Monitor.php | 14 ++++++++++++++ web/skins/classic/views/monitor.php | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index cc1d8eed7..538793ffb 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -331,6 +331,20 @@ private $control_fields = array( return $this->defaults{$field}; } // end function Height + public function SignalCheckColour($new=null) { + $field = 'SignalCheckColour'; + if ($new) { + $this->{$field} = $new; + } + + // Validate that it's a valid colour (we seem to allow color names, not just hex). + // This also helps prevent XSS. + if (array_key_exists($field, $this) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) { + return $this->{$field}; + } + return $this->defaults{$field}; + } // end function SignalCheckColour + public function set($data) { foreach ($data as $k => $v) { if ( method_exists($this, $k) ) { diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 59e4ca04f..df78bbda9 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -1021,7 +1021,7 @@ if ( $monitor->Type() == 'Local' ) { From cef54feaf9bf1374f0404bf525cdd322300882b5 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 16:54:06 -0800 Subject: [PATCH 18/35] monitor.php: Escape a bug of output variables. Fixes #2465 --- web/skins/classic/views/monitor.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index df78bbda9..254adcdfa 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -462,7 +462,7 @@ if ( canEdit( 'Monitors' ) ) { if ( isset ($_REQUEST['dupId'])) { ?>
- Configuration cloned from Monitor: + Configuration cloned from Monitor:
Id() || ($monitor->Id()!= $linked_monitor['Id'])) && visibleMonitor( $linked_monitor['Id'] ) ) { ?> - + GroupIds() ); V4LMultiBuffer() ? 'checked="checked"' : '' ) ?>/>
- + Type() == 'NVSocket' ) { @@ -873,7 +873,7 @@ include('_monitor_source_nvsocket.php'); - + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> @@ -897,11 +897,11 @@ if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) { } if ( $monitor->Type() == 'Local' ) { ?> - + Type() != 'WebSite' ) { ?> - + @@ -915,7 +915,7 @@ if ( $monitor->Type() == 'Local' ) { } case 'storage' : ?> - + - + Date: Sat, 9 Feb 2019 17:01:45 -0800 Subject: [PATCH 19/35] monitor.php: Escape monitor method. Fixes #2464 --- web/skins/classic/views/monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 254adcdfa..0b8d78a8e 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -523,7 +523,7 @@ foreach ( $tabs as $name=>$value ) { - + From ef0e5f453a4e60a5bdd6bc347e517a87182b6cad Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:11:53 -0800 Subject: [PATCH 20/35] monitor.php: Fix XSS from LinkedMonitors. Fixes #2463 --- web/skins/classic/views/monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 0b8d78a8e..7a5665631 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -522,7 +522,7 @@ foreach ( $tabs as $name=>$value ) { - + Date: Sat, 9 Feb 2019 17:15:02 -0800 Subject: [PATCH 21/35] functions.php: Fix SQLi in getFormChanges --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 85e3b022c..fab696ae7 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -612,7 +612,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { { if ( is_array($newValues[$key]) ) { if ( (!isset($values[$key])) or ( join(',',$newValues[$key]) != $values[$key] ) ) { - $changes[$key] = "`$key` = ".dbEscape(join(',',$newValues[$key])); + $changes[$key] = "`$key` = '".dbEscape(join(',',$newValues[$key]))."'"; } } else if ( (!isset($values[$key])) or $values[$key] ) { $changes[$key] = "`$key` = ''"; From fcbc22b6a27b2375327327c3d75995fe6a3cafd9 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:27:47 -0800 Subject: [PATCH 22/35] functions.php: Ensure 'limit' request parameter is an integer. Fixes #2456 --- web/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index fab696ae7..e4da8d150 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1085,7 +1085,7 @@ function parseSort( $saveToSession=false, $querySep='&' ) { $_SESSION['sort_asc'] = validHtmlStr($_REQUEST['sort_asc']); } if ($_REQUEST['limit'] != '') { - $limitQuery = "&limit=".$_REQUEST['limit']; + $limitQuery = "&limit=".validInt($_REQUEST['limit']); } } @@ -1426,7 +1426,7 @@ function getPagination( $pages, $page, $maxShortcuts, $query, $querySep='&' function sortHeader( $field, $querySep='&' ) { global $view; - return( '?view='.$view.$querySep.'page=1'.$_REQUEST['filter']['query'].$querySep.'sort_field='.$field.$querySep.'sort_asc='.($_REQUEST['sort_field'] == $field?!$_REQUEST['sort_asc']:0).$querySep.'limit='.$_REQUEST['limit'] ); + return '?view='.$view.$querySep.'page=1'.$_REQUEST['filter']['query'].$querySep.'sort_field='.$field.$querySep.'sort_asc='.($_REQUEST['sort_field'] == $field?!$_REQUEST['sort_asc']:0).$querySep.'limit='.validInt($_REQUEST['limit']); } function sortTag( $field ) { From 6d2f3c265f6154181a4452bdefdd990b4f0b22b6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:34:59 -0800 Subject: [PATCH 23/35] events.php: Remove inline event handlers and enforce CSP --- web/includes/functions.php | 1 + web/skins/classic/views/events.php | 4 ++-- web/skins/classic/views/js/events.js | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e4da8d150..891e986ff 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -55,6 +55,7 @@ function CSPHeaders($view, $nonce) { case 'donate': case 'download': case 'error': + case 'events': case 'export': case 'frame': case 'function': diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 3beff0188..0526dc8c2 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -100,7 +100,7 @@ xhtmlHeaders(__FILE__, translate('Events') ); diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index b594faa20..831490f78 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -169,6 +169,14 @@ function initPage() { $j('input[name=markEids\\[\\]]').each(function() { this.addEventListener('click', configureButton, false); }); + document.getElementById("refreshLink").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + document.getElementById("backLink").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); } $j(document).ready(initPage); From 9ce05a9a09de47868398a09e6c5259645b9ee73e Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:45:52 -0800 Subject: [PATCH 24/35] user.php: Escape the Username upon display. Fixes #2467 --- web/skins/classic/views/user.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/skins/classic/views/user.php b/web/skins/classic/views/user.php index 95ed639a5..b85d73483 100644 --- a/web/skins/classic/views/user.php +++ b/web/skins/classic/views/user.php @@ -58,14 +58,14 @@ xhtmlHeaders(__FILE__, translate('User').' - '.$newUser['Username']);
- +
-      +     
()
()
Type() == 'Local' ) {
- + - + - + From 6af2c4ad0e288fae5702e96391657d173bba2297 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 18:06:21 -0800 Subject: [PATCH 25/35] Escape output of WEB_TITLE, HOME_URL, HOME_CONTENT, & WEB_CONSOLE_BANNER. Fixes #2468 --- web/skins/classic/includes/functions.php | 8 ++++---- web/skins/classic/views/login.php | 2 +- web/skins/classic/views/logout.php | 2 +- web/skins/classic/views/none.php | 2 +- web/skins/classic/views/postlogin.php | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 703cd49d3..063977942 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -57,7 +57,7 @@ function xhtmlHeaders( $file, $title ) { - <?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?> + <?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> - <?php echo validHtmlStr($title) ?> @@ -254,7 +254,7 @@ function getNavBarHTML($reload = null) { - + -

account_circle

+

account_circle

diff --git a/web/skins/classic/views/logout.php b/web/skins/classic/views/logout.php index 772bacd80..1b38d812f 100644 --- a/web/skins/classic/views/logout.php +++ b/web/skins/classic/views/logout.php @@ -25,7 +25,7 @@ xhtmlHeaders(__FILE__, translate('Logout') );
diff --git a/web/skins/classic/views/none.php b/web/skins/classic/views/none.php index da04ed19b..1213b44d5 100644 --- a/web/skins/classic/views/none.php +++ b/web/skins/classic/views/none.php @@ -25,7 +25,7 @@ $skinJsFile = getSkinFile('js/skin.js'); - <?php echo ZM_WEB_TITLE_PREFIX ?> + <?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> "; + echo ""; } # end if tab == skins ?> @@ -95,7 +99,7 @@ foreach ( $tabs as $name=>$value ) { - +
@@ -132,7 +136,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI - + @@ -199,7 +203,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI -
+ @@ -264,7 +268,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI -
+ @@ -328,7 +332,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI $configCats[$tab]['ZM_BANDWIDTH_DEFAULT']['Hint'] = $bandwidth_options; } ?> - + diff --git a/web/skins/classic/views/plugin.php b/web/skins/classic/views/plugin.php index 4f3b4ccf2..ea7a9f347 100644 --- a/web/skins/classic/views/plugin.php +++ b/web/skins/classic/views/plugin.php @@ -107,7 +107,7 @@ function pLang($name)

- -

- + diff --git a/web/skins/classic/views/privacy.php b/web/skins/classic/views/privacy.php index 9bd283b4a..21c0bdb59 100644 --- a/web/skins/classic/views/privacy.php +++ b/web/skins/classic/views/privacy.php @@ -40,7 +40,7 @@ xhtmlHeaders(__FILE__, translate('Privacy') );

ZoneMinder -

- +
diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 5a3b5e5b6..70808138e 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -113,7 +113,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { ?> - + @@ -205,7 +205,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $Group = new Group($group_id); $Groups = $Group->Parents(); array_push($Groups, $Group); - return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); + return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); }, $Monitor->GroupIds() ) ); ?>
diff --git a/web/skins/classic/views/server.php b/web/skins/classic/views/server.php index 64508995d..0c028b8c1 100644 --- a/web/skins/classic/views/server.php +++ b/web/skins/classic/views/server.php @@ -39,7 +39,7 @@ xhtmlHeaders(__FILE__, translate('Server').' - '.$Server->Name());

Name() ?>

- + diff --git a/web/skins/classic/views/settings.php b/web/skins/classic/views/settings.php index 2ed9e7c5d..1946642b6 100644 --- a/web/skins/classic/views/settings.php +++ b/web/skins/classic/views/settings.php @@ -44,7 +44,7 @@ xhtmlHeaders(__FILE__, validHtmlStr($monitor['Name'])." - ".translate('Settings'

-

- + diff --git a/web/skins/classic/views/state.php b/web/skins/classic/views/state.php index cb8e5403a..dead5ebf5 100644 --- a/web/skins/classic/views/state.php +++ b/web/skins/classic/views/state.php @@ -24,7 +24,7 @@ if ( !canEdit('System') ) { } ?>
diff --git a/web/skins/classic/views/storage.php b/web/skins/classic/views/storage.php index 7ec3a63cf..8da0ba5b5 100644 --- a/web/skins/classic/views/storage.php +++ b/web/skins/classic/views/storage.php @@ -63,7 +63,7 @@ xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );

- + diff --git a/web/skins/classic/views/user.php b/web/skins/classic/views/user.php index b85d73483..931e58321 100644 --- a/web/skins/classic/views/user.php +++ b/web/skins/classic/views/user.php @@ -61,7 +61,7 @@ xhtmlHeaders(__FILE__, translate('User').' - '.$newUser['Username']);

- + diff --git a/web/skins/classic/views/version.php b/web/skins/classic/views/version.php index a7562f355..3ced8c613 100644 --- a/web/skins/classic/views/version.php +++ b/web/skins/classic/views/version.php @@ -63,7 +63,7 @@ if ( ZM_DYN_DB_VERSION && (ZM_DYN_DB_VERSION != ZM_VERSION) ) { - +

diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index 85a8abb6c..aab9278d6 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -123,7 +123,7 @@ if ( isset($_REQUEST['showIndex']) ) { - +
diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index 4a172083f..66f379e90 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -122,7 +122,7 @@ xhtmlHeaders(__FILE__, translate('Zone') );

Name() ?> -

- + diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index c66ffd000..7a176acc7 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -52,7 +52,7 @@ xhtmlHeaders(__FILE__, translate('Zones') );

- + From a97711de89d808edcec1b422b5c97645dbd9f501 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:12:36 -0800 Subject: [PATCH 31/35] Replace or sanitize remaining uses of PHP_SELF. Fixes #2446 --- web/includes/Frame.php | 5 ++--- web/includes/Server.php | 3 ++- web/includes/actions/groups.php | 2 +- web/includes/actions/login.php | 2 +- web/includes/actions/montage.php | 2 +- web/includes/actions/options.php | 2 +- web/includes/actions/privacy.php | 4 ++-- web/includes/functions.php | 4 ++-- web/skins/classic/js/skin.js.php | 6 +++++- 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/web/includes/Frame.php b/web/includes/Frame.php index 74a18ef59..d4c2a4dee 100644 --- a/web/includes/Frame.php +++ b/web/includes/Frame.php @@ -50,9 +50,8 @@ class Frame { } public function getImageSrc( $show='capture' ) { - - return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'FrameId'}.'&eid='.$this->{'EventId'}.'&show='.$show; - #return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg'; + return '?view=image&fid='.$this->{'FrameId'}.'&eid='.$this->{'EventId'}.'&show='.$show; + #return '?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg'; } // end function getImageSrc public static function find( $parameters = array(), $options = NULL ) { diff --git a/web/includes/Server.php b/web/includes/Server.php index 65721214d..ea633c4be 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -117,7 +117,8 @@ class Server { if ( isset($this->{'PathToIndex'}) and $this->{'PathToIndex'} ) { return $this->{'PathToIndex'}; } - return $_SERVER['PHP_SELF']; + // We can't trust PHP_SELF to not include an XSS vector. See note in skin.js.php. + return preg_replace('/\.php.*$/i', '.php', $_SERVER['PHP_SELF']); } public function UrlToIndex( $port=null ) { diff --git a/web/includes/actions/groups.php b/web/includes/actions/groups.php index 200f65f99..22d138240 100644 --- a/web/includes/actions/groups.php +++ b/web/includes/actions/groups.php @@ -43,7 +43,7 @@ if ( $action == 'delete' ) { $Group->delete(); } } - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=groups'; + $redirect = '?view=groups'; $refreshParent = true; } # end if action ?> diff --git a/web/includes/actions/login.php b/web/includes/actions/login.php index b497b29f5..5e35987c8 100644 --- a/web/includes/actions/login.php +++ b/web/includes/actions/login.php @@ -29,7 +29,7 @@ if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 're $view = 'login'; } else { $view = 'postlogin'; - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; } } ?> diff --git a/web/includes/actions/montage.php b/web/includes/actions/montage.php index 7182ba2dc..3040fd83a 100644 --- a/web/includes/actions/montage.php +++ b/web/includes/actions/montage.php @@ -40,7 +40,7 @@ if ( isset($_REQUEST['object']) ) { $_SESSION['zmMontageLayout'] = $Layout->Id(); setcookie('zmMontageLayout', $Layout->Id(), 1); session_write_close(); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=montage'; + $redirect = '?view=montage'; } // end if save } # end if isset($_REQUEST['object'] ) diff --git a/web/includes/actions/options.php b/web/includes/actions/options.php index 263a592f8..d7853ec9e 100644 --- a/web/includes/actions/options.php +++ b/web/includes/actions/options.php @@ -89,7 +89,7 @@ if ( $action == 'delete' ) { case 'lowband' : break; } - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=options&tab='.$_REQUEST['tab']; + $redirect = '?view=options&tab='.$_REQUEST['tab']; } loadConfig(false); return; diff --git a/web/includes/actions/privacy.php b/web/includes/actions/privacy.php index 19c4061ea..99bbd7150 100644 --- a/web/includes/actions/privacy.php +++ b/web/includes/actions/privacy.php @@ -28,12 +28,12 @@ if ( ($action == 'privacy') && isset($_REQUEST['option']) ) { case 'decline' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_TELEMETRY_DATA'"); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; break; case 'accept' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '1' WHERE Name = 'ZM_TELEMETRY_DATA'"); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; break; default: # Enable the privacy statement if we somehow submit something other than accept or decline dbQuery("UPDATE Config SET Value = '1' WHERE Name = 'ZM_SHOW_PRIVACY'"); diff --git a/web/includes/functions.php b/web/includes/functions.php index cbb54f1c9..f0e087d48 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -294,7 +294,7 @@ function getImageStreamHTML( $id, $src, $width, $height, $title='' ) { function outputControlStream( $src, $width, $height, $monitor, $scale, $target ) { ?> - + @@ -364,7 +364,7 @@ function getWebSiteUrl( $id, $src, $width, $height, $title='' ) { function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) { ?> - + diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index 1d0cfd61c..a9f6b85af 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -29,7 +29,11 @@ var AJAX_TIMEOUT = ; var navBarRefresh = ; var currentView = ''; -var thisUrl = ''; + +var thisUrl = ''; var skinPath = ''; var serverId = ''; From dbc1c7b72f8cab5094a4a498a66ca2c0d3f29872 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:39:54 -0800 Subject: [PATCH 32/35] Only output the CSRF Try Again button (and add a warning) when ZM_LOG_DEBUG is on. Fixes #2469 --- web/includes/csrf/csrf-magic.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php index 692015e70..576a8ef2a 100644 --- a/web/includes/csrf/csrf-magic.php +++ b/web/includes/csrf/csrf-magic.php @@ -288,9 +288,13 @@ function csrf_callback($tokens) { echo "CSRF check failed

CSRF check failed. Your form session may have expired, or you may not have - cookies enabled.

- $data -

Debug: $tokens

+ cookies enabled.

"; + if (ZM_LOG_DEBUG) { + // Don't make it too easy for users to inflict a CSRF attach on themselves. + echo "

Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.

"; + echo "
$data"; + } + echo "

Debug: $tokens

"; } From a6ee79f428ee8b99b23906a563256050a41e3663 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:40:39 -0800 Subject: [PATCH 33/35] Fix typo in dbc1c7b72f8cab5094a4a498a66ca2c0d3f29872 comment --- web/includes/csrf/csrf-magic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php index 576a8ef2a..584432ef7 100644 --- a/web/includes/csrf/csrf-magic.php +++ b/web/includes/csrf/csrf-magic.php @@ -290,7 +290,7 @@ function csrf_callback($tokens) {

CSRF check failed. Your form session may have expired, or you may not have cookies enabled.

"; if (ZM_LOG_DEBUG) { - // Don't make it too easy for users to inflict a CSRF attach on themselves. + // Don't make it too easy for users to inflict a CSRF attack on themselves. echo "

Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.

"; echo "
$data"; } From c8e41bfee75cb0a70e69d8f1488aa948fc31831a Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 00:10:39 -0800 Subject: [PATCH 34/35] log.php: Ensure 'line' is an integer. Helps with #2466 --- web/ajax/log.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index 282303a87..2a5aa039e 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -15,7 +15,7 @@ switch ( $_REQUEST['task'] ) { $file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/[\w.:]+\//', '', $_POST['file'] ) : ''; if ( !empty( $_POST['line'] ) ) - $line = $_POST['line']; + $line = validInt($_POST['line']); else $line = NULL; From c9032d3cb41d3aef0fd21dc0bd47302816788c66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Feb 2019 11:53:57 -0500 Subject: [PATCH 35/35] add autocomplete tags to username and password inputs --- web/skins/classic/views/login.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/login.php b/web/skins/classic/views/login.php index 75e8479c3..c75c9b602 100644 --- a/web/skins/classic/views/login.php +++ b/web/skins/classic/views/login.php @@ -19,10 +19,10 @@ xhtmlHeaders(__FILE__, translate('Login') );

account_circle

- + - +