From 1c402b44cc61316fb7b83c1c34cc6ba01d2cbf50 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 22 Nov 2020 17:39:05 +0100 Subject: [PATCH 1/4] added cookies check and logout --- webapp_frontend/src/background/api/auth.ts | 36 +++++++++++++++++-- .../src/background/methods/cookies.tsx | 28 +++++++++++++++ .../background/redux/actions/tokenTypes.tsx | 9 +++-- .../src/background/redux/actions/tokens.tsx | 5 ++- .../src/background/redux/reducers/tokens.tsx | 9 ++++- webapp_frontend/src/components/App.tsx | 3 +- .../src/components/basicElements/Login.tsx | 5 +-- .../src/components/pages/Health.tsx | 6 ++-- 8 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 webapp_frontend/src/background/methods/cookies.tsx diff --git a/webapp_frontend/src/background/api/auth.ts b/webapp_frontend/src/background/api/auth.ts index 6bb3fbdb..5d1cca4d 100644 --- a/webapp_frontend/src/background/api/auth.ts +++ b/webapp_frontend/src/background/api/auth.ts @@ -5,20 +5,38 @@ import {hostname, userPath} from "./api"; import {AddUser, UserState} from "../redux/actions/userTypes"; import store from "../redux/store"; -import {addAccessToken, addRefreshToken} from "../redux/actions/tokens"; +import {addAccessToken, addRefreshToken, checkedCookies, removeTokens} from "../redux/actions/tokens"; import {addUser} from "../redux/actions/user"; -import {AccessToken, AddAccessToken, AddRefreshToken, TokensState} from "../redux/actions/tokenTypes"; +import {AccessToken, AddAccessToken, AddRefreshToken, CheckedCookies, RemoveTokens, TokensState} from "../redux/actions/tokenTypes"; +import {deleteCookie, getCookie, setCookie} from "../methods/cookies"; // reference: https://daveceddia.com/access-redux-store-outside-react/ + +const cookieName:string='refreshToken'; + export interface BackendLoginData { refreshToken: string, user: UserState } -export const loginWithUsernameAndPassword = (userName: string, password: string): Promise => { + +export const checkForCookie=()=>{ + let refreshTokenCookieValue=getCookie(cookieName) + if (refreshTokenCookieValue){ + store.dispatch(addRefreshToken(refreshTokenCookieValue) as AddRefreshToken) + getAccessTokenWithRefreshToken(); + } + store.dispatch(checkedCookies(true) as CheckedCookies) + + +} + + + +export const loginWithUsernameAndPassword = (userName: string, password: string,stayLoggedIn:boolean): Promise => { return new Promise((resolve, reject) => { let config = { @@ -32,6 +50,11 @@ export const loginWithUsernameAndPassword = (userName: string, password: string) store.dispatch(addRefreshToken(data.data.refreshToken) as AddRefreshToken) store.dispatch(addUser(data.data.user as UserState) as AddUser) + if (stayLoggedIn){ + setCookie(cookieName,data.data.refreshToken,60) + } + + getAccessTokenWithRefreshToken() }) .catch(((error) => { @@ -63,11 +86,18 @@ export const getAccessTokenWithRefreshToken = () => { }) .catch(((error) => { + store.dispatch(removeTokens()as RemoveTokens); + console.log(error) })); } +export const logout=()=>{ + store.dispatch(removeTokens()as RemoveTokens); + deleteCookie(cookieName); +} + function setAuthHeaderToAxios(accessToken: string) { Axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`; diff --git a/webapp_frontend/src/background/methods/cookies.tsx b/webapp_frontend/src/background/methods/cookies.tsx new file mode 100644 index 00000000..ecb7c139 --- /dev/null +++ b/webapp_frontend/src/background/methods/cookies.tsx @@ -0,0 +1,28 @@ +export function getCookie(cname:string) { + let name = cname + "="; + let decodedCookie = decodeURIComponent(document.cookie); + let ca = decodedCookie.split(';'); + for(let i = 0; i ({ @@ -11,6 +11,9 @@ export const addAccessToken = (content: AccessToken) => ({ payload: content }); +export const removeTokens = ()=>({ + type: REMOVE_TOKENS +}) export const checkedCookies = (content: boolean) => ({ type: CHECKED_COOKIES, diff --git a/webapp_frontend/src/background/redux/reducers/tokens.tsx b/webapp_frontend/src/background/redux/reducers/tokens.tsx index bcb78587..3a263025 100644 --- a/webapp_frontend/src/background/redux/reducers/tokens.tsx +++ b/webapp_frontend/src/background/redux/reducers/tokens.tsx @@ -1,4 +1,4 @@ -import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, TokenActionsTypes, TokensState, AccessToken, CHECKED_COOKIES} from "../actions/tokenTypes"; +import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, TokenActionsTypes, TokensState, AccessToken, CHECKED_COOKIES, REMOVE_TOKENS} from "../actions/tokenTypes"; const initialState: TokensState = { refreshToken: null, @@ -26,6 +26,13 @@ export default function (state = initialState, action: TokenActionsTypes) { checkedCookies: state.checkedCookies }; } + case REMOVE_TOKENS:{ + return { + refreshToken: null, + accessToken: null, + checkedCookies: false + } + } case CHECKED_COOKIES: { return { refreshToken: state.refreshToken, diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx index 10b0594d..6d66e61c 100644 --- a/webapp_frontend/src/components/App.tsx +++ b/webapp_frontend/src/components/App.tsx @@ -13,6 +13,7 @@ import {addAccessToken, addRefreshToken, checkedCookies} from "../background/red import {SystemState} from "../background/redux/actions/sytemState"; import Login from "./basicElements/Login"; +import {checkForCookie} from "../background/api/auth"; @@ -63,7 +64,7 @@ function App(props: Props): ReactElement { return () } } else { - props.checkedCookies(true) + checkForCookie(); return (
Loading
) } diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx index b10c0191..39063826 100644 --- a/webapp_frontend/src/components/basicElements/Login.tsx +++ b/webapp_frontend/src/components/basicElements/Login.tsx @@ -12,14 +12,15 @@ function Login(): ReactElement { const handleSubmit = (event: FormEvent) => { event.preventDefault(); - loginWithUsernameAndPassword(userName, password) + loginWithUsernameAndPassword(userName, password,stayLoggedIn) .then(() => { //nothing to do here :) setErrorMessage(""); }) .catch(((error) => { console.log(error); - setErrorMessage(error.response.data.message); + + setErrorMessage(error.response?.data.message); })) diff --git a/webapp_frontend/src/components/pages/Health.tsx b/webapp_frontend/src/components/pages/Health.tsx index 16cfdf58..8a193d92 100644 --- a/webapp_frontend/src/components/pages/Health.tsx +++ b/webapp_frontend/src/components/pages/Health.tsx @@ -3,6 +3,7 @@ import logo from "../../assets/images/logos/logo.png"; import {Button, Table} from "react-bootstrap"; import {callBackendHealth} from "../../background/api/api"; import {audioOnOff, setAudioVolumeByID} from "../../background/methods/sound" +import {logout} from "../../background/api/auth"; export default function Health() { @@ -11,7 +12,7 @@ export default function Health() { useEffect(() => { updateVariables() - },[]); + }, []); function updateVariables(): void { Promise.all([callBackendHealth()]) @@ -58,6 +59,7 @@ export default function Health() { + ) -} \ No newline at end of file +} From dba9f85feb657af2d504a73c94c2b753b805284c Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 22 Nov 2020 18:03:33 +0100 Subject: [PATCH 2/4] fixed minor bugs --- webapp_frontend/src/background/api/auth.ts | 1 + webapp_frontend/src/background/constants.tsx | 3 ++- webapp_frontend/src/background/redux/reducers/tokens.tsx | 2 +- webapp_frontend/src/components/App.tsx | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/webapp_frontend/src/background/api/auth.ts b/webapp_frontend/src/background/api/auth.ts index 5d1cca4d..3f4d152c 100644 --- a/webapp_frontend/src/background/api/auth.ts +++ b/webapp_frontend/src/background/api/auth.ts @@ -89,6 +89,7 @@ export const getAccessTokenWithRefreshToken = () => { store.dispatch(removeTokens()as RemoveTokens); console.log(error) + //you probably want to notify the user, maybe with a toast or similar })); } diff --git a/webapp_frontend/src/background/constants.tsx b/webapp_frontend/src/background/constants.tsx index 0d9a78d0..f77a3cd0 100644 --- a/webapp_frontend/src/background/constants.tsx +++ b/webapp_frontend/src/background/constants.tsx @@ -11,7 +11,8 @@ const prod: constants = { const dev: constants = { url: { - API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001', + API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001', + // API_URL: 'http://localhost:8080', } }; export const constants = process.env.NODE_ENV === 'development' ? dev : prod; diff --git a/webapp_frontend/src/background/redux/reducers/tokens.tsx b/webapp_frontend/src/background/redux/reducers/tokens.tsx index 3a263025..7eab26c7 100644 --- a/webapp_frontend/src/background/redux/reducers/tokens.tsx +++ b/webapp_frontend/src/background/redux/reducers/tokens.tsx @@ -30,7 +30,7 @@ export default function (state = initialState, action: TokenActionsTypes) { return { refreshToken: null, accessToken: null, - checkedCookies: false + checkedCookies: true } } case CHECKED_COOKIES: { diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx index 6d66e61c..57e56fce 100644 --- a/webapp_frontend/src/components/App.tsx +++ b/webapp_frontend/src/components/App.tsx @@ -45,7 +45,7 @@ function App(props: Props): ReactElement { if (props.tokens.checkedCookies) { - if (props.tokens.refreshToken) { + if (props.tokens.refreshToken && props.tokens.accessToken) { return (
From 8a9ca0375cb2512598011d8fad8a14815c887c5f Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 22 Nov 2020 18:23:18 +0100 Subject: [PATCH 3/4] added loading --- webapp_frontend/src/background/api/auth.ts | 11 +++++----- .../src/components/basicElements/Login.tsx | 22 ++++++++++++++----- webapp_frontend/src/style/custom.scss | 1 + 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/webapp_frontend/src/background/api/auth.ts b/webapp_frontend/src/background/api/auth.ts index 3f4d152c..5f70bd26 100644 --- a/webapp_frontend/src/background/api/auth.ts +++ b/webapp_frontend/src/background/api/auth.ts @@ -37,7 +37,7 @@ export const checkForCookie=()=>{ export const loginWithUsernameAndPassword = (userName: string, password: string,stayLoggedIn:boolean): Promise => { - +console.log("[Auth] loginWithUsernameAndPassword") return new Promise((resolve, reject) => { let config = { headers: { @@ -47,11 +47,12 @@ export const loginWithUsernameAndPassword = (userName: string, password: string, return Axios.get(hostname + userPath + '/login', config) .then((data) => { - store.dispatch(addRefreshToken(data.data.refreshToken) as AddRefreshToken) + console.log(data.data) + store.dispatch(addRefreshToken(data.data.tokenValue) as AddRefreshToken) store.dispatch(addUser(data.data.user as UserState) as AddUser) if (stayLoggedIn){ - setCookie(cookieName,data.data.refreshToken,60) + setCookie(cookieName,data.data.tokenValue,60) } @@ -80,9 +81,9 @@ export const getAccessTokenWithRefreshToken = () => { Axios.get(hostname + userPath + '/auth', config) .then((data) => { - setAuthHeaderToAxios(data.data.token) + setAuthHeaderToAxios(data.data.tokenValue) - store.dispatch(addAccessToken({token: data.data.token, timestamp: data.data.validUntil}as AccessToken) as AddAccessToken); + store.dispatch(addAccessToken({token: data.data.tokenValue, timestamp: data.data.validUntil}as AccessToken) as AddAccessToken); }) .catch(((error) => { diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx index 39063826..95a3b163 100644 --- a/webapp_frontend/src/components/basicElements/Login.tsx +++ b/webapp_frontend/src/components/basicElements/Login.tsx @@ -1,6 +1,7 @@ import React, {FormEvent, ReactElement, useState} from 'react'; -import {Button, Form, Container, Row,Col} from "react-bootstrap"; +import {Button, Form, Container, Row,Col,Spinner} from "react-bootstrap"; import {loginWithUsernameAndPassword} from "../../background/api/auth"; +import {Simulate} from "react-dom/test-utils"; function Login(): ReactElement { @@ -8,18 +9,21 @@ function Login(): ReactElement { const [password, setPassword] = useState(""); const [stayLoggedIn, setStayLoggedIn] = useState(false); const [errorMessage, setErrorMessage] = useState(""); + const [loading,setLoading]=useState(false); const handleSubmit = (event: FormEvent) => { event.preventDefault(); + setLoading(true) loginWithUsernameAndPassword(userName, password,stayLoggedIn) .then(() => { //nothing to do here :) setErrorMessage(""); + setLoading(false); }) .catch(((error) => { console.log(error); - + setLoading(false) setErrorMessage(error.response?.data.message); })) @@ -45,11 +49,19 @@ function Login(): ReactElement { - setStayLoggedIn(!stayLoggedIn)}/> + setStayLoggedIn(!stayLoggedIn)}/> - +

{errorMessage}

diff --git a/webapp_frontend/src/style/custom.scss b/webapp_frontend/src/style/custom.scss index 6fdb2183..f9e685e4 100644 --- a/webapp_frontend/src/style/custom.scss +++ b/webapp_frontend/src/style/custom.scss @@ -23,3 +23,4 @@ $blue: #1a4965; @import "~bootstrap/scss/tables"; @import "~bootstrap/scss/utilities"; @import "~bootstrap/scss/forms"; +@import "~bootstrap/scss/spinners"; From 233c0d43b92d728607eab2c22a7741c3ae422fb4 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 22 Nov 2020 18:27:33 +0100 Subject: [PATCH 4/4] fixed bad import --- webapp_frontend/src/components/basicElements/Login.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx index 95a3b163..adea9893 100644 --- a/webapp_frontend/src/components/basicElements/Login.tsx +++ b/webapp_frontend/src/components/basicElements/Login.tsx @@ -1,8 +1,6 @@ import React, {FormEvent, ReactElement, useState} from 'react'; import {Button, Form, Container, Row,Col,Spinner} from "react-bootstrap"; import {loginWithUsernameAndPassword} from "../../background/api/auth"; -import {Simulate} from "react-dom/test-utils"; - function Login(): ReactElement { const [userName, setUsername] = useState("");