import { ALL_LOWER, ALL_UPPER, ALL_DIGIT } from '../../data/const.mjs'; import { MatcherBaseClass } from '../../types.mjs'; /* *------------------------------------------------------------------------------- * sequences (abcdef) ------------------------------ *------------------------------------------------------------------------------- */ class MatchSequence extends MatcherBaseClass { constructor() { super(...arguments); this.MAX_DELTA = 5; } // eslint-disable-next-line max-statements match({ password }) { /* * Identifies sequences by looking for repeated differences in unicode codepoint. * this allows skipping, such as 9753, and also matches some extended unicode sequences * such as Greek and Cyrillic alphabets. * * for example, consider the input 'abcdb975zy' * * password: a b c d b 9 7 5 z y * index: 0 1 2 3 4 5 6 7 8 9 * delta: 1 1 1 -2 -41 -2 -2 69 1 * * expected result: * [(i, j, delta), ...] = [(0, 3, 1), (5, 7, -2), (8, 9, 1)] */ const result = []; if (password.length === 1) { return []; } let i = 0; let lastDelta = null; const passwordLength = password.length; for (let k = 1; k < passwordLength; k += 1) { const delta = password.charCodeAt(k) - password.charCodeAt(k - 1); if (lastDelta === null) { lastDelta = delta; } if (delta !== lastDelta) { const j = k - 1; this.update({ i, j, delta: lastDelta, password, result }); i = j; lastDelta = delta; } } this.update({ i, j: passwordLength - 1, delta: lastDelta, password, result }); return result; } update({ i, j, delta, password, result }) { if (j - i > 1 || Math.abs(delta) === 1) { const absoluteDelta = Math.abs(delta); if (absoluteDelta > 0 && absoluteDelta <= this.MAX_DELTA) { const token = password.slice(i, j + 1 || 9e9); const { sequenceName, sequenceSpace } = this.getSequence(token); return result.push({ pattern: 'sequence', i, j, token: password.slice(i, j + 1 || 9e9), sequenceName, sequenceSpace, ascending: delta > 0 }); } } return null; } getSequence(token) { // TODO conservatively stick with roman alphabet size. // (this could be improved) let sequenceName = 'unicode'; let sequenceSpace = 26; if (ALL_LOWER.test(token)) { sequenceName = 'lower'; sequenceSpace = 26; } else if (ALL_UPPER.test(token)) { sequenceName = 'upper'; sequenceSpace = 26; } else if (ALL_DIGIT.test(token)) { sequenceName = 'digits'; sequenceSpace = 10; } return { sequenceName, sequenceSpace }; } } export { MatchSequence as default }; //# sourceMappingURL=matching.mjs.map