using System.Text;
using System.Threading.Tasks;
namespace System.Security
{
///
/// 为键/值对提供简单的安全存储
///
///
/// 每个平台使用平台提供的本机API来安全存储数据:
///
/// -
/// iOS:数据存储在KeyChain中。有关SecAccessible的其他信息
///
/// -
/// Android:加密密钥存储在密钥库中,加密数据存储在命名的共享首选项容器中
///
/// -
/// UWP:数据使用 DataProtectionProvider 加密并存储在命名的 ApplicationDataContainer
///
/// -
/// Windows 10 Desktop:数据使用 DataProtectionProvider 加密并存储在仓储中
///
/// -
/// Other Desktop:数据使用 AES 加密并存储在仓储中
///
/// -
/// AspNetCore:数据存储在仓储中
///
///
/// 注意:在运行 Android 23(6.0/M)以下的 Android 设备上,KeyStore中没有AES可用。作为最佳实践,此API将生成存储在KeyStore中的RSA/ECB/PKCS7Padding密钥对(KeyStore中这些较低的API级别支持的唯一类型),用于包装运行时生成的AES密钥。这个包装好的密钥存储在首选项中
///
public partial interface IStorage
{
#region Public API
///
/// 获取给定键的值
///
/// 键
/// 如果键不存在,则返回null
async Task GetAsync(string key)
{
if (IsNativeSupportedBytes)
{
var bytesValue = await GetBytesAsync(key);
if (bytesValue == null) return null;
try
{
return Encoding.UTF8.GetString(bytesValue);
}
catch
{
return null;
}
}
else
{
throw new NotImplementedException();
}
}
///
/// 存储给定键的值
///
/// 键
/// 值
///
Task SetAsync(string key, string? value)
{
if (IsNativeSupportedBytes)
{
var bytesValue = value == null ? null : Encoding.UTF8.GetBytes(value);
return SetAsync(key, bytesValue);
}
else
{
throw new NotImplementedException();
}
}
///
/// 移除给定键的键/值对
///
/// 要移除的键
/// 如果删除了键值对,则返回true
Task RemoveAsync(string key);
///
async Task GetAsync(string key) where TValue : notnull
{
try
{
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;
}
}
catch (Exception e)
{
Log.Error(nameof(IStorage), e, "GetAsync Fail, key: {0}.", key);
return default;
}
}
///
Task SetAsync(string key, TValue value)
{
if (IsNativeSupportedBytes)
{
var bytesValue = Serializable.SMP(value);
return SetAsync(key, bytesValue);
}
else
{
var strValue = Serializable.SMPB64U(value);
return SetAsync(key, strValue);
}
}
static IStorage Instance => DI.Get();
#endregion
protected bool IsNativeSupportedBytes { get; }
///
protected async Task GetBytesAsync(string key)
{
if (IsNativeSupportedBytes)
{
throw new NotImplementedException();
}
else
{
var strValue = await GetAsync(key);
try
{
return strValue.Base64UrlDecodeToByteArray_Nullable();
}
catch
{
return null;
}
}
}
///
protected Task SetAsync(string key, byte[]? value)
{
if (IsNativeSupportedBytes)
{
throw new NotImplementedException();
}
else
{
var strValue = value.Base64UrlEncode_Nullable();
return SetAsync(key, strValue);
}
}
}
}