From 4aba26c853be6571e3e1de82275e9284f6e12ecf Mon Sep 17 00:00:00 2001 From: keyldev Date: Thu, 2 Jul 2026 21:13:22 +0300 Subject: [PATCH] fix(editor): XM Sofia-hash template + wider dialog - new "XM (Sofia hash)" entry: 8-char NETSurveillance MD5 digest in password= (newer XM firmwares reject plaintext in the RTSP URL) - camera editor window 520x640 -> 560x680 (content clipped by the scrollbar) --- .../Dialogs/CameraEditorViewModel.cs | 20 +++++++++++++++++++ .../Views/Dialogs/CameraEditorContent.axaml | 1 + .../Views/Dialogs/CameraEditorWindow.axaml | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs b/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs index 92bb3f6..62567e7 100644 --- a/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs +++ b/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs @@ -179,6 +179,9 @@ private void ApplyRtspTemplate(string vendor) "xm" => ( $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=0.sdp?real_stream", $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=1.sdp?real_stream"), + "xm-sofia" => ( + $"rtsp://{host}:554/user={user}&password={SofiaHash(Password)}&channel=1&stream=0.sdp?real_stream", + $"rtsp://{host}:554/user={user}&password={SofiaHash(Password)}&channel=1&stream=1.sdp?real_stream"), "hikvision" => ( $"rtsp://{host}:554/Streaming/Channels/101", $"rtsp://{host}:554/Streaming/Channels/102"), @@ -198,6 +201,23 @@ private void ApplyRtspTemplate(string vendor) }; } + // XM/Xiongmai "Sofia" password digest (NETSurveillance/DVRIP): pairs of MD5 + // bytes summed mod 62, mapped to [0-9A-Za-z], 8 chars. Newer XM firmwares + // reject the plaintext password in the RTSP URL and want this instead + // (empty password hashes to the well-known "tlJwpbo6"). MD5 here is a + // protocol requirement, not our choice of cryptography. + private static string SofiaHash(string password) + { + var md5 = System.Security.Cryptography.MD5.HashData(System.Text.Encoding.UTF8.GetBytes(password)); + var chars = new char[8]; + for (var i = 0; i < 8; i++) + { + var n = (md5[2 * i] + md5[2 * i + 1]) % 62; + chars[i] = (char)(n < 10 ? '0' + n : n < 36 ? 'A' + n - 10 : 'a' + n - 36); + } + return new string(chars); + } + [RelayCommand(CanExecute = nameof(CanTestConnection))] private async Task TestConnectionAsync() { diff --git a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml index 6405022..25d9348 100644 --- a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml +++ b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml @@ -63,6 +63,7 @@ + diff --git a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorWindow.axaml b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorWindow.axaml index dad0654..48e0747 100644 --- a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorWindow.axaml +++ b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorWindow.axaml @@ -5,7 +5,7 @@ x:Class="OpenIPC.Viewer.App.Views.Dialogs.CameraEditorWindow" x:DataType="vm:CameraEditorViewModel" Title="{Binding Title}" - Width="520" Height="640" + Width="560" Height="680" WindowStartupLocation="CenterOwner" CanResize="False" Background="{StaticResource Bg1Brush}">