diff --git a/README.md b/README.md index 8b2b000..07649b9 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,17 @@ domain: # renewed. #contact_email: REQUIRED if service.http.https_addr is set + # The domain name which will be used to serve the web interface of Domani. If + # service.http.https_addr is enabled then an HTTPS certificate for this domain + # will be retrieved automatically. + # + # This can be set to null to disable the web interface entirely. + #interface_domain: "localhost" + # builtins are domains whose configuration is built into domani. These domains # are not able to be configured via the web interface, and will be hidden from # it unless the `public` key is set to true. - #builtins: + #builtin_domains: # An example built-in domain backed by a git repo. #git.example.com: @@ -79,13 +86,14 @@ domain: # domain list, but will not be configurable in the web interface #public: false - #proxied: + #proxied_domains: - # An example built-in domain backed by an gemini and HTTP reverse-proxies to + # An example proxied domain backed by an gemini and HTTP reverse-proxies to # other backends. # # HTTP requests will be proxied to http_url, and gemini requests will be - # proxied to gemini_url. Either can be null. + # proxied to gemini_url. Either can be null to disable serving on that + # protocol. # # HTTP requests to the backing service will automatically have # X-Forwarded-For and (if HTTPS) X-Forwarded-Proto headers added to them. @@ -106,7 +114,8 @@ domain: # - name: X-HEADER-TO-DELETE # value: "" - # Set to true to prevent the domain from being served over https. + # Set to true to prevent the domain from being served over https, even if + # http_url is set. #https_disabled: false service: @@ -132,13 +141,6 @@ service: #- kind: CNAME # name: domain.com - # The domain name which will be used to serve the web interface of Domani. If - # service.http.https_addr is enabled then an HTTPS certificate for this domain - # will be retrieved automatically. - # - # This can be set to null to disable the web interface entirely. - #interface_domain: "localhost" - #http: # The address to listen for HTTP requests on. This must use port 80 if diff --git a/src/domain/config.rs b/src/domain/config.rs index ee7f321..0f11fca 100644 --- a/src/domain/config.rs +++ b/src/domain/config.rs @@ -9,7 +9,11 @@ fn default_resolver_addr() -> net::SocketAddr { net::SocketAddr::from_str("1.1.1.1:53").unwrap() } -#[derive(Deserialize, Serialize)] +fn default_interface_domain() -> Option { + Some(domain::Name::from_str("localhost").unwrap()) +} + +#[derive(Clone, Deserialize, Serialize)] pub struct ConfigDNS { #[serde(default = "default_resolver_addr")] pub resolver_addr: net::SocketAddr, @@ -23,7 +27,7 @@ impl Default for ConfigDNS { } } -#[derive(Deserialize, Serialize)] +#[derive(Clone, Deserialize, Serialize)] pub struct ConfigACME { pub contact_email: String, } @@ -54,7 +58,7 @@ pub struct ConfigProxiedDomain { pub https_disabled: bool, } -#[derive(Deserialize, Serialize)] +#[derive(Clone, Deserialize, Serialize)] pub struct Config { pub store_dir_path: path::PathBuf, #[serde(default)] @@ -62,8 +66,11 @@ pub struct Config { pub acme: Option, #[serde(default)] - pub builtins: collections::HashMap, + pub builtin_domains: collections::HashMap, #[serde(default)] - pub proxied: collections::HashMap, + pub proxied_domains: collections::HashMap, + + #[serde(default = "default_interface_domain")] + pub interface_domain: Option, } diff --git a/src/domain/manager.rs b/src/domain/manager.rs index 6265509..2844ea3 100644 --- a/src/domain/manager.rs +++ b/src/domain/manager.rs @@ -1,8 +1,8 @@ -use crate::domain::{self, acme, checker, config, gemini, store, tls}; +use crate::domain::{self, acme, checker, gemini, store, tls}; use crate::error::unexpected::{self, Mappable}; use crate::{origin, task_stack, util}; -use std::{collections, sync}; +use std::sync; use tokio_util::sync::CancellationToken; pub enum GetSettingsResult { @@ -153,8 +153,7 @@ pub struct ManagerImpl { domain_checker: checker::DNSChecker, acme_manager: Option>, gemini_store: Option>, - builtins: collections::HashMap, - proxied: collections::HashMap, + config: domain::Config, } impl ManagerImpl { @@ -170,8 +169,7 @@ impl ManagerImpl { domain_checker: checker::DNSChecker, acme_manager: Option, gemini_store: Option, - builtins: collections::HashMap, - proxied: collections::HashMap, + config: domain::Config, ) -> sync::Arc { let manager = sync::Arc::new(ManagerImpl { origin_store: Box::from(origin_store), @@ -180,8 +178,7 @@ impl ManagerImpl { acme_manager: acme_manager .map(|m| Box::new(m) as Box), gemini_store: gemini_store.map(|m| Box::new(m) as Box), - builtins, - proxied, + config, }); task_stack.push_spawn(|canceller| { @@ -289,11 +286,11 @@ impl ManagerImpl { impl Manager for ManagerImpl { fn get_settings(&self, domain: &domain::Name) -> Result { - if let Some(config) = self.builtins.get(domain) { + if let Some(config) = self.config.builtin_domains.get(domain) { return Ok(GetSettingsResult::Builtin(config.clone())); } - if let Some(config) = self.proxied.get(domain) { + if let Some(config) = self.config.proxied_domains.get(domain) { return Ok(GetSettingsResult::Proxied(config.clone())); } @@ -330,7 +327,10 @@ impl Manager for ManagerImpl { settings: domain::Settings, ) -> util::BoxFuture<'mgr, Result<(), SyncWithSettingsError>> { Box::pin(async move { - if self.builtins.contains_key(&domain) || self.proxied.contains_key(&domain) { + let is_builtin = self.config.builtin_domains.contains_key(&domain); + let is_proxied = self.config.proxied_domains.contains_key(&domain); + + if is_builtin || is_proxied { return Err(SyncWithSettingsError::NotModifiable); } @@ -384,7 +384,8 @@ impl Manager for ManagerImpl { }) .collect(); - self.builtins + self.config + .builtin_domains .iter() .map(|(domain, config)| ManagedDomain { domain: domain.clone(), @@ -392,7 +393,8 @@ impl Manager for ManagerImpl { }) .collect_into(&mut res); - self.proxied + self.config + .proxied_domains .iter() .map(|(domain, _)| ManagedDomain { domain: domain.clone(), diff --git a/src/main.rs b/src/main.rs index 28acc23..02f9b92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,7 @@ async fn main() { // Since the interface domain _must_ point to the service (otherwise it wouldn't work) it's // reasonable to assume that a CNAME on any domain would suffice to point that domain to // the service. - if let Some(ref interface_domain) = config.service.interface_domain { + if let Some(ref interface_domain) = config.domain.interface_domain { let interface_cname = domani::service::ConfigDNSRecord::CNAME { name: interface_domain.clone(), }; @@ -106,6 +106,7 @@ async fn main() { let acme_config = config .domain .acme + .clone() .expect("acme configuration must be set if https is enabled"); let domain_acme_store = @@ -143,8 +144,7 @@ async fn main() { domain_checker, domain_acme_manager, domain_gemini_store, - config.domain.builtins.clone(), - config.domain.proxied.clone(), + config.domain.clone(), ); let _ = domani::service::http::Service::new( @@ -152,7 +152,8 @@ async fn main() { domain_manager.clone(), domani::domain::manager::HttpsCertResolver::from(domain_manager.clone()), config.service.clone(), - config.domain.proxied.clone(), + config.domain.proxied_domains.clone(), + config.domain.interface_domain.clone(), ); if gemini_enabled { @@ -161,7 +162,7 @@ async fn main() { domain_manager.clone(), domani::domain::manager::GeminiCertResolver::from(domain_manager.clone()), config.service.gemini.clone(), - config.domain.proxied.clone(), + config.domain.proxied_domains.clone(), ); } diff --git a/src/service/config.rs b/src/service/config.rs index 35ad9ec..a79ab03 100644 --- a/src/service/config.rs +++ b/src/service/config.rs @@ -1,10 +1,6 @@ use crate::{domain, service}; use serde::{Deserialize, Serialize}; -use std::{net, str::FromStr}; - -fn default_interface_domain() -> Option { - Some(domain::Name::from_str("localhost").unwrap()) -} +use std::net; #[derive(Serialize, Deserialize, Clone, PartialEq)] #[serde(tag = "kind")] @@ -31,9 +27,6 @@ pub struct Config { #[serde(default)] pub dns_records: Vec, - #[serde(default = "default_interface_domain")] - pub interface_domain: Option, - #[serde(default)] pub http: service::http::Config, diff --git a/src/service/http.rs b/src/service/http.rs index b334fca..9f49b0f 100644 --- a/src/service/http.rs +++ b/src/service/http.rs @@ -15,14 +15,6 @@ use std::{collections, future, net, sync}; use crate::error::unexpected; use crate::{domain, service, task_stack}; -pub struct Service { - domain_manager: sync::Arc, - cert_resolver: sync::Arc, - handlebars: handlebars::Handlebars<'static>, - config: service::Config, - proxied: collections::HashMap, -} - #[derive(Serialize)] struct BasePresenter<'a, T> { page_name: &'a str, @@ -52,13 +44,23 @@ struct DomainSyncArgs { url_encoded_domain_settings: util::UrlEncodedDomainSettings, } +pub struct Service { + domain_manager: sync::Arc, + cert_resolver: sync::Arc, + handlebars: handlebars::Handlebars<'static>, + config: service::Config, + proxied_domains: collections::HashMap, + interface_domain: Option, +} + impl Service { pub fn new( task_stack: &mut task_stack::TaskStack, domain_manager: sync::Arc, cert_resolver: CertResolver, config: service::Config, - proxied: collections::HashMap, + proxied_domains: collections::HashMap, + interface_domain: Option, ) -> sync::Arc where CertResolver: rustls::server::ResolvesServerCert + 'static, @@ -70,7 +72,8 @@ impl Service { cert_resolver: sync::Arc::from(cert_resolver), handlebars: tpl::get(), config, - proxied, + proxied_domains, + interface_domain, }); task_stack.push_spawn(|canceller| tasks::listen_http(service.clone(), canceller)); @@ -457,7 +460,7 @@ impl Service { } } - if let Some(config) = self.proxied.get(&domain) { + if let Some(config) = self.proxied_domains.get(&domain) { if let Some(ref http_url) = config.http_url { return service::http::proxy::serve_http_request( http_url.original_url.as_str(), @@ -478,7 +481,7 @@ impl Service { } } - if Some(&domain) == self.config.interface_domain.as_ref() { + if Some(&domain) == self.interface_domain.as_ref() { return self.serve_interface(req).await; } diff --git a/src/service/http/tasks.rs b/src/service/http/tasks.rs index e266bcf..a77e26f 100644 --- a/src/service/http/tasks.rs +++ b/src/service/http/tasks.rs @@ -16,7 +16,6 @@ pub async fn listen_http( // only used for logging let listen_host = service - .config .interface_domain .clone() .map_or(addr.ip().to_string(), |ref d| d.as_str().to_string()); @@ -56,7 +55,6 @@ pub async fn listen_https( // only used for logging let listen_host = service - .config .interface_domain .clone() .map_or(addr.ip().to_string(), |ref d| d.as_str().to_string());