commit d7b0d6f9f538e2b5ca36feb104bcc81e0d59059d
parent 0822c0c128d3b71b13109bb8c0f94f73174440fe
Author: Daniel GarcĂa <dani-garcia@users.noreply.github.com>
Date:   Thu,  3 Sep 2020 19:51:04 +0200
Merge pull request #1124 from aaxdev/fix/support-mobile-signalr-msgpack
Fixing MsgPack headers type and support mobile SignalR
Diffstat:
1 file changed, 37 insertions(+), 29 deletions(-)
diff --git a/src/api/notifications.rs b/src/api/notifications.rs
@@ -20,10 +20,12 @@ static SHOW_WEBSOCKETS_MSG: AtomicBool = AtomicBool::new(true);
 #[get("/hub")]
 fn websockets_err() -> EmptyResult {
     if CONFIG.websocket_enabled() && SHOW_WEBSOCKETS_MSG.compare_and_swap(true, false, Ordering::Relaxed) {
-        err!("###########################################################
+        err!(
+    "###########################################################
     '/notifications/hub' should be proxied to the websocket server or notifications won't work.
     Go to the Wiki for more info, or disable WebSockets setting WEBSOCKET_ENABLED=false.
-    ###########################################################################################")
+    ###########################################################################################"
+        )
     } else {
         Err(Error::empty())
     }
@@ -137,7 +139,6 @@ struct InitialMessage {
 const PING_MS: u64 = 15_000;
 const PING: Token = Token(1);
 
-const ID_KEY: &str = "id=";
 const ACCESS_TOKEN_KEY: &str = "access_token=";
 
 impl WSHandler {
@@ -148,6 +149,32 @@ impl WSHandler {
         let io_error = io::Error::from(io::ErrorKind::InvalidData);
         Err(ws::Error::new(ws::ErrorKind::Io(io_error), msg))
     }
+
+    fn get_request_token(&self, hs: Handshake) -> Option<String> {
+        use std::str::from_utf8;
+
+        // Verify we have a token header
+        if let Some(header_value) = hs.request.header("Authorization") {
+            if let Ok(converted) = from_utf8(header_value) {
+                if let Some(token_part) = converted.split("Bearer ").nth(1) {
+                    return Some(token_part.into());
+                }
+            }
+        };
+        
+        // Otherwise verify the query parameter value
+        let path = hs.request.resource();
+        if let Some(params) = path.split('?').nth(1) {
+            let params_iter = params.split('&').take(1);
+            for val in params_iter {
+                if val.starts_with(ACCESS_TOKEN_KEY) {
+                    return Some(val[ACCESS_TOKEN_KEY.len()..].into());
+                }
+            }
+        };
+
+        None
+    }
 }
 
 impl Handler for WSHandler {
@@ -156,35 +183,16 @@ impl Handler for WSHandler {
         //
         // We don't use `id`, and as of around 2020-03-25, the official clients
         // no longer seem to pass `id` (only `access_token`).
-        let path = hs.request.resource();
-
-        let (_id, access_token) = match path.split('?').nth(1) {
-            Some(params) => {
-                let params_iter = params.split('&').take(2);
-
-                let mut id = None;
-                let mut access_token = None;
 
-                for val in params_iter {
-                    if val.starts_with(ID_KEY) {
-                        id = Some(&val[ID_KEY.len()..]);
-                    } else if val.starts_with(ACCESS_TOKEN_KEY) {
-                        access_token = Some(&val[ACCESS_TOKEN_KEY.len()..]);
-                    }
-                }
-
-                match (id, access_token) {
-                    (Some(a), Some(b)) => (a, b),
-                    (None, Some(b)) => ("", b), // Ignore missing `id`.
-                    _ => return self.err("Missing access token"),
-                }
-            }
-            None => return self.err("Missing query parameters"),
+        // Get user token from header or query parameter
+        let access_token = match self.get_request_token(hs) {
+            Some(token) => token,
+            _ => return self.err("Missing access token"),
         };
 
         // Validate the user
         use crate::auth;
-        let claims = match auth::decode_login(access_token) {
+        let claims = match auth::decode_login(access_token.as_str()) {
             Ok(claims) => claims,
             Err(_) => return self.err("Invalid access token provided"),
         };
@@ -335,7 +343,7 @@ impl WebSocketUsers {
 /* Message Structure
 [
     1, // MessageType.Invocation
-    {}, // Headers
+    {}, // Headers (map)
     null, // InvocationId
     "ReceiveMessage", // Target
     [ // Arguments
@@ -352,7 +360,7 @@ fn create_update(payload: Vec<(Value, Value)>, ut: UpdateType) -> Vec<u8> {
 
     let value = V::Array(vec![
         1.into(),
-        V::Array(vec![]),
+        V::Map(vec![]),
         V::Nil,
         "ReceiveMessage".into(),
         V::Array(vec![V::Map(vec![