mirror of
https://github.com/gethomepage/homepage.git
synced 2026-09-12 15:15:58 -07:00
Actually no cookie
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { getSettingsMock, authOptionsMock, signInMock, routerQuery } = vi.hoisted(() => ({
|
||||
const { getSettingsMock, authOptionsMock, signInMock, replaceMock, routerQuery } = vi.hoisted(() => ({
|
||||
getSettingsMock: vi.fn(),
|
||||
authOptionsMock: vi.fn(),
|
||||
signInMock: vi.fn(),
|
||||
replaceMock: vi.fn(),
|
||||
routerQuery: {},
|
||||
}));
|
||||
|
||||
@@ -23,6 +24,7 @@ vi.mock("pages/api/auth/[...nextauth]", () => ({
|
||||
vi.mock("next/router", () => ({
|
||||
useRouter: () => ({
|
||||
query: routerQuery,
|
||||
replace: replaceMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -37,6 +39,7 @@ describe("pages/auth/signin", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
Object.keys(routerQuery).forEach((key) => delete routerQuery[key]);
|
||||
window.sessionStorage.clear();
|
||||
});
|
||||
|
||||
it("renders an error state when no providers are configured", async () => {
|
||||
@@ -106,11 +109,14 @@ describe("pages/auth/signin", () => {
|
||||
expect(screen.getByRole("button", { name: /login via homepage oidc/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the button when the server disabled auto-login", () => {
|
||||
render(<SignInPage providers={OIDC_PROVIDERS} settings={SETTINGS} autoLogin={false} />);
|
||||
it("stops auto-login and hands back the page when the session never sticks", () => {
|
||||
routerQuery.callbackUrl = "/some/page";
|
||||
|
||||
expect(signInMock).not.toHaveBeenCalled();
|
||||
expect(screen.getByRole("button", { name: /login via homepage oidc/i })).toBeInTheDocument();
|
||||
render(<SignInPage providers={OIDC_PROVIDERS} settings={SETTINGS} autoLogin />);
|
||||
render(<SignInPage providers={OIDC_PROVIDERS} settings={SETTINGS} autoLogin />);
|
||||
|
||||
expect(signInMock).toHaveBeenCalledTimes(1);
|
||||
expect(replaceMock).toHaveBeenCalledWith("/auth/signin?autologin=0&callbackUrl=%2Fsome%2Fpage");
|
||||
});
|
||||
|
||||
it("does not auto-login the password provider", () => {
|
||||
@@ -173,17 +179,6 @@ describe("pages/auth/signin", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("getServerSideProps disables auto-login while an attempt is pending", async () => {
|
||||
authOptionsMock.mockReturnValueOnce({ providers: [] });
|
||||
getSettingsMock.mockReturnValueOnce({ theme: "dark" });
|
||||
vi.stubEnv("HOMEPAGE_OIDC_AUTO_LOGIN", "true");
|
||||
|
||||
const res = await getServerSideProps({ req: { cookies: { "homepage-autologin-attempt": "1" } } });
|
||||
|
||||
expect(res.props.autoLogin).toBe(false);
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("getServerSideProps falls back to no providers when auth options fail to load", async () => {
|
||||
const consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
authOptionsMock.mockImplementationOnce(() => {
|
||||
|
||||
+16
-14
@@ -7,8 +7,8 @@ import { BiShieldQuarter } from "react-icons/bi";
|
||||
import { getSettings } from "utils/config/config";
|
||||
|
||||
const PUBLIC_SIGN_IN_SETTINGS = ["theme", "color", "title", "background", "backgroundOpacity"];
|
||||
const AUTO_LOGIN_COOKIE = "homepage-autologin-attempt";
|
||||
const AUTO_LOGIN_RETRY_SECONDS = 10;
|
||||
const AUTO_LOGIN_KEY = "homepage-autologin-attempt";
|
||||
const AUTO_LOGIN_RETRY_MS = 10000;
|
||||
|
||||
export default function SignIn({ providers, settings, autoLogin }) {
|
||||
const router = useRouter();
|
||||
@@ -33,12 +33,21 @@ export default function SignIn({ providers, settings, autoLogin }) {
|
||||
useEffect(() => {
|
||||
if (!redirecting) return;
|
||||
|
||||
// getServerSideProps drops autoLogin while this is set, so a bounce loop falls back to the button
|
||||
const secure = window.location.protocol === "https:" ? "; secure" : "";
|
||||
document.cookie = `${AUTO_LOGIN_COOKIE}=1; path=/auth; max-age=${AUTO_LOGIN_RETRY_SECONDS}; samesite=lax${secure}`;
|
||||
let lastAttempt = 0;
|
||||
try {
|
||||
lastAttempt = Number(window.sessionStorage.getItem(AUTO_LOGIN_KEY)) || 0;
|
||||
window.sessionStorage.setItem(AUTO_LOGIN_KEY, String(Date.now()));
|
||||
} catch {
|
||||
// sessionStorage throws when site data is blocked, fall through and redirect anyway
|
||||
}
|
||||
// Getting here quickly means the session never stuck, hand it back to the user
|
||||
if (Date.now() - lastAttempt < AUTO_LOGIN_RETRY_MS) {
|
||||
router.replace(`/auth/signin?autologin=0&callbackUrl=${encodeURIComponent(callbackUrl)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
signIn(oidcProvider.id, { callbackUrl });
|
||||
}, [redirecting, oidcProvider, callbackUrl]);
|
||||
}, [redirecting, oidcProvider, callbackUrl, router]);
|
||||
|
||||
let backgroundImage = "";
|
||||
let opacity = settings?.backgroundOpacity ?? 0;
|
||||
@@ -243,14 +252,7 @@ export async function getServerSideProps(context) {
|
||||
homepageSettings[key],
|
||||
]),
|
||||
);
|
||||
// A pending attempt means the previous redirect never established a session
|
||||
const autoLoginAttempted = context.req?.cookies?.[AUTO_LOGIN_COOKIE] === "1";
|
||||
|
||||
return {
|
||||
props: {
|
||||
providers,
|
||||
settings,
|
||||
autoLogin: process.env.HOMEPAGE_OIDC_AUTO_LOGIN === "true" && !autoLoginAttempted,
|
||||
},
|
||||
props: { providers, settings, autoLogin: process.env.HOMEPAGE_OIDC_AUTO_LOGIN === "true" },
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user