2022-03-23 07:14:54 +00:00
use log ::{ debug , warn } ;
2022-03-12 08:36:40 +00:00
use maud ::{ html , PreEscaped } ;
2022-03-13 09:09:00 +00:00
use peach_lib ::sbot ::{ SbotConfig , SbotStatus } ;
2022-03-23 07:14:54 +00:00
use rouille ::{ post_input , try_or_400 , Request , Response } ;
2022-03-12 08:36:40 +00:00
2022-03-23 07:14:54 +00:00
use crate ::{
templates ,
utils ::{
flash ::{ FlashRequest , FlashResponse } ,
2022-03-23 09:41:21 +00:00
sbot , theme ,
2022-03-23 07:14:54 +00:00
} ,
} ;
2022-03-12 08:36:40 +00:00
2022-03-13 09:09:00 +00:00
/// Read the status and configuration of the sbot.
/// Define fallback values if an error is returned from either read function.
fn read_status_and_config ( ) -> ( String , SbotConfig , String , String ) {
// retrieve go-sbot systemd process status
let run_on_startup = if let Ok ( status ) = SbotStatus ::read ( ) {
// if the read is ok, return the value or "disabled" if no value is set
match status . boot_state {
Some ( state ) = > state ,
None = > " disabled " . to_string ( ) ,
}
} else {
// if the read returns an error, set the value to "disabled"
" disabled " . to_string ( )
} ;
// retrieve sbot config parameters
let sbot_config = match SbotConfig ::read ( ) {
Ok ( config ) = > config ,
// build default config if an error is returned from the read attempt
Err ( _ ) = > SbotConfig ::default ( ) ,
} ;
// split the listen address into ip and port
let ( ip , port ) = match sbot_config . lis . find ( ':' ) {
Some ( index ) = > {
let ( ip , port ) = sbot_config . lis . split_at ( index ) ;
2022-03-23 07:14:54 +00:00
// remove the : from the port
2022-03-23 09:41:21 +00:00
( ip . to_string ( ) , port . replace ( ':' , " " ) )
2022-03-13 09:09:00 +00:00
}
// if no ':' separator is found, assume an ip has been configured (without port)
None = > ( sbot_config . lis . to_string ( ) , String ::new ( ) ) ,
} ;
2022-03-12 08:36:40 +00:00
2022-03-13 09:09:00 +00:00
( run_on_startup , sbot_config , ip , port )
}
2022-03-12 08:36:40 +00:00
/// Scuttlebutt settings menu template builder.
2022-03-23 07:14:54 +00:00
pub fn build_template ( request : & Request ) -> PreEscaped < String > {
// check for flash cookies; will be (None, None) if no flash cookies are found
let ( flash_name , flash_msg ) = request . retrieve_flash ( ) ;
2022-03-13 09:09:00 +00:00
let ( run_on_startup , sbot_config , ip , port ) = read_status_and_config ( ) ;
2022-03-12 08:36:40 +00:00
let menu_template = html! {
( PreEscaped ( " <!-- SBOT CONFIGURATION FORM --> " ) )
div class = " card center " {
form id = " sbotConfig " class = " center " action = " /settings/scuttlebutt/configure " method = " post " {
div class = " center " style = " display: flex; flex-direction: column; margin-bottom: 2rem; " title = " Number of hops to replicate " {
label for = " hops " class = " label-small font-gray " { " HOPS " }
div id = " hops " style = " display: flex; justify-content: space-evenly; " {
div {
2022-03-13 09:09:00 +00:00
@ if sbot_config . hops = = 0 {
2022-03-12 08:36:40 +00:00
input type = " radio " id = " hops_0 " name = " hops " value = " 0 " checked ;
} @ else {
input type = " radio " id = " hops_0 " name = " hops " value = " 0 " ;
}
label class = " font-normal " for = " hops_0 " { " 0 " }
}
div {
2022-03-13 09:09:00 +00:00
@ if sbot_config . hops = = 1 {
2022-03-12 08:36:40 +00:00
input type = " radio " id = " hops_1 " name = " hops " value = " 1 " checked ;
} @ else {
input type = " radio " id = " hops_1 " name = " hops " value = " 1 " ;
}
label class = " font-normal " for = " hops_1 " { " 1 " }
}
div {
2022-03-13 09:09:00 +00:00
@ if sbot_config . hops = = 2 {
2022-03-12 08:36:40 +00:00
input type = " radio " id = " hops_2 " name = " hops " value = " 2 " checked ;
} @ else {
input type = " radio " id = " hops_2 " name = " hops " value = " 2 " ;
}
label class = " font-normal " for = " hops_2 " { " 2 " }
}
div {
2022-03-13 09:09:00 +00:00
@ if sbot_config . hops = = 3 {
2022-03-12 08:36:40 +00:00
input type = " radio " id = " hops_3 " name = " hops " value = " 3 " checked ;
} @ else {
input type = " radio " id = " hops_3 " name = " hops " value = " 3 " ;
}
label class = " font-normal " for = " hops_3 " { " 3 " }
}
div {
2022-03-13 09:09:00 +00:00
@ if sbot_config . hops = = 4 {
2022-03-12 08:36:40 +00:00
input type = " radio " id = " hops_4 " name = " hops " value = " 4 " checked ;
} @ else {
input type = " radio " id = " hops_4 " name = " hops " value = " 4 " ;
}
label class = " font-normal " for = " hops_4 " { " 4 " }
}
}
}
div class = " center " style = " display: flex; justify-content: space-between; " {
div style = " display: flex; flex-direction: column; width: 60%; margin-bottom: 2rem; " title = " IP address on which the sbot runs " {
label for = " ip " class = " label-small font-gray " { " IP ADDRESS " }
2022-03-13 09:09:00 +00:00
input type = " text " id = " ip " name = " lis_ip " value = ( ip ) ;
2022-03-12 08:36:40 +00:00
}
div style = " display: flex; flex-direction: column; width: 20%; margin-bottom: 2rem; " title = " Port on which the sbot runs " {
label for = " port " class = " label-small font-gray " { " PORT " }
2022-03-13 09:09:00 +00:00
input type = " text " id = " port " name = " lis_port " value = ( port ) ;
2022-03-12 08:36:40 +00:00
}
}
div class = " center " style = " display: flex; flex-direction: column; margin-bottom: 2rem; " title = " Network key (aka 'caps key') to define the Scuttleverse in which the sbot operates in " {
label for = " network_key " class = " label-small font-gray " { " NETWORK KEY " }
2022-03-13 09:09:00 +00:00
input type = " text " id = " network_key " name = " shscap " value = ( sbot_config . shscap ) ;
2022-03-12 08:36:40 +00:00
}
div class = " center " style = " display: flex; flex-direction: column; margin-bottom: 2rem; " title = " Directory in which the sbot database is saved " {
label for = " database_dir " class = " label-small font-gray " { " DATABASE DIRECTORY " }
2022-03-13 09:09:00 +00:00
input type = " text " id = " database_dir " name = " repo " value = ( sbot_config . repo ) ;
2022-03-12 08:36:40 +00:00
}
div class = " center " {
2022-06-15 07:58:21 +00:00
@ if sbot_config . enable_ebt {
input type = " checkbox " id = " ebtReplication " style = " margin-bottom: 1rem; " name = " enable_ebt " checked ;
} @ else {
input type = " checkbox " id = " ebtReplication " style = " margin-bottom: 1rem; " name = " enable_ebt " ;
}
label class = " font-normal " for = " ebtReplication " title = " Enable Epidemic Broadcast Tree (EBT) replication instead of legacy replication " {
" Enable EBT Replication "
}
br ;
2022-03-17 09:01:36 +00:00
@ if sbot_config . localadv {
2022-03-12 08:36:40 +00:00
input type = " checkbox " id = " lanBroadcast " style = " margin-bottom: 1rem; " name = " localadv " checked ;
} @ else {
input type = " checkbox " id = " lanBroadcast " style = " margin-bottom: 1rem; " name = " localadv " ;
}
label class = " font-normal " for = " lanBroadcast " title = " Broadcast the IP and port of this sbot instance so that local peers can discovery it and attempt to connect " {
" Enable LAN Broadcasting "
}
br ;
2022-03-17 09:01:36 +00:00
@ if sbot_config . localdiscov {
2022-03-12 08:36:40 +00:00
input type = " checkbox " id = " lanDiscovery " style = " margin-bottom: 1rem; " name = " localdiscov " checked ;
} @ else {
input type = " checkbox " id = " lanDiscovery " style = " margin-bottom: 1rem; " name = " localdiscov " ;
}
label class = " font-normal " for = " lanDiscovery " title = " Listen for the presence of local peers and attempt to connect if found " { " Enable LAN Discovery " }
br ;
@ if run_on_startup = = " enabled " {
input type = " checkbox " id = " startup " style = " margin-bottom: 1rem; " name = " startup " checked ;
} @ else {
input type = " checkbox " id = " startup " style = " margin-bottom: 1rem; " name = " startup " ;
}
label class = " font-normal " for = " startup " title = " Run the pub automatically on system startup " { " Run pub when computer starts " }
br ;
2022-03-17 09:01:36 +00:00
@ if sbot_config . repair {
2022-03-12 08:36:40 +00:00
input type = " checkbox " id = " repair " name = " repair " checked ;
} @ else {
input type = " checkbox " id = " repair " name = " repair " ;
}
label class = " font-normal " for = " repair " title = " Attempt to repair the filesystem when starting the pub " { " Attempt filesystem repair when pub starts " }
}
( PreEscaped ( " <!-- hidden input elements for all other config variables --> " ) )
input type = " hidden " id = " debugdir " name = " debugdir " value = ( sbot_config . debugdir ) ;
input type = " hidden " id = " hmac " name = " hmac " value = ( sbot_config . hmac ) ;
input type = " hidden " id = " wslis " name = " wslis " value = ( sbot_config . wslis ) ;
input type = " hidden " id = " debuglis " name = " debuglis " value = ( sbot_config . debuglis ) ;
input type = " hidden " id = " promisc " name = " promisc " value = ( sbot_config . promisc ) ;
input type = " hidden " id = " nounixsock " name = " nounixsock " value = ( sbot_config . nounixsock ) ;
( PreEscaped ( " <!-- BUTTONS --> " ) )
input id = " saveConfig " class = " button button-primary center " style = " margin-top: 2rem; " type = " submit " title = " Save configuration parameters to file " value = " Save " ;
2022-03-23 07:14:54 +00:00
input id = " saveRestartConfig " class = " button button-primary center " type = " submit " title = " Save configuration parameters to file and then (re)start the pub " value = " Save & Restart " formaction = " /settings/scuttlebutt/configure/restart " ;
2022-03-12 08:36:40 +00:00
a id = " restoreDefaults " class = " button button-warning center " href = " /settings/scuttlebutt/configure/default " title = " Restore default configuration parameters and save them to file " { " Restore Defaults " }
}
2022-03-23 07:14:54 +00:00
// render flash message if cookies were found in the request
@ if let ( Some ( name ) , Some ( msg ) ) = ( flash_name , flash_msg ) {
( PreEscaped ( " <!-- FLASH MESSAGE --> " ) )
( templates ::flash ::build_template ( name , msg ) )
}
2022-03-12 08:36:40 +00:00
}
} ;
// wrap the nav bars around the settings menu template content
// parameters are template, title and back url
2022-06-21 11:13:36 +00:00
let body = templates ::nav ::build_template (
menu_template ,
" Scuttlebutt Settings " ,
Some ( " /settings/scuttlebutt " ) ,
) ;
2022-03-12 08:36:40 +00:00
2022-03-23 09:41:21 +00:00
// query the current theme so we can pass it into the base template builder
let theme = theme ::get_theme ( ) ;
2022-03-12 08:36:40 +00:00
// render the base template with the provided body
2022-03-23 09:41:21 +00:00
templates ::base ::build_template ( body , theme )
2022-03-12 08:36:40 +00:00
}
2022-03-23 07:14:54 +00:00
/// Parse the sbot configuration values and write to file.
pub fn handle_form ( request : & Request , restart : bool ) -> Response {
// query the request body for form data
// return a 400 error if the admin_id field is missing
let data = try_or_400! ( post_input! ( request , {
repo : String ,
debugdir : String ,
shscap : String ,
hmac : String ,
hops : u8 ,
lis_ip : String ,
lis_port : String ,
wslis : String ,
debuglis : String ,
localadv : bool ,
localdiscov : bool ,
enable_ebt : bool ,
promisc : bool ,
nounixsock : bool ,
startup : bool ,
repair : bool ,
} ) ) ;
// concat the ip and port for listen address
let lis = format! ( " {} : {} " , data . lis_ip , data . lis_port ) ;
// instantiate `SbotConfig` from form data
let config = SbotConfig {
lis ,
hops : data . hops ,
repo : data . repo ,
debugdir : data . debugdir ,
shscap : data . shscap ,
localadv : data . localadv ,
localdiscov : data . localdiscov ,
hmac : data . hmac ,
wslis : data . wslis ,
debuglis : data . debuglis ,
enable_ebt : data . enable_ebt ,
promisc : data . promisc ,
nounixsock : data . nounixsock ,
repair : data . repair ,
} ;
match data . startup {
true = > {
2022-03-24 07:27:06 +00:00
debug! ( " Enabling go-sbot.service " ) ;
2022-03-23 07:14:54 +00:00
if let Err ( e ) = sbot ::systemctl_sbot_cmd ( " enable " ) {
warn! ( " Failed to enable go-sbot.service: {} " , e )
}
}
false = > {
2022-03-24 07:27:06 +00:00
debug! ( " Disabling go-sbot.service " ) ;
2022-03-23 07:14:54 +00:00
if let Err ( e ) = sbot ::systemctl_sbot_cmd ( " disable " ) {
warn! ( " Failed to disable go-sbot.service: {} " , e )
}
}
} ;
// write config to file
let ( name , msg ) = match SbotConfig ::write ( config ) {
Ok ( _ ) = > {
// if `restart` query parameter is `true`, attempt sbot process (re)start
if restart {
// returns a tuple of (name, msg) based on the outcome (success or error)
sbot ::restart_sbot_process ( )
} else {
( " success " . to_string ( ) , " Updated configuration " . to_string ( ) )
}
}
Err ( err ) = > (
" error " . to_string ( ) ,
format! ( " Failed to update configuration: {} " , err ) ,
) ,
} ;
let ( flash_name , flash_msg ) = ( format! ( " flash_name= {} " , name ) , format! ( " flash_msg= {} " , msg ) ) ;
Response ::redirect_303 ( " /settings/scuttlebutt/configure " ) . add_flash ( flash_name , flash_msg )
}