mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 05:09:43 +02:00
feat: Stronger password policy
This commit is contained in:
parent
9ef9c00040
commit
799f34ab68
7 changed files with 33 additions and 10 deletions
|
@ -7,6 +7,7 @@ import { useDidUpdate, usePrevious, useToggle } from '../../lib/hooks';
|
||||||
import { Input, Popup } from '../../lib/custom-ui';
|
import { Input, Popup } from '../../lib/custom-ui';
|
||||||
|
|
||||||
import { useForm } from '../../hooks';
|
import { useForm } from '../../hooks';
|
||||||
|
import { isPassword } from '../../utils/validator';
|
||||||
|
|
||||||
import styles from './UserPasswordEditStep.module.scss';
|
import styles from './UserPasswordEditStep.module.scss';
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ const UserPasswordEditStep = React.memo(
|
||||||
const currentPasswordField = useRef(null);
|
const currentPasswordField = useRef(null);
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
const handleSubmit = useCallback(() => {
|
||||||
if (!data.password) {
|
if (!data.password || !isPassword(data.password)) {
|
||||||
passwordField.current.select();
|
passwordField.current.select();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -112,14 +113,18 @@ const UserPasswordEditStep = React.memo(
|
||||||
)}
|
)}
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<div className={styles.text}>{t('common.newPassword')}</div>
|
<div className={styles.text}>{t('common.newPassword')}</div>
|
||||||
|
<div className={styles.field}>
|
||||||
<Input.Password
|
<Input.Password
|
||||||
fluid
|
fluid
|
||||||
ref={passwordField}
|
ref={passwordField}
|
||||||
name="password"
|
name="password"
|
||||||
value={data.password}
|
value={data.password}
|
||||||
className={styles.field}
|
|
||||||
onChange={handleFieldChange}
|
onChange={handleFieldChange}
|
||||||
/>
|
/>
|
||||||
|
<div className={styles.note}>
|
||||||
|
{t('common.mustBeAtLeast6CharactersLongAndContainAtLeastOneLetterAndNumber')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{usePasswordConfirmation && (
|
{usePasswordConfirmation && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.text}>{t('common.currentPassword')}</div>
|
<div className={styles.text}>{t('common.currentPassword')}</div>
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-top: 4px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
color: #444444;
|
color: #444444;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
|
@ -105,6 +105,8 @@ export default {
|
||||||
members: 'Members',
|
members: 'Members',
|
||||||
minutes: 'Minutes',
|
minutes: 'Minutes',
|
||||||
moveCard_title: 'Move Card',
|
moveCard_title: 'Move Card',
|
||||||
|
mustBeAtLeast6CharactersLongAndContainAtLeastOneLetterAndNumber:
|
||||||
|
'Must be at least 6 characters long and contain at least one letter and number',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
newEmail: 'New e-mail',
|
newEmail: 'New e-mail',
|
||||||
newPassword: 'New password',
|
newPassword: 'New password',
|
||||||
|
|
|
@ -100,6 +100,8 @@ export default {
|
||||||
members: 'Участники',
|
members: 'Участники',
|
||||||
minutes: 'Минуты',
|
minutes: 'Минуты',
|
||||||
moveCard: 'Перемещение карточки',
|
moveCard: 'Перемещение карточки',
|
||||||
|
mustBeAtLeast6CharactersLongAndContainAtLeastOneLetterAndNumber:
|
||||||
|
'Должен быть не менее 6 символов и содержать хотя бы одну букву и цифру',
|
||||||
name: 'Имя',
|
name: 'Имя',
|
||||||
newEmail: 'Новый e-mail',
|
newEmail: 'Новый e-mail',
|
||||||
newPassword: 'Новый пароль',
|
newPassword: 'Новый пароль',
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
const PASSWORD_REGEX = /^(?=.*[A-Za-z])(?=.*\d).+$/;
|
||||||
const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/;
|
const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/;
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
export const isPassword = (string) => {
|
||||||
|
return string.length >= 3 && PASSWORD_REGEX.test(string);
|
||||||
|
};
|
||||||
|
|
||||||
export const isUsername = (string) => {
|
export const isUsername = (string) => {
|
||||||
return string.length >= 3 && string.length <= 16 && USERNAME_REGEX.test(string);
|
return string.length >= 3 && string.length <= 16 && USERNAME_REGEX.test(string);
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,8 @@ module.exports = {
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
minLength: 6,
|
||||||
|
regex: /^(?=.*[A-Za-z])(?=.*\d).+$/,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
|
@ -18,6 +18,8 @@ module.exports = {
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
minLength: 6,
|
||||||
|
regex: /^(?=.*[A-Za-z])(?=.*\d).+$/,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
currentPassword: {
|
currentPassword: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue