_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>
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>