-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.cursorrules
More file actions
73 lines (54 loc) · 3.15 KB
/
.cursorrules
File metadata and controls
73 lines (54 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# spoken-token — Cursor Rules
TOTP but you say it out loud. Derive time-rotating, human-speakable verification tokens from a shared secret. Zero runtime dependencies, ESM-only, works in Node.js and the browser.
## Commands
| Command | Purpose |
|---------|---------|
| `npm run build` | Compile TypeScript to `dist/` |
| `npm test` | Run all tests (vitest) |
| `npm run test:watch` | Watch mode |
| `npm run typecheck` | Type-check without emitting |
| `npm run lint` | Run ESLint |
| `npm run lint:fix` | ESLint with auto-fix |
## Structure
| File | Purpose |
|------|---------|
| `src/token.ts` | Core derivation: `deriveToken`, `deriveDirectionalPair` |
| `src/verify.ts` | Verification with tolerance window |
| `src/encoding.ts` | Output encoding (words, PIN, hex) |
| `src/wordlist.ts` | 2048-word en-v1 spoken-clarity wordlist |
| `src/counter.ts` | Time-based and event-ID counter derivation |
| `src/crypto.ts` | Pure JS SHA-256, HMAC-SHA256, hex/base64 utilities |
| `src/index.ts` | Barrel re-export |
| `PROTOCOL.md` | Full protocol specification v2.0 (SPOKEN-DERIVE, SPOKEN-ENCODE) |
## Subpath Exports
The package exposes five entry points:
- `spoken-token` — full API (barrel re-export)
- `spoken-token/counter` — `getCounter`, `counterFromEventId`, `counterToBytes`
- `spoken-token/wordlist` — `WORDLIST`, `WORDLIST_SIZE`, `getWord`, `indexOf`
- `spoken-token/encoding` — `encodeAsWords`, `encodeAsPin`, `encodeAsHex`, `encodeToken`
- `spoken-token/crypto` — `sha256`, `hmacSha256`, `randomSeed`, `hexToBytes`, `bytesToHex`, `timingSafeEqual`, `timingSafeStringEqual`
## Conventions
- **British English** — colour, initialise, behaviour, licence
- **ESM-only** — `"type": "module"` in package.json
- **TDD** — write failing test first, then implement
- **Zero dependencies** — all crypto is pure JS, no external packages
- Commit messages use `type: description` format (`fix:`, `feat:`, `docs:`, `refactor:`, `test:`)
- Tests are co-located: `token.ts` + `token.test.ts`
## Verifying Changes
Always run before submitting:
```bash
npm test && npm run typecheck && npm run lint
```
## Security Notes
- Token verification uses timing-safe comparison (`timingSafeStringEqual`)
- HMAC intermediate buffers and SHA-256 working state are zeroed after use
- `randomSeed()` returns a 64-char hex string (32 bytes) via `crypto.getRandomValues`
- PIN encoding uses a lookup table to keep modular bias below 1% for all digit counts
- Directional pairs use a `"pair\0"` prefix for cryptographic domain separation from identity-bound tokens
## Key Pitfalls
- **PIN bias:** The `PIN_BYTES` lookup table is carefully calibrated. Do not replace it with a formula.
- **Pair prefix:** The `"pair\0"` context prefix in `deriveDirectionalPair` prevents collision with identity-bound tokens. Do not remove it.
- **Whitespace rejection:** Empty and whitespace-only context strings, namespaces, and roles are rejected by design.
- **Counter range:** Counters are uint32 (0 to 4,294,967,295). Negative, fractional, and overflow values throw `RangeError`.
## Related Projects
- **canary-kit** extends spoken-token with duress signalling, liveness monitoring, group management, and Nostr transport.