Fix: Formatting and support for selecting org (line 109-122)

This commit is contained in:
Daniel Hougaard
2024-03-17 18:49:29 +01:00
parent b9986be387
commit e4dba6d5c8
@@ -1,8 +1,8 @@
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router" import { useRouter } from "next/router";
import axios from "axios" import axios from "axios";
import jwt_decode from "jwt-decode"; import jwt_decode from "jwt-decode";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
@@ -10,179 +10,191 @@ import attemptCliLogin from "@app/components/utilities/attemptCliLogin";
import attemptLogin from "@app/components/utilities/attemptLogin"; import attemptLogin from "@app/components/utilities/attemptLogin";
import { Button, Input } from "@app/components/v2"; import { Button, Input } from "@app/components/v2";
import { useUpdateUserAuthMethods } from "@app/hooks/api"; import { useUpdateUserAuthMethods } from "@app/hooks/api";
import { fetchOrganizations } from "@app/hooks/api/organization/queries";
import { fetchUserDetails } from "@app/hooks/api/users/queries"; import { fetchUserDetails } from "@app/hooks/api/users/queries";
import { navigateUserToOrg } from "../../Login.utils"; import { navigateUserToOrg, navigateUserToSelectOrg } from "../../Login.utils";
type Props = { type Props = {
providerAuthToken: string; providerAuthToken: string;
email: string; email: string;
password: string; password: string;
setPassword: (password: string) => void; setPassword: (password: string) => void;
setStep: (step: number) => void; setStep: (step: number) => void;
} };
export const PasswordStep = ({ export const PasswordStep = ({
providerAuthToken, providerAuthToken,
email, email,
password, password,
setPassword, setPassword,
setStep, setStep
}: Props) => { }: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useUpdateUserAuthMethods(); const { mutateAsync } = useUpdateUserAuthMethods();
const { const { callbackPort, isLinkingRequired, authMethod, organizationId } = jwt_decode(
callbackPort, providerAuthToken
isLinkingRequired, ) as any;
authMethod,
organizationId
} = jwt_decode(providerAuthToken) as any;
const handleLogin = async (e:React.FormEvent) => { const handleLogin = async (e: React.FormEvent) => {
e.preventDefault() e.preventDefault();
try { try {
setIsLoading(true); setIsLoading(true);
if (callbackPort) { if (callbackPort) {
// attemptCliLogin // attemptCliLogin
const isCliLoginSuccessful = await attemptCliLogin({ const isCliLoginSuccessful = await attemptCliLogin({
email, email,
password, password,
providerAuthToken providerAuthToken
}) });
if (isCliLoginSuccessful && isCliLoginSuccessful.success) { if (isCliLoginSuccessful && isCliLoginSuccessful.success) {
if (isCliLoginSuccessful.mfaEnabled) {
if (isCliLoginSuccessful.mfaEnabled) { // case: login requires MFA step
// case: login requires MFA step setStep(2);
setStep(2);
setIsLoading(false);
return;
}
// case: login was successful
const cliUrl = `http://127.0.0.1:${callbackPort}/`
// send request to server endpoint
const instance = axios.create()
await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse })
// cli page
router.push("/cli-redirect");
// on success, router.push to cli Login Successful page
}
} else {
const loginAttempt = await attemptLogin({
email,
password,
providerAuthToken,
});
if (loginAttempt && loginAttempt.success) {
// case: login was successful
if (loginAttempt.mfaEnabled) {
// TODO: deal with MFA
// case: login requires MFA step
setIsLoading(false);
setStep(2);
return;
}
// case: login does not require MFA step
setIsLoading(false);
createNotification({
text: "Successfully logged in",
type: "success"
});
if (isLinkingRequired) {
const user = await fetchUserDetails();
const newAuthMethods = [...user.authMethods, authMethod]
await mutateAsync({
authMethods: newAuthMethods
});
}
await navigateUserToOrg(router, organizationId);
}
}
} catch (err) {
setIsLoading(false); setIsLoading(false);
createNotification({ return;
text: "Login unsuccessful. Double-check your master password and try again.", }
type: "error" // case: login was successful
}); const cliUrl = `http://127.0.0.1:${callbackPort}/`;
console.error(err);
}
};
return ( // send request to server endpoint
<form const instance = axios.create();
onSubmit={handleLogin} await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse });
className="h-full mx-auto w-full max-w-md px-6 pt-8"
// cli page
router.push("/cli-redirect");
// on success, router.push to cli Login Successful page
}
} else {
const loginAttempt = await attemptLogin({
email,
password,
providerAuthToken
});
if (loginAttempt && loginAttempt.success) {
// case: login was successful
if (loginAttempt.mfaEnabled) {
// TODO: deal with MFA
// case: login requires MFA step
setIsLoading(false);
setStep(2);
return;
}
// case: login does not require MFA step
setIsLoading(false);
createNotification({
text: "Successfully logged in",
type: "success"
});
if (isLinkingRequired) {
const user = await fetchUserDetails();
const newAuthMethods = [...user.authMethods, authMethod];
await mutateAsync({
authMethods: newAuthMethods
});
}
// case: organization ID is present from the provider auth token -- navigate directly to the org
if (organizationId) {
await navigateUserToOrg(router, organizationId);
}
// case: no organization ID is present -- navigate to the select org page IF the user has any orgs
// if the user has no orgs, navigate to the create org page
else {
const userOrgs = await fetchOrganizations();
if (userOrgs.length > 0) {
navigateUserToSelectOrg(router);
} else {
await navigateUserToOrg(router);
}
}
}
}
} catch (err) {
setIsLoading(false);
createNotification({
text: "Login unsuccessful. Double-check your master password and try again.",
type: "error"
});
console.error(err);
}
};
return (
<form onSubmit={handleLogin} className="mx-auto h-full w-full max-w-md px-6 pt-8">
<div className="mb-8">
<p className="mx-auto mb-4 flex w-max justify-center bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
{isLinkingRequired ? "Link your account" : "What's your Infisical password?"}
</p>
{isLinkingRequired && (
<div className="mx-auto flex w-max flex-col items-center text-xs text-bunker-400">
<span className="max-w-sm px-4 text-center duration-200">
An existing account without this SSO authentication method enabled was found under the
same email. Login with your password to link the account.
</span>
</div>
)}
</div>
<div className="relative mx-auto flex max-h-24 w-1/4 w-full min-w-[22rem] items-center justify-center rounded-lg md:max-h-28 lg:w-1/6">
<div className="flex max-h-24 w-full items-center justify-center rounded-lg md:max-h-28">
<Input
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
placeholder="Enter your password..."
isRequired
autoComplete="current-password"
id="current-password"
className="h-12"
/>
</div>
</div>
<div className="mx-auto mt-4 flex w-1/4 w-full min-w-[22rem] items-center justify-center rounded-md text-center lg:w-1/6">
<Button
type="submit"
colorSchema="primary"
variant="outline_bg"
isFullWidth
isLoading={isLoading}
className="h-14"
> >
<div className="mb-8"> {t("login.login")}
<p className="mx-auto flex w-max justify-center text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-4"> </Button>
{isLinkingRequired ? "Link your account" : "What's your Infisical password?"} </div>
</p> <div className="mx-auto mt-4 flex w-max flex-col items-center text-xs text-bunker-400">
{isLinkingRequired && ( <span className="max-w-sm px-4 text-center duration-200">
<div className="text-bunker-400 text-xs flex flex-col items-center w-max mx-auto"> Infisical Master Password serves as a decryption mechanism so that even Google is not able
<span className='duration-200 max-w-sm text-center px-4'> to access your secrets.
An existing account without this SSO authentication method enabled was found under the same email. Login with your password to link the account. </span>
</span> <Link href="/verify-email">
</div> <span className="mt-2 cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4">
)} {t("login.forgot-password")}
</div> </span>
<div className="relative flex items-center justify-center lg:w-1/6 w-1/4 min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28"> </Link>
<div className="flex items-center justify-center w-full rounded-lg max-h-24 md:max-h-28"> </div>
<Input <div className="flex flex-row items-center justify-center">
value={password} <button
onChange={(e) => setPassword(e.target.value)} onClick={() => {
type="password" router.push("/login");
placeholder="Enter your password..." }}
isRequired type="button"
autoComplete="current-password" className="mt-2 cursor-pointer text-xs text-bunker-400 duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4"
id="current-password" >
className="h-12" {t("login.other-option")}
/> </button>
</div> </div>
</div> </form>
<div className='lg:w-1/6 w-1/4 w-full mx-auto flex items-center justify-center min-w-[22rem] text-center rounded-md mt-4'> );
<Button };
type="submit"
colorSchema="primary"
variant="outline_bg"
isFullWidth
isLoading={isLoading}
className="h-14"
>
{t("login.login")}
</Button>
</div>
<div className="text-bunker-400 text-xs flex flex-col items-center w-max mx-auto mt-4">
<span className='duration-200 max-w-sm text-center px-4'>
Infisical Master Password serves as a decryption mechanism so that even Google is not able to access your secrets.
</span>
<Link href="/verify-email">
<span className='hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t("login.forgot-password")}</span>
</Link>
</div>
<div className="flex flex-row items-center justify-center">
<button
onClick={() => {
router.push("/login");
}}
type="button"
className="text-bunker-400 text-xs hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer"
>
{t("login.other-option")}
</button>
</div>
</form>
);
}