Add check for most common passwords

This commit is contained in:
Tuan Dang
2023-06-07 00:06:35 +01:00
parent c5be497052
commit a8ed187443
9 changed files with 1547 additions and 6 deletions
@@ -1,5 +1,7 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import * as bigintConversion from 'bigint-conversion'; import * as bigintConversion from 'bigint-conversion';
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -224,6 +226,15 @@ export const logout = async (req: Request, res: Response) => {
}); });
}; };
export const getCommonPasswords = async (req: Request, res: Response) => {
const commonPasswords = fs.readFileSync(
path.resolve(__dirname, '../../data/' + 'common_passwords.txt'),
'utf8'
).split('\n');
return res.status(200).send(commonPasswords);
}
export const revokeAllSessions = async (req: Request, res: Response) => { export const revokeAllSessions = async (req: Request, res: Response) => {
await TokenVersion.updateMany({ await TokenVersion.updateMany({
user: req.user._id user: req.user._id
File diff suppressed because it is too large Load Diff
+7
View File
@@ -59,8 +59,15 @@ router.get(
authController.handleAuthProviderCallback, authController.handleAuthProviderCallback,
); );
router.get(
'/common-passwords',
authLimiter,
authController.getCommonPasswords
);
router.delete( router.delete(
'/sessions', '/sessions',
authLimiter,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AUTH_MODE_JWT]
}), }),
@@ -19,6 +19,7 @@ import { deriveArgonKey } from '../utilities/cryptography/crypto';
import { saveTokenToLocalStorage } from '../utilities/saveTokenToLocalStorage'; import { saveTokenToLocalStorage } from '../utilities/saveTokenToLocalStorage';
import SecurityClient from '../utilities/SecurityClient'; import SecurityClient from '../utilities/SecurityClient';
import { Button, Input } from '../v2'; import { Button, Input } from '../v2';
import { useGetCommonPasswords } from '@app/hooks/api';
// eslint-disable-next-line new-cap // eslint-disable-next-line new-cap
const client = new jsrp.client(); const client = new jsrp.client();
@@ -72,6 +73,7 @@ export default function UserInfoStep({
setAttributionSource, setAttributionSource,
providerAuthToken, providerAuthToken,
}: UserInfoStepProps): JSX.Element { }: UserInfoStepProps): JSX.Element {
const { data: commonPasswords } = useGetCommonPasswords();
const [nameError, setNameError] = useState(false); const [nameError, setNameError] = useState(false);
const [organizationNameError, setOrganizationNameError] = useState(false); const [organizationNameError, setOrganizationNameError] = useState(false);
const [passwordErrorLength, setPasswordErrorLength] = useState(false); const [passwordErrorLength, setPasswordErrorLength] = useState(false);
@@ -103,6 +105,7 @@ export default function UserInfoStep({
errorCheck = checkPassword({ errorCheck = checkPassword({
password, password,
commonPasswords,
setErrors setErrors
}); });
@@ -5,10 +5,12 @@ type Errors = {
number?: string, number?: string,
specialChar?: string, specialChar?: string,
repeatedChar?: string, repeatedChar?: string,
commonPassword?: string
}; };
interface CheckPasswordParams { interface CheckPasswordParams {
password: string; password: string;
commonPasswords: string[];
setErrors: (value: Errors) => void; setErrors: (value: Errors) => void;
} }
@@ -30,6 +32,7 @@ interface CheckPasswordParams {
*/ */
const checkPassword = ({ const checkPassword = ({
password, password,
commonPasswords,
setErrors setErrors
}: CheckPasswordParams): boolean => { }: CheckPasswordParams): boolean => {
let errors: Errors = {}; let errors: Errors = {};
@@ -58,6 +61,10 @@ const checkPassword = ({
errors.repeatedChar = "No 3 repeat, consecutive characters"; errors.repeatedChar = "No 3 repeat, consecutive characters";
} }
if (commonPasswords.includes(password)) {
errors.commonPassword = "No common passwords";
}
setErrors(errors); setErrors(errors);
return Object.keys(errors).length > 0; return Object.keys(errors).length > 0;
} }
+2 -1
View File
@@ -2,5 +2,6 @@ export {
useGetAuthToken, useGetAuthToken,
useSendMfaToken, useSendMfaToken,
useVerifyMfaToken, useVerifyMfaToken,
useRevokeAllSessions useRevokeAllSessions,
useGetCommonPasswords
} from './queries' } from './queries'
+10 -1
View File
@@ -10,7 +10,8 @@ import {
VerifyMfaTokenRes} from './types'; VerifyMfaTokenRes} from './types';
const authKeys = { const authKeys = {
getAuthToken: ['token'] as const getAuthToken: ['token'] as const,
commonPasswords: ['common-passwords'] as const
}; };
export const useSendMfaToken = () => { export const useSendMfaToken = () => {
@@ -58,3 +59,11 @@ export const useRevokeAllSessions = () => {
} }
}); });
} }
const fetchCommonPasswords = async () => {
const { data } = await apiRequest.get('/api/v1/auth/common-passwords');
return data || [];
};
export const useGetCommonPasswords = () =>
useQuery({ queryKey: authKeys.commonPasswords, queryFn: fetchCommonPasswords });
@@ -19,7 +19,8 @@ import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog';
import getAPIKeys from '../../api/apiKey/getAPIKeys'; import getAPIKeys from '../../api/apiKey/getAPIKeys';
import getUser from '../../api/user/getUser'; import getUser from '../../api/user/getUser';
import { import {
useRevokeAllSessions useRevokeAllSessions,
useGetCommonPasswords
} from '@app/hooks/api'; } from '@app/hooks/api';
type Errors = { type Errors = {
@@ -32,6 +33,7 @@ type Errors = {
}; };
export default function PersonalSettings() { export default function PersonalSettings() {
const { data: commonPasswords } = useGetCommonPasswords();
const [personalEmail, setPersonalEmail] = useState(''); const [personalEmail, setPersonalEmail] = useState('');
const [personalName, setPersonalName] = useState(''); const [personalName, setPersonalName] = useState('');
const [currentPasswordError, setCurrentPasswordError] = useState(false); const [currentPasswordError, setCurrentPasswordError] = useState(false);
@@ -168,6 +170,7 @@ export default function PersonalSettings() {
setNewPassword(password); setNewPassword(password);
checkPassword({ checkPassword({
password, password,
commonPasswords,
setErrors setErrors
}); });
}} }}
+5 -2
View File
@@ -17,7 +17,6 @@ import { encodeBase64 } from 'tweetnacl-util';
import Button from '@app/components/basic/buttons/Button'; import Button from '@app/components/basic/buttons/Button';
import InputField from '@app/components/basic/InputField'; import InputField from '@app/components/basic/InputField';
import attemptLogin from '@app/components/utilities/attemptLogin'; import attemptLogin from '@app/components/utilities/attemptLogin';
import passwordCheck from '@app/components/utilities/checks/PasswordCheck';
import checkPassword from '@app/components/utilities/checks/checkPassword'; import checkPassword from '@app/components/utilities/checks/checkPassword';
@@ -28,7 +27,9 @@ import { saveTokenToLocalStorage } from '@app/components/utilities/saveTokenToLo
import SecurityClient from '@app/components/utilities/SecurityClient'; import SecurityClient from '@app/components/utilities/SecurityClient';
import getOrganizations from '@app/pages/api/organization/getOrgs'; import getOrganizations from '@app/pages/api/organization/getOrgs';
import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects'; import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects';
import {
useGetCommonPasswords
} from '@app/hooks/api';
import completeAccountInformationSignupInvite from './api/auth/CompleteAccountInformationSignupInvite'; import completeAccountInformationSignupInvite from './api/auth/CompleteAccountInformationSignupInvite';
import verifySignupInvite from './api/auth/VerifySignupInvite'; import verifySignupInvite from './api/auth/VerifySignupInvite';
@@ -45,6 +46,7 @@ type Errors = {
}; };
export default function SignupInvite() { export default function SignupInvite() {
const { data: commonPasswords } = useGetCommonPasswords();
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [firstName, setFirstName] = useState(''); const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState(''); const [lastName, setLastName] = useState('');
@@ -81,6 +83,7 @@ export default function SignupInvite() {
errorCheck = checkPassword({ errorCheck = checkPassword({
password, password,
commonPasswords,
setErrors setErrors
}); });