feat(backend): move internal endpoints to /api/internal
This commit is contained in:
parent
eac0a17473
commit
06f7019330
9 changed files with 39 additions and 27 deletions
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, {
|
||||||
|
|
|
@ -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", {
|
||||||
|
|
|
@ -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("/", {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue