Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(l33t): make sure all full subs use levenshtein #245

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type IndexedPasswordChanges = PasswordChanges & { i: number }
export interface PasswordWithSubs {
password: string
changes: IndexedPasswordChanges[]
isFullSubstitution: boolean
}

interface HelperOptions {
Expand Down Expand Up @@ -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
}
Expand All @@ -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,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": true,
"password": "Pau$mard",
},
{
Expand All @@ -45,6 +46,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "nn",
},
],
"isFullSubstitution": false,
"password": "Pau$m4rd",
},
{
Expand All @@ -65,6 +67,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "Pau$nnard",
},
{
Expand All @@ -80,6 +83,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "|_|",
},
],
"isFullSubstitution": false,
"password": "Pau$nn4rd",
},
{
Expand All @@ -100,6 +104,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "Pa|_|$mard",
},
{
Expand All @@ -115,6 +120,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "nn",
},
],
"isFullSubstitution": false,
"password": "Pa|_|$m4rd",
},
{
Expand All @@ -130,6 +136,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "Pa|_|$nnard",
},
{
Expand All @@ -140,6 +147,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "Pa|_|$nn4rd",
},
{
Expand All @@ -160,6 +168,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "P4u$mard",
},
{
Expand All @@ -175,6 +184,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "nn",
},
],
"isFullSubstitution": false,
"password": "P4u$m4rd",
},
{
Expand All @@ -190,6 +200,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "P4u$nnard",
},
{
Expand All @@ -200,6 +211,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "|_|",
},
],
"isFullSubstitution": false,
"password": "P4u$nn4rd",
},
{
Expand All @@ -215,6 +227,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "4",
},
],
"isFullSubstitution": false,
"password": "P4|_|$mard",
},
{
Expand All @@ -225,6 +238,7 @@ exports[`getCleanPasswords should get correct clean passwords 1`] = `
"substitution": "nn",
},
],
"isFullSubstitution": false,
"password": "P4|_|$m4rd",
},
{
Expand All @@ -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",
},
]
Expand All @@ -254,6 +270,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = `
"substitution": "vv",
},
],
"isFullSubstitution": true,
"password": "w",
},
{
Expand All @@ -269,6 +286,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = `
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "ff",
},
{
Expand All @@ -284,6 +302,7 @@ exports[`getCleanPasswords should limit the substitutions correctly 1`] = `
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "fu",
},
]
Expand All @@ -304,6 +323,7 @@ exports[`getCleanPasswords should substitute to multiple symbols correctly 1`] =
"substitution": "fi",
},
],
"isFullSubstitution": true,
"password": "pacific",
},
{
Expand All @@ -314,6 +334,7 @@ exports[`getCleanPasswords should substitute to multiple symbols correctly 1`] =
"substitution": "@",
},
],
"isFullSubstitution": false,
"password": "pacific",
},
{
Expand All @@ -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",
},
]
Expand All @@ -343,6 +366,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "vv",
},
],
"isFullSubstitution": true,
"password": "w",
},
{
Expand All @@ -358,6 +382,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "ff",
},
{
Expand All @@ -373,6 +398,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "fu",
},
{
Expand All @@ -388,6 +414,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "uf",
},
{
Expand All @@ -403,6 +430,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": true,
"password": "uu",
},
{
Expand All @@ -413,6 +441,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": false,
"password": "fv",
},
{
Expand All @@ -423,6 +452,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": false,
"password": "uv",
},
{
Expand All @@ -433,6 +463,7 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": false,
"password": "vf",
},
{
Expand All @@ -443,10 +474,12 @@ exports[`getCleanPasswords should substitute to multiple variants correctly 1`]
"substitution": "v",
},
],
"isFullSubstitution": false,
"password": "vu",
},
{
"changes": [],
"isFullSubstitution": false,
"password": "vv",
},
]
Expand Down
Loading