3.5 KiB
3.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
openvpncertupdate is a single-file Python + curses TUI tool for managing OpenVPN user certificates via EasyRSA 3.2.x. It lists expiring/expired certs, re-issues them with fresh keys, creates new certs, and delivers configs via Cryptgeon (one-time password URL) and email. It also supports a non-interactive CLI mode for scripting and cron use.
Running
pip install -r requirements.txt # just: cryptography>=41
python3 openvpncertupdate.py # interactive TUI
python3 openvpncertupdate.py --create CN --email user@example.com
python3 openvpncertupdate.py --reissue CN [--email user@example.com]
python3 openvpncertupdate.py --revoke CN
python3 openvpncertupdate.py --gen-crl
Edit the SETTINGS block at the top of openvpncertupdate.py before first run.
CLI flags
| Flag | Effect |
|---|---|
--create CN |
Issue new cert (requires --email) |
--reissue CN |
Revoke + reissue cert (--email optional, falls back to stored) |
--revoke CN |
Revoke cert and regenerate CRL |
--gen-crl |
Regenerate and copy CRL only |
--email EMAIL |
Recipient address |
--send-email |
Force email delivery |
--no-send-email |
Skip email; print URL to stdout |
--show-eml |
Print base64-encoded .eml to stdout (implies --no-send-email unless --send-email also given) |
Tests
python3 -m pytest tests/ -v
python3 -m pytest tests/test_password.py -v # single file
python3 -m pytest tests/test_pki.py::test_sorted_ascending -v # single test
File layout — sections inside openvpncertupdate.py
| Section | Key symbols |
|---|---|
| SETTINGS | all-caps constants |
| PKI | CertInfo, load_expiring_certs(), load_all_certs(), _parse_index_line() |
| PASSWORD | generate_password() |
| EASYRSA | EasyRSAError, revoke_issued(), build_client_full(), gen_crl(), copy_crl() |
| METADATA | load_metadata(), save_email(), get_email() |
| CONFIG | build_ovpn() → vpn-configs/<CN>_<YYYY-MM-DD>_<NN>/CONFIG_NAME |
| CRYPTGEON | CryptgeonError, create_note() |
| MAILER | build_mime_message(), send_email() |
| TUI WIDGETS | InputField, clamp(), draw_box(), init_colors(), COLOR_* |
| TUI DIALOGS | show_confirm(), show_cert_form(), CertFormResult |
| TUI SCREEN | show_main_screen(), Action, ScreenResult |
| APP | CursesApp |
| CLI | CliRunner, _build_parser() |
| ENTRY POINT | main() |
Re-issue workflow
revoke-issued <CN>— archives old key + CSR topki/revoked/build-client-full <CN> --passout=pass:<pw>— generates new key + cert- CRL not auto-updated during renewal; use "Regenerate CRL" menu item or
rhotkey
TUI key bindings
| Key | Action |
|---|---|
↑/↓ |
Navigate list |
Space |
Toggle checkbox selection |
Enter |
Confirm / open selected item |
r |
Revoke selected cert |
A |
Toggle between expiring-only and all-certs view |
q/Esc |
Quit |
Key constraints
- EasyRSA called with
--batch;--passin=pass:<CA_PASSPHRASE>omitted whenCA_PASSPHRASE="" - Cryptgeon:
raw_key=os.urandom(32),aes_key=SHA-256(raw_key), AES-256-GCM, URL fragment=base64url(raw_key) copy_crl()doeschmod 644after copy- Password: pos 1=uppercase, pos 2=lowercase (no j), pos 3-27=alphanumeric, pos 28=lowercase (no j);
oO01lIbanned everywhere - Inline file path:
<PKI_DIR>/inline/private/<CN>.inline - User emails stored in
<PKI_DIR>/openvpncertupdate-metadata.json