Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions src/cortex-app-server/src/api/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ use axum::{Json, extract::Path};

use crate::error::{AppError, AppResult};

const ALLOWED_PROXY_PORTS: &[u16] = &[
3000, 3001, 3002, 3003, // React、Next.js
4000, 4173, 4200, // Angular、Vite 预览
5000, 5173, 5174, // Vite、Flask
8000, 8080, 8081, // Django、通用开发服务
];

/// List open ports on localhost.
pub async fn list_open_ports() -> Json<Vec<u16>> {
let ports_to_check: Vec<u16> = vec![
3000, 3001, 3002, 3003, // React, Next.js
4000, 4173, 4200, // Angular, Vite preview
5000, 5173, 5174, // Vite, Flask
8000, 8080, 8081, // Django, generic
];

let mut open_ports = Vec::new();

for port in ports_to_check {
for port in ALLOWED_PROXY_PORTS {
if std::net::TcpStream::connect(format!("127.0.0.1:{port}")).is_ok() {
open_ports.push(port);
open_ports.push(*port);
}
}

Expand All @@ -36,6 +36,12 @@ pub async fn proxy_to_port_path(
use axum::body::Body;
use axum::http::{StatusCode, header};

if !is_proxy_port_allowed(port) {
return Err(AppError::Authorization(format!(
"Port {port} is not allowed for proxying"
)));
}

let target_url = format!("http://127.0.0.1:{port}/{path}");

let client = reqwest::Client::builder()
Expand Down Expand Up @@ -79,3 +85,27 @@ pub async fn proxy_to_port_path(
.body(Body::from(body))
.map_err(|e| AppError::Internal(format!("Failed to build response: {e}")))
}

fn is_proxy_port_allowed(port: u16) -> bool {
ALLOWED_PROXY_PORTS.contains(&port)
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn proxy_rejects_non_dev_ports() {
let result = proxy_to_port_path(Path((22, String::new()))).await;

assert!(matches!(result, Err(AppError::Authorization(_))));
}

#[test]
fn proxy_allows_only_known_dev_ports() {
assert!(is_proxy_port_allowed(5173));
assert!(is_proxy_port_allowed(8080));
assert!(!is_proxy_port_allowed(22));
assert!(!is_proxy_port_allowed(9200));
}
}