2023-10-25 17:08:11 +02:00
|
|
|
use std::{fmt::Debug, net::SocketAddr};
|
|
|
|
|
|
|
|
use axum::{
|
|
|
|
extract::DefaultBodyLimit,
|
2023-11-05 23:05:48 +01:00
|
|
|
http::{request::Parts, HeaderName, HeaderValue, Method, StatusCode},
|
2023-10-25 17:08:11 +02:00
|
|
|
routing::{get, post},
|
|
|
|
Router,
|
|
|
|
};
|
2023-11-05 23:05:48 +01:00
|
|
|
use extractors::SubdomainModel;
|
|
|
|
use services::cors::CorsService;
|
|
|
|
use tower_http::cors::{AllowHeaders, AllowMethods, AllowOrigin, CorsLayer};
|
|
|
|
|
2023-10-25 17:08:11 +02:00
|
|
|
use migration::{Migrator, MigratorTrait};
|
|
|
|
use sea_orm::{ConnectOptions, Database};
|
|
|
|
|
|
|
|
mod apperror;
|
|
|
|
mod config;
|
|
|
|
mod extractors;
|
|
|
|
mod handlers;
|
|
|
|
mod services;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct AppState {
|
|
|
|
connection: sea_orm::DatabaseConnection,
|
|
|
|
config: config::Config,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
|
|
|
dotenv::dotenv().ok();
|
|
|
|
let config = config::Config::default();
|
|
|
|
|
|
|
|
let mut opt = ConnectOptions::new(&config.database_url);
|
|
|
|
opt.sqlx_logging(true);
|
|
|
|
let connection = Database::connect(opt).await.unwrap();
|
|
|
|
connection.ping().await.unwrap();
|
|
|
|
|
|
|
|
Migrator::up(&connection, None).await.unwrap();
|
|
|
|
|
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
|
|
|
|
|
|
|
|
tracing_subscriber::fmt()
|
|
|
|
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
|
|
|
.init();
|
|
|
|
|
|
|
|
let api_router = Router::new()
|
|
|
|
.route("/health", get(|| async { StatusCode::OK }))
|
|
|
|
.route("/login", post(handlers::auth::login))
|
|
|
|
.route("/registration", post(handlers::auth::registration))
|
|
|
|
.route("/upload", post(handlers::sites::upload))
|
|
|
|
.route("/teardown", post(handlers::sites::teardown))
|
|
|
|
.route("/download", post(handlers::sites::download))
|
|
|
|
.route("/enable", post(handlers::sites::enable))
|
2023-11-05 23:05:48 +01:00
|
|
|
.route("/disable", post(handlers::sites::disable))
|
|
|
|
.route("/cors/add", post(handlers::cors::add_origin))
|
|
|
|
.route("/cors/clear", post(handlers::cors::clear_all));
|
2023-10-25 17:08:11 +02:00
|
|
|
|
|
|
|
let state = std::sync::Arc::new(AppState {
|
|
|
|
connection,
|
|
|
|
config: Default::default(),
|
|
|
|
});
|
|
|
|
|
2023-11-05 23:05:48 +01:00
|
|
|
let cloned_state = state.clone();
|
|
|
|
|
|
|
|
let files_router = Router::new()
|
2023-10-25 17:08:11 +02:00
|
|
|
.route("/*path", get(handlers::sites::file))
|
2023-11-02 00:19:23 +01:00
|
|
|
.route("/", get(handlers::sites::index_redirect))
|
2023-11-05 23:05:48 +01:00
|
|
|
.layer(
|
|
|
|
CorsLayer::new()
|
|
|
|
.allow_methods(AllowMethods::exact(Method::GET))
|
|
|
|
.allow_headers(AllowHeaders::list([HeaderName::from_static("X-Subdomain")]))
|
|
|
|
.allow_origin(AllowOrigin::predicate(
|
|
|
|
move |origin: &HeaderValue, parts: &Parts| {
|
|
|
|
let origin = origin.to_str().unwrap_or_default();
|
|
|
|
let subdomain_model_future =
|
|
|
|
SubdomainModel::from_headers(&parts.headers, &cloned_state);
|
|
|
|
|
|
|
|
tokio::runtime::Handle::current().block_on(async {
|
|
|
|
let subdomain_model = subdomain_model_future.await;
|
|
|
|
match subdomain_model {
|
|
|
|
Ok(model) => match CorsService::check(model.0, origin, &cloned_state.connection).await{
|
|
|
|
Ok(result) => result,
|
|
|
|
Err(cause) => {
|
|
|
|
tracing::error!(%cause, "Failed to check origin for cors filtering!");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(cause) => {
|
|
|
|
tracing::error!(%cause, "Failed to find subdomain model for cors filtering!");
|
|
|
|
false
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut app = Router::new()
|
|
|
|
.nest("/api", api_router)
|
|
|
|
.nest("/", files_router)
|
2023-10-25 17:08:11 +02:00
|
|
|
.with_state(state.clone());
|
|
|
|
|
|
|
|
if config.max_body_limit_size.is_some() {
|
|
|
|
app = app.layer(DefaultBodyLimit::max(config.max_body_limit_size.unwrap()));
|
|
|
|
}
|
|
|
|
|
|
|
|
axum::Server::bind(&addr)
|
|
|
|
.serve(app.into_make_service())
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|