V14 / fad4e1a110e5
LocalBridgeApi.cs
Services/MessageBridge/LocalBridgeApi.cs
Changed in this versionCS
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;
}
}