main.rs (5411B)
1 #![deny( 2 unknown_lints, 3 future_incompatible, 4 let_underscore, 5 nonstandard_style, 6 refining_impl_trait, 7 rust_2018_compatibility, 8 rust_2018_idioms, 9 rust_2021_compatibility, 10 rust_2024_compatibility, 11 unsafe_code, 12 unused, 13 warnings, 14 clippy::all, 15 clippy::cargo, 16 clippy::complexity, 17 clippy::correctness, 18 clippy::nursery, 19 clippy::pedantic, 20 clippy::perf, 21 clippy::restriction, 22 clippy::style, 23 clippy::suspicious 24 )] 25 #![allow( 26 clippy::blanket_clippy_restriction_lints, 27 clippy::doc_markdown, 28 clippy::expect_used, 29 clippy::if_then_some_else_none, 30 clippy::implicit_return, 31 clippy::indexing_slicing, 32 clippy::items_after_statements, 33 clippy::min_ident_chars, 34 clippy::missing_docs_in_private_items, 35 clippy::missing_errors_doc, 36 clippy::missing_trait_methods, 37 clippy::mod_module_files, 38 clippy::module_name_repetitions, 39 clippy::multiple_crate_versions, 40 clippy::multiple_inherent_impl, 41 clippy::multiple_unsafe_ops_per_block, 42 clippy::no_effect_underscore_binding, 43 clippy::panic, 44 clippy::panic_in_result_fn, 45 clippy::partial_pub_fields, 46 clippy::pub_use, 47 clippy::question_mark_used, 48 clippy::redundant_type_annotations, 49 clippy::ref_patterns, 50 clippy::shadow_reuse, 51 clippy::significant_drop_in_scrutinee, 52 clippy::significant_drop_tightening, 53 clippy::single_call_fn, 54 clippy::single_char_lifetime_names, 55 clippy::std_instead_of_alloc, 56 clippy::std_instead_of_core, 57 clippy::too_many_lines, 58 clippy::unreachable, 59 clippy::unseparated_literal_suffix, 60 clippy::unwrap_in_result, 61 clippy::unwrap_used, 62 clippy::used_underscore_binding 63 )] 64 // The recursion_limit is mainly triggered by the json!() macro. 65 // The more key/value pairs there are the more recursion occurs. 66 // We want to keep this as low as possible, but not higher then 128. 67 // If you go above 128 it will cause rust-analyzer to fail, 68 #![recursion_limit = "206"] 69 #[macro_use] 70 extern crate diesel; 71 #[macro_use] 72 mod error; 73 #[macro_use] 74 extern crate rocket; 75 #[macro_use] 76 extern crate serde; 77 #[macro_use] 78 extern crate serde_json; 79 mod api; 80 mod auth; 81 mod config; 82 mod crypto; 83 mod db; 84 mod priv_sep; 85 mod util; 86 use config::Config; 87 pub use error::{Error, MapResult}; 88 use std::env; 89 use std::{path::Path, process}; 90 use tokio::runtime::Builder; 91 use tokio::signal; 92 pub const VERSION: &str = env!("CARGO_PKG_VERSION"); 93 94 fn main() -> Result<(), Error> { 95 let mut promises = priv_sep::pledge_init()?; 96 priv_sep::unveil_read(env::current_dir()?)?; 97 static_init(); 98 check_data_folder(); 99 check_web_vault(); 100 Builder::new_multi_thread() 101 .enable_all() 102 .build() 103 .map_or_else( 104 |e| Err(Error::from(e)), 105 |runtime| { 106 runtime.block_on(async { 107 config::get_config() 108 .rocket 109 .tls 110 .as_ref() 111 .map_or(Ok(()), |tls| { 112 tls.certs().left().map_or(Ok(()), |certs| { 113 priv_sep::unveil_read(certs).and_then(|()| { 114 tls.key().left().map_or(Ok(()), priv_sep::unveil_read) 115 }) 116 }) 117 })?; 118 priv_sep::pledge_away_unveil(&mut promises)?; 119 launch_rocket(create_db_pool().await).await 120 }) 121 }, 122 ) 123 } 124 #[inline] 125 fn static_init() { 126 config::init_config(); 127 priv_sep::unveil_create_read_write(Config::DATA_FOLDER).unwrap_or_else(|_| { 128 panic!( 129 "unable to unveil(2) {} with create, read, and write permissions", 130 Config::DATA_FOLDER 131 ) 132 }); 133 auth::init_values(); 134 } 135 136 #[allow(clippy::exit)] 137 fn check_data_folder() { 138 if !Path::new(Config::DATA_FOLDER).is_dir() { 139 process::exit(1); 140 } 141 } 142 #[allow(clippy::exit)] 143 fn check_web_vault() { 144 if config::get_config().web_vault_enabled 145 && !Path::new(Config::WEB_VAULT_FOLDER) 146 .join("index.html") 147 .exists() 148 { 149 process::exit(1); 150 } 151 } 152 #[allow(clippy::exit)] 153 async fn create_db_pool() -> db::DbPool { 154 (util::retry_db( 155 db::DbPool::from_config, 156 u32::from(config::get_config().db_connection_retries.get()), 157 ) 158 .await) 159 .unwrap_or_else(|_| { 160 process::exit(1); 161 }) 162 } 163 164 async fn launch_rocket(pool: db::DbPool) -> Result<(), Error> { 165 let instance = rocket::custom(&config::get_config().rocket) 166 .mount("/", api::web_routes()) 167 .mount("/admin", api::admin_routes()) 168 .mount("/api", api::core_routes()) 169 .mount("/events", api::core_events_routes()) 170 .mount("/icons", api::icons_routes()) 171 .mount("/identity", api::identity_routes()) 172 .register("/", api::web_catchers()) 173 .register("/admin", api::admin_catchers()) 174 .register("/api", api::core_catchers()) 175 .manage(pool) 176 .attach(util::AppHeaders) 177 .attach(util::Cors) 178 .ignite() 179 .await?; 180 let shutdown = instance.shutdown(); 181 tokio::spawn(async move { 182 signal::ctrl_c() 183 .await 184 .expect("Error setting Ctrl-C handler"); 185 shutdown.notify(); 186 }); 187 instance.launch().await?; 188 Ok(()) 189 }