From 2e3c5b09ec6e01a842b1d2858155b7dd27709d0a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 9 Sep 2022 21:59:14 -0400 Subject: [PATCH 1/4] Add Janus_RTSP_USer to Monitors --- db/zm_create.sql.in | 1 + db/zm_update-1.37.22.sql | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 db/zm_update-1.37.22.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index b648e5c54..86439feca 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -467,6 +467,7 @@ CREATE TABLE `Monitors` ( `JanusAudioEnabled` BOOLEAN NOT NULL default false, `Janus_Profile_Override` VARCHAR(30) NOT NULL DEFAULT '', `Janus_Use_RTSP_Restream` BOOLEAN NOT NULL default false, + `Janus_RTSP_User` INT(10), `LinkedMonitors` varchar(255), `Triggers` set('X10') NOT NULL default '', `EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '', diff --git a/db/zm_update-1.37.22.sql b/db/zm_update-1.37.22.sql new file mode 100644 index 000000000..0a1c457dc --- /dev/null +++ b/db/zm_update-1.37.22.sql @@ -0,0 +1,18 @@ +-- +-- Update Monitors table to have a MQTT_Enabled Column +-- + +SELECT 'Checking for `Janus_RTSP_User` in Monitors'; +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Monitors' + AND table_schema = DATABASE() + AND column_name = 'Janus_RTSP_User' + ) > 0, +"SELECT 'Column Janus_RTSP_User already exists in Monitors'", +"ALTER TABLE Monitors ADD COLUMN `Janus_RTSP_User` INT(10) AFTER `Janus_Use_RTSP_Restream`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; From a04cd54c577674a42bee31d3b85bf6072bd2bf28 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 9 Sep 2022 21:59:32 -0400 Subject: [PATCH 2/4] Add Janus_RTSP_User loading --- src/zm_monitor.cpp | 6 ++++-- src/zm_monitor.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 106dce871..a1ac2f17c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -82,7 +82,7 @@ struct Namespace namespaces[] = std::string load_monitor_sql = "SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Capturing`+0, `Analysing`+0, `AnalysisSource`+0, `AnalysisImage`+0," "`Recording`+0, `RecordingSource`+0, `Decoding`+0, " -"`JanusEnabled`, `JanusAudioEnabled`, `Janus_Profile_Override`, `Janus_Use_RTSP_Restream`," +"`JanusEnabled`, `JanusAudioEnabled`, `Janus_Profile_Override`, `Janus_Use_RTSP_Restream`, `Janus_RTSP_User`, " "`LinkedMonitors`, `EventStartCommand`, `EventEndCommand`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`," "`Device`, `Channel`, `Format`, `V4LMultiBuffer`, `V4LCapturesPerFrame`, " // V4L Settings "`Protocol`, `Method`, `Options`, `User`, `Pass`, `Host`, `Port`, `Path`, `SecondPath`, `Width`, `Height`, `Colours`, `Palette`, `Orientation`+0, `Deinterlacing`, " @@ -171,6 +171,7 @@ Monitor::Monitor() janus_audio_enabled(false), janus_profile_override(""), janus_use_rtsp_restream(false), + janus_rtsp_user(0), //protocol //method //options @@ -323,7 +324,7 @@ Monitor::Monitor() /* std::string load_monitor_sql = "SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Capturing`+0, `Analysing`+0, `AnalysisSource`+0, `AnalysisImage`+0," - "`Recording`+0, `RecordingSource`+0, `Decoding`+0, JanusEnabled, JanusAudioEnabled, Janus_Profile_Override, Janus_Use_RTSP_Restream" + "`Recording`+0, `RecordingSource`+0, `Decoding`+0, JanusEnabled, JanusAudioEnabled, Janus_Profile_Override, Janus_Use_RTSP_Restream, Janus_RTSP_User, " "LinkedMonitors, `EventStartCommand`, `EventEndCommand`, " "AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS," "Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings @@ -386,6 +387,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { janus_audio_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++; janus_profile_override = std::string(dbrow[col] ? dbrow[col] : ""); col++; janus_use_rtsp_restream = dbrow[col] ? atoi(dbrow[col]) : false; col++; + janus_rtsp_user = dbrow[col] ? atoi(dbrow[col]) : 0; col++; linked_monitors_string = dbrow[col] ? dbrow[col] : ""; col++; event_start_command = dbrow[col] ? dbrow[col] : ""; col++; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 038597ad0..b517eb50e 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -377,6 +377,7 @@ protected: bool janus_audio_enabled; // Whether we tell Janus to try to include audio. std::string janus_profile_override; // The Profile-ID to force the stream to use. bool janus_use_rtsp_restream; // Point Janus at the ZM RTSP output, rather than the camera directly. + int janus_rtsp_user; // User Id of a user to use for auth to RTSP_Server std::string protocol; std::string method; From 01fa423ba497d825110e558c6df99b46007fd4f4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 9 Sep 2022 22:01:10 -0400 Subject: [PATCH 3/4] When using RTSP_Server restream, need to auth as a ZM user. So load user and create an auth token. --- src/zm_monitor_janus.cpp | 44 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/zm_monitor_janus.cpp b/src/zm_monitor_janus.cpp index 630455259..0f89f2f41 100644 --- a/src/zm_monitor_janus.cpp +++ b/src/zm_monitor_janus.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // +#include "zm_crypt.h" #include "zm_monitor.h" #include @@ -40,16 +41,51 @@ Monitor::JanusManager::JanusManager(Monitor *parent_) : rtsp_username = ""; rtsp_password = ""; - if( parent->user.length() > 0 ) { - rtsp_username = escape_json_string(parent->user); - rtsp_password = escape_json_string(parent->pass); - } if (Use_RTSP_Restream) { int restream_port = config.min_rtsp_port; rtsp_path = "rtsp://127.0.0.1:" + std::to_string(restream_port) + "/" + parent->rtsp_streamname; + if (ZM_OPT_USE_AUTH) { + SystemTimePoint now = std::chrono::system_clock::now(); + time_t now_t = std::chrono::system_clock::to_time_t(now); + tm now_tm = {}; + localtime_r(&now_t, &now_tm); + if (parent->janus_rtsp_user) { + std::string sql = "SELECT `Id`, `Username`, `Password`, `Enabled`," + " `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0," + " `MonitorIds` FROM `Users` WHERE `Enabled`=1 AND `Id`=" + std::to_string(parent->janus_rtsp_user); + + MYSQL_RES *result = zmDbFetch(sql); + if (result) { + MYSQL_ROW dbrow = mysql_fetch_row(result); + const char *username = dbrow[1]; + const char *password = dbrow[2]; + + std::string auth_key = stringtf("%s%s%s%s%d%d%d%d", + config.auth_hash_secret, + username, + password, + (config.auth_hash_ips ? "127.0.0.1" : ""), + now_tm.tm_hour, + now_tm.tm_mday, + now_tm.tm_mon, + now_tm.tm_year); + Debug(1, "Creating auth_key '%s'", auth_key.c_str()); + + zm::crypto::MD5::Digest md5_digest = zm::crypto::MD5::GetDigestOf(auth_key); + mysql_free_result(result); + rtsp_path += "?auth=" + ByteArrayToHexString(md5_digest); + } else { + Warning("No user selected for RTSP_Server authentication!"); + } + } + } } else { rtsp_path = parent->path; + if (parent->user.length() > 0) { + rtsp_username = escape_json_string(parent->user); + rtsp_password = escape_json_string(parent->pass); + } } } From 7935cbc391566d7564bf104a68985ea8bbf3577c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 9 Sep 2022 22:01:29 -0400 Subject: [PATCH 4/4] Add Janus_RTSP_User and related UI code --- web/includes/Monitor.php | 1 + web/skins/classic/views/js/monitor.js | 24 ++++++++++++++++++++++++ web/skins/classic/views/monitor.php | 14 ++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 17ca28cd2..d9ee7d890 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -148,6 +148,7 @@ public static function getStatuses() { 'JanusAudioEnabled' => array('type'=>'boolean','default'=>0), 'Janus_Profile_Override' => '', 'Janus_Use_RTSP_Restream' => array('type'=>'boolean','default'=>0), + 'Janus_RTSP_User' => null, 'LinkedMonitors' => array('type'=>'set', 'default'=>null), 'Triggers' => array('type'=>'set','default'=>''), 'EventStartCommand' => '', diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index 2cf1c464c..cb07b4fb7 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -72,6 +72,21 @@ function loadLocations( element ) { } } +function Janus_Use_RTSP_Restream_onclick(e) { + console.log("hello"); + Janus_Use_RTSP_Restream = $j('[name="newMonitor[Janus_Use_RTSP_Restream]"]'); + if (Janus_Use_RTSP_Restream.length) { + const Janus_RTSP_User = $j('#Janus_RTSP_User'); + if (Janus_Use_RTSP_Restream[0].checked) { + Janus_RTSP_User.show(); + } else { + Janus_RTSP_User.hide(); + } + } else { + console.log("DIdn't find newMonitor[Janus_Use_RTSP_Restream]"); + } +} + function initPage() { var backBtn = $j('#backBtn'); var onvifBtn = $j('#onvifBtn'); @@ -285,6 +300,14 @@ function initPage() { } }); + const Janus_Use_RTSP_Restream = document.getElementsByName('newMonitor[Janus_Use_RTSP_Restream]'); + if (Janus_Use_RTSP_Restream.length) { + Janus_Use_RTSP_Restream[0].onclick = Janus_Use_RTSP_Restream_onclick; + console.log("Setup Janus_RTSP_Restream.onclick"); + } else { + console.log("newMonitor[Janus_Use_RTSP_Restream] not found"); + } + // Amcrest API controller if (document.getElementsByName("newMonitor[ONVIF_Event_Listener]")[0].checked) { document.getElementById("function_use_Amcrest_API").hidden = false; @@ -469,6 +492,7 @@ function updateLatitudeAndLongitude(latitude, longitude) { map.invalidateSize(true); }, 100); } + function getLocation() { if ('geolocation' in navigator) { navigator.geolocation.getCurrentPosition((position) => { diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index be21e0b5f..cb43dafcb 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -20,6 +20,7 @@ require_once('includes/Server.php'); require_once('includes/Storage.php'); +require_once('includes/User.php'); require_once('includes/Zone.php'); if (!canEdit('Monitors', empty($_REQUEST['mid'])?0:$_REQUEST['mid'])) { @@ -1237,6 +1238,19 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor if ( isset($OLANG['FUNCTION_JANUS_USE_RTSP_RESTREAM']) ) { echo '
'.$OLANG['FUNCTION_JANUS_USE_RTSP_RESTREAM']['Help'].'
'; } +?> + + + Janus_Use_RTSP_Restream()) ? 'style="display:none;"' : ''?>> + + translate('None')); + foreach (ZM\User::find() as $u) { + if ($u->MonitorIds() and (!$monitor->Id() or in_array($monitor->Id(), explode(',', $u->monitorIds())))) + continue; + $users[$u->Id()] = $u->Username(); + } + echo htmlSelect("newMonitor[Janus_RTSP_User]", $users, $monitor->Janus_RTSP_User()); ?>