From 0b8553d0c21b6e970c267231d3f23df01067d4f7 Mon Sep 17 00:00:00 2001 From: silverpill Date: Thu, 9 Feb 2023 15:37:50 +0000 Subject: [PATCH] Allow instance_uri configuration value to contain URI scheme --- CHANGELOG.md | 4 +++ config.yaml.example | 3 +- contrib/mitra_config.yaml | 3 +- src/config/main.rs | 13 +++----- src/utils/urls.rs | 64 ++++++++++++++++++++++++++++++++++----- 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e36ef94..d0e8d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Changed + +- Allow `instance_uri` configuration value to contain URI scheme. + ## [1.13.1] - 2023-02-09 ### Fixed diff --git a/config.yaml.example b/config.yaml.example index 9191687..ec95f0a 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -5,7 +5,8 @@ web_client_dir: null http_host: '127.0.0.1' http_port: 8380 -instance_uri: 127.0.0.1:8380 +instance_uri: http://127.0.0.1:8380 + instance_title: Mitra instance_short_description: My instance instance_description: My instance diff --git a/contrib/mitra_config.yaml b/contrib/mitra_config.yaml index d23c97b..8f4db3c 100644 --- a/contrib/mitra_config.yaml +++ b/contrib/mitra_config.yaml @@ -12,7 +12,8 @@ http_port: 8383 #log_level: info # Domain name -instance_uri: example.tld +instance_uri: https://example.tld + instance_title: example instance_short_description: my instance # Long description can contain markdown syntax diff --git a/src/config/main.rs b/src/config/main.rs index 09f2fdc..df76a33 100644 --- a/src/config/main.rs +++ b/src/config/main.rs @@ -9,7 +9,7 @@ use serde::{ }; use url::Url; -use crate::utils::urls::guess_protocol; +use crate::utils::urls::normalize_url; use super::blockchain::BlockchainConfig; use super::environment::Environment; @@ -78,7 +78,9 @@ pub struct Config { pub log_level: LogLevel, // Domain name or : + // URI scheme is optional instance_uri: String, + pub instance_title: String, pub instance_short_description: String, pub instance_description: String, @@ -121,14 +123,7 @@ pub struct Config { impl Config { pub(super) fn try_instance_url(&self) -> Result { - let scheme = match self.environment { - Environment::Development => "http", - Environment::Production => guess_protocol(&self.instance_uri), - }; - let url_str = format!("{}://{}", scheme, self.instance_uri); - let url = Url::parse(&url_str)?; - url.host().ok_or(url::ParseError::EmptyHost)?; // validates URL - Ok(url) + normalize_url(&self.instance_uri) } pub fn instance(&self) -> Instance { diff --git a/src/utils/urls.rs b/src/utils/urls.rs index 5b1cf5d..2b7559a 100644 --- a/src/utils/urls.rs +++ b/src/utils/urls.rs @@ -1,4 +1,4 @@ -use std::net::Ipv6Addr; +use std::net::{Ipv4Addr, Ipv6Addr}; use url::{Host, ParseError, Url}; pub fn get_hostname(url: &str) -> Result { @@ -14,13 +14,13 @@ pub fn get_hostname(url: &str) -> Result { } pub fn guess_protocol(hostname: &str) -> &'static str { + let maybe_ipv4_address = hostname.parse::(); + if let Ok(_ipv4_address) = maybe_ipv4_address { + return "http"; + }; let maybe_ipv6_address = hostname.parse::(); - if let Ok(ipv6_address) = maybe_ipv6_address { - let prefix = ipv6_address.segments()[0]; - if (0x0200..=0x03ff).contains(&prefix) { - // Yggdrasil - return "http"; - }; + if let Ok(_ipv6_address) = maybe_ipv6_address { + return "http"; }; if hostname.ends_with(".onion") || hostname.ends_with(".i2p") { // Tor / I2P @@ -31,9 +31,36 @@ pub fn guess_protocol(hostname: &str) -> &'static str { } } +pub fn normalize_url(url: &str) -> Result { + let normalized_url = if + url.starts_with("http://") || + url.starts_with("https://") + { + url.to_string() + } else { + // Add scheme + // Doesn't work for IPv6 + let hostname = if let Some((hostname, _port)) = url.split_once(':') { + hostname + } else { + url + }; + let url_scheme = guess_protocol(hostname); + format!( + "{}://{}", + url_scheme, + url, + ) + }; + let url = Url::parse(&normalized_url)?; + url.host().ok_or(ParseError::EmptyHost)?; // validates URL + Ok(url) +} + #[cfg(test)] mod tests { use super::*; + #[test] fn test_get_hostname() { let url = "https://example.org/objects/1"; @@ -41,6 +68,13 @@ mod tests { assert_eq!(hostname, "example.org"); } + #[test] + fn test_get_hostname_if_port_number() { + let url = "http://127.0.0.1:8380/objects/1"; + let hostname = get_hostname(url).unwrap(); + assert_eq!(hostname, "127.0.0.1"); + } + #[test] fn test_get_hostname_tor() { let url = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/objects/1"; @@ -76,9 +110,25 @@ mod tests { guess_protocol("zzz.i2p"), "http", ); + // Yggdrasil assert_eq!( guess_protocol("319:3cf0:dd1d:47b9:20c:29ff:fe2c:39be"), "http", ); + // localhost + assert_eq!( + guess_protocol("127.0.0.1"), + "http", + ); + } + + #[test] + fn test_normalize_url() { + let result = normalize_url("https://test.net").unwrap(); + assert_eq!(result.to_string(), "https://test.net/"); + let result = normalize_url("example.com").unwrap(); + assert_eq!(result.to_string(), "https://example.com/"); + let result = normalize_url("127.0.0.1:8380").unwrap(); + assert_eq!(result.to_string(), "http://127.0.0.1:8380/"); } }