2023-05-28 15:05:16 +02:00
|
|
|
use std::env;
|
|
|
|
|
2022-10-04 11:06:48 +02:00
|
|
|
use anyhow::Context;
|
2023-05-28 15:34:36 +02:00
|
|
|
use async_sqlx_session::PostgresSessionStore;
|
2023-05-28 15:05:16 +02:00
|
|
|
use axum::extract::FromRef;
|
|
|
|
use axum::http::{HeaderValue, Method};
|
|
|
|
use axum::Router;
|
2022-10-04 11:06:48 +02:00
|
|
|
use como_infrastructure::register::ServiceRegister;
|
2023-05-28 15:05:16 +02:00
|
|
|
use oauth2::basic::BasicClient;
|
2022-10-04 11:06:48 +02:00
|
|
|
use tower::ServiceBuilder;
|
|
|
|
use tower_http::{cors::CorsLayer, trace::TraceLayer};
|
|
|
|
|
2023-05-27 13:12:29 +02:00
|
|
|
use crate::controllers::auth::AuthController;
|
2022-10-04 11:06:48 +02:00
|
|
|
use crate::controllers::graphql::GraphQLController;
|
2023-05-28 15:05:16 +02:00
|
|
|
use crate::zitadel::client::oauth_client;
|
|
|
|
use crate::zitadel::{IntrospectionState, IntrospectionStateBuilder};
|
2023-05-27 13:12:29 +02:00
|
|
|
|
2022-10-04 11:06:48 +02:00
|
|
|
pub struct Api;
|
|
|
|
|
|
|
|
impl Api {
|
|
|
|
pub async fn new(
|
|
|
|
port: u32,
|
|
|
|
cors_origin: &str,
|
|
|
|
service_register: ServiceRegister,
|
|
|
|
) -> anyhow::Result<()> {
|
2023-05-28 15:05:16 +02:00
|
|
|
let client_id = env::var("CLIENT_ID").expect("Missing CLIENT_ID!");
|
|
|
|
let client_secret = env::var("CLIENT_SECRET").expect("Missing CLIENT_SECRET!");
|
|
|
|
let zitadel_url = env::var("ZITADEL_URL").expect("missing ZITADEL_URL");
|
|
|
|
|
|
|
|
let is = IntrospectionStateBuilder::new(&zitadel_url)
|
|
|
|
.with_basic_auth(&client_id, &client_secret)
|
|
|
|
.build()
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
let oauth_client = oauth_client();
|
|
|
|
let app_state = AppState {
|
|
|
|
oauth_client,
|
2023-05-28 15:34:36 +02:00
|
|
|
store: service_register.session_store.clone(),
|
2023-05-28 15:05:16 +02:00
|
|
|
introspection_state: is,
|
|
|
|
};
|
|
|
|
|
2022-10-04 11:06:48 +02:00
|
|
|
let router = Router::new()
|
2023-05-27 13:12:29 +02:00
|
|
|
.nest(
|
|
|
|
"/auth",
|
2023-05-28 15:05:16 +02:00
|
|
|
AuthController::new_router(service_register.clone(), app_state.clone()).await?,
|
2023-05-27 13:12:29 +02:00
|
|
|
)
|
2022-10-04 11:06:48 +02:00
|
|
|
.nest(
|
|
|
|
"/graphql",
|
2023-05-28 15:05:16 +02:00
|
|
|
GraphQLController::new_router(service_register.clone(), app_state.clone()),
|
2022-10-04 11:06:48 +02:00
|
|
|
)
|
|
|
|
.layer(
|
2023-05-28 15:05:16 +02:00
|
|
|
ServiceBuilder::new()
|
|
|
|
.layer(TraceLayer::new_for_http())
|
|
|
|
.layer(
|
|
|
|
CorsLayer::new()
|
|
|
|
.allow_origin(
|
|
|
|
cors_origin
|
|
|
|
.parse::<HeaderValue>()
|
|
|
|
.context("could not parse cors origin as header")?,
|
|
|
|
)
|
|
|
|
.allow_headers([axum::http::header::CONTENT_TYPE])
|
|
|
|
.allow_methods([Method::GET, Method::POST, Method::OPTIONS]),
|
|
|
|
),
|
2022-10-04 11:06:48 +02:00
|
|
|
);
|
|
|
|
|
2023-05-28 15:05:16 +02:00
|
|
|
let host = env::var("HOST").unwrap_or("0.0.0.0".to_string());
|
|
|
|
|
|
|
|
tracing::info!("running on: {host}:{}", port);
|
2023-05-27 13:12:29 +02:00
|
|
|
|
2023-05-28 15:05:16 +02:00
|
|
|
axum::Server::bind(&format!("{host}:{}", port).parse().unwrap())
|
2022-10-04 11:06:48 +02:00
|
|
|
.serve(router.into_make_service())
|
|
|
|
.await
|
|
|
|
.context("error while starting API")?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2023-05-28 15:05:16 +02:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct AppState {
|
|
|
|
oauth_client: BasicClient,
|
|
|
|
introspection_state: IntrospectionState,
|
2023-05-28 15:34:36 +02:00
|
|
|
store: PostgresSessionStore,
|
2023-05-28 15:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FromRef<AppState> for BasicClient {
|
|
|
|
fn from_ref(state: &AppState) -> Self {
|
|
|
|
state.oauth_client.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-28 15:34:36 +02:00
|
|
|
impl FromRef<AppState> for PostgresSessionStore {
|
2023-05-28 15:05:16 +02:00
|
|
|
fn from_ref(state: &AppState) -> Self {
|
|
|
|
state.store.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromRef<AppState> for IntrospectionState {
|
|
|
|
fn from_ref(input: &AppState) -> Self {
|
|
|
|
input.introspection_state.clone()
|
|
|
|
}
|
|
|
|
}
|