From 90c13efab1fd1b67625ec23815ccc195803e230e Mon Sep 17 00:00:00 2001
From: dec05eba <dec05eba@protonmail.com>
Date: Mon, 28 Sep 2020 00:21:23 +0200
Subject: Matrix: fix login with pantalaimon proxy, fix logout crash, show real
 login error

---
 src/plugins/Matrix.cpp | 82 ++++++++++++++++++--------------------------------
 1 file changed, 30 insertions(+), 52 deletions(-)

(limited to 'src/plugins')

diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 8b819a2..d709f73 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -54,7 +54,7 @@ namespace QuickMedia {
 
         char url[512];
         if(next_batch.empty())
-            snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=0", homeserver.c_str());
+            snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=0&full_state=true", homeserver.c_str());
         else
             snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=30000&since=%s", homeserver.c_str(), next_batch.c_str());
 
@@ -831,38 +831,6 @@ namespace QuickMedia {
         return post_message(room_id, filename, content_uri_json.asString(), MessageType::IMAGE, &message_info);
     }
 
-    static std::string parse_login_error_response(std::string json_str) {
-        if(json_str.empty())
-            return "Unknown error";
-
-        Json::Value json_root;
-        Json::CharReaderBuilder json_builder;
-        std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader());
-        std::string json_errors;
-        if(!json_reader->parse(&json_str[0], &json_str[json_str.size()], &json_root, &json_errors)) {
-            fprintf(stderr, "Matrix login response parse error: %s\n", json_errors.c_str());
-            return json_str;
-        }
-
-        if(!json_root.isObject())
-            return json_str;
-
-        const Json::Value &errcode_json = json_root["errcode"];
-        // Yes, matrix is retarded and returns M_NOT_JSON error code when username/password is incorrect
-        if(errcode_json.isString() && strcmp(errcode_json.asCString(), "M_NOT_JSON") == 0)
-            return "Incorrect username or password";
-
-        return json_str;
-    }
-
-    // Returns empty string on error
-    static std::string extract_homeserver_from_user_id(const std::string &user_id) {
-        size_t index = user_id.find(':');
-        if(index == std::string::npos)
-            return "";
-        return user_id.substr(index + 1);
-    }
-
     PluginResult Matrix::login(const std::string &username, const std::string &password, const std::string &homeserver, std::string &err_msg) {
         // TODO: this is deprecated but not all homeservers have the new version.
         // When this is removed from future version then switch to the new login method (identifier object with the username).
@@ -882,8 +850,8 @@ namespace QuickMedia {
         };
 
         std::string server_response;
-        if(download_to_string(homeserver + "/_matrix/client/r0/login", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
-            err_msg = parse_login_error_response(std::move(server_response));
+        if(download_to_string(homeserver + "/_matrix/client/r0/login", server_response, std::move(additional_args), use_tor, true, false) != DownloadResult::OK) {
+            err_msg = std::move(server_response);
             return PluginResult::NET_ERR;
         }
 
@@ -904,6 +872,12 @@ namespace QuickMedia {
             return PluginResult::ERR;
         }
 
+        const Json::Value &error = json_root["error"];
+        if(error.isString()) {
+            err_msg = error.asString();
+            return PluginResult::ERR;
+        }
+
         const Json::Value &user_id_json = json_root["user_id"];
         if(!user_id_json.isString()) {
             err_msg = "Failed to parse matrix login response";
@@ -916,17 +890,13 @@ namespace QuickMedia {
             return PluginResult::ERR;
         }
 
-        std::string user_id = user_id_json.asString();
+        // Use the user-provided homeserver instead of the one the server tells us about, otherwise this wont work with a proxy
+        // such as pantalaimon
+        json_root["homeserver"] = homeserver;
 
-        std::string homeserver_response = extract_homeserver_from_user_id(user_id);
-        if(homeserver_response.empty()) {
-            err_msg = "Missing homeserver in user id, user id: " + user_id;
-            return PluginResult::ERR;
-        }
-
-        this->user_id = std::move(user_id);
+        this->user_id = user_id_json.asString();
         this->access_token = access_token_json.asString();
-        this->homeserver = "https://" + std::move(homeserver_response);
+        this->homeserver = homeserver;
 
         // TODO: Handle well_known field. The spec says clients SHOULD handle it if its provided
 
@@ -956,6 +926,13 @@ namespace QuickMedia {
         if(download_to_string(homeserver + "/_matrix/client/r0/logout", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
             return PluginResult::NET_ERR;
 
+        // Make sure all fields are reset here!
+        room_data_by_id.clear();
+        user_id.clear();
+        access_token.clear();
+        homeserver.clear();
+        next_batch.clear();
+
         return PluginResult::OK;
     }
 
@@ -991,29 +968,30 @@ namespace QuickMedia {
             return PluginResult::ERR;
         }
 
-        std::string user_id = user_id_json.asString();
-        std::string access_token = access_token_json.asString();
-
-        std::string homeserver = extract_homeserver_from_user_id(user_id);
-        if(homeserver.empty()) {
-            fprintf(stderr, "Missing homeserver in user id, user id: %s\n", user_id.c_str());
+        const Json::Value &homeserver_json = json_root["homeserver"];
+        if(!homeserver_json.isString()) {
+            fprintf(stderr, "Failed to parse matrix cached session response\n");
             return PluginResult::ERR;
         }
 
+        std::string user_id = user_id_json.asString();
+        std::string access_token = access_token_json.asString();
+        std::string homeserver = homeserver_json.asString();
+
         std::vector<CommandArg> additional_args = {
             { "-H", "Authorization: Bearer " + access_token }
         };
 
         std::string server_response;
         // We want to make any request to the server that can verify that our token is still valid, doesn't matter which call
-        if(download_to_string("https://" + homeserver + "/_matrix/client/r0/account/whoami", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
+        if(download_to_string(homeserver + "/_matrix/client/r0/account/whoami", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
             fprintf(stderr, "Matrix whoami response: %s\n", server_response.c_str());
             return PluginResult::NET_ERR;
         }
 
         this->user_id = std::move(user_id);
         this->access_token = std::move(access_token);
-        this->homeserver = "https://" + homeserver;
+        this->homeserver = std::move(homeserver);
         return PluginResult::OK;
     }
 
-- 
cgit v1.2.3-70-g09d2