// SPDX-FileCopyrightText: 2024 Simon Bruder // // SPDX-License-Identifier: AGPL-3.0-or-later use std::env; use actix_identity::IdentityMiddleware; use actix_session::{storage::CookieSessionStore, SessionMiddleware}; use actix_web::middleware::ErrorHandlers; use actix_web::{cookie::Key, http::StatusCode, web, App, HttpServer}; use base64::prelude::{Engine as _, BASE64_STANDARD}; use log::{debug, info, warn}; #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); // generate a secret key with head -c 64 /dev/urandom | base64 -w0 let secret_key = match env::var("SECRET_KEY") { Ok(encoded) => Key::from( &BASE64_STANDARD .decode(encoded) .expect("failed to decode base64 in SECRET_KEY"), ), Err(_) => { warn!("SECRET_KEY was not specified, using randomly generated key"); Key::generate() } }; let pool: sqlx::PgPool = sqlx::Pool::::connect( &env::var("DATABASE_URL").expect("DATABASE_URL must be set"), ) .await .expect("failed to connect to database"); sqlx::migrate!() .run(&pool) .await .expect("failed to run migrations"); let address = env::var("LISTEN_ADDRESS").unwrap_or("::1".to_string()); let port = env::var("LISTEN_PORT").map_or(8080, |s| { s.parse::().expect("failed to parse LISTEN_PORT") }); let static_root = env::var("STATIC_ROOT").unwrap_or("static".to_string()); info!("Starting on {address}:{port} with static files from {static_root}"); debug!("Serving static files from {static_root}"); HttpServer::new(move || { App::new() .app_data(web::Data::new(pool.clone())) .service( web::scope("/api/v1") .wrap(li7y::middleware::ForceIdentity) .configure(li7y::api::v1::config), ) .service(actix_files::Files::new("/static", &static_root)) .configure(li7y::frontend::config) .wrap(ErrorHandlers::new().handler( StatusCode::UNAUTHORIZED, li7y::middleware::error_handlers::redirect_to_login, )) .wrap(IdentityMiddleware::default()) .wrap(SessionMiddleware::new( CookieSessionStore::default(), secret_key.clone(), )) }) .bind((address, port))? .run() .await }