Files
SnowLuma/.pnpm-store/v11/files/95/7e063ad32043837aac5e470cd22346f95823a45ecbdaf96d27027417221f9570db8e0527dbf5f383960399cdb65b34e7adb7f7bdb2b5b29a9125ce4ea2cd4e
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

118 lines
3.0 KiB
Plaintext

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