XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

LumaTunnel

【WinUI】LumaTunnel 是一个面向个人多设备的 Windows 代理系统。客户端在本机提供 HTTP/HTTPS CONNECT 与 SOCKS5 TCP 代理,并通过一个受信任 TLS 证书保护的 WSS 会话,将多个 TCP 流复用到自建 Windows Server 节点。

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Security.Cryptography;
using System.Text;
using LumaTunnel.Client.Interface;
using XFEExtension.NetCore.WinUIHelper.Implements.Services;

namespace LumaTunnel.Client.Implements;

public sealed class SecretStore : GlobalServiceBase, ISecretStore
{
    private readonly string _directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LumaTunnel", "secrets");

    public async Task SetAsync(string key, string value, CancellationToken cancellationToken = default)
    {
        Directory.CreateDirectory(_directory);
        var plaintext = Encoding.UTF8.GetBytes(value);
        var encrypted = ProtectedData.Protect(plaintext, Entropy(key), DataProtectionScope.CurrentUser);
        await File.WriteAllBytesAsync(PathFor(key), encrypted, cancellationToken).ConfigureAwait(false);
        CryptographicOperations.ZeroMemory(plaintext);
    }

    public async Task<string?> GetAsync(string key, CancellationToken cancellationToken = default)
    {
        var path = PathFor(key);
        if (!File.Exists(path))
            return null;
        var encrypted = await File.ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false);
        var plaintext = ProtectedData.Unprotect(encrypted, Entropy(key), DataProtectionScope.CurrentUser);
        try { return Encoding.UTF8.GetString(plaintext); }
        finally { CryptographicOperations.ZeroMemory(plaintext); }
    }

    public Task RemoveAsync(string key, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        var path = PathFor(key);
        if (File.Exists(path)) File.Delete(path);
        return Task.CompletedTask;
    }

    private string PathFor(string key) => Path.Combine(_directory, Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(key))) + ".secret");
    private static byte[] Entropy(string key) => SHA256.HashData(Encoding.UTF8.GetBytes("LumaTunnel:" + key));
}