Files
SnowLuma/.pnpm-store/v11/files/73/16b9358d115751b81af76e6b79fc0eed662b4eaee301832bb23b631ac9f3a947583085d86737884d8f897834b4cdc2761c2a5d401e95fcd91b081b56bd632a
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

139 lines
4.2 KiB
Plaintext

const SECOND = 1;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const MONTH = DAY * 31;
const YEAR = MONTH * 12;
const CENTURY = YEAR * 100;
const times = {
second: SECOND,
minute: MINUTE,
hour: HOUR,
day: DAY,
month: MONTH,
year: YEAR,
century: CENTURY
};
const timeEstimationValuesDefaults = {
scoring: {
0: 1e3,
1: 1e6,
2: 1e8,
3: 1e10
},
attackTime: {
onlineThrottlingXPerHour: 100,
onlineNoThrottlingXPerSecond: 10,
offlineSlowHashingXPerSecond: 1e4,
offlineFastHashingXPerSecond: 1e10
}
};
const checkTimeEstimationValues = timeEstimationValues => {
Object.entries(timeEstimationValues).forEach(([key, data]) => {
Object.entries(data).forEach(([subKey, value]) => {
// @ts-expect-error for testing purposes
if (value < timeEstimationValuesDefaults[key][subKey]) {
throw new Error('Time estimation values are not to be allowed to be less than default');
}
});
});
};
/*
* -------------------------------------------------------------------------------
* Estimates time for an attacker ---------------------------------------------------------------
* -------------------------------------------------------------------------------
*/
class TimeEstimates {
constructor(options) {
this.options = options;
}
estimateAttackTimes(guesses) {
const crackTimesSeconds = this.calculateCrackTimesSeconds(guesses);
const crackTimes = {};
Object.keys(crackTimesSeconds).forEach(crackTime => {
const usedScenario = crackTime;
const seconds = crackTimesSeconds[usedScenario];
const {
base,
displayStr
} = this.displayTime(seconds);
crackTimes[usedScenario] = {
base,
seconds,
display: this.translate(displayStr, base)
};
});
return {
crackTimes,
score: this.guessesToScore(guesses)
};
}
calculateCrackTimesSeconds(guesses) {
const attackTimesOptions = this.options.timeEstimationValues.attackTime;
return {
onlineThrottlingXPerHour: guesses / (attackTimesOptions.onlineThrottlingXPerHour / 3600),
onlineNoThrottlingXPerSecond: guesses / attackTimesOptions.onlineNoThrottlingXPerSecond,
offlineSlowHashingXPerSecond: guesses / attackTimesOptions.offlineSlowHashingXPerSecond,
offlineFastHashingXPerSecond: guesses / attackTimesOptions.offlineFastHashingXPerSecond
};
}
guessesToScore(guesses) {
const scoringOptions = this.options.timeEstimationValues.scoring;
const DELTA = 5;
if (guesses < scoringOptions[0] + DELTA) {
// risky password: "too guessable"
return 0;
}
if (guesses < scoringOptions[1] + DELTA) {
// modest protection from throttled online attacks: "very guessable"
return 1;
}
if (guesses < scoringOptions[2] + DELTA) {
// modest protection from unthrottled online attacks: "somewhat guessable"
return 2;
}
if (guesses < scoringOptions[3] + DELTA) {
// modest protection from offline attacks: "safely unguessable"
// assuming a salted, slow hash function like bcrypt, scrypt, PBKDF2, argon, etc
return 3;
}
// strong protection from offline attacks under same scenario: "very unguessable"
return 4;
}
displayTime(seconds) {
let displayStr = 'centuries';
let base = null;
const timeKeys = Object.keys(times);
const foundIndex = timeKeys.findIndex(time => seconds < times[time]);
if (foundIndex > -1) {
displayStr = timeKeys[foundIndex - 1];
if (foundIndex !== 0) {
base = Math.round(seconds / times[displayStr]);
} else {
displayStr = 'ltSecond';
}
}
return {
base,
displayStr
};
}
translate(displayStr, value) {
let key = displayStr;
if (value !== null && value !== 1) {
key += 's';
}
const {
timeEstimation
} = this.options.translations;
const translation = timeEstimation[key];
if (typeof translation === 'function') {
return translation(value);
}
return translation.replace('{base}', `${value}`);
}
}
export { TimeEstimates, checkTimeEstimationValues, timeEstimationValuesDefaults };
//# sourceMappingURL=TimeEstimates.mjs.map