Sic.Framework/MECF.Framework.UI.Client/Ctrlib/Controls/PanelLocker.xaml.cs

296 lines
9.5 KiB
C#
Raw Normal View History

2023-04-13 11:51:03 +08:00
// /************************************************************************
// * @file RecipeLockPanel.xaml.cs
// * @author Su Liang
// * @date 2023/03/08
// *
// * @copyright &copy Sicentury Inc.
// *
// * @brief
// *
// * @details
// *
// *
// * *****************************************************************************/
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
2023-04-13 11:51:03 +08:00
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using Aitex.Core.Util;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.OperationCenter;
using Panel = System.Windows.Controls.Panel;
namespace MECF.Framework.UI.Client.Ctrlib.Controls
{
public partial class PanelLocker
{
/// <summary>
/// 锁定时背景模糊半径
/// </summary>
private const double BLUR_RADIUS = 30;
/// <summary>
/// 默认密码admin的SHA256
/// </summary>
private const string DEF_PASSWORD = "8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918";
// 阻止密码攻击定时器
private readonly DeviceTimer _timPassAttackDetector;
// 密码连续重试次数
private int _retryTimes;
2023-04-13 11:51:03 +08:00
// 自动锁定计时器
private readonly Stopwatch _swAutoLock;
private PeriodicJob _pjobAutoLock;
2023-04-13 11:51:03 +08:00
private int _timeoutAutoLock = int.MaxValue;
public PanelLocker()
{
InitializeComponent();
_timPassAttackDetector = new DeviceTimer();
_retryTimes = 0;
_pjobAutoLock = new PeriodicJob(int.MaxValue, () =>
2023-04-13 11:51:03 +08:00
{
Dispatcher.Invoke(Lock);
return true;
}, "AutoLockRecipeEditor");
// Lock面板加载后或重新激活后将焦点自动设置到PasswordBox
Loaded += (sender, args) =>
{
txtPass.Focus();
};
2023-04-13 11:51:03 +08:00
}
#region Dps
public static readonly DependencyProperty LockTargetProperty = DependencyProperty.Register(
nameof(LockTarget), typeof(Panel), typeof(PanelLocker), new PropertyMetadata(default(Panel), (sender, args) =>
{
// 初次拿到LockTarget对象时锁定对象
if (sender is PanelLocker pl && args.NewValue is Panel)
{
pl.Lock();
}
}));
/// <summary>
/// 设置或返回待锁定的界面
/// </summary>
public Panel LockTarget
{
get => (Panel)GetValue(LockTargetProperty);
set => SetValue(LockTargetProperty, value);
}
public static readonly DependencyProperty ScPathPasswordProperty = DependencyProperty.Register(
nameof(ScPathPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.Recipe.EditorPassword"));
/// <summary>
/// 设置或返回SC中存放密码的节点。
/// </summary>
public string ScPathPassword
{
get => (string)GetValue(ScPathPasswordProperty);
set => SetValue(ScPathPasswordProperty, value);
}
public static readonly DependencyProperty ScPathIsResetPasswordProperty = DependencyProperty.Register(
nameof(ScPathIsResetPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.Recipe.ResetEditorPassword"));
/// <summary>
/// 设置或返回SC中复位密码的节点。
/// </summary>
public string ScPathIsResetPassword
{
get => (string)GetValue(ScPathIsResetPasswordProperty);
set => SetValue(ScPathIsResetPasswordProperty, value);
}
public static readonly DependencyProperty OpPathSetNewPasswordProperty = DependencyProperty.Register(
nameof(OpPathSetNewPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.SetNewRecipeEditorPassword"));
/// <summary>
/// 设置或返回RT中注册的用于设置新密码的OP。
/// </summary>
public string OpPathSetNewPassword
{
get => (string)GetValue(OpPathSetNewPasswordProperty);
set => SetValue(OpPathSetNewPasswordProperty, value);
}
public static readonly DependencyProperty OpPathResetPasswordToDefaultProperty = DependencyProperty.Register(
nameof(OpPathResetPasswordToDefault), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.ResetRecipeEditorPassword"));
public string OpPathResetPasswordToDefault
{
get => (string)GetValue(OpPathResetPasswordToDefaultProperty);
set => SetValue(OpPathResetPasswordToDefaultProperty, value);
}
2023-04-13 11:51:03 +08:00
#endregion
#region Methods
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
txtPass.Focus();
}
2023-04-13 11:51:03 +08:00
public void Lock()
{
txtPass.Password = "";
txtInfo.Text = "";
LockTarget.Effect = new BlurEffect();
Visibility = Visibility.Visible;
var aniBlurFadeOut = new DoubleAnimation(0, BLUR_RADIUS, new Duration(TimeSpan.FromMilliseconds(300)));
LockTarget.Effect.BeginAnimation(BlurEffect.RadiusProperty, aniBlurFadeOut);
// 停止自动锁定计时器
//_swAutoLock.Stop();
}
/// <summary>
/// 重置自动锁定超时计时器
/// </summary>
public void ResetAutoLockTimer()
{
_pjobAutoLock.Stop();
_pjobAutoLock.Start();
}
/// <summary>
/// 校验密码
/// </summary>
/// <returns></returns>
private bool CheckPassword()
{
// 是否请求重置密码
var reqResetPass = (bool)QueryDataClient.Instance.Service.GetConfig(ScPathIsResetPassword);
if (reqResetPass)
{
// 密码重置为admin
InvokeClient.Instance.Service.DoOperation(OpPathResetPasswordToDefault, DEF_PASSWORD);
2023-04-13 11:51:03 +08:00
}
2023-04-13 11:51:03 +08:00
// 读取系统配置中的Password如果读取失败使用默认密码admin
var passInSc = QueryDataClient.Instance.Service.GetConfig(ScPathPassword).ToString();
if (string.IsNullOrEmpty(passInSc))
passInSc = DEF_PASSWORD;
using (var sha = SHA256.Create())
{
var bytesHash = sha.ComputeHash(Encoding.UTF8.GetBytes(txtPass.Password));
var passInput = BitConverter.ToString(bytesHash).Replace("-", "");
if (passInput == passInSc)
{
txtPass.Password = "";
return true;
}
}
// 检测是否5s内重试密码5次以上。
if (_timPassAttackDetector.IsIdle() || _timPassAttackDetector.IsTimeout())
{
_timPassAttackDetector.Start(5000);
_retryTimes = 0;
}
else
{
_retryTimes++;
if (_retryTimes > 5)
{
btnUnlock.IsEnabled = false;
txtPass.IsEnabled = false;
// 如果5s内重试的次数大于5次禁用解锁窗口5秒钟
Task.Run(() =>
{
var deniedSec = 5;
while (deniedSec-- > 0)
{
Dispatcher.Invoke(() =>
{
txtInfo.Text = $"You have retried too many times, try again in {deniedSec} seconds";
});
2023-04-13 11:51:03 +08:00
Thread.Sleep(1000);
}
Dispatcher.Invoke(() =>
{
txtInfo.Text = "";
btnUnlock.IsEnabled = true;
txtPass.IsEnabled = true;
});
});
}
}
2023-04-13 11:51:03 +08:00
txtInfo.Text = "Incorrect Password";
txtPass.Password = "";
return false;
}
#endregion
#region Events
private void BtnUnlock_OnClick(object sender, RoutedEventArgs e)
{
if (!CheckPassword())
{
txtPass.Focus();
2023-04-13 11:51:03 +08:00
return;
}
2023-04-13 11:51:03 +08:00
if (LockTarget.Effect is BlurEffect eff)
{
var aniBlurFadeOut = new DoubleAnimation(BLUR_RADIUS, 0, new Duration(TimeSpan.FromMilliseconds(300)));
eff.BeginAnimation(BlurEffect.RadiusProperty, aniBlurFadeOut);
}
LockTarget.Effect = null;
2023-04-13 11:51:03 +08:00
this.Visibility = Visibility.Collapsed;
2023-04-13 11:51:03 +08:00
// 启动自动锁定计时器
/*var autoLockTimeout = (int)QueryDataClient.Instance.Service.GetConfig("System.RecipeEditorAutoLockTimeout");
if (autoLockTimeout <= 0)
autoLockTimeout = 60;
_swAutoLock.Interval = autoLockTimeout;
_swAutoLock.Start();*/
}
2023-04-13 11:51:03 +08:00
private void TxtPass_OnPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
BtnUnlock_OnClick(this, new RoutedEventArgs());
}
#endregion
2023-04-13 11:51:03 +08:00
}
}