mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 11:27:07 +00:00
Merge remote-tracking branch 'origin/2fa' into mfa
This commit is contained in:
@@ -0,0 +1,136 @@
|
|||||||
|
/* eslint-disable react/jsx-props-no-spreading */
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import ReactCodeInput from 'react-code-input';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
|
import sendVerificationEmail from '@app/pages/api/auth/SendVerificationEmail';
|
||||||
|
|
||||||
|
import Button from '../basic/buttons/Button';
|
||||||
|
import Error from '../basic/Error';
|
||||||
|
|
||||||
|
// The style for the verification code input
|
||||||
|
const props = {
|
||||||
|
inputStyle: {
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
margin: '4px',
|
||||||
|
MozAppearance: 'textfield',
|
||||||
|
width: '55px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
fontSize: '24px',
|
||||||
|
height: '55px',
|
||||||
|
paddingLeft: '7',
|
||||||
|
backgroundColor: '#0d1117',
|
||||||
|
color: 'white',
|
||||||
|
border: '1px solid #2d2f33',
|
||||||
|
textAlign: 'center',
|
||||||
|
outlineColor: '#8ca542',
|
||||||
|
borderColor: '#2d2f33'
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
const propsPhone = {
|
||||||
|
inputStyle: {
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
margin: '4px',
|
||||||
|
MozAppearance: 'textfield',
|
||||||
|
width: '40px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
fontSize: '24px',
|
||||||
|
height: '40px',
|
||||||
|
paddingLeft: '7',
|
||||||
|
backgroundColor: '#0d1117',
|
||||||
|
color: 'white',
|
||||||
|
border: '1px solid #2d2f33',
|
||||||
|
textAlign: 'center',
|
||||||
|
outlineColor: '#8ca542',
|
||||||
|
borderColor: '#2d2f33'
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
interface CodeInputStepProps {
|
||||||
|
email: string;
|
||||||
|
incrementStep: () => void;
|
||||||
|
setCode: (value: string) => void;
|
||||||
|
codeError: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the second step of sign up where users need to verify their email
|
||||||
|
* @param {object} obj
|
||||||
|
* @param {string} obj.email - user's email to which we just sent a verification email
|
||||||
|
* @param {function} obj.incrementStep - goes to the next step of signup
|
||||||
|
* @param {function} obj.setCode - state updating function that set the current value of the emai verification code
|
||||||
|
* @param {boolean} obj.codeError - whether the code was inputted wrong or now
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function TwoFAStep({
|
||||||
|
email,
|
||||||
|
incrementStep,
|
||||||
|
setCode,
|
||||||
|
codeError
|
||||||
|
}: CodeInputStepProps): JSX.Element {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isResendingVerificationEmail, setIsResendingVerificationEmail] = useState(false);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const resendVerificationEmail = async () => {
|
||||||
|
setIsResendingVerificationEmail(true);
|
||||||
|
setIsLoading(true);
|
||||||
|
sendVerificationEmail(email);
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsResendingVerificationEmail(false);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-bunker w-max mx-auto h-7/12 pt-10 pb-4 px-8 rounded-xl drop-shadow-xl mb-64 md:mb-16">
|
||||||
|
<p className="text-l flex justify-center text-bunker-300">{t('signup:step2-message')}</p>
|
||||||
|
<p className="text-l flex justify-center font-semibold my-2 text-bunker-300">{email} </p>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<ReactCodeInput
|
||||||
|
name=""
|
||||||
|
inputMode="tel"
|
||||||
|
type="text"
|
||||||
|
fields={6}
|
||||||
|
onChange={setCode}
|
||||||
|
{...props}
|
||||||
|
className="mt-6 mb-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="block md:hidden">
|
||||||
|
<ReactCodeInput
|
||||||
|
name=""
|
||||||
|
inputMode="tel"
|
||||||
|
type="text"
|
||||||
|
fields={6}
|
||||||
|
onChange={setCode}
|
||||||
|
{...propsPhone}
|
||||||
|
className="mt-2 mb-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{codeError && <Error text={t('signup:step2-code-error')} />}
|
||||||
|
<div className="flex max-w-max min-w-28 flex-col items-center justify-center md:p-2 max-h-24 mx-auto text-lg px-4 mt-4 mb-2">
|
||||||
|
<Button text={t('signup:verify') ?? ''} onButtonPressed={incrementStep} size="lg" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
|
||||||
|
<div className="flex flex-row items-baseline gap-1 text-sm">
|
||||||
|
<span className="text-bunker-400">{t('signup:step2-resend-alert')}</span>
|
||||||
|
<u
|
||||||
|
className={`font-normal ${
|
||||||
|
isResendingVerificationEmail
|
||||||
|
? 'text-bunker-400'
|
||||||
|
: 'text-primary-700 hover:text-primary duration-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<button disabled={isLoading} onClick={resendVerificationEmail} type="button">
|
||||||
|
{isResendingVerificationEmail
|
||||||
|
? t('signup:step2-resend-progress')
|
||||||
|
: t('signup:step2-resend-submit')}
|
||||||
|
</button>
|
||||||
|
</u>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-bunker-400 pb-2">{t('signup:step2-spam-alert')}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ export default function DonwloadBackupPDFStep({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
|
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
|
||||||
<p className="text-4xl text-center font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
<p className="text-4xl text-center font-semibold flex justify-center text-primary">
|
||||||
{t('signup:step4-message')}
|
{t('signup:step4-message')}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
|
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
|
||||||
@@ -42,7 +42,7 @@ export default function DonwloadBackupPDFStep({
|
|||||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl" />
|
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl" />
|
||||||
{t('signup:step4-description3')}
|
{t('signup:step4-description3')}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
|
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-4 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
|
||||||
<Button
|
<Button
|
||||||
text="Download PDF"
|
text="Download PDF"
|
||||||
onButtonPressed={async () => {
|
onButtonPressed={async () => {
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export default function UserInfoStep({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-bunker w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-36 md:mb-16">
|
<div className="bg-bunker w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-36 md:mb-16">
|
||||||
<p className="text-4xl font-bold flex justify-center mb-6 text-gray-400 mx-8 md:mx-16 text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
<p className="text-4xl font-bold flex justify-center mb-6 mx-8 md:mx-16 text-primary">
|
||||||
{t('signup:step3-message')}
|
{t('signup:step3-message')}
|
||||||
</p>
|
</p>
|
||||||
<div className="relative z-0 flex items-center justify-end w-full md:p-2 rounded-lg max-h-24">
|
<div className="relative z-0 flex items-center justify-end w-full md:p-2 rounded-lg max-h-24">
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ export default function Login() {
|
|||||||
* This function check if the user entered the correct credentials and should be allowed to log in.
|
* This function check if the user entered the correct credentials and should be allowed to log in.
|
||||||
*/
|
*/
|
||||||
const loginCheck = async () => {
|
const loginCheck = async () => {
|
||||||
|
|
||||||
|
// #TODO: IF 2FA IS ENABLED REDIRECT TO <2FASTEP /> AND 'return;'
|
||||||
|
|
||||||
if (!email || !password) {
|
if (!email || !password) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import passwordCheck from '@app/components/utilities/checks/PasswordCheck';
|
|||||||
import changePassword from '@app/components/utilities/cryptography/changePassword';
|
import changePassword from '@app/components/utilities/cryptography/changePassword';
|
||||||
import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey';
|
import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey';
|
||||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||||
|
import { SecuritySection } from '@app/views/Settings/PersonalSettingsPage/SecuritySection/SecuritySection';
|
||||||
|
|
||||||
import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog';
|
import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog';
|
||||||
import getAPIKeys from '../../api/apiKey/getAPIKeys';
|
import getAPIKeys from '../../api/apiKey/getAPIKeys';
|
||||||
@@ -100,6 +101,10 @@ export default function PersonalSettings() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<SecuritySection
|
||||||
|
isTwoFAEnabled
|
||||||
|
onIsTwoFAEnabledChange={(value: boolean) => console.log(value)}
|
||||||
|
/>
|
||||||
<div className="bg-white/5 rounded-md px-6 flex flex-col items-start w-full mt-2 mb-8 pt-2">
|
<div className="bg-white/5 rounded-md px-6 flex flex-col items-start w-full mt-2 mb-8 pt-2">
|
||||||
<div className="flex flex-row justify-between w-full">
|
<div className="flex flex-row justify-between w-full">
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex flex-col w-full">
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { Checkbox } from '@app/components/v2';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isTwoFAEnabled?: boolean;
|
||||||
|
onIsTwoFAEnabledChange: (state: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SecuritySection = ({
|
||||||
|
isTwoFAEnabled,
|
||||||
|
onIsTwoFAEnabledChange
|
||||||
|
}: Props) => {
|
||||||
|
return (
|
||||||
|
<form>
|
||||||
|
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-2">
|
||||||
|
<p className="mb-4 mt-2 text-xl font-semibold">
|
||||||
|
Two-factor Authentication
|
||||||
|
</p>
|
||||||
|
<Checkbox
|
||||||
|
className="data-[state=checked]:bg-primary"
|
||||||
|
id="isTwoFAEnabled"
|
||||||
|
isChecked={isTwoFAEnabled}
|
||||||
|
onCheckedChange={(state) => {
|
||||||
|
onIsTwoFAEnabledChange(state as boolean);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Enable 2-factor authentication via your personal email.
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { SecuritySection } from './SecuritySection';
|
||||||
@@ -314,10 +314,6 @@ export const ProjectSettingsPage = () => {
|
|||||||
workspaceName={currentWorkspace?.name}
|
workspaceName={currentWorkspace?.name}
|
||||||
onProjectNameChange={onRenameWorkspace}
|
onProjectNameChange={onRenameWorkspace}
|
||||||
/>
|
/>
|
||||||
<AutoCapitalizationSection
|
|
||||||
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
|
|
||||||
onAutoCapitalizationChange={onAutoCapitalizationToggle}
|
|
||||||
/>
|
|
||||||
<CopyProjectIDSection workspaceID={currentWorkspace?._id || ''} />
|
<CopyProjectIDSection workspaceID={currentWorkspace?._id || ''} />
|
||||||
<EnvironmentSection
|
<EnvironmentSection
|
||||||
environments={currentWorkspace?.environments || []}
|
environments={currentWorkspace?.environments || []}
|
||||||
@@ -339,6 +335,10 @@ export const ProjectSettingsPage = () => {
|
|||||||
workspaceName={currentWorkspace?.name || ''}
|
workspaceName={currentWorkspace?.name || ''}
|
||||||
onCreateTag={onCreateWsTag}
|
onCreateTag={onCreateWsTag}
|
||||||
/>
|
/>
|
||||||
|
<AutoCapitalizationSection
|
||||||
|
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
|
||||||
|
onAutoCapitalizationChange={onAutoCapitalizationToggle}
|
||||||
|
/>
|
||||||
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4">
|
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4">
|
||||||
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
|
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
|
||||||
<p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p>
|
<p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p>
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ export const AutoCapitalizationSection = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
<div className="mb-2 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-2">
|
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-2">
|
||||||
<p className="mb-4 mt-2 text-xl font-semibold">
|
<p className="mb-4 mt-2 text-xl font-semibold">
|
||||||
{t('settings-project:auto-capitalization')}
|
{t('settings-project:auto-capitalization')}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user