Skip to content

Commit 876d323

Browse files
authored
sdk: Check if server name points to homeserver during discovery (#3218)
The small first commit reintroduces `sanitize_server_name` in the public API. In Fractal, we use it to validate the string in the input before allowing the user to trigger the discovery. The main commit changes a bit the discovery process: before, server names like `example.org` would only be checked for the presence of a well-known, and only URLs like `https://example.org` would be checked as a homeserver. Now, providing `example.org` will also check if `https://example.org` is the URL of a homeserver. Sadly I don't think it's possible to add tests for it as it would require to have a homeserver accessible via HTTPS. --- * sdk: Restore sanitize_server_name in the public API Signed-off-by: Kévin Commaille <[email protected]> * sdk: Check if a provided server name points to a homeserver during discovery Before, only URLs like `https://example.org` would be checked as a homeserver. Providing `example.org` will check if `https://example.org` is the URL of a homeserver. Signed-off-by: Kévin Commaille <[email protected]> * Refactor to avoid duplication Signed-off-by: Kévin Commaille <[email protected]> --------- Signed-off-by: Kévin Commaille <[email protected]>
1 parent cabab28 commit 876d323

File tree

3 files changed

+55
-45
lines changed

3 files changed

+55
-45
lines changed

crates/matrix-sdk/src/client/builder.rs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -418,48 +418,8 @@ impl ClientBuilder {
418418
}
419419

420420
HomeserverConfig::ServerNameOrUrl(server_name_or_url) => {
421-
// Store the result to return at the end. If this doesn't get modified, then the
422-
// supplied name is neither a server name, nor a valid URL.
423-
let mut homeserver_details: Option<(
424-
String,
425-
Option<discover_homeserver::Response>,
426-
)> = None;
427-
let mut discovery_error: Option<ClientBuildError> = None;
428-
429-
// Attempt discovery as a server name first.
430-
let sanitize_result = sanitize_server_name(&server_name_or_url);
431-
if let Ok(server_name) = sanitize_result.as_ref() {
432-
let protocol = if server_name_or_url.starts_with("http://") {
433-
UrlScheme::Http
434-
} else {
435-
UrlScheme::Https
436-
};
437-
438-
match discover_homeserver(server_name.clone(), protocol, &http_client).await {
439-
Ok(well_known) => {
440-
homeserver_details =
441-
Some((well_known.homeserver.base_url.clone(), Some(well_known)));
442-
}
443-
Err(e) => {
444-
debug!(error = %e, "Well-known discovery failed.");
445-
discovery_error = Some(e);
446-
}
447-
}
448-
}
449-
450-
// When discovery fails, or the input isn't a valid server name, fallback to
451-
// trying a homeserver URL if supplied.
452-
if homeserver_details.is_none() {
453-
if let Ok(homeserver_url) = Url::parse(&server_name_or_url) {
454-
// Make sure the URL is definitely for a homeserver.
455-
if check_is_homeserver(&homeserver_url, &http_client).await {
456-
homeserver_details = Some((homeserver_url.to_string(), None));
457-
}
458-
}
459-
}
460-
461-
homeserver_details
462-
.ok_or(discovery_error.unwrap_or(ClientBuildError::InvalidServerName))?
421+
discover_homeserver_from_server_name_or_url(server_name_or_url, &http_client)
422+
.await?
463423
}
464424
};
465425

@@ -522,10 +482,58 @@ impl ClientBuilder {
522482
}
523483
}
524484

485+
/// Discovers a homeserver from a server name or a URL.
486+
///
487+
/// Tries well-known discovery and checking if the URL points to a homeserver.
488+
async fn discover_homeserver_from_server_name_or_url(
489+
mut server_name_or_url: String,
490+
http_client: &HttpClient,
491+
) -> Result<(String, Option<discover_homeserver::Response>), ClientBuildError> {
492+
let mut discovery_error: Option<ClientBuildError> = None;
493+
494+
// Attempt discovery as a server name first.
495+
let sanitize_result = sanitize_server_name(&server_name_or_url);
496+
497+
if let Ok(server_name) = sanitize_result.as_ref() {
498+
let protocol = if server_name_or_url.starts_with("http://") {
499+
UrlScheme::Http
500+
} else {
501+
UrlScheme::Https
502+
};
503+
504+
match discover_homeserver(server_name.clone(), protocol, http_client).await {
505+
Ok(well_known) => {
506+
return Ok((well_known.homeserver.base_url.clone(), Some(well_known)));
507+
}
508+
Err(e) => {
509+
debug!(error = %e, "Well-known discovery failed.");
510+
discovery_error = Some(e);
511+
512+
// Check if the server name points to a homeserver.
513+
server_name_or_url = match protocol {
514+
UrlScheme::Http => format!("http://{server_name}"),
515+
UrlScheme::Https => format!("https://{server_name}"),
516+
}
517+
}
518+
}
519+
}
520+
521+
// When discovery fails, or the input isn't a valid server name, fallback to
522+
// trying a homeserver URL.
523+
if let Ok(homeserver_url) = Url::parse(&server_name_or_url) {
524+
// Make sure the URL is definitely for a homeserver.
525+
if check_is_homeserver(&homeserver_url, http_client).await {
526+
return Ok((homeserver_url.to_string(), None));
527+
}
528+
}
529+
530+
Err(discovery_error.unwrap_or(ClientBuildError::InvalidServerName))
531+
}
532+
525533
/// Creates a server name from a user supplied string. The string is first
526534
/// sanitized by removing whitespace, the http(s) scheme and any trailing
527535
/// slashes before being parsed.
528-
fn sanitize_server_name(s: &str) -> crate::Result<OwnedServerName, IdParseError> {
536+
pub fn sanitize_server_name(s: &str) -> crate::Result<OwnedServerName, IdParseError> {
529537
ServerName::parse(
530538
s.trim().trim_start_matches("http://").trim_start_matches("https://").trim_end_matches('/'),
531539
)

crates/matrix-sdk/src/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ use crate::{
9797
mod builder;
9898
pub(crate) mod futures;
9999

100-
pub use self::builder::{ClientBuildError, ClientBuilder};
100+
pub use self::builder::{sanitize_server_name, ClientBuildError, ClientBuilder};
101101

102102
#[cfg(not(target_arch = "wasm32"))]
103103
type NotificationHandlerFut = Pin<Box<dyn Future<Output = ()> + Send>>;

crates/matrix-sdk/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ pub mod widget;
6262

6363
pub use account::Account;
6464
pub use authentication::{AuthApi, AuthSession, SessionTokens};
65-
pub use client::{Client, ClientBuildError, ClientBuilder, LoopCtrl, SessionChange};
65+
pub use client::{
66+
sanitize_server_name, Client, ClientBuildError, ClientBuilder, LoopCtrl, SessionChange,
67+
};
6668
#[cfg(feature = "image-proc")]
6769
pub use error::ImageError;
6870
pub use error::{

0 commit comments

Comments
 (0)