From a4edf6bd0c800488fc350b112537cee3864a8109 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Fri, 11 Aug 2023 11:27:33 +0700 Subject: [PATCH] Remove remaining SecurityClient auth calls in favor of hooks, keep RouteGuard --- backend/src/routes/v1/key.ts | 2 +- backend/src/routes/v1/membership.ts | 2 +- .../src/components/signup/CodeInputStep.tsx | 7 +- .../src/components/signup/EnterEmailStep.tsx | 7 +- .../src/components/signup/UserInfoStep.tsx | 4 +- .../utilities/attemptChangePassword.ts | 9 +- .../components/utilities/attemptCliLogin.ts | 3 +- .../utilities/attemptCliLoginMfa.ts | 6 +- .../src/components/utilities/attemptLogin.ts | 6 +- .../components/utilities/attemptLoginMfa.ts | 5 +- .../utilities/cryptography/changePassword.ts | 147 ------------ .../utilities/cryptography/issueBackupKey.ts | 34 +-- frontend/src/hooks/api/auth/index.tsx | 8 +- frontend/src/hooks/api/auth/queries.tsx | 219 +++++++++++++++++- frontend/src/hooks/api/auth/types.ts | 103 ++++++++ frontend/src/hooks/api/users/queries.tsx | 4 +- .../src/pages/api/auth/ChangePassword2.ts | 46 ---- frontend/src/pages/api/auth/CheckAuth.ts | 5 +- .../api/auth/CheckEmailVerificationCode.ts | 24 -- .../auth/CompleteAccountInformationSignup.ts | 79 ------- .../CompleteAccountInformationSignupInvite.ts | 70 ------ .../api/auth/EmailVerifyOnPasswordReset.ts | 34 --- .../pages/api/auth/IssueBackupPrivateKey.ts | 51 ---- frontend/src/pages/api/auth/Login1.ts | 33 --- frontend/src/pages/api/auth/Login2.ts | 42 ---- frontend/src/pages/api/auth/Logout.ts | 41 ---- frontend/src/pages/api/auth/SRP1.ts | 29 --- .../api/auth/SendEmailOnPasswordReset.ts | 33 --- .../pages/api/auth/SendVerificationEmail.ts | 17 -- frontend/src/pages/api/auth/Token.ts | 16 -- .../src/pages/api/auth/VerifySignupInvite.ts | 27 --- .../api/auth/getBackupEncryptedPrivateKey.ts | 24 -- .../src/pages/api/auth/publicKeyInfisical.ts | 8 - .../auth/resetPasswordOnAccountRecovery.ts | 57 ----- frontend/src/pages/api/auth/verifyMfaToken.ts | 25 -- frontend/src/pages/password-reset.tsx | 39 ++-- frontend/src/pages/signup/index.tsx | 26 ++- frontend/src/pages/signupinvite.tsx | 50 ++-- frontend/src/pages/verify-email.tsx | 7 +- .../UserInfoSSOStep/UserInfoSSOStep.tsx | 4 +- 40 files changed, 443 insertions(+), 910 deletions(-) delete mode 100644 frontend/src/components/utilities/cryptography/changePassword.ts delete mode 100644 frontend/src/pages/api/auth/ChangePassword2.ts delete mode 100644 frontend/src/pages/api/auth/CheckEmailVerificationCode.ts delete mode 100644 frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts delete mode 100644 frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts delete mode 100644 frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts delete mode 100644 frontend/src/pages/api/auth/IssueBackupPrivateKey.ts delete mode 100644 frontend/src/pages/api/auth/Login1.ts delete mode 100644 frontend/src/pages/api/auth/Login2.ts delete mode 100644 frontend/src/pages/api/auth/Logout.ts delete mode 100644 frontend/src/pages/api/auth/SRP1.ts delete mode 100644 frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts delete mode 100644 frontend/src/pages/api/auth/SendVerificationEmail.ts delete mode 100644 frontend/src/pages/api/auth/Token.ts delete mode 100644 frontend/src/pages/api/auth/VerifySignupInvite.ts delete mode 100644 frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts delete mode 100644 frontend/src/pages/api/auth/publicKeyInfisical.ts delete mode 100644 frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts delete mode 100644 frontend/src/pages/api/auth/verifyMfaToken.ts diff --git a/backend/src/routes/v1/key.ts b/backend/src/routes/v1/key.ts index 2274b3c3f..a72b508b9 100644 --- a/backend/src/routes/v1/key.ts +++ b/backend/src/routes/v1/key.ts @@ -26,7 +26,7 @@ router.post( keyController.uploadKey ); -router.get( +router.get( // TODO endpoint: deprecate (note: move frontend to v2/workspace/key or something) "/:workspaceId/latest", requireAuth({ acceptedAuthModes: [AuthMode.JWT], diff --git a/backend/src/routes/v1/membership.ts b/backend/src/routes/v1/membership.ts index ff4107022..cf38c7cbc 100644 --- a/backend/src/routes/v1/membership.ts +++ b/backend/src/routes/v1/membership.ts @@ -9,7 +9,7 @@ import { AuthMode } from "../../variables"; // note: ALL DEPRECIATED (moved to api/v2/workspace/:workspaceId/memberships/:membershipId) // TODO endpoint: consider moving these endpoints to be under /workspace to be more RESTful -router.get( // used for old CLI (deprecate) +router.get( // TODO endpoint: deprecate - used for old CLI (deprecate) "/:workspaceId/connect", requireAuth({ acceptedAuthModes: [AuthMode.JWT], diff --git a/frontend/src/components/signup/CodeInputStep.tsx b/frontend/src/components/signup/CodeInputStep.tsx index 7f6c75871..de831bbd2 100644 --- a/frontend/src/components/signup/CodeInputStep.tsx +++ b/frontend/src/components/signup/CodeInputStep.tsx @@ -3,7 +3,9 @@ import React, { useState } from "react"; import ReactCodeInput from "react-code-input"; import { useTranslation } from "react-i18next"; -import sendVerificationEmail from "@app/pages/api/auth/SendVerificationEmail"; +import { + useSendVerificationEmail +} from "@app/hooks/api"; import Error from "../basic/Error"; import { Button } from "../v2"; @@ -70,6 +72,7 @@ export default function CodeInputStep({ codeError, isCodeInputCheckLoading }: CodeInputStepProps): JSX.Element { + const { mutateAsync } = useSendVerificationEmail(); const [isLoading, setIsLoading] = useState(false); const [isResendingVerificationEmail, setIsResendingVerificationEmail] = useState(false); const { t } = useTranslation(); @@ -77,7 +80,7 @@ export default function CodeInputStep({ const resendVerificationEmail = async () => { setIsResendingVerificationEmail(true); setIsLoading(true); - sendVerificationEmail(email); + await mutateAsync({ email }); setTimeout(() => { setIsLoading(false); setIsResendingVerificationEmail(false); diff --git a/frontend/src/components/signup/EnterEmailStep.tsx b/frontend/src/components/signup/EnterEmailStep.tsx index 479c88318..e317a4ea5 100644 --- a/frontend/src/components/signup/EnterEmailStep.tsx +++ b/frontend/src/components/signup/EnterEmailStep.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import Link from "next/link"; -import sendVerificationEmail from "@app/pages/api/auth/SendVerificationEmail"; +import { useSendVerificationEmail } from "@app/hooks/api"; import { Button, Input } from "../v2"; @@ -25,13 +25,14 @@ export default function EnterEmailStep({ setEmail, incrementStep }: DownloadBackupPDFStepProps): JSX.Element { + const { mutateAsync } = useSendVerificationEmail(); const [emailError, setEmailError] = useState(false); const { t } = useTranslation(); /** * Verifies if the entered email "looks" correct */ - const emailCheck = () => { + const emailCheck = async () => { let emailCheckBool = false; if (!email) { setEmailError(true); @@ -45,7 +46,7 @@ export default function EnterEmailStep({ // If everything is correct, go to the next step if (!emailCheckBool) { - sendVerificationEmail(email); + await mutateAsync({ email }); incrementStep(); } }; diff --git a/frontend/src/components/signup/UserInfoStep.tsx b/frontend/src/components/signup/UserInfoStep.tsx index b0a0d420f..db4d040ad 100644 --- a/frontend/src/components/signup/UserInfoStep.tsx +++ b/frontend/src/components/signup/UserInfoStep.tsx @@ -9,8 +9,8 @@ import nacl from "tweetnacl"; import { encodeBase64 } from "tweetnacl-util"; import { useGetCommonPasswords } from "@app/hooks/api"; +import { completeAccountSignup } from "@app/hooks/api/auth/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries"; -import completeAccountInformationSignup from "@app/pages/api/auth/CompleteAccountInformationSignup"; import ProjectService from "@app/services/ProjectService"; import InputField from "../basic/InputField"; @@ -159,7 +159,7 @@ export default function UserInfoStep({ secret: Buffer.from(derivedKey.hash) }); - const response = await completeAccountInformationSignup({ + const response = await completeAccountSignup({ email, firstName: name.split(" ")[0], lastName: name.split(" ").slice(1).join(" "), diff --git a/frontend/src/components/utilities/attemptChangePassword.ts b/frontend/src/components/utilities/attemptChangePassword.ts index 5b42e0190..59363129f 100644 --- a/frontend/src/components/utilities/attemptChangePassword.ts +++ b/frontend/src/components/utilities/attemptChangePassword.ts @@ -3,8 +3,9 @@ import crypto from "crypto"; import jsrp from "jsrp"; -import changePassword2 from "@app/pages/api/auth/ChangePassword2"; -import SRP1 from "@app/pages/api/auth/SRP1"; +import { +changePassword, + srp1} from "@app/hooks/api/auth/queries"; import Aes256Gcm from "./cryptography/aes-256-gcm"; import { deriveArgonKey } from "./cryptography/crypto"; @@ -27,7 +28,7 @@ const attemptChangePassword = ({ email, currentPassword, newPassword }: Params): try { const clientPublicKey = clientOldPassword.getPublicKey(); - const res = await SRP1({ clientPublicKey }); + const res = await srp1({ clientPublicKey }); serverPublicKey = res.serverPublicKey; salt = res.salt; @@ -71,7 +72,7 @@ const attemptChangePassword = ({ email, currentPassword, newPassword }: Params): secret: Buffer.from(derivedKey.hash) }); - await changePassword2({ + await changePassword({ clientProof, protectedKey, protectedKeyIV, diff --git a/frontend/src/components/utilities/attemptCliLogin.ts b/frontend/src/components/utilities/attemptCliLogin.ts index 3b9ebc910..b2eeeceea 100644 --- a/frontend/src/components/utilities/attemptCliLogin.ts +++ b/frontend/src/components/utilities/attemptCliLogin.ts @@ -1,10 +1,9 @@ /* eslint-disable prefer-destructuring */ import jsrp from "jsrp"; +import { login1, login2 } from "@app/hooks/api/auth/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchMyOrganizationProjects } from "@app/hooks/api/users/queries"; -import login1 from "@app/pages/api/auth/Login1"; -import login2 from "@app/pages/api/auth/Login2"; import KeyService from "@app/services/KeyService"; import Telemetry from "./telemetry/Telemetry"; diff --git a/frontend/src/components/utilities/attemptCliLoginMfa.ts b/frontend/src/components/utilities/attemptCliLoginMfa.ts index 2fc6f17b9..6681e8464 100644 --- a/frontend/src/components/utilities/attemptCliLoginMfa.ts +++ b/frontend/src/components/utilities/attemptCliLoginMfa.ts @@ -1,10 +1,10 @@ /* eslint-disable prefer-destructuring */ import jsrp from "jsrp"; +import { login1 , verifyMfaToken } from "@app/hooks/api/auth/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchMyOrganizationProjects } from "@app/hooks/api/users/queries"; -import login1 from "@app/pages/api/auth/Login1"; -import verifyMfaToken from "@app/pages/api/auth/verifyMfaToken"; +// import verifyMfaToken from "@app/pages/api/auth/verifyMfaToken"; import KeyService from "@app/services/KeyService"; import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage"; @@ -65,7 +65,7 @@ const attemptLoginMfa = async ({ tag } = await verifyMfaToken({ email, - mfaToken + mfaCode: mfaToken }); // unset temporary (MFA) JWT token and set JWT token diff --git a/frontend/src/components/utilities/attemptLogin.ts b/frontend/src/components/utilities/attemptLogin.ts index 29c730e3f..c4fe91b05 100644 --- a/frontend/src/components/utilities/attemptLogin.ts +++ b/frontend/src/components/utilities/attemptLogin.ts @@ -1,10 +1,9 @@ /* eslint-disable prefer-destructuring */ import jsrp from "jsrp"; +import { login1, login2 } from "@app/hooks/api/auth/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchMyOrganizationProjects } from "@app/hooks/api/users/queries"; -import login1 from "@app/pages/api/auth/Login1"; -import login2 from "@app/pages/api/auth/Login2"; import KeyService from "@app/services/KeyService"; import Telemetry from "./telemetry/Telemetry"; @@ -46,12 +45,13 @@ const attemptLogin = async ( async () => { try { const clientPublicKey = client.getPublicKey(); + const { serverPublicKey, salt } = await login1({ email, clientPublicKey, providerAuthToken, }); - + client.setSalt(salt); client.setServerPublicKey(serverPublicKey); const clientProof = client.getProof(); // called M1 diff --git a/frontend/src/components/utilities/attemptLoginMfa.ts b/frontend/src/components/utilities/attemptLoginMfa.ts index feb58b596..c588eb965 100644 --- a/frontend/src/components/utilities/attemptLoginMfa.ts +++ b/frontend/src/components/utilities/attemptLoginMfa.ts @@ -1,10 +1,9 @@ /* eslint-disable prefer-destructuring */ import jsrp from "jsrp"; +import { login1 , verifyMfaToken } from "@app/hooks/api/auth/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchMyOrganizationProjects } from "@app/hooks/api/users/queries"; -import login1 from "@app/pages/api/auth/Login1"; -import verifyMfaToken from "@app/pages/api/auth/verifyMfaToken"; import KeyService from "@app/services/KeyService"; import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage"; @@ -56,7 +55,7 @@ const attemptLoginMfa = async ({ tag } = await verifyMfaToken({ email, - mfaToken + mfaCode: mfaToken }); // unset temporary (MFA) JWT token and set JWT token diff --git a/frontend/src/components/utilities/cryptography/changePassword.ts b/frontend/src/components/utilities/cryptography/changePassword.ts deleted file mode 100644 index 3e7ad22e0..000000000 --- a/frontend/src/components/utilities/cryptography/changePassword.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* eslint-disable new-cap */ -import crypto from "crypto"; - -import jsrp from "jsrp"; - -import changePassword2 from "@app/pages/api/auth/ChangePassword2"; -import SRP1 from "@app/pages/api/auth/SRP1"; - -import { saveTokenToLocalStorage } from "../saveTokenToLocalStorage"; -import Aes256Gcm from "./aes-256-gcm"; -import { deriveArgonKey } from "./crypto"; - -const clientOldPassword = new jsrp.client(); -const clientNewPassword = new jsrp.client(); - -/** - * This function loggs in the user (whether it's right after signup, or a normal login) - * @param {*} email - * @param {*} password - * @param {*} setErrorLogin - * @param {*} router - * @param {*} isSignUp - * @returns - */ -const changePassword = async ( - email: string, - currentPassword: string, - newPassword: string, - setCurrentPasswordError: (arg: boolean) => void, - setPasswordChanged: (arg: boolean) => void, - setCurrentPassword: (arg: string) => void, - setNewPassword: (arg: string) => void -) => { - try { - setPasswordChanged(false); - setCurrentPasswordError(false); - - clientOldPassword.init( - { - username: email, - password: currentPassword - }, - async () => { - const clientPublicKey = clientOldPassword.getPublicKey(); - - let serverPublicKey; - let salt; - try { - const res = await SRP1({ - clientPublicKey - }); - serverPublicKey = res.serverPublicKey; - salt = res.salt; - } catch (err) { - setCurrentPasswordError(true); - console.log("Wrong current password", err, 1); - } - - clientOldPassword.setSalt(salt); - clientOldPassword.setServerPublicKey(serverPublicKey); - const clientProof = clientOldPassword.getProof(); // called M1 - - clientNewPassword.init( - { - username: email, - password: newPassword - }, - async () => { - clientNewPassword.createVerifier(async (err, result) => { - - const derivedKey = await deriveArgonKey({ - password: newPassword, - salt: result.salt, - mem: 65536, - time: 3, - parallelism: 1, - hashLen: 32 - }); - - if (!derivedKey) throw new Error("Failed to derive key from password"); - - const key = crypto.randomBytes(32); - - // create encrypted private key by encrypting the private - // key with the symmetric key [key] - const { - ciphertext: encryptedPrivateKey, - iv: encryptedPrivateKeyIV, - tag: encryptedPrivateKeyTag - } = Aes256Gcm.encrypt({ - text: localStorage.getItem("PRIVATE_KEY") as string, - secret: key - }); - - // create the protected key by encrypting the symmetric key - // [key] with the derived key - const { - ciphertext: protectedKey, - iv: protectedKeyIV, - tag: protectedKeyTag - } = Aes256Gcm.encrypt({ - text: key.toString("hex"), - secret: Buffer.from(derivedKey.hash) - }); - - try { - await changePassword2({ - clientProof, - protectedKey, - protectedKeyIV, - protectedKeyTag, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt: result.salt, - verifier: result.verifier - }); - - saveTokenToLocalStorage({ - encryptedPrivateKey, - iv: encryptedPrivateKeyIV, - tag: encryptedPrivateKeyTag - }); - - setPasswordChanged(true); - setCurrentPassword(""); - setNewPassword(""); - - window.location.href = "/login"; - - // move to login page - } catch (error) { - setCurrentPasswordError(true); - console.log(error); - } - }); - } - ); - } - ); - } catch (error) { - console.log("Something went wrong during changing the password"); - } - return true; -}; - -export default changePassword; diff --git a/frontend/src/components/utilities/cryptography/issueBackupKey.ts b/frontend/src/components/utilities/cryptography/issueBackupKey.ts index 9f503e0c9..4391d027f 100644 --- a/frontend/src/components/utilities/cryptography/issueBackupKey.ts +++ b/frontend/src/components/utilities/cryptography/issueBackupKey.ts @@ -3,8 +3,9 @@ import crypto from "crypto"; import jsrp from "jsrp"; -import issueBackupPrivateKey from "@app/pages/api/auth/IssueBackupPrivateKey"; -import SRP1 from "@app/pages/api/auth/SRP1"; +import { issueBackupPrivateKey , + srp1 +} from "@app/hooks/api/auth/queries"; import generateBackupPDF from "../generateBackupPDF"; import Aes256Gcm from "./aes-256-gcm"; @@ -51,7 +52,7 @@ const issueBackupKey = async ({ let serverPublicKey; let salt; try { - const res = await SRP1({ + const res = await srp1({ clientPublicKey }); serverPublicKey = res.serverPublicKey; @@ -61,8 +62,8 @@ const issueBackupKey = async ({ console.log("Wrong current password", err, 1); } - clientPassword.setSalt(salt); - clientPassword.setServerPublicKey(serverPublicKey); + clientPassword.setSalt(salt as string); + clientPassword.setServerPublicKey(serverPublicKey as string); const clientProof = clientPassword.getProof(); // called M1 const generatedKey = crypto.randomBytes(16).toString("hex"); @@ -80,24 +81,25 @@ const issueBackupKey = async ({ secret: generatedKey }); - const res = await issueBackupPrivateKey({ - encryptedPrivateKey: ciphertext, - iv, - tag, - salt: result.salt, - verifier: result.verifier, - clientProof - }); + try { + await issueBackupPrivateKey({ + encryptedPrivateKey: ciphertext, + iv, + tag, + salt: result.salt, + verifier: result.verifier, + clientProof + }); - if (res?.status === 400) { - setBackupKeyError(true); - } else if (res?.status === 200) { generateBackupPDF({ personalName, personalEmail: email, generatedKey }); setBackupKeyIssued(true); + + } catch { + setBackupKeyError(true); } } ); diff --git a/frontend/src/hooks/api/auth/index.tsx b/frontend/src/hooks/api/auth/index.tsx index a4f967888..dbcc77a5a 100644 --- a/frontend/src/hooks/api/auth/index.tsx +++ b/frontend/src/hooks/api/auth/index.tsx @@ -1,6 +1,10 @@ export { useGetAuthToken, useGetCommonPasswords, + useResetPassword, useSendMfaToken, - useVerifyMfaToken -} from "./queries" + useSendPasswordResetEmail, + useSendVerificationEmail, + useVerifyEmailVerificationCode, + useVerifyMfaToken, + useVerifyPasswordResetCode} from "./queries" diff --git a/frontend/src/hooks/api/auth/queries.tsx b/frontend/src/hooks/api/auth/queries.tsx index 57878d2b3..094fd4b61 100644 --- a/frontend/src/hooks/api/auth/queries.tsx +++ b/frontend/src/hooks/api/auth/queries.tsx @@ -4,16 +4,86 @@ import { apiRequest } from "@app/config/request"; import { setAuthToken } from "@app/reactQuery"; import { + ChangePasswordDTO, + CompleteAccountDTO, + CompleteAccountSignupDTO, GetAuthTokenAPI, + GetBackupEncryptedPrivateKeyDTO, + IssueBackupPrivateKeyDTO, + Login1DTO, + Login1Res, + Login2DTO, + Login2Res, + ResetPasswordDTO, SendMfaTokenDTO, + SRP1DTO, + SRPR1Res, VerifyMfaTokenDTO, - VerifyMfaTokenRes} from "./types"; + VerifyMfaTokenRes, + VerifySignupInviteDTO} from "./types"; const authKeys = { getAuthToken: ["token"] as const, commonPasswords: ["common-passwords"] as const }; +export const login1 = async (loginDetails: Login1DTO) => { + const { data } = await apiRequest.post("/api/v3/auth/login1", loginDetails); + return data; +} + +export const login2 = async (loginDetails: Login2DTO) => { + const { data } = await apiRequest.post("/api/v3/auth/login2", loginDetails); + return data; +} + +export const useLogin1 = () => { + return useMutation({ + mutationFn: async (details: { + email: string; + clientPublicKey: string; + providerAuthToken?: string; + }) => { + return login1(details); + } + }); +} + +export const useLogin2 = () => { + return useMutation({ + mutationFn: async (details: { + email: string; + clientProof: string; + providerAuthToken?: string; + }) => { + return login2(details); + } + }); +} + +export const srp1 = async (details: SRP1DTO) => { + const { data } = await apiRequest.post("/api/v1/password/srp1", details); + return data; +} + +export const completeAccountSignup = async (details: CompleteAccountSignupDTO) => { + const { data } = await apiRequest.post("/api/v3/signup/complete-account/signup", details); + return data; +} + +export const completeAccountSignupInvite = async (details: CompleteAccountDTO) => { + const { data } = await apiRequest.post("/api/v2/signup/complete-account/invite", details); + return data; +} + +export const useCompleteAccountSignup = () => { + return useMutation({ + mutationFn: async (details: CompleteAccountSignupDTO) => { + return completeAccountSignup(details); + } + }); +} + export const useSendMfaToken = () => { return useMutation<{}, {}, SendMfaTokenDTO>({ mutationFn: async ({ email }) => { @@ -23,18 +93,161 @@ export const useSendMfaToken = () => { }); } +export const verifyMfaToken = async ({ + email, + mfaCode +}: { + email: string; + mfaCode: string; +}) => { + const { data } = await apiRequest.post("/api/v2/auth/mfa/verify", { + email, + mfaToken: mfaCode + }); + + return data; +} + export const useVerifyMfaToken = () => { return useMutation({ mutationFn: async ({ email, mfaCode }) => { - const { data } = await apiRequest.post("/api/v2/auth/mfa/verify", { + return verifyMfaToken({ email, - mfaToken: mfaCode + mfaCode }); + } + }); +} + +export const verifySignupInvite = async (details: VerifySignupInviteDTO) => { + const { data } = await apiRequest.post("/api/v1/invite-org/verify", details); + return data; +} + +export const useSendVerificationEmail = () => { + return useMutation({ + mutationFn: async ({ + email + }: { + email: string; + }) => { + const { data } = await apiRequest.post("/api/v1/signup/email/signup", { + email + }); + return data; } }); } +export const useVerifyEmailVerificationCode = () => { + return useMutation({ + mutationFn: async ({ + email, + code + }: { + email: string; + code: string; + }) => { + const { data } = await apiRequest.post("/api/v1/signup/email/verify", { + email, + code + }); + + return data; + } + }); +} + +export const useSendPasswordResetEmail = () => { + return useMutation({ + mutationFn: async ({ + email + }: { + email: string; + }) => { + const { data } = await apiRequest.post("/api/v1/password/email/password-reset", { + email + }); + + return data; + } + }); +} + +export const useVerifyPasswordResetCode = () => { + return useMutation({ + mutationFn: async ({ + email, + code + }: { + email: string; + code: string; + }) => { + const { data } = await apiRequest.post("/api/v1/password/email/password-reset-verify", { + email, + code + }); + + return data; + } + }); +} + +export const issueBackupPrivateKey = async (details: IssueBackupPrivateKeyDTO) => { + const { data } = await apiRequest.post("/api/v1/password/backup-private-key", details); + return data; +} + +export const getBackupEncryptedPrivateKey = async ({ + verificationToken +}: GetBackupEncryptedPrivateKeyDTO) => { + const { data } = await apiRequest.get("/api/v1/password/backup-private-key", { + headers: { + Authorization: `Bearer ${verificationToken}` + } + }); + + return data.backupPrivateKey; +} + +export const useResetPassword = () => { + return useMutation({ + mutationFn: async (details: ResetPasswordDTO) => { + const { data } = await apiRequest.post("/api/v1/password/password-reset", { + protectedKey: details.protectedKey, + protectedKeyIV: details.protectedKeyIV, + protectedKeyTag: details.protectedKeyTag, + encryptedPrivateKey: details.encryptedPrivateKey, + encryptedPrivateKeyIV: details.encryptedPrivateKeyIV, + encryptedPrivateKeyTag: details.encryptedPrivateKeyTag, + salt: details.salt, + verifier: details.verifier + }, { + headers: { + Authorization: `Bearer ${details.verificationToken}` + } + }); + + return data; + } + }); +} + +export const changePassword = async (details: ChangePasswordDTO) => { + const { data } = await apiRequest.post("/api/v1/password/change-password", details); + return data; +} + +export const useChangePassword = () => { + // note: use after srp1 + return useMutation({ + mutationFn: async (details: ChangePasswordDTO) => { + return changePassword(details); + } + }); +} + // Refresh token is set as cookie when logged in // Using that we fetch the auth bearer token needed for auth calls const fetchAuthToken = async () => { diff --git a/frontend/src/hooks/api/auth/types.ts b/frontend/src/hooks/api/auth/types.ts index 3d14c19ff..7ed7af566 100644 --- a/frontend/src/hooks/api/auth/types.ts +++ b/frontend/src/hooks/api/auth/types.ts @@ -21,4 +21,107 @@ export type VerifyMfaTokenRes = { encryptedPrivateKey: string; iv: string; tag: string; +} + +export type Login1DTO = { + email: string; + clientPublicKey: string; + providerAuthToken?: string; +} + +export type Login2DTO = { + email: string; + clientProof: string; + providerAuthToken?: string; +} + +export type Login1Res = { + serverPublicKey: string; + salt: string; +} + +export type Login2Res = { + mfaEnabled: boolean; + token: string; + encryptionVersion?: number; + protectedKey?: string; + protectedKeyIV?: string; + protectedKeyTag?: string; + publicKey?: string; + encryptedPrivateKey?: string; + iv?: string; + tag?: string; +} + +export type SRP1DTO = { + clientPublicKey: string; +} + +export type SRPR1Res = { + serverPublicKey: string; + salt: string; +} + +export type CompleteAccountDTO = { + email: string; + firstName: string; + lastName: string; + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + publicKey: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; +} + +export type CompleteAccountSignupDTO = CompleteAccountDTO & { + providerAuthToken?: string; + attributionSource?: string; + organizationName: string; +} + +export type VerifySignupInviteDTO = { + email: string; + code: string; + organizationId: string; +} + +export type ChangePasswordDTO = { + clientProof: string; + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; +} + +export type ResetPasswordDTO = { + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; + verificationToken: string; +} + +export type IssueBackupPrivateKeyDTO = { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} + +export type GetBackupEncryptedPrivateKeyDTO = { + verificationToken: string; } \ No newline at end of file diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index a2d9318e5..a0a8ddc2f 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -201,7 +201,9 @@ export const useRegisterUserAction = () => { export const useLogoutUser = () => useMutation({ - mutationFn: () => apiRequest.post("/api/v1/auth/logout"), + mutationFn: async () => { + await apiRequest.post("/api/v1/auth/logout"); + }, onSuccess: () => { setAuthToken(""); // Delete the cookie by not setting a value; Alternatively clear the local storage diff --git a/frontend/src/pages/api/auth/ChangePassword2.ts b/frontend/src/pages/api/auth/ChangePassword2.ts deleted file mode 100644 index 8381c13ad..000000000 --- a/frontend/src/pages/api/auth/ChangePassword2.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { apiRequest } from "@app/config/request"; - -interface Props { - clientProof: string; - protectedKey: string; - protectedKeyIV: string; - protectedKeyTag: string; - encryptedPrivateKey: string; - encryptedPrivateKeyIV: string; - encryptedPrivateKeyTag: string; - salt: string; - verifier: string; -} - -/** - * This is the second step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const changePassword2 = async ({ - clientProof, - protectedKey, - protectedKeyIV, - protectedKeyTag, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier -}: Props) => { - const { data } = await apiRequest.post("/api/v1/password/change-password", { - clientProof, - protectedKey, - protectedKeyIV, - protectedKeyTag, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier - }); - - return data; -} - -export default changePassword2; diff --git a/frontend/src/pages/api/auth/CheckAuth.ts b/frontend/src/pages/api/auth/CheckAuth.ts index 9b39c6933..f1b98f087 100644 --- a/frontend/src/pages/api/auth/CheckAuth.ts +++ b/frontend/src/pages/api/auth/CheckAuth.ts @@ -4,12 +4,13 @@ import SecurityClient from "@app/components/utilities/SecurityClient"; * This function is used to check if the user is authenticated. * To do that, we get their tokens from cookies, and verify if they are good. */ -const checkAuth = async () => - SecurityClient.fetchCall("/api/v1/auth/checkAuth", { +const checkAuth = async () => { + return SecurityClient.fetchCall("/api/v1/auth/checkAuth", { method: "POST", headers: { "Content-Type": "application/json" } }).then((res) => res); +} export default checkAuth; diff --git a/frontend/src/pages/api/auth/CheckEmailVerificationCode.ts b/frontend/src/pages/api/auth/CheckEmailVerificationCode.ts deleted file mode 100644 index 5cbd9dc2b..000000000 --- a/frontend/src/pages/api/auth/CheckEmailVerificationCode.ts +++ /dev/null @@ -1,24 +0,0 @@ -interface Props { - email: string; - code: string; -} - -/** - * This route check the verification code from the email that user just recieved - * @param {object} obj - * @param {string} obj.email - * @param {string} obj.code - * @returns - */ -const checkEmailVerificationCode = ({ email, code }: Props) => fetch("/api/v1/signup/email/verify", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - email, - code - }) - }); - -export default checkEmailVerificationCode; diff --git a/frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts b/frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts deleted file mode 100644 index 37ceb4e3a..000000000 --- a/frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts +++ /dev/null @@ -1,79 +0,0 @@ - -import { apiRequest } from "@app/config/request"; - -interface Props { - email: string; - firstName: string; - lastName: string; - protectedKey: string; - protectedKeyIV: string; - protectedKeyTag: string; - providerAuthToken?: string; - publicKey: string; - encryptedPrivateKey: string; - encryptedPrivateKeyIV: string; - encryptedPrivateKeyTag: string; - organizationName: string; - salt: string; - verifier: string; - attributionSource?: string; -} - -/** - * This function is called in the end of the signup process. - * It sends all the necessary nformation to the server. - * @param {object} obj - * @param {string} obj.email - email of the user completing signup - * @param {string} obj.firstName - first name of the user completing signup - * @param {string} obj.lastName - last name of the user completing sign up - * @param {string} obj.protectedKey - protected key in encryption version 2 - * @param {string} obj.protectedKeyIV - IV of protected key in encryption version 2 - * @param {string} obj.protectedKeyTag - tag of protected key in encryption version 2 - * @param {string} obj.organizationName - organization name for this user (usually, [FIRST_NAME]'s organization) - * @param {string} obj.publicKey - public key of the user completing signup - * @param {string} obj.ciphertext - * @param {string} obj.iv - * @param {string} obj.tag - * @param {string} obj.salt - * @param {string} obj.verifier - * @returns - */ -const completeAccountInformationSignup = async ({ - email, - firstName, - lastName, - protectedKey, - protectedKeyIV, - protectedKeyTag, - publicKey, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier, - organizationName, - providerAuthToken, - attributionSource -}: Props) => { - const { data } = await apiRequest.post("/api/v3/signup/complete-account/signup", { - email, - firstName, - lastName, - protectedKey, - protectedKeyIV, - protectedKeyTag, - publicKey, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier, - organizationName, - providerAuthToken, - ...(attributionSource ? { attributionSource } : {}) - }); - - return data; -} - -export default completeAccountInformationSignup; diff --git a/frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts b/frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts deleted file mode 100644 index e2264b3d6..000000000 --- a/frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { apiRequest } from "@app/config/request"; - -interface Props { - email: string; - firstName: string; - lastName: string; - protectedKey: string; - protectedKeyIV: string; - protectedKeyTag: string; - publicKey: string; - encryptedPrivateKey: string; - encryptedPrivateKeyIV: string; - encryptedPrivateKeyTag: string; - salt: string; - verifier: string; -} - -// missing token? -// TODO: add to SecurityClient - - -/** - * This function is called in the end of the signup process. - * It sends all the necessary nformation to the server. - * @param {object} obj - * @param {string} obj.email - email of the user completing signupinvite flow - * @param {string} obj.firstName - first name of the user completing signupinvite flow - * @param {string} obj.lastName - last name of the user completing signupinvite flow - * @param {string} obj.publicKey - public key of the user completing signupinvite flow - * @param {string} obj.ciphertext - * @param {string} obj.iv - * @param {string} obj.tag - * @param {string} obj.salt - * @param {string} obj.verifier - * @param {string} obj.token - token that confirms a user's identity - * @returns - */ -const completeAccountInformationSignupInvite = async ({ - email, - firstName, - lastName, - protectedKey, - protectedKeyIV, - protectedKeyTag, - publicKey, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier -}: Props) => { - const { data } = await apiRequest.post("/api/v2/signup/complete-account/invite", { - email, - firstName, - lastName, - protectedKey, - protectedKeyIV, - protectedKeyTag, - publicKey, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier - }); - - return data; -} - -export default completeAccountInformationSignupInvite; diff --git a/frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts b/frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts deleted file mode 100644 index 8e601c6a4..000000000 --- a/frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts +++ /dev/null @@ -1,34 +0,0 @@ -interface Props { - email: string; - code: string; -} - -/** - * This is the second part of the account recovery step (a user needs to verify their email). - * A user need to click on a button in a magic link page - * @param {object} obj - * @param {object} obj.email - email of a user that is trying to recover access to their account - * @param {object} obj.code - token that a use received via the magic link - * @returns - */ -const EmailVerifyOnPasswordReset = async ({ email, code }: Props) => { - const response = await fetch("/api/v1/password/email/password-reset-verify", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - email, - code - }) - }); - if (response?.status === 200) { - return response; - } - - throw new Error( - "Something went wrong during email verification on password reset." - ); -}; - -export default EmailVerifyOnPasswordReset; diff --git a/frontend/src/pages/api/auth/IssueBackupPrivateKey.ts b/frontend/src/pages/api/auth/IssueBackupPrivateKey.ts deleted file mode 100644 index e5fe18359..000000000 --- a/frontend/src/pages/api/auth/IssueBackupPrivateKey.ts +++ /dev/null @@ -1,51 +0,0 @@ -import SecurityClient from "@app/components/utilities/SecurityClient"; - -interface Props { - encryptedPrivateKey: string; - iv: string; - tag: string; - salt: string; - verifier: string; - clientProof: string; -} - -/** - * This is the route that issues a backup private key that will afterwards be added into a pdf - * @param {object} obj - * @param {string} obj.encryptedPrivateKey - * @param {string} obj.iv - * @param {string} obj.tag - * @param {string} obj.salt - * @param {string} obj.verifier - * @param {string} obj.clientProof - * @returns - */ -const issueBackupPrivateKey = ({ - encryptedPrivateKey, - iv, - tag, - salt, - verifier, - clientProof -}: Props) => - SecurityClient.fetchCall("/api/v1/password/backup-private-key", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - clientProof, - encryptedPrivateKey, - iv, - tag, - salt, - verifier - }) - }).then((res) => { - if (res?.status !== 200) { - console.log("Failed to issue the backup key"); - } - return res; - }); - -export default issueBackupPrivateKey; diff --git a/frontend/src/pages/api/auth/Login1.ts b/frontend/src/pages/api/auth/Login1.ts deleted file mode 100644 index 85377d34c..000000000 --- a/frontend/src/pages/api/auth/Login1.ts +++ /dev/null @@ -1,33 +0,0 @@ -interface Login1 { - serverPublicKey: string; - salt: string; -} - -/** - * This is the first step of the login process (pake) - * @param {*} email - * @param {*} clientPublicKey - * @returns - */ -const login1 = async (loginDetails: { - email: string; - clientPublicKey: string; - providerAuthToken?: string; -}) => { - const response = await fetch("/api/v3/auth/login1", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(loginDetails), - }); - // need precise error handling about the status code - if (response?.status === 200) { - const data = (await response.json()) as unknown as Login1; - return data; - } - - throw new Error("Wrong password"); -}; - -export default login1; diff --git a/frontend/src/pages/api/auth/Login2.ts b/frontend/src/pages/api/auth/Login2.ts deleted file mode 100644 index ea9df262b..000000000 --- a/frontend/src/pages/api/auth/Login2.ts +++ /dev/null @@ -1,42 +0,0 @@ -interface Login2Response { - mfaEnabled: boolean; - token: string; - encryptionVersion?: number; - protectedKey?: string; - protectedKeyIV?: string; - protectedKeyTag?: string; - publicKey?: string; - encryptedPrivateKey?: string; - iv?: string; - tag?: string; -} - -/** - * This is the second step of the login process - * @param {*} email - * @param {*} clientPublicKey - * @returns - */ -const login2 = async (loginDetails: { - email: string; - clientProof: string; - providerAuthToken?: string; -}) => { - const response = await fetch("/api/v3/auth/login2", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(loginDetails), - credentials: "include" - }); - // need precise error handling about the status code - if (response.status === 200) { - const data = (await response.json()) as unknown as Login2Response; - return data; - } - - throw new Error("Password verification failed"); -}; - -export default login2; diff --git a/frontend/src/pages/api/auth/Logout.ts b/frontend/src/pages/api/auth/Logout.ts deleted file mode 100644 index 343e093ed..000000000 --- a/frontend/src/pages/api/auth/Logout.ts +++ /dev/null @@ -1,41 +0,0 @@ -import SecurityClient from "@app/components/utilities/SecurityClient"; - -/** - * This route logs the user out. Note: the user should authorized to do this. - * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry - */ -const logout = async () => { - try { - const res = await SecurityClient.fetchCall("/api/v1/auth/logout", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - credentials: "include" - }); - - if (res?.status === 200) { - SecurityClient.setToken(""); - // Delete the cookie by not setting a value; Alternatively clear the local storage - localStorage.removeItem("protectedKey"); - localStorage.removeItem("protectedKeyIV"); - localStorage.removeItem("protectedKeyTag"); - localStorage.removeItem("publicKey"); - localStorage.removeItem("encryptedPrivateKey"); - localStorage.removeItem("iv"); - localStorage.removeItem("tag"); - localStorage.removeItem("PRIVATE_KEY"); - localStorage.removeItem("orgData.id"); - localStorage.removeItem("projectData.id"); - - return res; - } - - } catch (error) { - console.log("Error logging out", error); - } - - return undefined; -}; - -export default logout; diff --git a/frontend/src/pages/api/auth/SRP1.ts b/frontend/src/pages/api/auth/SRP1.ts deleted file mode 100644 index 142df3d7c..000000000 --- a/frontend/src/pages/api/auth/SRP1.ts +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from "@app/components/utilities/SecurityClient"; - -interface Props { - clientPublicKey: string; -} - -/** - * This is the first step of the change password process (pake) - * @param {string} clientPublicKey - * @returns - */ -const SRP1 = ({ clientPublicKey }: Props) => - SecurityClient.fetchCall("/api/v1/password/srp1", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - clientPublicKey - }) - }).then(async (res) => { - if (res && res.status === 200) { - return res.json(); - } - console.log("Failed to do the first step of SRP"); - return undefined; - }); - -export default SRP1; diff --git a/frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts b/frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts deleted file mode 100644 index 37c6d14d2..000000000 --- a/frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts +++ /dev/null @@ -1,33 +0,0 @@ -interface Props { - email: string; -} - -/** - * This is the first of the account recovery step (a user needs to verify their email). - * It will send an email containing a magic link to start the account recovery flow. - * @param {object} obj - * @param {object} obj.email - email of a user that is trying to recover access to their account - * @returns - */ -const SendEmailOnPasswordReset = async ({ email }: Props) => { - const response = await fetch("/api/v1/password/email/password-reset", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - email - }) - }); - // need precise error handling about the status code - if (response?.status === 200) { - const data = await response.json(); - return data; - } - - throw new Error( - "Something went wrong while sending the email verification for password reset." - ); -}; - -export default SendEmailOnPasswordReset; diff --git a/frontend/src/pages/api/auth/SendVerificationEmail.ts b/frontend/src/pages/api/auth/SendVerificationEmail.ts deleted file mode 100644 index 92180cc04..000000000 --- a/frontend/src/pages/api/auth/SendVerificationEmail.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * This route send the verification email to the user's email (contains a 6-digit verification code) - * @param {*} email - */ -const sendVerificationEmail = (email: string) => { - fetch("/api/v1/signup/email/signup", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - email - }) - }); -}; - -export default sendVerificationEmail; diff --git a/frontend/src/pages/api/auth/Token.ts b/frontend/src/pages/api/auth/Token.ts deleted file mode 100644 index 6bd5b5097..000000000 --- a/frontend/src/pages/api/auth/Token.ts +++ /dev/null @@ -1,16 +0,0 @@ -const token = async () => - fetch("/api/v1/auth/token", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - credentials: "include" - }).then(async (res) => { - if (res.status === 200) { - return (await res.json()).token; - } - console.log("Getting a new token failed"); - return undefined; - }); - -export default token; diff --git a/frontend/src/pages/api/auth/VerifySignupInvite.ts b/frontend/src/pages/api/auth/VerifySignupInvite.ts deleted file mode 100644 index 89dbb4db8..000000000 --- a/frontend/src/pages/api/auth/VerifySignupInvite.ts +++ /dev/null @@ -1,27 +0,0 @@ -interface Props { - email: string; - code: string; - organizationId: string; -} - -/** - * This route verifies the signup invite link - * @param {object} obj - * @param {string} obj.email - email that a user is trying to verify - * @param {string} obj.organizationId - id of organization that a user is trying to verify for - * @param {string} obj.code - code that a user received to the abovementioned email - * @returns - */ -const verifySignupInvite = ({ email, organizationId, code }: Props) => fetch("/api/v1/invite-org/verify", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - email, - organizationId, - code - }) - }); - -export default verifySignupInvite; diff --git a/frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts b/frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts deleted file mode 100644 index f344b575e..000000000 --- a/frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This is the route that get an encrypted private key (will be decrypted with a backup key) - * @param {object} obj - * @param {object} obj.verificationToken - this is the token that confirms that a user is the right one - * @returns - */ -const getBackupEncryptedPrivateKey = ({ - verificationToken -}: { - verificationToken: string; -}) => fetch("/api/v1/password/backup-private-key", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${ verificationToken}` - } - }).then(async (res) => { - if (res?.status !== 200) { - console.log("Failed to get the backup key"); - } - return (await res?.json())?.backupPrivateKey; - }); - -export default getBackupEncryptedPrivateKey; diff --git a/frontend/src/pages/api/auth/publicKeyInfisical.ts b/frontend/src/pages/api/auth/publicKeyInfisical.ts deleted file mode 100644 index 60caa411a..000000000 --- a/frontend/src/pages/api/auth/publicKeyInfisical.ts +++ /dev/null @@ -1,8 +0,0 @@ -const publicKeyInfisical = () => fetch("/api/v1/key/publicKey/infisical", { - method: "GET", - headers: { - "Content-Type": "application/json" - } - }); - -export default publicKeyInfisical; diff --git a/frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts b/frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts deleted file mode 100644 index aa93b03ed..000000000 --- a/frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts +++ /dev/null @@ -1,57 +0,0 @@ -interface Props { - protectedKey: string; - protectedKeyIV: string; - protectedKeyTag: string; - encryptedPrivateKey: string; - encryptedPrivateKeyIV: string; - encryptedPrivateKeyTag: string; - salt: string; - verifier: string; - verificationToken: string; -} - -/** - * This is the route that resets the account password if all the previus steps were passed - * @param {object} obj - * @param {object} obj.verificationToken - this is the token that confirms that a user is the right one - * @param {object} obj.encryptedPrivateKey - the new encrypted private key (encrypted using the new password) - * @param {object} obj.iv - * @param {object} obj.tag - * @param {object} obj.salt - * @param {object} obj.verifier - * @returns - */ -const resetPasswordOnAccountRecovery = ({ - protectedKey, - protectedKeyIV, - protectedKeyTag, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier, - verificationToken, -}: Props) => fetch("/api/v1/password/password-reset", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${verificationToken}` - }, - body: JSON.stringify({ - protectedKey, - protectedKeyIV, - protectedKeyTag, - encryptedPrivateKey, - encryptedPrivateKeyIV, - encryptedPrivateKeyTag, - salt, - verifier - }) - }).then(async (res) => { - if (res?.status !== 200) { - console.log("Failed to get the backup key"); - } - return res; - }); - -export default resetPasswordOnAccountRecovery; diff --git a/frontend/src/pages/api/auth/verifyMfaToken.ts b/frontend/src/pages/api/auth/verifyMfaToken.ts deleted file mode 100644 index fc298d0fe..000000000 --- a/frontend/src/pages/api/auth/verifyMfaToken.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { apiRequest } from "@app/config/request"; - -/** - * Verify MFA token [mfaToken] for user with email [email] - * @param {object} obj - * @param {string} obj.email - email of user - * @param {string} obj.mfaToken - MFA cod/token to verify - * @returns - */ -const verifyMfaToken = async ({ - email, - mfaToken -}: { - email: string; - mfaToken: string; -}) => { - const { data } = await apiRequest.post("/api/v2/auth/mfa/verify", { - email, - mfaToken - }); - - return data; -} - -export default verifyMfaToken; diff --git a/frontend/src/pages/password-reset.tsx b/frontend/src/pages/password-reset.tsx index 30efc2c3b..b38f67c01 100644 --- a/frontend/src/pages/password-reset.tsx +++ b/frontend/src/pages/password-reset.tsx @@ -12,11 +12,10 @@ import Button from "@app/components/basic/buttons/Button"; import InputField from "@app/components/basic/InputField"; import passwordCheck from "@app/components/utilities/checks/PasswordCheck"; import Aes256Gcm from "@app/components/utilities/cryptography/aes-256-gcm"; +import { useResetPassword,useVerifyPasswordResetCode } from "@app/hooks/api"; +import { getBackupEncryptedPrivateKey } from "@app/hooks/api/auth/queries"; import { deriveArgonKey } from "../components/utilities/cryptography/crypto"; -import EmailVerifyOnPasswordReset from "./api/auth/EmailVerifyOnPasswordReset"; -import getBackupEncryptedPrivateKey from "./api/auth/getBackupEncryptedPrivateKey"; -import resetPasswordOnAccountRecovery from "./api/auth/resetPasswordOnAccountRecovery"; // eslint-disable-next-line new-cap const client = new jsrp.client(); @@ -34,6 +33,10 @@ export default function PasswordReset() { const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); const router = useRouter(); + + const { mutateAsync: verifyPasswordResetCodeMutateAsync } = useVerifyPasswordResetCode(); + const { mutateAsync: resetPasswordMutateAsync } = useResetPassword(); + const parsedUrl = queryString.parse(router.asPath.split("?")[1]); const token = parsedUrl.token as string; const email = (parsedUrl.to as string)?.replace(" ", "+").trim(); @@ -43,7 +46,7 @@ export default function PasswordReset() { e.preventDefault(); try { const result = await getBackupEncryptedPrivateKey({ verificationToken }); - + setPrivateKey( Aes256Gcm.decrypt({ ciphertext: result.encryptedPrivateKey, @@ -53,7 +56,8 @@ export default function PasswordReset() { }) ); setStep(3); - } catch { + } catch(err) { + console.error(err); setBackupKeyError(true); } }; @@ -112,7 +116,7 @@ export default function PasswordReset() { secret: Buffer.from(derivedKey.hash) }); - const response = await resetPasswordOnAccountRecovery({ + await resetPasswordMutateAsync({ protectedKey, protectedKeyIV, protectedKeyTag, @@ -123,11 +127,9 @@ export default function PasswordReset() { verifier: result.verifier, verificationToken }); + + router.push("/login"); - // if everything works, go the main dashboard page. - if (response?.status === 200) { - router.push("/login"); - } setLoading(false) }); } @@ -146,15 +148,16 @@ export default function PasswordReset() {