2022-10-05 16:08:36 +05:30
/*
* Copyright ( C ) 2022 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 ;
2022-12-11 19:27:59 +05:30
use config ::{ builder ::DefaultState , Config , ConfigBuilder , ConfigError , Environment , File } ;
2022-10-05 16:08:36 +05:30
use derive_more ::Display ;
2022-11-16 17:20:34 +05:30
use log ::info ;
2022-10-05 16:08:36 +05:30
use log ::warn ;
use serde ::Deserialize ;
use serde ::Serialize ;
use url ::Url ;
2022-11-16 17:20:34 +05:30
const PREFIX : & str = " LPCONDUCTOR " ;
2022-12-07 12:02:34 +05:30
const SEPARATOR : & str = " _ " ;
2022-11-16 17:20:34 +05:30
2022-10-05 16:08:36 +05:30
#[ derive(Debug, Clone, Deserialize) ]
pub struct Server {
pub port : u32 ,
pub domain : String ,
pub ip : String ,
pub url_prefix : Option < String > ,
pub proxy_has_tls : bool ,
}
impl Server {
#[ cfg(not(tarpaulin_include)) ]
pub fn get_ip ( & self ) -> String {
format! ( " {} : {} " , self . ip , self . port )
}
}
2022-10-05 16:58:49 +05:30
#[ derive(Deserialize, Serialize, Display, Eq, PartialEq, Clone, Debug) ]
#[ serde(rename_all = " lowercase " ) ]
pub enum ConductorType {
/// doesn't do anything
#[ display(fmt = " dummy " ) ]
Dummy ,
}
2022-12-07 12:49:14 +05:30
#[ derive(Debug, Clone, Deserialize) ]
pub struct Creds {
2022-12-29 17:29:07 +05:30
pub token : String ,
2022-12-07 12:49:14 +05:30
}
2022-10-05 16:08:36 +05:30
#[ derive(Debug, Clone, Deserialize) ]
pub struct Settings {
pub debug : bool ,
2022-12-11 19:30:36 +05:30
pub creds : Creds ,
2022-10-05 16:08:36 +05:30
pub server : Server ,
2022-12-11 19:27:59 +05:30
pub source_code : Url ,
2022-10-05 16:58:49 +05:30
pub conductor : ConductorType ,
2022-10-05 16:08:36 +05:30
}
#[ cfg(not(tarpaulin_include)) ]
impl Settings {
2022-12-29 17:29:07 +05:30
pub fn authenticate ( & self , token : & str ) -> bool {
self . creds . token = = token
2022-12-07 12:49:14 +05:30
}
2022-10-05 16:08:36 +05:30
pub fn new ( ) -> Result < Self , ConfigError > {
2022-12-11 19:27:59 +05:30
let mut s = Config ::builder ( ) ;
2022-10-05 16:08:36 +05:30
2022-12-07 13:06:17 +05:30
const CURRENT_DIR : & str = " ./config/config.toml " ;
2022-10-05 16:08:36 +05:30
const ETC : & str = " /etc/lpconductor/config.toml " ;
if let Ok ( path ) = env ::var ( " LPCONDUCTOR_CONFIG " ) {
2022-12-11 19:27:59 +05:30
s = s . add_source ( File ::with_name ( & path ) ) ;
2022-10-05 16:08:36 +05:30
} else if Path ::new ( CURRENT_DIR ) . exists ( ) {
// merging default config from file
2022-12-11 19:27:59 +05:30
s = s . add_source ( File ::with_name ( CURRENT_DIR ) ) ;
2022-10-05 16:08:36 +05:30
} else if Path ::new ( ETC ) . exists ( ) {
2022-12-11 19:27:59 +05:30
s = s . add_source ( File ::with_name ( ETC ) ) ;
2022-10-05 16:08:36 +05:30
} else {
2022-11-16 17:20:34 +05:30
warn! ( " configuration file not found " ) ;
2022-10-05 16:08:36 +05:30
}
2022-12-11 19:27:59 +05:30
s = s . add_source ( Environment ::with_prefix ( PREFIX ) . separator ( SEPARATOR ) ) ;
s = set_separator_field ( s ) ;
2022-10-05 16:08:36 +05:30
match env ::var ( " PORT " ) {
Ok ( val ) = > {
2022-12-11 19:27:59 +05:30
s = s . set_override ( " server.port " , val ) . unwrap ( ) ;
2022-10-05 16:08:36 +05:30
}
Err ( e ) = > warn! ( " couldn't interpret PORT: {} " , e ) ,
}
2022-12-11 19:27:59 +05:30
let s = s . build ( ) ? ;
match s . try_deserialize ::< Self > ( ) {
2022-10-05 16:08:36 +05:30
Ok ( val ) = > {
Ok ( val )
} ,
2022-12-07 12:02:34 +05:30
Err ( e ) = > Err ( ConfigError ::Message ( format! ( " \n \n Error: {} . If it says missing fields, then please refer to https://git.batsense.net/LibrePages/conductor to learn more about how conductor reads configuration \n \n " , e ) ) ) ,
2022-10-05 16:08:36 +05:30
}
}
}
2022-11-16 17:20:34 +05:30
#[ cfg(not(tarpaulin_include)) ]
2022-12-11 19:27:59 +05:30
fn set_separator_field ( mut s : ConfigBuilder < DefaultState > ) -> ConfigBuilder < DefaultState > {
2022-11-16 17:20:34 +05:30
// ref: https://github.com/mehcode/config-rs/issues/391
2022-12-11 19:27:59 +05:30
fn from_env (
s : ConfigBuilder < DefaultState > ,
env_name : & str ,
config_name : & str ,
) -> ConfigBuilder < DefaultState > {
2022-11-16 17:20:34 +05:30
if let Ok ( val ) = env ::var ( env_name ) {
info! ( " Overriding {config_name} with data from env var {env_name} " ) ;
2022-12-11 19:27:59 +05:30
s . set_override ( config_name , val )
. unwrap_or_else ( | _ | panic! ( " Couldn't set {config_name} from env var {env_name} " ) )
} else {
s
2022-11-16 17:20:34 +05:30
}
}
2022-12-11 19:27:59 +05:30
s = from_env ( s , & format! ( " {PREFIX} {SEPARATOR} SOURCE_CODE " ) , " source_code " ) ;
s = from_env (
2022-11-16 17:20:34 +05:30
s ,
& format! ( " {PREFIX} {SEPARATOR} SERVER {SEPARATOR} URL_PREFIX " ) ,
" server.url_prefix " ,
) ;
2022-12-11 19:27:59 +05:30
s = from_env (
2022-11-16 17:20:34 +05:30
s ,
& format! ( " {PREFIX} {SEPARATOR} SERVER {SEPARATOR} PROXY_HAS_TLS " ) ,
" server.proxy_has_tls " ,
) ;
2022-12-29 17:48:30 +05:30
s = from_env (
s ,
& format! ( " {PREFIX} {SEPARATOR} CREDS {SEPARATOR} TOKEn " ) ,
" creds.token " ,
) ;
2022-12-11 19:27:59 +05:30
s
2022-10-05 16:08:36 +05:30
}
2022-12-07 12:49:14 +05:30
#[ cfg(test) ]
mod tests {
use super ::* ;
#[ test ]
fn creds_works ( ) {
let settings = Settings ::new ( ) . unwrap ( ) ;
2022-12-29 17:29:07 +05:30
let creds = settings . creds . clone ( ) ;
2022-12-07 12:49:14 +05:30
2022-12-29 17:29:07 +05:30
assert! ( settings . authenticate ( & creds . token ) ) ;
2022-12-07 12:49:14 +05:30
2022-12-11 19:30:36 +05:30
let mut creds = settings . creds . clone ( ) ;
2022-12-07 12:49:14 +05:30
2022-12-29 17:29:07 +05:30
creds . token = " noexist " . into ( ) ;
assert! ( ! settings . authenticate ( & creds . token ) )
2022-12-07 12:49:14 +05:30
}
}