// trifid-api, an open source reimplementation of the Defined Networking nebula management server. // Copyright (C) 2023 c0repwn3r // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . use actix_request_identifier::RequestIdentifier; use actix_web::{ web::{Data, JsonConfig}, App, HttpResponse, HttpServer, }; use log::{info, Level}; use sea_orm::{ConnectOptions, Database, DatabaseConnection}; use std::error::Error; use std::time::Duration; use crate::config::CONFIG; use crate::error::{APIError, APIErrorsResponse}; use crate::keystore::{keystore_init, Keystore}; use crate::tokens::random_id_no_id; use trifid_api_migration::{Migrator, MigratorTrait}; pub mod auth_tokens; pub mod codegen; pub mod config; pub mod crypto; pub mod cursor; pub mod error; pub mod keystore; pub mod magic_link; pub mod routes; pub mod timers; pub mod tokens; pub struct AppState { pub conn: DatabaseConnection, pub keystore: Keystore, } #[actix_web::main] async fn main() -> Result<(), Box> { simple_logger::init_with_level(Level::Debug).unwrap(); info!("Creating keystore..."); let keystore = keystore_init()?; info!("Connecting to database at {}...", CONFIG.database.url); let mut opt = ConnectOptions::new(CONFIG.database.url.clone()); opt.max_connections(CONFIG.database.max_connections) .min_connections(CONFIG.database.min_connections) .connect_timeout(Duration::from_secs(CONFIG.database.connect_timeout)) .acquire_timeout(Duration::from_secs(CONFIG.database.acquire_timeout)) .idle_timeout(Duration::from_secs(CONFIG.database.idle_timeout)) .max_lifetime(Duration::from_secs(CONFIG.database.max_lifetime)) .sqlx_logging(CONFIG.database.sqlx_logging) .sqlx_logging_level(log::LevelFilter::Info); let db = Database::connect(opt).await?; info!("Performing database migration..."); Migrator::up(&db, None).await?; let data = Data::new(AppState { conn: db, keystore }); HttpServer::new(move || { App::new() .app_data(data.clone()) .app_data(JsonConfig::default().error_handler(|err, _req| { let api_error: APIError = (&err).into(); actix_web::error::InternalError::from_response( err, HttpResponse::BadRequest().json(APIErrorsResponse { errors: vec![api_error], }), ) .into() })) .wrap(RequestIdentifier::with_generator(random_id_no_id)) .service(routes::v1::auth::magic_link::magic_link_request) .service(routes::v1::signup::signup_request) .service(routes::v1::auth::verify_magic_link::verify_magic_link_request) .service(routes::v1::totp_authenticators::totp_authenticators_request) .service(routes::v1::verify_totp_authenticators::verify_totp_authenticators_request) .service(routes::v1::auth::totp::totp_request) .service(routes::v1::networks::get_networks) .service(routes::v1::organization::create_org_request) .service(routes::v1::networks::get_network_request) .service(routes::v1::roles::create_role_request) .service(routes::v1::roles::get_roles) .service(routes::v1::roles::get_role) .service(routes::v1::roles::delete_role) .service(routes::v1::roles::update_role_request) .service(routes::v1::trifid::trifid_extensions) .service(routes::v1::hosts::get_hosts) .service(routes::v1::hosts::create_hosts_request) .service(routes::v1::hosts::get_host) .service(routes::v1::hosts::delete_host) .service(routes::v1::hosts::edit_host) .service(routes::v1::hosts::block_host) .service(routes::v1::hosts::enroll_host) .service(routes::v1::hosts::create_host_and_enrollment_code) .service(routes::v2::enroll::enroll) }) .bind(CONFIG.server.bind)? .run() .await?; Ok(()) }