use log::info; use rocket::{ get, post, request::FlashMessage, form::{Form, FromForm} }; use rocket::serde::json::Json; use rocket_dyn_templates::Template; use rocket::serde::{Deserialize, Serialize}; use peach_lib::config_manager; use peach_lib::config_manager::load_peach_config; use peach_lib::dyndns_client; use peach_lib::dyndns_client::{ check_is_new_dyndns_domain, get_dyndns_subdomain, get_full_dynamic_domain, is_dns_updater_online, }; use peach_lib::error::PeachError; use peach_lib::jsonrpc_client_core::{Error, ErrorKind}; use peach_lib::jsonrpc_core::types::error::ErrorCode; use crate::error::PeachWebError; use crate::routes::authentication::Authenticated; use crate::utils::build_json_response; use rocket::serde::json::Value; #[derive(Debug, Deserialize, FromForm)] pub struct DnsForm { pub external_domain: String, pub enable_dyndns: bool, pub dynamic_domain: String, } pub fn save_dns_configuration(dns_form: DnsForm) -> Result<(), PeachWebError> { // first save local configurations config_manager::set_external_domain(&dns_form.external_domain)?; config_manager::set_dyndns_enabled_value(dns_form.enable_dyndns)?; // if dynamic dns is enabled and this is a new domain name, then register it if dns_form.enable_dyndns { let full_dynamic_domain = get_full_dynamic_domain(&dns_form.dynamic_domain); // check if this is a new domain or if its already registered let is_new_domain = check_is_new_dyndns_domain(&full_dynamic_domain); if is_new_domain { match dyndns_client::register_domain(&full_dynamic_domain) { Ok(_) => { info!("Registered new dyndns domain"); // successful update Ok(()) } Err(err) => { info!("Failed to register dyndns domain: {:?}", err); // json response for failed update let msg: String = match err { PeachError::JsonRpcClientCore { source } => { match source { Error(ErrorKind::JsonRpcError(err), _state) => match err.code { ErrorCode::ServerError(-32030) => { format!("Error registering domain: {} was previously registered", full_dynamic_domain) } _ => { format!("Failed to register dyndns domain {:?}", err) } }, _ => { format!("Failed to register dyndns domain: {:?}", source) } } } _ => "Failed to register dyndns domain".to_string(), }; Err(PeachWebError::FailedToRegisterDynDomain { msg }) } } } // if the domain is already registered, then dont re-register, and just return success else { Ok(()) } } else { Ok(()) } } #[derive(Debug, Serialize)] pub struct ConfigureDNSContext { pub external_domain: String, pub dyndns_subdomain: String, pub enable_dyndns: bool, pub is_dyndns_online: bool, pub back: Option, pub title: Option, pub flash_name: Option, pub flash_msg: Option, } impl ConfigureDNSContext { pub fn build() -> ConfigureDNSContext { let peach_config = load_peach_config().unwrap(); let dyndns_fulldomain = peach_config.dyn_domain; let is_dyndns_online = is_dns_updater_online().unwrap(); let dyndns_subdomain = get_dyndns_subdomain(&dyndns_fulldomain).unwrap_or(dyndns_fulldomain); ConfigureDNSContext { external_domain: peach_config.external_domain, dyndns_subdomain, enable_dyndns: peach_config.dyn_enabled, is_dyndns_online, back: None, title: None, flash_name: None, flash_msg: None, } } } #[get("/network/dns")] pub fn configure_dns(flash: Option, auth: Authenticated) -> Template { let mut context = ConfigureDNSContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); context.title = Some("Configure DNS".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("configure_dns", &context) } #[post("/network/dns", data = "")] pub fn configure_dns_post(dns: Form, auth: Authenticated) -> Template { let result = save_dns_configuration(dns.into_inner()); match result { Ok(_) => { let mut context = ConfigureDNSContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); context.title = Some("Configure DNS".to_string()); context.flash_name = Some("success".to_string()); context.flash_msg = Some("New dynamic dns configuration is now enabled".to_string()); Template::render("configure_dns", &context) } Err(err) => { let mut context = ConfigureDNSContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); context.title = Some("Configure DNS".to_string()); context.flash_name = Some("error".to_string()); context.flash_msg = Some(format!("Failed to save dns configurations: {}", err)); Template::render("configure_dns", &context) } } } #[post("/api/v1/dns/configure", data = "")] pub fn save_dns_configuration_endpoint(dns_form: Json, auth: Authenticated) -> Value { let result = save_dns_configuration(dns_form.into_inner()); match result { Ok(_) => { let status = "success".to_string(); let msg = "New dynamic dns configuration is now enabled".to_string(); build_json_response(status, None, Some(msg)) } Err(err) => { let status = "error".to_string(); let msg = format!("{}", err); build_json_response(status, None, Some(msg)) } } }