codex-helper-core 0.15.0

Core library for codex-helper.
Documentation
use std::net::SocketAddr;

use axum::body::Body;
use axum::extract::{ConnectInfo, State};
use axum::http::{Request, Response, StatusCode};
use axum::middleware::Next;

use crate::dashboard_core::RemoteAdminAccessCapabilities;

use super::{ADMIN_PORT_OFFSET, ADMIN_TOKEN_ENV_VAR, ADMIN_TOKEN_HEADER};

#[derive(Clone)]
pub(super) struct AdminAccessConfig {
    token: Option<String>,
}

impl AdminAccessConfig {
    pub(super) fn from_env() -> Self {
        let token = std::env::var(ADMIN_TOKEN_ENV_VAR)
            .ok()
            .map(|value| value.trim().to_string())
            .filter(|value| !value.is_empty());
        Self { token }
    }
}

pub(super) fn admin_access_capabilities() -> RemoteAdminAccessCapabilities {
    let access = AdminAccessConfig::from_env();
    RemoteAdminAccessCapabilities {
        loopback_without_token: true,
        remote_requires_token: true,
        remote_enabled: access.token.is_some(),
        token_header: ADMIN_TOKEN_HEADER.to_string(),
        token_env_var: ADMIN_TOKEN_ENV_VAR.to_string(),
    }
}

pub fn admin_port_for_proxy_port(proxy_port: u16) -> u16 {
    if proxy_port <= u16::MAX - ADMIN_PORT_OFFSET {
        proxy_port + ADMIN_PORT_OFFSET
    } else if proxy_port > ADMIN_PORT_OFFSET {
        proxy_port - ADMIN_PORT_OFFSET
    } else {
        1
    }
}

pub fn local_proxy_base_url(port: u16) -> String {
    format!("http://127.0.0.1:{port}")
}

pub fn local_admin_base_url_for_proxy_port(proxy_port: u16) -> String {
    local_proxy_base_url(admin_port_for_proxy_port(proxy_port))
}

pub fn admin_base_url_from_proxy_base_url(proxy_base_url: &str) -> Option<String> {
    let mut url = reqwest::Url::parse(proxy_base_url).ok()?;
    let port = url.port_or_known_default()?;
    url.set_port(Some(admin_port_for_proxy_port(port))).ok()?;
    Some(url.to_string().trim_end_matches('/').to_string())
}

pub fn admin_loopback_addr_for_proxy_port(proxy_port: u16) -> SocketAddr {
    SocketAddr::from(([127, 0, 0, 1], admin_port_for_proxy_port(proxy_port)))
}

fn is_admin_path(path: &str) -> bool {
    path == "/__codex_helper" || path.starts_with("/__codex_helper/")
}

#[derive(Clone, serde::Serialize)]
pub(super) struct ProxyAdminDiscovery {
    pub(super) api_version: u32,
    pub(super) service_name: &'static str,
    pub(super) admin_base_url: String,
}

pub(super) async fn require_admin_access(
    State(access): State<AdminAccessConfig>,
    ConnectInfo(peer_addr): ConnectInfo<SocketAddr>,
    req: Request<Body>,
    next: Next,
) -> Result<Response<Body>, (StatusCode, String)> {
    if peer_addr.ip().is_loopback() {
        return Ok(next.run(req).await);
    }

    let provided = req
        .headers()
        .get(ADMIN_TOKEN_HEADER)
        .and_then(|value| value.to_str().ok())
        .map(str::trim)
        .filter(|value| !value.is_empty());
    let remote_allowed = access
        .token
        .as_deref()
        .is_some_and(|expected| Some(expected) == provided);
    if remote_allowed {
        return Ok(next.run(req).await);
    }

    Err((
        StatusCode::FORBIDDEN,
        format!(
            "admin routes are loopback-only; set {ADMIN_TOKEN_ENV_VAR} and send {ADMIN_TOKEN_HEADER} to allow remote access"
        ),
    ))
}

pub(super) async fn require_admin_path_only(
    req: Request<Body>,
    next: Next,
) -> Result<Response<Body>, StatusCode> {
    if is_admin_path(req.uri().path()) {
        return Ok(next.run(req).await);
    }
    Err(StatusCode::NOT_FOUND)
}

pub(super) async fn reject_admin_paths_from_proxy(
    req: Request<Body>,
    next: Next,
) -> Result<Response<Body>, StatusCode> {
    if is_admin_path(req.uri().path()) {
        return Err(StatusCode::NOT_FOUND);
    }
    Ok(next.run(req).await)
}