#[macro_use] extern crate diesel; #[macro_use] extern crate diesel_migrations; use actix::prelude::*; use actix_web::middleware::{errhandlers::ErrorHandlers, Logger}; use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{http, web, App, HttpServer}; use argonautica::{Hasher, Verifier}; use chrono::Duration; use diesel::mysql::MysqlConnection; use dotenv::dotenv; use r2d2_diesel::ConnectionManager; mod admin; mod error; mod error_handlers; mod model; mod schema; mod user; mod util; use crate::admin::user_creation::PassHashExecutor; use crate::model::DbExecutor; use crate::user::login::HashVerifyExecutor; embed_migrations!(); pub struct Secret(String); #[actix_rt::main] async fn main() -> std::io::Result<()> { dotenv().ok(); std::env::set_var( "RUST_LOG", "joklerpoint=debug,actix_web=trace,actix_server=debug", ); env_logger::init(); let bind_host: String = std::env::var("BIND_HOST").unwrap_or_else(|_| "127.0.0.1:8000".to_string()); let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); let manager = ConnectionManager::::new(database_url); let pool = r2d2::Pool::builder() .build(manager) .expect("Can to build connection pool"); embedded_migrations::run(&*pool.get().expect("Can connect to mysql")) .expect("Can run migrations"); let db_addr: Addr = SyncArbiter::start(4, move || DbExecutor(pool.clone())); let verifier_addr: Addr = SyncArbiter::start(4, move || HashVerifyExecutor(Verifier::default())); let hasher_addr: Addr = SyncArbiter::start(4, move || PassHashExecutor(Hasher::default())); HttpServer::new(move || { let secret: String = std::env::var("SECRET_KEY").expect("SECRET_KEY env var should be set"); let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string()); let secure_cookies = &domain != "localhost"; let error_handlers = ErrorHandlers::new() .handler( http::StatusCode::INTERNAL_SERVER_ERROR, error_handlers::internal_server_error, ) .handler(http::StatusCode::BAD_REQUEST, error_handlers::bad_request) .handler(http::StatusCode::NOT_FOUND, error_handlers::not_found); App::new() .data(db_addr.clone()) .data(verifier_addr.clone()) .data(hasher_addr.clone()) .data(Secret(secret.clone())) .wrap(error_handlers) .wrap(IdentityService::new( CookieIdentityPolicy::new(secret.as_bytes()) .name("jkp-session") .domain(domain.as_str()) .max_age_time(Duration::days(30)) .secure(secure_cookies), // this has to reflect the usage of https )) .wrap(Logger::default()) .route("/", web::get().to(user::index)) .service( web::resource("/login") .route(web::get().to(user::login)) .route(web::post().to(user::confirm_login)), ) .route("/transactions", web::get().to(user::transactions)) .service( web::resource("/transfer") .route(web::get().to(user::transfer)) .route(web::post().to(user::confirm_transfer)), ) .route("/settings", web::get().to(user::settings)) .route("/reset-password", web::post().to(user::reset_password)) .route("/logout", web::get().to(user::logout)) .service( web::resource("/admin") .route(web::get().to(admin::index)) .route(web::post().to(admin::create_user)), ) .service(actix_files::Files::new("/static", "static/")) }) .bind(&bind_host)? .run() .await?; Ok(()) }