feat(backend): move internal endpoints to /api/internal

This commit is contained in:
sam 2024-10-02 00:15:14 +02:00
parent eac0a17473
commit 06f7019330
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
9 changed files with 39 additions and 27 deletions

View file

@ -1,14 +1,18 @@
using System.Web; using System.Web;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Extensions;
using Foxnouns.Backend.Middleware;
using Foxnouns.Backend.Services; using Foxnouns.Backend.Services;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
using NodaTime; using NodaTime;
namespace Foxnouns.Backend.Controllers.Authentication; namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth")] [Route("/api/internal/auth")]
public class AuthController(Config config, KeyCacheService keyCache, ILogger logger) : ApiControllerBase public class AuthController(Config config, DatabaseContext db, KeyCacheService keyCache, ILogger logger)
: ApiControllerBase
{ {
private readonly ILogger _logger = logger.ForContext<AuthController>(); private readonly ILogger _logger = logger.ForContext<AuthController>();
@ -61,4 +65,15 @@ public class AuthController(Config config, KeyCacheService keyCache, ILogger log
public record OauthRegisterRequest(string Ticket, string Username); public record OauthRegisterRequest(string Ticket, string Username);
public record CallbackRequest(string Code, string State); public record CallbackRequest(string Code, string State);
[HttpPost("force-log-out")]
[Authorize("identify")]
public async Task<IActionResult> ForceLogoutAsync()
{
_logger.Information("Invalidating all tokens for user {UserId}", CurrentUser!.Id);
await db.Tokens.Where(t => t.UserId == CurrentUser.Id)
.ExecuteUpdateAsync(s => s.SetProperty(t => t.ManuallyExpired, true));
return NoContent();
}
} }

View file

@ -10,7 +10,7 @@ using NodaTime;
namespace Foxnouns.Backend.Controllers.Authentication; namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth/discord")] [Route("/api/internal/auth/discord")]
public class DiscordAuthController( public class DiscordAuthController(
[UsedImplicitly] Config config, [UsedImplicitly] Config config,
ILogger logger, ILogger logger,

View file

@ -1,6 +1,7 @@
using Foxnouns.Backend.Database; using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Database.Models;
using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Extensions;
using Foxnouns.Backend.Middleware;
using Foxnouns.Backend.Services; using Foxnouns.Backend.Services;
using Foxnouns.Backend.Utils; using Foxnouns.Backend.Utils;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -10,7 +11,7 @@ using NodaTime;
namespace Foxnouns.Backend.Controllers.Authentication; namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth/email")] [Route("/api/internal/auth/email")]
public class EmailAuthController( public class EmailAuthController(
[UsedImplicitly] Config config, [UsedImplicitly] Config config,
DatabaseContext db, DatabaseContext db,
@ -123,6 +124,17 @@ public class EmailAuthController(
)); ));
} }
[HttpPost("add")]
[Authorize("*")]
public async Task<IActionResult> AddEmailAddressAsync()
{
_logger.Information("beep");
return NoContent();
}
public record AddEmailAddressRequest(string Email, string Password);
private void CheckRequirements() private void CheckRequirements()
{ {
if (!config.EmailAuth.Enabled) if (!config.EmailAuth.Enabled)

View file

@ -1,35 +1,17 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Foxnouns.Backend.Database; using Foxnouns.Backend.Database;
using Foxnouns.Backend.Middleware;
using Foxnouns.Backend.Utils; using Foxnouns.Backend.Utils;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Template;
using Microsoft.EntityFrameworkCore;
namespace Foxnouns.Backend.Controllers; namespace Foxnouns.Backend.Controllers;
[ApiController] [ApiController]
[Route("/api/internal")] [Route("/api/internal")]
public partial class InternalController(ILogger logger, DatabaseContext db) : ControllerBase public partial class InternalController(DatabaseContext db) : ControllerBase
{ {
private readonly ILogger _logger = logger.ForContext<InternalController>();
[HttpPost("force-log-out")]
[Authenticate]
[Authorize("identify")]
public async Task<IActionResult> ForceLogoutAsync()
{
var user = HttpContext.GetUser()!;
_logger.Information("Invalidating all tokens for user {UserId}", user.Id);
await db.Tokens.Where(t => t.UserId == user.Id)
.ExecuteUpdateAsync(s => s.SetProperty(t => t.ManuallyExpired, true));
return NoContent();
}
[GeneratedRegex(@"(\{\w+\})")] [GeneratedRegex(@"(\{\w+\})")]
private static partial Regex PathVarRegex(); private static partial Regex PathVarRegex();

View file

@ -27,7 +27,7 @@ public static class AuthUtils
public static string[] ExpandScopes(this string[] scopes) public static string[] ExpandScopes(this string[] scopes)
{ {
if (scopes.Contains("*")) return Scopes; if (scopes.Contains("*")) return ["*", ..Scopes];
List<string> expandedScopes = ["identify"]; List<string> expandedScopes = ["identify"];
if (scopes.Contains("user")) expandedScopes.AddRange(UserScopes); if (scopes.Contains("user")) expandedScopes.AddRange(UserScopes);
if (scopes.Contains("member")) expandedScopes.AddRange(MemberScopes); if (scopes.Contains("member")) expandedScopes.AddRange(MemberScopes);

View file

@ -16,7 +16,7 @@ async function requestInternal(
path: string, path: string,
params: RequestParams = {}, params: RequestParams = {},
): Promise<Response> { ): Promise<Response> {
const base = params.isInternal ? INTERNAL_API_BASE : API_BASE + "/v2"; const base = params.isInternal ? INTERNAL_API_BASE + "/internal" : API_BASE + "/v2";
const url = `${base}${path}`; const url = `${base}${path}`;
const resp = await fetch(url, { const resp = await fetch(url, {

View file

@ -43,6 +43,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const resp = await serverRequest<CallbackResponse>("POST", "/auth/discord/callback", { const resp = await serverRequest<CallbackResponse>("POST", "/auth/discord/callback", {
body: { code, state }, body: { code, state },
isInternal: true,
}); });
if (resp.has_account) { if (resp.has_account) {
@ -89,6 +90,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
try { try {
const resp = await serverRequest<AuthResponse>("POST", "/auth/discord/register", { const resp = await serverRequest<AuthResponse>("POST", "/auth/discord/register", {
body: { username, ticket }, body: { username, ticket },
isInternal: true,
}); });
return redirect("/auth/welcome", { return redirect("/auth/welcome", {

View file

@ -41,7 +41,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
} }
} }
const urls = await serverRequest<AuthUrls>("POST", "/auth/urls"); const urls = await serverRequest<AuthUrls>("POST", "/auth/urls", { isInternal: true });
return json({ return json({
meta: { title: t("log-in.title") }, meta: { title: t("log-in.title") },
@ -57,6 +57,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
try { try {
const resp = await serverRequest<AuthResponse>("POST", "/auth/email/login", { const resp = await serverRequest<AuthResponse>("POST", "/auth/email/login", {
body: { email, password }, body: { email, password },
isInternal: true,
}); });
return redirect("/", { return redirect("/", {

View file

@ -10,7 +10,7 @@ export const action: ActionFunction = async ({ request }) => {
headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) }, headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) },
}); });
await fastRequest("POST", "/internal/force-log-out", { token, isInternal: true }); await fastRequest("POST", "/auth/force-log-out", { token, isInternal: true });
return redirect("/", { return redirect("/", {
status: 303, status: 303,