From 497cb1a70c10ab162bb6fd40e364343bc6cfb5bb Mon Sep 17 00:00:00 2001 From: Jimmy Liu Date: Thu, 25 Jul 2024 20:50:02 -0400 Subject: [PATCH 1/9] Implement password change frontend and backend * Used Firebase REST API to change password --- backend/middlewares/auth.ts | 20 +- .../middlewares/validators/authValidators.ts | 12 + backend/package.json | 3 + backend/rest/authRoutes.ts | 18 + backend/server.ts | 2 + .../services/implementations/authService.ts | 67 +++- .../services/implementations/userService.ts | 18 + backend/services/interfaces/authService.ts | 11 +- backend/services/interfaces/userService.ts | 10 + backend/utilities/firebaseRestClient.ts | 36 ++ backend/yarn.lock | 367 +++++++++++++++++- docker-compose.yml | 19 +- frontend/src/APIClients/AuthAPIClient.ts | 19 + frontend/src/App.tsx | 1 + frontend/src/components/auth/Login.tsx | 2 +- frontend/src/components/auth/PrivateRoute.tsx | 5 +- .../components/pages/CreatePasswordPage.tsx | 63 +++ frontend/src/constants/Routes.ts | 8 + frontend/src/types/AuthTypes.ts | 3 + 19 files changed, 658 insertions(+), 26 deletions(-) create mode 100644 frontend/src/components/pages/CreatePasswordPage.tsx diff --git a/backend/middlewares/auth.ts b/backend/middlewares/auth.ts index 5c02efc..9453124 100644 --- a/backend/middlewares/auth.ts +++ b/backend/middlewares/auth.ts @@ -3,9 +3,11 @@ import { NextFunction, Request, Response } from "express"; import AuthService from "../services/implementations/authService"; import UserService from "../services/implementations/userService"; import IAuthService from "../services/interfaces/authService"; -import { Role } from "../types/userTypes"; +import IUserService from "../services/interfaces/userService"; +import { Role, Status } from "../types/userTypes"; const authService: IAuthService = new AuthService(new UserService()); +const userService: IUserService = new UserService(); export const getAccessToken = (req: Request): string | null => { const authHeaderParts = req.headers.authorization?.split(" "); @@ -76,3 +78,19 @@ export const isAuthorizedByEmail = (emailField: string) => { return next(); }; }; + +export const isFirstTimeInvitedUser = () => { + return async (req: Request, res: Response, next: NextFunction) => { + console.log("hit check first time invitation") + const accessToken = getAccessToken(req); + const authorized = + accessToken && + await userService.isFirstTimeInvitedUser(accessToken); + if (!authorized) { + return res + .status(401) + .json({ error: "You are not a first-time invited administrator." }) + } + return next(); + } +} diff --git a/backend/middlewares/validators/authValidators.ts b/backend/middlewares/validators/authValidators.ts index 58f2b47..511b50d 100644 --- a/backend/middlewares/validators/authValidators.ts +++ b/backend/middlewares/validators/authValidators.ts @@ -71,5 +71,17 @@ export const forgotPasswordRequestValidator = async ( return res.status(400).send(getApiValidationError("email", "string")); } + return next(); +} + +export const updateTemporaryPasswordRequestValidator = async ( + req: Request, + res: Response, + next: NextFunction, +) => { + if (!validatePrimitive(req.body.newPassword, "string")) { + return res.status(400).send(getApiValidationError("newPassword", "string")); + } + return next(); }; diff --git a/backend/package.json b/backend/package.json index 353aa03..3bdaa32 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,6 +15,8 @@ "author": "", "license": "ISC", "dependencies": { + "@firebase/app": "^0.10.6", + "@firebase/auth": "^1.7.4", "@types/json2csv": "^5.0.3", "@types/multer": "^1.4.6", "@types/swagger-ui-express": "^4.1.2", @@ -25,6 +27,7 @@ "dotenv": "^8.2.0", "express": "^4.19.2", "express-rate-limit": "^6.2.0", + "firebase": "^10.12.3", "firebase-admin": "^9.5.0", "generate-password": "^1.7.1", "json2csv": "^5.0.6", diff --git a/backend/rest/authRoutes.ts b/backend/rest/authRoutes.ts index 03d7af4..cd75549 100644 --- a/backend/rest/authRoutes.ts +++ b/backend/rest/authRoutes.ts @@ -6,12 +6,14 @@ import { isAuthorizedByEmail, isAuthorizedByUserId, isAuthorizedByRole, + isFirstTimeInvitedUser, } from "../middlewares/auth"; import { loginRequestValidator, signupRequestValidator, inviteAdminRequestValidator, forgotPasswordRequestValidator, + updateTemporaryPasswordRequestValidator, } from "../middlewares/validators/authValidators"; import nodemailerConfig from "../nodemailer.config"; import AuthService from "../services/implementations/authService"; @@ -214,4 +216,20 @@ authRouter.post( }, ); +authRouter.post( + "/updateTemporaryPassword", + updateTemporaryPasswordRequestValidator, + // isFirstTimeInvitedUser, + async (req, res) => { + console.log("Hit route update temporary password") + try { + const accessToken = getAccessToken(req)!; + await authService.changeUserPassword(accessToken, req.body.newPassword); + res.status(204).send(); + } catch (error: unknown) { + res.status(500).json({ error: getErrorMessage(error) }); + } + }, +); + export default authRouter; diff --git a/backend/server.ts b/backend/server.ts index f1df001..3607c4a 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -5,6 +5,8 @@ import { createServer } from "http"; import { Server } from "socket.io"; import RateLimit from "express-rate-limit"; import * as firebaseAdmin from "firebase-admin"; +import * as firebaseAuth from "@firebase/auth" +import * as firebase from "firebase/app"; import swaggerUi from "swagger-ui-express"; import YAML from "yamljs"; diff --git a/backend/services/implementations/authService.ts b/backend/services/implementations/authService.ts index 335b0cc..45f8724 100644 --- a/backend/services/implementations/authService.ts +++ b/backend/services/implementations/authService.ts @@ -16,12 +16,19 @@ class AuthService implements IAuthService { emailService: IEmailService | null; + firebaseAuth: firebaseAuth.Auth; + constructor( userService: IUserService, emailService: IEmailService | null = null, ) { this.userService = userService; this.emailService = emailService; + const firebaseApp = firebase.initializeApp({ + apiKey: process.env.FIREBASE_WEB_API_KEY, + projectId: process.env.FIREBASE_PROJECT_ID, + }); + this.firebaseAuth = firebaseAuth.getAuth(firebaseApp); } /* eslint-disable class-methods-use-this */ @@ -136,25 +143,49 @@ class AuthService implements IAuthService { throw new Error(errorMessage); } - const emailVerificationLink = await firebaseAdmin - .auth() - .generateEmailVerificationLink(email); + try { + const emailVerificationLink = await firebaseAdmin + .auth() + .generateEmailVerificationLink(email); - const emailBody = `Hello,

- You have been invited as an administrator to Smart Saving, Smart Spending. -

- Please click the following link to verify your email and activate your account. - This link is only valid for 1 hour. -

- Verify email -

- To log in for the first time, use your email address and the following temporary password: ${temporaryPassword}`; - - await this.emailService.sendEmail( - email, - "Administrator Invitation: Smart Saving, Smart Spending", - emailBody, - ); + const emailBody = `Hello,

+ You have been invited as an administrator to Smart Saving, Smart Spending. +

+ Please click the following link to verify your email and activate your account. + This link is only valid for 1 hour. +

+ Verify email +

+ To log in for the first time, use your email address and the following temporary password: ${temporaryPassword}`; + + await this.emailService.sendEmail( + email, + "Administrator Invitation: Smart Saving, Smart Spending", + emailBody, + ); + } catch (error: unknown) { + Logger.error( + `Failed to invite new administrator. Reason = ${getErrorMessage(error)}`, + ); + throw error; + } + } + + async changeUserPassword( + accessToken: string, + newPassword: string, + ): Promise { + try { + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin + .auth() + .verifyIdToken(accessToken, true); + await FirebaseRestClient.changePassword(decodedIdToken.uid, newPassword); + } catch (error: unknown) { + Logger.error( + `Failed to change user's password. Reason = ${getErrorMessage(error)}`, + ); + throw error; + } } async isAuthorizedByRole( diff --git a/backend/services/implementations/userService.ts b/backend/services/implementations/userService.ts index ffdfa0b..9b14129 100644 --- a/backend/services/implementations/userService.ts +++ b/backend/services/implementations/userService.ts @@ -6,6 +6,7 @@ import MgUser, { User } from "../../models/user.mgmodel"; import { CreateUserDTO, Role, + Status, UpdateUserDTO, UserDTO, } from "../../types/userTypes"; @@ -343,6 +344,23 @@ class UserService implements IUserService { } return userDtos; } + + async isFirstTimeInvitedUser( + accessToken: string, + ): Promise { + try { + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin + .auth() + .verifyIdToken(accessToken, true); + const { status } = await getMongoUserByAuthId( + decodedIdToken.uid + ); + return status === "Invited"; + } catch (error: unknown) { + Logger.error(`Failed to verify user is first time invited user. Reason = ${getErrorMessage(error)}`); + throw error; + } + } } export default UserService; diff --git a/backend/services/interfaces/authService.ts b/backend/services/interfaces/authService.ts index de54fa0..0092739 100644 --- a/backend/services/interfaces/authService.ts +++ b/backend/services/interfaces/authService.ts @@ -1,6 +1,6 @@ import { ObjectId } from "mongoose"; import { AuthDTO, Token } from "../../types/authTypes"; -import { Role } from "../../types/userTypes"; +import { Role, Status } from "../../types/userTypes"; interface IAuthService { /** @@ -46,12 +46,19 @@ interface IAuthService { /** * Sends an email invitation to an invited administrator with the temporary password specified - * @param email email of new administrator invited + * @param email email address of new administrator invited * @param temporaryPassword the new administrator's temporary password * @throws Error if unable to generate link or send email */ sendAdminInvite(email: string, temporaryPassword: string): Promise; + /** + * Changes a user's password + * @param email the user's email address + * @param newPassword new password chosen to replace the user's old password + */ + changeUserPassword(accessToken: string, newPassword: string): Promise; + /** * Determine if the provided access token is valid and authorized for at least * one of the specified roles diff --git a/backend/services/interfaces/userService.ts b/backend/services/interfaces/userService.ts index c6e1a23..c63646a 100644 --- a/backend/services/interfaces/userService.ts +++ b/backend/services/interfaces/userService.ts @@ -2,6 +2,7 @@ import { ObjectId } from "mongoose"; import { CreateUserDTO, Role, + Status, UpdateUserDTO, UserDTO, } from "../../types/userTypes"; @@ -94,6 +95,15 @@ interface IUserService { * @returns an Array of UserDtos that all have the corresponding role */ getUsersByRole(role: Role): Promise>; + + /** + * Determine if the provided access token is valid and the user to which it belongs has the specified status + * @param accessToken user's access token + * @param status status to check for match + */ + isFirstTimeInvitedUser( + accessToken: string, + ): Promise; } export default IUserService; diff --git a/backend/utilities/firebaseRestClient.ts b/backend/utilities/firebaseRestClient.ts index 4a03738..7c9e365 100644 --- a/backend/utilities/firebaseRestClient.ts +++ b/backend/utilities/firebaseRestClient.ts @@ -9,6 +9,10 @@ const FIREBASE_SIGN_IN_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword"; const FIREBASE_REFRESH_TOKEN_URL = "https://securetoken.googleapis.com/v1/token"; +const FIREBASE_OAUTH_SIGN_IN_URL = + "https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp"; +const FIREBASE_CHANGE_PASSWORD_URL = + "https://identitytoolkit.googleapis.com/v1/accounts:update"; type PasswordSignInResponse = { idToken: string; @@ -117,6 +121,38 @@ const FirebaseRestClient = { refreshToken: (responseJson as RefreshTokenResponse).refresh_token, }; }, + + changePassword: async (authId: string, newPassword: string): Promise => { + const response: Response = await fetch( + `${FIREBASE_CHANGE_PASSWORD_URL}?key=${process.env.FIREBASE_WEB_API_KEY}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + idToken: authId, + password: newPassword, + }), + }, + ); + + const responseJson: + | RefreshTokenResponse + | RequestError = await response.json(); + + if (!response.ok) { + const errorMessage = [ + "Failed to change password via Firebase REST API, status code =", + `${response.status},`, + "error message =", + (responseJson as RequestError).error.message, + ]; + Logger.error(errorMessage.join(" ")); + + throw new Error("Failed to change password via Firebase REST API"); + } + }, }; export default FirebaseRestClient; diff --git a/backend/yarn.lock b/backend/yarn.lock index c9cc876..6a2b947 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -818,11 +818,60 @@ resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.7.0.tgz#c9e16d1b8bed1a991840b8d2a725fb58d0b5899f" integrity sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg== +"@firebase/app-types@0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.2.tgz#8cbcceba784753a7c0066a4809bc22f93adee080" + integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ== + +"@firebase/app@0.10.7", "@firebase/app@^0.10.6": + version "0.10.7" + resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.10.7.tgz#31cba1486c21b5a0cadc0036bfc0cec68ff53c8e" + integrity sha512-7OCd53B+wnk/onbMLn/vM10pDjw97zzWUD8m3swtLYKJIrL+gDZ7HZ4xcbBLw7OB8ikzu8k1ORNjRe2itgAy4g== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/auth-compat@0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.5.10.tgz#7705fc27883a8fafb2e85271e1d5cd7314609276" + integrity sha512-epDhgNIXmhl9DPuTW9Ec5NDJJKMFIdXBXiQI9O0xNHveow/ETtBCY86srzF7iCacqsd30CcpLwwXlhk8Y19Olg== + dependencies: + "@firebase/auth" "1.7.5" + "@firebase/auth-types" "0.12.2" + "@firebase/component" "0.6.8" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + undici "5.28.4" + "@firebase/auth-interop-types@0.1.6": version "0.1.6" resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== +"@firebase/auth-interop-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz#927f1f2139a680b55fef0bddbff2c982b08587e8" + integrity sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ== + +"@firebase/auth-types@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.12.2.tgz#f12d890585866e53b6ab18b16fa4d425c52eee6e" + integrity sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w== + +"@firebase/auth@1.7.5", "@firebase/auth@^1.7.4": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.7.5.tgz#8135e0933e874231d7ebafc94f5796a19f5df39b" + integrity sha512-DMFR1OA/f1/voeuFbSORg9AP36pMgOoSb/DRgiDalLmIJsDTlQNMCu+givjMP4s/XL85+tBk2MerYnK/AscJjw== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + undici "5.28.4" + "@firebase/component@0.5.13": version "0.5.13" resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.5.13.tgz#65a382e83bddd109380c9aa1f280791b1b4567c4" @@ -831,6 +880,26 @@ "@firebase/util" "1.5.2" tslib "^2.1.0" +"@firebase/component@0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.8.tgz#899b9318c0ce0586580e8cda7eaf61296f7fb43b" + integrity sha512-LcNvxGLLGjBwB0dJUsBGCej2fqAepWyBubs4jt1Tiuns7QLbXHuyObZ4aMeBjZjWx4m8g1LoVI9QFpSaq/k4/g== + dependencies: + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/database-compat@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-1.0.6.tgz#6a4966fe4a9d8bc2cb11ee98a1bb01ab954d7d66" + integrity sha512-1OGA0sLY47mkXjhICCrUTXEYFnSSXoiXWm1SHsN62b+Lzs5aKA3aWTjTUmYIoK93kDAMPkYpulSv8jcbH4Hwew== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/database" "1.0.6" + "@firebase/database-types" "1.0.4" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + "@firebase/database-compat@^0.1.1": version "0.1.8" resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.1.8.tgz#ab627f2bdbe94367f515d5bded880c86886bbd28" @@ -851,6 +920,14 @@ "@firebase/app-types" "0.7.0" "@firebase/util" "1.5.2" +"@firebase/database-types@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.4.tgz#dc507f7838ed29ac3235c68ebae5fd42a562e3e8" + integrity sha512-mz9ZzbH6euFXbcBo+enuJ36I5dR5w+enJHHjy9Y5ThCdKUseqfDjW3vCp1YxE9zygFCSjJJ/z1cQ+zodvUcwPQ== + dependencies: + "@firebase/app-types" "0.9.2" + "@firebase/util" "1.9.7" + "@firebase/database-types@^0.7.2": version "0.7.3" resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.7.3.tgz#819f16dd4c767c864b460004458620f265a3f735" @@ -870,6 +947,104 @@ faye-websocket "0.11.4" tslib "^2.1.0" +"@firebase/database@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.0.6.tgz#cf0592b140e207e35c14efe6776fc92266ac408a" + integrity sha512-nrexUEG/fpVlHtWKkyfhTC3834kZ1WS7voNyqbBsBCqHXQOvznN5Z0L3nxBqdXSJyltNAf4ndFlQqm5gZiEczQ== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + faye-websocket "0.11.4" + tslib "^2.1.0" + +"@firebase/firestore-compat@0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.33.tgz#8e591bfafb574c695b09101b98c1a1057f55c60e" + integrity sha512-i42a2l31N95CwYEB7zmfK0FS1mrO6pwOLwxavCrwu1BCFrVVVQhUheTPIda/iGguK/2Nog0RaIR1bo7QkZEz3g== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/firestore" "4.6.4" + "@firebase/firestore-types" "3.0.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/firestore-types@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.2.tgz#75c301acc5fa33943eaaa9570b963c55398cad2a" + integrity sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg== + +"@firebase/firestore@4.6.4": + version "4.6.4" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.6.4.tgz#f53fcfc3ecfeb844f2147a43382d013d21e64968" + integrity sha512-vk2MoH5HxYEhiNg1l+yBXq1Fkhue/11bFg4HdlTv6BJHcTnnAj2a+/afPpatcW4MOdYA3Tv+d5nGzWbbOC1SHw== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + "@firebase/webchannel-wrapper" "1.0.1" + "@grpc/grpc-js" "~1.9.0" + "@grpc/proto-loader" "^0.7.8" + tslib "^2.1.0" + undici "5.28.4" + +"@firebase/functions-compat@0.3.12": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.12.tgz#aae387eb48466df1d031fc5bb755c657cfeb5994" + integrity sha512-r3XUb5VlITWpML46JymfJPkK6I9j4SNlO7qWIXUc0TUmkv0oAfVoiIt1F83/NuMZXaGr4YWA/794nVSy4GV8tw== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/functions" "0.11.6" + "@firebase/functions-types" "0.6.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/functions-types@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.2.tgz#03b4ec9259d2f57548a3909d6a35ae35ad243552" + integrity sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w== + +"@firebase/functions@0.11.6": + version "0.11.6" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.11.6.tgz#607991a3a870051e6456d7ccb0217fac6305db89" + integrity sha512-GPfIBPtpwQvsC7SQbgaUjLTdja0CsNwMoKSgrzA1FGGRk4NX6qO7VQU6XCwBiAFWbpbQex6QWkSMsCzLx1uibQ== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.8" + "@firebase/messaging-interop-types" "0.2.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + undici "5.28.4" + +"@firebase/installations-compat@0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.8.tgz#ebc908afe84db2754b19a62f7655608911e13819" + integrity sha512-pI2q8JFHB7yIq/szmhzGSWXtOvtzl6tCUmyykv5C8vvfOVJUH6mP4M4iwjbK8S1JotKd/K70+JWyYlxgQ0Kpyw== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/installations" "0.6.8" + "@firebase/installations-types" "0.5.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/installations-types@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.2.tgz#4d4949e0e83ced7f36cbee009355cd305a36e158" + integrity sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA== + +"@firebase/installations@0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.8.tgz#f9c9d493bce04b04ca28814e926ef3ed71f033d6" + integrity sha512-57V374qdb2+wT5v7+ntpLXBjZkO6WRgmAUbVkRfFTM/4t980p0FesbqTAcOIiM8U866UeuuuF8lYH70D3jM/jQ== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/util" "1.9.7" + idb "7.1.1" + tslib "^2.1.0" + "@firebase/logger@0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.3.2.tgz#5046ffa8295c577846d54b6ca95645a03809800e" @@ -877,6 +1052,122 @@ dependencies: tslib "^2.1.0" +"@firebase/logger@0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.2.tgz#74dfcfeedee810deb8a7080d5b7eba56aa16ffa2" + integrity sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A== + dependencies: + tslib "^2.1.0" + +"@firebase/messaging-compat@0.2.10": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.10.tgz#08711f75e2d517fd209bfbc65b1f754b09b2121c" + integrity sha512-FXQm7rcowkDm8kFLduHV35IRYCRo+Ng0PIp/t1+EBuEbyplaKkGjZ932pE+owf/XR+G/60ku2QRBptRGLXZydg== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/messaging" "0.12.10" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/messaging-interop-types@0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz#81042f7e9739733fa4571d17f6eb6869522754d0" + integrity sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA== + +"@firebase/messaging@0.12.10": + version "0.12.10" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.10.tgz#29909f909b9588d44864732377d88de11f3b3ed3" + integrity sha512-fGbxJPKpl2DIKNJGhbk4mYPcM+qE2gl91r6xPoiol/mN88F5Ym6UeRdMVZah+pijh9WxM55alTYwXuW40r1Y2Q== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/installations" "0.6.8" + "@firebase/messaging-interop-types" "0.2.2" + "@firebase/util" "1.9.7" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/performance-compat@0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.8.tgz#d97bab3fd0c147c7f796e9b8f78712bc0b83699c" + integrity sha512-o7TFClRVJd3VIBoY7KZQqtCeW0PC6v9uBzM6Lfw3Nc9D7hM6OonqecYvh7NwJ6R14k+xM27frLS4BcCvFHKw2A== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/performance" "0.6.8" + "@firebase/performance-types" "0.2.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/performance-types@0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.2.tgz#7b78cd2ab2310bac89a63348d93e67e01eb06dd7" + integrity sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA== + +"@firebase/performance@0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.6.8.tgz#668b0fc207389f7829fd3bfb6614fe819b7db124" + integrity sha512-F+alziiIZ6Yn8FG47mxwljq+4XkgkT2uJIFRlkyViUQRLzrogaUJW6u/+6ZrePXnouKlKIwzqos3PVJraPEcCA== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/installations" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/remote-config-compat@0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.8.tgz#a6df065c1fd0a943e84ee0e76acfc6c1bede42f9" + integrity sha512-UxSFOp6dzFj2AHB8Bq/BYtbq5iFyizKx4Rd6WxAdaKYM8cnPMeK+l2v+Oogtjae+AeyHRI+MfL2acsfVe5cd2A== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/remote-config" "0.4.8" + "@firebase/remote-config-types" "0.3.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/remote-config-types@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz#a5d1009c6fd08036c5cd4f28764e3cd694f966d5" + integrity sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA== + +"@firebase/remote-config@0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.4.8.tgz#b6a79acdf73554e0ee31c278162b85592fc8c1f3" + integrity sha512-AMLqe6wfIRnjc6FkCWOSUjhc1fSTEf8o+cv1NolFvbiJ/tU+TqN4pI7pT+MIKQzNiq5fxLehkOx+xtAQBxPJKQ== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/installations" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/storage-compat@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.9.tgz#42496a7b5f7c384f0ea590d704934465102b4527" + integrity sha512-WWgAp5bTW961oIsCc9+98m4MIVKpEqztAlIngfHfwO/x3DYoBPRl/awMRG3CAXyVxG+7B7oHC5IsnqM+vTwx2A== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/storage" "0.12.6" + "@firebase/storage-types" "0.8.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/storage-types@0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.2.tgz#edb321b8a3872a9f74e1f27de046f160021c8e1f" + integrity sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g== + +"@firebase/storage@0.12.6": + version "0.12.6" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.12.6.tgz#49b2c77f10fd97da913a93e37c86cdff92a805eb" + integrity sha512-Zgb9WuehJxzhj7pGXUvkAEaH+3HvLjD9xSZ9nepuXf5f8378xME7oGJtREr/RnepdDA5YW0XIxe0QQBNHpe1nw== + dependencies: + "@firebase/component" "0.6.8" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + undici "5.28.4" + "@firebase/util@1.5.2": version "1.5.2" resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.5.2.tgz#bdd2bc11c956a8a6a0fa25fbd752a13e033558bc" @@ -884,6 +1175,29 @@ dependencies: tslib "^2.1.0" +"@firebase/util@1.9.7": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.9.7.tgz#c03b0ae065b3bba22800da0bd5314ef030848038" + integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA== + dependencies: + tslib "^2.1.0" + +"@firebase/vertexai-preview@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@firebase/vertexai-preview/-/vertexai-preview-0.0.3.tgz#73dea839439ebdbb5ccd946f297ede5b57e6e7e9" + integrity sha512-KVtUWLp+ScgiwkDKAvNkVucAyhLVQp6C6lhnVEuIg4mWhWcS3oerjAeVhZT4uNofKwWxRsOaB2Yec7DMTXlQPQ== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/component" "0.6.8" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.9.7" + tslib "^2.1.0" + +"@firebase/webchannel-wrapper@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.1.tgz#0b62c9f47f557a5b4adc073bb0a47542ce6af4c4" + integrity sha512-jmEnr/pk0yVkA7mIlHNnxCi+wWzOFUg0WyIotgkKAb2u1J7fAeDBcVNSTjTihbAYNusCLQdW5s9IJ5qwnEufcQ== + "@google-cloud/firestore@^4.5.0": version "4.15.1" resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-4.15.1.tgz#ed764fc76823ce120e68fe8c27ef1edd0650cd93" @@ -949,6 +1263,14 @@ "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" +"@grpc/grpc-js@~1.9.0": + version "1.9.15" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" + integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== + dependencies: + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" + "@grpc/proto-loader@^0.6.12": version "0.6.13" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc" @@ -960,7 +1282,7 @@ protobufjs "^6.11.3" yargs "^16.2.0" -"@grpc/proto-loader@^0.7.0": +"@grpc/proto-loader@^0.7.0", "@grpc/proto-loader@^0.7.8": version "0.7.13" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== @@ -3947,6 +4269,39 @@ firebase-admin@^9.5.0: "@google-cloud/firestore" "^4.5.0" "@google-cloud/storage" "^5.3.0" +firebase@^10.12.3: + version "10.12.4" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-10.12.4.tgz#ca2451d1cf999a3e94e2287c56abdd94e043ddb0" + integrity sha512-SQz49NMpwG4MLTPZ9C8jBp7IyS2haTvsIvjclgu+v/jvzNtjZoxIcoF6A13EIfBHmJ5eiuVlvttxElOf7LnJew== + dependencies: + "@firebase/analytics" "0.10.6" + "@firebase/analytics-compat" "0.2.12" + "@firebase/app" "0.10.7" + "@firebase/app-check" "0.8.6" + "@firebase/app-check-compat" "0.3.13" + "@firebase/app-compat" "0.2.37" + "@firebase/app-types" "0.9.2" + "@firebase/auth" "1.7.5" + "@firebase/auth-compat" "0.5.10" + "@firebase/database" "1.0.6" + "@firebase/database-compat" "1.0.6" + "@firebase/firestore" "4.6.4" + "@firebase/firestore-compat" "0.3.33" + "@firebase/functions" "0.11.6" + "@firebase/functions-compat" "0.3.12" + "@firebase/installations" "0.6.8" + "@firebase/installations-compat" "0.2.8" + "@firebase/messaging" "0.12.10" + "@firebase/messaging-compat" "0.2.10" + "@firebase/performance" "0.6.8" + "@firebase/performance-compat" "0.2.8" + "@firebase/remote-config" "0.4.8" + "@firebase/remote-config-compat" "0.2.8" + "@firebase/storage" "0.12.6" + "@firebase/storage-compat" "0.3.9" + "@firebase/util" "1.9.7" + "@firebase/vertexai-preview" "0.0.3" + flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" @@ -4366,6 +4721,11 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +idb@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -6507,6 +6867,11 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +safevalues@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/safevalues/-/safevalues-0.6.0.tgz#425eadbdb699c13d8cfd932485983f858222362a" + integrity sha512-MZ7DcTOcIoPXN36/UONVE9BT0pmwlCr9WcS7Pj/q4FxOwr33FkWC0CUWj/THQXYWxf/F7urbhaHaOeFPSqGqHA== + saslprep@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" diff --git a/docker-compose.yml b/docker-compose.yml index bb422b0..994132b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,9 @@ services: backend: container_name: eaf_backend restart: always + depends_on: + database: + condition: service_healthy build: context: ./backend dockerfile: Dockerfile @@ -27,6 +30,18 @@ services: - ./backend:/app env_file: - ./.env + database: + container_name: eaf_database + image: mongo + environment: + - MONGO_INITDB_ROOT_USERNAME=eaf_user + - MONGO_INITDB_ROOT_PASSWORD=eaf_password + ports: + - 27017:27017 + volumes: + - data:/data/db + healthcheck: + test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet # database: # container_name: eaf_database # image: mongodb/mongodb-atlas-local @@ -37,5 +52,5 @@ services: # - 27018:27017 # volumes: # - data:/data/db -# volumes: -# data: +volumes: + data: diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index ff419c9..b15bf94 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -63,6 +63,7 @@ const signup = async ( return null; } }; + const resetPassword = async (email: string | undefined): Promise => { const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, @@ -80,6 +81,23 @@ const resetPassword = async (email: string | undefined): Promise => { } }; +const updateTemporaryPassword = async (newPassword: string) => { + const bearerToken = `Bearer ${getLocalStorageObjProperty( + AUTHENTICATED_USER_KEY, + "accessToken", + )}`; + try { + await baseAPIClient.post( + `/auth/updateTemporaryPassword`, + { newPassword }, + { headers: { Authorization: bearerToken } }, + ); + return true; + } catch (error) { + return false; + } +}; + // for testing only, refresh does not need to be exposed in the client const refresh = async (): Promise => { try { @@ -122,6 +140,7 @@ export default { logout, signup, resetPassword, + updateTemporaryPassword, refresh, isUserVerified, }; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b3d7f68..6add2e3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -27,6 +27,7 @@ import { SocketProvider } from "./contexts/SocketContext"; import MakeHelpRequestPage from "./components/pages/MakeHelpRequestPage"; import ViewHelpRequestsPage from "./components/pages/ViewHelpRequestsPage"; import HelpRequestPage from "./components/pages/HelpRequestPage"; +import CreatePasswordPage from "./components/pages/CreatePasswordPage"; const App = (): React.ReactElement => { const currentUser: AuthenticatedUser | null = diff --git a/frontend/src/components/auth/Login.tsx b/frontend/src/components/auth/Login.tsx index 4674e6a..1fb8ef4 100644 --- a/frontend/src/components/auth/Login.tsx +++ b/frontend/src/components/auth/Login.tsx @@ -1,7 +1,7 @@ import React, { useContext, useState } from "react"; import { Redirect, useHistory, useLocation } from "react-router-dom"; import authAPIClient from "../../APIClients/AuthAPIClient"; -import { HOME_PAGE, SIGNUP_PAGE, WELCOME_PAGE } from "../../constants/Routes"; +import { CREATE_PASSWORD_PAGE, HOME_PAGE, SIGNUP_PAGE, WELCOME_PAGE } from "../../constants/Routes"; import AuthContext from "../../contexts/AuthContext"; import { AuthenticatedUser } from "../../types/AuthTypes"; import AUTHENTICATED_USER_KEY from "../../constants/AuthConstants"; diff --git a/frontend/src/components/auth/PrivateRoute.tsx b/frontend/src/components/auth/PrivateRoute.tsx index 136d0a8..df835fc 100644 --- a/frontend/src/components/auth/PrivateRoute.tsx +++ b/frontend/src/components/auth/PrivateRoute.tsx @@ -2,7 +2,7 @@ import React, { useContext } from "react"; import { Route, Redirect } from "react-router-dom"; import AuthContext from "../../contexts/AuthContext"; -import { NOT_AUTHORIZED_PAGE, WELCOME_PAGE } from "../../constants/Routes"; +import { CREATE_PASSWORD_PAGE, NOT_AUTHORIZED_PAGE, WELCOME_PAGE } from "../../constants/Routes"; import { Role } from "../../types/AuthTypes"; type PrivateRouteProps = { @@ -21,6 +21,9 @@ const PrivateRoute: React.FC = ({ const { authenticatedUser } = useContext(AuthContext); if (authenticatedUser) { + if (authenticatedUser.status === "Invited" && path !== CREATE_PASSWORD_PAGE) { + return + } return allowedRoles.includes(authenticatedUser.role) ? ( ) : ( diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx new file mode 100644 index 0000000..9c321db --- /dev/null +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -0,0 +1,63 @@ +import React, { useContext, useState } from "react"; +import { Redirect, useHistory } from "react-router-dom"; +import { HOME_PAGE, LOGIN_PAGE } from "../../constants/Routes"; +import AuthAPIClient from "../../APIClients/AuthAPIClient"; +import AuthContext from "../../contexts/AuthContext"; + +const CreatePasswordPage = (): React.ReactElement => { + const { authenticatedUser } = useContext(AuthContext); + const [newPassword, setNewPassword] = useState(""); + const history = useHistory(); + + if (authenticatedUser?.status !== "Invited") { + console.log("Not a newly invited user") + return + } + + const onSubmitNewPasswordClick = async () => { + const success = await AuthAPIClient.updateTemporaryPassword(newPassword); + console.log("Completed:", success) + if (success) { + // change this later to not use an alert + // eslint-disable-next-line no-alert + alert("Successfully changed your password. Please log in with your new credentials."); + } else { + // change this later to not use an alert + // eslint-disable-next-line no-alert + alert("Error occurred when changing your password. Please try again later."); + await AuthAPIClient.logout(authenticatedUser.id); + } + history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); + } + + return ( +
+

Choose a New Password

+
+ Since this is your first time logging in, please choose a new password. +
+
+ setNewPassword(event.target.value)} + placeholder="New Password" + /> + +
+
+ ); +}; + +export default CreatePasswordPage; diff --git a/frontend/src/constants/Routes.ts b/frontend/src/constants/Routes.ts index 5a82b51..a707892 100644 --- a/frontend/src/constants/Routes.ts +++ b/frontend/src/constants/Routes.ts @@ -8,6 +8,14 @@ export const SIGNUP_PAGE = "/signup"; export const CREATE_MODULE_PAGE = "/create-module"; +export const CREATE_ENTITY_PAGE = "/entity/create"; + +export const UPDATE_ENTITY_PAGE = "/entity/update"; + +export const HOOKS_PAGE = "/hooks"; + +export const CREATE_PASSWORD_PAGE = "/create-password"; + export const NOT_AUTHORIZED_PAGE = "/not-authorized"; export const MY_ACCOUNT_PAGE = "/account"; diff --git a/frontend/src/types/AuthTypes.ts b/frontend/src/types/AuthTypes.ts index b9b6065..0e573c9 100644 --- a/frontend/src/types/AuthTypes.ts +++ b/frontend/src/types/AuthTypes.ts @@ -1,5 +1,7 @@ export type Role = "Administrator" | "Facilitator" | "Learner"; +export type Status = "Active" | "Invited"; + export type AuthenticatedUser = { id: string; firstName: string; @@ -7,6 +9,7 @@ export type AuthenticatedUser = { email: string; role: Role; accessToken: string; + status: Status; }; export type AuthenticatedAdministrator = AuthenticatedUser; From 9110611419f1ebacfbc0f7ce998be22ba2870480 Mon Sep 17 00:00:00 2001 From: Jimmy Liu Date: Tue, 30 Jul 2024 21:13:34 -0400 Subject: [PATCH 2/9] Fix Firebase REST for changePassword and clean up routes --- .../middlewares/validators/authValidators.ts | 12 +++++++ backend/rest/authRoutes.ts | 36 ++++++++++++++++--- .../services/implementations/authService.ts | 7 ++-- backend/services/interfaces/authService.ts | 2 +- backend/utilities/firebaseRestClient.ts | 15 ++++++-- frontend/src/APIClients/AuthAPIClient.ts | 9 +++-- .../components/pages/CreatePasswordPage.tsx | 4 +-- 7 files changed, 68 insertions(+), 17 deletions(-) diff --git a/backend/middlewares/validators/authValidators.ts b/backend/middlewares/validators/authValidators.ts index 511b50d..0efe8b1 100644 --- a/backend/middlewares/validators/authValidators.ts +++ b/backend/middlewares/validators/authValidators.ts @@ -85,3 +85,15 @@ export const updateTemporaryPasswordRequestValidator = async ( return next(); }; + +export const updateUserStatusRequestValidator = async ( + req: Request, + res: Response, + next: NextFunction, +) => { + if (!validatePrimitive(req.body.status, "string")) { + return res.status(400).send(getApiValidationError("status", "string")); + } + + return next(); +} diff --git a/backend/rest/authRoutes.ts b/backend/rest/authRoutes.ts index cd75549..bbb955c 100644 --- a/backend/rest/authRoutes.ts +++ b/backend/rest/authRoutes.ts @@ -14,6 +14,7 @@ import { inviteAdminRequestValidator, forgotPasswordRequestValidator, updateTemporaryPasswordRequestValidator, + updateUserStatusRequestValidator, } from "../middlewares/validators/authValidators"; import nodemailerConfig from "../nodemailer.config"; import AuthService from "../services/implementations/authService"; @@ -25,6 +26,8 @@ import IUserService from "../services/interfaces/userService"; import { getErrorMessage } from "../utilities/errorUtils"; import { AuthErrorCodes } from "../types/authTypes"; +import * as firebaseAdmin from "firebase-admin"; + const authRouter: Router = Router(); const userService: IUserService = new UserService(); const emailService: IEmailService = new EmailService(nodemailerConfig); @@ -219,17 +222,42 @@ authRouter.post( authRouter.post( "/updateTemporaryPassword", updateTemporaryPasswordRequestValidator, - // isFirstTimeInvitedUser, + isFirstTimeInvitedUser(), async (req, res) => { - console.log("Hit route update temporary password") try { const accessToken = getAccessToken(req)!; - await authService.changeUserPassword(accessToken, req.body.newPassword); - res.status(204).send(); + const newAccessToken = await authService.changeUserPassword(accessToken, req.body.newPassword); + res.status(200).json({ + accessToken: newAccessToken, + }); } catch (error: unknown) { res.status(500).json({ error: getErrorMessage(error) }); } }, ); +authRouter.post( + "/updateUserStatus", + updateUserStatusRequestValidator, + isAuthorizedByRole(new Set(["Administrator", "Facilitator", "Learner"])), + async (req, res) => { + try { + const accessToken = getAccessToken(req)!; + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = + await firebaseAdmin.auth().verifyIdToken(accessToken, true); + const currentUser = await userService.getUserById(decodedIdToken.uid); + await userService.updateUserById( + decodedIdToken.uid, + { + ...currentUser, + status: req.body.status, + }, + ); + res.status(204).send(); + } catch (error: unknown) { + res.status(500).json({ error: getErrorMessage(error) }); + } + } +) + export default authRouter; diff --git a/backend/services/implementations/authService.ts b/backend/services/implementations/authService.ts index 45f8724..3a490d8 100644 --- a/backend/services/implementations/authService.ts +++ b/backend/services/implementations/authService.ts @@ -174,12 +174,9 @@ class AuthService implements IAuthService { async changeUserPassword( accessToken: string, newPassword: string, - ): Promise { + ): Promise { try { - const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin - .auth() - .verifyIdToken(accessToken, true); - await FirebaseRestClient.changePassword(decodedIdToken.uid, newPassword); + return await FirebaseRestClient.changePassword(accessToken, newPassword); } catch (error: unknown) { Logger.error( `Failed to change user's password. Reason = ${getErrorMessage(error)}`, diff --git a/backend/services/interfaces/authService.ts b/backend/services/interfaces/authService.ts index 0092739..0c9510a 100644 --- a/backend/services/interfaces/authService.ts +++ b/backend/services/interfaces/authService.ts @@ -57,7 +57,7 @@ interface IAuthService { * @param email the user's email address * @param newPassword new password chosen to replace the user's old password */ - changeUserPassword(accessToken: string, newPassword: string): Promise; + changeUserPassword(accessToken: string, newPassword: string): Promise; /** * Determine if the provided access token is valid and authorized for at least diff --git a/backend/utilities/firebaseRestClient.ts b/backend/utilities/firebaseRestClient.ts index 7c9e365..3469061 100644 --- a/backend/utilities/firebaseRestClient.ts +++ b/backend/utilities/firebaseRestClient.ts @@ -23,6 +23,13 @@ type PasswordSignInResponse = { registered: boolean; }; +type ChangePasswordResponse = { + localId: string, + email: string, + idToken: string, + emailVerified: boolean, +} + type RefreshTokenResponse = { expires_in: string; token_type: string; @@ -122,7 +129,7 @@ const FirebaseRestClient = { }; }, - changePassword: async (authId: string, newPassword: string): Promise => { + changePassword: async (accessToken: string, newPassword: string): Promise => { const response: Response = await fetch( `${FIREBASE_CHANGE_PASSWORD_URL}?key=${process.env.FIREBASE_WEB_API_KEY}`, { @@ -131,14 +138,14 @@ const FirebaseRestClient = { "Content-Type": "application/json", }, body: JSON.stringify({ - idToken: authId, + idToken: accessToken, password: newPassword, }), }, ); const responseJson: - | RefreshTokenResponse + | ChangePasswordResponse | RequestError = await response.json(); if (!response.ok) { @@ -152,6 +159,8 @@ const FirebaseRestClient = { throw new Error("Failed to change password via Firebase REST API"); } + + return (responseJson as ChangePasswordResponse).idToken; }, }; diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index b15bf94..d284b7e 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -81,17 +81,22 @@ const resetPassword = async (email: string | undefined): Promise => { } }; -const updateTemporaryPassword = async (newPassword: string) => { +const updateTemporaryPassword = async (newPassword: string): Promise => { const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", )}`; try { - await baseAPIClient.post( + const { data } = await baseAPIClient.post( `/auth/updateTemporaryPassword`, { newPassword }, { headers: { Authorization: bearerToken } }, ); + setLocalStorageObjProperty( + AUTHENTICATED_USER_KEY, + "accessToken", + data.accessToken, + ); return true; } catch (error) { return false; diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index 9c321db..7915dcf 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -16,16 +16,16 @@ const CreatePasswordPage = (): React.ReactElement => { const onSubmitNewPasswordClick = async () => { const success = await AuthAPIClient.updateTemporaryPassword(newPassword); - console.log("Completed:", success) if (success) { // change this later to not use an alert // eslint-disable-next-line no-alert alert("Successfully changed your password. Please log in with your new credentials."); + } else { // change this later to not use an alert // eslint-disable-next-line no-alert - alert("Error occurred when changing your password. Please try again later."); await AuthAPIClient.logout(authenticatedUser.id); + alert("Error occurred when changing your password. Please log in again."); } history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); } From 74fe519780a8a03968b045b8a4262722db89e559 Mon Sep 17 00:00:00 2001 From: Jimmy Liu Date: Tue, 30 Jul 2024 22:27:21 -0400 Subject: [PATCH 3/9] Finish update user status endpoint --- backend/middlewares/auth.ts | 3 +- backend/rest/authRoutes.ts | 3 +- frontend/src/APIClients/AuthAPIClient.ts | 32 +++++++++++++++++-- .../components/pages/CreatePasswordPage.tsx | 28 ++++++++++------ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/backend/middlewares/auth.ts b/backend/middlewares/auth.ts index 9453124..6d7c56d 100644 --- a/backend/middlewares/auth.ts +++ b/backend/middlewares/auth.ts @@ -81,7 +81,6 @@ export const isAuthorizedByEmail = (emailField: string) => { export const isFirstTimeInvitedUser = () => { return async (req: Request, res: Response, next: NextFunction) => { - console.log("hit check first time invitation") const accessToken = getAccessToken(req); const authorized = accessToken && @@ -89,7 +88,7 @@ export const isFirstTimeInvitedUser = () => { if (!authorized) { return res .status(401) - .json({ error: "You are not a first-time invited administrator." }) + .json({ error: "You are not a first-time invited user." }); } return next(); } diff --git a/backend/rest/authRoutes.ts b/backend/rest/authRoutes.ts index bbb955c..ff31758 100644 --- a/backend/rest/authRoutes.ts +++ b/backend/rest/authRoutes.ts @@ -222,7 +222,7 @@ authRouter.post( authRouter.post( "/updateTemporaryPassword", updateTemporaryPasswordRequestValidator, - isFirstTimeInvitedUser(), + // isFirstTimeInvitedUser(), async (req, res) => { try { const accessToken = getAccessToken(req)!; @@ -239,7 +239,6 @@ authRouter.post( authRouter.post( "/updateUserStatus", updateUserStatusRequestValidator, - isAuthorizedByRole(new Set(["Administrator", "Facilitator", "Learner"])), async (req, res) => { try { const accessToken = getAccessToken(req)!; diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index d284b7e..7c28787 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -1,11 +1,13 @@ import { AxiosError } from "axios"; import AUTHENTICATED_USER_KEY from "../constants/AuthConstants"; -import { AuthenticatedUser, Role } from "../types/AuthTypes"; +import { AuthenticatedUser, Role, Status } from "../types/AuthTypes"; import baseAPIClient from "./BaseAPIClient"; import { getLocalStorageObjProperty, setLocalStorageObjProperty, } from "../utils/LocalStorageUtils"; +import { useContext } from "react"; +import AuthContext from "../contexts/AuthContext"; const login = async ( email: string, @@ -82,6 +84,7 @@ const resetPassword = async (email: string | undefined): Promise => { }; const updateTemporaryPassword = async (newPassword: string): Promise => { + const { authenticatedUser } = useContext(AuthContext); const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", @@ -92,10 +95,17 @@ const updateTemporaryPassword = async (newPassword: string): Promise => { newPassword }, { headers: { Authorization: bearerToken } }, ); + const newAccessToken = await login( + authenticatedUser?.email!, + newPassword, + ); + if (!newAccessToken) { + throw new Error("Unable to authenticate user after logging in."); + } setLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", - data.accessToken, + newAccessToken.accessToken, ); return true; } catch (error) { @@ -103,6 +113,23 @@ const updateTemporaryPassword = async (newPassword: string): Promise => } }; +const updateUserStatus = async (newStatus: Status): Promise => { + const bearerToken = `Bearer ${getLocalStorageObjProperty( + AUTHENTICATED_USER_KEY, + "accessToken", + )}`; + try { + await baseAPIClient.post( + `/auth/updateUserStatus`, + { status: newStatus }, + { headers: { Authorization: bearerToken } }, + ); + return true; + } catch (error) { + return false; + } +} + // for testing only, refresh does not need to be exposed in the client const refresh = async (): Promise => { try { @@ -146,6 +173,7 @@ export default { signup, resetPassword, updateTemporaryPassword, + updateUserStatus, refresh, isUserVerified, }; diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index 7915dcf..35b3285 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -3,9 +3,10 @@ import { Redirect, useHistory } from "react-router-dom"; import { HOME_PAGE, LOGIN_PAGE } from "../../constants/Routes"; import AuthAPIClient from "../../APIClients/AuthAPIClient"; import AuthContext from "../../contexts/AuthContext"; +import AUTHENTICATED_USER_KEY from "../../constants/AuthConstants"; const CreatePasswordPage = (): React.ReactElement => { - const { authenticatedUser } = useContext(AuthContext); + const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext); const [newPassword, setNewPassword] = useState(""); const history = useHistory(); @@ -15,18 +16,27 @@ const CreatePasswordPage = (): React.ReactElement => { } const onSubmitNewPasswordClick = async () => { - const success = await AuthAPIClient.updateTemporaryPassword(newPassword); - if (success) { + const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword(newPassword); + if (!changePasswordSuccess) { // change this later to not use an alert // eslint-disable-next-line no-alert - alert("Successfully changed your password. Please log in with your new credentials."); - - } else { - // change this later to not use an alert - // eslint-disable-next-line no-alert - await AuthAPIClient.logout(authenticatedUser.id); + setAuthenticatedUser(null); + localStorage.removeItem(AUTHENTICATED_USER_KEY); + // await AuthAPIClient.logout(authenticatedUser.id); alert("Error occurred when changing your password. Please log in again."); + return; } + + // change this later to not use an alert + // eslint-disable-next-line no-alert + const updateStatusSuccess = await AuthAPIClient.updateUserStatus("Active"); + if (!updateStatusSuccess) { + alert("Failed to update user status to \"Active\""); + return; + } + + alert("Successfully changed your password. Please log in with your new credentials."); + history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); } From 95dfe530f135fb6bdf32ad2aadabef51ae653f51 Mon Sep 17 00:00:00 2001 From: Jimmy Liu Date: Tue, 30 Jul 2024 23:24:38 -0400 Subject: [PATCH 4/9] Fix all bugs for working product --- backend/rest/authRoutes.ts | 11 +------- .../services/implementations/userService.ts | 25 ++++++++++++++++++- backend/services/interfaces/userService.ts | 5 ++++ frontend/src/APIClients/AuthAPIClient.ts | 15 +++++------ .../components/pages/CreatePasswordPage.tsx | 7 ++++-- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/backend/rest/authRoutes.ts b/backend/rest/authRoutes.ts index ff31758..2cb93a0 100644 --- a/backend/rest/authRoutes.ts +++ b/backend/rest/authRoutes.ts @@ -242,16 +242,7 @@ authRouter.post( async (req, res) => { try { const accessToken = getAccessToken(req)!; - const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = - await firebaseAdmin.auth().verifyIdToken(accessToken, true); - const currentUser = await userService.getUserById(decodedIdToken.uid); - await userService.updateUserById( - decodedIdToken.uid, - { - ...currentUser, - status: req.body.status, - }, - ); + await userService.changeUserStatus(accessToken, req.body.status); res.status(204).send(); } catch (error: unknown) { res.status(500).json({ error: getErrorMessage(error) }); diff --git a/backend/services/implementations/userService.ts b/backend/services/implementations/userService.ts index 9b14129..daab875 100644 --- a/backend/services/implementations/userService.ts +++ b/backend/services/implementations/userService.ts @@ -192,7 +192,7 @@ class UserService implements IUserService { // must explicitly specify runValidators when updating through findByIdAndUpdate oldUser = await MgUser.findByIdAndUpdate( userId, - { firstName: user.firstName, lastName: user.lastName, role: user.role }, + { firstName: user.firstName, lastName: user.lastName, role: user.role, status: user.status }, { runValidators: true }, ); @@ -213,6 +213,7 @@ class UserService implements IUserService { firstName: oldUser.firstName, lastName: oldUser.lastName, role: oldUser.role, + status: oldUser.status, }, { runValidators: true }, ); @@ -349,18 +350,40 @@ class UserService implements IUserService { accessToken: string, ): Promise { try { + console.log("flag 5") const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin .auth() .verifyIdToken(accessToken, true); + console.log("flag 6") const { status } = await getMongoUserByAuthId( decodedIdToken.uid ); + console.log("flag 7") return status === "Invited"; } catch (error: unknown) { Logger.error(`Failed to verify user is first time invited user. Reason = ${getErrorMessage(error)}`); throw error; } } + + async changeUserStatus(accessToken: string, newStatus: Status): Promise { + try { + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin + .auth() + .verifyIdToken(accessToken, true); + const tokenUserId = await this.getUserIdByAuthId(decodedIdToken.uid); + const currentUser = await this.getUserById(tokenUserId); + const updatedUser: UpdateUserDTO = { + ...currentUser, + status: newStatus, + }; + console.log("Updated user:", updatedUser) + await this.updateUserById(tokenUserId, updatedUser); + } catch (error: unknown) { + Logger.error(`Failed to change user status. Reason = ${getErrorMessage(error)}`); + throw error; + } + } } export default UserService; diff --git a/backend/services/interfaces/userService.ts b/backend/services/interfaces/userService.ts index c63646a..0cf75a0 100644 --- a/backend/services/interfaces/userService.ts +++ b/backend/services/interfaces/userService.ts @@ -104,6 +104,11 @@ interface IUserService { isFirstTimeInvitedUser( accessToken: string, ): Promise; + + changeUserStatus( + accessToken: string, + newStatus: Status, + ): Promise; } export default IUserService; diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index 7c28787..be017db 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -6,8 +6,6 @@ import { getLocalStorageObjProperty, setLocalStorageObjProperty, } from "../utils/LocalStorageUtils"; -import { useContext } from "react"; -import AuthContext from "../contexts/AuthContext"; const login = async ( email: string, @@ -83,29 +81,28 @@ const resetPassword = async (email: string | undefined): Promise => { } }; -const updateTemporaryPassword = async (newPassword: string): Promise => { - const { authenticatedUser } = useContext(AuthContext); +const updateTemporaryPassword = async (email: string, newPassword: string): Promise => { const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", )}`; try { - const { data } = await baseAPIClient.post( + await baseAPIClient.post( `/auth/updateTemporaryPassword`, { newPassword }, { headers: { Authorization: bearerToken } }, ); - const newAccessToken = await login( - authenticatedUser?.email!, + const newAuthenticatedUser = await login( + email, newPassword, ); - if (!newAccessToken) { + if (!newAuthenticatedUser) { throw new Error("Unable to authenticate user after logging in."); } setLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", - newAccessToken.accessToken, + newAuthenticatedUser.accessToken, ); return true; } catch (error) { diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index 35b3285..a8ad20b 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -16,7 +16,7 @@ const CreatePasswordPage = (): React.ReactElement => { } const onSubmitNewPasswordClick = async () => { - const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword(newPassword); + const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword(authenticatedUser.email, newPassword); if (!changePasswordSuccess) { // change this later to not use an alert // eslint-disable-next-line no-alert @@ -35,7 +35,10 @@ const CreatePasswordPage = (): React.ReactElement => { return; } - alert("Successfully changed your password. Please log in with your new credentials."); + setAuthenticatedUser({ + ...authenticatedUser, + status: "Active", + }) history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); } From 206c66243219f43d626b65de9fceb42b81f3b2ec Mon Sep 17 00:00:00 2001 From: Jimmy Liu Date: Tue, 30 Jul 2024 23:37:45 -0400 Subject: [PATCH 5/9] Bug fixes and linter --- backend/middlewares/auth.ts | 9 +- .../middlewares/validators/authValidators.ts | 4 +- backend/rest/authRoutes.ts | 13 +- backend/server.ts | 2 - .../services/implementations/authService.ts | 5 +- .../services/implementations/userService.ts | 44 ++++--- backend/services/interfaces/authService.ts | 2 +- backend/services/interfaces/userService.ts | 14 +- backend/utilities/firebaseRestClient.ts | 22 ++-- frontend/src/APIClients/AuthAPIClient.ts | 12 +- frontend/src/components/auth/Login.tsx | 7 +- frontend/src/components/auth/PrivateRoute.tsx | 13 +- .../components/pages/CreatePasswordPage.tsx | 123 +++++++++--------- 13 files changed, 146 insertions(+), 124 deletions(-) diff --git a/backend/middlewares/auth.ts b/backend/middlewares/auth.ts index 6d7c56d..a7ddfaf 100644 --- a/backend/middlewares/auth.ts +++ b/backend/middlewares/auth.ts @@ -4,7 +4,7 @@ import AuthService from "../services/implementations/authService"; import UserService from "../services/implementations/userService"; import IAuthService from "../services/interfaces/authService"; import IUserService from "../services/interfaces/userService"; -import { Role, Status } from "../types/userTypes"; +import { Role } from "../types/userTypes"; const authService: IAuthService = new AuthService(new UserService()); const userService: IUserService = new UserService(); @@ -83,13 +83,12 @@ export const isFirstTimeInvitedUser = () => { return async (req: Request, res: Response, next: NextFunction) => { const accessToken = getAccessToken(req); const authorized = - accessToken && - await userService.isFirstTimeInvitedUser(accessToken); + accessToken && (await userService.isFirstTimeInvitedUser(accessToken)); if (!authorized) { return res .status(401) .json({ error: "You are not a first-time invited user." }); } return next(); - } -} + }; +}; diff --git a/backend/middlewares/validators/authValidators.ts b/backend/middlewares/validators/authValidators.ts index 0efe8b1..62825c0 100644 --- a/backend/middlewares/validators/authValidators.ts +++ b/backend/middlewares/validators/authValidators.ts @@ -72,7 +72,7 @@ export const forgotPasswordRequestValidator = async ( } return next(); -} +}; export const updateTemporaryPasswordRequestValidator = async ( req: Request, @@ -96,4 +96,4 @@ export const updateUserStatusRequestValidator = async ( } return next(); -} +}; diff --git a/backend/rest/authRoutes.ts b/backend/rest/authRoutes.ts index 2cb93a0..97c0828 100644 --- a/backend/rest/authRoutes.ts +++ b/backend/rest/authRoutes.ts @@ -26,8 +26,6 @@ import IUserService from "../services/interfaces/userService"; import { getErrorMessage } from "../utilities/errorUtils"; import { AuthErrorCodes } from "../types/authTypes"; -import * as firebaseAdmin from "firebase-admin"; - const authRouter: Router = Router(); const userService: IUserService = new UserService(); const emailService: IEmailService = new EmailService(nodemailerConfig); @@ -222,11 +220,14 @@ authRouter.post( authRouter.post( "/updateTemporaryPassword", updateTemporaryPasswordRequestValidator, - // isFirstTimeInvitedUser(), + isFirstTimeInvitedUser(), async (req, res) => { try { const accessToken = getAccessToken(req)!; - const newAccessToken = await authService.changeUserPassword(accessToken, req.body.newPassword); + const newAccessToken = await authService.changeUserPassword( + accessToken, + req.body.newPassword, + ); res.status(200).json({ accessToken: newAccessToken, }); @@ -247,7 +248,7 @@ authRouter.post( } catch (error: unknown) { res.status(500).json({ error: getErrorMessage(error) }); } - } -) + }, +); export default authRouter; diff --git a/backend/server.ts b/backend/server.ts index 3607c4a..f1df001 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -5,8 +5,6 @@ import { createServer } from "http"; import { Server } from "socket.io"; import RateLimit from "express-rate-limit"; import * as firebaseAdmin from "firebase-admin"; -import * as firebaseAuth from "@firebase/auth" -import * as firebase from "firebase/app"; import swaggerUi from "swagger-ui-express"; import YAML from "yamljs"; diff --git a/backend/services/implementations/authService.ts b/backend/services/implementations/authService.ts index 3a490d8..74a8b23 100644 --- a/backend/services/implementations/authService.ts +++ b/backend/services/implementations/authService.ts @@ -1,5 +1,6 @@ import * as firebaseAdmin from "firebase-admin"; import { ObjectId } from "mongoose"; + import IAuthService from "../interfaces/authService"; import IEmailService from "../interfaces/emailService"; import IUserService from "../interfaces/userService"; @@ -165,7 +166,9 @@ class AuthService implements IAuthService { ); } catch (error: unknown) { Logger.error( - `Failed to invite new administrator. Reason = ${getErrorMessage(error)}`, + `Failed to invite new administrator. Reason = ${getErrorMessage( + error, + )}`, ); throw error; } diff --git a/backend/services/implementations/userService.ts b/backend/services/implementations/userService.ts index daab875..46a8477 100644 --- a/backend/services/implementations/userService.ts +++ b/backend/services/implementations/userService.ts @@ -192,7 +192,12 @@ class UserService implements IUserService { // must explicitly specify runValidators when updating through findByIdAndUpdate oldUser = await MgUser.findByIdAndUpdate( userId, - { firstName: user.firstName, lastName: user.lastName, role: user.role, status: user.status }, + { + firstName: user.firstName, + lastName: user.lastName, + role: user.role, + status: user.status, + }, { runValidators: true }, ); @@ -346,41 +351,40 @@ class UserService implements IUserService { return userDtos; } - async isFirstTimeInvitedUser( - accessToken: string, - ): Promise { + async isFirstTimeInvitedUser(accessToken: string): Promise { try { - console.log("flag 5") - const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin - .auth() - .verifyIdToken(accessToken, true); - console.log("flag 6") - const { status } = await getMongoUserByAuthId( - decodedIdToken.uid - ); - console.log("flag 7") + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = + await firebaseAdmin.auth().verifyIdToken(accessToken, true); + const { status } = await getMongoUserByAuthId(decodedIdToken.uid); return status === "Invited"; } catch (error: unknown) { - Logger.error(`Failed to verify user is first time invited user. Reason = ${getErrorMessage(error)}`); + Logger.error( + `Failed to verify user is first time invited user. Reason = ${getErrorMessage( + error, + )}`, + ); throw error; } } - async changeUserStatus(accessToken: string, newStatus: Status): Promise { + async changeUserStatus( + accessToken: string, + newStatus: Status, + ): Promise { try { - const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = await firebaseAdmin - .auth() - .verifyIdToken(accessToken, true); + const decodedIdToken: firebaseAdmin.auth.DecodedIdToken = + await firebaseAdmin.auth().verifyIdToken(accessToken, true); const tokenUserId = await this.getUserIdByAuthId(decodedIdToken.uid); const currentUser = await this.getUserById(tokenUserId); const updatedUser: UpdateUserDTO = { ...currentUser, status: newStatus, }; - console.log("Updated user:", updatedUser) await this.updateUserById(tokenUserId, updatedUser); } catch (error: unknown) { - Logger.error(`Failed to change user status. Reason = ${getErrorMessage(error)}`); + Logger.error( + `Failed to change user status. Reason = ${getErrorMessage(error)}`, + ); throw error; } } diff --git a/backend/services/interfaces/authService.ts b/backend/services/interfaces/authService.ts index 0c9510a..eea5878 100644 --- a/backend/services/interfaces/authService.ts +++ b/backend/services/interfaces/authService.ts @@ -1,6 +1,6 @@ import { ObjectId } from "mongoose"; import { AuthDTO, Token } from "../../types/authTypes"; -import { Role, Status } from "../../types/userTypes"; +import { Role } from "../../types/userTypes"; interface IAuthService { /** diff --git a/backend/services/interfaces/userService.ts b/backend/services/interfaces/userService.ts index 0cf75a0..75b7b1f 100644 --- a/backend/services/interfaces/userService.ts +++ b/backend/services/interfaces/userService.ts @@ -101,14 +101,14 @@ interface IUserService { * @param accessToken user's access token * @param status status to check for match */ - isFirstTimeInvitedUser( - accessToken: string, - ): Promise; + isFirstTimeInvitedUser(accessToken: string): Promise; - changeUserStatus( - accessToken: string, - newStatus: Status, - ): Promise; + /** + * Update the user's status to the specified new status value + * @param accessToken user's access token + * @param newStatus status to update to + */ + changeUserStatus(accessToken: string, newStatus: Status): Promise; } export default IUserService; diff --git a/backend/utilities/firebaseRestClient.ts b/backend/utilities/firebaseRestClient.ts index 3469061..fdf4097 100644 --- a/backend/utilities/firebaseRestClient.ts +++ b/backend/utilities/firebaseRestClient.ts @@ -9,8 +9,6 @@ const FIREBASE_SIGN_IN_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword"; const FIREBASE_REFRESH_TOKEN_URL = "https://securetoken.googleapis.com/v1/token"; -const FIREBASE_OAUTH_SIGN_IN_URL = - "https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp"; const FIREBASE_CHANGE_PASSWORD_URL = "https://identitytoolkit.googleapis.com/v1/accounts:update"; @@ -24,11 +22,11 @@ type PasswordSignInResponse = { }; type ChangePasswordResponse = { - localId: string, - email: string, - idToken: string, - emailVerified: boolean, -} + localId: string; + email: string; + idToken: string; + emailVerified: boolean; +}; type RefreshTokenResponse = { expires_in: string; @@ -129,7 +127,10 @@ const FirebaseRestClient = { }; }, - changePassword: async (accessToken: string, newPassword: string): Promise => { + changePassword: async ( + accessToken: string, + newPassword: string, + ): Promise => { const response: Response = await fetch( `${FIREBASE_CHANGE_PASSWORD_URL}?key=${process.env.FIREBASE_WEB_API_KEY}`, { @@ -144,9 +145,8 @@ const FirebaseRestClient = { }, ); - const responseJson: - | ChangePasswordResponse - | RequestError = await response.json(); + const responseJson: ChangePasswordResponse | RequestError = + await response.json(); if (!response.ok) { const errorMessage = [ diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index be017db..c27f8cd 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -81,7 +81,10 @@ const resetPassword = async (email: string | undefined): Promise => { } }; -const updateTemporaryPassword = async (email: string, newPassword: string): Promise => { +const updateTemporaryPassword = async ( + email: string, + newPassword: string, +): Promise => { const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, "accessToken", @@ -92,10 +95,7 @@ const updateTemporaryPassword = async (email: string, newPassword: string): Prom { newPassword }, { headers: { Authorization: bearerToken } }, ); - const newAuthenticatedUser = await login( - email, - newPassword, - ); + const newAuthenticatedUser = await login(email, newPassword); if (!newAuthenticatedUser) { throw new Error("Unable to authenticate user after logging in."); } @@ -125,7 +125,7 @@ const updateUserStatus = async (newStatus: Status): Promise => { } catch (error) { return false; } -} +}; // for testing only, refresh does not need to be exposed in the client const refresh = async (): Promise => { diff --git a/frontend/src/components/auth/Login.tsx b/frontend/src/components/auth/Login.tsx index 1fb8ef4..23395dc 100644 --- a/frontend/src/components/auth/Login.tsx +++ b/frontend/src/components/auth/Login.tsx @@ -1,7 +1,12 @@ import React, { useContext, useState } from "react"; import { Redirect, useHistory, useLocation } from "react-router-dom"; import authAPIClient from "../../APIClients/AuthAPIClient"; -import { CREATE_PASSWORD_PAGE, HOME_PAGE, SIGNUP_PAGE, WELCOME_PAGE } from "../../constants/Routes"; +import { + CREATE_PASSWORD_PAGE, + HOME_PAGE, + SIGNUP_PAGE, + WELCOME_PAGE, +} from "../../constants/Routes"; import AuthContext from "../../contexts/AuthContext"; import { AuthenticatedUser } from "../../types/AuthTypes"; import AUTHENTICATED_USER_KEY from "../../constants/AuthConstants"; diff --git a/frontend/src/components/auth/PrivateRoute.tsx b/frontend/src/components/auth/PrivateRoute.tsx index df835fc..d88ddc2 100644 --- a/frontend/src/components/auth/PrivateRoute.tsx +++ b/frontend/src/components/auth/PrivateRoute.tsx @@ -2,7 +2,11 @@ import React, { useContext } from "react"; import { Route, Redirect } from "react-router-dom"; import AuthContext from "../../contexts/AuthContext"; -import { CREATE_PASSWORD_PAGE, NOT_AUTHORIZED_PAGE, WELCOME_PAGE } from "../../constants/Routes"; +import { + CREATE_PASSWORD_PAGE, + NOT_AUTHORIZED_PAGE, + WELCOME_PAGE, +} from "../../constants/Routes"; import { Role } from "../../types/AuthTypes"; type PrivateRouteProps = { @@ -21,8 +25,11 @@ const PrivateRoute: React.FC = ({ const { authenticatedUser } = useContext(AuthContext); if (authenticatedUser) { - if (authenticatedUser.status === "Invited" && path !== CREATE_PASSWORD_PAGE) { - return + if ( + authenticatedUser.status === "Invited" && + path !== CREATE_PASSWORD_PAGE + ) { + return ; } return allowedRoles.includes(authenticatedUser.role) ? ( diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index a8ad20b..0c0d5aa 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -6,71 +6,76 @@ import AuthContext from "../../contexts/AuthContext"; import AUTHENTICATED_USER_KEY from "../../constants/AuthConstants"; const CreatePasswordPage = (): React.ReactElement => { - const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext); - const [newPassword, setNewPassword] = useState(""); - const history = useHistory(); + const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext); + const [newPassword, setNewPassword] = useState(""); + const history = useHistory(); - if (authenticatedUser?.status !== "Invited") { - console.log("Not a newly invited user") - return - } - - const onSubmitNewPasswordClick = async () => { - const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword(authenticatedUser.email, newPassword); - if (!changePasswordSuccess) { - // change this later to not use an alert - // eslint-disable-next-line no-alert - setAuthenticatedUser(null); - localStorage.removeItem(AUTHENTICATED_USER_KEY); - // await AuthAPIClient.logout(authenticatedUser.id); - alert("Error occurred when changing your password. Please log in again."); - return; - } + if (authenticatedUser?.status !== "Invited") { + return ; + } - // change this later to not use an alert - // eslint-disable-next-line no-alert - const updateStatusSuccess = await AuthAPIClient.updateUserStatus("Active"); - if (!updateStatusSuccess) { - alert("Failed to update user status to \"Active\""); - return; - } + const onSubmitNewPasswordClick = async () => { + const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword( + authenticatedUser.email, + newPassword, + ); + if (!changePasswordSuccess) { + setAuthenticatedUser(null); + localStorage.removeItem(AUTHENTICATED_USER_KEY); + // await AuthAPIClient.logout(authenticatedUser.id); - setAuthenticatedUser({ - ...authenticatedUser, - status: "Active", - }) + // change this later to not use an alert + // eslint-disable-next-line no-alert + alert("Error occurred when changing your password. Please log in again."); + return; + } - history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); + const updateStatusSuccess = await AuthAPIClient.updateUserStatus("Active"); + if (!updateStatusSuccess) { + // change this later to not use an alert + // eslint-disable-next-line no-alert + alert('Failed to update user status to "Active"'); + return; } - return ( -
-

Choose a New Password

-
- Since this is your first time logging in, please choose a new password. -
-
- setNewPassword(event.target.value)} - placeholder="New Password" - /> - -
-
- ); + setAuthenticatedUser({ + ...authenticatedUser, + status: "Active", + }); + + history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); + }; + + return ( +
+

Choose a New Password

+
+ Since this is your first time logging in, please choose a new password. +
+
+ setNewPassword(event.target.value)} + placeholder="New Password" + /> + +
+
+ ); }; export default CreatePasswordPage; From dfea78ac722d135ab1db30f015497dac937149e7 Mon Sep 17 00:00:00 2001 From: ji-mmyliu Date: Mon, 23 Sep 2024 21:39:53 -0400 Subject: [PATCH 6/9] Revert docker compose changes --- docker-compose.yml | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 994132b..bb422b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,9 +16,6 @@ services: backend: container_name: eaf_backend restart: always - depends_on: - database: - condition: service_healthy build: context: ./backend dockerfile: Dockerfile @@ -30,18 +27,6 @@ services: - ./backend:/app env_file: - ./.env - database: - container_name: eaf_database - image: mongo - environment: - - MONGO_INITDB_ROOT_USERNAME=eaf_user - - MONGO_INITDB_ROOT_PASSWORD=eaf_password - ports: - - 27017:27017 - volumes: - - data:/data/db - healthcheck: - test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet # database: # container_name: eaf_database # image: mongodb/mongodb-atlas-local @@ -52,5 +37,5 @@ services: # - 27018:27017 # volumes: # - data:/data/db -volumes: - data: +# volumes: +# data: From 0b9ee9085e2c0b2d63b4b4b193eb98b46008c8a4 Mon Sep 17 00:00:00 2001 From: ji-mmyliu Date: Mon, 23 Sep 2024 21:51:54 -0400 Subject: [PATCH 7/9] Remove unnecessary packages --- backend/package.json | 3 - .../services/implementations/authService.ts | 7 - backend/yarn.lock | 367 +----------------- .../components/pages/CreatePasswordPage.tsx | 4 +- 4 files changed, 3 insertions(+), 378 deletions(-) diff --git a/backend/package.json b/backend/package.json index 3bdaa32..353aa03 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,8 +15,6 @@ "author": "", "license": "ISC", "dependencies": { - "@firebase/app": "^0.10.6", - "@firebase/auth": "^1.7.4", "@types/json2csv": "^5.0.3", "@types/multer": "^1.4.6", "@types/swagger-ui-express": "^4.1.2", @@ -27,7 +25,6 @@ "dotenv": "^8.2.0", "express": "^4.19.2", "express-rate-limit": "^6.2.0", - "firebase": "^10.12.3", "firebase-admin": "^9.5.0", "generate-password": "^1.7.1", "json2csv": "^5.0.6", diff --git a/backend/services/implementations/authService.ts b/backend/services/implementations/authService.ts index 74a8b23..ad3a4de 100644 --- a/backend/services/implementations/authService.ts +++ b/backend/services/implementations/authService.ts @@ -17,19 +17,12 @@ class AuthService implements IAuthService { emailService: IEmailService | null; - firebaseAuth: firebaseAuth.Auth; - constructor( userService: IUserService, emailService: IEmailService | null = null, ) { this.userService = userService; this.emailService = emailService; - const firebaseApp = firebase.initializeApp({ - apiKey: process.env.FIREBASE_WEB_API_KEY, - projectId: process.env.FIREBASE_PROJECT_ID, - }); - this.firebaseAuth = firebaseAuth.getAuth(firebaseApp); } /* eslint-disable class-methods-use-this */ diff --git a/backend/yarn.lock b/backend/yarn.lock index 6a2b947..c9cc876 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -818,60 +818,11 @@ resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.7.0.tgz#c9e16d1b8bed1a991840b8d2a725fb58d0b5899f" integrity sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg== -"@firebase/app-types@0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.2.tgz#8cbcceba784753a7c0066a4809bc22f93adee080" - integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ== - -"@firebase/app@0.10.7", "@firebase/app@^0.10.6": - version "0.10.7" - resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.10.7.tgz#31cba1486c21b5a0cadc0036bfc0cec68ff53c8e" - integrity sha512-7OCd53B+wnk/onbMLn/vM10pDjw97zzWUD8m3swtLYKJIrL+gDZ7HZ4xcbBLw7OB8ikzu8k1ORNjRe2itgAy4g== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/auth-compat@0.5.10": - version "0.5.10" - resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.5.10.tgz#7705fc27883a8fafb2e85271e1d5cd7314609276" - integrity sha512-epDhgNIXmhl9DPuTW9Ec5NDJJKMFIdXBXiQI9O0xNHveow/ETtBCY86srzF7iCacqsd30CcpLwwXlhk8Y19Olg== - dependencies: - "@firebase/auth" "1.7.5" - "@firebase/auth-types" "0.12.2" - "@firebase/component" "0.6.8" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - undici "5.28.4" - "@firebase/auth-interop-types@0.1.6": version "0.1.6" resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== -"@firebase/auth-interop-types@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz#927f1f2139a680b55fef0bddbff2c982b08587e8" - integrity sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ== - -"@firebase/auth-types@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.12.2.tgz#f12d890585866e53b6ab18b16fa4d425c52eee6e" - integrity sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w== - -"@firebase/auth@1.7.5", "@firebase/auth@^1.7.4": - version "1.7.5" - resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.7.5.tgz#8135e0933e874231d7ebafc94f5796a19f5df39b" - integrity sha512-DMFR1OA/f1/voeuFbSORg9AP36pMgOoSb/DRgiDalLmIJsDTlQNMCu+givjMP4s/XL85+tBk2MerYnK/AscJjw== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - undici "5.28.4" - "@firebase/component@0.5.13": version "0.5.13" resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.5.13.tgz#65a382e83bddd109380c9aa1f280791b1b4567c4" @@ -880,26 +831,6 @@ "@firebase/util" "1.5.2" tslib "^2.1.0" -"@firebase/component@0.6.8": - version "0.6.8" - resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.8.tgz#899b9318c0ce0586580e8cda7eaf61296f7fb43b" - integrity sha512-LcNvxGLLGjBwB0dJUsBGCej2fqAepWyBubs4jt1Tiuns7QLbXHuyObZ4aMeBjZjWx4m8g1LoVI9QFpSaq/k4/g== - dependencies: - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/database-compat@1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-1.0.6.tgz#6a4966fe4a9d8bc2cb11ee98a1bb01ab954d7d66" - integrity sha512-1OGA0sLY47mkXjhICCrUTXEYFnSSXoiXWm1SHsN62b+Lzs5aKA3aWTjTUmYIoK93kDAMPkYpulSv8jcbH4Hwew== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/database" "1.0.6" - "@firebase/database-types" "1.0.4" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - "@firebase/database-compat@^0.1.1": version "0.1.8" resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.1.8.tgz#ab627f2bdbe94367f515d5bded880c86886bbd28" @@ -920,14 +851,6 @@ "@firebase/app-types" "0.7.0" "@firebase/util" "1.5.2" -"@firebase/database-types@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.4.tgz#dc507f7838ed29ac3235c68ebae5fd42a562e3e8" - integrity sha512-mz9ZzbH6euFXbcBo+enuJ36I5dR5w+enJHHjy9Y5ThCdKUseqfDjW3vCp1YxE9zygFCSjJJ/z1cQ+zodvUcwPQ== - dependencies: - "@firebase/app-types" "0.9.2" - "@firebase/util" "1.9.7" - "@firebase/database-types@^0.7.2": version "0.7.3" resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.7.3.tgz#819f16dd4c767c864b460004458620f265a3f735" @@ -947,104 +870,6 @@ faye-websocket "0.11.4" tslib "^2.1.0" -"@firebase/database@1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.0.6.tgz#cf0592b140e207e35c14efe6776fc92266ac408a" - integrity sha512-nrexUEG/fpVlHtWKkyfhTC3834kZ1WS7voNyqbBsBCqHXQOvznN5Z0L3nxBqdXSJyltNAf4ndFlQqm5gZiEczQ== - dependencies: - "@firebase/app-check-interop-types" "0.3.2" - "@firebase/auth-interop-types" "0.2.3" - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - faye-websocket "0.11.4" - tslib "^2.1.0" - -"@firebase/firestore-compat@0.3.33": - version "0.3.33" - resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.33.tgz#8e591bfafb574c695b09101b98c1a1057f55c60e" - integrity sha512-i42a2l31N95CwYEB7zmfK0FS1mrO6pwOLwxavCrwu1BCFrVVVQhUheTPIda/iGguK/2Nog0RaIR1bo7QkZEz3g== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/firestore" "4.6.4" - "@firebase/firestore-types" "3.0.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/firestore-types@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.2.tgz#75c301acc5fa33943eaaa9570b963c55398cad2a" - integrity sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg== - -"@firebase/firestore@4.6.4": - version "4.6.4" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.6.4.tgz#f53fcfc3ecfeb844f2147a43382d013d21e64968" - integrity sha512-vk2MoH5HxYEhiNg1l+yBXq1Fkhue/11bFg4HdlTv6BJHcTnnAj2a+/afPpatcW4MOdYA3Tv+d5nGzWbbOC1SHw== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - "@firebase/webchannel-wrapper" "1.0.1" - "@grpc/grpc-js" "~1.9.0" - "@grpc/proto-loader" "^0.7.8" - tslib "^2.1.0" - undici "5.28.4" - -"@firebase/functions-compat@0.3.12": - version "0.3.12" - resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.12.tgz#aae387eb48466df1d031fc5bb755c657cfeb5994" - integrity sha512-r3XUb5VlITWpML46JymfJPkK6I9j4SNlO7qWIXUc0TUmkv0oAfVoiIt1F83/NuMZXaGr4YWA/794nVSy4GV8tw== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/functions" "0.11.6" - "@firebase/functions-types" "0.6.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/functions-types@0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.2.tgz#03b4ec9259d2f57548a3909d6a35ae35ad243552" - integrity sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w== - -"@firebase/functions@0.11.6": - version "0.11.6" - resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.11.6.tgz#607991a3a870051e6456d7ccb0217fac6305db89" - integrity sha512-GPfIBPtpwQvsC7SQbgaUjLTdja0CsNwMoKSgrzA1FGGRk4NX6qO7VQU6XCwBiAFWbpbQex6QWkSMsCzLx1uibQ== - dependencies: - "@firebase/app-check-interop-types" "0.3.2" - "@firebase/auth-interop-types" "0.2.3" - "@firebase/component" "0.6.8" - "@firebase/messaging-interop-types" "0.2.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - undici "5.28.4" - -"@firebase/installations-compat@0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.8.tgz#ebc908afe84db2754b19a62f7655608911e13819" - integrity sha512-pI2q8JFHB7yIq/szmhzGSWXtOvtzl6tCUmyykv5C8vvfOVJUH6mP4M4iwjbK8S1JotKd/K70+JWyYlxgQ0Kpyw== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/installations" "0.6.8" - "@firebase/installations-types" "0.5.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/installations-types@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.2.tgz#4d4949e0e83ced7f36cbee009355cd305a36e158" - integrity sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA== - -"@firebase/installations@0.6.8": - version "0.6.8" - resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.8.tgz#f9c9d493bce04b04ca28814e926ef3ed71f033d6" - integrity sha512-57V374qdb2+wT5v7+ntpLXBjZkO6WRgmAUbVkRfFTM/4t980p0FesbqTAcOIiM8U866UeuuuF8lYH70D3jM/jQ== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/util" "1.9.7" - idb "7.1.1" - tslib "^2.1.0" - "@firebase/logger@0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.3.2.tgz#5046ffa8295c577846d54b6ca95645a03809800e" @@ -1052,122 +877,6 @@ dependencies: tslib "^2.1.0" -"@firebase/logger@0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.2.tgz#74dfcfeedee810deb8a7080d5b7eba56aa16ffa2" - integrity sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A== - dependencies: - tslib "^2.1.0" - -"@firebase/messaging-compat@0.2.10": - version "0.2.10" - resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.10.tgz#08711f75e2d517fd209bfbc65b1f754b09b2121c" - integrity sha512-FXQm7rcowkDm8kFLduHV35IRYCRo+Ng0PIp/t1+EBuEbyplaKkGjZ932pE+owf/XR+G/60ku2QRBptRGLXZydg== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/messaging" "0.12.10" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/messaging-interop-types@0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz#81042f7e9739733fa4571d17f6eb6869522754d0" - integrity sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA== - -"@firebase/messaging@0.12.10": - version "0.12.10" - resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.10.tgz#29909f909b9588d44864732377d88de11f3b3ed3" - integrity sha512-fGbxJPKpl2DIKNJGhbk4mYPcM+qE2gl91r6xPoiol/mN88F5Ym6UeRdMVZah+pijh9WxM55alTYwXuW40r1Y2Q== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/installations" "0.6.8" - "@firebase/messaging-interop-types" "0.2.2" - "@firebase/util" "1.9.7" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/performance-compat@0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.8.tgz#d97bab3fd0c147c7f796e9b8f78712bc0b83699c" - integrity sha512-o7TFClRVJd3VIBoY7KZQqtCeW0PC6v9uBzM6Lfw3Nc9D7hM6OonqecYvh7NwJ6R14k+xM27frLS4BcCvFHKw2A== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/performance" "0.6.8" - "@firebase/performance-types" "0.2.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/performance-types@0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.2.tgz#7b78cd2ab2310bac89a63348d93e67e01eb06dd7" - integrity sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA== - -"@firebase/performance@0.6.8": - version "0.6.8" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.6.8.tgz#668b0fc207389f7829fd3bfb6614fe819b7db124" - integrity sha512-F+alziiIZ6Yn8FG47mxwljq+4XkgkT2uJIFRlkyViUQRLzrogaUJW6u/+6ZrePXnouKlKIwzqos3PVJraPEcCA== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/installations" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/remote-config-compat@0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.8.tgz#a6df065c1fd0a943e84ee0e76acfc6c1bede42f9" - integrity sha512-UxSFOp6dzFj2AHB8Bq/BYtbq5iFyizKx4Rd6WxAdaKYM8cnPMeK+l2v+Oogtjae+AeyHRI+MfL2acsfVe5cd2A== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/remote-config" "0.4.8" - "@firebase/remote-config-types" "0.3.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/remote-config-types@0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz#a5d1009c6fd08036c5cd4f28764e3cd694f966d5" - integrity sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA== - -"@firebase/remote-config@0.4.8": - version "0.4.8" - resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.4.8.tgz#b6a79acdf73554e0ee31c278162b85592fc8c1f3" - integrity sha512-AMLqe6wfIRnjc6FkCWOSUjhc1fSTEf8o+cv1NolFvbiJ/tU+TqN4pI7pT+MIKQzNiq5fxLehkOx+xtAQBxPJKQ== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/installations" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/storage-compat@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.9.tgz#42496a7b5f7c384f0ea590d704934465102b4527" - integrity sha512-WWgAp5bTW961oIsCc9+98m4MIVKpEqztAlIngfHfwO/x3DYoBPRl/awMRG3CAXyVxG+7B7oHC5IsnqM+vTwx2A== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/storage" "0.12.6" - "@firebase/storage-types" "0.8.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/storage-types@0.8.2": - version "0.8.2" - resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.2.tgz#edb321b8a3872a9f74e1f27de046f160021c8e1f" - integrity sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g== - -"@firebase/storage@0.12.6": - version "0.12.6" - resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.12.6.tgz#49b2c77f10fd97da913a93e37c86cdff92a805eb" - integrity sha512-Zgb9WuehJxzhj7pGXUvkAEaH+3HvLjD9xSZ9nepuXf5f8378xME7oGJtREr/RnepdDA5YW0XIxe0QQBNHpe1nw== - dependencies: - "@firebase/component" "0.6.8" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - undici "5.28.4" - "@firebase/util@1.5.2": version "1.5.2" resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.5.2.tgz#bdd2bc11c956a8a6a0fa25fbd752a13e033558bc" @@ -1175,29 +884,6 @@ dependencies: tslib "^2.1.0" -"@firebase/util@1.9.7": - version "1.9.7" - resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.9.7.tgz#c03b0ae065b3bba22800da0bd5314ef030848038" - integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA== - dependencies: - tslib "^2.1.0" - -"@firebase/vertexai-preview@0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@firebase/vertexai-preview/-/vertexai-preview-0.0.3.tgz#73dea839439ebdbb5ccd946f297ede5b57e6e7e9" - integrity sha512-KVtUWLp+ScgiwkDKAvNkVucAyhLVQp6C6lhnVEuIg4mWhWcS3oerjAeVhZT4uNofKwWxRsOaB2Yec7DMTXlQPQ== - dependencies: - "@firebase/app-check-interop-types" "0.3.2" - "@firebase/component" "0.6.8" - "@firebase/logger" "0.4.2" - "@firebase/util" "1.9.7" - tslib "^2.1.0" - -"@firebase/webchannel-wrapper@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.1.tgz#0b62c9f47f557a5b4adc073bb0a47542ce6af4c4" - integrity sha512-jmEnr/pk0yVkA7mIlHNnxCi+wWzOFUg0WyIotgkKAb2u1J7fAeDBcVNSTjTihbAYNusCLQdW5s9IJ5qwnEufcQ== - "@google-cloud/firestore@^4.5.0": version "4.15.1" resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-4.15.1.tgz#ed764fc76823ce120e68fe8c27ef1edd0650cd93" @@ -1263,14 +949,6 @@ "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" -"@grpc/grpc-js@~1.9.0": - version "1.9.15" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" - integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== - dependencies: - "@grpc/proto-loader" "^0.7.8" - "@types/node" ">=12.12.47" - "@grpc/proto-loader@^0.6.12": version "0.6.13" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc" @@ -1282,7 +960,7 @@ protobufjs "^6.11.3" yargs "^16.2.0" -"@grpc/proto-loader@^0.7.0", "@grpc/proto-loader@^0.7.8": +"@grpc/proto-loader@^0.7.0": version "0.7.13" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== @@ -4269,39 +3947,6 @@ firebase-admin@^9.5.0: "@google-cloud/firestore" "^4.5.0" "@google-cloud/storage" "^5.3.0" -firebase@^10.12.3: - version "10.12.4" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-10.12.4.tgz#ca2451d1cf999a3e94e2287c56abdd94e043ddb0" - integrity sha512-SQz49NMpwG4MLTPZ9C8jBp7IyS2haTvsIvjclgu+v/jvzNtjZoxIcoF6A13EIfBHmJ5eiuVlvttxElOf7LnJew== - dependencies: - "@firebase/analytics" "0.10.6" - "@firebase/analytics-compat" "0.2.12" - "@firebase/app" "0.10.7" - "@firebase/app-check" "0.8.6" - "@firebase/app-check-compat" "0.3.13" - "@firebase/app-compat" "0.2.37" - "@firebase/app-types" "0.9.2" - "@firebase/auth" "1.7.5" - "@firebase/auth-compat" "0.5.10" - "@firebase/database" "1.0.6" - "@firebase/database-compat" "1.0.6" - "@firebase/firestore" "4.6.4" - "@firebase/firestore-compat" "0.3.33" - "@firebase/functions" "0.11.6" - "@firebase/functions-compat" "0.3.12" - "@firebase/installations" "0.6.8" - "@firebase/installations-compat" "0.2.8" - "@firebase/messaging" "0.12.10" - "@firebase/messaging-compat" "0.2.10" - "@firebase/performance" "0.6.8" - "@firebase/performance-compat" "0.2.8" - "@firebase/remote-config" "0.4.8" - "@firebase/remote-config-compat" "0.2.8" - "@firebase/storage" "0.12.6" - "@firebase/storage-compat" "0.3.9" - "@firebase/util" "1.9.7" - "@firebase/vertexai-preview" "0.0.3" - flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" @@ -4721,11 +4366,6 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -idb@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" - integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== - ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -6867,11 +6507,6 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -safevalues@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/safevalues/-/safevalues-0.6.0.tgz#425eadbdb699c13d8cfd932485983f858222362a" - integrity sha512-MZ7DcTOcIoPXN36/UONVE9BT0pmwlCr9WcS7Pj/q4FxOwr33FkWC0CUWj/THQXYWxf/F7urbhaHaOeFPSqGqHA== - saslprep@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index 0c0d5aa..bef327f 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -22,7 +22,7 @@ const CreatePasswordPage = (): React.ReactElement => { if (!changePasswordSuccess) { setAuthenticatedUser(null); localStorage.removeItem(AUTHENTICATED_USER_KEY); - // await AuthAPIClient.logout(authenticatedUser.id); + await AuthAPIClient.logout(authenticatedUser.id); // change this later to not use an alert // eslint-disable-next-line no-alert @@ -43,7 +43,7 @@ const CreatePasswordPage = (): React.ReactElement => { status: "Active", }); - history.push(`${LOGIN_PAGE}?role=${authenticatedUser.role}`); + history.push(HOME_PAGE); }; return ( From c88f492ef7e308636a4d08a3f6a8a346ce99f6cb Mon Sep 17 00:00:00 2001 From: ji-mmyliu Date: Mon, 23 Sep 2024 22:43:48 -0400 Subject: [PATCH 8/9] Add role parameter to login for update temp password --- frontend/src/APIClients/AuthAPIClient.ts | 3 ++- frontend/src/components/pages/CreatePasswordPage.tsx | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index c27f8cd..0f44c9e 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -84,6 +84,7 @@ const resetPassword = async (email: string | undefined): Promise => { const updateTemporaryPassword = async ( email: string, newPassword: string, + role: Role, ): Promise => { const bearerToken = `Bearer ${getLocalStorageObjProperty( AUTHENTICATED_USER_KEY, @@ -95,7 +96,7 @@ const updateTemporaryPassword = async ( { newPassword }, { headers: { Authorization: bearerToken } }, ); - const newAuthenticatedUser = await login(email, newPassword); + const newAuthenticatedUser = await login(email, newPassword, role); if (!newAuthenticatedUser) { throw new Error("Unable to authenticate user after logging in."); } diff --git a/frontend/src/components/pages/CreatePasswordPage.tsx b/frontend/src/components/pages/CreatePasswordPage.tsx index bef327f..3924fdc 100644 --- a/frontend/src/components/pages/CreatePasswordPage.tsx +++ b/frontend/src/components/pages/CreatePasswordPage.tsx @@ -18,6 +18,7 @@ const CreatePasswordPage = (): React.ReactElement => { const changePasswordSuccess = await AuthAPIClient.updateTemporaryPassword( authenticatedUser.email, newPassword, + authenticatedUser.role, ); if (!changePasswordSuccess) { setAuthenticatedUser(null); From 4abcb496705c489aaa1933a845fc7805452a8b9f Mon Sep 17 00:00:00 2001 From: ji-mmyliu Date: Mon, 23 Sep 2024 22:57:55 -0400 Subject: [PATCH 9/9] Fix imports and lint --- backend/services/implementations/userService.ts | 7 +++++-- frontend/src/App.tsx | 6 ++++++ frontend/src/components/auth/Login.tsx | 7 +------ frontend/src/components/pages/CreatePasswordPage.tsx | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/services/implementations/userService.ts b/backend/services/implementations/userService.ts index 46a8477..59d18c6 100644 --- a/backend/services/implementations/userService.ts +++ b/backend/services/implementations/userService.ts @@ -26,7 +26,7 @@ const getMongoUserByAuthId = async (authId: string): Promise => { class UserService implements IUserService { /* eslint-disable class-methods-use-this */ - async getUserById(userId: string): Promise { + async getUserById(userId: string | ObjectId): Promise { let user: User | null; let firebaseUser: firebaseAdmin.auth.UserRecord; @@ -184,7 +184,10 @@ class UserService implements IUserService { }; } - async updateUserById(userId: string, user: UpdateUserDTO): Promise { + async updateUserById( + userId: ObjectId | string, + user: UpdateUserDTO, + ): Promise { let oldUser: User | null; let updatedFirebaseUser: firebaseAdmin.auth.UserRecord; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6add2e3..99d0e00 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -95,6 +95,12 @@ const App = (): React.ReactElement => { path={Routes.NOT_AUTHORIZED_PAGE} component={NotAuthorized} /> +