Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ uv run ssltui renew --cert myapp.local
uv run ssltui issue --cn api.local --san www.api.local --san 10.0.0.1 --days 365
```

### Get the root CA certificate

Print the root CA certificate (PEM) to stdout — handy for piping into a trust
store. A short summary is written to stderr when run interactively, so the
redirected output stays a clean PEM:

```bash
uv run ssltui getroot > local-ca.crt
# or write it directly
uv run ssltui getroot --out local-ca.crt
```

### Cron entry

Install via the TUI's **Cron Schedule** option, or add manually:
Expand Down
48 changes: 47 additions & 1 deletion ssltui/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,20 @@ def _build_parser() -> argparse.ArgumentParser:
help="Write to FILE instead of stdout (recommended for keys)",
)

# getroot
getroot = sub.add_parser(
"getroot", help="Print the root CA certificate (PEM) to stdout"
)
getroot.add_argument(
"--out",
metavar="FILE",
help="Write the CA cert to FILE instead of stdout",
)

return p


_SUBCMDS = frozenset({"renew", "status", "issue", "serve", "get"})
_SUBCMDS = frozenset({"renew", "status", "issue", "serve", "get", "getroot"})


def main(argv: list[str] | None = None) -> None:
Expand Down Expand Up @@ -123,6 +133,8 @@ def main(argv: list[str] | None = None) -> None:
_cmd_serve(args)
elif args.cmd == "get":
_cmd_get(args)
elif args.cmd == "getroot":
_cmd_getroot(args)
else:
# Default: interactive TUI
from ssltui.tui import run_tui
Expand Down Expand Up @@ -359,5 +371,39 @@ def _cmd_get(args) -> None:
sys.stdout.buffer.write(data)


def _cmd_getroot(args) -> None:
from ssltui import config
from ssltui.ca import CAError, ca_expiry, ca_fingerprint, ca_subject

root = config.data_dir()
ca_path = config.ca_cert_path(root)
if not ca_path.exists():
print(f"ERROR: CA not initialised at {root}.", file=sys.stderr)
sys.exit(1)

data = ca_path.read_bytes()

if args.out:
out = Path(args.out)
out.write_bytes(data)
out.chmod(0o644)
print(f"Written to {out}")
return

# When writing to a terminal, print a short summary to stderr so stdout
# stays a clean PEM that can be piped or redirected.
if sys.stdout.isatty():
try:
Comment on lines +393 to +396
print(
f"Root CA: {ca_subject(root)}\n"
f"Expires: {ca_expiry(root)}\n"
f"SHA256: {ca_fingerprint(root)}",
file=sys.stderr,
)
except CAError:
pass
sys.stdout.buffer.write(data)


if __name__ == "__main__":
main()
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading