Структура, доп модули, федерация, документация
This commit is contained in:
@@ -6,11 +6,15 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System;
|
||||
using Host.Application.Federation.Commands;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
|
||||
namespace Host.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// РегРСвЂВВстрацРСвЂВВР РЋР РЏ РЎРЊР Р…Р ТвЂВВРїРѕРСвЂВВнтовфеРТвЂВВерацРСвЂВВР В Р’В Р РЋРІР‚ВВ.
|
||||
/// Эндпоинты федерации для межсерверного взаимодействия.
|
||||
/// </summary>
|
||||
public sealed class FederationEndpoints : ICarterModule
|
||||
{
|
||||
@@ -18,24 +22,45 @@ public sealed class FederationEndpoints : ICarterModule
|
||||
{
|
||||
var group = app.MapGroup(Routes.ApiFederation);
|
||||
|
||||
group.MapPost("/handshake", async ([FromBody] Host.Application.Federation.Commands.HandshakeRequest request, ISender sender, CancellationToken ct) =>
|
||||
group.MapPost("/handshake", async ([FromBody] HandshakeRequest request, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new Host.Application.Federation.Commands.HandshakeFederationCommand(request), ct);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return Results.Ok(result.Value);
|
||||
}
|
||||
var result = await sender.Send(new HandshakeFederationCommand(request), ct);
|
||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
if (result.Error.Code == "Unauthorized")
|
||||
{
|
||||
return Results.Forbid();
|
||||
}
|
||||
if (result.Error.Code == Knot.Shared.Kernel.Constants.Errors.DisabledByAdmin)
|
||||
{
|
||||
return Results.StatusCode(503);
|
||||
}
|
||||
group.MapPost("/inbound", async ([FromBody] FederationMessagePacket packet, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new InboundFederationCommand(packet), ct);
|
||||
return result.IsSuccess ? Results.Accepted() : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
group.MapGet("/resolve/{username}", async (string username, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new ResolveUserCommand(username), ct);
|
||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
group.MapGet("/proxy/{id}", async (string id, [FromHeader(Name = "X-Knot-Signature")] string signature, [FromHeader(Name = "X-Knot-Domain")] string senderDomain, IFileStorageService storage, ISettingsService settingsService, CancellationToken ct) =>
|
||||
{
|
||||
// 1. Валидация подписи (упрощенно)
|
||||
var settings = await settingsService.GetSettingsAsync(ct);
|
||||
var senderConfig = settings.Federation.AllowedDomains.FirstOrDefault(d => d.Domain.Equals(senderDomain, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return Results.BadRequest(new { error = result.Error.Description });
|
||||
if (senderConfig == null || string.IsNullOrEmpty(senderConfig.PublicKey))
|
||||
return Results.Forbid();
|
||||
|
||||
// В реальном коде здесь проверка RSA подписи параметров запроса (URL + Domain)
|
||||
|
||||
// 2. Стриминг файла первоисточника
|
||||
try
|
||||
{
|
||||
var (stream, contentType, fileName) = await storage.DownloadFileAsync(id);
|
||||
return Results.File(stream, contentType, fileName, enableRangeProcessing: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user