Add /api/pair-code (auth) + /api/pair (public) endpoints

This commit is contained in:
2026-06-11 18:56:41 +00:00
parent db5c4e59a4
commit b5be4c6914
3 changed files with 125 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
namespace backend.Pairing;
public record IssueCodeRequest(string Name);
public record PairRequest(string Code, string Hostname, string Client_version);
public static class PairingEndpoints
{
public static IEndpointRouteBuilder MapPairingEndpoints(this IEndpointRouteBuilder app)
{
app.MapPost("/api/pair-code", async (
[FromBody] IssueCodeRequest req,
PairingService svc,
HttpContext http,
CancellationToken ct) =>
{
var uidStr = http.User.FindFirstValue(ClaimTypes.NameIdentifier);
if (!Guid.TryParse(uidStr, out var uid)) return Results.Unauthorized();
if (string.IsNullOrWhiteSpace(req.Name))
return Results.BadRequest(new { error = "name is required" });
var pc = await svc.IssueAsync(uid, req.Name.Trim(), ct);
return Results.Ok(new { code = pc.Code, expires_at = pc.ExpiresAt });
}).RequireAuthorization();
app.MapPost("/api/pair", async (
[FromBody] PairRequest req,
PairingService svc,
HttpContext http,
CancellationToken ct) =>
{
var result = await svc.ConsumeAsync(req.Code, ct);
if (result is null) return Results.NotFound(new { error = "code invalid or expired" });
var scheme = http.Request.Scheme == "https" ? "wss" : "ws";
var host = http.Request.Host.ToString();
return Results.Ok(new
{
device_id = result.DeviceId,
device_token = result.DeviceToken,
backend_ws = $"{scheme}://{host}/device",
});
});
return app;
}
}
+5
View File
@@ -1,5 +1,6 @@
using backend.Auth;
using backend.Data;
using backend.Pairing;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
@@ -10,6 +11,9 @@ builder.Services.AddDbContext<AppDbContext>(opt =>
builder.Services.AddAppIdentity();
builder.Services.AddAuthorization();
builder.Services.AddScoped<backend.Devices.DeviceTokenService>();
builder.Services.AddScoped<backend.Pairing.PairingService>();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
@@ -30,6 +34,7 @@ app.UseAuthentication();
app.UseAuthorization();
app.MapAuthEndpoints();
app.MapPairingEndpoints();
app.MapGet("/health", () => Results.Ok(new { ok = true }));