Set max password length (100 chars) to help prevent DDOS attack

This commit is contained in:
Joel Biddle
2023-08-22 14:05:00 +10:00
parent 5b342409e3
commit 534d96ffb6
7 changed files with 69 additions and 37 deletions

View File

@@ -231,10 +231,11 @@
"current": "Current password",
"current-wrong": "The current password may be wrong",
"new": "New password",
"validate-base": "Password should contain at least:",
"validate-length": "14 characters",
"validate-case": "1 lowercase character",
"validate-number": "1 number"
"validate-base": "Password should contain:",
"validate-too-short": "at least 14 characters",
"validate-too-long": "at most 100 characters",
"validate-case": "at least 1 lowercase character",
"validate-number": "at least 1 number"
},
"token": {
"service-tokens": "Service Tokens",

View File

@@ -215,10 +215,11 @@
"current": "Mot de passe actuel",
"current-wrong": "Le mot de passe actuel peut être érroné",
"new": "Nouveau mot de passe",
"validate-base": "Le mot de passe doit contenir au moins:",
"validate-length": "14 caractères",
"validate-case": "1 caractère miniscule",
"validate-number": "1 chiffre"
"validate-base": "Le mot de passe doit contenir:",
"validate-too-short": "au moins 14 caractères",
"validate-too-long": "au maximum 100 caractères",
"validate-case": "au moins 1 caractère miniscule",
"validate-number": "au moins 1 chiffre"
},
"token": {
"service-tokens": "Jetons de service",

View File

@@ -39,7 +39,8 @@ interface UserInfoStepProps {
}
type Errors = {
length?: string,
tooShort?: string,
tooLong?: string,
upperCase?: string,
lowerCase?: string,
number?: string,

View File

@@ -2,7 +2,8 @@
interface PasswordCheckProps {
password: string;
errorCheck: boolean;
setPasswordErrorLength: (value: boolean) => void;
setPasswordErrorTooShort: (value: boolean) => void;
setPasswordErrorTooLong: (value: boolean) => void;
setPasswordErrorNumber: (value: boolean) => void;
setPasswordErrorLowerCase: (value: boolean) => void;
}
@@ -12,17 +13,25 @@ interface PasswordCheckProps {
*/
const passwordCheck = ({
password,
setPasswordErrorLength,
setPasswordErrorTooShort,
setPasswordErrorNumber,
setPasswordErrorLowerCase,
setPasswordErrorTooLong,
errorCheck
}: PasswordCheckProps) => {
if (!password || password.length < 14) {
setPasswordErrorLength(true);
setPasswordErrorTooShort(true);
errorCheck = true;
} else {
setPasswordErrorLength(false);
setPasswordErrorTooShort(false);
}
if (password.length > 100) {
setPasswordErrorTooLong(true);
errorCheck = true;
} else {
setPasswordErrorTooLong(false);
}
if (!/\d/.test(password)) {

View File

@@ -1,5 +1,6 @@
type Errors = {
length?: string,
tooShort?: string,
tooLong?: string,
upperCase?: string,
lowerCase?: string,
number?: string,
@@ -15,11 +16,12 @@ interface CheckPasswordParams {
}
/**
* 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)
* Validate that the password [password]:
* - Contains at least 14 characters long
* - Contains at most 100 characters long
* - Contains at least 1 uppercase character (A-Z)
* - Contains at least 1 lowercase character (a-z)
* - Contains at least 1 number (0-9)
* - Does not contain 3 repeat, consecutive characters
*
* The function returns whether or not the password [password]
@@ -37,24 +39,28 @@ const checkPassword = ({
}: CheckPasswordParams): boolean => {
const errors: Errors = {};
if (password.length < 8) {
errors.length = "8 characters";
if (password.length < 14) {
errors.tooShort = "at least 14 characters";
}
if (password.length > 100) {
errors.tooLong = "at most 100 characters";
}
if (!/[A-Z]/.test(password)) {
errors.upperCase = "1 uppercase character (A-Z)";
errors.upperCase = "at least 1 uppercase character (A-Z)";
}
if (!/[a-z]/.test(password)) {
errors.lowerCase = "1 lowercase character (a-z)";
errors.lowerCase = "at least 1 lowercase character (a-z)";
}
if (!/[0-9]/.test(password)) {
errors.number = "1 number (0-9)";
errors.number = "at least 1 number (0-9)";
}
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
errors.specialChar = "1 special character (!@#$%^&*(),.?)";
errors.specialChar = "at least 1 special character (!@#$%^&*(),.?)";
}
if (/([A-Za-z0-9])\1\1\1/.test(password)) {

View File

@@ -28,7 +28,8 @@ export default function PasswordReset() {
const [privateKey, setPrivateKey] = useState("");
const [newPassword, setNewPassword] = useState("");
const [backupKeyError, setBackupKeyError] = useState(false);
const [passwordErrorLength, setPasswordErrorLength] = useState(false);
const [passwordErrorTooShort, setPasswordErrorTooShort] = useState(false);
const [passwordErrorTooLong, setPasswordErrorTooLong] = useState(false);
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
@@ -67,7 +68,8 @@ export default function PasswordReset() {
e.preventDefault();
const errorCheck = passwordCheck({
password: newPassword,
setPasswordErrorLength,
setPasswordErrorTooShort,
setPasswordErrorTooLong,
setPasswordErrorNumber,
setPasswordErrorLowerCase,
errorCheck: false
@@ -221,7 +223,8 @@ export default function PasswordReset() {
setNewPassword(password);
passwordCheck({
password,
setPasswordErrorLength,
setPasswordErrorTooShort,
setPasswordErrorTooLong,
setPasswordErrorNumber,
setPasswordErrorLowerCase,
errorCheck: false
@@ -230,22 +233,32 @@ export default function PasswordReset() {
type="password"
value={newPassword}
isRequired
error={passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber}
error={passwordErrorTooShort && passwordErrorTooLong && passwordErrorLowerCase && passwordErrorNumber}
autoComplete="new-password"
id="new-password"
/>
</div>
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
{passwordErrorTooShort || passwordErrorTooLong || passwordErrorLowerCase || passwordErrorNumber ? (
<div className="mx-2 mt-3 mb-2 flex w-full max-w-md flex-col items-start rounded-md bg-white/5 px-2 py-2">
<div className="mb-1 text-sm text-gray-400">Password should contain at least:</div>
<div className="mb-1 text-sm text-gray-400">Password should contain:</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorLength ? (
{passwordErrorTooShort ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>
14 characters
<div className={`${passwordErrorTooShort ? "text-gray-400" : "text-gray-600"} text-sm`}>
at least 14 characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorTooLong ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div className={`${passwordErrorTooLong ? "text-gray-400" : "text-gray-600"} text-sm`}>
at most 100 characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
@@ -257,7 +270,7 @@ export default function PasswordReset() {
<div
className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}
>
1 lowercase character
at least 1 lowercase character
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
@@ -267,7 +280,7 @@ export default function PasswordReset() {
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>
1 number
at least 1 number
</div>
</div>
</div>

View File

@@ -18,7 +18,8 @@ import { useUser } from "@app/context";
import { useGetCommonPasswords } from "@app/hooks/api";
type Errors = {
length?: string,
tooShort?: string,
tooLong?: string,
upperCase?: string,
lowerCase?: string,
number?: string,