diff options
Diffstat (limited to 'src/api')
-rw-r--r-- | src/api/Cargo.toml | 6 | ||||
-rw-r--r-- | src/api/admin/api_server.rs | 70 | ||||
-rw-r--r-- | src/api/admin/router.rs | 6 | ||||
-rw-r--r-- | src/api/s3/post_object.rs | 12 |
4 files changed, 63 insertions, 31 deletions
diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml index 747f70ab..a9279c37 100644 --- a/src/api/Cargo.toml +++ b/src/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "garage_api" -version = "0.8.2" +version = "0.8.3" authors = ["Alex Auvolat <alex@adnab.me>"] edition = "2018" license = "AGPL-3.0" @@ -28,7 +28,7 @@ crypto-common = "0.1" err-derive = "0.3" hex = "0.4" hmac = "0.12" -idna = "0.3" +idna = "0.4" tracing = "0.1" md-5 = "0.10" nom = "7.1" @@ -47,7 +47,7 @@ http-range = "0.1" hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] } multer = "2.0" percent-encoding = "2.1.0" -roxmltree = "0.14" +roxmltree = "0.18" serde = { version = "1.0", features = ["derive"] } serde_bytes = "0.11" serde_json = "1.0" diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index 6819e28e..cc04d81f 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -26,6 +26,7 @@ use crate::admin::cluster::*; use crate::admin::error::*; use crate::admin::key::*; use crate::admin::router::{Authorization, Endpoint}; +use crate::helpers::host_to_bucket; pub struct AdminApiServer { garage: Arc<Garage>, @@ -78,10 +79,7 @@ impl AdminApiServer { .body(Body::empty())?) } - async fn handle_check_website_enabled( - &self, - req: Request<Body>, - ) -> Result<Response<Body>, Error> { + async fn handle_check_domain(&self, req: Request<Body>) -> Result<Response<Body>, Error> { let query_params: HashMap<String, String> = req .uri() .query() @@ -102,12 +100,56 @@ impl AdminApiServer { .get("domain") .ok_or_internal_error("Could not parse domain query string")?; - let bucket_id = self + if self.check_domain(domain).await? { + Ok(Response::builder() + .status(StatusCode::OK) + .body(Body::from(format!( + "Domain '{domain}' is managed by Garage" + )))?) + } else { + Err(Error::bad_request(format!( + "Domain '{domain}' is not managed by Garage" + ))) + } + } + + async fn check_domain(&self, domain: &str) -> Result<bool, Error> { + // Resolve bucket from domain name, inferring if the website must be activated for the + // domain to be valid. + let (bucket_name, must_check_website) = if let Some(bname) = self + .garage + .config + .s3_api + .root_domain + .as_ref() + .and_then(|rd| host_to_bucket(domain, rd)) + { + (bname.to_string(), false) + } else if let Some(bname) = self + .garage + .config + .s3_web + .as_ref() + .and_then(|sw| host_to_bucket(domain, sw.root_domain.as_str())) + { + (bname.to_string(), true) + } else { + (domain.to_string(), true) + }; + + let bucket_id = match self .garage .bucket_helper() - .resolve_global_bucket_name(domain) + .resolve_global_bucket_name(&bucket_name) .await? - .ok_or(HelperError::NoSuchBucket(domain.to_string()))?; + { + Some(bucket_id) => bucket_id, + None => return Ok(false), + }; + + if !must_check_website { + return Ok(true); + } let bucket = self .garage @@ -119,16 +161,8 @@ impl AdminApiServer { let bucket_website_config = bucket_state.website_config.get(); match bucket_website_config { - Some(_v) => { - Ok(Response::builder() - .status(StatusCode::OK) - .body(Body::from(format!( - "Bucket '{domain}' is authorized for website hosting" - )))?) - } - None => Err(Error::bad_request(format!( - "Bucket '{domain}' is not authorized for website hosting" - ))), + Some(_v) => Ok(true), + None => Ok(false), } } @@ -229,7 +263,7 @@ impl ApiHandler for AdminApiServer { match endpoint { Endpoint::Options => self.handle_options(&req), - Endpoint::CheckWebsiteEnabled => self.handle_check_website_enabled(req).await, + Endpoint::CheckDomain => self.handle_check_domain(req).await, Endpoint::Health => self.handle_health(), Endpoint::Metrics => self.handle_metrics(), Endpoint::GetClusterStatus => handle_get_cluster_status(&self.garage).await, diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs index d54dabe8..254aff12 100644 --- a/src/api/admin/router.rs +++ b/src/api/admin/router.rs @@ -17,7 +17,7 @@ router_match! {@func #[derive(Debug, Clone, PartialEq, Eq)] pub enum Endpoint { Options, - CheckWebsiteEnabled, + CheckDomain, Health, Metrics, GetClusterStatus, @@ -93,7 +93,7 @@ impl Endpoint { let res = router_match!(@gen_path_parser (req.method(), path, query) [ OPTIONS _ => Options, - GET "/check" => CheckWebsiteEnabled, + GET "/check" => CheckDomain, GET "/health" => Health, GET "/metrics" => Metrics, GET "/v1/status" => GetClusterStatus, @@ -139,7 +139,7 @@ impl Endpoint { pub fn authorization_type(&self) -> Authorization { match self { Self::Health => Authorization::None, - Self::CheckWebsiteEnabled => Authorization::None, + Self::CheckDomain => Authorization::None, Self::Metrics => Authorization::MetricsToken, _ => Authorization::AdminToken, } diff --git a/src/api/s3/post_object.rs b/src/api/s3/post_object.rs index f2098ab0..542b7a81 100644 --- a/src/api/s3/post_object.rs +++ b/src/api/s3/post_object.rs @@ -30,7 +30,7 @@ pub async fn handle_post_object( .get(header::CONTENT_TYPE) .and_then(|ct| ct.to_str().ok()) .and_then(|ct| multer::parse_boundary(ct).ok()) - .ok_or_bad_request("Counld not get multipart boundary")?; + .ok_or_bad_request("Could not get multipart boundary")?; // 16k seems plenty for a header. 5G is the max size of a single part, so it seems reasonable // for a PostObject @@ -64,15 +64,13 @@ pub async fn handle_post_object( "tag" => (/* tag need to be reencoded, but we don't support them yet anyway */), "acl" => { if params.insert("x-amz-acl", content).is_some() { - return Err(Error::bad_request( - "Field 'acl' provided more than one time", - )); + return Err(Error::bad_request("Field 'acl' provided more than once")); } } _ => { if params.insert(&name, content).is_some() { return Err(Error::bad_request(format!( - "Field '{}' provided more than one time", + "Field '{}' provided more than once", name ))); } @@ -149,7 +147,7 @@ pub async fn handle_post_object( .ok_or_bad_request("Invalid expiration date")? .into(); if Utc::now() - expiration > Duration::zero() { - return Err(Error::bad_request("Expiration date is in the paste")); + return Err(Error::bad_request("Expiration date is in the past")); } let mut conditions = decoded_policy.into_conditions()?; @@ -330,7 +328,7 @@ impl Policy { if map.len() != 1 { return Err(Error::bad_request("Invalid policy item")); } - let (mut k, v) = map.into_iter().next().expect("size was verified"); + let (mut k, v) = map.into_iter().next().expect("Size could not be verified"); k.make_ascii_lowercase(); params.entry(k).or_default().push(Operation::Equal(v)); } |