2.2 KiB
repeat — repeated-chunk pattern matcher
(no submodules)
Purpose
Finds every maximal substring composed of a repeating chunk (e.g. aaaa,
abcabc, babababa) per Wheeler 2016 section 3.3. The chunk's strength is
estimated by recursively running mostGuessableMatchSequence on the chunk
itself with the same dictionary set — a password like passwordpassword
gets the dictionary's rank-1 strength times the repeat-count factor.
Features
- Detects single-character and multi-character repeats
- Picks the longer of greedy and lazy chunk candidates so the matcher does
not prefer
aafour times overaaaaonce - Recursive
baseGuessesviamostGuessableMatchSequence - Carries the recursive
baseMatchesso consumers can inspect the chunk's own cover
Usage: Basic Example
import { repeatMatch } from "@suaveplan/password-strength/matchers/repeat";
const matches = repeatMatch("aaaa", {});
console.log(matches[0].baseToken); // "a"
console.log(matches[0].repeatCount); // 4
Usage: Advanced Example
import { repeatMatch } from "@suaveplan/password-strength/matchers/repeat";
const dicts = { passwords: new Map([["password", 1]]) };
const matches = repeatMatch("passwordpassword", dicts);
for (const m of matches) {
console.log(m.baseToken, m.repeatCount, m.baseGuesses);
}
API Reference
repeatMatch(password: string, dictionaries: DictionarySet): RepeatMatch[]- Returns every maximal repeat-of-chunk substring. The dictionary set is threaded into the chunk's recursive scoring so dictionary words appearing inside the chunk inherit their rank.
Implementation Notes
The matcher runs both a greedy and a lazy chunk regex from each candidate start position and picks whichever produces the longer overall repeat. Greedy finds the longest possible chunk that still repeats at least once; lazy finds the smallest. Picking the longer span avoids over-fragmenting a real repeat into two adjacent shorter ones with the same characters. The recursive scoring call uses the dictionary and sequence matchers — recursive keyboard or date matching inside a chunk is rare in practice and intentionally excluded for performance under the 200-character DoS guard.