Files
Nighthawk42andClaude Opus 4.8 c416e98162 Add optional Flet desktop GUI and live TOTP code generation
Add src/bnet_auth_tool/gui.py: an imperative Flet 0.85 desktop app behind a
new `gui` extra, exposed as the `bnet-auth-gui` entry point. It reuses the
same vault, crypto, settings, and TOTP modules as the CLI — lock screen,
authenticator list with live rotating codes, detail dialog (QR/copy/delete),
legacy import, and online attach/retrieve (kept labelled unverified).

Add RFC 6238 TOTP code generation to totp.py (current_code / seconds_remaining,
pure stdlib) with reference-vector tests, since the GUI displays live codes.

Update README/AGENTS.md and uv.lock for the GUI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:17:27 -04:00

64 lines
3.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Guidance for AI agents and human contributors working on `bnet_auth_tool`.
## What this is
A Python CLI for managing Battle.net software authenticators. Two halves:
- **Offline (the important, fully-tested half):** an encrypted vault of authenticator
secrets, TOTP/QR reconstruction, and migration of legacy backups.
- **Online (unverified):** attach/retrieve flows against Blizzard's identity API. These
may be blocked by Blizzard at any time. **Do not claim they are "fixed"** — keep the
tempered "unverified" framing in the README and `--help`/menu text.
## Architecture
Source lives under `src/bnet_auth_tool/` (a proper package; there is no top-level script).
| Module | Responsibility |
| --- | --- |
| `config.py` | Load bundled `settings.yaml` + user override; resolve config/data dirs (`platformdirs`). Typed `Settings`/`ApiConfig`/`CryptoConfig`/`TotpConfig`. |
| `crypto.py` | `EncryptionManager`: scrypt+AES256GCM encrypt; decrypt dispatches on a versioned header (scrypt / PBKDF2 600k / legacy PBKDF2 100k). |
| `storage.py` | `Vault`: single encrypted file keyed by serial; add/list/get/remove. |
| `fileio.py` | Atomic, `0600`-hardened writes (`atomic_write_bytes`, `_harden`). |
| `api.py` | `BattleNetAuthenticator` online client; leak-safe error handling. |
| `totp.py` | hex→base32, `otpauth://` URL builder, QR PNG. |
| `migrate.py` | Discover + import legacy `battlenet_authenticator_*.json` files into the vault. |
| `cli.py` | Interactive menu **and** argparse subcommands; `main()` is the entry point. |
| `gui.py` | Optional Flet desktop GUI (`bnet-auth-gui`); imperative, same vault/crypto as the CLI. Behind the `gui` extra. |
| `errors.py` | Exception hierarchy rooted at `BnetAuthError`. |
`settings.yaml` is shipped inside the package and copied to the user's config dir on first
run. Endpoints/KDF/TOTP params are config, not code — change them there.
## Hard constraints (do not break)
1. **Legacy decryption must keep working.** Files encrypted by v1.x — including prev1.3
files with *no* `kdf_iterations` field — must still decrypt. Covered by `tests/test_crypto.py`.
2. **Secrets are sensitive.** Never log raw device secrets, restore codes, session tokens,
or full server error bodies. Vault/QR files are written `0600` and atomically.
3. **Online flows stay labelled unverified.** No optimistic "it works now" claims.
## Conventions
- Python **3.9+**; `from __future__ import annotations` in every module (so `X | None`
annotations are fine).
- Lint/format with **ruff**; config in `pyproject.toml`.
- Keep crypto parameters fast in tests (small scrypt `n`) — see `tests/conftest.py`.
- The GUI targets **Flet 0.85+** in imperative style: `ft.run(main)`, `page.show_dialog()` /
`page.pop_dialog()`, `page.clipboard.set()`, `page.window.width`. It holds no logic of its
own — all crypto/storage/TOTP goes through the same modules as the CLI.
## Workflow
```bash
uv sync --extra dev
uv run pytest
uv run ruff check .
uv run bnet-auth --help
```
When changing the encryption format, bump the `format` header in `crypto.py` and add a
back-compat test rather than mutating the existing decrypt paths.