mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-05-24 14:36:09 -04:00
Merge pull request #3537 from parvit/issue-695
Added configuring of authentication for rstp cameras
This commit is contained in:
@@ -85,6 +85,8 @@ FfmpegCamera::FfmpegCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
int p_width,
|
||||
@@ -114,10 +116,13 @@ FfmpegCamera::FfmpegCamera(
|
||||
),
|
||||
mPath(p_path),
|
||||
mSecondPath(p_second_path),
|
||||
mUser(UriEncode(p_user)),
|
||||
mPass(UriEncode(p_pass)),
|
||||
mMethod(p_method),
|
||||
mOptions(p_options),
|
||||
hwaccel_name(p_hwaccel_name),
|
||||
hwaccel_device(p_hwaccel_device)
|
||||
hwaccel_device(p_hwaccel_device),
|
||||
frameCount(0)
|
||||
{
|
||||
mMaskedPath = remove_authentication(mPath);
|
||||
mMaskedSecondPath = remove_authentication(mSecondPath);
|
||||
@@ -125,7 +130,6 @@ FfmpegCamera::FfmpegCamera(
|
||||
FFMPEGInit();
|
||||
}
|
||||
|
||||
frameCount = 0;
|
||||
mCanCapture = false;
|
||||
error_count = 0;
|
||||
use_hwaccel = true;
|
||||
@@ -276,6 +280,13 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
std::string protocol = mPath.substr(0, 4);
|
||||
protocol = StringToUpper(protocol);
|
||||
if ( protocol == "RTSP" ) {
|
||||
if( mUser.length() > 0 ) {
|
||||
ret = av_dict_set(&opts, "auth_type", "basic", 0);
|
||||
if (ret < 0) {
|
||||
Warning("Could not set auth_type method to 'basic'");
|
||||
}
|
||||
}
|
||||
|
||||
const std::string method = Method();
|
||||
if ( method == "rtpMulti" ) {
|
||||
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
|
||||
@@ -308,6 +319,12 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
mFormatContext->interrupt_callback.opaque = this;
|
||||
mFormatContext->flags |= AVFMT_FLAG_NOBUFFER | AVFMT_FLAG_FLUSH_PACKETS;
|
||||
|
||||
if( mUser.length() > 0 ) {
|
||||
// build the actual uri string with encoded parameters (from the user and pass fields)
|
||||
mPath = StringToLower(protocol) + "://" + mUser + ":" + mPass + "@" + mMaskedPath.substr(7, std::string::npos);
|
||||
Debug(1, "Rebuilt URI with encoded parameters: '%s'", mPath.c_str());
|
||||
}
|
||||
|
||||
ret = avformat_open_input(&mFormatContext, mPath.c_str(), input_format, &opts);
|
||||
if (ret != 0) {
|
||||
logPrintf(Logger::ERROR + monitor->Importance(),
|
||||
|
||||
@@ -38,6 +38,8 @@ class FfmpegCamera : public Camera {
|
||||
std::string mPath;
|
||||
std::string mMaskedPath;
|
||||
std::string mSecondPath;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
std::string mMaskedSecondPath;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
@@ -71,8 +73,10 @@ class FfmpegCamera : public Camera {
|
||||
public:
|
||||
FfmpegCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &path,
|
||||
const std::string &second_path,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
int p_width,
|
||||
|
||||
@@ -104,6 +104,8 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
|
||||
LibvlcCamera::LibvlcCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
int p_width,
|
||||
@@ -131,6 +133,8 @@ LibvlcCamera::LibvlcCamera(
|
||||
p_record_audio
|
||||
),
|
||||
mPath(p_path),
|
||||
mUser(UriEncode(p_user)),
|
||||
mPass(UriEncode(p_pass)),
|
||||
mMethod(p_method),
|
||||
mOptions(p_options)
|
||||
{
|
||||
@@ -214,6 +218,8 @@ int LibvlcCamera::PrimeCapture() {
|
||||
|
||||
opVect = Split(Options(), ",");
|
||||
|
||||
Debug(1, "Method: '%s'", Method().c_str());
|
||||
|
||||
// Set transport method as specified by method field, rtpUni is default
|
||||
if ( Method() == "rtpMulti" )
|
||||
opVect.push_back("--rtsp-mcast");
|
||||
@@ -241,6 +247,17 @@ int LibvlcCamera::PrimeCapture() {
|
||||
}
|
||||
(*libvlc_log_set_f)(mLibvlcInstance, LibvlcCamera::log_callback, nullptr);
|
||||
|
||||
// recreate the path with encoded authentication info
|
||||
if( mUser.length() > 0 ) {
|
||||
std::string mMaskedPath = remove_authentication(mPath);
|
||||
|
||||
std::string protocol = StringToUpper(mPath.substr(0, 4));
|
||||
if ( protocol == "RTSP" ) {
|
||||
// build the actual uri string with encoded parameters (from the user and pass fields)
|
||||
mPath = StringToLower(protocol) + "://" + mUser + ":" + mPass + "@" + mMaskedPath.substr(7, std::string::npos);
|
||||
Debug(1, "Rebuilt URI with encoded parameters: '%s'", mPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
mLibvlcMedia = (*libvlc_media_new_location_f)(mLibvlcInstance, mPath.c_str());
|
||||
if ( mLibvlcMedia == nullptr ) {
|
||||
|
||||
@@ -49,6 +49,8 @@ class LibvlcCamera : public Camera {
|
||||
static void log_callback( void *ptr, int level, const libvlc_log_t *ctx, const char *format, va_list vargs );
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
StringVector opVect; // mOptArgV will point into opVect so it needs to hang around
|
||||
@@ -62,7 +64,7 @@ protected:
|
||||
libvlc_media_player_t *mLibvlcMediaPlayer;
|
||||
|
||||
public:
|
||||
LibvlcCamera( const Monitor *monitor, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
LibvlcCamera( const Monitor *monitor, const std::string &path, const std::string &user,const std::string &pass, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
~LibvlcCamera();
|
||||
|
||||
const std::string &Path() const { return mPath; }
|
||||
|
||||
@@ -173,8 +173,8 @@ Monitor::Monitor()
|
||||
//options
|
||||
//host
|
||||
//port
|
||||
//user
|
||||
//pass
|
||||
user(),
|
||||
pass(),
|
||||
//path
|
||||
//device
|
||||
palette(0),
|
||||
@@ -622,6 +622,8 @@ void Monitor::LoadCamera() {
|
||||
host, // Host
|
||||
port, // Port
|
||||
path, // Path
|
||||
user,
|
||||
pass,
|
||||
camera_width,
|
||||
camera_height,
|
||||
rtsp_describe,
|
||||
@@ -658,6 +660,8 @@ void Monitor::LoadCamera() {
|
||||
camera = zm::make_unique<FfmpegCamera>(this,
|
||||
path,
|
||||
second_path,
|
||||
user,
|
||||
pass,
|
||||
method,
|
||||
options,
|
||||
camera_width,
|
||||
@@ -695,6 +699,8 @@ void Monitor::LoadCamera() {
|
||||
#if HAVE_LIBVLC
|
||||
camera = zm::make_unique<LibvlcCamera>(this,
|
||||
path.c_str(),
|
||||
user,
|
||||
pass,
|
||||
method,
|
||||
options,
|
||||
camera_width,
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
//
|
||||
|
||||
#include "zm_monitor.h"
|
||||
#include <regex>
|
||||
|
||||
std::string escape_json_string( std::string input );
|
||||
|
||||
Monitor::JanusManager::JanusManager(Monitor *parent_) :
|
||||
parent(parent_),
|
||||
@@ -35,29 +37,19 @@ Monitor::JanusManager::JanusManager(Monitor *parent_) :
|
||||
} else {
|
||||
janus_endpoint = "127.0.0.1:8088/janus";
|
||||
}
|
||||
|
||||
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_username = "";
|
||||
rtsp_password = "";
|
||||
rtsp_path = "rtsp://127.0.0.1:" + std::to_string(restream_port) + "/" + parent->rtsp_streamname;
|
||||
} else {
|
||||
std::size_t at_pos = parent->path.find("@", 7);
|
||||
if (at_pos != std::string::npos) {
|
||||
//If we find an @ symbol, we have a username/password. Otherwise, passwordless login.
|
||||
std::size_t colon_pos = parent->path.find(":", 7); //Search for the colon, but only after the rtsp:// text.
|
||||
if (colon_pos == std::string::npos) {
|
||||
//Looks like an invalid url
|
||||
throw std::runtime_error("Cannot Parse URL for Janus.");
|
||||
}
|
||||
rtsp_username = parent->path.substr(7, colon_pos-7);
|
||||
rtsp_password = parent->path.substr(colon_pos+1, at_pos - colon_pos - 1);
|
||||
rtsp_path = "rtsp://";
|
||||
rtsp_path += parent->path.substr(at_pos + 1);
|
||||
} else {
|
||||
rtsp_username = "";
|
||||
rtsp_password = "";
|
||||
rtsp_path = parent->path;
|
||||
}
|
||||
rtsp_path = parent->path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +156,7 @@ int Monitor::JanusManager::add_to_janus() {
|
||||
postData += "\", \"videofmtp\" : \"";
|
||||
postData += profile_override;
|
||||
}
|
||||
if (rtsp_username != "") {
|
||||
if (rtsp_username.length() > 0) {
|
||||
postData += "\", \"rtsp_user\" : \"";
|
||||
postData += rtsp_username;
|
||||
postData += "\", \"rtsp_pwd\" : \"";
|
||||
@@ -292,3 +284,15 @@ int Monitor::JanusManager::get_janus_handle() {
|
||||
janus_handle = response.substr(pos + 6, 16);
|
||||
return 1;
|
||||
} //get_janus_handle
|
||||
|
||||
std::string escape_json_string( std::string input ) {
|
||||
std::string tmp;
|
||||
tmp = regex_replace(input, std::regex("\n"), "\\n");
|
||||
tmp = regex_replace(tmp, std::regex("\b"), "\\b");
|
||||
tmp = regex_replace(tmp, std::regex("\f"), "\\f");
|
||||
tmp = regex_replace(tmp, std::regex("\r"), "\\r");
|
||||
tmp = regex_replace(tmp, std::regex("\t"), "\\t");
|
||||
tmp = regex_replace(tmp, std::regex("\""), "\\\"");
|
||||
tmp = regex_replace(tmp, std::regex("[\\\\]"), "\\\\");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ RemoteCameraRtsp::RemoteCameraRtsp(
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
@@ -47,6 +49,8 @@ RemoteCameraRtsp::RemoteCameraRtsp(
|
||||
p_brightness, p_contrast, p_hue, p_colour,
|
||||
p_capture, p_record_audio),
|
||||
rtsp_describe(p_rtsp_describe),
|
||||
user(p_user),
|
||||
pass(p_pass),
|
||||
frameCount(0)
|
||||
{
|
||||
if ( p_method == "rtpUni" )
|
||||
@@ -110,7 +114,7 @@ void RemoteCameraRtsp::Terminate() {
|
||||
}
|
||||
|
||||
int RemoteCameraRtsp::Connect() {
|
||||
rtspThread = zm::make_unique<RtspThread>(monitor->Id(), method, protocol, host, port, path, auth, rtsp_describe);
|
||||
rtspThread = zm::make_unique<RtspThread>(monitor->Id(), method, protocol, host, port, path, user, pass, rtsp_describe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ protected:
|
||||
int rtcp_sd;
|
||||
bool rtsp_describe;
|
||||
|
||||
const std::string user;
|
||||
const std::string pass;
|
||||
|
||||
Buffer buffer;
|
||||
Buffer lastSps;
|
||||
Buffer lastPps;
|
||||
@@ -57,6 +60,8 @@ public:
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
|
||||
@@ -135,7 +135,8 @@ RtspThread::RtspThread(
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &auth,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
bool rtsp_describe) :
|
||||
mId(id),
|
||||
mMethod(method),
|
||||
@@ -169,12 +170,16 @@ RtspThread::RtspThread(
|
||||
mHttpSession = stringtf("%d", rand());
|
||||
|
||||
mNeedAuth = false;
|
||||
StringVector parts = Split(auth, ":");
|
||||
Debug(2, "# of auth parts %zu", parts.size());
|
||||
if ( parts.size() > 1 )
|
||||
mAuthenticator = new zm::Authenticator(parts[0], parts[1]);
|
||||
else
|
||||
mAuthenticator = new zm::Authenticator(parts[0], "");
|
||||
if ( user.length() > 0 && pass.length() > 0 ) {
|
||||
Debug(2, "# of auth parts 2");
|
||||
mAuthenticator = new zm::Authenticator(user, pass);
|
||||
} else if( user.length() > 0 ) {
|
||||
Debug(2, "# of auth parts 1");
|
||||
mAuthenticator = new zm::Authenticator(user, "");
|
||||
} else {
|
||||
Debug(2, "# of auth parts 0");
|
||||
mAuthenticator = new zm::Authenticator("", "");
|
||||
}
|
||||
|
||||
mThread = std::thread(&RtspThread::Run, this);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,9 @@ private:
|
||||
void Run();
|
||||
|
||||
public:
|
||||
RtspThread( int id, RtspMethod method, const std::string &protocol, const std::string &host, const std::string &port, const std::string &path, const std::string &auth, bool rtsp_describe );
|
||||
RtspThread( int id, RtspMethod method, const std::string &protocol, const std::string &host,
|
||||
const std::string &port, const std::string &path, const std::string &user, const std::string &pass,
|
||||
bool rtsp_describe );
|
||||
~RtspThread();
|
||||
|
||||
public:
|
||||
|
||||
@@ -379,6 +379,26 @@ std::string UriDecode(const std::string &encoded) {
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
std::string UriEncode(const std::string &value) {
|
||||
const char *src = value.c_str();
|
||||
std::string retbuf;
|
||||
retbuf.reserve(value.length() * 3); // at most all characters get replaced with the escape
|
||||
|
||||
char tmp[5] = "";
|
||||
while(*src) {
|
||||
if ( *src == ' ' ) {
|
||||
retbuf.append("%%20");
|
||||
} else if ( !( (*src >= 'a' && *src <= 'z') || (*src >= 'A' && *src <= 'Z') ) ) {
|
||||
sprintf(tmp, "%%%02X", *src);
|
||||
retbuf.append(tmp);
|
||||
} else {
|
||||
retbuf.push_back(*src);
|
||||
}
|
||||
src++;
|
||||
}
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
QueryString::QueryString(std::istream &input) {
|
||||
while (!input.eof() && input.peek() > 0) {
|
||||
//Should eat "param1="
|
||||
|
||||
@@ -50,6 +50,10 @@ inline std::string StringToUpper(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||||
return str;
|
||||
}
|
||||
inline std::string StringToLower(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
return str;
|
||||
}
|
||||
|
||||
StringVector Split(const std::string &str, char delim);
|
||||
StringVector Split(const std::string &str, const std::string &delim, size_t limit = 0);
|
||||
@@ -130,6 +134,7 @@ constexpr std::size_t size(const T(&)[N]) noexcept { return N; }
|
||||
std::string mask_authentication(const std::string &url);
|
||||
std::string remove_authentication(const std::string &url);
|
||||
|
||||
std::string UriEncode(const std::string &value);
|
||||
std::string UriDecode(const std::string &encoded);
|
||||
|
||||
class QueryParameter {
|
||||
|
||||
@@ -289,6 +289,78 @@ public static function getStatuses() {
|
||||
return $this->{'Server'};
|
||||
}
|
||||
|
||||
public function Path($new=null) {
|
||||
// set the new value if requested
|
||||
if( $new !== null ) {
|
||||
$this->{'Path'} = $new;
|
||||
}
|
||||
|
||||
$old_us = $this->{'User'};
|
||||
$old_ps = $this->{'Pass'};
|
||||
|
||||
// empty value or old auth values terminate
|
||||
if( strlen($this->{'Path'}) == 0 )
|
||||
return $this->{'Path'};
|
||||
|
||||
// extract the authentication part from the path given
|
||||
$values = extract_auth_values_from_url($this->{'Path'});
|
||||
|
||||
// If no values for User and Pass fields are present then terminate
|
||||
if( count( $values ) !== 2 ) {
|
||||
return $this->{'Path'};
|
||||
}
|
||||
|
||||
$us = $values[0];
|
||||
$ps = $values[1];
|
||||
|
||||
// Update the auth fields if they were empty and remove them from the path
|
||||
// or if they are equal between the path and field
|
||||
if( (strlen($old_us) == 0 || strlen($old_ps) == 0) ||
|
||||
($us == $old_us && $ps == $old_ps) )
|
||||
{
|
||||
$this->{'Path'} = str_replace("$us:$ps@", "", $this->{'Path'});
|
||||
$this->{'User'} = $us;
|
||||
$this->{'Pass'} = $ps;
|
||||
}
|
||||
return $this->{'Path'};
|
||||
}
|
||||
|
||||
public function User($new=null) {
|
||||
if( $new !== null ) {
|
||||
// no url check if the update has different value
|
||||
$this->{'User'} = $new;
|
||||
}
|
||||
|
||||
if( strlen($this->{'User'}) > 0 )
|
||||
return $this->{'User'};
|
||||
|
||||
// Only try to update from path if the field is empty
|
||||
$values = extract_auth_values_from_url($this->{'Path'});
|
||||
if( count( $values ) == 2 ) {
|
||||
$us = $values[0];
|
||||
$this->{'User'} = $values[0];
|
||||
}
|
||||
return $this->{'User'};
|
||||
}
|
||||
|
||||
public function Pass($new=null) {
|
||||
if( $new !== null ) {
|
||||
// no url check if the update has different value
|
||||
$this->{'Pass'} = $new;
|
||||
}
|
||||
|
||||
if( strlen($this->{'Pass'}) > 0 )
|
||||
return $this->{'Pass'};
|
||||
|
||||
// Only try to update from path if the field is empty
|
||||
$values = extract_auth_values_from_url($this->{'Path'});
|
||||
if( count( $values ) == 2 ) {
|
||||
$ps = $values[1];
|
||||
$this->{'Pass'} = $values[1];
|
||||
}
|
||||
return $this->{'Pass'};
|
||||
}
|
||||
|
||||
public function __call($fn, array $args) {
|
||||
if (count($args)) {
|
||||
if (is_array($this->defaults[$fn]) and $this->defaults[$fn]['type'] == 'set') {
|
||||
|
||||
@@ -2345,4 +2345,23 @@ function get_subnets($interface) {
|
||||
return $subnets;
|
||||
}
|
||||
|
||||
function extract_auth_values_from_url($url): array {
|
||||
$protocolPrefixPos = strpos($url, '://');
|
||||
if( $protocolPrefixPos === false )
|
||||
return array();
|
||||
|
||||
$authSeparatorPos = strpos($url, '@', $protocolPrefixPos+3);
|
||||
if( $authSeparatorPos === false )
|
||||
return array();
|
||||
|
||||
$fieldsSeparatorPos = strpos($url, ':', $protocolPrefixPos+3);
|
||||
if( $fieldsSeparatorPos === false || $authSeparatorPos < $fieldsSeparatorPos )
|
||||
return array();
|
||||
|
||||
$username = substr( $url, $protocolPrefixPos+3, $fieldsSeparatorPos-($protocolPrefixPos+3) );
|
||||
$password = substr( $url, $fieldsSeparatorPos+1, $authSeparatorPos-$fieldsSeparatorPos-1 );
|
||||
|
||||
return array( $username, $password );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -302,6 +302,18 @@ function initPage() {
|
||||
}
|
||||
});
|
||||
|
||||
let monitorPath = document.getElementsByName("newMonitor[Path]")[0];
|
||||
monitorPath.addEventListener('keyup', change_Path); // on edit sync path -> user & pass
|
||||
monitorPath.addEventListener('blur', change_Path); // remove fields from path if user & pass equal on end of edit
|
||||
|
||||
let monitorUser = document.getElementsByName("newMonitor[User]");
|
||||
if( monitorUser.length > 0 )
|
||||
monitorUser[0].addEventListener('blur', change_Path); // remove fields from path if user & pass equal
|
||||
|
||||
let monitorPass = document.getElementsByName("newMonitor[Pass]");
|
||||
if( monitorPass.length > 0 )
|
||||
monitorPass[0].addEventListener('blur', change_Path); // remove fields from path if user & pass equal
|
||||
|
||||
if ( parseInt(ZM_OPT_USE_GEOLOCATION) ) {
|
||||
if ( window.L ) {
|
||||
const form = document.getElementById('contentForm');
|
||||
@@ -343,6 +355,64 @@ function initPage() {
|
||||
updateLinkedMonitorsUI();
|
||||
} // end function initPage()
|
||||
|
||||
function change_Path(event) {
|
||||
var pathInput = document.getElementsByName("newMonitor[Path]")[0];
|
||||
|
||||
var protoPrefixPos = pathInput.value.indexOf('://');
|
||||
if( protoPrefixPos == -1 )
|
||||
return;
|
||||
|
||||
// check the formatting of the url
|
||||
var authSeparatorPos = pathInput.value.indexOf( '@', protoPrefixPos+3 );
|
||||
if( authSeparatorPos == -1 ) {
|
||||
console.warn('ignoring URL incorrectly formatted, missing "@"');
|
||||
return;
|
||||
}
|
||||
|
||||
var fieldsSeparatorPos = pathInput.value.indexOf( ':', protoPrefixPos+3 );
|
||||
if( authSeparatorPos == -1 || fieldsSeparatorPos >= authSeparatorPos ) {
|
||||
console.warn('ignoring URL incorrectly formatted, missing ":"');
|
||||
return;
|
||||
}
|
||||
|
||||
var usernameValue = pathInput.value.substring( protoPrefixPos+3, fieldsSeparatorPos );
|
||||
var passwordValue = pathInput.value.substring( fieldsSeparatorPos+1, authSeparatorPos );
|
||||
if( usernameValue.length == 0 || passwordValue.length == 0 ) {
|
||||
console.warn('ignoring URL incorrectly formatted, empty username or password');
|
||||
return;
|
||||
}
|
||||
|
||||
// get the username / password inputs
|
||||
var userInput = document.getElementsByName("newMonitor[User]");
|
||||
var passInput = document.getElementsByName("newMonitor[Pass]");
|
||||
|
||||
if (userInput.length != 1 || passInput.length != 1) {
|
||||
return
|
||||
}
|
||||
|
||||
// on editing update the fields only if they are empty or a prefix of the new value
|
||||
if( event.type != 'blur' ) {
|
||||
if( userInput[0].value.length == 0 || usernameValue.indexOf(userInput[0].value) == 0 ||
|
||||
userInput[0].value.indexOf(usernameValue) == 0 )
|
||||
{
|
||||
userInput[0].value = usernameValue;
|
||||
}
|
||||
|
||||
if( passInput[0].value.length == 0 || passwordValue.indexOf(passInput[0].value) == 0 ||
|
||||
passInput[0].value.indexOf(passwordValue) == 0 )
|
||||
{
|
||||
passInput[0].value = passwordValue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// on leaving the input sync the values and remove it from the url
|
||||
// only if they already match (to not overwrite already present values)
|
||||
if( userInput[0].value == usernameValue && passInput[0].value == passwordValue )
|
||||
pathInput.value = pathInput.value.substring(0, protoPrefixPos+3) + pathInput.value.substring(authSeparatorPos+1, pathInput.value.length);
|
||||
}
|
||||
|
||||
function change_WebColour() {
|
||||
$j('#WebSwatch').css(
|
||||
'backgroundColor',
|
||||
|
||||
@@ -688,6 +688,8 @@ include('_monitor_source_nvsocket.php');
|
||||
<?php
|
||||
} else if ( $monitor->Type() == 'Remote' ) {
|
||||
?>
|
||||
<tr><td class="text-right pr-3"><?php echo 'Username' ?></td><td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/></td></tr>
|
||||
<tr><td class="text-right pr-3"><?php echo 'Password' ?></td><td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>"/></td></tr>
|
||||
<tr>
|
||||
<td class="text-right pr-3"><?php echo translate('RemoteProtocol') ?></td>
|
||||
<td><?php echo htmlSelect('newMonitor[Protocol]', $remoteProtocols, $monitor->Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?></td>
|
||||
@@ -748,6 +750,8 @@ include('_monitor_source_nvsocket.php');
|
||||
<td class="text-right pr-3"><?php echo translate('SourcePath') ?></td>
|
||||
<td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" /></td>
|
||||
</tr>
|
||||
<tr><td class="text-right pr-3"><?php echo 'Username' ?></td><td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/></td></tr>
|
||||
<tr><td class="text-right pr-3"><?php echo 'Password' ?></td><td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>"/></td></tr>
|
||||
<tr>
|
||||
<td class="text-right pr-3">
|
||||
<?php echo translate('RemoteMethod'); echo makeHelpLink('OPTIONS_RTSPTrans') ?></td>
|
||||
|
||||
Reference in New Issue
Block a user