Files
SnowLuma/.pnpm-store/v11/files/9f/0e78046a4e3e72529bb8b7d176657276b01a2a8d0d29c8408cd254516a84d2d27eabf506bb674f53063aa8457765fac1f29eced7ab84922543639b737f5810
TanTan 2a69b23b47
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
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

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),
}
}