Prevent users from seeing proxy config in web interface
This commit is contained in:
parent
87c779ebb6
commit
ccd2285b11
@ -6,6 +6,8 @@ use crate::util;
|
|||||||
use std::sync;
|
use std::sync;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
|
pub type GetSettingsResult = domain::store::GetResult;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum GetSettingsError {
|
pub enum GetSettingsError {
|
||||||
#[error("not found")]
|
#[error("not found")]
|
||||||
@ -140,7 +142,7 @@ pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyEr
|
|||||||
|
|
||||||
//#[mockall::automock]
|
//#[mockall::automock]
|
||||||
pub trait Manager: Sync + Send + rustls::server::ResolvesServerCert {
|
pub trait Manager: Sync + Send + rustls::server::ResolvesServerCert {
|
||||||
fn get_settings(&self, domain: &domain::Name) -> Result<domain::Settings, GetSettingsError>;
|
fn get_settings(&self, domain: &domain::Name) -> Result<GetSettingsResult, GetSettingsError>;
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
@ -235,7 +237,7 @@ impl ManagerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Manager for ManagerImpl {
|
impl Manager for ManagerImpl {
|
||||||
fn get_settings(&self, domain: &domain::Name) -> Result<domain::Settings, GetSettingsError> {
|
fn get_settings(&self, domain: &domain::Name) -> Result<GetSettingsResult, GetSettingsError> {
|
||||||
Ok(self.domain_store.get(domain)?)
|
Ok(self.domain_store.get(domain)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,13 +246,13 @@ impl Manager for ManagerImpl {
|
|||||||
domain: &domain::Name,
|
domain: &domain::Name,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<util::BoxByteStream, GetFileError> {
|
) -> Result<util::BoxByteStream, GetFileError> {
|
||||||
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());
|
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)
|
Ok(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,13 @@ use std::{collections, fs, io, path, str::FromStr};
|
|||||||
use crate::domain;
|
use crate::domain;
|
||||||
use crate::error::unexpected::{self, Intoable, Mappable};
|
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)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum GetError {
|
pub enum GetError {
|
||||||
#[error("not found")]
|
#[error("not found")]
|
||||||
@ -23,7 +30,7 @@ pub enum SetError {
|
|||||||
|
|
||||||
#[mockall::automock]
|
#[mockall::automock]
|
||||||
pub trait Store {
|
pub trait Store {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<domain::Settings, GetError>;
|
fn get(&self, domain: &domain::Name) -> Result<GetResult, GetError>;
|
||||||
fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError>;
|
fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError>;
|
||||||
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>;
|
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>;
|
||||||
}
|
}
|
||||||
@ -50,7 +57,7 @@ impl FSStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Store for FSStore {
|
impl Store for FSStore {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<domain::Settings, GetError> {
|
fn get(&self, domain: &domain::Name) -> Result<GetResult, GetError> {
|
||||||
let path = self.settings_file_path(domain);
|
let path = self.settings_file_path(domain);
|
||||||
let settings_file = fs::File::open(path.as_path()).map_err(|e| match e.kind() {
|
let settings_file = fs::File::open(path.as_path()).map_err(|e| match e.kind() {
|
||||||
io::ErrorKind::NotFound => GetError::NotFound,
|
io::ErrorKind::NotFound => GetError::NotFound,
|
||||||
@ -61,7 +68,12 @@ impl Store for FSStore {
|
|||||||
|
|
||||||
let settings = serde_json::from_reader(settings_file)
|
let settings = serde_json::from_reader(settings_file)
|
||||||
.map_unexpected_while(|| format!("json parsing {}", path.display()))?;
|
.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> {
|
fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError> {
|
||||||
@ -115,9 +127,13 @@ impl<S: Store> StoreWithBuiltin<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Store> Store for StoreWithBuiltin<S> {
|
impl<S: Store> Store for StoreWithBuiltin<S> {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<domain::Settings, GetError> {
|
fn get(&self, domain: &domain::Name) -> Result<GetResult, GetError> {
|
||||||
if let Some(domain) = self.domains.get(domain) {
|
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)
|
self.inner.get(domain)
|
||||||
}
|
}
|
||||||
@ -165,26 +181,39 @@ mod tests {
|
|||||||
url: "bar".to_string(),
|
url: "bar".to_string(),
|
||||||
branch_name: "baz".to_string(),
|
branch_name: "baz".to_string(),
|
||||||
},
|
},
|
||||||
|
serve_protocols: vec![domain::SettingsServeProtocol::Http],
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
store.get(&domain),
|
store.get(&domain),
|
||||||
Err::<domain::Settings, GetError>(GetError::NotFound)
|
Err::<GetResult, GetError>(GetError::NotFound)
|
||||||
));
|
));
|
||||||
|
|
||||||
store.set(&domain, &settings).expect("set");
|
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 {
|
let new_settings = domain::Settings {
|
||||||
origin_descr: Descr::Git {
|
origin_descr: Descr::Git {
|
||||||
url: "BAR".to_string(),
|
url: "BAR".to_string(),
|
||||||
branch_name: "BAZ".to_string(),
|
branch_name: "BAZ".to_string(),
|
||||||
},
|
},
|
||||||
|
serve_protocols: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
store.set(&domain, &new_settings).expect("set");
|
store.set(&domain, &new_settings).expect("set");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
new_settings,
|
GetResult {
|
||||||
|
settings: new_settings,
|
||||||
|
public: true,
|
||||||
|
builtin: false,
|
||||||
|
},
|
||||||
store.get(&domain).expect("settings retrieved")
|
store.get(&domain).expect("settings retrieved")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ impl<'svc> Service {
|
|||||||
req_is_https: bool,
|
req_is_https: bool,
|
||||||
) -> Response<Body> {
|
) -> Response<Body> {
|
||||||
let settings = match self.domain_manager.get_settings(&domain) {
|
let settings = match self.domain_manager.get_settings(&domain) {
|
||||||
Ok(settings) => settings,
|
Ok(domain::manager::GetSettingsResult { settings, .. }) => settings,
|
||||||
Err(domain::manager::GetSettingsError::NotFound) => {
|
Err(domain::manager::GetSettingsError::NotFound) => {
|
||||||
return self.render_error_page(404, "Domain not found");
|
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) {
|
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::NotFound) => None,
|
||||||
Err(domain::manager::GetSettingsError::Unexpected(e)) => {
|
Err(domain::manager::GetSettingsError::Unexpected(e)) => {
|
||||||
return self.internal_error(
|
return self.internal_error(
|
||||||
|
Loading…
Reference in New Issue
Block a user