From 1f573a25536ad46a82f49e647c9e0904d5272962 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Fri, 9 May 2025 07:07:32 -0500 Subject: [PATCH] Added support for disabling password login and registration (#947) Signed-off-by: Fred Heinecke Signed-off-by: solidDoWant --- back/.env.example | 7 ++ .../Attributes/DisableOnEnvVarAttribute.cs | 22 +++++ .../Models/DTO/ServerInfo.cs | 10 ++ back/src/Kyoo.Authentication/Views/AuthApi.cs | 3 + back/src/Kyoo.Core/Views/InfoApi.cs | 12 ++- .../models/src/resources/server-info.ts | 8 ++ front/packages/ui/src/login/login.tsx | 88 +++++++++-------- front/packages/ui/src/login/oidc.tsx | 3 +- front/packages/ui/src/login/register.tsx | 96 +++++++++++-------- 9 files changed, 165 insertions(+), 84 deletions(-) create mode 100644 back/src/Kyoo.Authentication/Attributes/DisableOnEnvVarAttribute.cs diff --git a/back/.env.example b/back/.env.example index 0b3a2aef..42beea2d 100644 --- a/back/.env.example +++ b/back/.env.example @@ -4,6 +4,13 @@ # http route prefix (will listen to $KYOO_PREFIX/movie for example) KYOO_PREFIX="" + +# Optional authentication settings +# Set to true to disable login with password (OIDC auth must be configured) +# AUTHENTICATION_DISABLE_PASSWORD_LOGIN=true +# Set to true to disable the creation of new users (OIDC auth must be configured) +# AUTHENTICATION_DISABLE_USER_REGISTRATION=true + # Postgres settings # POSTGRES_URL=postgres://user:password@hostname:port/dbname?sslmode=verify-full&sslrootcert=/path/to/server.crt&sslcert=/path/to/client.crt&sslkey=/path/to/client.key # The behavior of the below variables match what is documented here: diff --git a/back/src/Kyoo.Authentication/Attributes/DisableOnEnvVarAttribute.cs b/back/src/Kyoo.Authentication/Attributes/DisableOnEnvVarAttribute.cs new file mode 100644 index 00000000..50e2e67d --- /dev/null +++ b/back/src/Kyoo.Authentication/Attributes/DisableOnEnvVarAttribute.cs @@ -0,0 +1,22 @@ +using System; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Kyoo.Authentication.Attributes; + +/// +/// Disables the action if the specified environment variable is set to true. +/// +public class DisableOnEnvVarAttribute(string varName) : Attribute, IResourceFilter +{ + public void OnResourceExecuting(ResourceExecutingContext context) + { + var config = context.HttpContext.RequestServices.GetRequiredService(); + + if (config.GetValue(varName, false)) + context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult(); + } + + public void OnResourceExecuted(ResourceExecutedContext context) { } +} diff --git a/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs b/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs index 6286cb7c..c7421a17 100644 --- a/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs +++ b/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs @@ -51,6 +51,16 @@ public class ServerInfo /// Check if kyoo's setup is finished. /// public SetupStep SetupStatus { get; set; } + + /// + /// True if password login is enabled on this instance. + /// + public bool PasswordLoginEnabled { get; set; } + + /// + /// True if registration is enabled on this instance. + /// + public bool RegistrationEnabled { get; set; } } public class OidcInfo diff --git a/back/src/Kyoo.Authentication/Views/AuthApi.cs b/back/src/Kyoo.Authentication/Views/AuthApi.cs index 550e1990..6fa1f4e9 100644 --- a/back/src/Kyoo.Authentication/Views/AuthApi.cs +++ b/back/src/Kyoo.Authentication/Views/AuthApi.cs @@ -26,6 +26,7 @@ using Kyoo.Abstractions.Models.Attributes; using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Abstractions.Models.Permissions; using Kyoo.Abstractions.Models.Utils; +using Kyoo.Authentication.Attributes; using Kyoo.Authentication.Models; using Kyoo.Authentication.Models.DTO; using Kyoo.Models; @@ -206,6 +207,7 @@ public class AuthApi( [HttpPost("login")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))] + [DisableOnEnvVar("AUTHENTICATION_DISABLE_PASSWORD_LOGIN")] public async Task> Login([FromBody] LoginRequest request) { User? user = await users.GetOrDefault( @@ -241,6 +243,7 @@ public class AuthApi( [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status409Conflict, Type = typeof(RequestError))] + [DisableOnEnvVar("AUTHENTICATION_DISABLE_USER_REGISTRATION")] public async Task> Register([FromBody] RegisterRequest request) { try diff --git a/back/src/Kyoo.Core/Views/InfoApi.cs b/back/src/Kyoo.Core/Views/InfoApi.cs index 48cd132d..ac0e2f22 100644 --- a/back/src/Kyoo.Core/Views/InfoApi.cs +++ b/back/src/Kyoo.Core/Views/InfoApi.cs @@ -23,6 +23,7 @@ using Kyoo.Abstractions.Models.Attributes; using Kyoo.Authentication.Models; using Kyoo.Core.Controllers; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; using static Kyoo.Abstractions.Models.Utils.Constants; namespace Kyoo.Authentication.Views; @@ -33,7 +34,8 @@ namespace Kyoo.Authentication.Views; [ApiController] [Route("info")] [ApiDefinition("Info", Group = UsersGroup)] -public class InfoApi(PermissionOption options, MiscRepository info) : ControllerBase +public class InfoApi(PermissionOption options, MiscRepository info, IConfiguration configuration) + : ControllerBase { public async Task> GetInfo() { @@ -51,6 +53,14 @@ public class InfoApi(PermissionOption options, MiscRepository info) : Controller )) .ToDictionary(x => x.Key, x => x.Value), SetupStatus = await info.GetSetupStep(), + PasswordLoginEnabled = !configuration.GetValue( + "AUTHENTICATION_DISABLE_PASSWORD_LOGIN", + false + ), + RegistrationEnabled = !configuration.GetValue( + "AUTHENTICATION_DISABLE_USER_REGISTRATION", + false + ), } ); } diff --git a/front/packages/models/src/resources/server-info.ts b/front/packages/models/src/resources/server-info.ts index 05fa90e6..d0319f13 100644 --- a/front/packages/models/src/resources/server-info.ts +++ b/front/packages/models/src/resources/server-info.ts @@ -61,6 +61,14 @@ export const ServerInfoP = z * Check if kyoo's setup is finished. */ setupStatus: z.nativeEnum(SetupStep), + /* + * True if password login is enabled on this instance. + */ + passwordLoginEnabled: z.boolean(), + /* + * True if registration is enabled on this instance. + */ + registrationEnabled: z.boolean(), }) .transform((x) => { const baseUrl = Platform.OS === "web" ? x.publicUrl : "kyoo://"; diff --git a/front/packages/ui/src/login/login.tsx b/front/packages/ui/src/login/login.tsx index 34621273..a32193fc 100644 --- a/front/packages/ui/src/login/login.tsx +++ b/front/packages/ui/src/login/login.tsx @@ -18,11 +18,10 @@ * along with Kyoo. If not, see . */ -import { type QueryPage, login } from "@kyoo/models"; +import { type QueryPage, ServerInfoP, login, useFetch } from "@kyoo/models"; import { A, Button, H1, Input, P, ts } from "@kyoo/primitives"; import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Trans } from "react-i18next"; +import { Trans, useTranslation } from "react-i18next"; import { Platform } from "react-native"; import { useRouter } from "solito/router"; import { percent, px, useYoshiki } from "yoshiki/native"; @@ -35,6 +34,11 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({ apiUrl, error: initialError, }) => { + const { data } = useFetch({ + path: ["info"], + parser: ServerInfoP, + }); + const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(initialError); @@ -53,43 +57,47 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({ return (

{t("login.login")}

- -

{t("login.username")}

- setUsername(value)} - autoCapitalize="none" - /> -

{t("login.password")}

- setPassword(value)} - /> - {error &&

theme.colors.red })}>{error}

} -