Files
ClaudeDo/src/ClaudeDo.Worker/Planning/PlanningTokenAuth.cs
2026-06-04 15:57:12 +02:00

50 lines
1.6 KiB
C#

using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Runner;
using Microsoft.AspNetCore.Http;
namespace ClaudeDo.Worker.Planning;
public sealed class PlanningTokenAuthMiddleware
{
private readonly RequestDelegate _next;
public PlanningTokenAuthMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext ctx, TaskRepository tasks, TaskRunTokenRegistry runTokens)
{
if (!ctx.Request.Path.StartsWithSegments("/mcp"))
{
await _next(ctx);
return;
}
var auth = ctx.Request.Headers["Authorization"].ToString();
if (!auth.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
ctx.Response.StatusCode = 401;
await ctx.Response.WriteAsync("Missing bearer token");
return;
}
var token = auth.Substring("Bearer ".Length).Trim();
var parent = await tasks.FindByPlanningTokenAsync(token, ctx.RequestAborted);
if (parent is not null && parent.PlanningPhase == ClaudeDo.Data.Models.PlanningPhase.Active)
{
ctx.Items["PlanningContext"] = new PlanningMcpContext { ParentTaskId = parent.Id };
await _next(ctx);
return;
}
if (runTokens.TryResolve(token, out var callerTaskId))
{
ctx.Items["TaskRunContext"] = new TaskRunMcpContext { CallerTaskId = callerTaskId };
await _next(ctx);
return;
}
ctx.Response.StatusCode = 401;
await ctx.Response.WriteAsync("Invalid or expired token");
}
}