diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 38a4a31d0..ea2d1478d 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -119,6 +119,8 @@ FfmpegCamera::FfmpegCamera( hwaccel_name(p_hwaccel_name), hwaccel_device(p_hwaccel_device) { + mMaskedPath = mask_authentication(mPath); + mMaskedSecondPath = mask_authentication(mSecondPath); if ( capture ) { FFMPEGInit(); } @@ -161,12 +163,12 @@ FfmpegCamera::~FfmpegCamera() { int FfmpegCamera::PrimeCapture() { start_read_time = std::chrono::steady_clock::now(); if ( mCanCapture ) { - Debug(1, "Priming capture from %s, Closing", mPath.c_str()); + Debug(1, "Priming capture from %s, Closing", mMaskedPath.c_str()); Close(); } mVideoStreamId = -1; mAudioStreamId = -1; - Debug(1, "Priming capture from %s", mPath.c_str()); + Debug(1, "Priming capture from %s", mMaskedPath.c_str()); return OpenFfmpeg(); } @@ -294,7 +296,7 @@ int FfmpegCamera::OpenFfmpeg() { mPath = mPath.substr(7); } // end if RTSP - Debug(1, "Calling avformat_open_input for %s", mPath.c_str()); + Debug(1, "Calling avformat_open_input for %s", mMaskedPath.c_str()); mFormatContext = avformat_alloc_context(); mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; @@ -321,7 +323,7 @@ int FfmpegCamera::OpenFfmpeg() { ret = avformat_find_stream_info(mFormatContext, nullptr); if (ret < 0) { Error("Unable to find stream info from %s due to: %s", - mPath.c_str(), av_make_error_string(ret).c_str()); + mMaskedPath.c_str(), av_make_error_string(ret).c_str()); avformat_close_input(&mFormatContext); return -1; } @@ -374,7 +376,7 @@ int FfmpegCamera::OpenFfmpeg() { mVideoCodec = avcodec_find_decoder(mVideoStream->codecpar->codec_id); if (!mVideoCodec) { // Try and get the codec from the codec context - Error("Can't find codec for video stream from %s", mPath.c_str()); + Error("Can't find codec for video stream from %s", mMaskedPath.c_str()); return -1; } } @@ -483,7 +485,7 @@ int FfmpegCamera::OpenFfmpeg() { Warning("Option %s not recognized by ffmpeg", e->key); } if (ret < 0) { - Error("Unable to open codec for video stream from %s", mPath.c_str()); + Error("Unable to open codec for video stream from %s", mMaskedPath.c_str()); av_dict_free(&opts); return -1; } @@ -504,7 +506,7 @@ int FfmpegCamera::OpenFfmpeg() { if ( mAudioStreamId >= 0 ) { const AVCodec *mAudioCodec = nullptr; if (!(mAudioCodec = avcodec_find_decoder(mAudioStream->codecpar->codec_id))) { - Debug(1, "Can't find codec for audio stream from %s", mPath.c_str()); + Debug(1, "Can't find codec for audio stream from %s", mMaskedPath.c_str()); } else { mAudioCodecContext = avcodec_alloc_context3(mAudioCodec); avcodec_parameters_to_context(mAudioCodecContext, mAudioStream->codecpar); @@ -512,7 +514,7 @@ int FfmpegCamera::OpenFfmpeg() { zm_dump_stream_format((mSecondFormatContext?mSecondFormatContext:mFormatContext), mAudioStreamId, 0, 0); // Open the codec if (avcodec_open2(mAudioCodecContext, mAudioCodec, nullptr) < 0) { - Error("Unable to open codec for audio stream from %s", mPath.c_str()); + Error("Unable to open codec for audio stream from %s", mMaskedPath.c_str()); return -1; } // end if opened } // end if found decoder diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index e320d3b31..42b716b03 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -36,7 +36,9 @@ typedef struct DecodeContext { class FfmpegCamera : public Camera { protected: std::string mPath; + std::string mMaskedPath; std::string mSecondPath; + std::string mMaskedSecondPath; std::string mMethod; std::string mOptions; diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index 6ea4e0dae..8b7fb9ecd 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -442,3 +442,32 @@ std::string QueryString::parseValue(std::istream &input) { return UriDecode(url_encoded_value); } + +std::string mask_authentication(const std::string &url) { + std::string masked_url = url; + std::size_t at_at = masked_url.find("@"); + if (at_at == std::string::npos) { + return masked_url; + } + std::size_t password_at = masked_url.rfind(":", at_at); + + if (password_at == std::string::npos) { + // no : means no http:// either so something liek username@192.168.1.1 + masked_url.replace(0, at_at, at_at, '*'); + } else if (masked_url[password_at+1] == '/') { + // no password, something like http://username@192.168.1.1 + masked_url.replace(password_at+3, at_at-(password_at+3), at_at-(password_at+3), '*'); + } else { + // have username and password, something like http://username:password@192.168.1.1/ + masked_url.replace(password_at+1, at_at - (password_at+1), at_at - (password_at+1), '*'); + std::size_t username_at = masked_url.rfind("/", password_at); + if (username_at == std::string::npos) { + // Something like username:password@192.168.1.1 + masked_url.replace(0, password_at, password_at, '*'); + } else { + masked_url.replace(username_at+1, password_at-(username_at+1), password_at-(username_at+1), '*'); + // something like http://username:password@192.168.1.1/ + } + } + return masked_url; +} diff --git a/src/zm_utils.h b/src/zm_utils.h index d5ee88202..b9e978238 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -127,6 +127,8 @@ template constexpr std::size_t size(const T(&)[N]) noexcept { return N; } } +std::string mask_authentication(const std::string &url); + std::string UriDecode(const std::string &encoded); class QueryParameter { diff --git a/tests/zm_utils.cpp b/tests/zm_utils.cpp index 43b6a4a71..c09d5bdc6 100644 --- a/tests/zm_utils.cpp +++ b/tests/zm_utils.cpp @@ -250,3 +250,31 @@ TEST_CASE("QueryString") { REQUIRE(p2->values()[0] == "value2"); } } + +TEST_CASE("mask_authentication") { + SECTION("no authentication") { + std::string url("http://192.168.1.1"); + std::string result = mask_authentication(url); + REQUIRE(url == result); + } + SECTION("has username no password has scheme") { + std::string url("http://username@192.168.1.1"); + std::string result = mask_authentication(url); + REQUIRE(result == "http://********@192.168.1.1"); + } + SECTION("has username no password no scheme") { + std::string url("username@192.168.1.1"); + std::string result = mask_authentication(url); + REQUIRE(result == "********@192.168.1.1"); + } + SECTION("has username has password no scheme") { + std::string url("username:password@192.168.1.1"); + std::string result = mask_authentication(url); + REQUIRE(result == "********:********@192.168.1.1"); + } + SECTION("has username has password has scheme") { + std::string url("http://username:password@192.168.1.1"); + std::string result = mask_authentication(url); + REQUIRE(result == "http://********:********@192.168.1.1"); + } +}