# Secure Password Generator

This utility generates cryptographically strong passwords using the `secrets` module. It allows customization of password length and character sets (symbols, numbers).

**Modules Used:**
*   [[programming/python/modules/secrets-module|secrets]]: For generating cryptographically strong random numbers.
*   `string`: For accessing pre-defined character sets (letters, digits, punctuation).
*   [[programming/python/modules/argparse-module|argparse]]: To handle command-line arguments.

## Quick Start (Tokens)

If you just need a secure random string (e.g., for an API key or a password where specific character classes aren't required), the simplest method is `secrets.token_urlsafe()`.

```python
import secrets
# Generates a random URL-safe text string, containing nbytes random bytes.
print(secrets.token_urlsafe(16)) 
```

## The Code

Save this as `passgen.py`.

```python
import secrets
import string
import argparse

def generate_password(length, use_symbols, use_numbers):
    # 1. Define Character Sets
    letters = string.ascii_letters  # a-z, A-Z
    digits = string.digits          # 0-9
    symbols = string.punctuation    # ! " # $ % ...

    # 2. Build the Pool
    pool = letters
    if use_numbers:
        pool += digits
    if use_symbols:
        pool += symbols

    # 3. Generate until constraints are met
    # We use a loop to ensure the password contains at least one of each selected type
    while True:
        password = ''.join(secrets.choice(pool) for _ in range(length))
        
        # Check constraints
        has_letter = any(c in letters for c in password)
        has_digit = any(c in digits for c in password) if use_numbers else True
        has_symbol = any(c in symbols for c in password) if use_symbols else True
        
        if has_letter and has_digit and has_symbol:
            return password

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Secure Password Generator")
    parser.add_argument("-l", "--length", type=int, default=16, help="Length of the password (default: 16)")
    parser.add_argument("--no-symbols", action="store_true", help="Exclude symbols")
    parser.add_argument("--no-numbers", action="store_true", help="Exclude numbers")
    
    args = parser.parse_args()
    
    # Note: Arguments are negative flags (--no-X), so we invert them for the function
    pwd = generate_password(args.length, not args.no_symbols, not args.no_numbers)
    print(f"Generated Password: {pwd}")
```

## Usage

```bash
# Default (16 chars, symbols and numbers included)
python passgen.py

# 20 characters, no symbols
python passgen.py --length 20 --no-symbols
```

[[programming/python/python]]