CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-certbot

ACME client that automates the process of obtaining, installing, and renewing SSL/TLS certificates from Let's Encrypt certificate authority.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

display-ui.mddocs/

Display & User Interface

User interaction utilities for prompting, displaying information, and managing user interface elements in command-line and interactive environments.

Capabilities

Email Collection

Prompt users for email addresses with validation and error handling.

def get_email(invalid: bool = False, **kwargs) -> str:
    """
    Prompt for valid email address with interactive input.
    
    Args:
        invalid: True if an invalid address was previously provided by user
        **kwargs: Additional arguments (unused but maintained for compatibility)
    
    Returns:
        Valid email address string, or empty string if user skips
        
    Raises:
        errors.Error: If user cancels the operation
    """

Usage examples:

from certbot.display import ops

# Prompt for email address
try:
    email = ops.get_email()
    if email:
        print(f"Using email: {email}")
    else:
        print("No email provided")
except errors.Error:
    print("User cancelled email input")

# Prompt after invalid email was provided
try:
    email = ops.get_email(invalid=True)
except errors.Error:
    print("User cancelled after invalid email")

Account Selection

Allow users to choose from available ACME accounts.

def choose_account(accounts: list[Account]) -> Optional[Account]:
    """
    Choose an account from available accounts with interactive menu.
    
    Args:
        accounts: List containing at least one Account object
    
    Returns:
        Selected Account object, or None if user cancels
    """

Usage example:

from certbot.display import ops
from certbot._internal import account

# Load available accounts
accounts = account_storage.find_all()

if accounts:
    selected_account = ops.choose_account(accounts)
    if selected_account:
        print(f"Using account: {selected_account.slug}")
    else:
        print("No account selected")
else:
    print("No accounts available")

Value Selection

Present users with multiple choice selection interfaces.

def choose_values(values: list[str], question: Optional[str] = None) -> list[str]:
    """
    Display screen to let user pick one or multiple values from provided list.
    
    Args:
        values: List of values to select from
        question: Question to ask user while choosing values
    
    Returns:
        List of selected values (may be empty if user cancels)
    """

def choose_names(installer, question: Optional[str] = None) -> list[str]:
    """
    Display screen for interactive domain name selection from installer.
    
    Args:
        installer: Installer plugin instance
        question: Question to display to user
    
    Returns:
        List of selected domain names
    """

def get_valid_domains(domains: Iterable[str]) -> list[str]:
    """
    Validate and filter domain list for certificate eligibility.
    
    Args:
        domains: Iterable of domain names to validate
    
    Returns:
        List of valid domain names
    """

Usage examples:

from certbot.display import ops

# Let user choose domains to include
domains = ['example.com', 'www.example.com', 'api.example.com', 'mail.example.com']
selected = ops.choose_values(
    values=domains,
    question="Which domains would you like to include in the certificate?"
)

if selected:
    print(f"Selected domains: {', '.join(selected)}")
else:
    print("No domains selected")

# Choose enhancements to apply
enhancements = ['redirect', 'hsts', 'uir']
chosen_enhancements = ops.choose_values(
    values=enhancements,
    question="Which security enhancements would you like to enable?"
)

Display Utilities

Low-level display utilities for user interaction.

def input_text(message: str, default: str = "", 
              force_interactive: bool = False) -> tuple[int, str]:
    """
    Get text input from user with interactive prompt.
    
    Args:
        message: Message to display to user
        default: Default value if user provides no input
        force_interactive: Force interactive mode even in non-interactive environments
    
    Returns:
        Tuple of (status_code, user_input)
        Status codes: OK (user provided input), CANCEL (user cancelled)
    """

def menu(message: str, choices: list[str], 
        force_interactive: bool = False) -> tuple[int, int]:
    """
    Display menu and get user selection.
    
    Args:
        message: Message to display above menu
        choices: List of menu options
        force_interactive: Force interactive mode even in non-interactive environments
    
    Returns:
        Tuple of (status_code, selected_index)
        Status codes: OK (user made selection), CANCEL (user cancelled)
    """

def checklist(message: str, tags: list[str], 
             force_interactive: bool = False) -> tuple[int, list[str]]:
    """
    Display checklist for multiple selection.
    
    Args:
        message: Message to display above checklist
        tags: List of items for selection
        force_interactive: Force interactive mode even in non-interactive environments
    
    Returns:
        Tuple of (status_code, selected_items)
        Status codes: OK (user made selections), CANCEL (user cancelled)
    """

def yesno(message: str, yes_label: str = "Yes", no_label: str = "No",
          force_interactive: bool = False) -> bool:
    """
    Display yes/no prompt to user.
    
    Args:
        message: Question to display to user
        yes_label: Text for yes option
        no_label: Text for no option
        force_interactive: Force interactive mode
    
    Returns:
        True if user selected yes, False if no
    """

def notify(message: str) -> None:
    """
    Display notification message to user.
    
    Args:
        message: Message to display
    """

def notification(message: str, pause: bool = True, wrap: bool = True) -> None:
    """
    Display notification with formatting options.
    
    Args:
        message: Message to display
        pause: Whether to pause for user acknowledgment
        wrap: Whether to wrap long lines
    """

def directory_select(message: str, default: str = "") -> tuple[int, str]:
    """
    Display directory selection dialog.
    
    Args:
        message: Prompt message for directory selection
        default: Default directory path
    
    Returns:
        Tuple of (status_code, selected_directory)
    """

Usage examples:

from certbot.display import util as display_util

# Get text input from user
code, text = display_util.input_text(
    message="Enter your organization name:", 
    default="Example Corp"
)
if code == display_util.OK:
    print(f"Organization: {text}")

# Display menu for single selection
options = ['Apache', 'Nginx', 'Other']
code, index = display_util.menu(
    message="Select your web server:",
    choices=options,
    force_interactive=True
)
if code == display_util.OK:
    print(f"Selected: {options[index]}")

# Display checklist for multiple selections
features = ['HTTPS redirect', 'HSTS headers', 'OCSP stapling']
code, selected = display_util.checklist(
    message="Select security features to enable:",
    tags=features,
    force_interactive=True
)
if code == display_util.OK:
    print(f"Selected features: {', '.join(selected)}")

Status and Success Messages

Functions to display operation status and success notifications.

def success_installation(domains: list[str]) -> None:
    """
    Display successful certificate installation message.
    
    Args:
        domains: List of domains for which certificates were installed
    """

def success_renewal(domains: list[str]) -> None:
    """
    Display successful certificate renewal message.
    
    Args:
        domains: List of domains for which certificates were renewed
    """

def success_revocation(cert_path: str) -> None:
    """
    Display successful certificate revocation message.
    
    Args:
        cert_path: Path to revoked certificate
    """

def report_executed_command(command: str, returncode: int, stdout: str, stderr: str) -> None:
    """
    Report results of executed command to user.
    
    Args:
        command: Command that was executed
        returncode: Process return code
        stdout: Standard output from command
        stderr: Standard error from command
    """

def validated_input(validator: Callable, message: str, **kwargs) -> tuple[str, str]:
    """
    Get user input with validation function.
    
    Args:
        validator: Function to validate input
        message: Prompt message
        **kwargs: Additional arguments
    
    Returns:
        Tuple of (status, validated_input)
    """

def validated_directory(validator: Callable, message: str, **kwargs) -> tuple[str, str]:
    """
    Get directory path with validation.
    
    Args:
        validator: Function to validate directory
        message: Prompt message
        **kwargs: Additional arguments
    
    Returns:
        Tuple of (status, validated_directory_path)
    """

Display Constants

Status codes returned by display utility functions.

OK = 0      # User completed operation successfully
CANCEL = 1  # User cancelled operation
WIDTH = 72  # Standard display width for text formatting

Non-Interactive Mode

Certbot can run in non-interactive mode where user prompts are automatically handled:

from certbot import configuration

# Configure non-interactive mode
config.non_interactive = True

# Email collection in non-interactive mode
if config.non_interactive:
    if not config.email:
        # Use default behavior or raise error
        raise errors.Error("Email required in non-interactive mode")
else:
    # Use interactive prompts
    email = ops.get_email()

Display Error Handling

Handle user cancellation and display errors gracefully:

from certbot.display import ops
from certbot import errors

def get_user_preferences():
    """Get user preferences with error handling."""
    try:
        # Get email
        email = ops.get_email()
        
        # Get domain selection
        available_domains = discover_domains()
        if available_domains:
            selected_domains = ops.choose_values(
                values=available_domains,
                question="Select domains for certificate:"
            )
        else:
            selected_domains = []
        
        return {
            'email': email,
            'domains': selected_domains
        }
        
    except errors.Error as e:
        print(f"User interaction failed: {e}")
        return None

# Handle different user interaction scenarios
preferences = get_user_preferences()
if preferences:
    if preferences['email']:
        print(f"Contact email: {preferences['email']}")
    
    if preferences['domains']:
        print(f"Certificate domains: {', '.join(preferences['domains'])}")
    else:
        print("No domains selected - manual configuration required")
else:
    print("User cancelled configuration")

Validation Integration

Display utilities integrate with Certbot's validation systems:

from certbot.display import ops
from certbot import util

def get_validated_email():
    """Get email with validation loop."""
    while True:
        try:
            email = ops.get_email()
            if not email:
                return ""  # User chose to skip
            
            if util.safe_email(email):
                return email
            else:
                # Will show "invalid email" message on next prompt
                email = ops.get_email(invalid=True)
                
        except errors.Error:
            # User cancelled
            return None

# Usage
email = get_validated_email()
if email is None:
    print("User cancelled email input")
elif email == "":
    print("User chose to skip email")
else:
    print(f"Valid email obtained: {email}")

Install with Tessl CLI

npx tessl i tessl/pypi-certbot

docs

crypto-utilities.md

display-ui.md

error-handling.md

index.md

main-config.md

plugin-development.md

utility-functions.md

tile.json