import { useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; import { faCheck, faX } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import Button from "~/components/basic/buttons/Button"; import InputField from "~/components/basic/InputField"; import passwordCheck from "~/components/utilities/checks/PasswordCheck"; import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm"; import { getTranslatedStaticProps } from "~/components/utilities/withTranslateProps"; import EmailVerifyOnPasswordReset from "./api/auth/EmailVerifyOnPasswordReset"; import getBackupEncryptedPrivateKey from "./api/auth/getBackupEncryptedPrivateKey"; import resetPasswordOnAccountRecovery from "./api/auth/resetPasswordOnAccountRecovery"; const queryString = require("query-string"); const nacl = require("tweetnacl"); const jsrp = require("jsrp"); nacl.util = require("tweetnacl-util"); const client = new jsrp.client(); export default function PasswordReset() { const router = useRouter(); const parsedUrl = queryString.parse(router.asPath.split("?")[1]); const token = parsedUrl.token; const email = parsedUrl.to?.replace(" ", "+").trim(); const [verificationToken, setVerificationToken] = useState(""); const [step, setStep] = useState(1); const [backupKey, setBackupKey] = useState(""); const [privateKey, setPrivateKey] = useState(""); const [newPassword, setNewPassword] = useState(""); const [backupKeyError, setBackupKeyError] = useState(false); const [passwordErrorLength, setPasswordErrorLength] = useState(false); const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); // Unencrypt the private key with a backup key const getEncryptedKeyHandler = async () => { try { const result = await getBackupEncryptedPrivateKey({ verificationToken }); setPrivateKey( Aes256Gcm.decrypt({ ciphertext: result.encryptedPrivateKey, iv: result.iv, tag: result.tag, secret: backupKey, }) ); setStep(3); } catch { setBackupKeyError(true); } }; // If everything is correct, reset the password const resetPasswordHandler = async () => { let errorCheck = false; errorCheck = passwordCheck({ password: newPassword, setPasswordErrorLength, setPasswordErrorNumber, setPasswordErrorLowerCase, currentErrorCheck: errorCheck, }); if (!errorCheck) { // Generate a random pair of a public and a private key const { ciphertext, iv, tag } = Aes256Gcm.encrypt({ text: privateKey, secret: newPassword .slice(0, 32) .padStart( 32 + (newPassword.slice(0, 32).length - new Blob([newPassword]).size), "0" ), }) as { ciphertext: string; iv: string; tag: string }; client.init( { username: email, password: newPassword, }, async () => { client.createVerifier( async (err: any, result: { salt: string; verifier: string }) => { const response = await resetPasswordOnAccountRecovery({ verificationToken, encryptedPrivateKey: ciphertext, iv, tag, salt: result.salt, verifier: result.verifier, }); // if everything works, go the main dashboard page. if (response?.status === 200) { router.push("/login"); } } ); } ); } }; // Click a button to confirm email const stepConfirmEmail = (

Confirm your email

verify email
); // Input backup key const stepInputBackupKey = (

Enter your backup key

You can find it in your emrgency kit. You had to download the enrgency kit during signup.

); // Enter new password const stepEnterNewPassword = (

Enter new password

Make sure you save it somewhere save.

{ setNewPassword(password); passwordCheck({ password, setPasswordErrorLength, setPasswordErrorNumber, setPasswordErrorLowerCase, currentErrorCheck: false, }); }} type="password" value={newPassword} isRequired error={ passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber } autoComplete="new-password" id="new-password" />
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
Password should contain at least:
{passwordErrorLength ? ( ) : ( )}
14 characters
{passwordErrorLowerCase ? ( ) : ( )}
1 lowercase character
{passwordErrorNumber ? ( ) : ( )}
1 number
) : (
)}
); return (
{step === 1 && stepConfirmEmail} {step === 2 && stepInputBackupKey} {step === 3 && stepEnterNewPassword}
); } export const getServerSideProps = getTranslatedStaticProps([]);