Skip to main content

codive_relay/
lib.rs

1//! Relay server for secure tunneling
2//!
3//! This crate implements the public relay server that enables remote access
4//! to local agent servers. It accepts WebSocket connections from agents,
5//! assigns unique tunnel URLs, and proxies HTTP traffic through encrypted
6//! WebSocket connections.
7
8pub mod routes;
9pub mod state;
10pub mod tunnel;
11
12use axum::{
13    http::{header, HeaderValue},
14    Router,
15};
16use std::sync::Arc;
17use tower_http::cors::{Any, CorsLayer};
18use tower_http::set_header::SetResponseHeaderLayer;
19use tower_http::trace::TraceLayer;
20
21pub use state::{AuthRateLimitConfig, AuthResult, RelayConfig, RelayState, TokenError, TunnelClaims};
22
23/// Create the relay server router
24pub fn create_relay_app(state: Arc<RelayState>) -> Router {
25    // CORS configuration
26    // Note: In production, restrict origins to your domain
27    let cors = CorsLayer::new()
28        .allow_origin(Any)
29        .allow_methods(Any)
30        .allow_headers(Any);
31
32    Router::new()
33        .merge(routes::routes())
34        .layer(TraceLayer::new_for_http())
35        .layer(cors)
36        // Security headers
37        .layer(security_headers_layer())
38        .with_state(state)
39}
40
41/// Create a layer that adds security headers to all responses
42fn security_headers_layer() -> tower::ServiceBuilder<
43    tower::layer::util::Stack<
44        SetResponseHeaderLayer<HeaderValue>,
45        tower::layer::util::Stack<
46            SetResponseHeaderLayer<HeaderValue>,
47            tower::layer::util::Stack<
48                SetResponseHeaderLayer<HeaderValue>,
49                tower::layer::util::Stack<
50                    SetResponseHeaderLayer<HeaderValue>,
51                    tower::layer::util::Stack<
52                        SetResponseHeaderLayer<HeaderValue>,
53                        tower::layer::util::Identity,
54                    >,
55                >,
56            >,
57        >,
58    >,
59> {
60    tower::ServiceBuilder::new()
61        // Strict-Transport-Security: enforce HTTPS for 1 year, include subdomains
62        .layer(SetResponseHeaderLayer::overriding(
63            header::STRICT_TRANSPORT_SECURITY,
64            HeaderValue::from_static("max-age=31536000; includeSubDomains; preload"),
65        ))
66        // X-Frame-Options: prevent clickjacking
67        .layer(SetResponseHeaderLayer::overriding(
68            header::X_FRAME_OPTIONS,
69            HeaderValue::from_static("DENY"),
70        ))
71        // X-Content-Type-Options: prevent MIME type sniffing
72        .layer(SetResponseHeaderLayer::overriding(
73            header::X_CONTENT_TYPE_OPTIONS,
74            HeaderValue::from_static("nosniff"),
75        ))
76        // X-XSS-Protection: legacy XSS protection (for older browsers)
77        .layer(SetResponseHeaderLayer::overriding(
78            header::X_XSS_PROTECTION,
79            HeaderValue::from_static("1; mode=block"),
80        ))
81        // Content-Security-Policy: restrict resource loading
82        .layer(SetResponseHeaderLayer::overriding(
83            header::CONTENT_SECURITY_POLICY,
84            HeaderValue::from_static("default-src 'self'; frame-ancestors 'none'; form-action 'self'"),
85        ))
86}