/* eslint-disable no-nested-ternary */ /* eslint-disable @typescript-eslint/no-unused-vars */ import crypto from 'crypto'; import { useState } from 'react'; import Head from 'next/head'; import Image from 'next/image'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import jsrp from 'jsrp'; import queryString from 'query-string'; import nacl from 'tweetnacl'; import { encodeBase64 } from 'tweetnacl-util'; import Button from '@app/components/basic/buttons/Button'; import InputField from '@app/components/basic/InputField'; import attemptLogin from '@app/components/utilities/attemptLogin'; import passwordCheck from '@app/components/utilities/checks/PasswordCheck'; import Aes256Gcm from '@app/components/utilities/cryptography/aes-256-gcm'; import { deriveArgonKey } from '@app/components/utilities/cryptography/crypto'; import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey'; import { saveTokenToLocalStorage } from '@app/components/utilities/saveTokenToLocalStorage'; import SecurityClient from '@app/components/utilities/SecurityClient'; import getOrganizations from '@app/pages/api/organization/getOrgs'; import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects'; import completeAccountInformationSignupInvite from './api/auth/CompleteAccountInformationSignupInvite'; import verifySignupInvite from './api/auth/VerifySignupInvite'; // eslint-disable-next-line new-cap const client = new jsrp.client(); export default function SignupInvite() { const [password, setPassword] = useState(''); const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [firstNameError, setFirstNameError] = useState(false); const [lastNameError, setLastNameError] = useState(false); const [passwordErrorLength, setPasswordErrorLength] = useState(false); const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); const [errorLogin, setErrorLogin] = useState(false); const [isLoading, setIsLoading] = useState(false); const [step, setStep] = useState(1); const [backupKeyError, setBackupKeyError] = useState(false); const [verificationToken, setVerificationToken] = useState(''); const [backupKeyIssued, setBackupKeyIssued] = useState(false); const router = useRouter(); const parsedUrl = queryString.parse(router.asPath.split('?')[1]); const token = parsedUrl.token as string; const email = (parsedUrl.to as string)?.replace(' ', '+').trim(); // Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria. const signupErrorCheck = async () => { setIsLoading(true); let errorCheck = false; if (!firstName) { setFirstNameError(true); errorCheck = true; } else { setFirstNameError(false); } if (!lastName) { setLastNameError(true); errorCheck = true; } else { setLastNameError(false); } errorCheck = passwordCheck({ password, setPasswordErrorLength, setPasswordErrorNumber, setPasswordErrorLowerCase, errorCheck }); if (!errorCheck) { // Generate a random pair of a public and a private key const pair = nacl.box.keyPair(); const secretKeyUint8Array = pair.secretKey; const publicKeyUint8Array = pair.publicKey; const privateKey = encodeBase64(secretKeyUint8Array); const publicKey = encodeBase64(publicKeyUint8Array); localStorage.setItem('PRIVATE_KEY', privateKey); client.init( { username: email, password }, async () => { client.createVerifier(async (err, result) => { try { const derivedKey = await deriveArgonKey({ password, 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: privateKey, 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) }); const { token: jwtToken } = await completeAccountInformationSignupInvite({ email, firstName, lastName, protectedKey, protectedKeyIV, protectedKeyTag, publicKey, encryptedPrivateKey, encryptedPrivateKeyIV, encryptedPrivateKeyTag, salt: result.salt, verifier: result.verifier }); // unset temporary signup JWT token and set JWT token SecurityClient.setSignupToken(''); SecurityClient.setToken(jwtToken); saveTokenToLocalStorage({ publicKey, encryptedPrivateKey, iv: encryptedPrivateKeyIV, tag: encryptedPrivateKeyTag, privateKey }); const userOrgs = await getOrganizations(); const orgId = userOrgs[0]._id; localStorage.setItem('orgData.id', orgId); setStep(3); } catch (error) { setIsLoading(false); console.error(error); } }); } ); } else { setIsLoading(false); } }; // Step 4 of the sign up process (download the emergency kit pdf) const stepConfirmEmail = (
Confirm your email
Almost there!
Save your Emergency Kit