← All tasks
pythonclaude-code/python-t1 #14Not a task: already works

TOTP Generator (python, written by Claude Code)

envgap__claude-code__python-t1-14

Written by a coding agent; not on GitHubWritten 2026-02-27

01 / FAILURE SIGNATURE

As the study recorded it

No identifying execution failure has been captured.
Not a benchmark task.
  • The project already builds and runs before the fix, so there is nothing to repair.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
requirements.txt
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

claude-code/python-t1 #14 · read the task the agent was given
Claude Code wrote this python project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: TOTP Generator

Write a program that generates and validates Time-based One-Time Passwords (TOTP) compatible with RFC 6238, supporting secret key management, QR code URI generation, and multi-account storage.

FUNCTIONAL REQUIREMENTS:
- Support subcommands: generate (create a new TOTP secret), code (show current OTP code), verify (check if a code is valid), and list (show all stored accounts)
- generate: Create a cryptographically random base32-encoded secret key of configurable length (--length flag, default 20 bytes)
- code: Display the current 6-digit TOTP code for a given account, with a countdown timer showing seconds until the code expires (30-second default period)
- verify: Accept a 6-digit code and check if it matches the current or adjacent time windows (configurable drift tolerance via --drift flag, default 1 window)
- Support configurable TOTP parameters: digit count (6 or 8), time period (30 or 60 seconds), and hash algorithm (SHA-1, SHA-256, SHA-512)
- Generate otpauth:// URIs compatible with authenticator apps (Google Authenticator, Authy)
- Store account secrets in an encrypted local JSON file using a master password
- Support multiple accounts with labels (--account flag with issuer:username format)
- Print the current code, remaining seconds, and next code to console
- If no arguments are given, generate a demo account with a random secret, display the current code and the otpauth:// URI, verify the current code, then show what happens with an incorrect code
- Handle errors: invalid base32 secrets, expired codes, duplicate account names, wrong master password

Create a complete Python project for a clean Ubuntu 22.04 machine with only Python 3.10+ installed. Include:
- Source code
- requirements.txt with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

README.md
# TOTP Generator - Python (Trial 1)

A TOTP (Time-based One-Time Password) generator and validator implementing RFC 6238, with multi-account storage and otpauth:// URI and QR code generation.

## Dependencies

- **pyotp** (2.9.0) - Python library for generating and verifying TOTP/HOTP codes
- **qrcode** (7.4.2) - QR code image generation for otpauth URIs

## Setup

```bash
pip install -r requirements.txt
```

## Usage

Run the interactive CLI:

```bash
python totp_gen.py
```

### Features

- Add TOTP accounts with custom or auto-generated secrets
- Generate current TOTP codes for any stored account
- Validate TOTP codes with configurable time-window tolerance
- Generate otpauth:// URIs compatible with authenticator apps
- Generate QR code images for easy account setup
- Multi-account storage in a local JSON file
- List and remove stored accounts

### Programmatic Usage

```python
from totp_gen import add_account, generate_totp, validate_totp, get_otpauth_uri

# Add an account
add_account("user@example.com", issuer="GitHub")

# Generate a TOTP code
code = generate_totp("GitHub:user@example.com")

# Validate a code
is_valid = validate_totp("GitHub:user@example.com", code)

# Get otpauth URI
uri = get_otpauth_uri("GitHub:user@example.com")
```
requirements.txt
pyotp==2.9.0
qrcode==7.4.2
totp_gen.py
"""
TOTP Generator - Generates and validates RFC 6238 TOTP codes with
multi-account storage and otpauth:// URI generation.

Dependencies: pyotp, qrcode
"""

import json
import os
import sys
import time
from pathlib import Path

import pyotp
import qrcode


ACCOUNTS_FILE = "totp_accounts.json"


def load_accounts() -> dict:
    """Load stored accounts from the JSON file."""
    if os.path.exists(ACCOUNTS_FILE):
        with open(ACCOUNTS_FILE, "r") as f:
            return json.load(f)
    return {}


def save_accounts(accounts: dict) -> None:
    """Save accounts to the JSON file."""
    with open(ACCOUNTS_FILE, "w") as f:
        json.dump(accounts, f, indent=2)


def add_account(name: str, issuer: str = "", secret: str = None,
                digits: int = 6, interval: int = 30) -> dict:
    """
    Add a new TOTP account. If no secret is provided, one is generated.

    Args:
        name: Account name / email.
        issuer: Service name (e.g. 'GitHub').
        secret: Base32-encoded secret. Auto-generated if None.
        digits: Number of digits in the TOTP code (default 6).
        interval: Time step in seconds (default 30).

    Returns:
        The account dictionary that was stored.
    """
    accounts = load_accounts()

    if secret is None:
        secret = pyotp.random_base32()

    account = {
        "name": name,
        "issuer": issuer,
        "secret": secret,
        "digits": digits,
        "interval": interval,
    }

    key = f"{issuer}:{name}" if issuer else name
    accounts[key] = account
    save_accounts(accounts)
    print(f"Account '{key}' added successfully.")
    return account


def generate_totp(account_key: str) -> str:
    """
    Generate a current TOTP code for the given account.

    Args:
        account_key: The key identifying the account (issuer:name or name).

    Returns:
        The current TOTP code string.
    """
    accounts = load_accounts()
    if account_key not in accounts:
        raise KeyError(f"Account '{account_key}' not found.")

    acct = accounts[account_key]
    totp = pyotp.TOTP(
        acct["secret"],
        digits=acct.get("digits", 6),
        interval=acct.get("interval", 30),
    )
    code = totp.now()
    remaining = acct.get("interval", 30) - (int(time.time()) % acct.get("interval", 30))
    print(f"TOTP for '{account_key}': {code}  (valid for {remaining}s)")
    return code


def validate_totp(account_key: str, code: str, window: int = 1) -> bool:
    """
    Validate a TOTP code against the stored account secret.

    Args:
        account_key: The key identifying the account.
        code: The TOTP code to validate.
        window: Number of time-step windows to check (default 1).

    Returns:
        True if the code is valid, False otherwise.
    """
    accounts = load_accounts()
    if account_key not in accounts:
        raise KeyError(f"Account '{account_key}' not found.")

    acct = accounts[account_key]
    totp = pyotp.TOTP(
        acct["secret"],
        digits=acct.get("digits", 6),
        interval=acct.get("interval", 30),
    )
    valid = totp.verify(code, valid_window=window)
    status = "VALID" if valid else "INVALID"
    print(f"Code '{code}' for '{account_key}' is {status}.")
    return valid


def get_otpauth_uri(account_key: str) -> str:
    """
    Generate an otpauth:// URI for the given account (for QR code scanning).

    Args:
        account_key: The key identifying the account.

    Returns:
        The otpauth:// URI string.
    """
    accounts = load_accounts()
    if account_key not in accounts:
        raise KeyError(f"Account '{account_key}' not found.")

    acct = accounts[account_key]
    totp = pyotp.TOTP(
        acct["secret"],
        digits=acct.get("digits", 6),
        interval=acct.get("interval", 30),
    )
    uri = totp.provisioning_uri(
        name=acct["name"],
        issuer_name=acct.get("issuer", ""),
    )
    print(f"otpauth URI: {uri}")
    return uri


def generate_qr_code(account_key: str, output_file: str = None) -> str:
    """
    Generate a QR code image for the account's otpauth URI.

    Args:
        account_key: The key identifying the account.
        output_file: Path for the output PNG. Defaults to '{account_key}_qr.png'.

    Returns:
        The path to the generated QR code image.
    """
    uri = get_otpauth_uri(account_key)
    if output_file is None:
        safe_name = account_key.replace(":", "_").replace(" ", "_")
        output_file = f"{safe_name}_qr.png"

    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(uri)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(output_file)
    print(f"QR code saved to '{output_file}'.")
    return output_file


def list_accounts() -> list:
    """List all stored accounts."""
    accounts = load_accounts()
    if not accounts:
        print("No accounts stored.")
        return []

    print(f"\n{'Account Key':<35} {'Issuer':<20} {'Digits':<8} {'Interval':<10}")
    print("-" * 75)
    for key, acct in accounts.items():
        print(f"{key:<35} {acct.get('issuer', ''):<20} "
              f"{acct.get('digits', 6):<8} {acct.get('interval', 30):<10}")
    print()
    return list(accounts.keys())


def remove_account(account_key: str) -> bool:
    """Remove an account from storage."""
    accounts = load_accounts()
    if account_key not in accounts:
        print(f"Account '{account_key}' not found.")
        return False
    del accounts[account_key]
    save_accounts(accounts)
    print(f"Account '{account_key}' removed.")
    return True


def main():
    """Interactive CLI for the TOTP generator."""
    while True:
        print("\n=== TOTP Generator ===")
        print("1. Add account")
        print("2. Generate TOTP code")
        print("3. Validate TOTP code")
        print("4. Show otpauth URI")
        print("5. Generate QR code")
        print("6. List accounts")
        print("7. Remove account")
        print("8. Exit")

        choice = input("\nSelect option: ").strip()

        if choice == "1":
            name = input("Account name (e.g. user@example.com): ").strip()
            issuer = input("Issuer (e.g. GitHub): ").strip()
            secret_input = input("Secret (leave blank to auto-generate): ").strip()
            secret = secret_input if secret_input else None
            digits_input = input("Digits (default 6): ").strip()
            digits = int(digits_input) if digits_input else 6
            interval_input = input("Interval in seconds (default 30): ").strip()
            interval = int(interval_input) if interval_input else 30
            add_account(name, issuer, secret, digits, interval)

        elif choice == "2":
            key = input("Account key: ").strip()
            try:
                generate_totp(key)
            except KeyError as e:
                print(e)

        elif choice == "3":
            key = input("Account key: ").strip()
            code = input("TOTP code to validate: ").strip()
            try:
                validate_totp(key, code)
            except KeyError as e:
                print(e)

        elif choice == "4":
            key = input("Account key: ").strip()
            try:
                get_otpauth_uri(key)
            except KeyError as e:
                print(e)

        elif choice == "5":
            key = input("Account key: ").strip()
            try:
                generate_qr_code(key)
            except KeyError as e:
                print(e)

        elif choice == "6":
            list_accounts()

        elif choice == "7":
            key = input("Account key to remove: ").strip()
            remove_account(key)

        elif choice == "8":
            print("Goodbye.")
            sys.exit(0)

        else:
            print("Invalid option.")


if __name__ == "__main__":
    main()