Files
skills/docs/security-stack/security/password-strength/src/matchers/keyboard/keyboard.md
2026-05-29 08:20:56 +01:00

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 graphs option
  • Counts both turns (direction changes) and shiftedCount (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.