mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-12-08 17:26:38 +00:00
feat: add option to disable ui warnings
This commit is contained in:
@@ -71,6 +71,7 @@ func (c *rootCmd) Register() {
|
|||||||
{"disable-analytics", false, "Disable anonymous version collection."},
|
{"disable-analytics", false, "Disable anonymous version collection."},
|
||||||
{"disable-resources", false, "Disable the resources server."},
|
{"disable-resources", false, "Disable the resources server."},
|
||||||
{"socket-path", "", "Path to the Unix socket to bind the server to."},
|
{"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 {
|
for _, opt := range configOptions {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "tinyauth-shadcn",
|
"name": "tinyauth",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Layout = () => {
|
export const Layout = () => {
|
||||||
const { appUrl } = useAppContext();
|
const { appUrl, disableUiWarnings } = useAppContext();
|
||||||
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
|
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
|
||||||
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
|
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
|
||||||
});
|
});
|
||||||
@@ -42,7 +42,7 @@ export const Layout = () => {
|
|||||||
setIgnoreDomainWarning(true);
|
setIgnoreDomainWarning(true);
|
||||||
}, [setIgnoreDomainWarning]);
|
}, [setIgnoreDomainWarning]);
|
||||||
|
|
||||||
if (!ignoreDomainWarning && appUrl !== currentUrl) {
|
if (!ignoreDomainWarning && !disableUiWarnings && appUrl !== currentUrl) {
|
||||||
return (
|
return (
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
<DomainWarning
|
<DomainWarning
|
||||||
|
|||||||
@@ -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, []);
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ import { Navigate, useLocation, useNavigate } from "react-router";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export const ContinuePage = () => {
|
export const ContinuePage = () => {
|
||||||
const { cookieDomain } = useAppContext();
|
const { cookieDomain, disableUiWarnings } = useAppContext();
|
||||||
const { isLoggedIn } = useUserContext();
|
const { isLoggedIn } = useUserContext();
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -53,12 +53,16 @@ export const ContinuePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isLoggedIn ||
|
(!isValidRedirectUri ||
|
||||||
!isValidRedirectUri ||
|
|
||||||
!isTrustedRedirectUri ||
|
|
||||||
!isAllowedRedirectProto ||
|
!isAllowedRedirectProto ||
|
||||||
isHttpsDowngrade
|
!isTrustedRedirectUri ||
|
||||||
|
isHttpsDowngrade) &&
|
||||||
|
!disableUiWarnings
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -76,14 +80,7 @@ export const ContinuePage = () => {
|
|||||||
clearTimeout(auto);
|
clearTimeout(auto);
|
||||||
clearTimeout(reveal);
|
clearTimeout(reveal);
|
||||||
};
|
};
|
||||||
}, [
|
}, []);
|
||||||
handleRedirect,
|
|
||||||
isAllowedRedirectProto,
|
|
||||||
isHttpsDowngrade,
|
|
||||||
isLoggedIn,
|
|
||||||
isTrustedRedirectUri,
|
|
||||||
isValidRedirectUri,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return (
|
return (
|
||||||
@@ -98,7 +95,7 @@ export const ContinuePage = () => {
|
|||||||
return <Navigate to="/logout" replace />;
|
return <Navigate to="/logout" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTrustedRedirectUri) {
|
if (!isTrustedRedirectUri && !disableUiWarnings) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -136,7 +133,7 @@ export const ContinuePage = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHttpsDowngrade) {
|
if (isHttpsDowngrade && !disableUiWarnings) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { OAuthButton } from "@/components/ui/oauth-button";
|
|||||||
import { SeperatorWithChildren } from "@/components/ui/separator";
|
import { SeperatorWithChildren } from "@/components/ui/separator";
|
||||||
import { useAppContext } from "@/context/app-context";
|
import { useAppContext } from "@/context/app-context";
|
||||||
import { useUserContext } from "@/context/user-context";
|
import { useUserContext } from "@/context/user-context";
|
||||||
import { useIsMounted } from "@/lib/hooks/use-is-mounted";
|
|
||||||
import { LoginSchema } from "@/schemas/login-schema";
|
import { LoginSchema } from "@/schemas/login-schema";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import axios, { AxiosError } from "axios";
|
import axios, { AxiosError } from "axios";
|
||||||
@@ -40,7 +39,6 @@ export const LoginPage = () => {
|
|||||||
const { providers, title, oauthAutoRedirect } = useAppContext();
|
const { providers, title, oauthAutoRedirect } = useAppContext();
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isMounted = useIsMounted();
|
|
||||||
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
|
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
||||||
@@ -112,9 +110,7 @@ export const LoginPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isMounted()) {
|
|
||||||
if (
|
if (
|
||||||
oauthProviders.length !== 0 &&
|
|
||||||
providers.find((provider) => provider.id === oauthAutoRedirect) &&
|
providers.find((provider) => provider.id === oauthAutoRedirect) &&
|
||||||
!isLoggedIn &&
|
!isLoggedIn &&
|
||||||
redirectUri
|
redirectUri
|
||||||
@@ -127,16 +123,7 @@ export const LoginPage = () => {
|
|||||||
setShowRedirectButton(true);
|
setShowRedirectButton(true);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
}
|
}, []);
|
||||||
}, [
|
|
||||||
isMounted,
|
|
||||||
oauthProviders.length,
|
|
||||||
providers,
|
|
||||||
isLoggedIn,
|
|
||||||
redirectUri,
|
|
||||||
oauthAutoRedirect,
|
|
||||||
oauthMutation,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const appContextSchema = z.object({
|
|||||||
forgotPasswordMessage: z.string(),
|
forgotPasswordMessage: z.string(),
|
||||||
backgroundImage: z.string(),
|
backgroundImage: z.string(),
|
||||||
oauthAutoRedirect: z.string(),
|
oauthAutoRedirect: z.string(),
|
||||||
|
disableUiWarnings: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AppContextSchema = z.infer<typeof appContextSchema>;
|
export type AppContextSchema = z.infer<typeof appContextSchema>;
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
ForgotPasswordMessage: app.config.ForgotPasswordMessage,
|
ForgotPasswordMessage: app.config.ForgotPasswordMessage,
|
||||||
BackgroundImage: app.config.BackgroundImage,
|
BackgroundImage: app.config.BackgroundImage,
|
||||||
OAuthAutoRedirect: app.config.OAuthAutoRedirect,
|
OAuthAutoRedirect: app.config.OAuthAutoRedirect,
|
||||||
|
DisableUIWarnings: app.config.DisableUIWarnings,
|
||||||
}, apiRouter)
|
}, apiRouter)
|
||||||
|
|
||||||
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
|
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ type Config struct {
|
|||||||
TrustedProxies string `mapstructure:"trusted-proxies"`
|
TrustedProxies string `mapstructure:"trusted-proxies"`
|
||||||
DisableAnalytics bool `mapstructure:"disable-analytics"`
|
DisableAnalytics bool `mapstructure:"disable-analytics"`
|
||||||
DisableResources bool `mapstructure:"disable-resources"`
|
DisableResources bool `mapstructure:"disable-resources"`
|
||||||
|
DisableUIWarnings bool `mapstructure:"disable-ui-warnings"`
|
||||||
SocketPath string `mapstructure:"socket-path"`
|
SocketPath string `mapstructure:"socket-path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type AppContextResponse struct {
|
|||||||
ForgotPasswordMessage string `json:"forgotPasswordMessage"`
|
ForgotPasswordMessage string `json:"forgotPasswordMessage"`
|
||||||
BackgroundImage string `json:"backgroundImage"`
|
BackgroundImage string `json:"backgroundImage"`
|
||||||
OAuthAutoRedirect string `json:"oauthAutoRedirect"`
|
OAuthAutoRedirect string `json:"oauthAutoRedirect"`
|
||||||
|
DisableUIWarnings bool `json:"disableUiWarnings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
@@ -48,6 +49,7 @@ type ContextControllerConfig struct {
|
|||||||
ForgotPasswordMessage string
|
ForgotPasswordMessage string
|
||||||
BackgroundImage string
|
BackgroundImage string
|
||||||
OAuthAutoRedirect string
|
OAuthAutoRedirect string
|
||||||
|
DisableUIWarnings bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextController struct {
|
type ContextController struct {
|
||||||
@@ -56,6 +58,10 @@ type ContextController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController {
|
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{
|
return &ContextController{
|
||||||
config: config,
|
config: config,
|
||||||
router: router,
|
router: router,
|
||||||
@@ -117,5 +123,6 @@ func (controller *ContextController) appContextHandler(c *gin.Context) {
|
|||||||
ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
|
ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
|
||||||
BackgroundImage: controller.config.BackgroundImage,
|
BackgroundImage: controller.config.BackgroundImage,
|
||||||
OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
|
OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
|
||||||
|
DisableUIWarnings: controller.config.DisableUIWarnings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ var controllerCfg = controller.ContextControllerConfig{
|
|||||||
ForgotPasswordMessage: "Contact admin to reset your password.",
|
ForgotPasswordMessage: "Contact admin to reset your password.",
|
||||||
BackgroundImage: "/assets/bg.jpg",
|
BackgroundImage: "/assets/bg.jpg",
|
||||||
OAuthAutoRedirect: "google",
|
OAuthAutoRedirect: "google",
|
||||||
|
DisableUIWarnings: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
var userContext = config.UserContext{
|
var userContext = config.UserContext{
|
||||||
@@ -75,6 +76,7 @@ func TestAppContextHandler(t *testing.T) {
|
|||||||
ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage,
|
ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage,
|
||||||
BackgroundImage: controllerCfg.BackgroundImage,
|
BackgroundImage: controllerCfg.BackgroundImage,
|
||||||
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
||||||
|
DisableUIWarnings: controllerCfg.DisableUIWarnings,
|
||||||
}
|
}
|
||||||
|
|
||||||
router, recorder := setupContextController(nil)
|
router, recorder := setupContextController(nil)
|
||||||
@@ -102,6 +104,7 @@ func TestUserContextHandler(t *testing.T) {
|
|||||||
Provider: userContext.Provider,
|
Provider: userContext.Provider,
|
||||||
OAuth: userContext.OAuth,
|
OAuth: userContext.OAuth,
|
||||||
TotpPending: userContext.TotpPending,
|
TotpPending: userContext.TotpPending,
|
||||||
|
OAuthName: userContext.OAuthName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with context
|
// Test with context
|
||||||
|
|||||||
Reference in New Issue
Block a user