Merge pull request #339 from Infisical/mfa

MFA
This commit is contained in:
Maidul Islam
2023-02-19 18:33:11 -05:00
committed by GitHub
100 changed files with 3513 additions and 1734 deletions
+22 -6
View File
@@ -1,12 +1,15 @@
import SecurityClient from '@app/components/utilities/SecurityClient';
interface Props {
clientProof: string;
protectedKey: string;
protectedKeyIV: string;
protectedKeyTag: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
encryptedPrivateKeyIV: string;
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
clientProof: string;
}
/**
@@ -14,7 +17,17 @@ interface Props {
* @param {*} clientPublicKey
* @returns
*/
const changePassword2 = ({ encryptedPrivateKey, iv, tag, salt, verifier, clientProof }: Props) =>
const changePassword2 = ({
clientProof,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
}: Props) =>
SecurityClient.fetchCall('/api/v1/password/change-password', {
method: 'POST',
headers: {
@@ -22,9 +35,12 @@ const changePassword2 = ({ encryptedPrivateKey, iv, tag, salt, verifier, clientP
},
body: JSON.stringify({
clientProof,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
})
@@ -1,15 +1,20 @@
import { apiRequest } from "@app/config/request";
interface Props {
email: string;
firstName: string;
lastName: string;
protectedKey: string;
protectedKeyIV: string;
protectedKeyTag: string;
publicKey: string;
ciphertext: string;
encryptedPrivateKey: string;
encryptedPrivateKeyIV: string;
encryptedPrivateKeyTag: string;
organizationName: string;
iv: string;
tag: string;
salt: string;
verifier: string;
token: string;
}
/**
@@ -19,6 +24,9 @@ interface Props {
* @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
@@ -26,39 +34,40 @@ interface Props {
* @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 completeAccountInformationSignup = ({
const completeAccountInformationSignup = async ({
email,
firstName,
lastName,
organizationName,
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
ciphertext,
iv,
tag,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
token
}: Props) => fetch('/api/v1/signup/complete-account/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${ token}`
},
body: JSON.stringify({
email,
firstName,
lastName,
publicKey,
encryptedPrivateKey: ciphertext,
organizationName,
iv,
tag,
salt,
verifier
})
organizationName
}: 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,16 +1,24 @@
import { apiRequest } from "@app/config/request";
interface Props {
email: string;
firstName: string;
lastName: string;
protectedKey: string;
protectedKeyIV: string;
protectedKeyTag: string;
publicKey: string;
ciphertext: string;
iv: string;
tag: string;
encryptedPrivateKey: string;
encryptedPrivateKeyIV: string;
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.
@@ -27,34 +35,36 @@ interface Props {
* @param {string} obj.token - token that confirms a user's identity
* @returns
*/
const completeAccountInformationSignupInvite = ({
const completeAccountInformationSignupInvite = async ({
email,
firstName,
lastName,
protectedKey,
protectedKeyIV,
protectedKeyTag,
publicKey,
ciphertext,
iv,
tag,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
token
}: Props) => fetch('/api/v1/signup/complete-account/invite', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${ token}`
},
body: JSON.stringify({
email,
firstName,
lastName,
publicKey,
encryptedPrivateKey: ciphertext,
iv,
tag,
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;
+2 -2
View File
@@ -10,7 +10,7 @@ interface Login1 {
* @returns
*/
const login1 = async (email: string, clientPublicKey: string) => {
const response = await fetch("/api/v1/auth/login1", {
const response = await fetch("/api/v2/auth/login1", {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -25,7 +25,7 @@ const login1 = async (email: string, clientPublicKey: string) => {
const data = (await response.json()) as unknown as Login1;
return data;
}
throw new Error("Wrong password");
};
+10 -5
View File
@@ -1,9 +1,14 @@
interface Login2Response {
encryptedPrivateKey: string;
iv: string;
publicKey: string;
tag: string;
mfaEnabled: boolean;
token: string;
encryptionVersion?: number;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
publicKey?: string;
encryptedPrivateKey?: string;
iv?: string;
tag?: string;
}
/**
@@ -13,7 +18,7 @@ interface Login2Response {
* @returns
*/
const login2 = async (email: string, clientProof: string) => {
const response = await fetch('/api/v1/auth/login2', {
const response = await fetch('/api/v2/auth/login2', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
+28 -17
View File
@@ -4,27 +4,38 @@ 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
localStorage.setItem('publicKey', '');
localStorage.setItem('encryptedPrivateKey', '');
localStorage.setItem('iv', '');
localStorage.setItem('tag', '');
localStorage.setItem('PRIVATE_KEY', '');
console.log('User logged out', res);
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;
}
console.log('Failed to log out');
return undefined;
});
} catch (error) {
console.log('Error logging out', error);
}
return undefined;
};
export default logout;
@@ -1,10 +1,13 @@
interface Props {
verificationToken: string;
protectedKey: string;
protectedKeyIV: string;
protectedKeyTag: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
encryptedPrivateKeyIV: string;
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
verificationToken: string;
}
/**
@@ -19,22 +22,28 @@ interface Props {
* @returns
*/
const resetPasswordOnAccountRecovery = ({
verificationToken,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
verifier,
verificationToken,
}: Props) => fetch('/api/v1/password/password-reset', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${ verificationToken}`
Authorization: `Bearer ${verificationToken}`
},
body: JSON.stringify({
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
})
@@ -0,0 +1,25 @@
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;
@@ -0,0 +1,32 @@
import SecurityClient from '@app/components/utilities/SecurityClient';
interface Props {
isMfaEnabled: boolean;
}
/**
* Update the user's MFA-enabled status to [isMfaEnabled]
* @param {Object} obj
* @param {Boolean} obj.isMfaEnabled - whether or not MFA status should be set to enabled or not
* @returns {User} user - user with updated MFA-enabled status
*/
const updateMyMfaEnabled = async ({
isMfaEnabled
}: Props) =>
SecurityClient.fetchCall(`/api/v2/users/me/mfa`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
isMfaEnabled,
})
}).then(async (res) => {
if (res && res.status === 200) {
return (await res.json()).user;
}
console.log('Failed to update MFA status');
return undefined;
});
export default updateMyMfaEnabled;