feat: implement DirectoryClaimStore for managing directory claims and enhance ServerDirectoryService with registration error handling

This commit is contained in:
HueByte
2026-04-24 15:51:01 +02:00
parent 1bbe099835
commit 67587dafc2
4 changed files with 365 additions and 6 deletions
@@ -1,5 +1,8 @@
using System.Security.Claims;
using EchoHub.Core.DTOs;
using EchoHub.Core.Models;
using EchoHub.Server.Data;
using EchoHub.Server.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
@@ -13,11 +16,13 @@ public class ServerController : ControllerBase
{
private readonly EchoHubDbContext _db;
private readonly IConfiguration _config;
private readonly DirectoryClaimStore _claimStore;
public ServerController(EchoHubDbContext db, IConfiguration config)
public ServerController(EchoHubDbContext db, IConfiguration config, DirectoryClaimStore claimStore)
{
_db = db;
_config = config;
_claimStore = claimStore;
}
[HttpGet("info")]
@@ -47,4 +52,46 @@ public class ServerController : ControllerBase
return Ok(new EncryptionKeyResponse(key));
}
/// <summary>
/// Operator-facing view of the EchoHubSpace directory registration: ServerId for admin
/// support tickets, current registration state, and the last error/conflict if any.
/// Never exposes the claim token itself.
/// </summary>
[HttpGet("directory")]
[Authorize]
public async Task<IActionResult> GetDirectoryStatus()
{
var (_, error) = await GetCallerAsync(ServerRole.Admin);
if (error is not null) return error;
var status = _claimStore.Status;
var response = new
{
ServerId = _claimStore.ServerId,
HasClaimToken = _claimStore.ClaimToken is not null,
status.IsRegistered,
status.LastRegisteredAt,
status.LastError,
status.ConflictingHosts,
};
return Ok(response);
}
private async Task<(User? Caller, IActionResult? Error)> GetCallerAsync(ServerRole minimumRole)
{
var userIdClaim = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (userIdClaim is null)
return (null, Unauthorized(new ErrorResponse("Authentication required.")));
var caller = await _db.Users.FindAsync(Guid.Parse(userIdClaim));
if (caller is null)
return (null, Unauthorized(new ErrorResponse("User not found.")));
if (caller.Role < minimumRole)
return (null, StatusCode(403, new ErrorResponse($"Requires {minimumRole} role or higher.")));
return (caller, null);
}
}