diff --git a/src/domain/manager.rs b/src/domain/manager.rs index ce74dba..c8e499c 100644 --- a/src/domain/manager.rs +++ b/src/domain/manager.rs @@ -6,6 +6,8 @@ use crate::util; use std::sync; use tokio_util::sync::CancellationToken; +pub type GetSettingsResult = domain::store::GetResult; + #[derive(thiserror::Error, Debug)] pub enum GetSettingsError { #[error("not found")] @@ -140,7 +142,7 @@ pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyEr //#[mockall::automock] pub trait Manager: Sync + Send + rustls::server::ResolvesServerCert { - fn get_settings(&self, domain: &domain::Name) -> Result; + fn get_settings(&self, domain: &domain::Name) -> Result; fn get_file<'store>( &'store self, @@ -235,7 +237,7 @@ impl ManagerImpl { } impl Manager for ManagerImpl { - fn get_settings(&self, domain: &domain::Name) -> Result { + fn get_settings(&self, domain: &domain::Name) -> Result { Ok(self.domain_store.get(domain)?) } @@ -244,13 +246,13 @@ impl Manager for ManagerImpl { domain: &domain::Name, path: &str, ) -> Result { - let config = self.domain_store.get(domain)?; + let settings = self.domain_store.get(domain)?.settings; - if let origin::Descr::Proxy { .. } = config.origin_descr { + if let origin::Descr::Proxy { .. } = settings.origin_descr { return Err(unexpected::Error::from("origin is proxy, can't serve file").into()); } - let f = self.origin_store.get_file(&config.origin_descr, path)?; + let f = self.origin_store.get_file(&settings.origin_descr, path)?; Ok(f) } diff --git a/src/domain/store.rs b/src/domain/store.rs index fbd1c01..1d6a191 100644 --- a/src/domain/store.rs +++ b/src/domain/store.rs @@ -3,6 +3,13 @@ use std::{collections, fs, io, path, str::FromStr}; use crate::domain; use crate::error::unexpected::{self, Intoable, Mappable}; +#[derive(Debug, PartialEq)] +pub struct GetResult { + pub settings: domain::Settings, + pub builtin: bool, + pub public: bool, +} + #[derive(thiserror::Error, Debug)] pub enum GetError { #[error("not found")] @@ -23,7 +30,7 @@ pub enum SetError { #[mockall::automock] pub trait Store { - fn get(&self, domain: &domain::Name) -> Result; + fn get(&self, domain: &domain::Name) -> Result; fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError>; fn all_domains(&self) -> Result, unexpected::Error>; } @@ -50,7 +57,7 @@ impl FSStore { } impl Store for FSStore { - fn get(&self, domain: &domain::Name) -> Result { + fn get(&self, domain: &domain::Name) -> Result { let path = self.settings_file_path(domain); let settings_file = fs::File::open(path.as_path()).map_err(|e| match e.kind() { io::ErrorKind::NotFound => GetError::NotFound, @@ -61,7 +68,12 @@ impl Store for FSStore { let settings = serde_json::from_reader(settings_file) .map_unexpected_while(|| format!("json parsing {}", path.display()))?; - Ok(settings) + + Ok(GetResult { + settings, + public: true, + builtin: false, + }) } fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError> { @@ -115,9 +127,13 @@ impl StoreWithBuiltin { } impl Store for StoreWithBuiltin { - fn get(&self, domain: &domain::Name) -> Result { + fn get(&self, domain: &domain::Name) -> Result { if let Some(domain) = self.domains.get(domain) { - return Ok(domain.settings.clone()); + return Ok(GetResult { + settings: domain.settings.clone(), + public: domain.public, + builtin: true, + }); } self.inner.get(domain) } @@ -165,26 +181,39 @@ mod tests { url: "bar".to_string(), branch_name: "baz".to_string(), }, + serve_protocols: vec![domain::SettingsServeProtocol::Http], }; assert!(matches!( store.get(&domain), - Err::(GetError::NotFound) + Err::(GetError::NotFound) )); store.set(&domain, &settings).expect("set"); - assert_eq!(settings, store.get(&domain).expect("settings retrieved")); + assert_eq!( + GetResult { + settings, + public: true, + builtin: false, + }, + store.get(&domain).expect("settings retrieved") + ); let new_settings = domain::Settings { origin_descr: Descr::Git { url: "BAR".to_string(), branch_name: "BAZ".to_string(), }, + serve_protocols: vec![], }; store.set(&domain, &new_settings).expect("set"); assert_eq!( - new_settings, + GetResult { + settings: new_settings, + public: true, + builtin: false, + }, store.get(&domain).expect("settings retrieved") ); } diff --git a/src/service/http.rs b/src/service/http.rs index f30ddc8..147325f 100644 --- a/src/service/http.rs +++ b/src/service/http.rs @@ -166,7 +166,7 @@ impl<'svc> Service { req_is_https: bool, ) -> Response { let settings = match self.domain_manager.get_settings(&domain) { - Ok(settings) => settings, + Ok(domain::manager::GetSettingsResult { settings, .. }) => settings, Err(domain::manager::GetSettingsError::NotFound) => { return self.render_error_page(404, "Domain not found"); } @@ -266,7 +266,24 @@ impl<'svc> Service { } let settings = match self.domain_manager.get_settings(&args.domain) { - Ok(settings) => Some(settings), + Ok(domain::manager::GetSettingsResult { + settings, + public, + builtin, + }) => match (public, builtin) { + (false, _) => None, + (true, false) => Some(settings), + (true, true) => { + return self.render_error_page( + 403, + format!( + "Settings for domain {} cannot be viewed or modified", + args.domain + ) + .as_str(), + ) + } + }, Err(domain::manager::GetSettingsError::NotFound) => None, Err(domain::manager::GetSettingsError::Unexpected(e)) => { return self.internal_error(