postrust_proxy/saas/handlers/
mod.rs1pub mod auth;
4pub mod domains;
5pub mod routes;
6pub mod upstreams;
7pub mod wellknown;
8
9use crate::admin::api::ApiResponse;
10use crate::error::ProxyError;
11use crate::saas::api_keys::ApiKeyService;
12use crate::saas::auth::SaasAuthLayer;
13use crate::saas::manager::DomainManager;
14use crate::saas::verification::DomainVerificationService;
15use axum::{
16 middleware,
17 routing::{delete, get, post, put},
18 Router,
19};
20use sqlx::PgPool;
21use std::sync::Arc;
22
23#[derive(Clone)]
25pub struct SaasState {
26 pub domain_manager: Arc<DomainManager>,
27 pub api_key_service: Arc<ApiKeyService>,
28 pub auth_layer: Arc<SaasAuthLayer>,
29}
30
31impl SaasState {
32 pub fn new(pool: PgPool, jwt_secret: Option<String>) -> Self {
34 let verification_service = Arc::new(DomainVerificationService::new());
35 let domain_manager = Arc::new(DomainManager::new(pool.clone(), verification_service));
36 let api_key_service = Arc::new(ApiKeyService::new(pool.clone()));
37 let auth_layer = Arc::new(SaasAuthLayer::new(pool, jwt_secret));
38
39 Self {
40 domain_manager,
41 api_key_service,
42 auth_layer,
43 }
44 }
45}
46
47pub fn saas_router(state: SaasState) -> Router {
49 let auth_layer = state.auth_layer.clone();
50
51 let public_routes = Router::new().route(
53 "/.well-known/postrust-verification/:token",
54 get(wellknown::handle_verification_challenge),
55 );
56
57 let protected_routes = Router::new()
59 .route("/auth/api-keys", post(auth::create_api_key))
61 .route("/auth/api-keys", get(auth::list_api_keys))
62 .route("/auth/api-keys/:id", delete(auth::revoke_api_key))
63 .route("/tenant/me", get(auth::get_current_tenant))
65 .route("/tenant/usage", get(auth::get_tenant_usage))
66 .route("/domains", get(domains::list_domains))
68 .route("/domains", post(domains::create_domain))
69 .route("/domains/:id", get(domains::get_domain))
70 .route("/domains/:id", delete(domains::delete_domain))
71 .route("/domains/:id/verify", post(domains::verify_domain))
72 .route("/domains/:id/enable", post(domains::enable_domain))
73 .route("/domains/:id/disable", post(domains::disable_domain))
74 .route("/domains/:domain_id/routes", get(routes::list_routes))
76 .route("/domains/:domain_id/routes", post(routes::create_route))
77 .route("/domains/:domain_id/routes/:id", get(routes::get_route))
78 .route("/domains/:domain_id/routes/:id", put(routes::update_route))
79 .route(
80 "/domains/:domain_id/routes/:id",
81 delete(routes::delete_route),
82 )
83 .route("/upstreams", get(upstreams::list_upstreams))
85 .route("/upstreams", post(upstreams::create_upstream))
86 .route("/upstreams/:id", get(upstreams::get_upstream))
87 .route("/upstreams/:id", put(upstreams::update_upstream))
88 .route("/upstreams/:id", delete(upstreams::delete_upstream))
89 .route("/upstreams/:id/backends", post(upstreams::add_backend))
90 .route(
91 "/upstreams/:id/backends/:backend_id",
92 delete(upstreams::remove_backend),
93 )
94 .layer(middleware::from_fn_with_state(
95 auth_layer,
96 crate::saas::auth::auth_middleware,
97 ))
98 .with_state(state.clone());
99
100 Router::new()
102 .merge(public_routes.with_state(state.clone()))
103 .nest("/api/v1", protected_routes)
104}
105
106pub fn error_response(error: ProxyError) -> (axum::http::StatusCode, axum::Json<ApiResponse<()>>) {
108 let status = error.status_code();
109 let response = ApiResponse::<()>::error(error.to_string());
110 (status, axum::Json(response))
111}