Browse Source

Format mint URL (lowercase hostname) (#311)

callebtc 7 months ago
parent
commit
125001211c
2 changed files with 67 additions and 21 deletions
  1. 5 4
      crates/cdk/src/mint/mod.rs
  2. 62 17
      crates/cdk/src/mint_url.rs

+ 5 - 4
crates/cdk/src/mint/mod.rs

@@ -154,10 +154,8 @@ impl Mint {
             }
         }
 
-        let mint_url = MintUrl::from(mint_url);
-
         Ok(Self {
-            mint_url,
+            mint_url: MintUrl::from(mint_url),
             keysets: Arc::new(RwLock::new(active_keysets)),
             secp_ctx,
             xpriv,
@@ -1569,7 +1567,10 @@ mod tests {
 
     #[tokio::test]
     async fn mint_mod_rotate_keyset() -> Result<(), Error> {
-        let config: MintConfig = Default::default();
+        let config = MintConfig::<'_> {
+            mint_url: "http://example.com",
+            ..Default::default()
+        };
         let mint = create_mint(config).await?;
 
         let keysets = mint.keysets().await.unwrap();

+ 62 - 17
crates/cdk/src/mint_url.rs

@@ -16,6 +16,9 @@ pub enum Error {
     /// Url error
     #[error(transparent)]
     Url(#[from] ParseError),
+    /// Invalid URL structure
+    #[error("Invalid URL")]
+    InvalidUrl,
 }
 
 /// MintUrl Url
@@ -23,13 +26,38 @@ pub enum Error {
 pub struct MintUrl(String);
 
 impl MintUrl {
-    /// New mint url
-    pub fn new<S>(url: S) -> Self
-    where
-        S: Into<String>,
-    {
-        let url: String = url.into();
-        Self(url.trim_end_matches('/').to_string())
+    fn format_url(url: &str) -> Result<String, Error> {
+        if url.is_empty() {
+            return Err(Error::InvalidUrl);
+        }
+        let url = url.trim_end_matches('/');
+        // https://URL.com/path/TO/resource -> https://url.com/path/TO/resource
+        let protocol = url
+            .split("://")
+            .nth(0)
+            .ok_or(Error::InvalidUrl)?
+            .to_lowercase();
+        let host = url
+            .split("://")
+            .nth(1)
+            .ok_or(Error::InvalidUrl)?
+            .split('/')
+            .nth(0)
+            .ok_or(Error::InvalidUrl)?
+            .to_lowercase();
+        let path = url
+            .split("://")
+            .nth(1)
+            .ok_or(Error::InvalidUrl)?
+            .split('/')
+            .skip(1)
+            .collect::<Vec<&str>>()
+            .join("/");
+        let mut formatted_url = format!("{}://{}", protocol, host);
+        if !path.is_empty() {
+            formatted_url.push_str(&format!("/{}", path));
+        }
+        Ok(formatted_url)
     }
 
     /// Empty mint url
@@ -42,11 +70,6 @@ impl MintUrl {
         let url: Url = self.try_into()?;
         Ok(url.join(path)?)
     }
-
-    /// Remove trailing slashes from url
-    pub fn trim_trailing_slashes(&self) -> Self {
-        Self(self.to_string().trim_end_matches('/').to_string())
-    }
 }
 
 impl<'de> Deserialize<'de> for MintUrl {
@@ -65,7 +88,8 @@ where
 {
     fn from(url: S) -> Self {
         let url: String = url.into();
-        Self(url.trim_end_matches('/').to_string())
+        let formatted_url = Self::format_url(&url).unwrap();
+        Self(formatted_url)
     }
 }
 
@@ -73,7 +97,11 @@ impl FromStr for MintUrl {
     type Err = Error;
 
     fn from_str(url: &str) -> Result<Self, Self::Err> {
-        Ok(Self::from(url))
+        let formatted_url = Self::format_url(url);
+        match formatted_url {
+            Ok(url) => Ok(Self(url)),
+            Err(_) => Err(Error::InvalidUrl),
+        }
     }
 }
 
@@ -111,12 +139,29 @@ mod tests {
         let formatted_url = "http://url-to-check.com";
 
         let very_trimmed_url = MintUrl::from_str(very_unformatted_url).unwrap();
-        assert_eq!("http://url-to-check.com", very_trimmed_url.to_string());
+        assert_eq!(formatted_url, very_trimmed_url.to_string());
 
         let trimmed_url = MintUrl::from_str(unformatted_url).unwrap();
-        assert_eq!("http://url-to-check.com", trimmed_url.to_string());
+        assert_eq!(formatted_url, trimmed_url.to_string());
 
         let unchanged_url = MintUrl::from_str(formatted_url).unwrap();
-        assert_eq!("http://url-to-check.com", unchanged_url.to_string());
+        assert_eq!(formatted_url, unchanged_url.to_string());
+    }
+    #[test]
+    fn test_case_insensitive() {
+        let wrong_cased_url = "http://URL-to-check.com";
+        let correct_cased_url = "http://url-to-check.com";
+
+        let cased_url_formatted = MintUrl::from_str(wrong_cased_url).unwrap();
+        assert_eq!(correct_cased_url, cased_url_formatted.to_string());
+
+        let wrong_cased_url_with_path = "http://URL-to-check.com/PATH/to/check";
+        let correct_cased_url_with_path = "http://url-to-check.com/PATH/to/check";
+
+        let cased_url_with_path_formatted = MintUrl::from_str(wrong_cased_url_with_path).unwrap();
+        assert_eq!(
+            correct_cased_url_with_path,
+            cased_url_with_path_formatted.to_string()
+        );
     }
 }