diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..b77d92f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +recursive-include completions * diff --git a/README.md b/README.md new file mode 100644 index 0000000..e2ab6d9 --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# GenPass + +**Secure password generator CLI** written in Python. +Generate strong, random passwords from the command line with customizable character sets. + +--- + +## Features + +- Specify password length and quantity +- Include/exclude: + - Lowercase letters (`--lower`) + - Uppercase letters (`--upper`) + - Digits (`--digits`) + - Symbols (`--symbols`) +- Optional custom symbol set (`--symbol-set`) +- Ensure at least one character from each selected type (can be disabled with `--no-ensure`) +- Shell completions for **bash**, **zsh**, and **fish** +- Easy installation via **pipx** or local script + +--- + +## Installation + +### 1. Via pipx (recommended) +```bash +pipx install git+https://github.com/yourusername/genpass +```` + +### 2. Local installation + +Clone the repo and run the install script: + +```bash +git clone https://github.com/yourusername/genpass.git +cd genpass +./install.sh +``` + +This will also set up shell completions for bash, zsh, and fish. + +--- + +## Usage + +Generate a single password (default 16 characters): + +```bash +genpass --lower --upper --digits --symbols +``` + +Generate 5 passwords of length 20: + +```bash +genpass -l 20 -n 5 --lower --upper --digits --symbols +``` + +Use a custom symbol set: + +```bash +genpass --symbols --symbol-set "!@#%&" +``` + +Disable "ensure each type" rule: + +```bash +genpass --lower --upper --digits --no-ensure +``` + +--- + +## Shell Completion + +After installation, completions are automatically copied to your shell folders. +Restart your shell or source the completion files manually: + +**Bash** + +```bash +source ~/.local/share/bash-completion/completions/genpass +``` + +**Zsh** + +```bash +source ~/.local/share/zsh/site-functions/_genpass +``` + +**Fish** + +```fish +source ~/.local/share/fish/vendor_completions.d/genpass.fish +``` + +--- + +## Development + +1. Install in editable mode for development: + +```bash +pipx install --editable . +``` + +2. Make changes in `genpass/cli.py` and test immediately. + +--- + +## Contributing + +Contributions are welcome! Please fork the repo and submit pull requests. +Ensure code follows PEP8 style and add shell completion tests if applicable. + +--- + +## License + +This project is licensed under the **MIT License** – see the [LICENSE](LICENSE) file for details. + +``` + diff --git a/completions/genpass.bash b/completions/genpass.bash new file mode 100644 index 0000000..1736e54 --- /dev/null +++ b/completions/genpass.bash @@ -0,0 +1,7 @@ +_genpass() { + local cur opts + cur="${COMP_WORDS[COMP_CWORD]}" + opts="--help -l --length -n --count --lower --upper --digits --symbols --symbol-set --no-ensure" + COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) +} +complete -F _genpass genpass diff --git a/completions/genpass.fish b/completions/genpass.fish new file mode 100644 index 0000000..ffe428e --- /dev/null +++ b/completions/genpass.fish @@ -0,0 +1,8 @@ +complete -c genpass -l length -s l -d "Password length" +complete -c genpass -l count -s n -d "Number of passwords" +complete -c genpass -l lower -d "Lowercase letters" +complete -c genpass -l upper -d "Uppercase letters" +complete -c genpass -l digits -d "Digits" +complete -c genpass -l symbols -d "Symbols" +complete -c genpass -l symbol-set -d "Custom symbol set" +complete -c genpass -l no-ensure -d "Disable character guarantees" diff --git a/completions/genpass.zsh b/completions/genpass.zsh new file mode 100644 index 0000000..a63031d --- /dev/null +++ b/completions/genpass.zsh @@ -0,0 +1,10 @@ +#compdef genpass +_arguments \ + '--length[-l]:password length:' \ + '--count[-n]:number of passwords:' \ + '--lower[use lowercase letters]' \ + '--upper[use uppercase letters]' \ + '--digits[use digits]' \ + '--symbols[use symbols]' \ + '--symbol-set[custom symbol set]' \ + '--no-ensure[do not enforce each type]' diff --git a/genpass/__init__.py b/genpass/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/genpass/cli.py b/genpass/cli.py new file mode 100644 index 0000000..c95ad1b --- /dev/null +++ b/genpass/cli.py @@ -0,0 +1,47 @@ +import argparse +import secrets +import string +import sys + +def generate_password(length, pools, ensure_each=True): + if not pools: + raise ValueError("No character sets selected") + password = [] + if ensure_each: + if length < len(pools): + raise ValueError("Password length too small") + for pool in pools: + password.append(secrets.choice(pool)) + all_chars = "".join(pools) + while len(password) < length: + password.append(secrets.choice(all_chars)) + secrets.SystemRandom().shuffle(password) + return "".join(password) + +def main(): + parser = argparse.ArgumentParser(prog="genpass", description="Secure password generator") + parser.add_argument("-l", "--length", type=int, default=16) + parser.add_argument("-n", "--count", type=int, default=1) + parser.add_argument("--lower", action="store_true") + parser.add_argument("--upper", action="store_true") + parser.add_argument("--digits", action="store_true") + parser.add_argument("--symbols", action="store_true") + parser.add_argument("--symbol-set", default="!@#$%^&*()-_=+[]{};:,.<>?") + parser.add_argument("--no-ensure", action="store_true") + args = parser.parse_args() + + pools = [] + if args.lower: pools.append(string.ascii_lowercase) + if args.upper: pools.append(string.ascii_uppercase) + if args.digits: pools.append(string.digits) + if args.symbols: pools.append(args.symbol_set) + + if not pools: + print("Select at least one character set", file=sys.stderr) + sys.exit(1) + + for _ in range(args.count): + print(generate_password(args.length, pools, ensure_each=not args.no_ensure)) + +if __name__ == "__main__": + main() diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..40181c6 --- /dev/null +++ b/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -e + +if ! command -v pipx >/dev/null; then + echo "[!] pipx not found. Install it first:" + echo " python3 -m pip install --user pipx" + echo " pipx ensurepath" + exit 1 +fi + +pipx install . + +PREFIX="${XDG_DATA_HOME:-$HOME/.local/share}" + +mkdir -p "$PREFIX/bash-completion/completions" +mkdir -p "$PREFIX/zsh/site-functions" +mkdir -p "$PREFIX/fish/vendor_completions.d" + +cp completions/genpass.bash "$PREFIX/bash-completion/completions/genpass" +cp completions/genpass.zsh "$PREFIX/zsh/site-functions/_genpass" +cp completions/genpass.fish "$PREFIX/fish/vendor_completions.d/genpass.fish" + +echo "[✓] Installation complete. Restart your shell." diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9a368bc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[project] +name = "genpass" +version = "1.0.0" +description = "Secure password generator CLI" +authors = [{ name = "Ilya Kom" }] +readme = "README.md" +license = "MIT" +requires-python = ">= 3.8" + +[project.scripts] +genpass = "genpass.cli:main" + +[tool.setuptools] +packages = ["genpass"]