mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 08:29:55 +00:00
merge main and deconflict
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
import crypto from "crypto";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { useServerConfig } from "@app/context";
|
||||
import { initProjectHelper } from "@app/helpers/project";
|
||||
import { completeAccountSignup, useSelectOrganization } from "@app/hooks/api/auth/queries";
|
||||
import { fetchOrganizations } from "@app/hooks/api/organization/queries";
|
||||
@@ -14,15 +10,9 @@ import { onRequestError } from "@app/hooks/api/reactQuery";
|
||||
|
||||
import InputField from "../basic/InputField";
|
||||
import checkPassword from "../utilities/checks/password/checkPassword";
|
||||
import Aes256Gcm from "../utilities/cryptography/aes-256-gcm";
|
||||
import { deriveArgonKey, generateKeyPair } from "../utilities/cryptography/crypto";
|
||||
import { saveTokenToLocalStorage } from "../utilities/saveTokenToLocalStorage";
|
||||
import SecurityClient from "../utilities/SecurityClient";
|
||||
import { Button, Input } from "../v2";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
|
||||
interface UserInfoStepProps {
|
||||
incrementStep: () => void;
|
||||
email: string;
|
||||
@@ -76,7 +66,6 @@ export default function UserInfoStep({
|
||||
}: UserInfoStepProps): JSX.Element {
|
||||
const [nameError, setNameError] = useState(false);
|
||||
const [organizationNameError, setOrganizationNameError] = useState(false);
|
||||
const { config } = useServerConfig();
|
||||
|
||||
const [errors, setErrors] = useState<Errors>({});
|
||||
|
||||
@@ -108,109 +97,41 @@ export default function UserInfoStep({
|
||||
});
|
||||
|
||||
if (!errorCheck) {
|
||||
// Generate a random pair of a public and a private key
|
||||
const pair = await generateKeyPair(config.fipsEnabled);
|
||||
try {
|
||||
const response = await completeAccountSignup({
|
||||
email,
|
||||
password,
|
||||
firstName: name.split(" ")[0],
|
||||
lastName: name.split(" ").slice(1).join(" "),
|
||||
providerAuthToken,
|
||||
organizationName,
|
||||
attributionSource
|
||||
});
|
||||
|
||||
localStorage.setItem("PRIVATE_KEY", pair.privateKey);
|
||||
// unset signup JWT token and set JWT token
|
||||
SecurityClient.setSignupToken("");
|
||||
SecurityClient.setToken(response.token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
|
||||
client.init(
|
||||
{
|
||||
username: email,
|
||||
password
|
||||
},
|
||||
async () => {
|
||||
client.createVerifier(async (_err: any, result: { salt: string; verifier: string }) => {
|
||||
try {
|
||||
// TODO: moduralize into KeyService
|
||||
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: pair.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 response = await completeAccountSignup({
|
||||
email,
|
||||
password,
|
||||
firstName: name.split(" ")[0],
|
||||
lastName: name.split(" ").slice(1).join(" "),
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
publicKey: pair.publicKey,
|
||||
encryptedPrivateKey,
|
||||
encryptedPrivateKeyIV,
|
||||
encryptedPrivateKeyTag,
|
||||
providerAuthToken,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
organizationName,
|
||||
attributionSource
|
||||
});
|
||||
|
||||
// unset signup JWT token and set JWT token
|
||||
SecurityClient.setSignupToken("");
|
||||
SecurityClient.setToken(response.token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
|
||||
if (response.organizationId) {
|
||||
await selectOrganization({ organizationId: response.organizationId });
|
||||
}
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
publicKey: pair.publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv: encryptedPrivateKeyIV,
|
||||
tag: encryptedPrivateKeyTag,
|
||||
privateKey: pair.privateKey
|
||||
});
|
||||
|
||||
const userOrgs = await fetchOrganizations();
|
||||
|
||||
const orgId = userOrgs[0]?.id;
|
||||
await initProjectHelper({
|
||||
projectName: "Example Project"
|
||||
});
|
||||
|
||||
localStorage.setItem("orgData.id", orgId);
|
||||
|
||||
incrementStep();
|
||||
} catch (error) {
|
||||
onRequestError(error);
|
||||
setIsLoading(false);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
if (response.organizationId) {
|
||||
await selectOrganization({ organizationId: response.organizationId });
|
||||
}
|
||||
);
|
||||
|
||||
const userOrgs = await fetchOrganizations();
|
||||
|
||||
const orgId = userOrgs[0]?.id;
|
||||
await initProjectHelper({
|
||||
projectName: "Example Project"
|
||||
});
|
||||
|
||||
localStorage.setItem("orgData.id", orgId);
|
||||
|
||||
incrementStep();
|
||||
} catch (error) {
|
||||
onRequestError(error);
|
||||
setIsLoading(false);
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/* eslint-disable new-cap */
|
||||
import crypto from "crypto";
|
||||
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { changePassword, srp1 } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import Aes256Gcm from "./cryptography/aes-256-gcm";
|
||||
import { deriveArgonKey } from "./cryptography/crypto";
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
|
||||
const clientOldPassword = new jsrp.client();
|
||||
const clientNewPassword = new jsrp.client();
|
||||
|
||||
type Params = {
|
||||
email: string;
|
||||
currentPassword: string;
|
||||
newPassword: string;
|
||||
};
|
||||
|
||||
const attemptChangePassword = ({ email, currentPassword, newPassword }: Params): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
clientOldPassword.init({ username: email, password: currentPassword }, async () => {
|
||||
let serverPublicKey;
|
||||
let salt;
|
||||
|
||||
try {
|
||||
const clientPublicKey = clientOldPassword.getPublicKey();
|
||||
|
||||
const res = await srp1({ clientPublicKey });
|
||||
|
||||
serverPublicKey = res.serverPublicKey;
|
||||
salt = res.salt;
|
||||
|
||||
clientOldPassword.setSalt(salt);
|
||||
clientOldPassword.setServerPublicKey(serverPublicKey);
|
||||
|
||||
const clientProof = clientOldPassword.getProof();
|
||||
|
||||
clientNewPassword.init({ username: email, password: newPassword }, async () => {
|
||||
clientNewPassword.createVerifier(async (_err, result) => {
|
||||
try {
|
||||
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);
|
||||
|
||||
const {
|
||||
ciphertext: encryptedPrivateKey,
|
||||
iv: encryptedPrivateKeyIV,
|
||||
tag: encryptedPrivateKeyTag
|
||||
} = Aes256Gcm.encrypt({
|
||||
text: localStorage.getItem("PRIVATE_KEY") as string,
|
||||
secret: key
|
||||
});
|
||||
|
||||
const {
|
||||
ciphertext: protectedKey,
|
||||
iv: protectedKeyIV,
|
||||
tag: protectedKeyTag
|
||||
} = Aes256Gcm.encrypt({
|
||||
text: key.toString("hex"),
|
||||
secret: Buffer.from(derivedKey.hash)
|
||||
});
|
||||
|
||||
await changePassword({
|
||||
password: newPassword,
|
||||
clientProof,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
encryptedPrivateKey,
|
||||
encryptedPrivateKeyIV,
|
||||
encryptedPrivateKeyTag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier
|
||||
});
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
encryptedPrivateKey,
|
||||
iv: encryptedPrivateKeyIV,
|
||||
tag: encryptedPrivateKeyTag
|
||||
});
|
||||
|
||||
resolve();
|
||||
} catch (err2) {
|
||||
console.error(err2);
|
||||
reject(err2);
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default attemptChangePassword;
|
||||
@@ -1,18 +1,18 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
import axios from "axios";
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { decryptPrivateKeyHelper } from "@app/helpers/key";
|
||||
import { login1, login2 } from "@app/hooks/api/auth/queries";
|
||||
import { login1, login2, loginV3 } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import { createNotification } from "../notifications";
|
||||
import Telemetry from "./telemetry/Telemetry";
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
import { LoginMode } from "./attemptLogin";
|
||||
import SecurityClient from "./SecurityClient";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
|
||||
export interface IsCliLoginSuccessful {
|
||||
mfaEnabled: boolean;
|
||||
loginResponse?: {
|
||||
email: string;
|
||||
privateKey: string;
|
||||
@@ -31,14 +31,62 @@ const attemptLogin = async ({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken
|
||||
captchaToken,
|
||||
loginMode = LoginMode.ServerSide
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
captchaToken?: string;
|
||||
loginMode?: LoginMode;
|
||||
}): Promise<IsCliLoginSuccessful> => {
|
||||
const telemetry = new Telemetry().getInstance();
|
||||
|
||||
if (loginMode === LoginMode.ServerSide) {
|
||||
console.log("Attempting login with server side...");
|
||||
const data = await loginV3({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken
|
||||
}).catch((err) => {
|
||||
if (axios.isAxiosError(err) && err.response?.status === 400) {
|
||||
if (err.response?.data?.error === "LegacyEncryptionScheme") {
|
||||
createNotification({
|
||||
text: "Failed to login without SRP, attempting to authenticate with legacy SRP authentication.",
|
||||
type: "info"
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (data === null) {
|
||||
return attemptLogin({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken,
|
||||
loginMode: LoginMode.LegacySrp
|
||||
});
|
||||
}
|
||||
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
SecurityClient.setToken(data.accessToken);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
loginResponse: {
|
||||
email,
|
||||
privateKey: "",
|
||||
JTWToken: data.accessToken
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
client.init(
|
||||
{
|
||||
@@ -58,79 +106,26 @@ const attemptLogin = async ({
|
||||
client.setServerPublicKey(serverPublicKey);
|
||||
const clientProof = client.getProof(); // called M1
|
||||
|
||||
const {
|
||||
mfaEnabled,
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await login2({
|
||||
const { encryptionVersion, token, encryptedPrivateKey, iv, tag } = await login2({
|
||||
email,
|
||||
password,
|
||||
clientProof,
|
||||
providerAuthToken,
|
||||
captchaToken
|
||||
});
|
||||
if (mfaEnabled) {
|
||||
// case: MFA is enabled
|
||||
|
||||
// set temporary (MFA) JWT token
|
||||
SecurityClient.setMfaToken(token);
|
||||
|
||||
resolve({
|
||||
mfaEnabled,
|
||||
success: true
|
||||
});
|
||||
} else if (
|
||||
!mfaEnabled &&
|
||||
encryptionVersion &&
|
||||
encryptedPrivateKey &&
|
||||
iv &&
|
||||
tag &&
|
||||
token
|
||||
) {
|
||||
// case: MFA is not enabled
|
||||
|
||||
// unset provider auth token in case it was used
|
||||
if (encryptionVersion && encryptedPrivateKey && iv && tag && token) {
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
// set JWT token
|
||||
SecurityClient.setToken(token);
|
||||
|
||||
const privateKey = await decryptPrivateKeyHelper({
|
||||
encryptionVersion,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
password,
|
||||
salt,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag
|
||||
});
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
privateKey
|
||||
});
|
||||
|
||||
if (email) {
|
||||
telemetry.identify(email, email);
|
||||
telemetry.capture("User Logged In");
|
||||
}
|
||||
|
||||
resolve({
|
||||
mfaEnabled: false,
|
||||
loginResponse: {
|
||||
email,
|
||||
privateKey,
|
||||
privateKey: "",
|
||||
JTWToken: token
|
||||
},
|
||||
success: true
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { decryptPrivateKeyHelper } from "@app/helpers/key";
|
||||
import { login1, verifyMfaToken } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
import SecurityClient from "./SecurityClient";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
|
||||
interface IsMfaLoginSuccessful {
|
||||
success: boolean;
|
||||
loginResponse: {
|
||||
privateKey: string;
|
||||
JTWToken: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not MFA-login is successful for user with email [email]
|
||||
* and MFA token [mfaToken]
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.email - email of user
|
||||
* @param {String} obj.mfaToken - MFA code/token
|
||||
*/
|
||||
const attemptLoginMfa = async ({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
mfaToken
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
mfaToken: string;
|
||||
}): Promise<IsMfaLoginSuccessful> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.init(
|
||||
{
|
||||
username: email,
|
||||
password
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
const clientPublicKey = client.getPublicKey();
|
||||
const { salt } = await login1({
|
||||
email,
|
||||
clientPublicKey,
|
||||
providerAuthToken
|
||||
});
|
||||
|
||||
const {
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await verifyMfaToken({
|
||||
email,
|
||||
mfaCode: mfaToken
|
||||
});
|
||||
|
||||
// unset temporary (MFA) JWT token and set JWT token
|
||||
SecurityClient.setMfaToken("");
|
||||
SecurityClient.setToken(token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
|
||||
const privateKey = await decryptPrivateKeyHelper({
|
||||
encryptionVersion,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
password,
|
||||
salt,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag
|
||||
});
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
privateKey
|
||||
});
|
||||
|
||||
resolve({
|
||||
success: true,
|
||||
loginResponse: {
|
||||
privateKey,
|
||||
JTWToken: token
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default attemptLoginMfa;
|
||||
@@ -1,15 +1,19 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
import axios from "axios";
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { decryptPrivateKeyHelper } from "@app/helpers/key";
|
||||
import { login1, login2 } from "@app/hooks/api/auth/queries";
|
||||
import { login1, login2, loginV3 } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import { createNotification } from "../notifications";
|
||||
import Telemetry from "./telemetry/Telemetry";
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
import SecurityClient from "./SecurityClient";
|
||||
|
||||
export enum LoginMode {
|
||||
LegacySrp = "legacy-srp",
|
||||
ServerSide = "server-side"
|
||||
}
|
||||
|
||||
interface IsLoginSuccessful {
|
||||
mfaEnabled: boolean;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
@@ -23,14 +27,62 @@ const attemptLogin = async ({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken
|
||||
captchaToken,
|
||||
loginMode = LoginMode.ServerSide
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
captchaToken?: string;
|
||||
loginMode?: LoginMode;
|
||||
}): Promise<IsLoginSuccessful> => {
|
||||
const telemetry = new Telemetry().getInstance();
|
||||
|
||||
if (loginMode === LoginMode.ServerSide) {
|
||||
console.log("Attempting login with server side...");
|
||||
const data = await loginV3({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken
|
||||
}).catch((err) => {
|
||||
if (axios.isAxiosError(err) && err.response?.status === 400) {
|
||||
if (err.response?.data?.error === "LegacyEncryptionScheme") {
|
||||
createNotification({
|
||||
text: "Failed to login without SRP, attempting to authenticate with legacy SRP authentication.",
|
||||
type: "info"
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (data === null) {
|
||||
return attemptLogin({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
captchaToken,
|
||||
loginMode: LoginMode.LegacySrp
|
||||
});
|
||||
}
|
||||
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
SecurityClient.setToken(data.accessToken);
|
||||
|
||||
if (email) {
|
||||
telemetry.identify(email, email);
|
||||
telemetry.capture("User Logged In");
|
||||
}
|
||||
|
||||
return {
|
||||
success: true
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
await new Promise((resolve) => {
|
||||
@@ -48,18 +100,7 @@ const attemptLogin = async ({
|
||||
client.setServerPublicKey(serverPublicKey);
|
||||
const clientProof = client.getProof(); // called M1
|
||||
|
||||
const {
|
||||
mfaEnabled,
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await login2({
|
||||
const { encryptionVersion, token, encryptedPrivateKey, iv, tag } = await login2({
|
||||
captchaToken,
|
||||
email,
|
||||
password,
|
||||
@@ -67,56 +108,22 @@ const attemptLogin = async ({
|
||||
providerAuthToken
|
||||
});
|
||||
|
||||
if (mfaEnabled) {
|
||||
// case: MFA is enabled
|
||||
|
||||
// set temporary (MFA) JWT token
|
||||
SecurityClient.setMfaToken(token);
|
||||
|
||||
return {
|
||||
mfaEnabled,
|
||||
success: true
|
||||
};
|
||||
}
|
||||
if (!mfaEnabled && encryptionVersion && encryptedPrivateKey && iv && tag && token) {
|
||||
// case: MFA is not enabled
|
||||
|
||||
if (encryptionVersion && encryptedPrivateKey && iv && tag && token) {
|
||||
// unset provider auth token in case it was used
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
// set JWT token
|
||||
SecurityClient.setToken(token);
|
||||
|
||||
const privateKey = await decryptPrivateKeyHelper({
|
||||
encryptionVersion,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
password,
|
||||
salt,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag
|
||||
});
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
privateKey
|
||||
});
|
||||
|
||||
if (email) {
|
||||
telemetry.identify(email, email);
|
||||
telemetry.capture("User Logged In");
|
||||
}
|
||||
|
||||
return {
|
||||
mfaEnabled: false,
|
||||
success: true
|
||||
};
|
||||
}
|
||||
return { success: false, mfaEnabled: false };
|
||||
return { success: false };
|
||||
};
|
||||
|
||||
export default attemptLogin;
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { decryptPrivateKeyHelper } from "@app/helpers/key";
|
||||
import { login1, verifyMfaToken } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
import SecurityClient from "./SecurityClient";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
|
||||
/**
|
||||
* Return whether or not MFA-login is successful for user with email [email]
|
||||
* and MFA token [mfaToken]
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.email - email of user
|
||||
* @param {String} obj.mfaToken - MFA code/token
|
||||
*/
|
||||
const attemptLoginMfa = async ({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
mfaToken
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
mfaToken: string;
|
||||
}): Promise<boolean> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.init(
|
||||
{
|
||||
username: email,
|
||||
password
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
const clientPublicKey = client.getPublicKey();
|
||||
const { salt } = await login1({
|
||||
email,
|
||||
clientPublicKey,
|
||||
providerAuthToken
|
||||
});
|
||||
|
||||
const {
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await verifyMfaToken({
|
||||
email,
|
||||
mfaCode: mfaToken
|
||||
});
|
||||
|
||||
// unset temporary (MFA) JWT token and set JWT token
|
||||
SecurityClient.setMfaToken("");
|
||||
SecurityClient.setToken(token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
|
||||
const privateKey = await decryptPrivateKeyHelper({
|
||||
encryptionVersion,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
password,
|
||||
salt,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag
|
||||
});
|
||||
|
||||
saveTokenToLocalStorage({
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
privateKey
|
||||
});
|
||||
|
||||
resolve(true);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default attemptLoginMfa;
|
||||
@@ -1,114 +0,0 @@
|
||||
/* eslint-disable new-cap */
|
||||
import crypto from "crypto";
|
||||
|
||||
import jsrp from "jsrp";
|
||||
|
||||
import { issueBackupPrivateKey, srp1 } from "@app/hooks/api/auth/queries";
|
||||
|
||||
import generateBackupPDF from "../generateBackupPDF";
|
||||
import Aes256Gcm from "./aes-256-gcm";
|
||||
|
||||
const clientPassword = new jsrp.client();
|
||||
const clientKey = new jsrp.client();
|
||||
|
||||
interface BackupKeyProps {
|
||||
email: string;
|
||||
password: string;
|
||||
personalName: string;
|
||||
setBackupKeyError: (value: boolean) => void;
|
||||
setBackupKeyIssued: (value: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function issue a backup key for a user
|
||||
* @param {obkect} obj
|
||||
* @param {string} obj.email - email of a user issuing a backup key
|
||||
* @param {string} obj.password - password of a user issuing a backup key
|
||||
* @param {string} obj.personalName - name of a user issuing a backup key
|
||||
* @param {function} obj.setBackupKeyError - state function that turns true if there is an erorr with a backup key
|
||||
* @param {function} obj.setBackupKeyIssued - state function that turns true if a backup key was issued correctly
|
||||
* @returns
|
||||
*/
|
||||
const issueBackupKey = async ({
|
||||
email,
|
||||
password,
|
||||
personalName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued
|
||||
}: BackupKeyProps) => {
|
||||
try {
|
||||
setBackupKeyError(false);
|
||||
setBackupKeyIssued(false);
|
||||
clientPassword.init(
|
||||
{
|
||||
username: email,
|
||||
password
|
||||
},
|
||||
async () => {
|
||||
const clientPublicKey = clientPassword.getPublicKey();
|
||||
|
||||
let serverPublicKey;
|
||||
let salt;
|
||||
try {
|
||||
const res = await srp1({
|
||||
clientPublicKey
|
||||
});
|
||||
serverPublicKey = res.serverPublicKey;
|
||||
salt = res.salt;
|
||||
} catch (err) {
|
||||
setBackupKeyError(true);
|
||||
console.log("Wrong current password", err, 1);
|
||||
}
|
||||
|
||||
clientPassword.setSalt(salt as string);
|
||||
clientPassword.setServerPublicKey(serverPublicKey as string);
|
||||
const clientProof = clientPassword.getProof(); // called M1
|
||||
|
||||
const generatedKey = crypto.randomBytes(16).toString("hex");
|
||||
|
||||
clientKey.init(
|
||||
{
|
||||
username: email,
|
||||
password: generatedKey
|
||||
},
|
||||
async () => {
|
||||
clientKey.createVerifier(
|
||||
async (_err: any, result: { salt: string; verifier: string }) => {
|
||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
|
||||
text: String(localStorage.getItem("PRIVATE_KEY")),
|
||||
secret: generatedKey
|
||||
});
|
||||
|
||||
try {
|
||||
await issueBackupPrivateKey({
|
||||
encryptedPrivateKey: ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
clientProof
|
||||
});
|
||||
|
||||
generateBackupPDF({
|
||||
personalName,
|
||||
personalEmail: email,
|
||||
generatedKey
|
||||
});
|
||||
setBackupKeyIssued(true);
|
||||
} catch {
|
||||
setBackupKeyError(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
setBackupKeyError(true);
|
||||
console.log("Failed to issue a backup key");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export default issueBackupKey;
|
||||
@@ -1,67 +0,0 @@
|
||||
interface Props {
|
||||
protectedKey?: string;
|
||||
protectedKeyIV?: string;
|
||||
protectedKeyTag?: string;
|
||||
publicKey?: string;
|
||||
encryptedPrivateKey?: string;
|
||||
iv?: string;
|
||||
tag?: string;
|
||||
privateKey?: string;
|
||||
}
|
||||
|
||||
export const saveTokenToLocalStorage = ({
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
privateKey
|
||||
}: Props) => {
|
||||
try {
|
||||
if (protectedKey) {
|
||||
localStorage.removeItem("protectedKey");
|
||||
localStorage.setItem("protectedKey", protectedKey);
|
||||
}
|
||||
|
||||
if (protectedKeyIV) {
|
||||
localStorage.removeItem("protectedKeyIV");
|
||||
localStorage.setItem("protectedKeyIV", protectedKeyIV);
|
||||
}
|
||||
|
||||
if (protectedKeyTag) {
|
||||
localStorage.removeItem("protectedKeyTag");
|
||||
localStorage.setItem("protectedKeyTag", protectedKeyTag);
|
||||
}
|
||||
|
||||
if (publicKey) {
|
||||
localStorage.removeItem("publicKey");
|
||||
localStorage.setItem("publicKey", publicKey);
|
||||
}
|
||||
|
||||
if (encryptedPrivateKey) {
|
||||
localStorage.removeItem("encryptedPrivateKey");
|
||||
localStorage.setItem("encryptedPrivateKey", encryptedPrivateKey);
|
||||
}
|
||||
|
||||
if (iv) {
|
||||
localStorage.removeItem("iv");
|
||||
localStorage.setItem("iv", iv);
|
||||
}
|
||||
|
||||
if (tag) {
|
||||
localStorage.removeItem("tag");
|
||||
localStorage.setItem("tag", tag);
|
||||
}
|
||||
|
||||
if (privateKey) {
|
||||
localStorage.removeItem("PRIVATE_KEY");
|
||||
localStorage.setItem("PRIVATE_KEY", privateKey);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
throw new Error(`Unable to send the tokens in local storage:${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user