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
62 lines
2.4 KiB
Plaintext
62 lines
2.4 KiB
Plaintext
'use strict';
|
|
|
|
var _const = require('../../data/const.cjs');
|
|
var types = require('../../types.cjs');
|
|
|
|
const separatorRegex = new RegExp(`[${_const.SEPERATOR_CHARS.join('')}]`);
|
|
/*
|
|
*-------------------------------------------------------------------------------
|
|
* separators (any semi-repeated special character) -----------------------------
|
|
*-------------------------------------------------------------------------------
|
|
*/
|
|
class MatchSeparator extends types.MatcherBaseClass {
|
|
static getMostUsedSeparatorChar(password) {
|
|
const mostUsedSeperators = [...password.split('').filter(c => separatorRegex.test(c)).reduce((memo, c) => {
|
|
const m = memo.get(c);
|
|
if (m) {
|
|
memo.set(c, parseInt(m, 10) + 1);
|
|
} else {
|
|
memo.set(c, 1);
|
|
}
|
|
return memo;
|
|
}, new Map()).entries()].sort(([_a, a], [_b, b]) => b - a);
|
|
if (!mostUsedSeperators.length) return undefined;
|
|
const match = mostUsedSeperators[0];
|
|
// If the special character is only used once, don't treat it like a separator
|
|
if (match[1] < 2) return undefined;
|
|
return match[0];
|
|
}
|
|
static getSeparatorRegex(separator) {
|
|
return new RegExp(`([^${separator}\n])(${separator})(?!${separator})`, 'g');
|
|
// negative lookbehind can be added again in a few years when it is more supported by the browsers (currently 2023)
|
|
// https://github.com/zxcvbn-ts/zxcvbn/issues/202
|
|
// return new RegExp(`(?<!${separator})(${separator})(?!${separator})`, 'g')
|
|
}
|
|
match({
|
|
password
|
|
}) {
|
|
const result = [];
|
|
if (password.length === 0) return result;
|
|
const mostUsedSpecial = MatchSeparator.getMostUsedSeparatorChar(password);
|
|
if (mostUsedSpecial === undefined) return result;
|
|
const isSeparator = MatchSeparator.getSeparatorRegex(mostUsedSpecial);
|
|
for (const match of password.matchAll(isSeparator)) {
|
|
if (match.index === undefined) continue;
|
|
// add one to the index because we changed the regex from negative lookbehind to something simple.
|
|
// this simple approach uses the first character before the separater too but we only need the index of the separater
|
|
// https://github.com/zxcvbn-ts/zxcvbn/issues/202
|
|
const i = match.index + 1;
|
|
result.push({
|
|
pattern: 'separator',
|
|
token: mostUsedSpecial,
|
|
i,
|
|
j: i
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
module.exports = MatchSeparator;
|
|
//# sourceMappingURL=matching.cjs.map
|