//! # WEB SERVER FOR THE KUADRADO SOFTWARE WEBSITE mod app_state; mod crypto; mod env; mod init_admin; mod middleware; mod model; mod service; mod standard_static_files; mod tls; mod view; mod view_resource; use actix_files::Files; use actix_web::{ middleware::{normalize::TrailingSlash, Logger, NormalizePath}, web::{get, resource, scope, to, Data}, App, HttpResponse, HttpServer, }; use actix_web_middleware_redirect_https::RedirectHTTPS; use app_state::AppState; use env::get_log_level; use env_logger::Env; use middleware::AuthenticatedAdminMiddleware; use service::*; use standard_static_files::{favicon, robots, sitemap}; use std::env::var as env_var; use tls::get_tls_config; use view::get_view; use view_resource::{ViewResourceDescriptor, ViewResourceManager}; #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::Builder::from_env(Env::default().default_filter_or(get_log_level())).init(); let server_port = env_var("SERVER_PORT").expect("SERVER_PORT is not defined."); let server_port_tls = env_var("SERVER_PORT_TLS").expect("SERVER_PORT_TLS is not defined."); let public_dir = std::path::PathBuf::from(env_var("RESOURCES_DIR").expect("RESOURCES_DIR is not defined")) .join("public"); let app_state = AppState::with_default_admin_user().await; HttpServer::new(move || { App::new() .wrap(Logger::default()) // Redirect all requests to https .wrap(RedirectHTTPS::with_replacements(&[( format!(":{}", server_port), format!(":{}", server_port_tls), )])) .app_data(Data::new(app_state.clone())) .app_data(Data::new(AuthenticatedAdminMiddleware::new( "kuadrado-admin-auth", ))) .app_data(Data::new(ViewResourceManager::with_views(vec![ ViewResourceDescriptor { path_str: "admin-panel", index_file_name: "index.html", resource_name: "admin-panel", apply_auth_middleware: true, }, ViewResourceDescriptor { path_str: "admin-login", index_file_name: "index.html", resource_name: "admin-login", apply_auth_middleware: false, }, ViewResourceDescriptor { path_str: "404", index_file_name: "404.html", resource_name: "404", apply_auth_middleware: false, }, ViewResourceDescriptor { path_str: "unauthorized", index_file_name: "unauthorized.html", resource_name: "unauthorized", apply_auth_middleware: false, }, ]))) .wrap(NormalizePath::new(TrailingSlash::Trim)) // .app_data(JsonConfig::default().limit(1 << 25u8)) // Allow json payload to have size until ~32MB ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // REST API ///////////////////////////////////////////////////////////////////////////////////////////////// .service(admin_authentication) .service(post_article) .service(update_article) .service(delete_article) .service(get_articles_by_category) .service(get_article) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // STANDARD FILES /////////////////////////////////////////////////////////////////////////////////////////// .service(resource("/favicon.ico").route(get().to(favicon))) .service(resource("/robots.txt").route(get().to(robots))) .service(resource("/sitemap.xml").route(get().to(sitemap))) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // VIEWS //////////////////////////////////////////////////////////////////////////////////////////////////// .service( scope("/v") .service(Files::new( "/admin-panel/assets", public_dir.join("views/admin-panel/assets"), )) .service(Files::new( "/admin-login/assets", public_dir.join("views/admin-login/assets"), )) // get_view will match any url to we put it at last .service(get_view), ) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC WEBSITE ////////////////////////////////////////////////////////////////////////////////////////////// .service(Files::new("/", &public_dir).index_file("index.html")) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // empty 404 //////////////////////////////////////////////////////////////////////////////////////////////// .default_service(to(|| { HttpResponse::NotFound().body("<h1>404 - Page not found</h1>") })) }) .bind(format!("0.0.0.0:{}", env_var("SERVER_PORT").unwrap()))? .bind_rustls( format!("0.0.0.0:{}", env_var("SERVER_PORT_TLS").unwrap()), get_tls_config(), )? .run() .await }