Automated Action ab87d3c506 Implement comprehensive cryptocurrency exchange platform
- Built complete CEX platform with FastAPI and Python
- JWT-based authentication system with secure password hashing
- Multi-currency crypto wallet support (BTC, ETH, USDT)
- Fiat account management (USD, EUR, GBP)
- Local transaction signing without external APIs
- Comprehensive transaction handling (send/receive/deposit/withdraw)
- SQLAlchemy models with Alembic migrations
- Security middleware (rate limiting, headers, logging)
- Input validation and sanitization
- Encrypted private key storage with PBKDF2
- Standardized codebase architecture with service layer pattern
- Complete API documentation with health endpoints
- Comprehensive README with setup instructions

Features:
- User registration and authentication
- Crypto wallet creation and management
- Secure transaction signing using local private keys
- Fiat deposit/withdrawal system
- Transaction history and tracking
- Rate limiting and security headers
- Input validation for all endpoints
- Error handling and logging
2025-06-20 23:08:04 +00:00

133 lines
4.1 KiB
Python

import re
from fastapi import HTTPException, status
class ValidationUtils:
@staticmethod
def validate_email(email: str) -> bool:
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
@staticmethod
def validate_password(password: str) -> bool:
# At least 8 characters, one uppercase, one lowercase, one digit
if len(password) < 8:
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[a-z]', password):
return False
if not re.search(r'\d', password):
return False
return True
@staticmethod
def validate_phone_number(phone: str) -> bool:
# Basic international phone number validation
pattern = r'^\+?[1-9]\d{1,14}$'
return re.match(pattern, phone) is not None
@staticmethod
def validate_amount(amount: float, min_amount: float = 0.0001, max_amount: float = 1000000) -> bool:
if amount <= 0:
return False
if amount < min_amount or amount > max_amount:
return False
return True
@staticmethod
def validate_currency_code(currency: str) -> bool:
valid_currencies = ['BTC', 'ETH', 'USDT', 'USD', 'EUR', 'GBP']
return currency.upper() in valid_currencies
@staticmethod
def sanitize_string(input_string: str, max_length: int = 255) -> str:
if not input_string:
return ""
# Remove potentially dangerous characters
sanitized = re.sub(r'[<>"\']', '', input_string)
# Trim to max length
return sanitized[:max_length].strip()
@staticmethod
def validate_kyc_level(level: int) -> bool:
return level in [0, 1, 2]
@staticmethod
def validate_transaction_type(transaction_type: str) -> bool:
valid_types = ['SEND', 'RECEIVE', 'DEPOSIT', 'WITHDRAWAL']
return transaction_type.upper() in valid_types
def validate_required_fields(data: dict, required_fields: list) -> None:
"""Validate that all required fields are present and not empty"""
missing_fields = []
for field in required_fields:
if field not in data or not data[field]:
missing_fields.append(field)
if missing_fields:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Missing required fields: {', '.join(missing_fields)}"
)
def validate_user_registration(email: str, password: str, full_name: str) -> None:
"""Validate user registration data"""
if not ValidationUtils.validate_email(email):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid email format"
)
if not ValidationUtils.validate_password(password):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Password must be at least 8 characters with uppercase, lowercase, and digit"
)
if len(full_name.strip()) < 2:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Full name must be at least 2 characters"
)
def validate_transaction_amount(amount: float, currency: str) -> None:
"""Validate transaction amount based on currency"""
min_amounts = {
'BTC': 0.00001,
'ETH': 0.001,
'USDT': 0.01,
'USD': 0.01,
'EUR': 0.01,
'GBP': 0.01
}
max_amounts = {
'BTC': 100,
'ETH': 1000,
'USDT': 100000,
'USD': 100000,
'EUR': 100000,
'GBP': 100000
}
currency = currency.upper()
min_amount = min_amounts.get(currency, 0.01)
max_amount = max_amounts.get(currency, 100000)
if amount < min_amount:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Minimum amount for {currency} is {min_amount}"
)
if amount > max_amount:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Maximum amount for {currency} is {max_amount}"
)