2021-10-04 21:21:10 +05:30
/*
* Copyright ( C ) 2021 Aravinth Manivannan < realaravinth @ batsense . net >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https ://www.gnu.org/licenses/>.
* /
use std ::env ;
use std ::path ::Path ;
use config ::{ Config , ConfigError , Environment , File } ;
use log ::{ debug , warn } ;
use serde ::Deserialize ;
2023-01-24 19:00:31 +05:30
use serde ::Serialize ;
2021-10-04 21:21:10 +05:30
use url ::Url ;
2021-10-14 18:53:06 +05:30
use uuid ::Uuid ;
2021-10-04 21:21:10 +05:30
2023-01-24 19:00:31 +05:30
#[ derive(Debug, Clone, Serialize, Deserialize) ]
2021-10-04 21:21:10 +05:30
pub struct Server {
pub port : u32 ,
pub domain : String ,
pub cookie_secret : String ,
2021-10-14 18:53:06 +05:30
pub cookie_secret2 : String ,
2021-10-04 21:21:10 +05:30
pub ip : String ,
pub proxy_has_tls : bool ,
}
impl Server {
#[ cfg(not(tarpaulin_include)) ]
pub fn get_ip ( & self ) -> String {
format! ( " {} : {} " , self . ip , self . port )
}
}
2023-01-24 19:00:31 +05:30
#[ derive(Debug, Clone, Serialize, Deserialize) ]
2021-10-04 21:21:10 +05:30
struct DatabaseBuilder {
pub port : u32 ,
pub hostname : String ,
pub username : String ,
pub password : String ,
pub name : String ,
pub url : String ,
}
impl DatabaseBuilder {
#[ cfg(not(tarpaulin_include)) ]
fn extract_database_url ( url : & Url ) -> Self {
debug! ( " Databse name: {} " , url . path ( ) ) ;
let mut path = url . path ( ) . split ( '/' ) ;
path . next ( ) ;
let name = path . next ( ) . expect ( " no database name " ) . to_string ( ) ;
DatabaseBuilder {
port : url . port ( ) . expect ( " Enter database port " ) . into ( ) ,
hostname : url . host ( ) . expect ( " Enter database host " ) . to_string ( ) ,
username : url . username ( ) . into ( ) ,
url : url . to_string ( ) ,
password : url . password ( ) . expect ( " Enter database password " ) . into ( ) ,
name ,
}
}
}
2023-01-24 19:00:31 +05:30
#[ derive(Debug, Clone, Serialize, Deserialize) ]
2021-10-04 21:21:10 +05:30
pub struct Database {
pub url : String ,
pub pool : u32 ,
}
2023-01-24 19:00:31 +05:30
#[ derive(Debug, Clone, Serialize, Deserialize) ]
pub struct Footer {
pub about : Url ,
pub privacy : Url ,
pub security : Url ,
pub donate : Url ,
pub thanks : Url ,
}
#[ derive(Debug, Clone, Serialize, Deserialize) ]
2021-10-04 21:21:10 +05:30
pub struct Settings {
pub debug : bool ,
pub allow_registration : bool ,
pub database : Database ,
pub server : Server ,
pub source_code : String ,
2023-01-24 19:00:31 +05:30
pub support_email : String ,
2021-10-14 18:53:06 +05:30
pub default_campaign : String ,
2023-01-24 19:00:31 +05:30
pub footer : Footer ,
2021-10-04 21:21:10 +05:30
}
#[ cfg(not(tarpaulin_include)) ]
impl Settings {
pub fn new ( ) -> Result < Self , ConfigError > {
let mut s = Config ::new ( ) ;
// setting default values
#[ cfg(test) ]
s . set_default ( " database.pool " , 2. to_string ( ) )
. expect ( " Couldn't get the number of CPUs " ) ;
const CURRENT_DIR : & str = " ./config/default.toml " ;
2021-10-13 18:43:08 +05:30
const ETC : & str = " /etc/mcaptcha-survey/config.toml " ;
2021-10-04 21:21:10 +05:30
if let Ok ( path ) = env ::var ( " ATHENA_CONFIG " ) {
s . merge ( File ::with_name ( & path ) ) ? ;
} else if Path ::new ( CURRENT_DIR ) . exists ( ) {
// merging default config from file
s . merge ( File ::with_name ( CURRENT_DIR ) ) ? ;
} else if Path ::new ( ETC ) . exists ( ) {
s . merge ( File ::with_name ( ETC ) ) ? ;
} else {
log ::warn! ( " configuration file not found " ) ;
}
2021-10-14 18:53:06 +05:30
s . merge ( Environment ::with_prefix ( " MCAPTCHA " ) . separator ( " __ " ) ) ? ;
2021-10-04 21:21:10 +05:30
check_url ( & s ) ;
2021-10-14 18:53:06 +05:30
check_uuid ( & s ) ;
2021-10-04 21:21:10 +05:30
match env ::var ( " PORT " ) {
Ok ( val ) = > {
s . set ( " server.port " , val ) . unwrap ( ) ;
}
Err ( e ) = > warn! ( " couldn't interpret PORT: {} " , e ) ,
}
match env ::var ( " DATABASE_URL " ) {
Ok ( val ) = > {
let url = Url ::parse ( & val ) . expect ( " couldn't parse Database URL " ) ;
let database_conf = DatabaseBuilder ::extract_database_url ( & url ) ;
set_from_database_url ( & mut s , & database_conf ) ;
}
Err ( e ) = > warn! ( " couldn't interpret DATABASE_URL: {} " , e ) ,
}
set_database_url ( & mut s ) ;
match s . try_into ( ) {
Ok ( val ) = > Ok ( val ) ,
Err ( e ) = > Err ( ConfigError ::Message ( format! ( " \n \n Error: {} . If it says missing fields, then please refer to https://github.com/mCaptcha/mcaptcha#configuration to learn more about how mcaptcha reads configuration \n \n " , e ) ) ) ,
}
}
}
#[ cfg(not(tarpaulin_include)) ]
fn check_url ( s : & Config ) {
let url = s
. get ::< String > ( " source_code " )
. expect ( " Couldn't access source_code " ) ;
Url ::parse ( & url ) . expect ( " Please enter a URL for source_code in settings " ) ;
}
2021-10-14 18:53:06 +05:30
#[ cfg(not(tarpaulin_include)) ]
fn check_uuid ( s : & Config ) {
use std ::str ::FromStr ;
let id = s
. get ::< String > ( " default_campaign " )
. expect ( " Couldn't access default_campaign " ) ;
Uuid ::from_str ( & id ) . expect ( " Please enter a UUID for default_campaign in settings " ) ;
}
2021-10-04 21:21:10 +05:30
#[ cfg(not(tarpaulin_include)) ]
fn set_from_database_url ( s : & mut Config , database_conf : & DatabaseBuilder ) {
s . set ( " database.username " , database_conf . username . clone ( ) )
. expect ( " Couldn't set database username " ) ;
s . set ( " database.password " , database_conf . password . clone ( ) )
. expect ( " Couldn't access database password " ) ;
s . set ( " database.hostname " , database_conf . hostname . clone ( ) )
. expect ( " Couldn't access database hostname " ) ;
s . set ( " database.port " , database_conf . port as i64 )
. expect ( " Couldn't access database port " ) ;
s . set ( " database.name " , database_conf . name . clone ( ) )
. expect ( " Couldn't access database name " ) ;
}
#[ cfg(not(tarpaulin_include)) ]
fn set_database_url ( s : & mut Config ) {
s . set (
" database.url " ,
format! (
r "postgres://{}:{}@{}:{}/{}" ,
s . get ::< String > ( " database.username " )
. expect ( " Couldn't access database username " ) ,
s . get ::< String > ( " database.password " )
. expect ( " Couldn't access database password " ) ,
s . get ::< String > ( " database.hostname " )
. expect ( " Couldn't access database hostname " ) ,
s . get ::< String > ( " database.port " )
. expect ( " Couldn't access database port " ) ,
s . get ::< String > ( " database.name " )
. expect ( " Couldn't access database name " )
) ,
)
. expect ( " Couldn't set databse url " ) ;
}