mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 17:40:44 +00:00
Merge branch 'main' into checkly-integration
This commit is contained in:
@@ -2,18 +2,19 @@ import crypto from 'crypto';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { faCheck, faXmark } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faXmark } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import jsrp from 'jsrp';
|
||||
import nacl from 'tweetnacl';
|
||||
import { encodeBase64 } from 'tweetnacl-util';
|
||||
|
||||
import { useGetCommonPasswords } from '@app/hooks/api';
|
||||
import completeAccountInformationSignup from '@app/pages/api/auth/CompleteAccountInformationSignup';
|
||||
import getOrganizations from '@app/pages/api/organization/getOrgs';
|
||||
import ProjectService from '@app/services/ProjectService';
|
||||
|
||||
import InputField from '../basic/InputField';
|
||||
import passwordCheck from '../utilities/checks/PasswordCheck';
|
||||
import checkPassword from '../utilities/checks/checkPassword';
|
||||
import Aes256Gcm from '../utilities/cryptography/aes-256-gcm';
|
||||
import { deriveArgonKey } from '../utilities/cryptography/crypto';
|
||||
import { saveTokenToLocalStorage } from '../utilities/saveTokenToLocalStorage';
|
||||
@@ -37,6 +38,15 @@ interface UserInfoStepProps {
|
||||
providerAuthToken?: string;
|
||||
}
|
||||
|
||||
type Errors = {
|
||||
length?: string,
|
||||
upperCase?: string,
|
||||
lowerCase?: string,
|
||||
number?: string,
|
||||
specialChar?: string,
|
||||
repeatedChar?: string,
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the step of the sign up flow where people provife their name/surname and password
|
||||
* @param {object} obj
|
||||
@@ -63,11 +73,11 @@ export default function UserInfoStep({
|
||||
setAttributionSource,
|
||||
providerAuthToken,
|
||||
}: UserInfoStepProps): JSX.Element {
|
||||
const { data: commonPasswords } = useGetCommonPasswords();
|
||||
const [nameError, setNameError] = useState(false);
|
||||
const [organizationNameError, setOrganizationNameError] = useState(false);
|
||||
const [passwordErrorLength, setPasswordErrorLength] = useState(false);
|
||||
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
|
||||
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
|
||||
|
||||
const [errors, setErrors] = useState<Errors>({});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
@@ -89,12 +99,11 @@ export default function UserInfoStep({
|
||||
} else {
|
||||
setOrganizationNameError(false);
|
||||
}
|
||||
errorCheck = passwordCheck({
|
||||
|
||||
errorCheck = checkPassword({
|
||||
password,
|
||||
setPasswordErrorLength,
|
||||
setPasswordErrorNumber,
|
||||
setPasswordErrorLowerCase,
|
||||
errorCheck
|
||||
commonPasswords,
|
||||
setErrors
|
||||
});
|
||||
|
||||
if (!errorCheck) {
|
||||
@@ -248,59 +257,45 @@ export default function UserInfoStep({
|
||||
label={t('section.password.password')}
|
||||
onChangeHandler={(pass: string) => {
|
||||
setPassword(pass);
|
||||
passwordCheck({
|
||||
checkPassword({
|
||||
password: pass,
|
||||
setPasswordErrorLength,
|
||||
setPasswordErrorNumber,
|
||||
setPasswordErrorLowerCase,
|
||||
errorCheck: false
|
||||
commonPasswords,
|
||||
setErrors
|
||||
});
|
||||
}}
|
||||
type="password"
|
||||
value={password}
|
||||
isRequired
|
||||
error={passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase}
|
||||
error={Object.keys(errors).length > 0}
|
||||
autoComplete="new-password"
|
||||
id="new-password"
|
||||
/>
|
||||
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
|
||||
{Object.keys(errors).length > 0 && (
|
||||
<div className="mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-2 py-2">
|
||||
<div className="mb-1 text-sm text-gray-400">{t('section.password.validate-base')}</div>
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon icon={faXmark} className="text-md text-red ml-0.5 mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div className={`${passwordErrorLength ? 'text-gray-400' : 'text-gray-600'} text-sm`}>
|
||||
{t('section.password.validate-length')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon icon={faXmark} className="text-md text-red ml-0.5 mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div
|
||||
className={`${passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'} text-sm`}
|
||||
>
|
||||
{t('section.password.validate-case')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon icon={faXmark} className="text-md text-red ml-0.5 mr-2.5" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div className={`${passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'} text-sm`}>
|
||||
{t('section.password.validate-number')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-2 text-sm text-gray-400">{t('section.password.validate-base')}</div>
|
||||
{Object.keys(errors).map((key) => {
|
||||
if (errors[key as keyof Errors]) {
|
||||
return (
|
||||
<div
|
||||
className="ml-1 flex flex-row items-top justify-start"
|
||||
key={key}
|
||||
>
|
||||
<div>
|
||||
<FontAwesomeIcon
|
||||
icon={faXmark}
|
||||
className="text-md text-red ml-0.5 mr-2.5"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-gray-400 text-sm">
|
||||
{errors[key as keyof Errors]}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="py-2" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center lg:w-[19%] w-1/4 min-w-[20rem] mt-2 max-w-xs md:max-w-md mx-auto text-sm text-center md:text-left">
|
||||
|
||||
@@ -17,6 +17,7 @@ const passwordCheck = ({
|
||||
setPasswordErrorLowerCase,
|
||||
errorCheck
|
||||
}: PasswordCheckProps) => {
|
||||
|
||||
if (!password || password.length < 14) {
|
||||
setPasswordErrorLength(true);
|
||||
errorCheck = true;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
type Errors = {
|
||||
length?: string,
|
||||
upperCase?: string,
|
||||
lowerCase?: string,
|
||||
number?: string,
|
||||
specialChar?: string,
|
||||
repeatedChar?: string,
|
||||
commonPassword?: string
|
||||
};
|
||||
|
||||
interface CheckPasswordParams {
|
||||
password: string;
|
||||
commonPasswords: string[];
|
||||
setErrors: (value: Errors) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the password [password] is at least:
|
||||
* - 8 characters long
|
||||
* - Contains 1 uppercase character (A-Z)
|
||||
* - Contains 1 lowercase character (a-z)
|
||||
* - Contains 1 number (0-9)
|
||||
* - Does not contain 3 repeat, consecutive characters
|
||||
*
|
||||
* The function returns whether or not the password [password]
|
||||
* passes the minimum requirements above. It sets errors on
|
||||
* an erorr object via [setErrors].
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.password - the password to check
|
||||
* @param {Function} obj.setErrors - set state function to set error object
|
||||
*/
|
||||
const checkPassword = ({
|
||||
password,
|
||||
commonPasswords,
|
||||
setErrors
|
||||
}: CheckPasswordParams): boolean => {
|
||||
const errors: Errors = {};
|
||||
|
||||
if (password.length < 8) {
|
||||
errors.length = "8 characters";
|
||||
}
|
||||
|
||||
if (!/[A-Z]/.test(password)) {
|
||||
errors.upperCase = "1 uppercase character (A-Z)";
|
||||
}
|
||||
|
||||
if (!/[a-z]/.test(password)) {
|
||||
errors.lowerCase = "1 lowercase character (a-z)";
|
||||
}
|
||||
|
||||
if (!/[0-9]/.test(password)) {
|
||||
errors.number = "1 number (0-9)";
|
||||
}
|
||||
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
errors.specialChar = "1 special character (!@#$%^&*(),.?)";
|
||||
}
|
||||
|
||||
if (/([A-Za-z0-9])\1\1\1/.test(password)) {
|
||||
errors.repeatedChar = "No 3 repeat, consecutive characters";
|
||||
}
|
||||
|
||||
if (commonPasswords.includes(password)) {
|
||||
errors.commonPassword = "No common passwords";
|
||||
}
|
||||
|
||||
setErrors(errors);
|
||||
return Object.keys(errors).length > 0;
|
||||
}
|
||||
|
||||
export default checkPassword;
|
||||
@@ -125,6 +125,10 @@ const changePassword = async (
|
||||
setPasswordChanged(true);
|
||||
setCurrentPassword('');
|
||||
setNewPassword('');
|
||||
|
||||
window.location.href = '/login';
|
||||
|
||||
// move to login page
|
||||
} catch (error) {
|
||||
setCurrentPasswordError(true);
|
||||
console.log(error);
|
||||
|
||||
@@ -73,10 +73,15 @@ export const DeleteActionModal = ({
|
||||
}
|
||||
onClose={onClose}
|
||||
>
|
||||
<form>
|
||||
<form
|
||||
onSubmit={(evt) => {
|
||||
evt.preventDefault();
|
||||
if (deleteKey === inputData) onDelete();
|
||||
}}
|
||||
>
|
||||
<FormControl
|
||||
label={
|
||||
<div className="pb-2 text-sm break-words">
|
||||
<div className="break-words pb-2 text-sm">
|
||||
Type <span className="font-bold">{deleteKey}</span> to delete the resource
|
||||
</div>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user