| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "lodash.isempty": "^4.4.0", | "lodash.isempty": "^4.4.0", | ||||
| "owasp-password-strength-test": "^1.3.0", | "owasp-password-strength-test": "^1.3.0", | ||||
| "qs": "^6.11.0", | |||||
| "react": "^17.0.2", | "react": "^17.0.2", | ||||
| "react-dom": "^17.0.2", | "react-dom": "^17.0.2", | ||||
| "react-helmet-async": "^1.0.9", | "react-helmet-async": "^1.0.9", |
| NOT_FOUND_PAGE, | NOT_FOUND_PAGE, | ||||
| ERROR_PAGE, | ERROR_PAGE, | ||||
| BASE_PAGE, | BASE_PAGE, | ||||
| GOOGLE_AUTH_CALLBACK_PAGE, | |||||
| AUTH_CALLBACK_PAGE, | |||||
| REGISTER_PAGE, | REGISTER_PAGE, | ||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| import ErrorPage from "./pages/ErrorPages/ErrorPage"; | import ErrorPage from "./pages/ErrorPages/ErrorPage"; | ||||
| import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | ||||
| import PrivateRoute from "./components/Router/PrivateRoute"; | import PrivateRoute from "./components/Router/PrivateRoute"; | ||||
| import GoogleAuthCallback from "./pages/GoogleAuthCallback/GoogleAuthCallback"; | |||||
| import AuthCallback from "./pages/AuthCallback/AuthCallback"; | |||||
| import RegisterPage from "./pages/RegisterPage/RegisterPageMUI"; | import RegisterPage from "./pages/RegisterPage/RegisterPageMUI"; | ||||
| const AppRoutes = () => ( | const AppRoutes = () => ( | ||||
| <Route exact path={BASE_PAGE} component={LoginPage} /> | <Route exact path={BASE_PAGE} component={LoginPage} /> | ||||
| <Route exact path={LOGIN_PAGE} component={LoginPage} /> | <Route exact path={LOGIN_PAGE} component={LoginPage} /> | ||||
| <Route exact path={REGISTER_PAGE} component={RegisterPage} /> | <Route exact path={REGISTER_PAGE} component={RegisterPage} /> | ||||
| <Route path={GOOGLE_AUTH_CALLBACK_PAGE} component={GoogleAuthCallback} /> | |||||
| <Route path={AUTH_CALLBACK_PAGE} component={AuthCallback} /> | |||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | ||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | <Route path={ERROR_PAGE} component={ErrorPage} /> | ||||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> |
| export const HOME_PAGE = '/home'; | export const HOME_PAGE = '/home'; | ||||
| export const ERROR_PAGE = '/error-page'; | export const ERROR_PAGE = '/error-page'; | ||||
| export const NOT_FOUND_PAGE = '/not-found'; | export const NOT_FOUND_PAGE = '/not-found'; | ||||
| export const GOOGLE_AUTH_CALLBACK_PAGE = '/api/auth/google/callback' | |||||
| export const AUTH_CALLBACK_PAGE = '/api/auth/:provider/callback' |
| import React, { useEffect } from "react"; | |||||
| import { useLocation } from "react-router-dom"; | |||||
| import { HOME_PAGE } from "../../constants/pages"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useParams } from "react-router-dom"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { fetchAuthProvider } from "../../store/actions/authProvider/authProviderActions"; | |||||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||||
| import { AUTH_PROVIDER_SCOPE } from "../../store/actions/authProvider/authProviderActionConstants"; | |||||
| import Backdrop from '../../components/MUI/BackdropComponent'; | |||||
| function AuthCallback({ history }) { | |||||
| const dispatch = useDispatch(); | |||||
| const { provider } = useParams(); | |||||
| const location = useLocation(); | |||||
| const handleApiResponseSuccess = () => { | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| from: history.location.pathname, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const isLoading = useSelector(selectIsLoadingByActionType(AUTH_PROVIDER_SCOPE)); | |||||
| useEffect(() => { | |||||
| if (!location) { | |||||
| return; | |||||
| } | |||||
| const { search } = location; | |||||
| dispatch(fetchAuthProvider({ provider, search, handleApiResponseSuccess })); | |||||
| }, [location]); | |||||
| return ( | |||||
| <div> | |||||
| {isLoading && <Backdrop position="absolute" isLoading={isLoading} />} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| AuthCallback.propTypes = { | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| export default AuthCallback; |
| import React, { useEffect } from "react"; | |||||
| import { useLocation } from "react-router-dom"; | |||||
| import { authScopeSetHelper } from "../../util/helpers/authScopeHelpers"; | |||||
| import { addHeaderToken } from "../../request"; | |||||
| import { HOME_PAGE } from "../../constants/pages"; | |||||
| import { JWT_REFRESH_TOKEN, JWT_TOKEN } from "../../constants/localStorage"; | |||||
| import { setUser } from "../../store/actions/user/userActions"; | |||||
| import PropTypes from "prop-types"; | |||||
| import axios from "axios"; | |||||
| function GoogleAuthCallback({ history }) { | |||||
| const location = useLocation(); | |||||
| const handleApiResponseSuccess = () => { | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| from: history.location.pathname, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| useEffect(() => { | |||||
| if (!location) { | |||||
| return; | |||||
| } | |||||
| const { search } = location; | |||||
| axios({ | |||||
| method: "GET", | |||||
| url: `http://localhost:1337/api/auth/google/callback?${search}`, | |||||
| }).then((res) => { | |||||
| if (res.data?.jwt) { | |||||
| const user = res.data?.user; | |||||
| authScopeSetHelper(JWT_TOKEN, res.data.jwt); | |||||
| authScopeSetHelper(JWT_REFRESH_TOKEN, res.data.refreshToken); | |||||
| addHeaderToken(res.data?.jwt); | |||||
| setUser(user); | |||||
| handleApiResponseSuccess(); | |||||
| } | |||||
| }); | |||||
| }, [location]); | |||||
| return ( | |||||
| <div> | |||||
| <></> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| GoogleAuthCallback.propTypes = { | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| export default GoogleAuthCallback; |
| authentications: { | authentications: { | ||||
| getUsernames: 'authenticate/usernames', | getUsernames: 'authenticate/usernames', | ||||
| login: 'api/auth/local', | login: 'api/auth/local', | ||||
| authProvider: 'api/auth/{provider}/callback?{search}', | |||||
| register: 'api/auth/local/register', | register: 'api/auth/local/register', | ||||
| getUserSecurityQuestion: 'users/username/securityquestion', | getUserSecurityQuestion: 'users/username/securityquestion', | ||||
| confirmSecurityQuestion: 'authenticate/confirm', | confirmSecurityQuestion: 'authenticate/confirm', |
| import axios from "axios"; | import axios from "axios"; | ||||
| // import queryString from 'qs'; | |||||
| import queryString from "qs"; | |||||
| const request = axios.create({ | const request = axios.create({ | ||||
| baseURL: "http://localhost:1337/", | baseURL: "http://localhost:1337/", | ||||
| "Content-Type": "application/json", | "Content-Type": "application/json", | ||||
| }, | }, | ||||
| //withCredentials: true, | //withCredentials: true, | ||||
| // paramsSerializer: (params) => | |||||
| // queryString.stringify(params, { arrayFormat: 'comma' }), | |||||
| paramsSerializer: (params) => | |||||
| queryString.stringify(params, { arrayFormat: "comma" }), | |||||
| }); | }); | ||||
| export const getRequest = (url, params = null, options = null) => | export const getRequest = (url, params = null, options = null) => |
| import { getRequest, postRequest } from "./index"; | |||||
| import { getRequest, postRequest, replaceInUrl } from "./index"; | |||||
| import apiEndpoints from "./apiEndpoints"; | import apiEndpoints from "./apiEndpoints"; | ||||
| export const getUsernames = (emailorusername) => | export const getUsernames = (emailorusername) => | ||||
| export const attemptLogin = (payload) => | export const attemptLogin = (payload) => | ||||
| postRequest(apiEndpoints.authentications.login, payload); | postRequest(apiEndpoints.authentications.login, payload); | ||||
| export const attemptAuthProvider = (provider, search) => | |||||
| getRequest( | |||||
| replaceInUrl(apiEndpoints.authentications.authProvider, { | |||||
| provider, | |||||
| search, | |||||
| }) | |||||
| ); | |||||
| export const attemptRegister = (payload) => | export const attemptRegister = (payload) => | ||||
| postRequest(apiEndpoints.authentications.register, payload); | postRequest(apiEndpoints.authentications.register, payload); | ||||
| import { createErrorType, createFetchType, createSuccessType } from "../actionHelpers"; | |||||
| export const AUTH_PROVIDER_SCOPE = 'AUTH_PROVIDER'; | |||||
| export const AUTH_PROVIDER_FETCH = createFetchType(AUTH_PROVIDER_SCOPE); | |||||
| export const AUTH_PROVIDER_SUCCESS = createSuccessType(AUTH_PROVIDER_SCOPE); | |||||
| export const AUTH_PROVIDER_ERROR = createErrorType(AUTH_PROVIDER_SCOPE); |
| import { | |||||
| AUTH_PROVIDER_ERROR, | |||||
| AUTH_PROVIDER_FETCH, | |||||
| AUTH_PROVIDER_SUCCESS, | |||||
| } from "./authProviderActionConstants"; | |||||
| export const fetchAuthProvider = (payload) => ({ | |||||
| type: AUTH_PROVIDER_FETCH, | |||||
| payload, | |||||
| }); | |||||
| export const fetchAuthProviderSuccess = (payload) => ({ | |||||
| type: AUTH_PROVIDER_SUCCESS, | |||||
| payload, | |||||
| }); | |||||
| export const fetchAuthProviderError = (payload) => ({ | |||||
| type: AUTH_PROVIDER_ERROR, | |||||
| payload, | |||||
| }); |
| import createReducer from "../../utils/createReducer"; | |||||
| import { | |||||
| AUTH_PROVIDER_ERROR, | |||||
| AUTH_PROVIDER_SUCCESS, | |||||
| } from "../../actions/authProvider/authProviderActionConstants"; | |||||
| const initialState = { | |||||
| success: "", | |||||
| errorMessage: "", | |||||
| }; | |||||
| export default createReducer( | |||||
| { | |||||
| [AUTH_PROVIDER_SUCCESS]: setProvider, | |||||
| [AUTH_PROVIDER_ERROR]: setProviderError, | |||||
| }, | |||||
| initialState | |||||
| ); | |||||
| function setProvider(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| successMessage: action.payload, | |||||
| }; | |||||
| } | |||||
| function setProviderError(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| errorMessage: action.payload, | |||||
| }; | |||||
| } | |||||
| import userReducer from './user/userReducer'; | import userReducer from './user/userReducer'; | ||||
| import randomDataReducer from './randomData/randomDataReducer'; | import randomDataReducer from './randomData/randomDataReducer'; | ||||
| import registerReducer from './register/registerReducer' | import registerReducer from './register/registerReducer' | ||||
| import auhtProviderReducer from './authProvider/auhtProviderReducer'; | |||||
| export default combineReducers({ | export default combineReducers({ | ||||
| login: loginReducer, | login: loginReducer, | ||||
| loading:loadingReducer, | loading:loadingReducer, | ||||
| randomData: randomDataReducer, | randomData: randomDataReducer, | ||||
| register: registerReducer, | register: registerReducer, | ||||
| authProvider: auhtProviderReducer | |||||
| }); | }); |
| import { all, call, put, takeLatest } from "@redux-saga/core/effects"; | |||||
| import { attemptAuthProvider } from "../../request/loginRequest"; | |||||
| import { | |||||
| fetchUserError, | |||||
| fetchUserSuccess, | |||||
| } from "../actions/login/loginActions"; | |||||
| import { setUser } from "../actions/user/userActions"; | |||||
| import { addHeaderToken } from "../../request"; | |||||
| import { | |||||
| JWT_REFRESH_TOKEN, | |||||
| JWT_TOKEN, | |||||
| } from "../../constants/localStorage"; | |||||
| import { | |||||
| authScopeSetHelper, | |||||
| } from "../../util/helpers/authScopeHelpers"; | |||||
| import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| import { AUTH_PROVIDER_FETCH } from "../actions/authProvider/authProviderActionConstants"; | |||||
| import { fetchAuthProviderError, fetchAuthProviderSuccess } from "../actions/authProvider/authProviderActions"; | |||||
| function* fetchAuthProvider({ payload }) { | |||||
| try { | |||||
| const { data } = yield call(attemptAuthProvider, payload.provider, payload.search); | |||||
| if (data?.jwt) { | |||||
| const user = data?.user; | |||||
| yield call(authScopeSetHelper, JWT_TOKEN, data.jwt); | |||||
| yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data?.refreshToken); | |||||
| yield call(addHeaderToken, data?.jwt); | |||||
| yield put(setUser(user)); | |||||
| } | |||||
| yield put(fetchUserSuccess(data)); | |||||
| yield put (fetchAuthProviderSuccess('Success')) | |||||
| if (payload.handleApiResponseSuccess) { | |||||
| yield call(payload.handleApiResponseSuccess); | |||||
| } | |||||
| } catch (e) { | |||||
| if (e.response && e.response.data) { | |||||
| const errorMessage = yield call(rejectErrorCodeHelper, e); | |||||
| yield put(fetchUserError(errorMessage)); | |||||
| yield put(fetchAuthProviderError('Error')) | |||||
| } | |||||
| } | |||||
| } | |||||
| export default function* authProviderSaga() { | |||||
| yield all([ | |||||
| takeLatest(AUTH_PROVIDER_FETCH, fetchAuthProvider), | |||||
| ]); | |||||
| } |
| import { all } from "redux-saga/effects"; | import { all } from "redux-saga/effects"; | ||||
| import loginSaga from "./loginSaga"; | import loginSaga from "./loginSaga"; | ||||
| import registerSaga from "./registerSaga"; | import registerSaga from "./registerSaga"; | ||||
| import authProviderSaga from "./authProviderSaga"; | |||||
| export default function* rootSaga() { | export default function* rootSaga() { | ||||
| yield all([loginSaga(), registerSaga()]); | |||||
| yield all([loginSaga(), registerSaga(), authProviderSaga()]); | |||||
| } | } |
| import { createSelector } from 'reselect'; | |||||
| const authProviderSelector = (state) => state.authProvider; | |||||
| export const selectLoginError = createSelector( | |||||
| authProviderSelector, | |||||
| (state) => state.errorMessage, | |||||
| ); |
| resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" | ||||
| integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== | ||||
| qs@^6.11.0: | |||||
| version "6.11.0" | |||||
| resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" | |||||
| integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== | |||||
| dependencies: | |||||
| side-channel "^1.0.4" | |||||
| query-string@^4.1.0: | query-string@^4.1.0: | ||||
| version "4.3.4" | version "4.3.4" | ||||
| resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" | resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" |