diff --git a/packages/libraries/main/src/matcher/dictionary/variants/matching/l33t.ts b/packages/libraries/main/src/matcher/dictionary/variants/matching/l33t.ts index aac0a80a..ab88929a 100644 --- a/packages/libraries/main/src/matcher/dictionary/variants/matching/l33t.ts +++ b/packages/libraries/main/src/matcher/dictionary/variants/matching/l33t.ts @@ -76,17 +76,14 @@ class MatchL33t { zxcvbnOptions.trieNodeRoot, ) let hasFullMatch = false - let isFullSubstitution = true subbedPasswords.forEach((subbedPassword) => { if (hasFullMatch) { return } const matchedDictionary = this.defaultMatch({ password: subbedPassword.password, - useLevenshtein: isFullSubstitution, + useLevenshtein: subbedPassword.isFullSubstitution, }) - // only the first entry has a full substitution - isFullSubstitution = false matchedDictionary.forEach((match: DictionaryMatch) => { if (!hasFullMatch) { hasFullMatch = match.i === 0 && match.j === password.length - 1 diff --git a/packages/libraries/main/src/matcher/dictionary/variants/matching/unmunger/getCleanPasswords.ts b/packages/libraries/main/src/matcher/dictionary/variants/matching/unmunger/getCleanPasswords.ts index fdf33fbc..45bc77c7 100644 --- a/packages/libraries/main/src/matcher/dictionary/variants/matching/unmunger/getCleanPasswords.ts +++ b/packages/libraries/main/src/matcher/dictionary/variants/matching/unmunger/getCleanPasswords.ts @@ -16,6 +16,7 @@ export type IndexedPasswordChanges = PasswordChanges & { i: number } export interface PasswordWithSubs { password: string changes: IndexedPasswordChanges[] + isFullSubstitution: boolean } interface HelperOptions { @@ -75,7 +76,7 @@ class CleanPasswords { if (index === this.substr.length) { if (onlyFullSub === isFullSub) { - this.finalPasswords.push({ password: this.buffer.join(''), changes }) + this.finalPasswords.push({ password: this.buffer.join(''), changes, isFullSubstitution: onlyFullSub }) } return } @@ -87,38 +88,39 @@ class CleanPasswords { // iterate backward to get wider substitutions first for (let i = index + nodes.length - 1; i >= index; i -= 1) { const cur = nodes[i - index] + const sub = cur.parents.join('') if (cur.isTerminal()) { // Skip if this would be a 4th or more consecutive substitution of the same letter // this should work in all language as there shouldn't be the same letter more than four times in a row // So we can ignore the rest to save calculation time if ( - lastSubLetter === cur.parents.join('') && + lastSubLetter === sub && consecutiveSubCount >= 3 ) { // eslint-disable-next-line no-continue continue } hasSubs = true - const subs = cur.subs! + const letters = cur.subs! // eslint-disable-next-line no-restricted-syntax - for (const sub of subs) { - this.buffer.push(sub) + for (const letter of letters) { + this.buffer.push(letter) const newSubs = changes.concat({ i: subIndex, - letter: sub, - substitution: cur.parents.join(''), + letter, + substitution: sub, }) // recursively build the rest of the string this.helper({ onlyFullSub, isFullSub, - index: i + 1, - subIndex: subIndex + sub.length, + index: index + sub.length, + subIndex: subIndex + letter.length, changes: newSubs, - lastSubLetter: cur.parents.join(''), + lastSubLetter: sub, consecutiveSubCount: - lastSubLetter === cur.parents.join('') + lastSubLetter === sub ? consecutiveSubCount + 1 : 1, }) diff --git a/packages/libraries/main/test/matcher/dictionary/variant/matching/unmunger/__snapshots__/getCleanPasswords.spec.ts.snap b/packages/libraries/main/test/matcher/dictionary/variant/matching/unmunger/__snapshots__/getCleanPasswords.spec.ts.snap index f7cffeee..68a05050 100644 --- a/packages/libraries/main/test/matcher/dictionary/variant/matching/unmunger/__snapshots__/getCleanPasswords.spec.ts.snap +++ b/packages/libraries/main/test/matcher/dictionary/variant/matching/unmunger/__snapshots__/getCleanPasswords.spec.ts.snap @@ -25,6 +25,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": true, "password": "Pau$mard", }, { @@ -45,6 +46,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "nn", }, ], + "isFullSubstitution": false, "password": "Pau$m4rd", }, { @@ -65,6 +67,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "Pau$nnard", }, { @@ -80,6 +83,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "|_|", }, ], + "isFullSubstitution": false, "password": "Pau$nn4rd", }, { @@ -100,6 +104,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "Pa|_|$mard", }, { @@ -115,6 +120,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "nn", }, ], + "isFullSubstitution": false, "password": "Pa|_|$m4rd", }, { @@ -130,6 +136,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "Pa|_|$nnard", }, { @@ -140,6 +147,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "Pa|_|$nn4rd", }, { @@ -160,6 +168,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "P4u$mard", }, { @@ -175,6 +184,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "nn", }, ], + "isFullSubstitution": false, "password": "P4u$m4rd", }, { @@ -190,6 +200,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "P4u$nnard", }, { @@ -200,6 +211,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "|_|", }, ], + "isFullSubstitution": false, "password": "P4u$nn4rd", }, { @@ -215,6 +227,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "P4|_|$mard", }, { @@ -225,6 +238,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "nn", }, ], + "isFullSubstitution": false, "password": "P4|_|$m4rd", }, { @@ -235,10 +249,12 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = ` "substitution": "4", }, ], + "isFullSubstitution": false, "password": "P4|_|$nnard", }, { "changes": [], + "isFullSubstitution": false, "password": "P4|_|$nn4rd", }, ] @@ -254,6 +270,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = ` "substitution": "vv", }, ], + "isFullSubstitution": true, "password": "w", }, { @@ -269,6 +286,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = ` "substitution": "v", }, ], + "isFullSubstitution": true, "password": "ff", }, { @@ -284,6 +302,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = ` "substitution": "v", }, ], + "isFullSubstitution": true, "password": "fu", }, ] @@ -304,6 +323,7 @@ exports[`getCleanPasswords should substitute to multiple symbols correctly 1`] = "substitution": "fi", }, ], + "isFullSubstitution": true, "password": "pacific", }, { @@ -314,6 +334,7 @@ exports[`getCleanPasswords should substitute to multiple symbols correctly 1`] = "substitution": "@", }, ], + "isFullSubstitution": false, "password": "pacific", }, { @@ -324,10 +345,12 @@ exports[`getCleanPasswords should substitute to multiple symbols correctly 1`] = "substitution": "fi", }, ], + "isFullSubstitution": false, "password": "p@cific", }, { "changes": [], + "isFullSubstitution": false, "password": "p@cific", }, ] @@ -343,6 +366,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "vv", }, ], + "isFullSubstitution": true, "password": "w", }, { @@ -358,6 +382,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": true, "password": "ff", }, { @@ -373,6 +398,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": true, "password": "fu", }, { @@ -388,6 +414,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": true, "password": "uf", }, { @@ -403,6 +430,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": true, "password": "uu", }, { @@ -413,6 +441,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": false, "password": "fv", }, { @@ -423,6 +452,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": false, "password": "uv", }, { @@ -433,6 +463,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": false, "password": "vf", }, { @@ -443,10 +474,12 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`] "substitution": "v", }, ], + "isFullSubstitution": false, "password": "vu", }, { "changes": [], + "isFullSubstitution": false, "password": "vv", }, ]