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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Security.Principal;
using System.Text;

namespace XFEEDToolBox.Plugin;

internal static unsafe class PipeServer
{
    private static readonly UTF8Encoding Utf8 = new(false, true);
    [StructLayout(LayoutKind.Sequential)]
    private struct SecurityAttributes { internal uint Length; internal nint Descriptor; internal int Inherit; }

    internal static void StartJson(string service, int capacity, Func<JsonElement, JsonNode?> handler) => Start(service, capacity, text =>
    {
        try
        {
            using var document = JsonDocument.Parse(text);
            return Obj(("ok", true), ("result", handler(document.RootElement)));
        }
        catch (Exception error) { return Obj(("ok", false), ("error", error.Message)); }
    });

    internal static void Start(string service, int capacity, Func<string, JsonNode?> handler)
    {
        var worker = new Thread(() => Serve(service, capacity, handler)) { IsBackground = true, Name = "XFEEDToolBox." + service };
        worker.Start();
    }

    private static void Serve(string service, int capacity, Func<string, JsonNode?> handler)
    {
        nint descriptor = 0;
        try
        {
            using var identity = WindowsIdentity.GetCurrent();
            var sid = identity.User?.Value;
            if (sid is null || !ConvertStringSecurityDescriptorToSecurityDescriptorW("D:P(A;;GA;;;" + sid + ")", 1, out descriptor, out _)) return;
            var security = new SecurityAttributes { Length = (uint)sizeof(SecurityAttributes), Descriptor = descriptor };
            var name = @"\\.\pipe\XFEEDToolBox." + service + "." + ProcessId;
            var buffer = new byte[capacity];
            var requestCapacity = service switch { "Plugin" => 1023, "Navigation" => 65535, _ => capacity };
            for (;;)
            {
                // Message mode and PIPE_REJECT_REMOTE_CLIENTS preserve the old local IPC boundary.
                var pipe = CreateNamedPipeW(name, 3, 0x2 | 0x4 | 0x8, 1, (uint)capacity, (uint)capacity, 1000, ref security);
                if (pipe == new nint(-1)) return;
                try
                {
                    if (!ConnectNamedPipe(pipe, 0) && Marshal.GetLastWin32Error() != 535) continue;
                    uint count;
                    fixed (byte* input = buffer)
                    {
                        if (!ReadFile(pipe, input, (uint)requestCapacity, out count, 0)) continue;
                    }
                    JsonNode? response;
                    try { response = handler(Utf8.GetString(buffer, 0, checked((int)count))); }
                    catch (Exception error) { response = Obj(("ok", false), ("error", error.Message)); }
                    string json;
                    try { json = response?.ToJsonString() ?? "null"; }
                    catch (Exception error) { json = Obj(("ok", false), ("error", error.Message)).ToJsonString(); }
                    var bytes = Encoding.UTF8.GetBytes(json + "\n");
                    fixed (byte* output = bytes)
                        if (WriteFile(pipe, output, (uint)bytes.Length, out var written, 0) && written == bytes.Length) FlushFileBuffers(pipe);
                }
                catch (Exception) { /* Reject one failed connection without retiring the service. */ }
                finally { DisconnectNamedPipe(pipe); CloseHandle(pipe); }
            }
        }
        catch (Exception) { /* A companion service failure must not escape into the host. */ }
        finally { if (descriptor != 0) LocalFree(descriptor); }
    }
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptorW(string sddl, uint revision, out nint descriptor, out uint size);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern nint CreateNamedPipeW(string name, uint access, uint mode, uint instances, uint outputSize, uint inputSize, uint timeout, ref SecurityAttributes security);
    [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ConnectNamedPipe(nint pipe, nint overlapped);
    [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ReadFile(nint handle, byte* buffer, uint size, out uint count, nint overlapped);
    [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool WriteFile(nint handle, byte* buffer, uint size, out uint count, nint overlapped);
    [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FlushFileBuffers(nint pipe);
    [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DisconnectNamedPipe(nint pipe);
    [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(nint handle);
    [DllImport("kernel32.dll")] private static extern nint LocalFree(nint address);
}