_parse_index_line now extracts the emailAddress segment from the DN
alongside CN, returning a (cn, expiry, email) triple. CertInfo gains an
email field populated by both load functions.
In _main(), RENEW_SELECTED falls back to cert.email when the metadata
store has no entry for the CN — so certs created outside this tool (or
before the metadata store existed) pre-fill the email field correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Counter overflow: drop len==2 guard in build_ovpn so suffixes grow
naturally beyond _99 instead of silently resetting to _00
- TOGGLE_ALL: preserve checked set and cursor across A-key view switches
by threading saved_checked/saved_cursor through ScreenResult and back
into show_main_screen on the next call
- CLI Cryptgeon fallback: skip email/eml when Cryptgeon fails instead of
embedding the raw plaintext password in the email body
- --show-eml silent skip: warn explicitly when --show-eml is requested
but no email address is available
- URL truncation: show full one-time URL in TUI confirmation dialog
- _fatal(): remove misleading alias; inline self._error() + return at the
sole call site so termination is explicit
- argparse: replace store_true/store_false with store_const for the
three-state --send-email / --no-send-email / neither pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split revoke_issued and build_client_full into separate try/except blocks.
When renewal is in progress and build-client-full fails after a successful
revoke, display an explicit warning that the old certificate has been revoked
but no new one was built, and advise re-running the renewal.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement COLOR_* constants, initialization, box/centered drawing,
clamp utility, and InputField with handle_key/value logic for pure
text editing without live curses. All tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add send_email() function that composes multipart MIME messages with
template-based body and .ovpn file attachment, piped to mail binary via
subprocess.Popen. Supports Cryptgeon URL insertion and sender metadata.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements generate_password() function that produces 28-character passwords
following charset rules: position 1 uppercase, position 2 and last lowercase
with restricted characters, middle positions alphanumeric. Uses secrets module
for cryptographic randomness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>