# Rustelo Crypto Module

A comprehensive encryption/decryption system for securing sensitive data in Rustelo applications, including session user information and configuration values.

## Features

- **AES-256-GCM encryption** for maximum security
- **Encrypted user sessions** with automatic expiration
- **Encrypted configuration values** for sensitive data like database URLs and API keys
- **Integration with existing auth system** 
- **Middleware support** for automatic session handling
- **Environment variable encryption** for production deployment
- **Key management** with automatic generation and rotation support

## Quick Start

### 1. Initialize the Crypto System

```rust
use server::crypto::{CryptoService, integration::AppStateWithCrypto};
use std::sync::Arc;

// Initialize crypto service
let crypto = Arc::new(CryptoService::new()?);

// Initialize full crypto system with session and config stores
let app_state = AppStateWithCrypto::new().await?;
```

### 2. Basic String Encryption

```rust
let crypto = CryptoService::new()?;

// Encrypt a string
let encrypted = crypto.encrypt_string("sensitive data")?;
println!("Encrypted: {}", encrypted);

// Decrypt it back
let decrypted = crypto.decrypt_string(&encrypted)?;
println!("Decrypted: {}", decrypted);
```

### 3. Encrypt User Session Data

```rust
use server::crypto::session::{EncryptedSessionStore, EncryptedSessionConfig};

// Create session store
let session_config = EncryptedSessionConfig::default();
let session_store = EncryptedSessionStore::new(crypto.clone(), session_config);

// Create encrypted session for user
let encrypted_session = session_store.create_session(&user)?;

// Later, retrieve session data
let session_data = session_store.get_session(&encrypted_session)?;
```

### 4. Encrypt Configuration Values

```rust
use server::crypto::config::{EncryptedConfigStore, EncryptedConfigBuilder};

// Create config store
let config_store = EncryptedConfigBuilder::new(crypto.clone())
    .with_file("config/encrypted.json".to_string())
    .with_auto_load_env()
    .build()
    .await?;

// Store encrypted database URL
config_store.set_encrypted(
    "database_url", 
    "postgresql://user:password@localhost/db".to_string(),
    Some("Production database".to_string())
)?;

// Retrieve decrypted value
let db_url = config_store.get("database_url")?;
```

## Environment Setup

### Required Environment Variables

```bash
# Crypto key for encryption/decryption (base64 encoded)
CRYPTO_KEY=your-32-byte-key-base64-encoded

# Optional: Environment type affects cookie security
ENVIRONMENT=production

# Optional: Cookie domain for sessions
COOKIE_DOMAIN=yourdomain.com
```

### Generate a New Crypto Key

```rust
use server::crypto::CryptoService;

// Generate a new key
let key = CryptoService::generate_key_base64();
println!("New crypto key: {}", key);
```

Or use the CLI tool:

```bash
# Generate new key
cargo run --bin config_tool -- generate-key

# Encrypt a value
cargo run --bin config_tool -- encrypt "sensitive-value"

# Decrypt a value
cargo run --bin config_tool -- decrypt "encrypted-base64-value"
```

## Session Management

### Configuration

```rust
use server::crypto::session::EncryptedSessionConfig;

let session_config = EncryptedSessionConfig {
    cookie_name: "rustelo_session".to_string(),
    session_lifetime: 3600 * 24, // 24 hours
    secure: true,                // HTTPS only in production
    http_only: true,            // Prevent XSS
    path: "/".to_string(),
    domain: Some("yourdomain.com".to_string()),
    same_site: tower_cookies::SameSite::Lax,
};
```

### User Login with Encrypted Session

```rust
use server::crypto::session::session_helpers;

// Login user and create encrypted session
let encrypted_session = session_helpers::login_user(
    &session_store,
    &cookies,
    &user
).await?;

// Session cookie is automatically set
```

### Middleware Integration

```rust
use server::crypto::session::{
    encrypted_session_middleware,
    require_auth_middleware,
    require_role_middleware,
    EncryptedSessionExt
};
use axum::middleware;

// Add session middleware
let app = Router::new()
    .route("/protected", get(protected_handler))
    .layer(middleware::from_fn_with_state(
        session_store.clone(),
        encrypted_session_middleware
    ))
    .layer(middleware::from_fn(require_auth_middleware));

// Use session data in handlers
async fn protected_handler(request: Request) -> Result<Json<User>, StatusCode> {
    if let Some(user) = request.current_user() {
        Ok(Json(user))
    } else {
        Err(StatusCode::UNAUTHORIZED)
    }
}
```

## Configuration Management

### Automatic Environment Loading

```rust
use server::crypto::config::EncryptedConfigBuilder;

let config_store = EncryptedConfigBuilder::new(crypto.clone())
    .with_file("config/encrypted.json".to_string())
    .with_auto_load_env() // Loads common secrets from environment
    .with_env_mapping("custom_api_key".to_string(), "API_KEY".to_string())
    .build()
    .await?;
```

### Supported Environment Variables

When using `with_auto_load_env()`, these variables are automatically encrypted:

- `DATABASE_URL` → `database_url`
- `JWT_SECRET` → `jwt_secret`
- `SESSION_SECRET` → `session_secret`
- `GOOGLE_CLIENT_SECRET` → `oauth_google_client_secret`
- `GITHUB_CLIENT_SECRET` → `oauth_github_client_secret`
- `SMTP_PASSWORD` → `smtp_password`
- `REDIS_PASSWORD` → `redis_password`
- `STRIPE_SECRET_KEY` → `stripe_secret_key`
- `AWS_SECRET_ACCESS_KEY` → `aws_secret_access_key`
- `OPENAI_API_KEY` → `openai_api_key`

### Configuration File Format

```json
{
  "database_url": {
    "encrypted": "base64-encoded-encrypted-data",
    "hint": "Production database URL",
    "encrypted_at": 1640995200
  },
  "jwt_secret": {
    "encrypted": "base64-encoded-encrypted-data",
    "hint": "JWT signing secret",
    "encrypted_at": 1640995200
  },
  "api_timeout": "30",
  "debug_mode": "false"
}
```

## Security Features

### User Data Encryption

All sensitive user data is encrypted in sessions:

- User ID, email, username
- Display name and profile information
- User roles and permissions
- Categories and tags
- User preferences
- Session metadata

### Configuration Encryption

Sensitive configuration values are encrypted at rest:

- Database connection strings
- API keys and secrets
- OAuth client secrets
- Email server passwords
- Third-party service credentials

### Key Management

- **Automatic key generation** if not provided
- **Base64 encoding** for easy storage
- **Key rotation support** (manual)
- **Environment-based configuration**

## API Reference

### CryptoService

```rust
impl CryptoService {
    // Create new service (loads key from environment)
    pub fn new() -> Result<Self, CryptoError>
    
    // Create with specific key
    pub fn with_key(key_bytes: &[u8]) -> Result<Self, CryptoError>
    
    // Encrypt/decrypt strings
    pub fn encrypt_string(&self, data: &str) -> Result<String, CryptoError>
    pub fn decrypt_string(&self, encrypted: &str) -> Result<String, CryptoError>
    
    // Encrypt/decrypt JSON objects
    pub fn encrypt_json<T: Serialize>(&self, data: &T) -> Result<String, CryptoError>
    pub fn decrypt_json<T: DeserializeOwned>(&self, encrypted: &str) -> Result<T, CryptoError>
    
    // Key management
    pub fn generate_key_base64() -> String
    pub fn get_key_base64(&self) -> String
}
```

### EncryptedSessionStore

```rust
impl EncryptedSessionStore {
    // Create new store
    pub fn new(crypto: Arc<CryptoService>, config: EncryptedSessionConfig) -> Self
    
    // Session management
    pub fn create_session(&self, user: &User) -> Result<String, CryptoError>
    pub fn get_session(&self, encrypted: &str) -> Result<EncryptedSessionData, CryptoError>
    pub fn refresh_session(&self, user: &User) -> Result<String, CryptoError>
    
    // Cookie management
    pub fn set_session_cookie(&self, cookies: &Cookies, session: &str)
    pub fn get_session_cookie(&self, cookies: &Cookies) -> Option<String>
    pub fn remove_session_cookie(&self, cookies: &Cookies)
}
```

### EncryptedConfigStore

```rust
impl EncryptedConfigStore {
    // Create new store
    pub fn new(crypto: Arc<CryptoService>) -> Self
    
    // Value management
    pub fn set_plain(&mut self, key: &str, value: String)
    pub fn set_encrypted(&mut self, key: &str, value: String, hint: Option<String>) -> Result<(), CryptoError>
    pub fn get(&self, key: &str) -> Result<Option<String>, CryptoError>
    pub fn get_or_default(&self, key: &str, default: &str) -> Result<String, CryptoError>
    
    // File operations
    pub async fn load_from_file(&mut self, file: &str) -> Result<(), CryptoError>
    pub async fn save_to_file(&self, file: &str) -> Result<(), CryptoError>
    
    // Environment integration
    pub async fn load_from_env(&mut self, mappings: &[(&str, &str)]) -> Result<(), CryptoError>
    pub async fn init_with_common_secrets(&mut self) -> Result<(), CryptoError>
}
```

## Integration Examples

### Complete Auth System Integration

```rust
use server::crypto::integration::{AppStateWithCrypto, create_crypto_routes};
use axum::Router;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize crypto system
    let app_state = AppStateWithCrypto::new().await?;
    
    // Create router with crypto-enabled routes
    let app = create_crypto_routes()
        .with_state(app_state);
    
    // Start server
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
    axum::serve(listener, app).await?;
    
    Ok(())
}
```

### Database Integration

```rust
use sqlx::PgPool;

async fn connect_database(config_store: &EncryptedConfigStore) -> Result<PgPool, sqlx::Error> {
    let database_url = config_store.get("database_url")
        .map_err(|e| sqlx::Error::Configuration(e.to_string()))?
        .ok_or_else(|| sqlx::Error::Configuration("Database URL not found".to_string()))?;
    
    PgPool::connect(&database_url).await
}
```

### JWT Integration

```rust
use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};

async fn create_jwt_service(config_store: &EncryptedConfigStore) -> Result<JwtService, Box<dyn std::error::Error>> {
    let secret = config_store.get("jwt_secret")?
        .ok_or("JWT secret not found")?;
    
    Ok(JwtService::new(&secret))
}
```

## Performance Considerations

- **Encryption overhead**: AES-256-GCM is fast but adds ~1-2ms per operation
- **Session storage**: Encrypted sessions are larger than plain text (base64 + metadata)
- **Key management**: Keep crypto keys in memory for performance
- **Caching**: Consider caching decrypted config values for frequently accessed data

## Security Best Practices

1. **Always use HTTPS** in production with `secure: true` cookies
2. **Set strong crypto keys** (32 bytes, randomly generated)
3. **Rotate keys regularly** (implement key rotation strategy)
4. **Use environment variables** for sensitive keys, not config files
5. **Validate session expiration** on every request
6. **Log security events** but never log decrypted data
7. **Use HTTP-only cookies** to prevent XSS attacks

## Troubleshooting

### Common Issues

**"Invalid key format" error**
- Ensure `CRYPTO_KEY` is base64 encoded and represents 32 bytes
- Generate new key with `CryptoService::generate_key_base64()`

**"Decryption failed" error**
- Key might have changed since encryption
- Data might be corrupted
- Check if data format is correct

**"Session expired" error**
- Session lifetime exceeded
- User needs to login again
- Check session configuration

### Debug Mode

```rust
// Enable debug logging
std::env::set_var("RUST_LOG", "server::crypto=debug");
tracing_subscriber::init();
```

### Testing

```bash
# Run all crypto tests
cargo test crypto

# Run specific test
cargo test crypto::tests::test_encryption

# Run integration tests
cargo test crypto::integration::tests
```

## Migration Guide

### From Plain Text Sessions

```rust
// Old: Plain text session
let session_data = serde_json::to_string(&user)?;
cookies.add(Cookie::new("session", session_data));

// New: Encrypted session
let encrypted_session = session_store.create_session(&user)?;
session_store.set_session_cookie(&cookies, &encrypted_session);
```

### From Environment Variables

```rust
// Old: Direct environment access
let db_url = std::env::var("DATABASE_URL")?;

// New: Encrypted config
let db_url = config_store.get("database_url")?
    .ok_or("Database URL not configured")?;
```

## Contributing

When adding new crypto features:

1. **Add comprehensive tests** for all new functionality
2. **Document security implications** in code comments
3. **Follow existing patterns** for error handling and logging
4. **Update this README** with new features and examples
5. **Consider backward compatibility** when changing APIs

## License

This crypto module is part of the Rustelo framework and follows the same MIT license.

## Complete Usage Example

Here's a comprehensive example showing how to integrate all crypto features:

### 1. Environment Setup (.env file)

```bash
# Crypto configuration
CRYPTO_KEY=your-32-byte-key-base64-encoded
ENVIRONMENT=development
SESSION_LIFETIME_HOURS=24
ENCRYPTED_CONFIG_FILE=config/encrypted.json
COOKIE_DOMAIN=localhost

# Sensitive values that will be encrypted
DATABASE_URL=postgresql://user:password@localhost/rustelo_dev
JWT_SECRET=your-jwt-secret-key
SMTP_PASSWORD=your-smtp-password
GOOGLE_CLIENT_SECRET=your-google-oauth-secret
GITHUB_CLIENT_SECRET=your-github-oauth-secret
```

### 2. Initialize Crypto System

```rust
use server::crypto::{
    CryptoService,
    config::EncryptedConfigBuilder,
    session::{EncryptedSessionStore, EncryptedSessionConfig},
};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize crypto service
    let crypto = Arc::new(CryptoService::new()?);
    
    // Initialize encrypted config store
    let config_store = Arc::new(
        EncryptedConfigBuilder::new(crypto.clone())
            .with_file("config/encrypted.json".to_string())
            .with_auto_load_env() // Automatically encrypt env vars
            .build()
            .await?
    );
    
    // Initialize encrypted session store
    let session_config = EncryptedSessionConfig {
        cookie_name: "rustelo_session".to_string(),
        session_lifetime: 24 * 3600, // 24 hours
        secure: std::env::var("ENVIRONMENT").unwrap_or_default() == "production",
        http_only: true,
        path: "/".to_string(),
        domain: std::env::var("COOKIE_DOMAIN").ok(),
        same_site: tower_cookies::SameSite::Lax,
    };
    let session_store = Arc::new(EncryptedSessionStore::new(crypto.clone(), session_config));
    
    // Your app logic here...
    
    Ok(())
}
```

### 3. Database Connection with Encrypted URL

```rust
use sqlx::PgPool;

async fn connect_database(
    config_store: &EncryptedConfigStore
) -> Result<PgPool, Box<dyn std::error::Error>> {
    // Get encrypted database URL
    let database_url = config_store.get("database_url")?
        .ok_or("Database URL not found")?;
    
    // Connect to database
    let pool = PgPool::connect(&database_url).await?;
    
    println!("✓ Database connected successfully");
    Ok(pool)
}
```

### 4. Login Handler with Encrypted Sessions

```rust
use axum::{extract::State, response::Json, http::StatusCode};
use tower_cookies::Cookies;
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct LoginRequest {
    email: String,
    password: String,
}

#[derive(Serialize)]
struct LoginResponse {
    success: bool,
    user: User,
    session_expires_in: i64,
}

async fn login_handler(
    State(session_store): State<Arc<EncryptedSessionStore>>,
    cookies: Cookies,
    Json(login_req): Json<LoginRequest>,
) -> Result<Json<LoginResponse>, StatusCode> {
    // Validate credentials (implement your validation logic)
    let user = validate_user_credentials(&login_req.email, &login_req.password)
        .await
        .map_err(|_| StatusCode::UNAUTHORIZED)?;
    
    // Create encrypted session
    let encrypted_session = session_store.create_session(&user)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Set session cookie
    session_store.set_session_cookie(&cookies, &encrypted_session);
    
    Ok(Json(LoginResponse {
        success: true,
        user,
        session_expires_in: session_store.config.session_lifetime,
    }))
}
```

### 5. Protected Route with Session Validation

```rust
use server::crypto::session::EncryptedSessionExt;

async fn protected_route(
    State(session_store): State<Arc<EncryptedSessionStore>>,
    cookies: Cookies,
) -> Result<Json<serde_json::Value>, StatusCode> {
    // Get encrypted session
    if let Some(encrypted_session) = session_store.get_session_cookie(&cookies) {
        match session_store.get_session(&encrypted_session) {
            Ok(session_data) => {
                // Session is valid, return protected data
                Ok(Json(serde_json::json!({
                    "message": "Access granted",
                    "user": {
                        "id": session_data.user_id,
                        "email": session_data.email,
                        "categories": session_data.categories,
                        "tags": session_data.tags,
                        "preferences": session_data.preferences,
                    }
                })))
            }
            Err(_) => {
                // Invalid session, remove cookie
                session_store.remove_session_cookie(&cookies);
                Err(StatusCode::UNAUTHORIZED)
            }
        }
    } else {
        Err(StatusCode::UNAUTHORIZED)
    }
}
```

### 6. Middleware Setup

```rust
use axum::{Router, middleware, routing::{get, post}};
use tower_cookies::CookieManagerLayer;
use server::crypto::session::encrypted_session_middleware;

fn create_app(
    session_store: Arc<EncryptedSessionStore>
) -> Router {
    Router::new()
        // Public routes
        .route("/api/login", post(login_handler))
        .route("/api/logout", post(logout_handler))
        // Protected routes
        .route("/api/dashboard", get(protected_route))
        .route("/api/profile", get(get_profile))
        // Add state
        .with_state(session_store.clone())
        // Add cookie middleware
        .layer(CookieManagerLayer::new())
        // Add encrypted session middleware
        .layer(middleware::from_fn_with_state(
            session_store,
            encrypted_session_middleware
        ))
}
```

### 7. Configuration Management

```rust
// Add encrypted config value
config_store.set_encrypted(
    "stripe_secret_key",
    "sk_test_your_stripe_secret_key".to_string(),
    Some("Stripe API secret key".to_string())
)?;

// Get encrypted config value
let stripe_key = config_store.get("stripe_secret_key")?
    .ok_or("Stripe key not configured")?;

// Use with third-party service
let stripe_client = stripe::Client::new(stripe_key);
```

### 8. CLI Tool Usage

```bash
# Generate new crypto key
cargo run --bin crypto_tool generate-key --output .crypto_key

# Initialize encrypted config
cargo run --bin crypto_tool init-config --load-env

# Add encrypted value
cargo run --bin crypto_tool add-value \
  --key "api_key" \
  --value "your-secret-api-key" \
  --hint "Third-party API key"

# Get decrypted value
cargo run --bin crypto_tool get-value --key "api_key"

# List all config keys
cargo run --bin crypto_tool list-keys --show-status

# Validate config file
cargo run --bin crypto_tool validate

# Migrate plain config to encrypted
cargo run --bin crypto_tool migrate \
  --input config/plain.json \
  --output config/encrypted.json \
  --encrypt-keys "database_url,jwt_secret,api_keys"
```

### 9. Testing

```rust
#[cfg(test)]
mod tests {
    use super::*;
    use axum::body::Body;
    use axum::http::{Request, StatusCode};
    use tower::ServiceExt;

    #[tokio::test]
    async fn test_crypto_integration() {
        // Initialize crypto system
        let crypto = Arc::new(CryptoService::new().unwrap());
        
        // Test encryption/decryption
        let original = "sensitive data";
        let encrypted = crypto.encrypt_string(original).unwrap();
        let decrypted = crypto.decrypt_string(&encrypted).unwrap();
        assert_eq!(original, decrypted);
        
        // Test session creation
        let session_store = Arc::new(EncryptedSessionStore::with_default_config(crypto));
        let user = create_test_user();
        let session = session_store.create_session(&user).unwrap();
        let session_data = session_store.get_session(&session).unwrap();
        assert_eq!(session_data.email, user.email);
    }
    
    #[tokio::test]
    async fn test_protected_route() {
        let app = create_test_app().await;
        
        // Test without session - should be unauthorized
        let response = app
            .clone()
            .oneshot(Request::builder().uri("/api/dashboard").body(Body::empty()).unwrap())
            .await
            .unwrap();
        assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
        
        // Test with valid session - should be authorized
        // (Implementation depends on your specific setup)
    }
}
```

### 10. Production Deployment

```dockerfile
# Dockerfile example
FROM rust:1.75 as builder

WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates
COPY --from=builder /app/target/release/server /usr/local/bin/server
COPY --from=builder /app/config /app/config

# Set secure environment variables
ENV ENVIRONMENT=production
ENV CRYPTO_KEY_FILE=/run/secrets/crypto_key
ENV DATABASE_URL_FILE=/run/secrets/database_url

EXPOSE 3030
CMD ["server"]
```

```bash
# Docker Compose with secrets
version: '3.8'
services:
  rustelo:
    build: .
    environment:
      - ENVIRONMENT=production
      - CRYPTO_KEY_FILE=/run/secrets/crypto_key
    secrets:
      - crypto_key
      - database_url
    ports:
      - "3030:3030"

secrets:
  crypto_key:
    file: ./secrets/crypto_key.txt
  database_url:
    file: ./secrets/database_url.txt
```

This example demonstrates a complete integration of the crypto system with:
- Environment-based configuration
- Encrypted session management
- Protected routes with middleware
- Database integration with encrypted URLs
- CLI tool usage for configuration management
- Testing strategies
- Production deployment considerations

The system automatically handles encryption/decryption of sensitive data while maintaining a clean API for developers.
