codive-relay 0.1.0

Relay server for secure tunneling
Documentation
//! Relay server for secure tunneling
//!
//! This crate implements the public relay server that enables remote access
//! to local agent servers. It accepts WebSocket connections from agents,
//! assigns unique tunnel URLs, and proxies HTTP traffic through encrypted
//! WebSocket connections.

pub mod routes;
pub mod state;
pub mod tunnel;

use axum::{
    http::{header, HeaderValue},
    Router,
};
use std::sync::Arc;
use tower_http::cors::{Any, CorsLayer};
use tower_http::set_header::SetResponseHeaderLayer;
use tower_http::trace::TraceLayer;

pub use state::{AuthRateLimitConfig, AuthResult, RelayConfig, RelayState, TokenError, TunnelClaims};

/// Create the relay server router
pub fn create_relay_app(state: Arc<RelayState>) -> Router {
    // CORS configuration
    // Note: In production, restrict origins to your domain
    let cors = CorsLayer::new()
        .allow_origin(Any)
        .allow_methods(Any)
        .allow_headers(Any);

    Router::new()
        .merge(routes::routes())
        .layer(TraceLayer::new_for_http())
        .layer(cors)
        // Security headers
        .layer(security_headers_layer())
        .with_state(state)
}

/// Create a layer that adds security headers to all responses
fn security_headers_layer() -> tower::ServiceBuilder<
    tower::layer::util::Stack<
        SetResponseHeaderLayer<HeaderValue>,
        tower::layer::util::Stack<
            SetResponseHeaderLayer<HeaderValue>,
            tower::layer::util::Stack<
                SetResponseHeaderLayer<HeaderValue>,
                tower::layer::util::Stack<
                    SetResponseHeaderLayer<HeaderValue>,
                    tower::layer::util::Stack<
                        SetResponseHeaderLayer<HeaderValue>,
                        tower::layer::util::Identity,
                    >,
                >,
            >,
        >,
    >,
> {
    tower::ServiceBuilder::new()
        // Strict-Transport-Security: enforce HTTPS for 1 year, include subdomains
        .layer(SetResponseHeaderLayer::overriding(
            header::STRICT_TRANSPORT_SECURITY,
            HeaderValue::from_static("max-age=31536000; includeSubDomains; preload"),
        ))
        // X-Frame-Options: prevent clickjacking
        .layer(SetResponseHeaderLayer::overriding(
            header::X_FRAME_OPTIONS,
            HeaderValue::from_static("DENY"),
        ))
        // X-Content-Type-Options: prevent MIME type sniffing
        .layer(SetResponseHeaderLayer::overriding(
            header::X_CONTENT_TYPE_OPTIONS,
            HeaderValue::from_static("nosniff"),
        ))
        // X-XSS-Protection: legacy XSS protection (for older browsers)
        .layer(SetResponseHeaderLayer::overriding(
            header::X_XSS_PROTECTION,
            HeaderValue::from_static("1; mode=block"),
        ))
        // Content-Security-Policy: restrict resource loading
        .layer(SetResponseHeaderLayer::overriding(
            header::CONTENT_SECURITY_POLICY,
            HeaderValue::from_static("default-src 'self'; frame-ancestors 'none'; form-action 'self'"),
        ))
}