mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-26 21:28:50 +01:00
Auth fix (#624)
* chore(eslint): add ignore pattern for packages/data-provider/types
chore(data-provider): fix import formatting in index.ts
chore(data-provider): add types/index.d.ts to tsconfig include
* fix(Auth): fix "skip login" bug, where UI would render in an unauthenticated state
fix(Login.tsx): replace navigate('/chat/new') with navigate('/chat/new', { replace: true })
fix(AuthContext.tsx): replace navigate(redirect) with navigate(redirect, { replace: true })
fix(AuthContext.tsx): replace navigate('/login') with navigate('/login', { replace: true })
fix(AuthContext.tsx): replace navigate('/login') with navigate('/login', { replace: true })
fix(routes/Chat.jsx): add check for isAuthenticated: navigate to '/login' and render null if not authenticated
fix(routes/index.jsx): add check for isAuthenticated: navigate to '/login' and render null if not authenticated
* refactor(SubmitButton.jsx): create a set of endpoints to hide set tokens
fix(SubmitButton.jsx): fix condition to check if token is provided for certain endpoints
This commit is contained in:
parent
747e087cf5
commit
f5672ddcf8
10 changed files with 47 additions and 21 deletions
|
|
@ -13,6 +13,9 @@ module.exports = {
|
||||||
'plugin:jest/recommended',
|
'plugin:jest/recommended',
|
||||||
'prettier'
|
'prettier'
|
||||||
],
|
],
|
||||||
|
ignorePatterns: [
|
||||||
|
'packages/data-provider/types/**/*',
|
||||||
|
],
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 'latest',
|
ecmaVersion: 'latest',
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ function Login() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
navigate('/chat/new');
|
navigate('/chat/new', { replace: true });
|
||||||
}
|
}
|
||||||
}, [isAuthenticated, navigate]);
|
}, [isAuthenticated, navigate]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export default function SubmitButton({
|
||||||
const { getToken } = store.useToken(endpoint);
|
const { getToken } = store.useToken(endpoint);
|
||||||
|
|
||||||
const isTokenProvided = endpointsConfig?.[endpoint]?.userProvide ? !!getToken() : true;
|
const isTokenProvided = endpointsConfig?.[endpoint]?.userProvide ? !!getToken() : true;
|
||||||
|
const endpointsToHideSetTokens = new Set(['openAI', 'azureOpenAI', 'bingAI']);
|
||||||
|
|
||||||
const clickHandler = (e) => {
|
const clickHandler = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -38,7 +39,7 @@ export default function SubmitButton({
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
} else if (!isTokenProvided && (endpoint !== 'openAI' || endpoint !== 'azureOpenAI' )) {
|
} else if (!isTokenProvided && (!endpointsToHideSetTokens.has(endpoint))) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ const AuthContextProvider = ({
|
||||||
setTokenHeader(token);
|
setTokenHeader(token);
|
||||||
setIsAuthenticated(isAuthenticated);
|
setIsAuthenticated(isAuthenticated);
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
navigate(redirect);
|
navigate(redirect, { replace: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[navigate]
|
[navigate]
|
||||||
|
|
@ -101,7 +101,8 @@ const AuthContextProvider = ({
|
||||||
setUserContext({ token, isAuthenticated: true, user, redirect: '/chat/new' });
|
setUserContext({ token, isAuthenticated: true, user, redirect: '/chat/new' });
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
doSetError(error.message);
|
doSetError((error as Error).message);
|
||||||
|
navigate('/login', { replace: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -122,7 +123,7 @@ const AuthContextProvider = ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
doSetError(error.message);
|
doSetError((error as Error).message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -131,9 +132,8 @@ const AuthContextProvider = ({
|
||||||
if (userQuery.data) {
|
if (userQuery.data) {
|
||||||
setUser(userQuery.data);
|
setUser(userQuery.data);
|
||||||
} else if (userQuery.isError) {
|
} else if (userQuery.isError) {
|
||||||
//@ts-ignore - userQuery.error is of type unknown
|
doSetError((userQuery?.error as Error).message);
|
||||||
doSetError(userQuery?.error.message);
|
navigate('/login', { replace: true });
|
||||||
navigate('/login');
|
|
||||||
}
|
}
|
||||||
if (error && isAuthenticated) {
|
if (error && isAuthenticated) {
|
||||||
doSetError(undefined);
|
doSetError(undefined);
|
||||||
|
|
@ -143,7 +143,7 @@ const AuthContextProvider = ({
|
||||||
if (tokenFromCookie) {
|
if (tokenFromCookie) {
|
||||||
setUserContext({ token: tokenFromCookie, isAuthenticated: true, user: userQuery.data });
|
setUserContext({ token: tokenFromCookie, isAuthenticated: true, user: userQuery.data });
|
||||||
} else {
|
} else {
|
||||||
navigate('/login');
|
navigate('/login', { replace: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ import {
|
||||||
} from '@librechat/data-provider';
|
} from '@librechat/data-provider';
|
||||||
|
|
||||||
export default function Chat() {
|
export default function Chat() {
|
||||||
|
const { isAuthenticated } = useAuthContext();
|
||||||
const [shouldNavigate, setShouldNavigate] = useState(true);
|
const [shouldNavigate, setShouldNavigate] = useState(true);
|
||||||
const searchQuery = useRecoilValue(store.searchQuery);
|
const searchQuery = useRecoilValue(store.searchQuery);
|
||||||
const [conversation, setConversation] = useRecoilState(store.conversation);
|
const [conversation, setConversation] = useRecoilState(store.conversation);
|
||||||
|
|
@ -29,6 +31,18 @@ export default function Chat() {
|
||||||
const getConversationMutation = useGetConversationByIdMutation(conversationId);
|
const getConversationMutation = useGetConversationByIdMutation(conversationId);
|
||||||
const { data: config } = useGetStartupConfig();
|
const { data: config } = useGetStartupConfig();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timeout = setTimeout(() => {
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
navigate('/login', { replace: true });
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}, [isAuthenticated, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isSubmitting && !shouldNavigate) {
|
if (!isSubmitting && !shouldNavigate) {
|
||||||
setShouldNavigate(true);
|
setShouldNavigate(true);
|
||||||
|
|
@ -41,7 +55,7 @@ export default function Chat() {
|
||||||
if (conversation === null && conversationId === 'new') {
|
if (conversation === null && conversationId === 'new') {
|
||||||
newConversation();
|
newConversation();
|
||||||
setShouldNavigate(true);
|
setShouldNavigate(true);
|
||||||
}
|
}
|
||||||
// No current conversation and conversationId exists
|
// No current conversation and conversationId exists
|
||||||
else if (conversation === null && conversationId) {
|
else if (conversation === null && conversationId) {
|
||||||
getConversationMutation.mutate(conversationId, {
|
getConversationMutation.mutate(conversationId, {
|
||||||
|
|
@ -53,24 +67,24 @@ export default function Chat() {
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('Failed to fetch the conversation');
|
console.error('Failed to fetch the conversation');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
navigate(`/chat/new`);
|
navigate('/chat/new');
|
||||||
newConversation();
|
newConversation();
|
||||||
setShouldNavigate(true);
|
setShouldNavigate(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setMessages(null);
|
setMessages(null);
|
||||||
}
|
}
|
||||||
// No current conversation and no conversationId
|
// No current conversation and no conversationId
|
||||||
else if (conversation === null) {
|
else if (conversation === null) {
|
||||||
navigate(`/chat/new`);
|
navigate('/chat/new');
|
||||||
setShouldNavigate(true);
|
setShouldNavigate(true);
|
||||||
}
|
}
|
||||||
// Current conversationId is 'search'
|
// Current conversationId is 'search'
|
||||||
else if (conversation?.conversationId === 'search') {
|
else if (conversation?.conversationId === 'search') {
|
||||||
navigate(`/search/${searchQuery}`);
|
navigate(`/search/${searchQuery}`);
|
||||||
setShouldNavigate(true);
|
setShouldNavigate(true);
|
||||||
}
|
}
|
||||||
// Conversation change and isSubmitting
|
// Conversation change and isSubmitting
|
||||||
else if (conversation?.conversationId !== conversationId && isSubmitting) {
|
else if (conversation?.conversationId !== conversationId && isSubmitting) {
|
||||||
setShouldNavigate(false);
|
setShouldNavigate(false);
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +115,10 @@ export default function Chat() {
|
||||||
}
|
}
|
||||||
}, [messagesQuery.data, messagesQuery.isError, setMessages]);
|
}, [messagesQuery.data, messagesQuery.isError, setMessages]);
|
||||||
|
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// if not a conversation
|
// if not a conversation
|
||||||
if (conversation?.conversationId === 'search') return null;
|
if (conversation?.conversationId === 'search') return null;
|
||||||
// if conversationId not match
|
// if conversationId not match
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export default function Root() {
|
||||||
const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled);
|
const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled);
|
||||||
const setEndpointsConfig = useSetRecoilState(store.endpointsConfig);
|
const setEndpointsConfig = useSetRecoilState(store.endpointsConfig);
|
||||||
const setPresets = useSetRecoilState(store.presets);
|
const setPresets = useSetRecoilState(store.presets);
|
||||||
const { user } = useAuthContext();
|
const { user, isAuthenticated } = useAuthContext();
|
||||||
|
|
||||||
const searchEnabledQuery = useGetSearchEnabledQuery();
|
const searchEnabledQuery = useGetSearchEnabledQuery();
|
||||||
const endpointsQuery = useGetEndpointsQuery();
|
const endpointsQuery = useGetEndpointsQuery();
|
||||||
|
|
@ -57,6 +57,10 @@ export default function Root() {
|
||||||
}
|
}
|
||||||
}, [searchEnabledQuery.data, searchEnabledQuery.isError]);
|
}, [searchEnabledQuery.data, searchEnabledQuery.isError]);
|
||||||
|
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-screen">
|
<div className="flex h-screen">
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export default function Search() {
|
||||||
searchPlaceholderConversation();
|
searchPlaceholderConversation();
|
||||||
setSearchQuery(query);
|
setSearchQuery(query);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/chat/new`);
|
navigate('/chat/new');
|
||||||
}
|
}
|
||||||
} else if (conversation?.conversationId === 'search') {
|
} else if (conversation?.conversationId === 'search') {
|
||||||
// jump to search page
|
// jump to search page
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const AuthLayout = () => (
|
||||||
export const router = createBrowserRouter([
|
export const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
path: 'register',
|
path: 'register',
|
||||||
element: <Registration />
|
element: <Registration />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'forgot-password',
|
path: 'forgot-password',
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ export * from './types';
|
||||||
export * from './react-query-service';
|
export * from './react-query-service';
|
||||||
export * from './headers-helpers';
|
export * from './headers-helpers';
|
||||||
export * from './sse.mjs';
|
export * from './sse.mjs';
|
||||||
export {default as createPayload} from './createPayload';
|
export { default as createPayload } from './createPayload';
|
||||||
|
|
@ -23,5 +23,5 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist", "types"],
|
"exclude": ["node_modules", "dist", "types"],
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*", "types/index.d.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue