diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/version-2.x/authentication-and-access-control/password-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/version-2.x/authentication-and-access-control/password-management.md index a2ec2f2de7..3dbc94228c 100644 --- a/docs/i18n/es/docusaurus-plugin-content-docs/version-2.x/authentication-and-access-control/password-management.md +++ b/docs/i18n/es/docusaurus-plugin-content-docs/version-2.x/authentication-and-access-control/password-management.md @@ -65,8 +65,19 @@ if (passwordHashNeedsToBeRefreshed(user.password)) { npm install @foal/password ``` -To prevent users from using very weak passwords such as `123456` or `password`, you can call the `isCommon` function. This utility checks if the given password is part of the 10000 most common passwords listed [here](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-10000.txt). +To prevent users from using very weak passwords such as `123456` or `password`, you can call the `isCommon` function. This utility checks if the given password is part of the most common passwords listed [here](https://github.com/danielmiessler/SecLists/tree/master/Passwords/Common-Credentials). +Example 1: Check if the given password is part of the `10,000 most common passwords list`. ```typescript const isPasswordTooCommon = await isCommon(password); -``` \ No newline at end of file +``` + +Example 2: Check if the given password is part of the `10,000 most common passwords list`. +```typescript +const isPasswordTooCommon = await isCommon(password, 'TenMillionListTop10k'); +``` + +Example 3: Check if the given password is part of the `100,000 most common passwords list`. +```typescript +const isPasswordTooCommon = await isCommon(password, 'TenMillionListTop100k'); +``` diff --git a/packages/password/DATASOURCES.md b/packages/password/DATASOURCES.md new file mode 100644 index 0000000000..fb61503e25 --- /dev/null +++ b/packages/password/DATASOURCES.md @@ -0,0 +1,4 @@ +# DataSources origin + +* https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-10000.txt +* https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-100000.txt diff --git a/packages/password/src/10-million-password-list-top-100000.txt.gz b/packages/password/src/10-million-password-list-top-100000.txt.gz new file mode 100644 index 0000000000..5a1f946f95 Binary files /dev/null and b/packages/password/src/10-million-password-list-top-100000.txt.gz differ diff --git a/packages/password/src/common-password-datasource.ts b/packages/password/src/common-password-datasource.ts new file mode 100644 index 0000000000..c603683d93 --- /dev/null +++ b/packages/password/src/common-password-datasource.ts @@ -0,0 +1 @@ +export type CommonPasswordDataSource = 'TenMillionListTop10k' | 'TenMillionListTop100k'; \ No newline at end of file diff --git a/packages/password/src/is-common.util.spec.ts b/packages/password/src/is-common.util.spec.ts index 0784cd6ad6..1063f9e38e 100644 --- a/packages/password/src/is-common.util.spec.ts +++ b/packages/password/src/is-common.util.spec.ts @@ -2,16 +2,43 @@ import { strictEqual } from 'assert'; // 3p -import { isCommon } from './is-common.util'; +import { clearCommonPasswordsCache, isCommon } from './is-common.util'; -describe('isCommon', () => { - - it('should return true if the given password is part of the 10000 most common passwords.', async () => { - strictEqual(await isCommon('12345'), true); +describe('isCommon util', () => { + describe('isCommon', () => { + describe('default datasource', () => { + it('should return true if the given password is part of the 10000 most common passwords.', async () => { + strictEqual(await isCommon('12345'), true); + }); + it('should return false if the given password is not part of the 10000 most common passwords.', async () => { + strictEqual(await isCommon('a bird in the sky'), false); + }); + }); + describe('10k datasource', () => { + it('should return true if the given password is part of the 100000 most common passwords.', async () => { + strictEqual(await isCommon('12345', 'TenMillionListTop10k'), true); + }); + it('should return false if the given password is not part of the 100000 most common passwords.', async () => { + strictEqual(await isCommon('a bird in the sky', 'TenMillionListTop10k'), false); + }); + }); + describe('100k datasource', () => { + it('should return true if the given password is part of the 100000 most common passwords.', async () => { + strictEqual(await isCommon('Cinder', 'TenMillionListTop100k'), true); + }); + it('should return false if the given password is not part of the 100000 most common passwords.', async () => { + strictEqual(await isCommon('a bird in the sky', 'TenMillionListTop100k'), false); + }); + }); }); - it('should return false if the given password is not part of the 10000 most common passwords.', async () => { - strictEqual(await isCommon('a bird in the sky'), false); + describe('clearCommonPasswordsCache', () => { + it('should not fail if it is empty', () => { + clearCommonPasswordsCache(); + }); + it('should not fail if it is full', async () => { + await isCommon('12345', 'TenMillionListTop10k'); + clearCommonPasswordsCache(); + }); }); - }); diff --git a/packages/password/src/is-common.util.ts b/packages/password/src/is-common.util.ts index fe5c60ce31..51b95f0adc 100644 --- a/packages/password/src/is-common.util.ts +++ b/packages/password/src/is-common.util.ts @@ -3,20 +3,36 @@ import { readFile } from 'node:fs/promises'; import { join } from 'path'; import { promisify } from 'util'; import { gunzip, InputType } from 'zlib'; +import { CommonPasswordDataSource } from './common-password-datasource'; -let list: string[]; +const dataSourcesCache: Record = {}; + +const dataSources: Record = { + 'TenMillionListTop10k': '10-million-password-list-top-10000.txt.gz', + 'TenMillionListTop100k': '10-million-password-list-top-100000.txt.gz', +}; /** - * Test if a password belongs to a list of 10k common passwords. + * Test if a password belongs to a list of common passwords. * * @export * @param {string} password - The password to test. + * @param {CommonPasswordDataSource} database - Data source. * @returns {Promise} - True if the password is found in the list. False otherwise. */ -export async function isCommon(password: string): Promise { - if (!list) { - const fileContent = await readFile(join(__dirname, './10-million-password-list-top-10000.txt.gz')); - list = (await promisify(gunzip)(fileContent)).toString().split('\n'); +export async function isCommon(password: string, dataSource: CommonPasswordDataSource = 'TenMillionListTop10k'): Promise { + if (!dataSourcesCache[dataSource]) { + const file = dataSources[dataSource]; + const fileContent = await readFile(join(__dirname, './' + file)); + dataSourcesCache[dataSource] = (await promisify(gunzip)(fileContent)).toString().split('\n'); } - return list.includes(password); + + return dataSourcesCache[dataSource].includes(password); } + +/** + * Clear the common passwords cache. + */ +export function clearCommonPasswordsCache() { + Object.keys(dataSources).forEach(ds => delete dataSourcesCache[ds]); +} \ No newline at end of file