← All source files

V14 / fad4e1a110e5

LocalBridgeApi.cs

Services/MessageBridge/LocalBridgeApi.cs

Changed in this version
CS
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace Lilith.MessageBridge;

public static class LocalBridgeApi
{
    public static WebApplication Create(BridgeStore store, string token, int port)
    {
        if (token.Length is < 32 or > 256 || token.Any(char.IsControl) || port is < 1024 or > 65535) throw new ArgumentException("Configure bridge token and port.");
        var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = [] });
        builder.Logging.ClearProviders();
        builder.WebHost.ConfigureKestrel(o => { o.Listen(IPAddress.Loopback, port); o.Limits.MaxRequestBodySize = 16000; });
        var app = builder.Build();
        app.Use(async (context, next) =>
        {
            context.Response.Headers.CacheControl = "no-store";
            if (context.Request.Headers.ContainsKey("Origin") || context.Request.Host.Host != "127.0.0.1" || !IPAddress.IsLoopback(context.Connection.RemoteIpAddress ?? IPAddress.None)) { context.Response.StatusCode = 403; return; }
            if (!CryptographicOperations.FixedTimeEquals(SHA256.HashData(Encoding.UTF8.GetBytes("Bearer " + token)), SHA256.HashData(Encoding.UTF8.GetBytes(context.Request.Headers.Authorization.ToString())))) { context.Response.StatusCode = 401; return; }
            try { await next(context); }
            catch (Exception ex) when (ex is ArgumentException or InvalidOperationException or FileNotFoundException or BadHttpRequestException)
            { context.Response.StatusCode = 400; await context.Response.WriteAsJsonAsync(new { status = "error", code = "invalid_channel_request" }); }
        });
        foreach (string action in new[] { "channels", "inbox", "status", "proposal", "claim", "prepare", "send", "reject" })
        {
            string operation = action;
            app.MapPost("/api/v1/messages/" + operation, async (BridgeRequest request, CancellationToken ct) => Results.Json(await store.ExecuteAsync(operation, request, ct)));
        }
        return app;
    }
}