From 9065b8577942e3c732e85b1782785cbe87173442 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 09 Oct 2021 03:54:19 +0100 Subject: [PATCH] Crate name validation on publish --- chartered-web/src/endpoints/cargo_api/publish.rs | 26 ++++++++++++++++++++++++++ chartered-web/src/endpoints/web_api/auth/password.rs | 5 +++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/chartered-web/src/endpoints/cargo_api/publish.rs b/chartered-web/src/endpoints/cargo_api/publish.rs index 83b4ebd..07f2a81 100644 --- a/chartered-web/src/endpoints/cargo_api/publish.rs +++ a/chartered-web/src/endpoints/cargo_api/publish.rs @@ -16,6 +16,8 @@ JsonParse(#[from] serde_json::Error), #[error("Invalid body")] MetadataParse, + #[error("expected a valid crate name to start with a letter, contain only letters, numbers, hyphens, or underscores and have at most 64 characters ")] + InvalidCrateName, } impl Error { @@ -24,7 +26,9 @@ match self { Self::Database(e) => e.status_code(), - Self::JsonParse(_) | Self::MetadataParse => StatusCode::BAD_REQUEST, + Self::JsonParse(_) | Self::MetadataParse | Self::InvalidCrateName => { + StatusCode::BAD_REQUEST + } } } } @@ -43,6 +47,22 @@ other: Vec, } +fn validate_crate_name(name: &str) -> bool { + const MAX_NAME_LENGTH: usize = 64; + + let starts_with_alphabetic = name + .chars() + .next() + .map(|c| c.is_ascii_alphabetic()) + .unwrap_or_default(); + let is_alphanumeric = name + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_'); + let is_under_max_length = name.len() < MAX_NAME_LENGTH; + + starts_with_alphabetic && is_alphanumeric && is_under_max_length +} + pub async fn handle( extract::Path((_session_key, organisation)): extract::Path<(String, String)>, extract::Extension(db): extract::Extension, @@ -52,6 +72,10 @@ let (_, (metadata_bytes, crate_bytes)) = parse(body.as_ref()).map_err(|_| Error::MetadataParse)?; let metadata: Metadata = serde_json::from_slice(metadata_bytes)?; + + if !validate_crate_name(&metadata.inner.name) { + return Err(Error::InvalidCrateName); + } let crate_with_permissions = Crate::find_by_name( db.clone(), diff --git a/chartered-web/src/endpoints/web_api/auth/password.rs b/chartered-web/src/endpoints/web_api/auth/password.rs index 5e2b720..c523154 100644 --- a/chartered-web/src/endpoints/web_api/auth/password.rs +++ a/chartered-web/src/endpoints/web_api/auth/password.rs @@ -30,6 +30,11 @@ user_agent: Option>, addr: extract::ConnectInfo, ) -> Result, Error> { + // we use `:` as a splitter for openid logins so it isn't legal during password login + if req.username.contains(':') { + return Err(Error::UnknownUser); + } + // TODO: passwords let user = User::find_by_username(db.clone(), req.username) .await? -- rgit 0.1.3