CNs, passwords, URLs, and paths are collected during the session and
printed to the terminal once curses closes — including on crashes,
since _print_session_log runs in a finally block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add SMTP_HOST/PORT/USER/PASSWORD/TLS settings. When SMTP_HOST is set,
send_email() uses smtplib (supports STARTTLS, SSL, or plain); auth is
skipped when SMTP_USER is empty. Falls back to MAIL_BINARY when SMTP_HOST
is unset, preserving existing behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- First Esc in main screen shows "Press Esc again to quit" in footer;
second Esc exits. Any other key resets the pending state.
- Update test_posts_to_correct_endpoint to expect contents as base64 string
and presence of meta field, matching the updated Cryptgeon API payload.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Newer Cryptgeon versions expect `contents` as a base64 string (not a byte
array) and require a `meta` string field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix cursor not appearing in Certificate Details text fields (hint addstr
was clobbering the cursor position set by place_cursor before refresh)
- Add Left/Right arrow key switching between Continue and Cancel buttons
- Expand password generation banned characters from oO01lI to oO01lIQ5S2Z8B
(adds visually ambiguous pairs: Q/0, 5/S, 2/Z, 8/B)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tab (or Down/Enter on a field) now cycles through the three text fields
and then onto [ Continue ] and [ Cancel ] buttons at the bottom of the
form. Enter or Space activates the focused button. Ctrl-G still
confirms immediately from any position. Escape still cancels.
The form window is trimmed from h=16 to h=13 since the buttons replace
the now-redundant empty space below the password field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ctrl-S (0x13) is the XOFF flow-control character; terminals intercept it
before curses sees it, causing output suspension in Konsole and others.
Replaced with Ctrl-G (0x07 / BEL) which has no terminal-level meaning.
Updated hint bar and test stub accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs combined to make the cursor invisible:
- curses.curs_set(0) was set globally in _main() and never re-enabled
for the form, so the cursor was hidden the whole time.
- InputField.draw() called win.move() to position the cursor, but all
fields were drawn in order, so the cursor always landed on the last
field (password) regardless of which field had focus.
Fix: split draw() into draw() (render only) + place_cursor() (move
only). show_cert_form() now calls curses.curs_set(1) on entry,
place_cursor() on the focused field after drawing all fields, and
curses.curs_set(0) before each return.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_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>