diff --git a/PYTHON_STANDARDS.md b/PYTHON_STANDARDS.md new file mode 100644 index 0000000..39d50dd --- /dev/null +++ b/PYTHON_STANDARDS.md @@ -0,0 +1,143 @@ +# Python Coding Standards + +**Note:** We prefer TypeScript/Bash, but when Python is necessary, follow these standards. + +## Type Hints (Required) + +Always use type hints for function parameters and return values. + +### Function Signatures + +```python +from typing import List, Dict, Optional, Tuple + +def install_tools( + tools: Optional[List[str]] = None, + distro_type: str = 'unknown', + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install tools with type-safe parameters + + Args: + tools: List of package names (None for all) + distro_type: Distro type for filtering + logger: Logger instance + + Returns: + True if successful + """ + pass +``` + +### Variable Type Hints + +```python +# Simple types +count: int = 0 +name: str = "toolbelt" +is_installed: bool = True + +# Collections +tools: List[str] = ["nmap", "masscan"] +config: Dict[str, str] = {"key": "value"} +result: Tuple[str, int] = ("success", 200) + +# Optional values +logger: Optional[logging.Logger] = None +``` + +### Common Types + +```python +from typing import List, Dict, Set, Tuple, Optional, Union, Any + +# Lists +packages: List[str] = [] + +# Dictionaries +tool_config: Dict[str, Any] = {} + +# Optional (can be None) +logger: Optional[logging.Logger] = None + +# Union (multiple types) +result: Union[str, int] = "success" + +# Tuples with specific types +coordinates: Tuple[int, int] = (10, 20) +``` + +## Why Type Hints Matter + +1. **Catch bugs early** - Type checkers find errors before runtime +2. **Better IDE support** - Autocomplete knows what methods exist +3. **Documentation** - Function signatures show what to pass +4. **Refactoring safety** - Change types, find all affected code + +## Type Checking + +Run type checker before committing: + +```bash +# Install mypy +pip3 install mypy + +# Check types +mypy toolbelt.py utils.py config.py installer.py +``` + +## When to Skip Type Hints + +- Quick throwaway scripts (< 50 lines) +- Interactive REPL exploration +- Never skip in production code + +## Additional Standards + +### Imports + +```python +# Standard library first +import os +import sys +from pathlib import Path + +# Third party +import requests + +# Local modules +from utils import setup_logging +import config +``` + +### Error Handling + +```python +# Specific exceptions, not bare except +try: + result = risky_operation() +except FileNotFoundError as e: + logger.error(f"File not found: {e}") +except PermissionError as e: + logger.error(f"Permission denied: {e}") +except Exception as e: + logger.error(f"Unexpected error: {e}") + raise +``` + +### Logging + +```python +# Use logging, not print (for production code) +import logging + +logger = logging.getLogger(__name__) +logger.info("Operation started") +logger.warning("Potential issue") +logger.error("Operation failed") +``` + +## Bottom Line + +**If we must use Python, we do it right. Type hints are non-negotiable for production code.** diff --git a/README.md b/README.md index ef2bc7c..b356b95 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ wfuzz, arjun, scrapy, tld, requests, fuzzywuzzy - **Python:** 3.6+ - **Package Manager:** apt - **Privileges:** sudo access (script runs as user, not root) +- **Optional:** gum (for interactive multi-select) - `go install github.com/charmbracelet/gum@latest` --- @@ -163,9 +164,25 @@ python3 toolbelt.py python3 toolbelt.py # Select: 2) Browse & Select Categories # Choose category (e.g., Go Tools) -# Install all or select specific tools +# Option 1: Install all tools +# Option 2: Select specific tools (interactive multi-select with gum) ``` +### Interactive Tool Selection (gum) + +With gum installed, you get beautiful interactive multi-select: + +```bash +python3 toolbelt.py +# Select: 2) Browse & Select Categories +# Choose: Go Tools +# Select: 2) Select Specific Tools +# Use SPACE to toggle, ENTER when done +# Confirm selection and install +``` + +**Without gum:** The script will prompt you to install it or fall back to "Install All" option. + ### Check Installed Tools ```bash diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..0b69af3 --- /dev/null +++ b/TODO.md @@ -0,0 +1,338 @@ +# Toolbelt Enhancement TODO + +## v2.1 Priority Features + +### 1. Tool Update Detection ⭐⭐⭐ +**Priority: HIGH** + +Check which Go tools have updates available and provide interactive update menu. + +```python +# Compare installed version vs @latest +# Show which tools need updates +# Bulk update option +``` + +**Implementation:** +- Query `go list -m` for installed versions +- Compare against `@latest` from go.dev +- Interactive menu to select which tools to update + +--- + +### 2. Individual Tool Selection (Level 3) ⭐⭐⭐ +**Priority: HIGH** + +Replace "Coming Soon" with actual tool selection using gum. + +**Using `gum choose --no-limit` for multi-select:** + +```bash +# Install gum first +go install github.com/charmbracelet/gum@latest + +# Then use in Python via subprocess +selected = subprocess.run( + ['gum', 'choose', '--no-limit'] + tool_list, + capture_output=True, + text=True +).stdout.strip().split('\n') +``` + +**Implementation Plan:** +1. Add gum as optional dependency (install if not present) +2. In `tool_selection_menu()`, replace option 2 with gum multi-select +3. Pass selected tools to category installer +4. Fallback to sequential selection if gum not available + +**Example:** +```python +def select_apt_tools(distro_type: str) -> List[str]: + """Let user select specific APT tools with gum multi-select""" + all_tools = config.get_apt_tools_for_distro(distro_type) + + if check_command_exists('gum'): + # Multi-select with gum + result = subprocess.run( + ['gum', 'choose', '--no-limit', '--header', 'Select tools to install:'] + all_tools, + capture_output=True, + text=True + ) + selected = [t for t in result.stdout.strip().split('\n') if t] + return selected + else: + # Fallback: show list, let user pick + print_warning("Install gum for multi-select: go install github.com/charmbracelet/gum@latest") + # ... manual selection loop +``` + +--- + +### 3. Wordlist Management ⭐⭐ +**Priority: MEDIUM** + +Download and organize common wordlists for pentesting. + +**Wordlists to Include:** +- SecLists (already in APT tools, but organize it) +- rockyou.txt +- Daniel Miessler's lists +- Custom wordlists for subdomains, directories, passwords + +**Directory Structure:** +``` +~/wordlists/ +├── passwords/ +│ ├── rockyou.txt +│ └── common-passwords.txt +├── subdomains/ +│ ├── subdomains-top1mil.txt +│ └── dns-bruteforce.txt +├── directories/ +│ ├── common.txt +│ └── raft-large-directories.txt +└── usernames/ + └── common-usernames.txt +``` + +**Implementation:** +- New category: "Wordlist Management" +- Download from GitHub releases +- Extract and organize +- Create symlinks to common locations + +--- + +### 4. Resource Monitoring ⭐⭐ +**Priority: MEDIUM** + +Show disk space requirements before installation. + +**Features:** +- Check available disk space +- Estimate download size per category +- Warn if insufficient space +- Show progress during large downloads + +**Implementation:** +```python +def check_disk_space(required_gb: float) -> bool: + """Check if enough disk space available""" + stat = os.statvfs(os.path.expanduser('~')) + available_gb = (stat.f_bavail * stat.f_frsize) / (1024**3) + + if available_gb < required_gb: + print_error(f"Insufficient disk space!") + print_info(f"Required: {required_gb}GB, Available: {available_gb:.1f}GB") + return False + return True +``` + +--- + +### 5. Tool Usage Instructions (tldr) ⭐⭐ +**Priority: MEDIUM** + +Show basic usage examples after installing each tool. + +**Using tldr pages:** +```bash +# Install tldr +pip3 install tldr + +# Show usage +tldr nuclei +``` + +**Implementation:** +```python +def show_tool_usage(tool_name: str): + """Display quick usage guide for tool""" + if check_command_exists('tldr'): + subprocess.run(['tldr', tool_name]) + else: + # Fallback: show our own examples from config + if tool_name in TOOL_EXAMPLES: + print_info(f"\nQuick Start for {tool_name}:") + print(TOOL_EXAMPLES[tool_name]) +``` + +**Add to config.py:** +```python +TOOL_EXAMPLES = { + "nuclei": "nuclei -t /path/to/templates -u https://target.com", + "httpx": "cat domains.txt | httpx -status-code -title", + "subfinder": "subfinder -d target.com -o subdomains.txt", + # ... etc +} +``` + +--- + +### 6. Export/Import Configuration ⭐ +**Priority: LOW** + +Save and restore custom tool selections. + +**Format:** +```json +{ + "name": "my-custom-setup", + "created": "2025-10-31", + "distro": "kali", + "tools": { + "apt": ["nmap", "masscan", "burpsuite"], + "go": ["nuclei", "httpx", "subfinder"], + "scripts": true + } +} +``` + +**Implementation:** +- Save to `~/.config/toolbelt/configs/` +- Load previous configs +- Share between systems + +--- + +### 7. Workspace Setup ⭐ +**Priority: LOW** + +Create standard pentesting directory structure. + +**Directory Tree:** +``` +~/pentesting/ +├── targets/ +│ └── example.com/ +│ ├── recon/ +│ ├── scans/ +│ └── loot/ +├── wordlists/ (symlink to ~/wordlists) +├── tools/ (symlink to /opt) +└── reports/ +``` + +**Implementation:** +- New menu option: "Setup Workspace" +- Creates directories +- Adds .gitignore templates +- Initializes git repos where appropriate + +--- + +### 8. Tmux Integration (via tmux-recon) ⭐⭐⭐ +**Priority: HIGH** (After tmux-recon.py is done) + +**Menu Option:** +``` +7) 🚀 Launch Pentesting Environment (tmux-recon) + Advanced shell environment with tmux automation +``` + +**Action:** +- Check if tmux-recon is installed +- If not, prompt to clone and install +- If yes, launch tmux-recon automation + +**Implementation:** +```python +def launch_tmux_environment(): + """Launch tmux-recon pentesting environment""" + if not os.path.exists('/opt/tmux-recon'): + print_warning("tmux-recon not installed") + response = input("Clone and install tmux-recon? [y/N]: ") + if response.lower() == 'y': + # Clone and run tmux-recon + pass + else: + # Launch tmux-recon + subprocess.run(['/opt/tmux-recon/tmux-recon.py', '--auto']) +``` + +--- + +### 9. Health Check / Verify Installation ⭐ +**Priority: LOW** + +Verify all installed tools are working correctly. + +**Checks:** +- Run `--version` or `--help` on each tool +- Verify can execute +- Check for broken symlinks +- Report missing dependencies + +**Implementation:** +```python +def health_check(): + """Verify all installed tools work""" + broken_tools = [] + + for tool in installed_tools: + try: + subprocess.run([tool, '--version'], + capture_output=True, + timeout=5) + except Exception: + broken_tools.append(tool) + + if broken_tools: + print_error(f"Broken tools: {', '.join(broken_tools)}") +``` + +--- + +### 10. Progress Bars for Large Downloads ⭐ +**Priority: LOW** + +Better visual feedback during installation. + +**Using tqdm:** +```python +from tqdm import tqdm + +def download_with_progress(url: str, output: str): + """Download with progress bar""" + response = requests.get(url, stream=True) + total = int(response.headers.get('content-length', 0)) + + with open(output, 'wb') as f, tqdm( + total=total, + unit='B', + unit_scale=True, + desc=output + ) as bar: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + bar.update(len(chunk)) +``` + +--- + +## Implementation Priority + +**v2.1 (Next Release):** +1. Individual Tool Selection (gum multi-select) ✅ **COMPLETED** +2. Tool Update Detection 🔜 +3. Wordlist Management 🔜 + +**v2.2:** +4. Resource Monitoring +5. Usage Instructions (tldr) +6. Tmux-recon Integration + +**v2.3:** +7. Export/Import Configs +8. Workspace Setup +9. Health Check +10. Progress Bars + +--- + +## Notes + +- All features should maintain modular architecture +- Add comprehensive logging for new features +- Update README with each release +- Keep Python type hints for all new code diff --git a/images/flux_jedi-toolbelt_seed_0_1.jpeg b/images/flux_jedi-toolbelt_seed_0_1.jpeg new file mode 100644 index 0000000..a6542d0 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_0_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_10_1.jpeg b/images/flux_jedi-toolbelt_seed_10_1.jpeg new file mode 100644 index 0000000..cd06466 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_10_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_11_1.jpeg b/images/flux_jedi-toolbelt_seed_11_1.jpeg new file mode 100644 index 0000000..16bf4ba Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_11_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_12_1.jpeg b/images/flux_jedi-toolbelt_seed_12_1.jpeg new file mode 100644 index 0000000..357bd0d Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_12_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_13_1.jpeg b/images/flux_jedi-toolbelt_seed_13_1.jpeg new file mode 100644 index 0000000..b19d466 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_13_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_14_1.jpeg b/images/flux_jedi-toolbelt_seed_14_1.jpeg new file mode 100644 index 0000000..da47608 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_14_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_15_1.jpeg b/images/flux_jedi-toolbelt_seed_15_1.jpeg new file mode 100644 index 0000000..926c697 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_15_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_16_1.jpeg b/images/flux_jedi-toolbelt_seed_16_1.jpeg new file mode 100644 index 0000000..5ccb140 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_16_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_17_1.jpeg b/images/flux_jedi-toolbelt_seed_17_1.jpeg new file mode 100644 index 0000000..407aaa4 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_17_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_18_1.jpeg b/images/flux_jedi-toolbelt_seed_18_1.jpeg new file mode 100644 index 0000000..f1ba920 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_18_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_19_1.jpeg b/images/flux_jedi-toolbelt_seed_19_1.jpeg new file mode 100644 index 0000000..1ec4d20 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_19_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_1_1.jpeg b/images/flux_jedi-toolbelt_seed_1_1.jpeg new file mode 100644 index 0000000..624e953 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_1_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_2_1.jpeg b/images/flux_jedi-toolbelt_seed_2_1.jpeg new file mode 100644 index 0000000..54417d1 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_2_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_3_1.jpeg b/images/flux_jedi-toolbelt_seed_3_1.jpeg new file mode 100644 index 0000000..dbbd79d Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_3_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_4_1.jpeg b/images/flux_jedi-toolbelt_seed_4_1.jpeg new file mode 100644 index 0000000..bad386b Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_4_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_5_1.jpeg b/images/flux_jedi-toolbelt_seed_5_1.jpeg new file mode 100644 index 0000000..fedf98f Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_5_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_6_1.jpeg b/images/flux_jedi-toolbelt_seed_6_1.jpeg new file mode 100644 index 0000000..bd6eec8 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_6_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_7_1.jpeg b/images/flux_jedi-toolbelt_seed_7_1.jpeg new file mode 100644 index 0000000..820c53c Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_7_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_8_1.jpeg b/images/flux_jedi-toolbelt_seed_8_1.jpeg new file mode 100644 index 0000000..f552b31 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_8_1.jpeg differ diff --git a/images/flux_jedi-toolbelt_seed_9_1.jpeg b/images/flux_jedi-toolbelt_seed_9_1.jpeg new file mode 100644 index 0000000..7f9d297 Binary files /dev/null and b/images/flux_jedi-toolbelt_seed_9_1.jpeg differ diff --git a/toolbelt.py b/toolbelt.py index 89c97b5..64f9d79 100755 --- a/toolbelt.py +++ b/toolbelt.py @@ -16,6 +16,7 @@ from utils import ( check_apt, check_sudo, check_command_exists, + gum_multi_select, print_banner, print_section, print_success, @@ -259,8 +260,15 @@ def show_tool_selection_menu(category_id: str, distro_type: str): print_info(cat_info['description']) print() + # Check if gum is available + has_gum = check_command_exists('gum') + print(colorize("1)", 'green') + " Install All Tools in Category") - print(colorize("2)", 'green') + " Select Specific Tools (Coming Soon)") + if has_gum: + print(colorize("2)", 'green') + " Select Specific Tools (multi-select)") + else: + print(colorize("2)", 'green') + " Select Specific Tools (requires gum)") + print_info(" Install gum: go install github.com/charmbracelet/gum@latest") print() print(colorize("0)", 'red') + " Back") print() @@ -277,8 +285,7 @@ def tool_selection_menu(category_id: str, distro_type: str, logger): elif choice == '1': install_category_all(category_id, distro_type, logger) elif choice == '2': - print_warning("Individual tool selection coming in next update!") - input("\nPress Enter to continue...") + install_category_selected(category_id, distro_type, logger) else: print_error("Invalid option. Please try again.") input("\nPress Enter to continue...") @@ -313,6 +320,107 @@ def install_category_all(category_id: str, distro_type: str, logger): input("\nPress Enter to continue...") +def install_category_selected(category_id: str, distro_type: str, logger): + """Install selected tools from a category using gum multi-select""" + cat_info = config.CATEGORIES[category_id] + + # Check if gum is available + if not check_command_exists('gum'): + print() + print_error("gum is not installed!") + print_info("gum is required for interactive multi-select") + print() + print_info("Install gum with:") + print(" go install github.com/charmbracelet/gum@latest") + print() + print_info("Make sure $GOPATH/bin is in your PATH") + print() + input("Press Enter to continue...") + return + + print_section(f"Select {cat_info['name']}") + + # Get tool list based on category + tools_list: List[str] = [] + + if category_id == 'apt': + tools_list = config.get_apt_tools_for_distro(distro_type) + elif category_id == 'go': + tools_list = list(config.GO_TOOLS.keys()) + elif category_id == 'opt': + tools_list = list(config.get_opt_tools_for_distro(distro_type).keys()) + elif category_id == 'python': + tools_list = list(config.PYTHON_TOOLS.keys()) + elif category_id == 'docker': + tools_list = list(config.DOCKER_TOOLS.keys()) + elif category_id == 'scripts': + print() + print_info("Scripts category downloads all scripts as a set") + print_info("Use option 1 to install all scripts") + print() + input("Press Enter to continue...") + return + + if not tools_list: + print_error(f"No tools available for {cat_info['name']}") + input("\nPress Enter to continue...") + return + + # Show count + print_info(f"Available tools: {len(tools_list)}") + print() + print(colorize("TIP: Use SPACE to select, ENTER when done, Ctrl+C to cancel", 'yellow')) + print() + + # Use gum for multi-select + selected = gum_multi_select( + tools_list, + header=f"Select {cat_info['name']} to install:" + ) + + if not selected: + print() + print_warning("No tools selected") + input("\nPress Enter to continue...") + return + + # Show what was selected + print() + print_section(f"Installing {len(selected)} Selected Tools") + for tool in selected: + print(colorize(f" • {tool}", 'cyan')) + print() + + # Confirm installation + response = input(colorize("Proceed with installation? [Y/n]: ", 'yellow')).strip().lower() + if response == 'n': + print_warning("Installation cancelled") + input("\nPress Enter to continue...") + return + + # Install selected tools + success = False + + if category_id == 'apt': + success = installer.install_apt_tools(tools=selected, distro_type=distro_type, logger=logger) + elif category_id == 'go': + success = installer.install_go_tools(tools=selected, logger=logger) + elif category_id == 'opt': + success = installer.install_opt_tools(tools=selected, distro_type=distro_type, logger=logger) + elif category_id == 'python': + success = installer.install_python_tools(tools=selected, logger=logger) + elif category_id == 'docker': + success = installer.install_docker_tools(tools=selected, logger=logger) + + print() + if success: + print_success(f"Selected {cat_info['name']} installation complete!") + else: + print_warning(f"Selected {cat_info['name']} installation completed with some errors") + + input("\nPress Enter to continue...") + + # ============================================================================ # View Installed Tools # ============================================================================ diff --git a/utils.py b/utils.py index 440b8f2..4b0771f 100644 --- a/utils.py +++ b/utils.py @@ -170,6 +170,45 @@ def check_command_exists(command: str) -> bool: return False +def gum_multi_select( + options: List[str], + header: str = "Select items (space to select, enter when done):" +) -> List[str]: + """ + Use gum to let user multi-select from options + + Args: + options: List of options to choose from + header: Header text to display + + Returns: + List of selected options + """ + if not check_command_exists('gum'): + return [] + + try: + result = subprocess.run( + ['gum', 'choose', '--no-limit', '--header', header] + options, + capture_output=True, + text=True, + timeout=300 # 5 minute timeout + ) + + if result.returncode == 0: + # Parse output - one item per line + selected = [item.strip() for item in result.stdout.split('\n') if item.strip()] + return selected + return [] + + except subprocess.TimeoutExpired: + print_warning("Selection timed out") + return [] + except Exception as e: + logging.error(f"gum multi-select failed: {e}") + return [] + + def check_apt() -> bool: """Check if apt package manager is available""" return check_command_exists('apt')