From 6e8d4f950bf0e26ea2709f6c3584aa3e038edeba Mon Sep 17 00:00:00 2001 From: ngn Date: Mon, 12 Jun 2023 22:02:12 +0300 Subject: [PATCH 01/10] Implemented password strength check --- assets/locales/ur/auth.json | 2 +- src/api/routes/auth/register.ts | 14 ++---- src/api/util/utility/passwordStrength.ts | 44 +++++++++++-------- .../subconfigurations/register/Password.ts | 5 +-- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/assets/locales/ur/auth.json b/assets/locales/ur/auth.json index 1dac24744..022bb663c 100644 --- a/assets/locales/ur/auth.json +++ b/assets/locales/ur/auth.json @@ -10,7 +10,7 @@ "EMAIL_INVALID": "Invalid Email", "EMAIL_ALREADY_REGISTERED": "Email is already registered", "DATE_OF_BIRTH_UNDERAGE": "You need to be {{years}} years or older", - "PASSWORD_REQUIREMENTS_MIN_LENGTH": "Must be at least {{min}} characters long.", + "PASSWORD_BAD_PASSWORD": "Password is too weak or common to use.", "CONSENT_REQUIRED": "You must agree to the Terms of Service and Privacy Policy.", "USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another" } diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts index 14dc319a8..513b20545 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts @@ -18,6 +18,7 @@ import { IPAnalysis, + checkPassword, getIpAdress, isProxy, route, @@ -159,7 +160,6 @@ router.post( } // TODO: gift_code_sku_id? - // TODO: check password strength if (email) { // replace all dots and chars after +, if its a gmail.com email @@ -225,17 +225,11 @@ router.post( } if (body.password) { - const min = register.password.minLength - ? register.password.minLength - : 8; - if (body.password.length < min) { + if(checkPassword(body.password) pw > 1 */ export function checkPassword(password: string): number { - const { minLength, minNumbers, minUpperCase, minSymbols } = + const { strength } = Config.get().register.password; - let strength = 0; + + let pwStrength = 0 // checks for total password len - if (password.length >= minLength - 1) { - strength += 0.05; + if (password.length >= 8 - 1) { + pwStrength += 0.05; } // checks for amount of Numbers - if (password.count(reNUMBER) >= minNumbers - 1) { - strength += 0.05; + const numbers = password.match(reNUMBER) + if (numbers && numbers.length >= 2 - 1) { + pwStrength += 0.05; } // checks for amount of Uppercase Letters - if (password.count(reUPPERCASELETTER) >= minUpperCase - 1) { - strength += 0.05; + const uppercase = password.match(reUPPER) + if (uppercase && uppercase.length >= 2 - 1) { + pwStrength += 0.05; } // checks for amount of symbols - if (password.replace(reSYMBOLS, "").length >= minSymbols - 1) { - strength += 0.05; + const symbols = password.match(reSYMBOLS) + if (symbols && symbols.length >= 2 - 1) { + pwStrength += 0.05; } // checks if password only consists of numbers or only consists of chars - if ( - password.length == password.count(reNUMBER) || - password.length === password.count(reUPPERCASELETTER) - ) { - strength = 0; - } + if (numbers && uppercase){ + if ( + password.length == numbers.length || + password.length === uppercase.length + ) { + pwStrength = 0; + } + } const entropyMap: { [key: string]: number } = {}; for (let i = 0; i < password.length; i++) { @@ -77,7 +83,7 @@ export function checkPassword(password: string): number { const entropies = Object.values(entropyMap); entropies.map((x) => x / entropyMap.length); - strength += + pwStrength += entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / Math.log2(password.length); return strength; diff --git a/src/util/config/types/subconfigurations/register/Password.ts b/src/util/config/types/subconfigurations/register/Password.ts index 36c3e3dc4..1790255f8 100644 --- a/src/util/config/types/subconfigurations/register/Password.ts +++ b/src/util/config/types/subconfigurations/register/Password.ts @@ -18,8 +18,5 @@ export class PasswordConfiguration { required: boolean = false; - minLength: number = 8; - minNumbers: number = 2; - minUpperCase: number = 2; - minSymbols: number = 0; + strength: number = 0.5; } From 1dccb2dbe4fcfc1d9ce470e4156a7960e7f068b2 Mon Sep 17 00:00:00 2001 From: ngn Date: Mon, 12 Jun 2023 22:04:33 +0300 Subject: [PATCH 02/10] made it prettier --- src/api/routes/auth/register.ts | 2 +- src/api/util/utility/passwordStrength.ts | 31 +++++++++---------- .../subconfigurations/register/Password.ts | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts index 513b20545..9854f459d 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts @@ -225,7 +225,7 @@ router.post( } if (body.password) { - if(checkPassword(body.password) pw > 1 */ export function checkPassword(password: string): number { - const { strength } = - Config.get().register.password; + const { strength } = Config.get().register.password; - let pwStrength = 0 + let pwStrength = 0; // checks for total password len if (password.length >= 8 - 1) { @@ -47,32 +46,32 @@ export function checkPassword(password: string): number { } // checks for amount of Numbers - const numbers = password.match(reNUMBER) - if (numbers && numbers.length >= 2 - 1) { + const numbers = password.match(reNUMBER); + if (numbers && numbers.length >= 2 - 1) { pwStrength += 0.05; } // checks for amount of Uppercase Letters - const uppercase = password.match(reUPPER) - if (uppercase && uppercase.length >= 2 - 1) { + const uppercase = password.match(reUPPER); + if (uppercase && uppercase.length >= 2 - 1) { pwStrength += 0.05; } // checks for amount of symbols - const symbols = password.match(reSYMBOLS) + const symbols = password.match(reSYMBOLS); if (symbols && symbols.length >= 2 - 1) { pwStrength += 0.05; } // checks if password only consists of numbers or only consists of chars - if (numbers && uppercase){ - if ( - password.length == numbers.length || - password.length === uppercase.length - ) { - pwStrength = 0; - } - } + if (numbers && uppercase) { + if ( + password.length == numbers.length || + password.length === uppercase.length + ) { + pwStrength = 0; + } + } const entropyMap: { [key: string]: number } = {}; for (let i = 0; i < password.length; i++) { diff --git a/src/util/config/types/subconfigurations/register/Password.ts b/src/util/config/types/subconfigurations/register/Password.ts index 1790255f8..4f0522bb2 100644 --- a/src/util/config/types/subconfigurations/register/Password.ts +++ b/src/util/config/types/subconfigurations/register/Password.ts @@ -18,5 +18,5 @@ export class PasswordConfiguration { required: boolean = false; - strength: number = 0.5; + strength: number = 0.5; } From 43ac5fb021433528f35d93674bc935499ee4b46f Mon Sep 17 00:00:00 2001 From: ngn <78868991+ngn13@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:24:02 +0300 Subject: [PATCH 03/10] fixing the return value --- src/api/util/utility/passwordStrength.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index fcfb40e19..3646a3f81 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -85,5 +85,5 @@ export function checkPassword(password: string): number { pwStrength += entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / Math.log2(password.length); - return strength; + return pwStrength; } From 314bb29396cf20a13a7f1986fd89d207bbac3986 Mon Sep 17 00:00:00 2001 From: ngn <78868991+ngn13@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:29:44 +0300 Subject: [PATCH 04/10] fixing the unnecessary calculations --- src/api/util/utility/passwordStrength.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 3646a3f81..3c78a108f 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -41,25 +41,25 @@ export function checkPassword(password: string): number { let pwStrength = 0; // checks for total password len - if (password.length >= 8 - 1) { + if (password.length >= 7) { pwStrength += 0.05; } // checks for amount of Numbers const numbers = password.match(reNUMBER); - if (numbers && numbers.length >= 2 - 1) { + if (numbers && numbers.length >= 1) { pwStrength += 0.05; } // checks for amount of Uppercase Letters const uppercase = password.match(reUPPER); - if (uppercase && uppercase.length >= 2 - 1) { + if (uppercase && uppercase.length >= 1) { pwStrength += 0.05; } // checks for amount of symbols const symbols = password.match(reSYMBOLS); - if (symbols && symbols.length >= 2 - 1) { + if (symbols && symbols.length >= 1) { pwStrength += 0.05; } From 15c2239b42c439f8a69001e6fc400ce8c4823b4e Mon Sep 17 00:00:00 2001 From: ngn Date: Wed, 14 Jun 2023 19:10:21 +0300 Subject: [PATCH 05/10] cleaning up and fixing checkPassword --- src/api/util/utility/passwordStrength.ts | 44 +++++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 3c78a108f..02d9c03f7 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -35,33 +35,29 @@ const reSYMBOLS = /[^a-zA-Z0-9\s]/g; * * Returns: 0 > pw > 1 */ -export function checkPassword(password: string): number { - const { strength } = Config.get().register.password; - let pwStrength = 0; +function calculateEntropy(str: string) { + // TODO: calculate the shannon entropy + return 0; +} + +export function checkPassword(password: string): number { + let strength = 0; // checks for total password len - if (password.length >= 7) { - pwStrength += 0.05; - } + if (password.length >= 7) strength += 0.2; - // checks for amount of Numbers + // checks for numbers const numbers = password.match(reNUMBER); - if (numbers && numbers.length >= 1) { - pwStrength += 0.05; - } + if (numbers) strength += 0.2; - // checks for amount of Uppercase Letters + // checks for uppercase Letters const uppercase = password.match(reUPPER); - if (uppercase && uppercase.length >= 1) { - pwStrength += 0.05; - } + if (uppercase) strength += 0.3; - // checks for amount of symbols + // checks for symbols const symbols = password.match(reSYMBOLS); - if (symbols && symbols.length >= 1) { - pwStrength += 0.05; - } + if (symbols) strength += 0.3; // checks if password only consists of numbers or only consists of chars if (numbers && uppercase) { @@ -69,10 +65,13 @@ export function checkPassword(password: string): number { password.length == numbers.length || password.length === uppercase.length ) { - pwStrength = 0; + strength = 0; } } + /* + * this seems to be broken + * const entropyMap: { [key: string]: number } = {}; for (let i = 0; i < password.length; i++) { if (entropyMap[password[i]]) entropyMap[password[i]]++; @@ -82,8 +81,11 @@ export function checkPassword(password: string): number { const entropies = Object.values(entropyMap); entropies.map((x) => x / entropyMap.length); - pwStrength += + strength += entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / Math.log2(password.length); - return pwStrength; + */ + + strength += calculateEntropy(password) + return strength; } From 0f86b30bcd29d09366c61f41a93714453fb82f51 Mon Sep 17 00:00:00 2001 From: ngn Date: Wed, 14 Jun 2023 19:17:12 +0300 Subject: [PATCH 06/10] made it prettier --- src/api/util/utility/passwordStrength.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 02d9c03f7..73b303597 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -86,6 +86,6 @@ export function checkPassword(password: string): number { Math.log2(password.length); */ - strength += calculateEntropy(password) + strength += calculateEntropy(password); return strength; } From a753b16e0b9a6e6e280b1633ddc41723ad89d5e0 Mon Sep 17 00:00:00 2001 From: Scott Gould Date: Mon, 1 Jan 2024 01:59:44 -0500 Subject: [PATCH 07/10] Actually calculate entropy Signed-off-by: Scott Gould --- src/api/util/utility/passwordStrength.ts | 58 ++++++++++++++++-------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 73b303597..c9dcabe8e 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -37,8 +37,40 @@ const reSYMBOLS = /[^a-zA-Z0-9\s]/g; */ function calculateEntropy(str: string) { - // TODO: calculate the shannon entropy - return 0; + // Initialize entropy to 0 + let entropy = 0; + + // Initialize a frequency array with 256 elements all set to 0 + // This array will hold the frequency of each character in the string + const frequency = new Array(256).fill(0); + + // Get the length of the string + const length = str.length; + + // Iterate over each character in the string + for (let i = 0; i < length; i++) { + // Increment the frequency of the current character + frequency[str.charCodeAt(i)]++; + } + + // Iterate over each possible character + for (let i = 0; i < 256; i++) { + // Calculate the probability of the current character + const p = frequency[i] / length; + + // If the character appears in the string (probability > 0) + // add its contribution to the entropy + if (p > 0) entropy -= p * Math.log2(p); + } + + // Normalize the entropy to the range [0, 1] + const MAX_ENTROPY_PER_CHAR = Math.log2(95); // Maximum entropy per character for all printable ASCII characters + const MAX_ENTROPY = MAX_ENTROPY_PER_CHAR * length; // Maximum possible entropy for the password + entropy = entropy / MAX_ENTROPY; + + + // Return the calculated entropy + return entropy; } export function checkPassword(password: string): number { @@ -69,23 +101,11 @@ export function checkPassword(password: string): number { } } - /* - * this seems to be broken - * - const entropyMap: { [key: string]: number } = {}; - for (let i = 0; i < password.length; i++) { - if (entropyMap[password[i]]) entropyMap[password[i]]++; - else entropyMap[password[i]] = 1; - } - - const entropies = Object.values(entropyMap); - - entropies.map((x) => x / entropyMap.length); - strength += - entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / - Math.log2(password.length); - */ - strength += calculateEntropy(password); + // Strength should between 0 and 1??? (am I wrong?) + // Normalize the strength score to the range [0, 1] + const MAX_STRENGTH = 2.0; // Maximum possible strength score + strength = strength / MAX_STRENGTH; + return strength; } From acc02a8255f5df98d53893c1716c87a37b65c24e Mon Sep 17 00:00:00 2001 From: Scott Gould Date: Mon, 1 Jan 2024 02:02:51 -0500 Subject: [PATCH 08/10] Fix formatting Signed-off-by: Scott Gould --- src/api/util/utility/passwordStrength.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index c9dcabe8e..1b68d13ad 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -63,12 +63,11 @@ function calculateEntropy(str: string) { if (p > 0) entropy -= p * Math.log2(p); } - // Normalize the entropy to the range [0, 1] - const MAX_ENTROPY_PER_CHAR = Math.log2(95); // Maximum entropy per character for all printable ASCII characters - const MAX_ENTROPY = MAX_ENTROPY_PER_CHAR * length; // Maximum possible entropy for the password - entropy = entropy / MAX_ENTROPY; + // Normalize the entropy to the range [0, 1] + const MAX_ENTROPY_PER_CHAR = Math.log2(95); // Maximum entropy per character for all printable ASCII characters + const MAX_ENTROPY = MAX_ENTROPY_PER_CHAR * length; // Maximum possible entropy for the password + entropy = entropy / MAX_ENTROPY; - // Return the calculated entropy return entropy; } From 63ef2a437bc83dec5377397cca3effc6e0d70b0c Mon Sep 17 00:00:00 2001 From: Scott Gould Date: Tue, 2 Jan 2024 02:10:59 -0500 Subject: [PATCH 09/10] Format with prettier --- src/api/util/utility/passwordStrength.ts | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 1b68d13ad..8f48a8178 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -47,28 +47,28 @@ function calculateEntropy(str: string) { // Get the length of the string const length = str.length; - // Iterate over each character in the string + // Iterate over each character in the string for (let i = 0; i < length; i++) { // Increment the frequency of the current character frequency[str.charCodeAt(i)]++; } - + // Iterate over each possible character - for (let i = 0; i < 256; i++) { - // Calculate the probability of the current character - const p = frequency[i] / length; + for (let i = 0; i < 256; i++) { + // Calculate the probability of the current character + const p = frequency[i] / length; - // If the character appears in the string (probability > 0) - // add its contribution to the entropy - if (p > 0) entropy -= p * Math.log2(p); - } + // If the character appears in the string (probability > 0) + // add its contribution to the entropy + if (p > 0) entropy -= p * Math.log2(p); + } // Normalize the entropy to the range [0, 1] - const MAX_ENTROPY_PER_CHAR = Math.log2(95); // Maximum entropy per character for all printable ASCII characters - const MAX_ENTROPY = MAX_ENTROPY_PER_CHAR * length; // Maximum possible entropy for the password - entropy = entropy / MAX_ENTROPY; + const MAX_ENTROPY_PER_CHAR = Math.log2(95); // Maximum entropy per character for all printable ASCII characters + const MAX_ENTROPY = MAX_ENTROPY_PER_CHAR * length; // Maximum possible entropy for the password + entropy = entropy / MAX_ENTROPY; - // Return the calculated entropy + // Return the calculated entropy return entropy; } @@ -102,9 +102,9 @@ export function checkPassword(password: string): number { strength += calculateEntropy(password); // Strength should between 0 and 1??? (am I wrong?) - // Normalize the strength score to the range [0, 1] - const MAX_STRENGTH = 2.0; // Maximum possible strength score - strength = strength / MAX_STRENGTH; + // Normalize the strength score to the range [0, 1] + const MAX_STRENGTH = 2.0; // Maximum possible strength score + strength = strength / MAX_STRENGTH; return strength; } From e12fae8abeac00039e39a16552b7bf031334b314 Mon Sep 17 00:00:00 2001 From: ngn <78868991+ngn13@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:48:39 +0000 Subject: [PATCH 10/10] removed strength normalization --- src/api/util/utility/passwordStrength.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index 8f48a8178..ac6eeca10 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -101,10 +101,5 @@ export function checkPassword(password: string): number { } strength += calculateEntropy(password); - // Strength should between 0 and 1??? (am I wrong?) - // Normalize the strength score to the range [0, 1] - const MAX_STRENGTH = 2.0; // Maximum possible strength score - strength = strength / MAX_STRENGTH; - return strength; }