fix TUI crash on serial consoles; make index.txt the sole email store
curses.use_default_colors() raises on terminals (e.g. serial consoles using TERM=linux/vt100) whose terminfo lacks default-color support; init_colors() now falls back to an explicit black background and caps the "disabled" color to 8-color terminals. --reissue without --email silently sent no mail when the CN wasn't in openvpncertupdate-metadata.json, even though its email was already embedded in the cert's index.txt subject (via EASYRSA_REQ_EMAIL) and the TUI already fell back to it. Since build_client_full() always writes that subject field whenever an email is known, metadata.json was a redundant, driftable copy — remove it and have get_email() read index.txt directly, picking the last non-revoked entry for a CN since index.txt can contain revoked/duplicate lines for the same CN. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import textwrap
|
||||
import pytest
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from openvpncertupdate import load_all_certs, load_expiring_certs, CertInfo, _parse_index_line
|
||||
from openvpncertupdate import load_all_certs, load_expiring_certs, CertInfo, _parse_index_line, get_email
|
||||
|
||||
|
||||
def _fmt(dt: datetime) -> str:
|
||||
@@ -107,3 +107,44 @@ def test_load_all_certs_sorted_ascending(tmp_path):
|
||||
certs = load_all_certs(pki)
|
||||
dates = [c.expires for c in certs]
|
||||
assert dates == sorted(dates)
|
||||
|
||||
|
||||
def test_get_email_reads_from_index_txt(tmp_path):
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
pki = tmp_path / "pki"
|
||||
pki.mkdir()
|
||||
expiry = now + timedelta(days=5)
|
||||
line = f"V\t{expiry.strftime('%y%m%d%H%M%S')}Z\t\t01\tunknown\t/CN=carol/emailAddress=carol@example.com\n"
|
||||
(pki / "index.txt").write_text(line)
|
||||
assert get_email(str(pki), "carol") == "carol@example.com"
|
||||
|
||||
|
||||
def test_get_email_missing_cn_returns_empty(tmp_path):
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
pki = make_pki(tmp_path, now)
|
||||
assert get_email(pki, "nobody") == ""
|
||||
|
||||
|
||||
def test_get_email_ignores_revoked_entry(tmp_path):
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
pki = make_pki(tmp_path, now)
|
||||
# "revoked" CN in make_pki() has status R, not V
|
||||
assert get_email(pki, "revoked") == ""
|
||||
|
||||
|
||||
def test_get_email_picks_last_valid_entry_among_duplicates(tmp_path):
|
||||
# index.txt is append-only: a CN can have several lines (old ones R,
|
||||
# or multiple V if a cert was reissued without going through this
|
||||
# tool's revoke-first flow). The most recently appended V line wins.
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
pki = tmp_path / "pki"
|
||||
pki.mkdir()
|
||||
e1 = (now + timedelta(days=5)).strftime("%y%m%d%H%M%S") + "Z"
|
||||
e2 = (now + timedelta(days=365)).strftime("%y%m%d%H%M%S") + "Z"
|
||||
content = (
|
||||
f"R\t{e1}\t230101Z,superseded\t01\tunknown\t/CN=dave/emailAddress=old@example.com\n"
|
||||
f"V\t{e1}\t\t02\tunknown\t/CN=dave/emailAddress=older-valid@example.com\n"
|
||||
f"V\t{e2}\t\t03\tunknown\t/CN=dave/emailAddress=newest@example.com\n"
|
||||
)
|
||||
(pki / "index.txt").write_text(content)
|
||||
assert get_email(str(pki), "dave") == "newest@example.com"
|
||||
|
||||
Reference in New Issue
Block a user