feat: Auth and User System (#205)

* server-side JWT auth implementation

* move oauth routes and strategies, fix bugs

* backend modifications for wiring up the frontend login and reg forms

* Add frontend data services for login and registration

* Add login and registration forms

* Implment auth context, functional client side auth

* protect routes with jwt auth

* finish local strategy (using local storage)

* Start setting up google auth

* disable token refresh, remove old auth middleware

* refactor client, add ApiErrorBoundary context

* disable google and facebook strategies

* fix: fix presets not displaying specific to user

* fix: fix issue with browser refresh

* fix: casing issue with User.js (#11)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* fix: issue with api error watcher (#12)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* feat: add google auth social login

* fix: make google login url dynamic based on dev/prod

* fix: bug where UI is briefly displayed before redirecting to login

* fix: fix cookie expires value for local auth

* Update README.md

* Update LOCAL_INSTALL structure

* Add local testing instructions

* Only load google strategy if client id and secret are provided

* Update .env.example files with new params

* fix issue with not redirecting to register form

* only show google login button if value is set in .env

* cleanup log messages

* Add label to button for google login on login form

* doc: fix client/server url values in .env.example

* feat: add error message details to registration failure

* Restore preventing paste on confirm password

* auto-login user after registering

* feat: forgot password (#24)

* make login/reg pages look like openai's

* add password reset data services

* new form designs similar to openai, add password reset pages

* add api's for password reset

* email utils for password reset

* remove bcrypt salt rounds from process.env

* refactor: restructure api auth code, consolidate routes (#25)

* add api's for password reset

* remove bcrypt salt rounds from process.env

* refactor: consolidate auth routes, use controller pattern

* refactor: code cleanup

* feat: migrate data to first user (#26)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes after refactor (#27)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: issue with auto-login when logging out then logging in with new browser window (#28)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: Update README and .env.example files with user system information (#29)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: update README and .env.example files

* Fixup: LOCAL_INSTALL.md PS instructions (#200) (#30)

Co-authored-by: alfredo-f <alfredo.fomitchenko@mail.polimi.it>

* feat: send user with completion to protect against abuse (#31)

* Fixup: LOCAL_INSTALL.md PS instructions (#200)

* server-side JWT auth implementation

* move oauth routes and strategies, fix bugs

* backend modifications for wiring up the frontend login and reg forms

* Add frontend data services for login and registration

* Add login and registration forms

* Implment auth context, functional client side auth

* protect routes with jwt auth

* finish local strategy (using local storage)

* Start setting up google auth

* disable token refresh, remove old auth middleware

* refactor client, add ApiErrorBoundary context

* disable google and facebook strategies

* fix: fix presets not displaying specific to user

* fix: fix issue with browser refresh

* fix: casing issue with User.js (#11)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* feat: add google auth social login

* fix: make google login url dynamic based on dev/prod

* fix: bug where UI is briefly displayed before redirecting to login

* fix: fix cookie expires value for local auth

* Only load google strategy if client id and secret are provided

* Update .env.example files with new params

* fix issue with not redirecting to register form

* only show google login button if value is set in .env

* cleanup log messages

* Add label to button for google login on login form

* doc: fix client/server url values in .env.example

* feat: add error message details to registration failure

* Restore preventing paste on confirm password

* auto-login user after registering

* feat: forgot password (#24)

* make login/reg pages look like openai's

* add password reset data services

* new form designs similar to openai, add password reset pages

* add api's for password reset

* email utils for password reset

* remove bcrypt salt rounds from process.env

* refactor: restructure api auth code, consolidate routes (#25)

* add api's for password reset

* remove bcrypt salt rounds from process.env

* refactor: consolidate auth routes, use controller pattern

* refactor: code cleanup

* feat: migrate data to first user (#26)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes after refactor (#27)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: issue with auto-login when logging out then logging in with new browser window (#28)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: Update README and .env.example files with user system information (#29)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: update README and .env.example files

* Send user id to openai to protect against abuse

* add meilisearch to gitignore

* Remove webpack

---------

Co-authored-by: alfredo-f <alfredo.fomitchenko@mail.polimi.it>

---------

Co-authored-by: Danny Avila <110412045+danny-avila@users.noreply.github.com>
Co-authored-by: Alfredo Fomitchenko <alfredo.fomitchenko@mail.polimi.it>
This commit is contained in:
Dan Orlando 2023-05-07 10:04:51 -07:00 committed by GitHub
parent 65543eb084
commit dac19038a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 3968 additions and 3394 deletions

View file

@ -1,5 +1,5 @@
export const user = () => {
return `/api/me`;
return `/api/auth/user`;
};
export const messages = (id: string) => {
@ -49,3 +49,35 @@ export const aiEndpoints = () => {
export const tokenizer = () => {
return `/api/tokenizer`;
}
export const login = () => {
return '/api/auth/login';
}
export const logout = () => {
return '/api/auth/logout';
}
export const register = () => {
return '/api/auth/register';
}
export const loginFacebook = () => {
return '/api/auth/facebook';
}
export const loginGoogle = () => {
return '/api/auth/google';
}
export const refreshToken = () => {
return '/api/auth/refresh';
}
export const requestPasswordReset = () => {
return '/api/auth/requestPasswordReset';
}
export const resetPassword = () => {
return '/api/auth/resetPassword';
}

View file

@ -67,4 +67,32 @@ export const getAIEndpoints = () => {
export const updateTokenCount = (text: string) => {
return request.post(endpoints.tokenizer(), {arg: text});
}
export const login = (payload: t.TLoginUser) => {
return request.post(endpoints.login(), payload);
}
export const logout = () => {
return request.post(endpoints.logout());
}
export const register = (payload: t.TRegisterUser) => {
return request.post(endpoints.register(), payload);
}
export const refreshToken = () => {
return request.post(endpoints.refreshToken());
}
export const getLoginGoogle = () => {
return request.get(endpoints.loginGoogle());
}
export const requestPasswordReset = (payload: t.TRequestPasswordReset) => {
return request.post(endpoints.requestPasswordReset(), payload);
}
export const resetPassword = (payload: t.TResetPassword) => {
return request.post(endpoints.resetPassword(), payload);
}

View file

@ -8,6 +8,7 @@ import {
} from "@tanstack/react-query";
import * as t from "./types";
import * as dataService from "./data-service";
import axios from 'axios';
export enum QueryKeys {
messages = "messsages",
@ -25,11 +26,13 @@ export const useAbortRequestWithMessage = (): UseMutationResult<void, Error, { e
return useMutation(({ endpoint, abortKey, message }) => dataService.abortRequestWithMessage(endpoint, abortKey, message));
};
export const useGetUserQuery = (): QueryObserverResult<t.TUser> => {
export const useGetUserQuery = (config?: UseQueryOptions<t.TUser>): QueryObserverResult<t.TUser> => {
return useQuery<t.TUser>([QueryKeys.user], () => dataService.getUser(), {
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchOnMount: false,
retry: false,
...config,
});
};
@ -120,11 +123,13 @@ export const useClearConversationsMutation = (): UseMutationResult<unknown> => {
});
};
export const useGetConversationsQuery = (pageNumber: string): QueryObserverResult<t.TConversation[]> => {
return useQuery([QueryKeys.allConversations, pageNumber], () =>
export const useGetConversationsQuery = (pageNumber: string, config?: UseQueryOptions<t.TConversation[]>): QueryObserverResult<t.TConversation[]> => {
return useQuery<t.TConversation[]>([QueryKeys.allConversations, pageNumber], () =>
dataService.getConversations(pageNumber), {
refetchOnReconnect: false,
refetchOnMount: false,
retry: 1,
...config,
}
);
}
@ -176,11 +181,12 @@ export const useUpdatePresetMutation = (): UseMutationResult<t.TPreset[], unknow
);
};
export const useGetPresetsQuery = (): QueryObserverResult<t.TPreset[], unknown> => {
return useQuery([QueryKeys.presets], () => dataService.getPresets(), {
export const useGetPresetsQuery = (config?: UseQueryOptions<t.TPreset[]>): QueryObserverResult<t.TPreset[], unknown> => {
return useQuery<t.TPreset[]>([QueryKeys.presets], () => dataService.getPresets(), {
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchOnMount: false,
...config,
});
};
@ -223,4 +229,52 @@ export const useUpdateTokenCountMutation = (): UseMutationResult<t.TUpdateTokenC
},
}
);
}
export const useLoginUserMutation = (): UseMutationResult<t.TLoginUserResponse, unknown, t.TLoginUserRequest, unknown> => {
const queryClient = useQueryClient();
return useMutation(
(payload: t.TLoginUserRequest) =>
dataService.login(payload),
{
onSuccess: () => {
queryClient.invalidateQueries([QueryKeys.user]);
},
}
);
}
export const useRegisterUserMutation = (): UseMutationResult<t.TRegisterUserResponse, unknown, t.TRegisterUser, unknown> => {
const queryClient = useQueryClient();
return useMutation(
(payload: t.TRegisterUser) =>
dataService.register(payload),
{
onSuccess: () => {
queryClient.invalidateQueries([QueryKeys.user]);
},
}
);
}
export const useLogoutUserMutation = (): UseMutationResult<unknown> => {
const queryClient = useQueryClient();
return useMutation(() => dataService.logout(), {
onSuccess: () => {
queryClient.invalidateQueries([QueryKeys.user]);
},
});
}
export const useRefreshTokenMutation = (): UseMutationResult<t.TRefreshTokenResponse, unknown, unknown, unknown> => {
return useMutation(() => dataService.refreshToken(), {
});
}
export const useRequestPasswordResetMutation = (): UseMutationResult<unknown> => {
return useMutation((payload: t.TRequestPasswordReset) => dataService.requestPasswordReset(payload));
}
export const useResetPasswordMutation = (): UseMutationResult<unknown> => {
return useMutation((payload: t.TResetPassword) => dataService.resetPassword(payload));
}

View file

@ -1,7 +1,7 @@
import axios, { AxiosRequestConfig } from "axios";
async function _get<T>(url: string, options?: AxiosRequestConfig): Promise<T> {
const response = await axios.get(url, { withCredentials: true, ...options});
const response = await axios.get(url, { ...options});
return response.data;
}

View file

@ -98,8 +98,14 @@ export type TPreset = {
}
export type TUser = {
id: string,
username: string,
display: string
email: string,
name: string,
avatar: string,
role: string,
createdAt: string,
updatedAt: string,
};
export type TGetConversationsResponse = {
@ -160,4 +166,31 @@ export type TMessageTreeNode = {}
export type TSearchMessage = {}
export type TSearchMessageTreeNode = {}
export type TSearchMessageTreeNode = {}
export type TRegisterUser = {
name: string,
email: string,
username: string,
password: string,
}
export type TLoginUser = {
email: string,
password: string,
}
export type TLoginResponse = {
token: string,
user: TUser
}
export type TRequestPasswordReset = {
email: string,
}
export type TResetPassword = {
userId: string,
token: string,
password: string,
}