2.3 KiB
keyboard — keyboard adjacency matcher
(no submodules)
Purpose
Detects spatial walks across a physical keyboard layout (QWERTY, DVORAK,
AZERTY, or any caller-supplied adjacency graph) per Wheeler 2016 section
3.5. A password like qwerty traces a straight horizontal walk along the
top row; the matcher reports its length, the number of times the walker
changed direction, and how many shift-required presses it contained — all
inputs to the keyboard guess estimate in section 4.5.
Features
- Pluggable graph map via the
graphsoption - Counts both
turns(direction changes) andshiftedCount(capital / symbol presses) - Default graph is QWERTY; alternative layouts ship under
graphs/{dvorak,azerty}subpaths - Rejects malformed graphs (self-adjacency or asymmetric edges) via
validateGraph→PWSTRENGTH.GRAPH_INVALID
Usage: Basic Example
import { keyboardMatch } from "@suaveplan/password-strength/matchers/keyboard";
const matches = keyboardMatch("qwerty");
console.log(matches[0]); // { graph: "qwerty", turns: 0, shiftedCount: 0, … }
Usage: Advanced Example
import { keyboardMatch } from "@suaveplan/password-strength/matchers/keyboard";
import { DVORAK_GRAPH } from "@suaveplan/password-strength/graphs/dvorak";
const matches = keyboardMatch("aoeuhtns", { graphs: { dvorak: DVORAK_GRAPH } });
for (const m of matches) {
console.log(m.token, m.graph, m.turns, m.shiftedCount);
}
API Reference
keyboardMatch(password: string, opts?: KeyboardMatchOptions): KeyboardMatch[]opts.graphs:Record<string, KeyboardGraph>— override the default QWERTY-only graph set. Each graph is validated before use.
KeyboardMatchOptions:{ graphs?: KeyboardGraphMap }
Implementation Notes
Each walk advances character by character; a transition is accepted iff the
target character appears in the current key's adjacency slots (six slots
per key, encoding the six surrounding keys on a staggered layout). A
direction change increments turns; a press whose target matches the
shifted half of the slot increments shiftedCount. The walk continues
greedily until the chain breaks; the matcher then restarts at the
following index. Graph validation rejects malformed graphs upfront so the
matcher never produces self-loops or asymmetric walks.