diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs index 550d89773..5a96e4e00 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs @@ -1,11 +1,14 @@ using Avalonia; using Avalonia.ReactiveUI; using NLog; -using System.IO; using System.Properties; using System.Reflection; +using System.Security; +using System.Collections.Generic; +using System.Text; using System.Threading.Tasks; using LogLevel = Microsoft.Extensions.Logging.LogLevel; +using System.IO; [assembly: AssemblyTitle(ThisAssembly.AssemblyTrademark + " v" + ThisAssembly.Version)] namespace System.Application.UI @@ -28,6 +31,11 @@ namespace System.Application.UI { Migrations.FromV1(); Startup.Init(); + +#if DEBUG + TestSecurityStorage(); +#endif + #if WINDOWS var app = new WpfApp(); app.InitializeComponent(); @@ -85,5 +93,59 @@ namespace System.Application.UI } } } + +#if DEBUG + + static async void TestSecurityStorage() + { + await IStorage.Instance.SetAsync("↑↑", Encoding.UTF8.GetBytes("↓↓")); + + var left_top = Encoding.UTF8.GetString(( + await IStorage.Instance.GetAsync("↑↑")).ThrowIsNull("↑-key")); + + if (left_top != "↓↓") + { + throw new Exception(); + } + + await IStorage.Instance.SetAsync("←←", "→→"); + + var left_left = await IStorage.Instance.GetAsync("←←"); + + if (left_left != "→→") + { + throw new Exception(); + } + + await IStorage.Instance.SetAsync("aa", "bb"); + + var left_aa = await IStorage.Instance.GetAsync("aa"); + + if (left_aa != "bb") + { + throw new Exception(); + } + + var dict = new Dictionary { + { "🎈✨", "🎆🎇" }, + { "✨🎊", "🎃🎑" }, + }; + + await IStorage.Instance.SetAsync("dict", dict); + + var left_dict = await IStorage.Instance.GetAsync>("dict"); + + if (left_dict == null) + { + throw new Exception(); + } + + if (left_dict.Count != dict.Count) + { + throw new Exception(); + } + } + +#endif } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Startup.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Startup.cs index 6ee52e814..ce42b8780 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Startup.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Startup.cs @@ -36,6 +36,8 @@ namespace System.Application.UI // 桌面平台服务 此项放在其他通用业务实现服务之前 services.AddDesktopPlatformService(); + services.TryAddToast(); + // 添加日志实现 services.AddDesktopLogging(); diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/Windows10SecurityService.cs b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/Windows10SecurityService.cs new file mode 100644 index 000000000..e2e7d7841 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop.Windows/Application/Services/Implementation/Windows10SecurityService.cs @@ -0,0 +1,84 @@ +// https://github.com/xamarin/Essentials/blob/1.6.1/Xamarin.Essentials/SecureStorage/SecureStorage.uwp.cs +using Microsoft.Extensions.Options; +using System.Application.Models; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Runtime.Versioning; +using System.Threading.Tasks; +using Windows.Security.Cryptography.DataProtection; + +namespace System.Application.Services.Implementation +{ + /// + /// https://docs.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider?view=winrt-10240 + /// + [SupportedOSPlatform("Windows10.0.10240.0")] + internal sealed class Windows10SecurityService : SecurityService + { + public Windows10SecurityService(IOptions options) : base(options) + { + } + + static async Task E__(byte[]? bytes) + { + if (bytes == null) return null; + + // LOCAL=user and LOCAL=machine do not require enterprise auth capability + var provider = new DataProtectionProvider("LOCAL=user"); + + var buffer = await provider.ProtectAsync(bytes.AsBuffer()); + + var encBytes = buffer.ToArray(); + + return encBytes; + } + + static async Task D__(byte[]? encBytes) + { + if (encBytes == null) return null; + + var provider = new DataProtectionProvider(); + + var buffer = await provider.UnprotectAsync(encBytes.AsBuffer()); + + return buffer.ToArray(); + } + + public override Task E(string? value) + { + var value2 = E_(value); + return E__(value2); + } + + public override Task EB(byte[]? value) + { + var value2 = EB_(value); + return E__(value2); + } + + public override async Task D(byte[]? value) + { + try + { + var value2 = await D__(value); + return D_(value2); + } + catch + { + return null; + } + } + + public override async Task DB(byte[]? value) + { + try + { + var value2 = await D__(value); + return DB_(value2); + } + catch + { + return null; + } + } + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.cs b/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.cs deleted file mode 100644 index 852cdfe60..000000000 --- a/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.cs +++ /dev/null @@ -1,67 +0,0 @@ -// https://github.com/xamarin/Essentials/blob/1.6.1/Xamarin.Essentials/SecureStorage/SecureStorage.shared.cs -using System.Application; -using System.Threading.Tasks; - -namespace System.Security -{ - /// - /// https://docs.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider?view=winrt-10240 - /// - internal sealed partial class Windows10DesktopClientStorage : IStorage - { - // Special Alias that is only used for Secure Storage. All others should use: Preferences.GetPrivatePreferencesSharedName - internal static readonly string Alias = $"{BuildConfig.APPLICATION_ID}.xamarinessentials"; - - public string? Get(string key) - { - Func> func = () => GetAsync(key); - var result = func.RunSync(); - return result; - } - - public Task GetAsync(string key) - { - if (string.IsNullOrWhiteSpace(key)) - throw new ArgumentNullException(nameof(key)); - return PlatformGetAsync(key); - } - - public void Set(string key, string? value) - { - if (string.IsNullOrEmpty(value)) - { - Remove(key); - return; - } - Func func = () => SetAsync(key, value); - func.RunSync(); - } - - public Task SetAsync(string key, string? value) - { - if (string.IsNullOrEmpty(value)) - { - Remove(key); - return Task.CompletedTask; - } - return SetAsync_(key, value); - } - - static Task SetAsync_(string key, string? value) - { - if (string.IsNullOrWhiteSpace(key)) - throw new ArgumentNullException(nameof(key)); - - if (value == null) - throw new ArgumentNullException(nameof(value)); - - return PlatformSetAsync(key, value); - } - - public bool Remove(string key) => PlatformRemove(key); - - public Task RemoveAsync(string key) => Task.FromResult(Remove(key)); - - public static void RemoveAll() => PlatformRemoveAll(); - } -} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.uwp.cs b/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.uwp.cs deleted file mode 100644 index bbfece098..000000000 --- a/System.Application.SteamTools.Client.Desktop.Windows/Security/Windows10DesktopClientStorage.uwp.cs +++ /dev/null @@ -1,73 +0,0 @@ -// https://github.com/xamarin/Essentials/blob/1.6.1/Xamarin.Essentials/SecureStorage/SecureStorage.uwp.cs -#pragma warning disable CA1416 // 验证平台兼容性 -using System.Runtime.InteropServices.WindowsRuntime; -using System.Text; -using System.Threading.Tasks; -using Windows.Security.Cryptography.DataProtection; -using Windows.Storage; - -namespace System.Security -{ - partial class Windows10DesktopClientStorage - { - static async Task PlatformGetAsync(string key) - { - var settings = GetSettings(Alias); - - if (settings.Values[key] is not byte[] encBytes) - return null; - - var provider = new DataProtectionProvider(); - - var buffer = await provider.UnprotectAsync(encBytes.AsBuffer()); - - return Encoding.UTF8.GetString(buffer.ToArray()); - } - - static async Task PlatformSetAsync(string key, string data) - { - var settings = GetSettings(Alias); - - var bytes = Encoding.UTF8.GetBytes(data); - - // LOCAL=user and LOCAL=machine do not require enterprise auth capability - var provider = new DataProtectionProvider("LOCAL=user"); - - var buffer = await provider.ProtectAsync(bytes.AsBuffer()); - - var encBytes = buffer.ToArray(); - - settings.Values[key] = encBytes; - } - - static bool PlatformRemove(string key) - { - var settings = GetSettings(Alias); - - if (settings.Values.ContainsKey(key)) - { - settings.Values.Remove(key); - return true; - } - - return false; - } - - static void PlatformRemoveAll() - { - var settings = GetSettings(Alias); - - settings.Values.Clear(); - } - - static ApplicationDataContainer GetSettings(string name) - { - var localSettings = ApplicationData.Current.LocalSettings; - - if (!localSettings.Containers.ContainsKey(name)) - localSettings.CreateContainer(name, ApplicationDataCreateDisposition.Always); - return localSettings.Containers[name]; - } - } -} -#pragma warning restore CA1416 // 验证平台兼容性 \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Windows/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client.Desktop.Windows/ServiceCollectionExtensions.cs index bd65df590..154bfb081 100644 --- a/System.Application.SteamTools.Client.Desktop.Windows/ServiceCollectionExtensions.cs +++ b/System.Application.SteamTools.Client.Desktop.Windows/ServiceCollectionExtensions.cs @@ -19,10 +19,10 @@ namespace Microsoft.Extensions.DependencyInjection { services.AddSingleton(); services.AddSingleton(); - //if (Environment.OSVersion.Version.Major >= 10) - //{ - // services.AddSingleton(); - //} + if (Environment.OSVersion.Version.Major >= 10) + { + services.AddSingleton(); + } } else { diff --git a/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj b/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj index ac0a47f7d..8af028cb9 100644 --- a/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj +++ b/System.Application.SteamTools.Client.Desktop.Windows/System.Application.SteamTools.Client.Desktop.Windows.csproj @@ -8,11 +8,6 @@ false - - - - - Properties\AssemblyInfo.cs @@ -32,8 +27,4 @@ - - - - diff --git a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs index bb32678b4..a531290a1 100644 --- a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs +++ b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs @@ -9,6 +9,14 @@ namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { + /// + /// 尝试添加适用于Desktop的Toast + /// + /// + /// + public static IServiceCollection TryAddToast(this IServiceCollection services) + => PlatformToastImpl.TryAddToast(services); + /// /// 添加桌面端日志实现 /// diff --git a/System.Application.SteamTools.Client.Desktop/Services/Implementation/PlatformToastImpl.cs b/System.Application.SteamTools.Client.Desktop/Services/Implementation/PlatformToastImpl.cs new file mode 100644 index 000000000..4afb2369e --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/Services/Implementation/PlatformToastImpl.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace System.Application.Services.Implementation +{ + internal sealed class PlatformToastImpl : ToastImpl + { + public PlatformToastImpl(IToastIntercept intercept) : base(intercept) + { + } + + protected override void PlatformShow(string text, int duration) + { + ToastService.Current.Notify(text); + } + + internal static IServiceCollection TryAddToast(IServiceCollection services) + => TryAddToast(services); + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs b/System.Application.SteamTools.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs index 635dc936d..d49c77042 100644 --- a/System.Application.SteamTools.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs +++ b/System.Application.SteamTools.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs @@ -32,7 +32,7 @@ namespace System.Application.UI.ViewModels DebugString += Services.ToastService.Current.Message + Environment.NewLine; DebugString += Services.ToastService.Current.IsVisible + Environment.NewLine; - DI.Get().ShowDialog("Test", "Test"); + //DI.Get().ShowDialog("Test", "Test"); } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client/Models/AppSettings.cs b/System.Application.SteamTools.Client/Models/AppSettings.cs index 34d8c3e0a..6af625ed9 100644 --- a/System.Application.SteamTools.Client/Models/AppSettings.cs +++ b/System.Application.SteamTools.Client/Models/AppSettings.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography; +using System.Application.Security; +using System.Security.Cryptography; using MPIgnore = MessagePack.IgnoreMemberAttribute; using MPKey = MessagePack.KeyAttribute; using MPObj = MessagePack.MessagePackObjectAttribute; @@ -41,7 +42,7 @@ namespace System.Application.Models { if (aes == null) { - if (AesSecret == null) throw new ArgumentNullException(nameof(AesSecret)); + if (AesSecret == null) throw new IsNotOfficialChannelPackageException(nameof(Aes), new ArgumentNullException(nameof(AesSecret))); aes = AESUtils.Create(AesSecret); } return aes; @@ -69,7 +70,7 @@ namespace System.Application.Models { if (rsa == null) { - if (RSASecret == null) throw new ArgumentNullException(nameof(RSASecret)); + if (RSASecret == null) throw new IsNotOfficialChannelPackageException(nameof(RSA), new ArgumentNullException(nameof(RSASecret))); rsa = RSAUtils.CreateFromJsonString(RSASecret); } return rsa; diff --git a/System.Application.SteamTools.Client/Services/Implementation/SecurityService.cs b/System.Application.SteamTools.Client/Services/Implementation/SecurityService.cs index 7e61f3e48..80154228e 100644 --- a/System.Application.SteamTools.Client/Services/Implementation/SecurityService.cs +++ b/System.Application.SteamTools.Client/Services/Implementation/SecurityService.cs @@ -1,11 +1,12 @@ using Microsoft.Extensions.Options; using System.Application.Models; +using System.Application.Security; using System.Security.Cryptography; namespace System.Application.Services.Implementation { /// - public class SecurityService : ISecurityService + public class SecurityService : SecurityServiceBase { protected readonly AppSettings settings; @@ -14,12 +15,20 @@ namespace System.Application.Services.Implementation settings = options.Value; } - public virtual byte[]? E(string? value) => AESUtils.EncryptToByteArray_Nullable(settings.Aes, value); - - public virtual byte[]? EB(byte[]? value) => AESUtils.Encrypt_Nullable(settings.Aes, value); - - public virtual string? D(byte[]? value) => AESUtils.DecryptToString_Nullable(settings.Aes, value); - - public virtual byte[]? DB(byte[]? value) => AESUtils.Decrypt_Nullable(settings.Aes, value); + public override Aes? Aes + { + get + { + try + { + return settings.Aes; + } + catch (IsNotOfficialChannelPackageException e) + { + Log.Error(nameof(SecurityService), e, nameof(ApiResponseCode.IsNotOfficialChannelPackage)); + return null; + } + } + } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client/Services/Implementation/UserManager.cs b/System.Application.SteamTools.Client/Services/Implementation/UserManager.cs index 479254749..14ce7a30c 100644 --- a/System.Application.SteamTools.Client/Services/Implementation/UserManager.cs +++ b/System.Application.SteamTools.Client/Services/Implementation/UserManager.cs @@ -143,19 +143,21 @@ namespace System.Application.Services.Implementation return userRepository.FindAsync(userId); } - TUserDTO? GetUserByTable(User? user, Func binding) where TUserDTO : IUserDTO + async Task GetUserByTable(User? user, Func> binding) where TUserDTO : IUserDTO { if (user == null) return default; - var value = binding.Invoke(user); + var value = await binding(user); return value; } - TUserDTO? BindingUser(User user) where TUserDTO : IUserDTO, new() + async Task BindingUser(User user) where TUserDTO : IUserDTO, new() { + var nickName = await security.D(user.NickName); + var value = new TUserDTO { Id = user.Id, - NickName = security.D(user.NickName), + NickName = nickName, Avatar = user.Avatar, }; return value; @@ -164,7 +166,7 @@ namespace System.Application.Services.Implementation public async Task GetUserByIdAsync(Guid userId) { var user = await GetUserTableByIdAsync(userId); - var value = GetUserByTable(user, BindingUser); + var value = await GetUserByTable(user, BindingUser); return value; } @@ -224,10 +226,12 @@ namespace System.Application.Services.Implementation public async Task InsertOrUpdateAsync(IUserDTO user) { + var nickName_ = await security.E(user.NickName); + var userTable = new User { Id = user.Id, - NickName = security.E(user.NickName), + NickName = nickName_, Avatar = user.Avatar, }; //if (user is UserInfoDTO userInfo) diff --git a/System.Application.SteamTools.Services.CloudService/Services/CloudService/CloudServiceClientBase.cs b/System.Application.SteamTools.Services.CloudService/Services/CloudService/CloudServiceClientBase.cs index b99cdd3c0..532536827 100644 --- a/System.Application.SteamTools.Services.CloudService/Services/CloudService/CloudServiceClientBase.cs +++ b/System.Application.SteamTools.Services.CloudService/Services/CloudService/CloudServiceClientBase.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Options; using System.Application.Columns; using System.Application.Models; +using System.Application.Security; using System.Application.Services.CloudService.Clients; using System.Application.Services.CloudService.Clients.Abstractions; using System.Net.Http; @@ -40,8 +41,9 @@ namespace System.Application.Services.CloudService { return Settings.RSA; } - catch + catch (IsNotOfficialChannelPackageException e) { + logger.LogError(e, nameof(ApiResponseCode.IsNotOfficialChannelPackage)); throw new ApiResponseCodeException(ApiResponseCode.IsNotOfficialChannelPackage); } } diff --git a/System.Application.SteamTools/Security/IsNotOfficialChannelPackageException.cs b/System.Application.SteamTools/Security/IsNotOfficialChannelPackageException.cs new file mode 100644 index 000000000..c3d868f92 --- /dev/null +++ b/System.Application.SteamTools/Security/IsNotOfficialChannelPackageException.cs @@ -0,0 +1,23 @@ +using System.Runtime.Serialization; + +namespace System.Application.Security +{ + public sealed class IsNotOfficialChannelPackageException : Exception + { + public IsNotOfficialChannelPackageException() + { + } + + public IsNotOfficialChannelPackageException(string message) : base(message) + { + } + + public IsNotOfficialChannelPackageException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + public IsNotOfficialChannelPackageException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/System.Common.ClientLib.Droid/Application/Services/Implementation/PlatformToastImpl.cs b/System.Common.ClientLib.Droid/Application/Services/Implementation/PlatformToastImpl.cs index cd3d3d958..e8135bbd3 100644 --- a/System.Common.ClientLib.Droid/Application/Services/Implementation/PlatformToastImpl.cs +++ b/System.Common.ClientLib.Droid/Application/Services/Implementation/PlatformToastImpl.cs @@ -63,7 +63,7 @@ namespace System.Application.Services.Implementation _ => base.ToDuration(toastLength), }; - public static IServiceCollection TryAddToast(IServiceCollection services) + internal static IServiceCollection TryAddToast(IServiceCollection services) => TryAddToast(services); } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client/Services/ISecurityService.cs b/System.Common.ClientLib/Application/Services/ISecurityService.cs similarity index 67% rename from System.Application.SteamTools.Client/Services/ISecurityService.cs rename to System.Common.ClientLib/Application/Services/ISecurityService.cs index af66205fe..7662c4246 100644 --- a/System.Application.SteamTools.Client/Services/ISecurityService.cs +++ b/System.Common.ClientLib/Application/Services/ISecurityService.cs @@ -1,4 +1,6 @@ -namespace System.Application.Services +using System.Threading.Tasks; + +namespace System.Application.Services { /// /// 安全服务 @@ -10,19 +12,19 @@ /// /// /// - byte[]? E(string? value); + Task E(string? value); /// - byte[]? EB(byte[]? value); + Task EB(byte[]? value); /// /// 解密 /// /// /// - string? D(byte[]? value); + Task D(byte[]? value); /// - byte[]? DB(byte[]? value); + Task DB(byte[]? value); } } \ No newline at end of file diff --git a/System.Common.ClientLib/Application/Services/Implementation/SecurityServiceBase.cs b/System.Common.ClientLib/Application/Services/Implementation/SecurityServiceBase.cs new file mode 100644 index 000000000..2f9aa523d --- /dev/null +++ b/System.Common.ClientLib/Application/Services/Implementation/SecurityServiceBase.cs @@ -0,0 +1,89 @@ +using System.Security.Cryptography; +using System.Threading.Tasks; +using System.Text; +using System.Diagnostics.CodeAnalysis; + +namespace System.Application.Services.Implementation +{ + /// + public abstract class SecurityServiceBase : ISecurityService + { + public abstract Aes? Aes { get; } + + public byte[]? E_(string? value) + { + var aes = Aes; + if (aes != null) + { + return AESUtils.EncryptToByteArray_Nullable(aes, value); + } + else + { + if (value == null) return null; + return Encoding.UTF8.GetBytes(value); + } + } + + public byte[]? EB_(byte[]? value) + { + var aes = Aes; + if (aes != null) + { + return AESUtils.Encrypt_Nullable(aes, value); + } + else + { + return value; + } + } + + public string? D_(byte[]? value) + { + var aes = Aes; + if (aes != null) + { + try + { + return AESUtils.DecryptToString_Nullable(aes, value); + } + catch + { + return null; + } + } + else + { + if (value == null) return null; + return Encoding.UTF8.GetString(value); + } + } + + public byte[]? DB_(byte[]? value) + { + var aes = Aes; + if (aes != null) + { + try + { + return AESUtils.Decrypt_Nullable(aes, value); + } + catch + { + return null; + } + } + else + { + return value; + } + } + + public virtual Task E(string? value) => Task.FromResult(E_(value)); + + public virtual Task EB(byte[]? value) => Task.FromResult(EB_(value)); + + public virtual Task D(byte[]? value) => Task.FromResult(D_(value)); + + public virtual Task DB(byte[]? value) => Task.FromResult(DB_(value)); + } +} \ No newline at end of file diff --git a/System.Common.ClientLib/Security/DesktopClientStorage.cs b/System.Common.ClientLib/Security/DesktopClientStorage.cs index 294522544..11ec41f5c 100644 --- a/System.Common.ClientLib/Security/DesktopClientStorage.cs +++ b/System.Common.ClientLib/Security/DesktopClientStorage.cs @@ -1,4 +1,6 @@ using System.Application.Repositories; +using System.Application.Services; +using System.Security.Cryptography; using System.Threading.Tasks; using KeyValuePair = System.Application.Entities.KeyValuePair; @@ -6,26 +8,39 @@ namespace System.Security { internal sealed class DesktopClientStorage : Repository, IStorage { + readonly ISecurityService ss; + + public DesktopClientStorage(ISecurityService ss) + { + this.ss = ss; + } + bool IStorage.IsNativeSupportedBytes => true; + static string GetKey(string key) => Hashs.String.SHA256(key); + async Task IStorage.GetBytesAsync(string key) { + key = GetKey(key); var item = await FirstOrDefaultAsync(x => x.Id == key); var value = item?.Value; - return value; + var value2 = await ss.DB(value); + return value2; } async Task InsertOrUpdateAsync(string key, byte[] value) { + var value2 = await ss.EB(value); await InsertOrUpdateAsync(new KeyValuePair { Id = key, - Value = value, + Value = value2.ThrowIsNull(nameof(value2)), }); } Task IStorage.SetAsync(string key, byte[]? value) { + key = GetKey(key); if (value == null || value.Length <= 0) { return DeleteAsync(key); @@ -38,6 +53,7 @@ namespace System.Security async Task IStorage.RemoveAsync(string key) { + key = GetKey(key); var result = await DeleteAsync(key); return result > 0; } diff --git a/System.Common.CoreLib/Security/IStorage.cs b/System.Common.CoreLib/Security/IStorage.cs index 6aa639e96..4e8317df9 100644 --- a/System.Common.CoreLib/Security/IStorage.cs +++ b/System.Common.CoreLib/Security/IStorage.cs @@ -16,10 +16,16 @@ namespace System.Security /// Android:加密密钥存储在密钥库中,加密数据存储在命名的共享首选项容器中 /// /// - /// UWP / Windows 10 Desktop:数据使用 DataProtectionProvider 加密并存储在命名的 ApplicationDataContainer + /// UWP:数据使用 DataProtectionProvider 加密并存储在命名的 ApplicationDataContainer /// /// - /// AspNetCore / Other Desktop:数据使用仓储实现 + /// Windows 10 Desktop:数据使用 DataProtectionProvider 加密并存储在仓储中 + /// + /// + /// Other Desktop:数据使用 AES 加密并存储在仓储中 + /// + /// + /// AspNetCore:数据存储在仓储中 /// /// /// 注意:在运行 Android 23(6.0/M)以下的 Android 设备上,KeyStore中没有AES可用。作为最佳实践,此API将生成存储在KeyStore中的RSA/ECB/PKCS7Padding密钥对(KeyStore中这些较低的API级别支持的唯一类型),用于包装运行时生成的AES密钥。这个包装好的密钥存储在首选项中 @@ -83,19 +89,27 @@ namespace System.Security /// async Task GetAsync(string key) where TValue : notnull { - if (IsNativeSupportedBytes) + try { - var bytesValue = await GetBytesAsync(key); - if (bytesValue == null) return default; - var value = Serializable.DMP(bytesValue); - return value; + if (IsNativeSupportedBytes) + { + var bytesValue = await GetBytesAsync(key); + if (bytesValue == null) return default; + var value = Serializable.DMP(bytesValue); + return value; + } + else + { + var strValue = await GetAsync(key); + if (strValue == null) return default; + var value = Serializable.DMPB64U(strValue); + return value; + } } - else + catch (Exception e) { - var strValue = await GetAsync(key); - if (strValue == null) return default; - var value = Serializable.DMPB64U(strValue); - return value; + Log.Error(nameof(IStorage), e, "GetAsync Fail, key: {0}.", key); + return default; } } @@ -104,12 +118,12 @@ namespace System.Security { if (IsNativeSupportedBytes) { - var bytesValue = SMP(value); + var bytesValue = Serializable.SMP(value); return SetAsync(key, bytesValue); } else { - var strValue = SMPB64U(value); + var strValue = Serializable.SMPB64U(value); return SetAsync(key, strValue); } } @@ -154,47 +168,5 @@ namespace System.Security return SetAsync(key, strValue); } } - - private static string? SMPB64U(TValue value) - { - string? strValue; - if (value is string str) - { - strValue = str; - } - else - { - if (value == null) - { - strValue = null; - } - else - { - strValue = Serializable.SMPB64U(value); - } - } - return strValue; - } - - private static byte[]? SMP(TValue value) - { - byte[]? bytesValue; - if (value is byte[] bytes) - { - bytesValue = bytes; - } - else - { - if (value == null) - { - bytesValue = null; - } - else - { - bytesValue = Serializable.SMP(value); - } - } - return bytesValue; - } } } \ No newline at end of file diff --git a/System.Common.CoreLib/Serializable.cs b/System.Common.CoreLib/Serializable.cs index aae984114..cbafd05c6 100644 --- a/System.Common.CoreLib/Serializable.cs +++ b/System.Common.CoreLib/Serializable.cs @@ -204,14 +204,8 @@ namespace System { if (!string.IsNullOrWhiteSpace(value)) { - try - { - var buffer = value.Base64UrlDecodeToByteArray(); - return DMP(buffer, cancellationToken); - } - catch - { - } + var buffer = value.Base64UrlDecodeToByteArray(); + return DMP(buffer, cancellationToken); } return default; }