| @@ -25,6 +25,7 @@ | |||
| "i18next": "^20.3.1", | |||
| "json-server": "^0.17.0", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "jwt-decode": "^3.1.2", | |||
| "lodash": "^4.17.21", | |||
| "lodash.isempty": "^4.4.0", | |||
| "owasp-password-strength-test": "^1.3.0", | |||
| @@ -14589,6 +14590,11 @@ | |||
| "safe-buffer": "^5.0.1" | |||
| } | |||
| }, | |||
| "node_modules/jwt-decode": { | |||
| "version": "3.1.2", | |||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| }, | |||
| "node_modules/keyv": { | |||
| "version": "3.1.0", | |||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | |||
| @@ -35542,6 +35548,11 @@ | |||
| "safe-buffer": "^5.0.1" | |||
| } | |||
| }, | |||
| "jwt-decode": { | |||
| "version": "3.1.2", | |||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| }, | |||
| "keyv": { | |||
| "version": "3.1.0", | |||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | |||
| @@ -20,6 +20,7 @@ | |||
| "i18next": "^20.3.1", | |||
| "json-server": "^0.17.0", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "jwt-decode": "^3.1.2", | |||
| "lodash": "^4.17.21", | |||
| "lodash.isempty": "^4.4.0", | |||
| "owasp-password-strength-test": "^1.3.0", | |||
| @@ -31,6 +31,7 @@ | |||
| Learn how to configure a non-root public URL by running `npm run build`. | |||
| --> | |||
| <title>React App</title> | |||
| <script src="https://accounts.google.com/gsi/client" async defer></script> | |||
| </head> | |||
| <body> | |||
| <noscript>You need to enable JavaScript to run this app.</noscript> | |||
| @@ -8,10 +8,12 @@ import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import HrLogo from "../../assets/images/hrcenter.png"; | |||
| import DiligLogo from "../../assets/images/logo_horizontal_black.png"; | |||
| import jwt_decode from 'jwt-decode'; | |||
| import googleLogo from "../../assets/images/google1.png"; | |||
| import { | |||
| clearLoginErrors, | |||
| fetchUser, | |||
| fetchGoogleUser | |||
| } from "../../store/actions/login/loginActions"; | |||
| import { selectLoginError } from "../../store/selectors/loginSelectors"; | |||
| import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages"; | |||
| @@ -52,6 +54,20 @@ const LoginPage = ({ history }) => { | |||
| // redirectClient(); | |||
| // }, [history]); | |||
| const handleCallbackResponse = (response) => { | |||
| console.log(response.credential); | |||
| const userObject = jwt_decode(response.credential); | |||
| console.log(userObject); | |||
| const username = userObject.email; | |||
| dispatch(clearLoginErrors()); | |||
| dispatch( | |||
| fetchGoogleUser({ | |||
| username, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| } | |||
| const isLoading = useSelector( | |||
| selectIsLoadingByActionType(LOGIN_USER_LOADING) | |||
| ); | |||
| @@ -77,6 +93,19 @@ const LoginPage = ({ history }) => { | |||
| ); | |||
| }; | |||
| const handleGoogleSubmit = (values) => { | |||
| /* global google */ | |||
| google.accounts.id.initialize({ | |||
| client_id: "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com", | |||
| callback: handleCallbackResponse | |||
| }); | |||
| google.accounts.id.renderButton( | |||
| document.getElementById("signInDiv"), | |||
| { theme: "outline", size: "large"} | |||
| ); | |||
| }; | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| username: "", | |||
| @@ -187,6 +216,7 @@ const LoginPage = ({ history }) => { | |||
| <Button | |||
| className="c-btn c-btn--gray flex-center" | |||
| sx={{ width: "100%", mt: 2 }} | |||
| onClick={handleGoogleSubmit} | |||
| > | |||
| <img src={googleLogo} style={{ marginRight: "15px" }} /> | |||
| <Typography sx={{ m: 0, p: 0 }} variant="buttonText"> | |||
| @@ -198,6 +228,7 @@ const LoginPage = ({ history }) => { | |||
| </div> | |||
| </Box> | |||
| </Box> | |||
| <div id='signInDiv'></div> | |||
| </Container> | |||
| ); | |||
| }; | |||
| @@ -1,5 +1,8 @@ | |||
| const base = "http://localhost:26081/v1"; | |||
| export default { | |||
| authentications: { | |||
| login: 'http://localhost:26081/v1/users/authenticate', | |||
| login: base + '/users/authenticate', | |||
| googleLogin: base + '/users/authenticateGoogle', | |||
| }, | |||
| }; | |||
| @@ -9,6 +9,9 @@ export const getUsernames = (emailorusername) => | |||
| export const attemptLogin = (payload) => | |||
| postRequest(apiEndpoints.authentications.login, payload); | |||
| export const attemptGoogleLogin = (payload) => | |||
| postRequest(apiEndpoints.authentications.googleLogin, payload); | |||
| export const updateSecurityAnswer = (payload) => | |||
| postRequest(apiEndpoints.authentications.confirmSecurityQuestion, payload); | |||
| @@ -17,6 +17,15 @@ export const CLEAR_LOGIN_USER_ERROR = createClearType( | |||
| ); | |||
| export const LOGIN_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | |||
| const LOGIN_GOOGLE_USER_SCOPE = 'LOGIN_GOOGLE_USER'; | |||
| export const LOGIN_GOOGLE_USER_FETCH = createFetchType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const LOGIN_GOOGLE_USER_SUCCESS = createSuccessType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const LOGIN_GOOGLE_USER_ERROR = createErrorType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const CLEAR_LOGIN_GOOGLE_USER_ERROR = createClearType( | |||
| `${LOGIN_GOOGLE_USER_SCOPE}_ERROR`, | |||
| ); | |||
| export const LOGIN_GOOGLE_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | |||
| export const UPDATE_USER_JWT_TOKEN = 'UPDATE_USER_JWT_TOKEN'; | |||
| export const RESET_LOGIN_STATE = 'RESET_LOGIN_STATE'; | |||
| @@ -4,6 +4,9 @@ import { | |||
| LOGIN_USER_ERROR, | |||
| LOGIN_USER_FETCH, | |||
| LOGIN_USER_SUCCESS, | |||
| LOGIN_GOOGLE_USER_ERROR, | |||
| LOGIN_GOOGLE_USER_FETCH, | |||
| LOGIN_GOOGLE_USER_SUCCESS, | |||
| LOGOUT_USER, | |||
| RESET_LOGIN_STATE, | |||
| UPDATE_USER_JWT_TOKEN, | |||
| @@ -19,16 +22,31 @@ export const fetchUser = (payload) => ({ | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUser = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_FETCH, | |||
| payload, | |||
| }); | |||
| export const fetchUserSuccess = (payload) => ({ | |||
| type: LOGIN_USER_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUserSuccess = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const fetchUserError = (payload) => ({ | |||
| type: LOGIN_USER_ERROR, | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUserError = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_ERROR, | |||
| payload, | |||
| }); | |||
| export const updateUserToken = (payload) => ({ | |||
| type: UPDATE_USER_JWT_TOKEN, | |||
| payload, | |||
| @@ -3,12 +3,14 @@ import jwt from 'jsonwebtoken'; | |||
| import history from '../utils/history'; | |||
| import { | |||
| AUTHENTICATE_USER, | |||
| LOGIN_GOOGLE_USER_FETCH, | |||
| LOGIN_USER_FETCH, | |||
| LOGOUT_USER, | |||
| REFRESH_TOKEN, | |||
| GENERATE_TOKEN, | |||
| } from '../actions/login/loginActionConstants'; | |||
| import { | |||
| attemptGoogleLogin, | |||
| attemptLogin, | |||
| logoutUserRequest, | |||
| refreshTokenRequest, | |||
| @@ -68,6 +70,31 @@ function* fetchUser({ payload }) { | |||
| } | |||
| } | |||
| } | |||
| function* fetchGoogleUser({ payload }) { | |||
| try { | |||
| const { data } = yield call(attemptGoogleLogin, payload); | |||
| if (data.token) { | |||
| const user = jwt.decode(data.token); | |||
| yield call(authScopeSetHelper, JWT_TOKEN, data.token); | |||
| yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken); | |||
| yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken); | |||
| yield call(addHeaderToken, data.token); | |||
| yield put(setUser(user)); | |||
| } | |||
| yield put(fetchUserSuccess(data)); | |||
| if (payload.handleApiResponseSuccess) { | |||
| yield call(payload.handleApiResponseSuccess); | |||
| } | |||
| } catch (e) { | |||
| if (e.response && e.response.data) { | |||
| if (payload.handleApiResponseFailed) { | |||
| yield call(payload.handleApiResponseFailed); | |||
| } | |||
| const errorMessage = yield call(rejectErrorCodeHelper, e); | |||
| yield put(fetchUserError(errorMessage)); | |||
| } | |||
| } | |||
| } | |||
| function* authenticateUser() { | |||
| try { | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| @@ -171,6 +198,7 @@ export function* generateToken({ payload }) { | |||
| export default function* loginSaga() { | |||
| yield all([ | |||
| takeLatest(LOGIN_USER_FETCH, fetchUser), | |||
| takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser), | |||
| takeLatest(AUTHENTICATE_USER, authenticateUser), | |||
| takeLatest(LOGOUT_USER, logoutUser), | |||
| takeLatest(REFRESH_TOKEN, refreshToken), | |||
| @@ -7845,6 +7845,11 @@ | |||
| "jwa" "^1.4.1" | |||
| "safe-buffer" "^5.0.1" | |||
| "jwt-decode@^3.1.2": | |||
| "integrity" "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| "resolved" "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" | |||
| "version" "3.1.2" | |||
| "keyv@^3.0.0": | |||
| "integrity" "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==" | |||
| "resolved" "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" | |||