From b475ff40e5019a8af92b2d161c01f1bcab2b823d Mon Sep 17 00:00:00 2001 From: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:18:40 +0100 Subject: [PATCH] feat: support specifying allowed external registries in config --- CHANGELOG.md | 1 + registry/src/endpoints/publish_version.rs | 24 ++------------ src/source/pesde/mod.rs | 38 ++++++++++++++++++++++- src/util.rs | 11 ++++++- 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30645fb..23f08f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make `includes` use glob patterns by @daimond113 - Use symlinks for workspace dependencies to not require reinstalling by @daimond113 - Add `auth token` command to print the auth token for the index by @daimond113 +- Support specifying which external registries are allowed on registries by @daimond113 ### Fixed - Install dependencies of packages in `x` command diff --git a/registry/src/endpoints/publish_version.rs b/registry/src/endpoints/publish_version.rs index 0b51c79..cae611b 100644 --- a/registry/src/endpoints/publish_version.rs +++ b/registry/src/endpoints/publish_version.rs @@ -66,25 +66,6 @@ struct DocEntryInfo { collapsed: bool, } -fn compare_repo_urls(this: &gix::Url, external: &gix::Url) -> bool { - let this = this.to_bstring().to_string().to_lowercase(); - let external = external.to_bstring().to_string().to_lowercase(); - - let this = if this.ends_with(".git") { - &this[..this.len() - 4] - } else { - &this - }; - - let external = if external.ends_with(".git") { - &external[..external.len() - 4] - } else { - &external - }; - - this == external -} - pub async fn publish_package( app_state: web::Data, bytes: Bytes, @@ -321,8 +302,9 @@ pub async fn publish_package( .index .as_deref() .filter(|index| match gix::Url::try_from(*index) { - Ok(_) if config.other_registries_allowed => true, - Ok(url) => compare_repo_urls(source.repo_url(), &url), + Ok(url) => config + .other_registries_allowed + .is_allowed(source.repo_url().clone(), url), Err(_) => false, }) .is_none() diff --git a/src/source/pesde/mod.rs b/src/source/pesde/mod.rs index e8c4667..919b302 100644 --- a/src/source/pesde/mod.rs +++ b/src/source/pesde/mod.rs @@ -265,6 +265,42 @@ fn default_archive_size() -> usize { 4 * 1024 * 1024 } +/// The allowed registries for a package +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum AllowedRegistries { + /// All registries are allowed + All(bool), + /// Only specific registries are allowed + #[serde(deserialize_with = "crate::util::deserialize_gix_url_hashset")] + Specific(HashSet), +} + +impl Default for AllowedRegistries { + fn default() -> Self { + Self::All(false) + } +} + +impl AllowedRegistries { + /// Whether the given URL is allowed + pub fn is_allowed(&self, mut this: Url, mut external: Url) -> bool { + // strip .git suffix to allow for more flexible matching + this.path = this.path.strip_suffix(b".git").unwrap_or(&this.path).into(); + external.path = external + .path + .strip_suffix(b".git") + .unwrap_or(&external.path) + .into(); + + this == external + || (match self { + Self::All(all) => *all, + Self::Specific(urls) => urls.contains(&this) || urls.contains(&external), + }) + } +} + /// The configuration for the pesde index #[derive(Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] @@ -278,7 +314,7 @@ pub struct IndexConfig { pub git_allowed: bool, /// Whether other registries are allowed as a source for publishing packages #[serde(default)] - pub other_registries_allowed: bool, + pub other_registries_allowed: AllowedRegistries, /// Whether Wally is allowed as a source for publishing packages #[serde(default)] pub wally_allowed: bool, diff --git a/src/util.rs b/src/util.rs index b52fe1d..3baca73 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,7 +2,7 @@ use crate::AuthConfig; use gix::bstr::BStr; use serde::{Deserialize, Deserializer, Serializer}; use sha2::{Digest, Sha256}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; pub fn authenticate_conn( conn: &mut gix::remote::Connection< @@ -59,6 +59,15 @@ pub fn deserialize_gix_url_vec<'de, D: Deserializer<'de>>( .collect() } +pub fn deserialize_gix_url_hashset<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + HashSet::::deserialize(deserializer)? + .into_iter() + .map(|v| gix::Url::from_bytes(BStr::new(&v)).map_err(serde::de::Error::custom)) + .collect() +} + pub fn deserialize_git_like_url<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result {