refactor: move from session storage to cookie
This commit is contained in:
parent
37f19a1a63
commit
52d4e452a2
8 changed files with 42 additions and 23 deletions
|
|
@ -1,11 +0,0 @@
|
||||||
const RECOVERY_KEY_DOWNLOAD_SKIPPED_KEY = "zerobyte:recovery-key-download-skipped";
|
|
||||||
|
|
||||||
export function hasSkippedRecoveryKeyDownload() {
|
|
||||||
if (typeof window === "undefined") return false;
|
|
||||||
|
|
||||||
return window.sessionStorage.getItem(RECOVERY_KEY_DOWNLOAD_SKIPPED_KEY) === "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function skipRecoveryKeyDownload() {
|
|
||||||
window.sessionStorage.setItem(RECOVERY_KEY_DOWNLOAD_SKIPPED_KEY, "true");
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,10 @@ import { Input } from "~/client/components/ui/input";
|
||||||
import { Label } from "~/client/components/ui/label";
|
import { Label } from "~/client/components/ui/label";
|
||||||
import { downloadResticPasswordMutation } from "~/client/api-client/@tanstack/react-query.gen";
|
import { downloadResticPasswordMutation } from "~/client/api-client/@tanstack/react-query.gen";
|
||||||
import { parseError } from "~/client/lib/errors";
|
import { parseError } from "~/client/lib/errors";
|
||||||
import { skipRecoveryKeyDownload } from "~/client/lib/recovery-key-skip";
|
import {
|
||||||
|
RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_MAX_AGE,
|
||||||
|
RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME,
|
||||||
|
} from "~/lib/recovery-key-skip";
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
|
|
||||||
const RECOVERY_KEY_CREDENTIAL_REQUIRED_MESSAGE =
|
const RECOVERY_KEY_CREDENTIAL_REQUIRED_MESSAGE =
|
||||||
|
|
@ -17,9 +20,10 @@ const RECOVERY_KEY_CREDENTIAL_REQUIRED_MESSAGE =
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
hasCredentialPassword: boolean;
|
hasCredentialPassword: boolean;
|
||||||
|
userId: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function DownloadRecoveryKeyPage({ hasCredentialPassword }: Props) {
|
export function DownloadRecoveryKeyPage({ hasCredentialPassword, userId }: Props) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [blockedMessage, setBlockedMessage] = useState<string | null>(null);
|
const [blockedMessage, setBlockedMessage] = useState<string | null>(null);
|
||||||
|
|
@ -61,7 +65,9 @@ export function DownloadRecoveryKeyPage({ hasCredentialPassword }: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSkip = () => {
|
const handleSkip = () => {
|
||||||
skipRecoveryKeyDownload();
|
if (!userId) return;
|
||||||
|
|
||||||
|
document.cookie = `${RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME}=${userId}; path=/; max-age=${RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_MAX_AGE}`;
|
||||||
void navigate({ to: "/volumes", replace: true });
|
void navigate({ to: "/volumes", replace: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "~/clie
|
||||||
import { Label } from "~/client/components/ui/label";
|
import { Label } from "~/client/components/ui/label";
|
||||||
import { authClient } from "~/client/lib/auth-client";
|
import { authClient } from "~/client/lib/auth-client";
|
||||||
import { logger } from "~/client/lib/logger";
|
import { logger } from "~/client/lib/logger";
|
||||||
import { hasSkippedRecoveryKeyDownload } from "~/client/lib/recovery-key-skip";
|
import { RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME } from "~/lib/recovery-key-skip";
|
||||||
import { decodeLoginError, getLoginErrorDescription } from "~/client/lib/sso-errors";
|
import { decodeLoginError, getLoginErrorDescription } from "~/client/lib/sso-errors";
|
||||||
import { ResetPasswordDialog } from "../components/reset-password-dialog";
|
import { ResetPasswordDialog } from "../components/reset-password-dialog";
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
|
|
@ -33,6 +33,12 @@ type LoginPageProps = {
|
||||||
error?: string;
|
error?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function hasSkippedRecoveryKeyDownload(userId: string) {
|
||||||
|
return document.cookie
|
||||||
|
.split(";")
|
||||||
|
.some((cookie) => cookie.trim() === `${RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME}=${userId}`);
|
||||||
|
}
|
||||||
|
|
||||||
export function LoginPage({ error }: LoginPageProps = {}) {
|
export function LoginPage({ error }: LoginPageProps = {}) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [showResetDialog, setShowResetDialog] = useState(false);
|
const [showResetDialog, setShowResetDialog] = useState(false);
|
||||||
|
|
@ -78,7 +84,7 @@ export function LoginPage({ error }: LoginPageProps = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const d = await authClient.getSession();
|
const d = await authClient.getSession();
|
||||||
if (data.user && !d.data?.user.hasDownloadedResticPassword && !hasSkippedRecoveryKeyDownload()) {
|
if (data.user && !d.data?.user.hasDownloadedResticPassword && !hasSkippedRecoveryKeyDownload(data.user.id)) {
|
||||||
void navigate({ to: "/download-recovery-key" });
|
void navigate({ to: "/download-recovery-key" });
|
||||||
} else {
|
} else {
|
||||||
void navigate({ to: "/volumes" });
|
void navigate({ to: "/volumes" });
|
||||||
|
|
@ -117,7 +123,7 @@ export function LoginPage({ error }: LoginPageProps = {}) {
|
||||||
if (
|
if (
|
||||||
session.data?.user &&
|
session.data?.user &&
|
||||||
!session.data.user.hasDownloadedResticPassword &&
|
!session.data.user.hasDownloadedResticPassword &&
|
||||||
!hasSkippedRecoveryKeyDownload()
|
!hasSkippedRecoveryKeyDownload(session.data.user.id)
|
||||||
) {
|
) {
|
||||||
void navigate({ to: "/download-recovery-key" });
|
void navigate({ to: "/download-recovery-key" });
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,5 @@ export type AppContext = {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
hasUsers: boolean;
|
hasUsers: boolean;
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
|
hasSkippedRecoveryKeyDownload: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
2
app/lib/recovery-key-skip.ts
Normal file
2
app/lib/recovery-key-skip.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export const RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME = "zerobyte_recovery_key_download_skipped";
|
||||||
|
export const RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_MAX_AGE = 60 * 60;
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { createMiddleware } from "@tanstack/react-start";
|
import { createMiddleware } from "@tanstack/react-start";
|
||||||
import { redirect } from "@tanstack/react-router";
|
import { redirect } from "@tanstack/react-router";
|
||||||
import { auth } from "~/server/lib/auth";
|
import { auth } from "~/server/lib/auth";
|
||||||
import { getRequestHeaders } from "@tanstack/react-start/server";
|
import { getCookie, getRequestHeaders } from "@tanstack/react-start/server";
|
||||||
import { authService } from "~/server/modules/auth/auth.service";
|
import { authService } from "~/server/modules/auth/auth.service";
|
||||||
import { isAuthRoute } from "~/lib/auth-routes";
|
import { isAuthRoute } from "~/lib/auth-routes";
|
||||||
|
import { RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME } from "~/lib/recovery-key-skip";
|
||||||
|
|
||||||
export const authMiddleware = createMiddleware().server(async ({ next, request }) => {
|
export const authMiddleware = createMiddleware().server(async ({ next, request }) => {
|
||||||
const headers = getRequestHeaders();
|
const headers = getRequestHeaders();
|
||||||
|
|
@ -20,7 +21,13 @@ export const authMiddleware = createMiddleware().server(async ({ next, request }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session?.user?.id) {
|
if (session?.user?.id) {
|
||||||
if (!session.user.hasDownloadedResticPassword && pathname !== "/download-recovery-key") {
|
const hasSkippedRecoveryKeyDownload = getCookie(RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME) === session.user.id;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!session.user.hasDownloadedResticPassword &&
|
||||||
|
!hasSkippedRecoveryKeyDownload &&
|
||||||
|
pathname !== "/download-recovery-key"
|
||||||
|
) {
|
||||||
throw redirect({ to: "/download-recovery-key" });
|
throw redirect({ to: "/download-recovery-key" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ const getRecoveryKeyUserState = createServerFn({ method: "GET" }).handler(async
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasCredentialPassword: session?.user ? await userHasCredentialPassword(session.user.id) : false,
|
hasCredentialPassword: session?.user ? await userHasCredentialPassword(session.user.id) : false,
|
||||||
|
userId: session?.user.id ?? null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -30,7 +31,7 @@ export const Route = createFileRoute("/(auth)/download-recovery-key")({
|
||||||
});
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const { hasCredentialPassword } = Route.useLoaderData();
|
const { hasCredentialPassword, userId } = Route.useLoaderData();
|
||||||
|
|
||||||
return <DownloadRecoveryKeyPage hasCredentialPassword={hasCredentialPassword} />;
|
return <DownloadRecoveryKeyPage hasCredentialPassword={hasCredentialPassword} userId={userId} />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { getOrganizationContext } from "~/server/lib/functions/organization-cont
|
||||||
import { getServerConstants } from "~/server/lib/functions/server-constants";
|
import { getServerConstants } from "~/server/lib/functions/server-constants";
|
||||||
import { userHasCredentialPassword } from "~/server/modules/auth/helpers";
|
import { userHasCredentialPassword } from "~/server/modules/auth/helpers";
|
||||||
import { authService } from "~/server/modules/auth/auth.service";
|
import { authService } from "~/server/modules/auth/auth.service";
|
||||||
import { hasSkippedRecoveryKeyDownload } from "~/client/lib/recovery-key-skip";
|
import { RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME } from "~/lib/recovery-key-skip";
|
||||||
|
|
||||||
export const fetchUser = createServerFn({ method: "GET" }).handler(async () => {
|
export const fetchUser = createServerFn({ method: "GET" }).handler(async () => {
|
||||||
const headers = getRequestHeaders();
|
const headers = getRequestHeaders();
|
||||||
|
|
@ -19,11 +19,14 @@ export const fetchUser = createServerFn({ method: "GET" }).handler(async () => {
|
||||||
|
|
||||||
const sidebarCookie = getCookie(SIDEBAR_COOKIE_NAME);
|
const sidebarCookie = getCookie(SIDEBAR_COOKIE_NAME);
|
||||||
const sidebarOpen = !sidebarCookie ? true : sidebarCookie === "true";
|
const sidebarOpen = !sidebarCookie ? true : sidebarCookie === "true";
|
||||||
|
const hasSkippedRecoveryKeyDownload =
|
||||||
|
!!session?.user && getCookie(RECOVERY_KEY_DOWNLOAD_SKIPPED_COOKIE_NAME) === session.user.id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: session?.user ? { ...session.user, hasCredentialPassword } : null,
|
user: session?.user ? { ...session.user, hasCredentialPassword } : null,
|
||||||
hasUsers,
|
hasUsers,
|
||||||
sidebarOpen,
|
sidebarOpen,
|
||||||
|
hasSkippedRecoveryKeyDownload,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -46,7 +49,11 @@ export const Route = createFileRoute("/(dashboard)")({
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (authContext.user && !authContext.user.hasDownloadedResticPassword && !hasSkippedRecoveryKeyDownload()) {
|
if (
|
||||||
|
authContext.user &&
|
||||||
|
!authContext.user.hasDownloadedResticPassword &&
|
||||||
|
!authContext.hasSkippedRecoveryKeyDownload
|
||||||
|
) {
|
||||||
throw redirect({ to: "/download-recovery-key" });
|
throw redirect({ to: "/download-recovery-key" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue