[fractal] api: Create types for well-known request



commit 2a659b3962d6c52c07dee15cfdfeb6217a9284d1
Author: Christopher Davis <brainblasted disroot org>
Date:   Sat Mar 23 21:32:15 2019 -0700

    api: Create types for well-known request
    
    Instead of asking for the identity server and homeserver
    url for login, we can ask the users to give us a domain
    and make a request to .well-known/matrix/client. This
    will give us the identity server and the true url for
    the homeserver.
    
    See https://matrix.org/docs/spec/client_server/latest#well-known-uri for details

 fractal-matrix-api/src/backend/mod.rs      |  2 +-
 fractal-matrix-api/src/backend/register.rs | 18 +++++++++++
 fractal-matrix-api/src/model/register.rs   | 48 +++++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 2 deletions(-)
---
diff --git a/fractal-matrix-api/src/backend/mod.rs b/fractal-matrix-api/src/backend/mod.rs
index 7487c7d4..0e1c7a4f 100644
--- a/fractal-matrix-api/src/backend/mod.rs
+++ b/fractal-matrix-api/src/backend/mod.rs
@@ -14,7 +14,7 @@ use crate::cache::CacheMap;
 
 mod directory;
 mod media;
-mod register;
+pub mod register;
 mod room;
 mod stickers;
 mod sync;
diff --git a/fractal-matrix-api/src/backend/register.rs b/fractal-matrix-api/src/backend/register.rs
index 4193957e..a393093b 100644
--- a/fractal-matrix-api/src/backend/register.rs
+++ b/fractal-matrix-api/src/backend/register.rs
@@ -11,6 +11,7 @@ use crate::types::LoginRequest;
 use crate::types::LoginResponse;
 use crate::types::RegisterRequest;
 use crate::types::RegisterResponse;
+use crate::types::WellKnownResponse;
 
 use crate::backend::types::BKResponse;
 use crate::backend::types::Backend;
@@ -158,3 +159,20 @@ pub fn register(bk: &Backend, user: String, password: String, server: &str) -> R
 
     Ok(())
 }
+
+pub fn get_well_known(domain: &str) -> Result<WellKnownResponse, Error> {
+    let well_known = Url::parse(domain)?.join(".well-known/matrix/client")?;
+
+    // NOTE: The query! macro doesn't like what we're
+    // trying to do, so this implements what we need
+
+    let handle = thread::spawn(move || json_q("get", &well_known, &json!(null)));
+
+    match handle.join() {
+        Ok(r) => match r {
+            Ok(val) => serde_json::from_value(val).map_err(|_| Error::BackendError),
+            Err(e) => Err(e.into()),
+        },
+        _ => Err(Error::BackendError),
+    }
+}
diff --git a/fractal-matrix-api/src/model/register.rs b/fractal-matrix-api/src/model/register.rs
index 82a33cde..cbd7a666 100644
--- a/fractal-matrix-api/src/model/register.rs
+++ b/fractal-matrix-api/src/model/register.rs
@@ -1,6 +1,6 @@
 use super::{AuthenticationData, Identifier, Medium, UserIdentifier};
 use crate::globals;
-use serde::{Deserialize, Serialize};
+use serde::{de, Deserialize, Deserializer, Serialize};
 use std::ops::Not;
 
 #[derive(Clone, Debug, Serialize)]
@@ -83,3 +83,49 @@ pub struct RegisterResponse {
     pub access_token: Option<String>,
     pub device_id: Option<String>,
 }
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(default, tag = "type")]
+pub struct WellKnownResponse {
+    #[serde(deserialize_with = "extract_base_url", rename = "m.homeserver")]
+    pub homeserver: Option<String>,
+    #[serde(deserialize_with = "extract_base_url", rename = "m.identity_server")]
+    pub identity_server: Option<String>,
+}
+
+impl Default for WellKnownResponse {
+    fn default() -> Self {
+        // Identity server is usually vector.im if not specified
+        Self {
+            homeserver: None,
+            identity_server: Some("https://vector.im".to_owned()),
+        }
+    }
+}
+
+fn extract_base_url<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    struct BaseUrlVisitor;
+
+    impl<'de> de::Visitor<'de> for BaseUrlVisitor {
+        type Value = Option<String>;
+
+        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+            formatter.write_str("an object with a base_url key")
+        }
+
+        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+        where
+            A: de::MapAccess<'de>,
+        {
+            let res = map
+                .next_entry::<String, String>()?
+                .and_then(|(key, value)| if key == "base_url" { Some(value) } else { None });
+            Ok(res)
+        }
+    }
+
+    deserializer.deserialize_any(BaseUrlVisitor)
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]