mirror of
https://github.com/idanoo/autobrr
synced 2025-07-25 09:49:13 +00:00
fix(auth): cookie expiry and renewal (#1527)
* fix(auth/web): logout when expired/invalid/no cookie is present * fix(auth/web): specify error message in invalid cookie * fix(auth/web): reset error boundary on login * fix(auth/web): fix onboarding * chore: code cleanup * fix(web): revert tanstack/router to 1.31.0 * refactor(web): remove react-error-boundary * feat(auth): refresh cookie when close to expiry * enhancement(web): specify defaultError message in HttpClient * fix(web): use absolute paths for router links (#1530) * chore(web): bump `@tanstack/react-router` to `1.31.6` * fix(web): settings routes * fix(web): filter routes * fix(web): remove unused ReleasesIndexRoute * chore(web): add documentation for HttpClient * chore(lint): remove unnecessary whitespace
This commit is contained in:
parent
3dab295387
commit
8120c33f6b
19 changed files with 364 additions and 366 deletions
|
@ -26,16 +26,16 @@ interface NavTabType {
|
|||
}
|
||||
|
||||
const subNavigation: NavTabType[] = [
|
||||
{ name: "Application", href: ".", icon: CogIcon, exact: true },
|
||||
{ name: "Logs", href: "logs", icon: Square3Stack3DIcon },
|
||||
{ name: "Indexers", href: "indexers", icon: KeyIcon },
|
||||
{ name: "IRC", href: "irc", icon: ChatBubbleLeftRightIcon },
|
||||
{ name: "Feeds", href: "feeds", icon: RssIcon },
|
||||
{ name: "Clients", href: "clients", icon: FolderArrowDownIcon },
|
||||
{ name: "Notifications", href: "notifications", icon: BellIcon },
|
||||
{ name: "API keys", href: "api", icon: KeyIcon },
|
||||
{ name: "Releases", href: "releases", icon: RectangleStackIcon },
|
||||
{ name: "Account", href: "account", icon: UserCircleIcon }
|
||||
{ name: "Application", href: "/settings", icon: CogIcon, exact: true },
|
||||
{ name: "Logs", href: "/settings/logs", icon: Square3Stack3DIcon },
|
||||
{ name: "Indexers", href: "/settings/indexers", icon: KeyIcon },
|
||||
{ name: "IRC", href: "/settings/irc", icon: ChatBubbleLeftRightIcon },
|
||||
{ name: "Feeds", href: "/settings/feeds", icon: RssIcon },
|
||||
{ name: "Clients", href: "/settings/clients", icon: FolderArrowDownIcon },
|
||||
{ name: "Notifications", href: "/settings/notifications", icon: BellIcon },
|
||||
{ name: "API keys", href: "/settings/api", icon: KeyIcon },
|
||||
{ name: "Releases", href: "/settings/releases", icon: RectangleStackIcon },
|
||||
{ name: "Account", href: "/settings/account", icon: UserCircleIcon }
|
||||
// {name: 'Regex Playground', href: 'regex-playground', icon: CogIcon, current: false}
|
||||
// {name: 'Rules', href: 'rules', icon: ClipboardCheckIcon, current: false},
|
||||
];
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import React, { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useMutation, useQueryErrorResetBoundary } from "@tanstack/react-query";
|
||||
import { useRouter, useSearch } from "@tanstack/react-router";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
|
@ -18,15 +18,20 @@ import { PasswordInput, TextInput } from "@components/inputs/text";
|
|||
import { LoginRoute } from "@app/routes";
|
||||
|
||||
import Logo from "@app/logo.svg?react";
|
||||
import { AuthContext } from "@utils/Context";
|
||||
// import { WarningAlert } from "@components/alerts";
|
||||
|
||||
type LoginFormFields = {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export const Login = () => {
|
||||
export const Login = () => {
|
||||
const [auth, setAuth] = AuthContext.use();
|
||||
|
||||
const queryErrorResetBoundary = useQueryErrorResetBoundary()
|
||||
|
||||
const router = useRouter()
|
||||
const { auth } = LoginRoute.useRouteContext()
|
||||
const search = useSearch({ from: LoginRoute.id })
|
||||
|
||||
const { handleSubmit, register, formState } = useForm<LoginFormFields>({
|
||||
|
@ -35,14 +40,19 @@ export const Login = () => {
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
queryErrorResetBoundary.reset()
|
||||
// remove user session when visiting login page
|
||||
auth.logout()
|
||||
}, []);
|
||||
AuthContext.reset();
|
||||
}, [queryErrorResetBoundary]);
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationFn: (data: LoginFormFields) => APIClient.auth.login(data.username, data.password),
|
||||
onSuccess: (_, variables: LoginFormFields) => {
|
||||
auth.login(variables.username)
|
||||
queryErrorResetBoundary.reset()
|
||||
setAuth({
|
||||
isLoggedIn: true,
|
||||
username: variables.username
|
||||
});
|
||||
router.invalidate()
|
||||
},
|
||||
onError: (error) => {
|
||||
|
@ -60,7 +70,7 @@ export const Login = () => {
|
|||
} else if (auth.isLoggedIn) {
|
||||
router.history.push("/")
|
||||
}
|
||||
}, [auth.isLoggedIn, search.redirect])
|
||||
}, [auth.isLoggedIn, search.redirect]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col justify-center px-3">
|
||||
|
|
|
@ -43,7 +43,7 @@ export const Onboarding = () => {
|
|||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (data: InputValues) => APIClient.auth.onboard(data.username, data.password1),
|
||||
onSuccess: () => navigate({ to: "/" })
|
||||
onSuccess: () => navigate({ to: "/login" })
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
@ -33,12 +33,12 @@ interface tabType {
|
|||
}
|
||||
|
||||
const tabs: tabType[] = [
|
||||
{ name: "General", href: ".", exact: true },
|
||||
{ name: "Movies and TV", href: "movies-tv" },
|
||||
{ name: "Music", href: "music" },
|
||||
{ name: "Advanced", href: "advanced" },
|
||||
{ name: "External", href: "external" },
|
||||
{ name: "Actions", href: "actions" }
|
||||
{ name: "General", href: "/filters/$filterId", exact: true },
|
||||
{ name: "Movies and TV", href: "/filters/$filterId/movies-tv" },
|
||||
{ name: "Music", href: "/filters/$filterId/music" },
|
||||
{ name: "Advanced", href: "/filters/$filterId/advanced" },
|
||||
{ name: "External", href: "/filters/$filterId/external" },
|
||||
{ name: "Actions", href: "/filters/$filterId/actions" }
|
||||
];
|
||||
|
||||
export interface NavLinkProps {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
EyeSlashIcon
|
||||
} from "@heroicons/react/24/solid";
|
||||
|
||||
import { ReleasesIndexRoute } from "@app/routes";
|
||||
import { ReleasesRoute } from "@app/routes";
|
||||
import { ReleasesListQueryOptions } from "@api/queries";
|
||||
import { RandomLinuxIsos } from "@utils";
|
||||
|
||||
|
@ -94,7 +94,7 @@ const EmptyReleaseList = () => (
|
|||
);
|
||||
|
||||
export const ReleaseTable = () => {
|
||||
const search = ReleasesIndexRoute.useSearch()
|
||||
const search = ReleasesRoute.useSearch()
|
||||
|
||||
const columns = React.useMemo(() => [
|
||||
{
|
||||
|
|
|
@ -8,12 +8,11 @@ import { Form, Formik } from "formik";
|
|||
import toast from "react-hot-toast";
|
||||
import { UserIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
import { SettingsAccountRoute } from "@app/routes";
|
||||
import { AuthContext } from "@utils/Context";
|
||||
import { APIClient } from "@api/APIClient";
|
||||
import { Section } from "./_components";
|
||||
import { PasswordField, TextField } from "@components/inputs";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { AuthContext } from "@utils/Context";
|
||||
|
||||
const AccountSettings = () => (
|
||||
<Section
|
||||
|
@ -35,7 +34,7 @@ interface InputValues {
|
|||
}
|
||||
|
||||
function Credentials() {
|
||||
const ctx = SettingsAccountRoute.useRouteContext()
|
||||
const username = AuthContext.useSelector((s) => s.username);
|
||||
|
||||
const validate = (values: InputValues) => {
|
||||
const errors: Record<string, string> = {};
|
||||
|
@ -52,7 +51,7 @@ function Credentials() {
|
|||
const logoutMutation = useMutation({
|
||||
mutationFn: APIClient.auth.logout,
|
||||
onSuccess: () => {
|
||||
AuthContext.logout();
|
||||
AuthContext.reset();
|
||||
|
||||
toast.custom((t) => (
|
||||
<Toast type="success" body="User updated successfully. Please sign in again!" t={t} />
|
||||
|
@ -78,7 +77,7 @@ function Credentials() {
|
|||
<div className="px-2 pb-6 bg-white dark:bg-gray-800">
|
||||
<Formik
|
||||
initialValues={{
|
||||
username: ctx.auth.username!,
|
||||
username: username,
|
||||
newUsername: "",
|
||||
oldPassword: "",
|
||||
newPassword: "",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue