diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json deleted file mode 100644 index 4a287b1..0000000 --- a/.config/dotnet-tools.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "husky": { - "version": "0.7.1", - "commands": ["husky"], - "rollForward": false - } - } -} diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index fd85d23..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -## husky task runner examples ------------------- -## Note : for local installation use 'dotnet' prefix. e.g. 'dotnet husky' - -## run all tasks -#husky run - -### run all tasks with group: 'group-name' -#husky run --group group-name - -## run task with name: 'task-name' -#husky run --name task-name - -## pass hook arguments to task -#husky run --args "$1" "$2" - -## or put your custom commands ------------------- -#echo 'Husky.Net is awesome!' - -dotnet husky run diff --git a/.husky/task-runner.json b/.husky/task-runner.json deleted file mode 100644 index 8ebba21..0000000 --- a/.husky/task-runner.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://alirezanet.github.io/Husky.Net/schema.json", - "tasks": [ - { - "name": "run-prettier", - "command": "yarn", - "args": ["format"], - "pathMode": "absolute" - }, - { - "name": "dotnet-format", - "command": "dotnet", - "args": ["format"] - } - ] -} diff --git a/.idea/.idea.Foxnouns.NET/.idea/jsLinters/eslint.xml b/.idea/.idea.Foxnouns.NET/.idea/jsLinters/eslint.xml index 5f8621e..204acf7 100644 --- a/.idea/.idea.Foxnouns.NET/.idea/jsLinters/eslint.xml +++ b/.idea/.idea.Foxnouns.NET/.idea/jsLinters/eslint.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/.idea/.idea.Foxnouns.NET/.idea/prettier.xml b/.idea/.idea.Foxnouns.NET/.idea/prettier.xml index ffcf89b..653a9e0 100644 --- a/.idea/.idea.Foxnouns.NET/.idea/prettier.xml +++ b/.idea/.idea.Foxnouns.NET/.idea/prettier.xml @@ -1,7 +1,7 @@ - + diff --git a/Foxnouns.Backend/Controllers/Authentication/AuthController.cs b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs index e8b3e76..b9570c0 100644 --- a/Foxnouns.Backend/Controllers/Authentication/AuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs @@ -1,18 +1,14 @@ using System.Web; -using Foxnouns.Backend.Database; using Foxnouns.Backend.Extensions; -using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using NodaTime; namespace Foxnouns.Backend.Controllers.Authentication; -[Route("/api/internal/auth")] -public class AuthController(Config config, DatabaseContext db, KeyCacheService keyCache, ILogger logger) - : ApiControllerBase +[Route("/api/v2/auth")] +public class AuthController(Config config, KeyCacheService keyCache, ILogger logger) : ApiControllerBase { private readonly ILogger _logger = logger.ForContext(); @@ -65,15 +61,4 @@ public class AuthController(Config config, DatabaseContext db, KeyCacheService k public record OauthRegisterRequest(string Ticket, string Username); public record CallbackRequest(string Code, string State); - - [HttpPost("force-log-out")] - [Authorize("identify")] - public async Task 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(); - } } \ No newline at end of file diff --git a/Foxnouns.Backend/Controllers/Authentication/DiscordAuthController.cs b/Foxnouns.Backend/Controllers/Authentication/DiscordAuthController.cs index f08569a..a1c3eed 100644 --- a/Foxnouns.Backend/Controllers/Authentication/DiscordAuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/DiscordAuthController.cs @@ -10,7 +10,7 @@ using NodaTime; namespace Foxnouns.Backend.Controllers.Authentication; -[Route("/api/internal/auth/discord")] +[Route("/api/v2/auth/discord")] public class DiscordAuthController( [UsedImplicitly] Config config, ILogger logger, diff --git a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs index 251fb5f..1649948 100644 --- a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs @@ -1,7 +1,6 @@ using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Extensions; -using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; using Foxnouns.Backend.Utils; using JetBrains.Annotations; @@ -11,7 +10,7 @@ using NodaTime; namespace Foxnouns.Backend.Controllers.Authentication; -[Route("/api/internal/auth/email")] +[Route("/api/v2/auth/email")] public class EmailAuthController( [UsedImplicitly] Config config, DatabaseContext db, @@ -124,20 +123,9 @@ public class EmailAuthController( )); } - [HttpPost("add")] - [Authorize("*")] - public async Task AddEmailAddressAsync() - { - _logger.Information("beep"); - - return NoContent(); - } - - public record AddEmailAddressRequest(string Email, string Password); - private void CheckRequirements() { - if (!config.EmailAuth.Enabled) + if (!config.DiscordAuth.Enabled) throw new ApiError.BadRequest("Email authentication is not enabled on this instance."); } diff --git a/Foxnouns.Backend/Controllers/UsersController.cs b/Foxnouns.Backend/Controllers/UsersController.cs index fb0e301..9a182f4 100644 --- a/Foxnouns.Backend/Controllers/UsersController.cs +++ b/Foxnouns.Backend/Controllers/UsersController.cs @@ -186,8 +186,7 @@ public class UsersController( if (preferences.Count > MaxCustomPreferences) errors.Add(("custom_preferences", - ValidationError.LengthError("Too many custom preferences", 0, MaxCustomPreferences, - preferences.Count))); + ValidationError.LengthError("Too many custom preferences", 0, MaxCustomPreferences, preferences.Count))); if (preferences.Count > 50) return errors; // TODO: validate individual preferences diff --git a/Foxnouns.Backend/Utils/AuthUtils.cs b/Foxnouns.Backend/Utils/AuthUtils.cs index c7bd717..c767198 100644 --- a/Foxnouns.Backend/Utils/AuthUtils.cs +++ b/Foxnouns.Backend/Utils/AuthUtils.cs @@ -27,7 +27,7 @@ public static class AuthUtils public static string[] ExpandScopes(this string[] scopes) { - if (scopes.Contains("*")) return ["*", ..Scopes]; + if (scopes.Contains("*")) return Scopes; List expandedScopes = ["identify"]; if (scopes.Contains("user")) expandedScopes.AddRange(UserScopes); if (scopes.Contains("member")) expandedScopes.AddRange(MemberScopes); diff --git a/Foxnouns.Backend/Utils/ValidationUtils.cs b/Foxnouns.Backend/Utils/ValidationUtils.cs index 2dd52b9..392e5ed 100644 --- a/Foxnouns.Backend/Utils/ValidationUtils.cs +++ b/Foxnouns.Backend/Utils/ValidationUtils.cs @@ -289,7 +289,6 @@ public static partial class ValidationUtils [GeneratedRegex(@"^[a-zA-Z_0-9\-\.]{2,40}$", RegexOptions.IgnoreCase, "en-NL")] private static partial Regex UsernameRegex(); - [GeneratedRegex("""^[^@'$%&()+<=>^|~`,*!#/\\\[\]""\{\}\?]{1,100}$""", RegexOptions.IgnoreCase, "en-NL")] private static partial Regex MemberRegex(); } \ No newline at end of file diff --git a/Foxnouns.Frontend/app/env.server.ts b/Foxnouns.Frontend/app/env.server.ts index 5e5e84b..2add747 100644 --- a/Foxnouns.Frontend/app/env.server.ts +++ b/Foxnouns.Frontend/app/env.server.ts @@ -2,5 +2,4 @@ import "dotenv/config"; import { env } from "node:process"; export const API_BASE = env.API_BASE || "https://pronouns.localhost/api"; -export const INTERNAL_API_BASE = env.INTERNAL_API_BASE || "https://localhost:5000/api"; export const LANGUAGE = env.LANGUAGE || "en"; diff --git a/Foxnouns.Frontend/app/lib/request.server.ts b/Foxnouns.Frontend/app/lib/request.server.ts index c92f67d..4648d5f 100644 --- a/Foxnouns.Frontend/app/lib/request.server.ts +++ b/Foxnouns.Frontend/app/lib/request.server.ts @@ -1,5 +1,5 @@ import { parse as parseCookie, serialize as serializeCookie } from "cookie"; -import { API_BASE, INTERNAL_API_BASE } from "~/env.server"; +import { API_BASE } from "~/env.server"; import { ApiError, ErrorCode } from "./api/error"; import { tokenCookieName } from "~/lib/utils"; @@ -8,17 +8,14 @@ export type RequestParams = { // eslint-disable-next-line @typescript-eslint/no-explicit-any body?: any; headers?: Record; - isInternal?: boolean; }; -async function requestInternal( +export default async function serverRequest( method: string, path: string, params: RequestParams = {}, -): Promise { - const base = params.isInternal ? INTERNAL_API_BASE + "/internal" : API_BASE + "/v2"; - - const url = `${base}${path}`; +) { + const url = `${API_BASE}/v2${path}`; const resp = await fetch(url, { method, body: params.body ? JSON.stringify(params.body) : undefined, @@ -40,19 +37,6 @@ async function requestInternal( } if (resp.status < 200 || resp.status >= 400) throw (await resp.json()) as ApiError; - return resp; -} - -export async function fastRequest(method: string, path: string, params: RequestParams = {}) { - await requestInternal(method, path, params); -} - -export default async function serverRequest( - method: string, - path: string, - params: RequestParams = {}, -) { - const resp = await requestInternal(method, path, params); return (await resp.json()) as T; } diff --git a/Foxnouns.Frontend/app/routes/auth.callback.discord/route.tsx b/Foxnouns.Frontend/app/routes/auth.callback.discord/route.tsx index 5fb246c..c5200fd 100644 --- a/Foxnouns.Frontend/app/routes/auth.callback.discord/route.tsx +++ b/Foxnouns.Frontend/app/routes/auth.callback.discord/route.tsx @@ -43,7 +43,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { const resp = await serverRequest("POST", "/auth/discord/callback", { body: { code, state }, - isInternal: true, }); if (resp.has_account) { @@ -90,7 +89,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { try { const resp = await serverRequest("POST", "/auth/discord/register", { body: { username, ticket }, - isInternal: true, }); return redirect("/auth/welcome", { diff --git a/Foxnouns.Frontend/app/routes/auth.log-in/route.tsx b/Foxnouns.Frontend/app/routes/auth.log-in/route.tsx index eadbaa9..fc25d75 100644 --- a/Foxnouns.Frontend/app/routes/auth.log-in/route.tsx +++ b/Foxnouns.Frontend/app/routes/auth.log-in/route.tsx @@ -41,7 +41,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { } } - const urls = await serverRequest("POST", "/auth/urls", { isInternal: true }); + const urls = await serverRequest("POST", "/auth/urls"); return json({ meta: { title: t("log-in.title") }, @@ -57,7 +57,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { try { const resp = await serverRequest("POST", "/auth/email/login", { body: { email, password }, - isInternal: true, }); return redirect("/", { diff --git a/Foxnouns.Frontend/app/routes/settings._index/route.tsx b/Foxnouns.Frontend/app/routes/settings._index/route.tsx index 5b90851..d575108 100644 --- a/Foxnouns.Frontend/app/routes/settings._index/route.tsx +++ b/Foxnouns.Frontend/app/routes/settings._index/route.tsx @@ -1,6 +1,6 @@ import { Button, Form, InputGroup, Table } from "react-bootstrap"; import { useTranslation } from "react-i18next"; -import { Form as RemixForm, useActionData, useFetcher, useRouteLoaderData } from "@remix-run/react"; +import { Form as RemixForm, useActionData, useRouteLoaderData } from "@remix-run/react"; import { loader as settingsLoader } from "../settings/route"; import { loader as rootLoader } from "../../root"; import { DateTime } from "luxon"; @@ -43,7 +43,6 @@ export default function SettingsIndex() { const actionData = useActionData(); const { meta } = useRouteLoaderData("root")!; const { t } = useTranslation(); - const fetcher = useFetcher(); const createdAt = idTimestamp(user.id); @@ -56,7 +55,13 @@ export default function SettingsIndex() { {t("settings.general.username")} - + {t("settings.general.change-username")} @@ -80,14 +85,9 @@ export default function SettingsIndex() { {t("settings.general.log-out-everywhere")} - {t("settings.general.log-out-everywhere-hint")} - - - {t("settings.general.force-log-out-button")} - - + - {t("settings.general.table-header")} + {t("settings.general.table-header")} diff --git a/Foxnouns.Frontend/app/routes/settings.force-log-out/route.tsx b/Foxnouns.Frontend/app/routes/settings.force-log-out/route.tsx deleted file mode 100644 index 608761b..0000000 --- a/Foxnouns.Frontend/app/routes/settings.force-log-out/route.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { ActionFunction, redirect } from "@remix-run/node"; -import { fastRequest, getToken, writeCookie } from "~/lib/request.server"; -import { tokenCookieName } from "~/lib/utils"; - -export const action: ActionFunction = async ({ request }) => { - const token = getToken(request); - if (!token) - return redirect("/", { - status: 303, - headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) }, - }); - - await fastRequest("POST", "/auth/force-log-out", { token, isInternal: true }); - - return redirect("/", { - status: 303, - headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) }, - }); -}; diff --git a/Foxnouns.Frontend/public/locales/en.json b/Foxnouns.Frontend/public/locales/en.json index c35a1d7..279173b 100644 --- a/Foxnouns.Frontend/public/locales/en.json +++ b/Foxnouns.Frontend/public/locales/en.json @@ -96,8 +96,6 @@ "change-username": "Change username", "username-change-hint": "Changing your username will make any existing links to your or your members' profiles invalid.\nYour username must be unique, be at most 40 characters long, and only contain letters from the basic English alphabet, dashes, underscores, and periods. Your username is used as part of your profile link, you can set a separate display name.", "log-out-everywhere": "Log out everywhere", - "log-out-everywhere-hint": "If you think one of your tokens might have been compromised, you can log out on all devices by clicking this button.", - "force-log-out-button": "Force log out", "table-header": "General account information", "id": "Your user ID", "created": "Account created at", diff --git a/docker-compose.yml b/docker-compose.yml index 6fafd18..7176fc2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,6 @@ services: build: ./Foxnouns.Frontend environment: - "API_BASE=http://rate:5003/api" - - "INTERNAL_API_BASE=http://backend:5000/api" restart: unless-stopped volumes: - ./docker/frontend.env:/app/.env diff --git a/migrators/NetImporter/ImportUser.cs b/migrators/NetImporter/ImportUser.cs index 9547980..3524fad 100644 --- a/migrators/NetImporter/ImportUser.cs +++ b/migrators/NetImporter/ImportUser.cs @@ -112,12 +112,12 @@ public static class Users foreach (var field in oldUser.Fields ?? []) { var entries = field.Entries.Select(entry => new FieldEntry - { - Value = entry.Value, - Status = prefMapping.TryGetValue(entry.Status, out var newStatus) + { + Value = entry.Value, + Status = prefMapping.TryGetValue(entry.Status, out var newStatus) ? newStatus.ToString() : entry.Status, - }) + }) .ToList(); user.Fields.Add(new Field diff --git a/package.json b/package.json index 4c05b19..da7f5dc 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "concurrently": "^9.0.1" }, "scripts": { - "dev": "concurrently -n .net,node,rate -c magenta,yellow,blue -i 'cd Foxnouns.Backend && dotnet watch --no-hot-reload' 'cd Foxnouns.Frontend && yarn dev' 'cd rate && go run -v .'", - "format": "cd Foxnouns.Frontend && yarn format" + "dev": "concurrently -n .net,node,rate -c magenta,yellow,blue -i 'cd Foxnouns.Backend && dotnet watch --no-hot-reload' 'cd Foxnouns.Frontend && yarn dev' 'cd rate && go run -v .'" } }
{t("settings.general.log-out-everywhere-hint")}