@stokr/components-library 3.0.54 → 3.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,12 +4,13 @@ import PropTypes from "prop-types";
|
|
|
4
4
|
import stdin_default$1 from "../SvgIcons/CapsLockSvg.js";
|
|
5
5
|
import { InfoIcon } from "../InfoIcon/InfoIcon.js";
|
|
6
6
|
import { Wrapper, Label, InputWrap } from "./Input.styles.js";
|
|
7
|
+
import { getPasswordEntropy, ENTROPY_WEAK, ENTROPY_MEDIUM } from "../../utils/password-validation.js";
|
|
7
8
|
import { InfoIconWrapper, ShowPassword, BottomWrap, PasswordStrengthWrap, PasswordStrengthIndicators, PasswordStrengthIndicator, PasswordStrengthText, CapslockIndicator } from "./InputPassword.styles.js";
|
|
8
9
|
const PasswordStrength = {
|
|
9
10
|
NONE: "none",
|
|
10
11
|
WEAK: "Weak",
|
|
11
|
-
MEDIUM: "
|
|
12
|
-
STRONG: "
|
|
12
|
+
MEDIUM: "Good",
|
|
13
|
+
STRONG: "Strong"
|
|
13
14
|
};
|
|
14
15
|
const InputPassword = (props) => {
|
|
15
16
|
const {
|
|
@@ -53,15 +54,10 @@ const InputPassword = (props) => {
|
|
|
53
54
|
onChange?.(e, field);
|
|
54
55
|
};
|
|
55
56
|
const passwordStrengthFunction = () => {
|
|
56
|
-
if (value
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
return PasswordStrength.WEAK;
|
|
61
|
-
}
|
|
62
|
-
if (value.length < 11) {
|
|
63
|
-
return PasswordStrength.MEDIUM;
|
|
64
|
-
}
|
|
57
|
+
if (!value) return PasswordStrength.NONE;
|
|
58
|
+
const entropy = getPasswordEntropy(value);
|
|
59
|
+
if (entropy < ENTROPY_WEAK) return PasswordStrength.WEAK;
|
|
60
|
+
if (entropy < ENTROPY_MEDIUM) return PasswordStrength.MEDIUM;
|
|
65
61
|
return PasswordStrength.STRONG;
|
|
66
62
|
};
|
|
67
63
|
const passwordStrength = passwordStrengthFunction();
|
|
@@ -16,6 +16,7 @@ import { Row, Column } from "../Grid/Grid.styles.js";
|
|
|
16
16
|
import { ComponentWrapper } from "../ComponentWrapper/ComponentWrapper.styles.js";
|
|
17
17
|
import fetchDataPublic from "../../api/fetchDataPublic.js";
|
|
18
18
|
import { emailRegex } from "../../constants/globalVariables.js";
|
|
19
|
+
import { isPasswordValid, PASSWORD_REQUIREMENTS_MESSAGE } from "../../utils/password-validation.js";
|
|
19
20
|
import { ModalInner, ModalLinkWrap, ModalLink } from "../Modal/Modal.styles.js";
|
|
20
21
|
import { FormField, FormError } from "../Form/Form.styles.js";
|
|
21
22
|
const TermsStyled = styled.span`
|
|
@@ -78,7 +79,11 @@ const RegisterModal = (props) => {
|
|
|
78
79
|
}, [props.popupError]);
|
|
79
80
|
const validationSchema = Yup.object().shape({
|
|
80
81
|
email: Yup.string().matches(emailRegex, "Oops, that's not a valid address").required("Oops, this can‘t be blank"),
|
|
81
|
-
password: Yup.string().
|
|
82
|
+
password: Yup.string().test("password-full", function(val) {
|
|
83
|
+
if (!val) return this.createError({ message: "Oops, this can’t be blank" });
|
|
84
|
+
if (!isPasswordValid(val)) return this.createError({ message: PASSWORD_REQUIREMENTS_MESSAGE });
|
|
85
|
+
return true;
|
|
86
|
+
}),
|
|
82
87
|
terms: Yup.bool().oneOf([true], "Please agree to continue"),
|
|
83
88
|
newsletter: Yup.bool()
|
|
84
89
|
// .oneOf([true], 'Newsletter accept is required'),
|
|
@@ -136,13 +141,13 @@ const RegisterModal = (props) => {
|
|
|
136
141
|
clearPopupError();
|
|
137
142
|
}
|
|
138
143
|
if (withTouch) {
|
|
139
|
-
setFieldValue(field.name, field.value,
|
|
140
|
-
setFieldTouched(field.name);
|
|
144
|
+
setFieldValue(field.name, field.value, true);
|
|
145
|
+
setFieldTouched(field.name, true, false);
|
|
141
146
|
} else {
|
|
142
147
|
handleChange(e);
|
|
143
148
|
}
|
|
144
149
|
};
|
|
145
|
-
const submitDisabled = !values.email || !!errors.email || !!errors.terms || values.password
|
|
150
|
+
const submitDisabled = !values.email || !!errors.email || !!errors.terms || !isPasswordValid(values.password) || isActionLoading === "signUp" || popupError.popup === "register";
|
|
146
151
|
return /* @__PURE__ */ jsxs(stdin_default$1, { children: [
|
|
147
152
|
/* @__PURE__ */ jsx(ComponentWrapper, { noPadding: true, children: /* @__PURE__ */ jsxs(FormField, { children: [
|
|
148
153
|
/* @__PURE__ */ jsx(
|
|
@@ -179,11 +184,11 @@ const RegisterModal = (props) => {
|
|
|
179
184
|
touched: !!touched.password,
|
|
180
185
|
info: "For a stronger password, try a mix of lowercase, capitals, numbers and special characters.",
|
|
181
186
|
autoComplete: "new-password",
|
|
182
|
-
"data-cy": "register-modal-password-input"
|
|
187
|
+
"data-cy": "register-modal-password-input",
|
|
188
|
+
showStrength: true
|
|
183
189
|
}
|
|
184
190
|
),
|
|
185
|
-
/* @__PURE__ */ jsx(FormError, { show: errors.password && touched.password, children: errors.password })
|
|
186
|
-
/* @__PURE__ */ jsx(FormError, { show: !errors.password && touched.password && values.password.length <= 5, children: "The password must be at least 6 characters long" })
|
|
191
|
+
/* @__PURE__ */ jsx(FormError, { show: errors.password && touched.password, children: errors.password })
|
|
187
192
|
] }) }),
|
|
188
193
|
/* @__PURE__ */ jsx(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true }),
|
|
189
194
|
/* @__PURE__ */ jsxs(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true, children: [
|
|
@@ -10,6 +10,7 @@ import stdin_default$2 from "../Input/InputPassword.js";
|
|
|
10
10
|
import { Button } from "../Button/Button.styles.js";
|
|
11
11
|
import { Row, Column } from "../Grid/Grid.styles.js";
|
|
12
12
|
import { ComponentWrapper } from "../ComponentWrapper/ComponentWrapper.styles.js";
|
|
13
|
+
import { isPasswordValid, PASSWORD_REQUIREMENTS_MESSAGE } from "../../utils/password-validation.js";
|
|
13
14
|
import { ModalInner, ModalLinkWrap, ModalLink } from "../Modal/Modal.styles.js";
|
|
14
15
|
import { FormField, FormError } from "../Form/Form.styles.js";
|
|
15
16
|
const ResetPasswordModal = ({
|
|
@@ -26,7 +27,11 @@ const ResetPasswordModal = ({
|
|
|
26
27
|
confirmPassword: ""
|
|
27
28
|
};
|
|
28
29
|
const validationSchema = Yup.object().shape({
|
|
29
|
-
password: Yup.string().
|
|
30
|
+
password: Yup.string().test("password-full", function(val) {
|
|
31
|
+
if (!val) return this.createError({ message: "Oops, this can’t be blank" });
|
|
32
|
+
if (!isPasswordValid(val)) return this.createError({ message: PASSWORD_REQUIREMENTS_MESSAGE });
|
|
33
|
+
return true;
|
|
34
|
+
}),
|
|
30
35
|
confirmPassword: Yup.string().required("Oops, this can‘t be blank")
|
|
31
36
|
});
|
|
32
37
|
useEffect(() => {
|
|
@@ -54,10 +59,10 @@ const ResetPasswordModal = ({
|
|
|
54
59
|
children: ({ values, errors, touched, handleBlur, setFieldValue, setFieldTouched }) => {
|
|
55
60
|
const onChangeWithTouch = (e) => {
|
|
56
61
|
const field = e.target;
|
|
57
|
-
setFieldValue(field.name, field.value,
|
|
58
|
-
setFieldTouched(field.name);
|
|
62
|
+
setFieldValue(field.name, field.value, true);
|
|
63
|
+
setFieldTouched(field.name, true, false);
|
|
59
64
|
};
|
|
60
|
-
const submitDisabled = values.password
|
|
65
|
+
const submitDisabled = !isPasswordValid(values.password) || values.password !== values.confirmPassword || isActionLoading === "resetPassword";
|
|
61
66
|
return /* @__PURE__ */ jsxs(stdin_default$1, { children: [
|
|
62
67
|
/* @__PURE__ */ jsx("br", {}),
|
|
63
68
|
/* @__PURE__ */ jsx("br", {}),
|
|
@@ -76,17 +81,11 @@ const ResetPasswordModal = ({
|
|
|
76
81
|
touched: !!touched.password,
|
|
77
82
|
info: "For a stronger password, try a mix of lowercase, capitals, numbers and special characters.",
|
|
78
83
|
autoComplete: "new-password",
|
|
79
|
-
"data-cy": "reset-password-modal-password-input"
|
|
84
|
+
"data-cy": "reset-password-modal-password-input",
|
|
85
|
+
showStrength: true
|
|
80
86
|
}
|
|
81
87
|
),
|
|
82
|
-
/* @__PURE__ */ jsx(FormError, { show: errors.password && touched.password, children: errors.password })
|
|
83
|
-
/* @__PURE__ */ jsx(
|
|
84
|
-
FormError,
|
|
85
|
-
{
|
|
86
|
-
show: !errors.password && touched.password && values.password.length <= 5,
|
|
87
|
-
children: "The password must be at least 6 characters long"
|
|
88
|
-
}
|
|
89
|
-
)
|
|
88
|
+
/* @__PURE__ */ jsx(FormError, { show: errors.password && touched.password, children: errors.password })
|
|
90
89
|
] }) }),
|
|
91
90
|
/* @__PURE__ */ jsx("br", {}),
|
|
92
91
|
/* @__PURE__ */ jsx(ComponentWrapper, { noPadding: true, children: /* @__PURE__ */ jsxs(FormField, { children: [
|
package/dist/index.js
CHANGED
|
@@ -132,6 +132,7 @@ import { cooldownHOC, useComponentVisible, useContainerSize, useCooldown, useMob
|
|
|
132
132
|
import { fixDecimals } from "./utils/fix-decimals.js";
|
|
133
133
|
import { CURRENCY_CONFIG, formatCurrencyValue, getCurrencyConfig, getCurrencyIcon, getCurrencySymbol, getLiquidAssetIcon, getProjectCurrencySign } from "./utils/formatCurrencyValue.js";
|
|
134
134
|
import { isUSInvestor, usCountries } from "./utils/isUSInvestor.js";
|
|
135
|
+
import { ENTROPY_MEDIUM, ENTROPY_WEAK, PASSWORD_MIN_LENGTH, PASSWORD_REQUIREMENTS_MESSAGE, getPasswordCriteria, getPasswordEntropy, isPasswordValid } from "./utils/password-validation.js";
|
|
135
136
|
import { km_ify } from "./utils/km_ify.js";
|
|
136
137
|
import { momentUtils } from "./utils/moment.js";
|
|
137
138
|
import { openFile, saveAs } from "./utils/saveAs.js";
|
|
@@ -331,6 +332,8 @@ export {
|
|
|
331
332
|
default14 as DocumentSmallSvg,
|
|
332
333
|
default15 as DocumentSvg,
|
|
333
334
|
DoubleButtons,
|
|
335
|
+
ENTROPY_MEDIUM,
|
|
336
|
+
ENTROPY_WEAK,
|
|
334
337
|
default16 as Enable2FAFlow,
|
|
335
338
|
default17 as EnterCode,
|
|
336
339
|
ErrorMessage,
|
|
@@ -448,6 +451,8 @@ export {
|
|
|
448
451
|
OptionLabel,
|
|
449
452
|
OtpInput,
|
|
450
453
|
Outer,
|
|
454
|
+
PASSWORD_MIN_LENGTH,
|
|
455
|
+
PASSWORD_REQUIREMENTS_MESSAGE,
|
|
451
456
|
PHONE_MEDIA,
|
|
452
457
|
PageTransition,
|
|
453
458
|
PageWrapper,
|
|
@@ -620,6 +625,8 @@ export {
|
|
|
620
625
|
getFooterGroups,
|
|
621
626
|
getLiquidAssetIcon,
|
|
622
627
|
getMedia,
|
|
628
|
+
getPasswordCriteria,
|
|
629
|
+
getPasswordEntropy,
|
|
623
630
|
getProjectCurrencySign,
|
|
624
631
|
getTokenBucket,
|
|
625
632
|
getVerifyIdentityChecklist,
|
|
@@ -631,6 +638,7 @@ export {
|
|
|
631
638
|
isAccountLockedError,
|
|
632
639
|
isAlreadyOnOnboardingFlow,
|
|
633
640
|
isExternalUrl,
|
|
641
|
+
isPasswordValid,
|
|
634
642
|
isUSInvestor,
|
|
635
643
|
km_ify,
|
|
636
644
|
learnMoreCategoryPropTypes,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const PASSWORD_MIN_LENGTH = 8;
|
|
2
|
+
const PASSWORD_REQUIREMENTS_MESSAGE = "Use at least 8 characters with a mix of letters, numbers, and symbols.";
|
|
3
|
+
const ENTROPY_WEAK = 50;
|
|
4
|
+
const ENTROPY_MEDIUM = 80;
|
|
5
|
+
const getCharsetSize = (password) => {
|
|
6
|
+
let size = 0;
|
|
7
|
+
if (/[a-z]/.test(password)) size += 26;
|
|
8
|
+
if (/[A-Z]/.test(password)) size += 26;
|
|
9
|
+
if (/[0-9]/.test(password)) size += 10;
|
|
10
|
+
if (/[^A-Za-z0-9]/.test(password)) size += 32;
|
|
11
|
+
return size;
|
|
12
|
+
};
|
|
13
|
+
const getPasswordEntropy = (value) => {
|
|
14
|
+
const password = value || "";
|
|
15
|
+
if (password.length === 0) return 0;
|
|
16
|
+
const charsetSize = getCharsetSize(password);
|
|
17
|
+
const uniqueChars = new Set(password).size;
|
|
18
|
+
const effectiveLength = (password.length + uniqueChars) / 2;
|
|
19
|
+
return effectiveLength * Math.log2(charsetSize);
|
|
20
|
+
};
|
|
21
|
+
const getPasswordCriteria = (value) => {
|
|
22
|
+
const password = value || "";
|
|
23
|
+
const hasLowercase = /[a-z]/.test(password);
|
|
24
|
+
const hasUppercase = /[A-Z]/.test(password);
|
|
25
|
+
const hasNumber = /[0-9]/.test(password);
|
|
26
|
+
const hasSpecial = /[^A-Za-z0-9]/.test(password);
|
|
27
|
+
return {
|
|
28
|
+
length: password.length,
|
|
29
|
+
hasLength: password.length >= PASSWORD_MIN_LENGTH,
|
|
30
|
+
hasLowercase,
|
|
31
|
+
hasUppercase,
|
|
32
|
+
hasNumber,
|
|
33
|
+
hasSpecial,
|
|
34
|
+
classesMet: [hasLowercase, hasUppercase, hasNumber, hasSpecial].filter(Boolean).length
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const isPasswordValid = (value) => {
|
|
38
|
+
const password = value || "";
|
|
39
|
+
return password.length >= PASSWORD_MIN_LENGTH && getPasswordEntropy(password) >= ENTROPY_WEAK;
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
ENTROPY_MEDIUM,
|
|
43
|
+
ENTROPY_WEAK,
|
|
44
|
+
PASSWORD_MIN_LENGTH,
|
|
45
|
+
PASSWORD_REQUIREMENTS_MESSAGE,
|
|
46
|
+
getPasswordCriteria,
|
|
47
|
+
getPasswordEntropy,
|
|
48
|
+
isPasswordValid
|
|
49
|
+
};
|