feat: add option to disable ui warnings

This commit is contained in:
Stavros
2025-11-21 17:37:01 +02:00
parent 22a2ab3322
commit 6c90046343
11 changed files with 43 additions and 60 deletions

View File

@@ -71,6 +71,7 @@ func (c *rootCmd) Register() {
{"disable-analytics", false, "Disable anonymous version collection."},
{"disable-resources", false, "Disable the resources server."},
{"socket-path", "", "Path to the Unix socket to bind the server to."},
{"disable-ui-warnings", false, "Disable UI warnings about insecure configurations."},
}
for _, opt := range configOptions {

View File

@@ -1,5 +1,5 @@
{
"name": "tinyauth-shadcn",
"name": "tinyauth",
"private": true,
"version": "0.0.0",
"type": "module",

View File

@@ -31,7 +31,7 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
};
export const Layout = () => {
const { appUrl } = useAppContext();
const { appUrl, disableUiWarnings } = useAppContext();
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
});
@@ -42,7 +42,7 @@ export const Layout = () => {
setIgnoreDomainWarning(true);
}, [setIgnoreDomainWarning]);
if (!ignoreDomainWarning && appUrl !== currentUrl) {
if (!ignoreDomainWarning && !disableUiWarnings && appUrl !== currentUrl) {
return (
<BaseLayout>
<DomainWarning

View File

@@ -1,15 +0,0 @@
import { useCallback, useEffect, useRef } from "react";
export function useIsMounted(): () => boolean {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return useCallback(() => isMounted.current, []);
}

View File

@@ -14,7 +14,7 @@ import { Navigate, useLocation, useNavigate } from "react-router";
import { useEffect, useState } from "react";
export const ContinuePage = () => {
const { cookieDomain } = useAppContext();
const { cookieDomain, disableUiWarnings } = useAppContext();
const { isLoggedIn } = useUserContext();
const { search } = useLocation();
const { t } = useTranslation();
@@ -53,12 +53,16 @@ export const ContinuePage = () => {
};
useEffect(() => {
if (!isLoggedIn) {
return;
}
if (
!isLoggedIn ||
!isValidRedirectUri ||
!isTrustedRedirectUri ||
(!isValidRedirectUri ||
!isAllowedRedirectProto ||
isHttpsDowngrade
!isTrustedRedirectUri ||
isHttpsDowngrade) &&
!disableUiWarnings
) {
return;
}
@@ -76,14 +80,7 @@ export const ContinuePage = () => {
clearTimeout(auto);
clearTimeout(reveal);
};
}, [
handleRedirect,
isAllowedRedirectProto,
isHttpsDowngrade,
isLoggedIn,
isTrustedRedirectUri,
isValidRedirectUri,
]);
}, []);
if (!isLoggedIn) {
return (
@@ -98,7 +95,7 @@ export const ContinuePage = () => {
return <Navigate to="/logout" replace />;
}
if (!isTrustedRedirectUri) {
if (!isTrustedRedirectUri && !disableUiWarnings) {
return (
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
<CardHeader>
@@ -136,7 +133,7 @@ export const ContinuePage = () => {
);
}
if (isHttpsDowngrade) {
if (isHttpsDowngrade && !disableUiWarnings) {
return (
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
<CardHeader>

View File

@@ -18,7 +18,6 @@ import { OAuthButton } from "@/components/ui/oauth-button";
import { SeperatorWithChildren } from "@/components/ui/separator";
import { useAppContext } from "@/context/app-context";
import { useUserContext } from "@/context/user-context";
import { useIsMounted } from "@/lib/hooks/use-is-mounted";
import { LoginSchema } from "@/schemas/login-schema";
import { useMutation } from "@tanstack/react-query";
import axios, { AxiosError } from "axios";
@@ -40,7 +39,6 @@ export const LoginPage = () => {
const { providers, title, oauthAutoRedirect } = useAppContext();
const { search } = useLocation();
const { t } = useTranslation();
const isMounted = useIsMounted();
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
useState(false);
const [showRedirectButton, setShowRedirectButton] = useState(false);
@@ -112,9 +110,7 @@ export const LoginPage = () => {
});
useEffect(() => {
if (isMounted()) {
if (
oauthProviders.length !== 0 &&
providers.find((provider) => provider.id === oauthAutoRedirect) &&
!isLoggedIn &&
redirectUri
@@ -127,16 +123,7 @@ export const LoginPage = () => {
setShowRedirectButton(true);
}, 5000);
}
}
}, [
isMounted,
oauthProviders.length,
providers,
isLoggedIn,
redirectUri,
oauthAutoRedirect,
oauthMutation,
]);
}, []);
useEffect(
() => () => {

View File

@@ -14,6 +14,7 @@ export const appContextSchema = z.object({
forgotPasswordMessage: z.string(),
backgroundImage: z.string(),
oauthAutoRedirect: z.string(),
disableUiWarnings: z.boolean(),
});
export type AppContextSchema = z.infer<typeof appContextSchema>;

View File

@@ -236,6 +236,7 @@ func (app *BootstrapApp) Setup() error {
ForgotPasswordMessage: app.config.ForgotPasswordMessage,
BackgroundImage: app.config.BackgroundImage,
OAuthAutoRedirect: app.config.OAuthAutoRedirect,
DisableUIWarnings: app.config.DisableUIWarnings,
}, apiRouter)
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{

View File

@@ -41,6 +41,7 @@ type Config struct {
TrustedProxies string `mapstructure:"trusted-proxies"`
DisableAnalytics bool `mapstructure:"disable-analytics"`
DisableResources bool `mapstructure:"disable-resources"`
DisableUIWarnings bool `mapstructure:"disable-ui-warnings"`
SocketPath string `mapstructure:"socket-path"`
}

View File

@@ -32,6 +32,7 @@ type AppContextResponse struct {
ForgotPasswordMessage string `json:"forgotPasswordMessage"`
BackgroundImage string `json:"backgroundImage"`
OAuthAutoRedirect string `json:"oauthAutoRedirect"`
DisableUIWarnings bool `json:"disableUiWarnings"`
}
type Provider struct {
@@ -48,6 +49,7 @@ type ContextControllerConfig struct {
ForgotPasswordMessage string
BackgroundImage string
OAuthAutoRedirect string
DisableUIWarnings bool
}
type ContextController struct {
@@ -56,6 +58,10 @@ type ContextController struct {
}
func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController {
if config.DisableUIWarnings {
log.Warn().Msg("UI warnings are disabled. This may expose users to security risks. Proceed with caution.")
}
return &ContextController{
config: config,
router: router,
@@ -117,5 +123,6 @@ func (controller *ContextController) appContextHandler(c *gin.Context) {
ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
BackgroundImage: controller.config.BackgroundImage,
OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
DisableUIWarnings: controller.config.DisableUIWarnings,
})
}

View File

@@ -30,6 +30,7 @@ var controllerCfg = controller.ContextControllerConfig{
ForgotPasswordMessage: "Contact admin to reset your password.",
BackgroundImage: "/assets/bg.jpg",
OAuthAutoRedirect: "google",
DisableUIWarnings: false,
}
var userContext = config.UserContext{
@@ -75,6 +76,7 @@ func TestAppContextHandler(t *testing.T) {
ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage,
BackgroundImage: controllerCfg.BackgroundImage,
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
DisableUIWarnings: controllerCfg.DisableUIWarnings,
}
router, recorder := setupContextController(nil)
@@ -102,6 +104,7 @@ func TestUserContextHandler(t *testing.T) {
Provider: userContext.Provider,
OAuth: userContext.OAuth,
TotpPending: userContext.TotpPending,
OAuthName: userContext.OAuthName,
}
// Test with context