add:安全中心

This commit is contained in:
2026-02-16 20:22:41 +08:00
parent 2f8c368eef
commit 45dc3cb537
18 changed files with 1167 additions and 49 deletions
@@ -0,0 +1,148 @@
<local:SettingsPanelBase x:Class="Ink_Canvas.Windows.SettingsViews.SecurityPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Ink_Canvas.Windows.SettingsViews"
mc:Ignorable="d"
d:DesignHeight="950" d:DesignWidth="640">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="ToggleSwitchStyle" TargetType="Border">
<Setter Property="Width" Value="48"/>
<Setter Property="Height" Value="25"/>
<Setter Property="CornerRadius" Value="12"/>
<Setter Property="Padding" Value="3,0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Margin" Value="0,0,15,0"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer ScrollChanged="ScrollViewerEx_ScrollChanged"
IsManipulationEnabled="True"
Name="ScrollViewerEx"
IsDeferredScrollingEnabled="True"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Disabled"
IsTabStop="False"
TabIndex="-1"
Margin="0,0,2,2">
<StackPanel Margin="60,12,60,24">
<Border BorderBrush="#e6e6e6" BorderThickness="1.25,1.25,1.25,4" CornerRadius="8">
<StackPanel Orientation="Vertical" Margin="18,18,18,18">
<TextBlock Text="安全密码默认关闭。开启后可用于退出软件、进入设置与重置配置时的二次验证。"
TextWrapping="Wrap"
Foreground="#9a9996"
FontSize="11"
Margin="0,0,0,12"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="启用安全密码" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="开启后需要设置密码" HorizontalAlignment="Left"/>
</StackPanel>
<Border x:Name="ToggleSwitchPasswordEnabled"
Style="{StaticResource ToggleSwitchStyle}"
Background="#e1e1e1"
Tag="PasswordEnabled"
MouseLeftButtonDown="ToggleSwitch_Click">
<Border Width="19" Height="19" Background="White" CornerRadius="10" HorizontalAlignment="Left" VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect BlurRadius="4" Direction="-45" Color="Black" Opacity="0.3" ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
<Border Height="1" Background="#ebebeb" Margin="0,8,0,8"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="密码管理" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="设置或修改安全密码" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,15,0">
<Button x:Name="BtnSetOrChangePassword" Width="120" Height="32" Click="BtnSetOrChangePassword_Click" Content="设置/修改密码"/>
<Button x:Name="BtnDisablePassword" Width="90" Height="32" Margin="8,0,0,0" Click="BtnDisablePassword_Click" Content="关闭密码"/>
</StackPanel>
</Grid>
<Border Height="1" Background="#ebebeb" Margin="0,8,0,8"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="退出软件需要密码" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="关闭 InkCanvasForClass 时进行密码验证" HorizontalAlignment="Left"/>
</StackPanel>
<Border x:Name="ToggleSwitchRequirePasswordOnExit" Style="{StaticResource ToggleSwitchStyle}" Background="#e1e1e1" Tag="RequirePasswordOnExit" MouseLeftButtonDown="ToggleSwitch_Click">
<Border Width="19" Height="19" Background="White" CornerRadius="10" HorizontalAlignment="Left" VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect BlurRadius="4" Direction="-45" Color="Black" Opacity="0.3" ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
<Border Height="1" Background="#ebebeb" Margin="0,8,0,8"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="进入设置需要密码" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="打开设置面板/新设置窗口时进行验证" HorizontalAlignment="Left"/>
</StackPanel>
<Border x:Name="ToggleSwitchRequirePasswordOnEnterSettings" Style="{StaticResource ToggleSwitchStyle}" Background="#e1e1e1" Tag="RequirePasswordOnEnterSettings" MouseLeftButtonDown="ToggleSwitch_Click">
<Border Width="19" Height="19" Background="White" CornerRadius="10" HorizontalAlignment="Left" VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect BlurRadius="4" Direction="-45" Color="Black" Opacity="0.3" ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
<Border Height="1" Background="#ebebeb" Margin="0,8,0,8"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="重置配置需要密码" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="重置 Settings.json 前进行二次验证" HorizontalAlignment="Left"/>
</StackPanel>
<Border x:Name="ToggleSwitchRequirePasswordOnResetConfig" Style="{StaticResource ToggleSwitchStyle}" Background="#e1e1e1" Tag="RequirePasswordOnResetConfig" MouseLeftButtonDown="ToggleSwitch_Click">
<Border Width="19" Height="19" Background="White" CornerRadius="10" HorizontalAlignment="Left" VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect BlurRadius="4" Direction="-45" Color="Black" Opacity="0.3" ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
</StackPanel>
</Border>
<Border Margin="0,25,0,0" BorderBrush="#e6e6e6" BorderThickness="1.25,1.25,1.25,4" CornerRadius="8">
<StackPanel Orientation="Vertical" Margin="18,18,18,18">
<TextBlock Text="进程保护默认开启:运行期间保护根目录下的程序文件(exe/dll/config)不被外部修改。"
TextWrapping="Wrap"
Foreground="#9a9996"
FontSize="11"
Margin="0,0,0,12"/>
<Grid Height="54">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBlock Foreground="#2e3436" FontSize="14.5" Text="进程保护" HorizontalAlignment="Left"/>
<TextBlock Foreground="#9a9996" FontSize="11" Margin="0,3.5,0,0" Text="开启后关键文件会被只读占用" HorizontalAlignment="Left"/>
</StackPanel>
<Border x:Name="ToggleSwitchEnableProcessProtection" Style="{StaticResource ToggleSwitchStyle}" Background="#3584e4" Tag="EnableProcessProtection" MouseLeftButtonDown="ToggleSwitch_Click">
<Border Width="19" Height="19" Background="White" CornerRadius="10" HorizontalAlignment="Right" VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect BlurRadius="4" Direction="-45" Color="Black" Opacity="0.3" ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</local:SettingsPanelBase>
@@ -0,0 +1,194 @@
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Helpers;
using System;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews
{
public partial class SecurityPanel : SettingsPanelBase
{
public SecurityPanel()
{
InitializeComponent();
}
public override void LoadSettings()
{
if (MainWindow.Settings == null) return;
if (MainWindow.Settings.Security == null) MainWindow.Settings.Security = new Security();
_isLoaded = false;
try
{
var sec = MainWindow.Settings.Security;
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchPasswordEnabled"), sec.PasswordEnabled);
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchRequirePasswordOnExit"), sec.RequirePasswordOnExit);
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchRequirePasswordOnEnterSettings"), sec.RequirePasswordOnEnterSettings);
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchRequirePasswordOnResetConfig"), sec.RequirePasswordOnResetConfig);
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchEnableProcessProtection"), sec.EnableProcessProtection);
UpdatePasswordUiState();
}
catch
{
}
_isLoaded = true;
}
private void UpdatePasswordUiState()
{
var sec = MainWindow.Settings?.Security;
var enabled = sec != null && sec.PasswordEnabled;
if (BtnSetOrChangePassword != null) BtnSetOrChangePassword.IsEnabled = enabled;
if (BtnDisablePassword != null) BtnDisablePassword.IsEnabled = enabled;
// 用途开关:仅在启用密码功能时可操作
var usageEnabled = enabled;
var t1 = FindToggleSwitch("ToggleSwitchRequirePasswordOnExit");
var t2 = FindToggleSwitch("ToggleSwitchRequirePasswordOnEnterSettings");
var t3 = FindToggleSwitch("ToggleSwitchRequirePasswordOnResetConfig");
if (t1 != null) t1.IsEnabled = usageEnabled;
if (t2 != null) t2.IsEnabled = usageEnabled;
if (t3 != null) t3.IsEnabled = usageEnabled;
}
protected override async void HandleToggleSwitchChange(string tag, bool newState)
{
if (MainWindow.Settings == null) return;
if (MainWindow.Settings.Security == null) MainWindow.Settings.Security = new Security();
var sec = MainWindow.Settings.Security;
switch (tag)
{
case "PasswordEnabled":
if (newState)
{
var havePassword = SecurityManager.HasPasswordConfigured(MainWindow.Settings);
if (!havePassword)
{
var pwd = await SecurityManager.PromptSetNewPasswordAsync(Window.GetWindow(this));
if (string.IsNullOrEmpty(pwd))
{
_isLoaded = false;
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchPasswordEnabled"), false);
_isLoaded = true;
return;
}
SecurityManager.SetPassword(MainWindow.Settings, pwd);
}
sec.PasswordEnabled = true;
MainWindow.SaveSettingsToFile();
UpdatePasswordUiState();
}
else
{
// 关闭:需要输入当前密码确认(已设置密码时)
if (SecurityManager.HasPasswordConfigured(MainWindow.Settings))
{
bool ok = await SecurityManager.PromptAndVerifyAsync(MainWindow.Settings, Window.GetWindow(this),
"关闭安全密码", "请输入当前密码以关闭安全密码功能。");
if (!ok)
{
_isLoaded = false;
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchPasswordEnabled"), true);
_isLoaded = true;
return;
}
}
sec.PasswordEnabled = false;
SecurityManager.ClearPassword(MainWindow.Settings);
MainWindow.SaveSettingsToFile();
UpdatePasswordUiState();
}
break;
case "RequirePasswordOnExit":
sec.RequirePasswordOnExit = newState;
MainWindow.SaveSettingsToFile();
break;
case "RequirePasswordOnEnterSettings":
sec.RequirePasswordOnEnterSettings = newState;
MainWindow.SaveSettingsToFile();
break;
case "RequirePasswordOnResetConfig":
sec.RequirePasswordOnResetConfig = newState;
MainWindow.SaveSettingsToFile();
break;
case "EnableProcessProtection":
sec.EnableProcessProtection = newState;
MainWindow.SaveSettingsToFile();
ProcessProtectionManager.SetEnabled(newState);
break;
}
}
protected override void HandleOptionChange(string group, string value)
{
// 本面板无选项按钮组
}
protected override void ToggleSwitch_Click(object sender, RoutedEventArgs e)
{
base.ToggleSwitch_Click(sender, e);
}
private async void BtnSetOrChangePassword_Click(object sender, RoutedEventArgs e)
{
if (MainWindow.Settings == null) return;
if (MainWindow.Settings.Security == null) MainWindow.Settings.Security = new Security();
var owner = Window.GetWindow(this);
var newPwd = await SecurityManager.PromptChangePasswordAsync(MainWindow.Settings, owner);
if (!string.IsNullOrEmpty(newPwd))
{
SecurityManager.SetPassword(MainWindow.Settings, newPwd);
MainWindow.Settings.Security.PasswordEnabled = true;
MainWindow.SaveSettingsToFile();
UpdatePasswordUiState();
}
}
private void BtnDisablePassword_Click(object sender, RoutedEventArgs e)
{
// 触发和开关一致的逻辑
if (FindToggleSwitch("ToggleSwitchPasswordEnabled") is Border b)
{
// 模拟点击到 off
if (MainWindow.Settings?.Security?.PasswordEnabled == true)
{
_isLoaded = true;
SetToggleSwitchState(b, false);
HandleToggleSwitchChange("PasswordEnabled", false);
}
}
}
public event EventHandler<RoutedEventArgs> IsTopBarNeedShadowEffect;
public event EventHandler<RoutedEventArgs> IsTopBarNeedNoShadowEffect;
private void ScrollViewerEx_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var scrollViewer = (ScrollViewer)sender;
if (scrollViewer.VerticalOffset >= 10) IsTopBarNeedShadowEffect?.Invoke(this, new RoutedEventArgs());
else IsTopBarNeedNoShadowEffect?.Invoke(this, new RoutedEventArgs());
}
public void ApplyTheme()
{
try
{
ThemeHelper.ApplyThemeToControl(this);
LoadSettings();
}
catch { }
}
}
}
@@ -39,6 +39,7 @@ namespace Ink_Canvas.Windows.SettingsViews
{
System.Diagnostics.Debug.WriteLine($"SettingsPanelBase 应用主题时出错: {ex.Message}");
}
LoadSettings();
_isLoaded = true;
}