From 74bd298322bc0b54fc863c3f08be8f6d02d5091d Mon Sep 17 00:00:00 2001 From: Markus Tacker Date: Mon, 30 Aug 2021 23:03:54 +0200 Subject: [PATCH] fix: use email instead of username --- db/seeders/20210302050835-demo-groups.js | 2 +- docs/authentication.md | 4 +-- frontend/src/hooks/useAuth.ts | 9 ++++-- frontend/src/pages/PublicHome.tsx | 36 ++++++++++++------------ src/authenticateRequest.ts | 2 +- src/models/user_account.ts | 4 +-- src/routes/login.ts | 6 ++-- src/routes/me.ts | 2 +- src/routes/register.ts | 10 +++---- src/testServer.ts | 4 +-- src/tests/authentication.test.ts | 14 ++++----- src/tests/groups_api.test.ts | 19 +++++++------ src/tests/helpers/index.ts | 4 +-- src/tests/line_items_api.test.ts | 2 +- src/tests/offers_api.test.ts | 2 +- src/tests/pallets_api.test.ts | 2 +- src/tests/shipment_exports_api.test.ts | 2 +- 17 files changed, 65 insertions(+), 59 deletions(-) diff --git a/db/seeders/20210302050835-demo-groups.js b/db/seeders/20210302050835-demo-groups.js index 1d98d385a..33bd52158 100644 --- a/db/seeders/20210302050835-demo-groups.js +++ b/db/seeders/20210302050835-demo-groups.js @@ -6,7 +6,7 @@ module.exports = { up: async (queryInterface, Sequelize) => { await queryInterface.bulkInsert('UserAccounts', [ { - username: 'seeded-account-id', + email: 'seeded-account-id@example.com', createdAt: new Date(), updatedAt: new Date(), }, diff --git a/docs/authentication.md b/docs/authentication.md index 4446cf0ab..0de517c08 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -2,11 +2,11 @@ The backend authenticates requests using signed cookies which contains user's id so that it does not have to be fetched for every request. -Cookies are sent [`secure` and `HttpOnly`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) when users register their account, or when they log in using username and password. +Cookies are sent [`secure` and `HttpOnly`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) when users register their account, or when they log in using email and password. Cookies expire after 30 minutes and the client is responsible for renewing cookies by calling the `GET /me/cookie` endpoint before they expire. -When renewing cookies, the server will re-check if the user still exists and if they haven't changed their password. For this a hash of the user's password hash, email, username, and id will be generated and included in the cookie. If any of these properties changes, the cookie cannot be renewed and the user has to log-in again. +When renewing cookies, the server will re-check if the user still exists and if they haven't changed their password. For this a hash of the user's password hash, email, and id will be generated and included in the cookie. If any of these properties changes, the cookie cannot be renewed and the user has to log-in again. ## Admin permissions diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts index 60acb771b..5c6435ed4 100644 --- a/frontend/src/hooks/useAuth.ts +++ b/frontend/src/hooks/useAuth.ts @@ -9,17 +9,20 @@ export const useAuth = () => { isLoading, isAuthenticated, logout: () => { - // FIXME: clear cookies and reload + // Delete cookies (since the auth cookie is httpOnly we cannot access + // it using JavaScript, e.g. cookie.delete() will not work). + // Therefore we ask the server to send us an invalid cookie. fetch(`${SERVER_URL}/me/cookie`, { method: 'DELETE' }).then(() => { setIsAuthenticated(false) + // Reload the page (no need to handle logout in the app) document.location.reload() }) }, - login: ({ username, password }: { username: string; password: string }) => { + login: ({ email, password }: { email: string; password: string }) => { setIsLoading(true) fetch(`${SERVER_URL}/me/login`, { method: 'POST', - body: JSON.stringify({ username, password }), + body: JSON.stringify({ email, password }), }) .then(() => { setIsAuthenticated(true) diff --git a/frontend/src/pages/PublicHome.tsx b/frontend/src/pages/PublicHome.tsx index fc6ac1e31..7210491be 100644 --- a/frontend/src/pages/PublicHome.tsx +++ b/frontend/src/pages/PublicHome.tsx @@ -5,18 +5,18 @@ import { useAuth } from '../hooks/useAuth' const SERVER_URL = process.env.REACT_APP_SERVER_URL +const emailRegEx = /.+@.+\..+/ +const passwordRegEx = + /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/ + const PublicHomePage: FunctionComponent = () => { const { login } = useAuth() const [showRegisterForm, setShowRegisterForm] = useState(false) - const [username, setUsername] = useState('') + const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [password2, setPassword2] = useState('') - const loginFormValid = - username.length > 0 && - /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test( - password, - ) + const loginFormValid = emailRegEx.test(email) && passwordRegEx.test(password) const registerFormValid = loginFormValid && password === password2 @@ -36,11 +36,11 @@ const PublicHomePage: FunctionComponent = () => { {showLoginForm && (
setUsername(value)} + label="email" + type="email" + name="email" + value={email} + onChange={({ target: { value } }) => setEmail(value)} /> {