Refactoring functions into services, helper functions, hooks, patch bugs

This commit is contained in:
Tuan Dang
2023-02-14 17:38:58 +07:00
parent 13b1805d04
commit e1ad8fbee8
30 changed files with 383 additions and 360 deletions
@@ -1,4 +1,5 @@
import SecurityClient from '@app/components/utilities/SecurityClient';
import { apiRequest } from "@app/config/request";
interface Props {
email: string;
@@ -35,7 +36,7 @@ interface Props {
* @param {string} obj.verifier
* @returns
*/
const completeAccountInformationSignup = ({
const completeAccountInformationSignup = async ({
email,
firstName,
lastName,
@@ -49,32 +50,24 @@ const completeAccountInformationSignup = ({
salt,
verifier,
organizationName
}: Props) => SecurityClient.fetchCall('/api/v2/signup/complete-account/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
firstName,
lastName,
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
organizationName
})
}).then(async (res) => {
if (res && res?.status === 200) {
return res.json();
}
console.log('Failed to verify MFA code');
throw new Error('Something went wrong during MFA code verification');
}: Props) => {
const { data } = await apiRequest.post('/api/v2/signup/complete-account/signup', {
email,
firstName,
lastName,
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
organizationName
});
return data;
}
export default completeAccountInformationSignup;
@@ -1,3 +1,5 @@
import { apiRequest } from "@app/config/request";
interface Props {
email: string;
firstName: string;
@@ -11,9 +13,12 @@ interface Props {
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
token: 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.
@@ -30,7 +35,7 @@ interface Props {
* @param {string} obj.token - token that confirms a user's identity
* @returns
*/
const completeAccountInformationSignupInvite = ({
const completeAccountInformationSignupInvite = async ({
email,
firstName,
lastName,
@@ -42,28 +47,24 @@ const completeAccountInformationSignupInvite = ({
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
token
}: Props) => fetch('/api/v2/signup/complete-account/invite', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify({
email,
firstName,
lastName,
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
})
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;
+19 -12
View File
@@ -4,14 +4,16 @@ 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 () =>
SecurityClient.fetchCall('/api/v1/auth/logout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
}).then((res) => {
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
@@ -23,12 +25,17 @@ const logout = async () =>
localStorage.removeItem('iv');
localStorage.removeItem('tag');
localStorage.removeItem('PRIVATE_KEY');
localStorage.removeItem('orgData.id');
localStorage.removeItem('projectData.id');
console.log('User logged out', res);
return res;
}
console.log('Failed to log out');
return undefined;
});
} catch (error) {
console.log('Error logging out', error);
}
return undefined;
};
export default logout;
@@ -1,29 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* Send new MFA token to user with email [email]
* @param {object} obj
* @param {string} obj.email - email of user
* @returns
*/
const resendMfaToken = async ({
email,
}: {
email: string;
}) => SecurityClient.fetchCall('/api/v2/auth/mfa/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email
})
}).then(async (res) => {
if (res && res?.status === 200) {
return res.json();
}
console.log('Failed to send new MFA code');
throw new Error('Something went wrong while sending new MFA code');
});
export default resendMfaToken;
+9 -19
View File
@@ -1,4 +1,4 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
import { apiRequest } from "@app/config/request";
/**
* Verify MFA token [mfaToken] for user with email [email]
@@ -13,23 +13,13 @@ const verifyMfaToken = async ({
}: {
email: string;
mfaToken: string;
}) => SecurityClient.fetchCall('/api/v2/auth/mfa/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
mfaToken
})
}).then(async (res) => {
if (res && res?.status === 200) {
return res.json();
}
console.log('Failed to verify MFA code');
throw new Error('Something went wrong during MFA code verification');
});
}) => {
const { data } = await apiRequest.post('/api/v2/auth/mfa/verify', {
email,
mfaToken
});
return data;
}
export default verifyMfaToken;
+1 -7
View File
@@ -17,7 +17,6 @@ export default function Login() {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isAlreadyLoggedIn, setIsAlreadyLoggedIn] = useState(false);
const [step, setStep] = useState(1);
const { t } = useTranslation();
const lang = router.locale ?? 'en';
@@ -41,7 +40,6 @@ export default function Login() {
}
};
if (isLoggedIn()) {
setIsAlreadyLoggedIn(true);
redirectToDashboard();
}
}, []);
@@ -72,10 +70,6 @@ export default function Login() {
}
}
if (isAlreadyLoggedIn) {
return null
}
return (
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
<Head>
@@ -106,4 +100,4 @@ export default function Login() {
);
}
export const getStaticProps = getTranslatedStaticProps(['auth', 'login']);
export const getStaticProps = getTranslatedStaticProps(['auth', 'login', 'signup']);
+2 -1
View File
@@ -59,7 +59,8 @@ export default function SignUp() {
// Checking if the code matches the email.
const response = await checkEmailVerificationCode({ email, code });
if (response.status === 200) {
SecurityClient.setToken((await response.json()).token);
const {token} = await response.json();
SecurityClient.setSignupToken(token);
setStep(3);
} else {
setCodeError(true);
+28 -25
View File
@@ -21,6 +21,10 @@ 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';
@@ -29,7 +33,6 @@ import verifySignupInvite from './api/auth/VerifySignupInvite';
const client = new jsrp.client();
export default function SignupInvite() {
console.log('SignupInvite');
const [password, setPassword] = useState('');
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
@@ -82,13 +85,6 @@ export default function SignupInvite() {
const privateKey = encodeBase64(secretKeyUint8Array);
const publicKey = encodeBase64(publicKeyUint8Array);
// const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
// text: PRIVATE_KEY,
// secret: password
// .slice(0, 32)
// .padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), '0')
// });
localStorage.setItem('PRIVATE_KEY', privateKey);
client.init(
@@ -134,8 +130,9 @@ export default function SignupInvite() {
secret: Buffer.from(derivedKey.hash)
});
console.log('SignupInvite A');
let response = await completeAccountInformationSignupInvite({
const {
token: jwtToken
} = await completeAccountInformationSignupInvite({
email,
firstName,
lastName,
@@ -147,24 +144,30 @@ export default function SignupInvite() {
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt: result.salt,
verifier: result.verifier,
token: verificationToken
verifier: result.verifier
});
console.log('SignupInvite B');
// unset temporary signup JWT token and set JWT token
SecurityClient.setSignupToken('');
SecurityClient.setToken(jwtToken);
// if everything works, go the main dashboard page.
if (!errorCheck && response.status === 200) {
response = await response.json();
saveTokenToLocalStorage({
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
encryptedPrivateKey,
iv: encryptedPrivateKeyIV,
tag: encryptedPrivateKeyTag,
privateKey
});
console.log('SignupInvite C');
localStorage.setItem('publicKey', publicKey);
localStorage.setItem('encryptedPrivateKey', encryptedPrivateKey);
localStorage.setItem('iv', encryptedPrivateKeyIV);
localStorage.setItem('tag', encryptedPrivateKeyTag);
console.log('SignupInvite D');
const userOrgs = await getOrganizations();
setStep(3);
}
const orgId = userOrgs[0]._id;
localStorage.setItem('orgData.id', orgId);
setStep(3);
} catch (error) {
setIsLoading(false);
console.error(error);
@@ -197,7 +200,7 @@ export default function SignupInvite() {
// user will have temp token if doesn't have an account
// then continue with account setup workflow
if (res?.token) {
setVerificationToken(res.token);
SecurityClient.setSignupToken(res.token);
setStep(2);
} else {
// user will be redirected to dashboard