Initial commit
This commit is contained in:
366
skills/inquirer-patterns/templates/python/password_prompt.py
Normal file
366
skills/inquirer-patterns/templates/python/password_prompt.py
Normal file
@@ -0,0 +1,366 @@
|
||||
"""
|
||||
Password Prompt Template
|
||||
|
||||
Use for: Sensitive input (credentials, tokens)
|
||||
Features: Hidden input, confirmation, validation
|
||||
"""
|
||||
|
||||
import questionary
|
||||
import re
|
||||
from questionary import ValidationError, Validator
|
||||
|
||||
|
||||
class PasswordStrengthValidator(Validator):
|
||||
"""Validator for password strength requirements"""
|
||||
|
||||
def __init__(self, min_length=8, require_uppercase=True, require_lowercase=True,
|
||||
require_digit=True, require_special=True):
|
||||
self.min_length = min_length
|
||||
self.require_uppercase = require_uppercase
|
||||
self.require_lowercase = require_lowercase
|
||||
self.require_digit = require_digit
|
||||
self.require_special = require_special
|
||||
|
||||
def validate(self, document):
|
||||
password = document.text
|
||||
issues = []
|
||||
|
||||
if len(password) < self.min_length:
|
||||
issues.append(f"at least {self.min_length} characters")
|
||||
|
||||
if self.require_uppercase and not re.search(r'[A-Z]', password):
|
||||
issues.append("an uppercase letter")
|
||||
|
||||
if self.require_lowercase and not re.search(r'[a-z]', password):
|
||||
issues.append("a lowercase letter")
|
||||
|
||||
if self.require_digit and not re.search(r'[0-9]', password):
|
||||
issues.append("a number")
|
||||
|
||||
if self.require_special and not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
|
||||
issues.append("a special character")
|
||||
|
||||
if issues:
|
||||
raise ValidationError(
|
||||
message=f"Password must contain: {', '.join(issues)}",
|
||||
cursor_position=len(password)
|
||||
)
|
||||
|
||||
|
||||
class APIKeyValidator(Validator):
|
||||
"""Validator for API key format"""
|
||||
|
||||
def validate(self, document):
|
||||
api_key = document.text
|
||||
|
||||
if len(api_key) == 0:
|
||||
raise ValidationError(
|
||||
message="API key is required",
|
||||
cursor_position=0
|
||||
)
|
||||
|
||||
if not (api_key.startswith('sk-') or api_key.startswith('pk-')):
|
||||
raise ValidationError(
|
||||
message='API key must start with "sk-" or "pk-"',
|
||||
cursor_position=len(api_key)
|
||||
)
|
||||
|
||||
if len(api_key) < 32:
|
||||
raise ValidationError(
|
||||
message="API key appears to be too short",
|
||||
cursor_position=len(api_key)
|
||||
)
|
||||
|
||||
|
||||
def calculate_password_strength(password):
|
||||
"""Calculate password strength score"""
|
||||
strength = 0
|
||||
|
||||
if len(password) >= 8:
|
||||
strength += 1
|
||||
if len(password) >= 12:
|
||||
strength += 1
|
||||
if re.search(r'[a-z]', password):
|
||||
strength += 1
|
||||
if re.search(r'[A-Z]', password):
|
||||
strength += 1
|
||||
if re.search(r'[0-9]', password):
|
||||
strength += 1
|
||||
if re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
|
||||
strength += 1
|
||||
|
||||
levels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong', 'Very Strong']
|
||||
return levels[min(strength, len(levels) - 1)]
|
||||
|
||||
|
||||
def password_prompt_example():
|
||||
"""Example password prompts with validation"""
|
||||
|
||||
print("\n🔒 Password Prompt Example\n")
|
||||
|
||||
# Password with strength validation
|
||||
password = questionary.password(
|
||||
"Enter your password:",
|
||||
validate=PasswordStrengthValidator(min_length=8)
|
||||
).ask()
|
||||
|
||||
# Confirm password
|
||||
confirm_password = questionary.password(
|
||||
"Confirm your password:",
|
||||
validate=lambda text: text == password or "Passwords do not match"
|
||||
).ask()
|
||||
|
||||
print(f"\n✅ Password strength: {calculate_password_strength(password)}")
|
||||
|
||||
# API key input
|
||||
api_key = questionary.password(
|
||||
"Enter your API key:",
|
||||
validate=APIKeyValidator()
|
||||
).ask()
|
||||
|
||||
print(f"✅ API key format: {api_key[:6]}...")
|
||||
|
||||
# Optional encryption key
|
||||
encryption_key = questionary.password(
|
||||
"Enter encryption key (optional, press Enter to skip):",
|
||||
validate=lambda text: len(text) == 0 or len(text) >= 16 or "Encryption key must be at least 16 characters"
|
||||
).ask()
|
||||
|
||||
# Don't log actual passwords!
|
||||
answers = {
|
||||
'passwordSet': True,
|
||||
'passwordStrength': calculate_password_strength(password),
|
||||
'apiKeyPrefix': api_key[:6],
|
||||
'encryptionKeySet': len(encryption_key) > 0
|
||||
}
|
||||
|
||||
print("\n✅ Credentials received (not displayed for security)")
|
||||
import json
|
||||
print(json.dumps(answers, indent=2))
|
||||
|
||||
return answers
|
||||
|
||||
|
||||
def secure_account_setup():
|
||||
"""Example: Complete secure account setup"""
|
||||
|
||||
print("\n🔐 Secure Account Setup\n")
|
||||
|
||||
# Username
|
||||
username = questionary.text(
|
||||
"Username:",
|
||||
validate=lambda text: len(text) > 0 or "Username required"
|
||||
).ask()
|
||||
|
||||
# Strong password
|
||||
print("\n📝 Password requirements:")
|
||||
print(" • At least 12 characters")
|
||||
print(" • Uppercase and lowercase letters")
|
||||
print(" • Numbers")
|
||||
print(" • Special characters (!@#$%^&*)")
|
||||
print()
|
||||
|
||||
password = questionary.password(
|
||||
"Password:",
|
||||
validate=PasswordStrengthValidator(
|
||||
min_length=12,
|
||||
require_uppercase=True,
|
||||
require_lowercase=True,
|
||||
require_digit=True,
|
||||
require_special=True
|
||||
)
|
||||
).ask()
|
||||
|
||||
# Confirm password
|
||||
confirm = questionary.password(
|
||||
"Confirm password:",
|
||||
validate=lambda text: text == password or "Passwords do not match"
|
||||
).ask()
|
||||
|
||||
# Optional: Remember credentials
|
||||
remember = questionary.confirm(
|
||||
"Remember credentials? (stored securely)",
|
||||
default=False
|
||||
).ask()
|
||||
|
||||
strength = calculate_password_strength(password)
|
||||
|
||||
print(f"\n✅ Account created for: {username}")
|
||||
print(f"🔒 Password strength: {strength}")
|
||||
|
||||
if remember:
|
||||
print("💾 Credentials will be stored securely")
|
||||
|
||||
return {
|
||||
'username': username,
|
||||
'passwordStrength': strength,
|
||||
'remember': remember
|
||||
}
|
||||
|
||||
|
||||
def database_credentials_setup():
|
||||
"""Example: Database connection credentials"""
|
||||
|
||||
print("\n🗄️ Database Credentials Setup\n")
|
||||
|
||||
# Database username
|
||||
db_user = questionary.text(
|
||||
"Database username:",
|
||||
default="postgres",
|
||||
validate=lambda text: len(text) > 0 or "Username required"
|
||||
).ask()
|
||||
|
||||
# Database password
|
||||
db_password = questionary.password(
|
||||
"Database password:",
|
||||
validate=lambda text: len(text) >= 8 or "Password must be at least 8 characters"
|
||||
).ask()
|
||||
|
||||
# Admin password (if needed)
|
||||
is_admin = questionary.confirm(
|
||||
"Create admin user?",
|
||||
default=False
|
||||
).ask()
|
||||
|
||||
admin_password = None
|
||||
if is_admin:
|
||||
admin_password = questionary.password(
|
||||
"Admin password:",
|
||||
validate=PasswordStrengthValidator(min_length=12)
|
||||
).ask()
|
||||
|
||||
admin_confirm = questionary.password(
|
||||
"Confirm admin password:",
|
||||
validate=lambda text: text == admin_password or "Passwords do not match"
|
||||
).ask()
|
||||
|
||||
print(f"\n✅ Admin password strength: {calculate_password_strength(admin_password)}")
|
||||
|
||||
credentials = {
|
||||
'dbUser': db_user,
|
||||
'dbPasswordSet': True,
|
||||
'adminConfigured': is_admin
|
||||
}
|
||||
|
||||
print("\n✅ Database credentials configured")
|
||||
import json
|
||||
print(json.dumps(credentials, indent=2))
|
||||
|
||||
return credentials
|
||||
|
||||
|
||||
def api_token_setup():
|
||||
"""Example: API token and secret key setup"""
|
||||
|
||||
print("\n🔑 API Token Setup\n")
|
||||
|
||||
# API key
|
||||
api_key = questionary.password(
|
||||
"Enter API key:",
|
||||
validate=lambda text: len(text) > 0 or "API key required"
|
||||
).ask()
|
||||
|
||||
# Secret key
|
||||
secret_key = questionary.password(
|
||||
"Enter secret key:",
|
||||
validate=lambda text: len(text) >= 32 or "Secret key must be at least 32 characters"
|
||||
).ask()
|
||||
|
||||
# Webhook secret (optional)
|
||||
use_webhooks = questionary.confirm(
|
||||
"Configure webhook authentication?",
|
||||
default=False
|
||||
).ask()
|
||||
|
||||
webhook_secret = None
|
||||
if use_webhooks:
|
||||
webhook_secret = questionary.password(
|
||||
"Webhook secret:",
|
||||
validate=lambda text: len(text) >= 16 or "Webhook secret must be at least 16 characters"
|
||||
).ask()
|
||||
|
||||
# Environment
|
||||
environment = questionary.select(
|
||||
"Environment:",
|
||||
choices=['Development', 'Staging', 'Production']
|
||||
).ask()
|
||||
|
||||
config = {
|
||||
'apiKeySet': True,
|
||||
'secretKeySet': True,
|
||||
'webhookConfigured': use_webhooks,
|
||||
'environment': environment
|
||||
}
|
||||
|
||||
print("\n✅ API credentials configured")
|
||||
print(f"Environment: {environment}")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def password_change_flow():
|
||||
"""Example: Password change with old password verification"""
|
||||
|
||||
print("\n🔄 Change Password\n")
|
||||
|
||||
# Old password (in real app, verify against stored hash)
|
||||
old_password = questionary.password(
|
||||
"Enter current password:",
|
||||
validate=lambda text: len(text) > 0 or "Current password required"
|
||||
).ask()
|
||||
|
||||
# New password
|
||||
new_password = questionary.password(
|
||||
"Enter new password:",
|
||||
validate=PasswordStrengthValidator(min_length=8)
|
||||
).ask()
|
||||
|
||||
# Ensure new password is different
|
||||
if new_password == old_password:
|
||||
print("\n❌ New password must be different from current password")
|
||||
return password_change_flow()
|
||||
|
||||
# Confirm new password
|
||||
confirm_password = questionary.password(
|
||||
"Confirm new password:",
|
||||
validate=lambda text: text == new_password or "Passwords do not match"
|
||||
).ask()
|
||||
|
||||
print(f"\n✅ Password changed successfully")
|
||||
print(f"🔒 New password strength: {calculate_password_strength(new_password)}")
|
||||
|
||||
return {'passwordChanged': True}
|
||||
|
||||
|
||||
def main():
|
||||
"""Run password prompt examples"""
|
||||
try:
|
||||
print("=== Password Prompt Examples ===")
|
||||
|
||||
# Example 1: Basic password prompts
|
||||
password_prompt_example()
|
||||
|
||||
# Example 2: Secure account setup
|
||||
secure_account_setup()
|
||||
|
||||
# Example 3: Database credentials
|
||||
database_credentials_setup()
|
||||
|
||||
# Example 4: API token setup
|
||||
api_token_setup()
|
||||
|
||||
# Example 5: Password change
|
||||
password_change_flow()
|
||||
|
||||
print("\n✅ Password prompt examples complete!")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n❌ User interrupted prompt")
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
print(f"\n\n❌ Error: {e}")
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user