mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #1178 from akhilmhdh/patch/sign-up
fix: resolved backup key generation in signup, removed owner check and logic race condition error
This commit is contained in:
@@ -1,24 +1,16 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
Membership,
|
||||
MembershipOrg,
|
||||
Workspace
|
||||
} from "../../models";
|
||||
import { Membership, MembershipOrg, Workspace } from "../../models";
|
||||
import { Role } from "../../ee/models";
|
||||
import { deleteMembershipOrg } from "../../helpers/membershipOrg";
|
||||
import {
|
||||
import {
|
||||
createOrganization as create,
|
||||
deleteOrganization,
|
||||
updateSubscriptionOrgQuantity
|
||||
} from "../../helpers/organization";
|
||||
import { addMembershipsOrg } from "../../helpers/membershipOrg";
|
||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||
import {
|
||||
ACCEPTED,
|
||||
ADMIN,
|
||||
CUSTOM
|
||||
} from "../../variables";
|
||||
import { ACCEPTED, ADMIN, CUSTOM } from "../../variables";
|
||||
import * as reqValidator from "../../validation/organization";
|
||||
import { validateRequest } from "../../helpers/validation";
|
||||
import {
|
||||
@@ -155,7 +147,7 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
|
||||
OrgPermissionSubjects.Member
|
||||
);
|
||||
|
||||
const isCustomRole = !["admin", "member", "owner"].includes(role);
|
||||
const isCustomRole = !["admin", "member"].includes(role);
|
||||
if (isCustomRole) {
|
||||
const orgRole = await Role.findOne({ slug: role, isOrgRole: true });
|
||||
if (!orgRole) throw BadRequestError({ message: "Role not found" });
|
||||
@@ -336,7 +328,7 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const createOrganization = async (req: Request, res: Response) => {
|
||||
export const createOrganization = async (req: Request, res: Response) => {
|
||||
const {
|
||||
body: { name }
|
||||
} = await validateRequest(reqValidator.CreateOrgv2, req);
|
||||
@@ -361,27 +353,27 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
|
||||
/**
|
||||
* Delete organization with id [organizationId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const deleteOrganizationById = async (req: Request, res: Response) => {
|
||||
const {
|
||||
params: { organizationId }
|
||||
} = await validateRequest(reqValidator.DeleteOrgv2, req);
|
||||
|
||||
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: new Types.ObjectId(organizationId),
|
||||
role: ADMIN
|
||||
});
|
||||
|
||||
|
||||
if (!membershipOrg) throw UnauthorizedRequestError();
|
||||
|
||||
|
||||
const organization = await deleteOrganization({
|
||||
organizationId: new Types.ObjectId(organizationId)
|
||||
});
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
organization
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,11 @@ import { useTranslation } from "react-i18next";
|
||||
import { faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import issueBackupKey from "../utilities/cryptography/issueBackupKey";
|
||||
import { useToggle } from "@app/hooks";
|
||||
import { generateUserBackupKey } from "@app/lib/crypto";
|
||||
|
||||
import { useNotificationContext } from "../context/Notifications/NotificationProvider";
|
||||
import { generateBackupPDFAsync } from "../utilities/generateBackupPDF";
|
||||
import { Button } from "../v2";
|
||||
|
||||
interface DownloadBackupPDFStepProps {
|
||||
@@ -28,35 +32,56 @@ export default function DonwloadBackupPDFStep({
|
||||
name
|
||||
}: DownloadBackupPDFStepProps): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const [isLoading, setIsLoading] = useToggle();
|
||||
|
||||
const handleBackupKeyGenerate = async () => {
|
||||
try {
|
||||
setIsLoading.on();
|
||||
const generatedKey = await generateUserBackupKey(email, password);
|
||||
await generateBackupPDFAsync({
|
||||
generatedKey,
|
||||
personalEmail: email,
|
||||
personalName: name
|
||||
});
|
||||
incrementStep();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Faield to generate backup key"
|
||||
});
|
||||
} finally {
|
||||
setIsLoading.off();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
|
||||
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />{t("signup.step4-message")}
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />
|
||||
{t("signup.step4-message")}
|
||||
</p>
|
||||
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">
|
||||
<div className="w-full mt-4 md:mt-8 flex flex-row text-center items-center m-2 text-bunker-300 rounded-md lg:w-1/6 lg:w-1/6 w-full md:min-w-[23rem] px-3 mx-auto">
|
||||
<span className='mb-2'>{t("signup.step4-description1")} {t("signup.step4-description3")}</span>
|
||||
<span className="mb-2">
|
||||
{t("signup.step4-description1")} {t("signup.step4-description3")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center px-3 justify-center mt-0 md:mt-4 mb-2 md:mb-4 lg:w-1/6 w-full md:min-w-[20rem] mt-2 md:max-w-md mx-auto text-sm text-center md:text-left">
|
||||
<div className="text-l py-1 text-lg w-full">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await issueBackupKey({
|
||||
email,
|
||||
password,
|
||||
personalName: name,
|
||||
setBackupKeyError: () => { },
|
||||
setBackupKeyIssued: () => { }
|
||||
});
|
||||
incrementStep();
|
||||
}}
|
||||
onClick={handleBackupKeyGenerate}
|
||||
size="sm"
|
||||
isFullWidth
|
||||
className='h-12'
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
className="h-12"
|
||||
colorSchema="primary"
|
||||
variant="outline_bg"
|
||||
> Download PDF </Button>
|
||||
>
|
||||
Download PDF
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,6 @@ import Telemetry from "./telemetry/Telemetry";
|
||||
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
|
||||
import SecurityClient from "./SecurityClient";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
|
||||
interface IsLoginSuccessful {
|
||||
mfaEnabled: boolean;
|
||||
success: boolean;
|
||||
@@ -22,118 +19,100 @@ interface IsLoginSuccessful {
|
||||
* @param {string} email - email of user to log in
|
||||
* @param {string} password - password of user to log in
|
||||
*/
|
||||
const attemptLogin = async (
|
||||
{
|
||||
email,
|
||||
password,
|
||||
providerAuthToken,
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
}
|
||||
): Promise<IsLoginSuccessful> => {
|
||||
const attemptLogin = async ({
|
||||
email,
|
||||
password,
|
||||
providerAuthToken
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
providerAuthToken?: string;
|
||||
}): Promise<IsLoginSuccessful> => {
|
||||
const telemetry = new Telemetry().getInstance();
|
||||
return new Promise((resolve, reject) => {
|
||||
client.init(
|
||||
{
|
||||
username: email,
|
||||
password
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
const clientPublicKey = client.getPublicKey();
|
||||
|
||||
const { serverPublicKey, salt } = await login1({
|
||||
email,
|
||||
clientPublicKey,
|
||||
providerAuthToken,
|
||||
});
|
||||
|
||||
client.setSalt(salt);
|
||||
client.setServerPublicKey(serverPublicKey);
|
||||
const clientProof = client.getProof(); // called M1
|
||||
|
||||
const {
|
||||
mfaEnabled,
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await login2(
|
||||
{
|
||||
email,
|
||||
clientProof,
|
||||
providerAuthToken,
|
||||
}
|
||||
);
|
||||
|
||||
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
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
// set JWT token
|
||||
SecurityClient.setToken(token);
|
||||
|
||||
const privateKey = await KeyService.decryptPrivateKey({
|
||||
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,
|
||||
success: true
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
// eslint-disable-next-line new-cap
|
||||
const client = new jsrp.client();
|
||||
await new Promise((resolve) => {
|
||||
client.init({ username: email, password }, () => resolve(null));
|
||||
});
|
||||
const clientPublicKey = client.getPublicKey();
|
||||
|
||||
const { serverPublicKey, salt } = await login1({
|
||||
email,
|
||||
clientPublicKey,
|
||||
providerAuthToken
|
||||
});
|
||||
|
||||
client.setSalt(salt);
|
||||
client.setServerPublicKey(serverPublicKey);
|
||||
const clientProof = client.getProof(); // called M1
|
||||
|
||||
const {
|
||||
mfaEnabled,
|
||||
encryptionVersion,
|
||||
protectedKey,
|
||||
protectedKeyIV,
|
||||
protectedKeyTag,
|
||||
token,
|
||||
publicKey,
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag
|
||||
} = await login2({
|
||||
email,
|
||||
clientProof,
|
||||
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
|
||||
|
||||
// unset provider auth token in case it was used
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
// set JWT token
|
||||
SecurityClient.setToken(token);
|
||||
|
||||
const privateKey = await KeyService.decryptPrivateKey({
|
||||
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 };
|
||||
};
|
||||
|
||||
export default attemptLogin;
|
||||
|
||||
Reference in New Issue
Block a user