Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Canceled after 0s
102 lines
3.0 KiB
Plaintext
102 lines
3.0 KiB
Plaintext
import {
|
|
MIN_SUBMATCH_GUESSES_SINGLE_CHAR,
|
|
MIN_SUBMATCH_GUESSES_MULTI_CHAR,
|
|
} from '../data/const'
|
|
import utils from './utils'
|
|
import Options from '../Options'
|
|
import {
|
|
DefaultScoringFunction,
|
|
DictionaryScoringExtras,
|
|
MatchEstimated,
|
|
MatchExtended,
|
|
} from '../types'
|
|
import bruteforceMatcher from '../matcher/bruteforce/scoring'
|
|
import dateMatcher from '../matcher/date/scoring'
|
|
import dictionaryMatcher from '../matcher/dictionary/scoring'
|
|
import regexMatcher from '../matcher/regex/scoring'
|
|
import repeatMatcher from '../matcher/repeat/scoring'
|
|
import sequenceMatcher from '../matcher/sequence/scoring'
|
|
import spatialMatcher from '../matcher/spatial/scoring'
|
|
import separatorMatcher from '../matcher/separator/scoring'
|
|
import wordSequenceMatcher from '../matcher/wordSequence/scoring'
|
|
|
|
const getMinGuesses = (
|
|
match: MatchExtended | MatchEstimated,
|
|
password: string,
|
|
) => {
|
|
let minGuesses = 1
|
|
if (match.token.length < password.length) {
|
|
if (match.token.length === 1) {
|
|
minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR
|
|
} else {
|
|
minGuesses = MIN_SUBMATCH_GUESSES_MULTI_CHAR
|
|
}
|
|
}
|
|
return minGuesses
|
|
}
|
|
|
|
type Matchers = Record<string, DefaultScoringFunction>
|
|
|
|
const matchers: Matchers = {
|
|
bruteforce: bruteforceMatcher,
|
|
date: dateMatcher,
|
|
dictionary: dictionaryMatcher,
|
|
regex: regexMatcher,
|
|
repeat: repeatMatcher,
|
|
sequence: sequenceMatcher,
|
|
spatial: spatialMatcher,
|
|
separator: separatorMatcher,
|
|
wordSequence: wordSequenceMatcher,
|
|
}
|
|
|
|
const getScoring = (
|
|
options: Options,
|
|
name: string,
|
|
match: MatchExtended | MatchEstimated,
|
|
) => {
|
|
if (matchers[name]) {
|
|
return matchers[name](match, options)
|
|
}
|
|
if (options.matchers[name] && 'scoring' in options.matchers[name]) {
|
|
return options.matchers[name].scoring(match, options)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// guess estimation -- one function per match pattern ---------------------------
|
|
// ------------------------------------------------------------------------------
|
|
|
|
export default (
|
|
options: Options,
|
|
match: MatchExtended | MatchEstimated,
|
|
password: string,
|
|
): MatchEstimated => {
|
|
const extraData: Partial<DictionaryScoringExtras> = {}
|
|
// a match's guess estimate doesn't change. cache it.
|
|
if ('guesses' in match && match.guesses != null) {
|
|
return match as MatchEstimated
|
|
}
|
|
|
|
const minGuesses = getMinGuesses(match, password)
|
|
|
|
const estimationResult = getScoring(options, match.pattern, match)
|
|
let guesses = 0
|
|
if (typeof estimationResult === 'number') {
|
|
guesses = estimationResult
|
|
} else if (match.pattern === 'dictionary') {
|
|
guesses = estimationResult.calculation
|
|
extraData.baseGuesses = estimationResult.baseGuesses
|
|
extraData.uppercaseVariations = estimationResult.uppercaseVariations
|
|
extraData.l33tVariations = estimationResult.l33tVariations
|
|
}
|
|
|
|
const matchGuesses = Math.max(guesses, minGuesses)
|
|
return {
|
|
...match,
|
|
...extraData,
|
|
guesses: matchGuesses,
|
|
guessesLog10: utils.log10(matchGuesses),
|
|
}
|
|
}
|