From 1103cc15cfe59b35e540855090af381b0f2e5f8e Mon Sep 17 00:00:00 2001
From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>
Date: Sun, 5 Jul 2020 21:33:27 +0530
Subject: [PATCH] Adding icons to UserProfile

---
 CMakeLists.txt                                |   3 -
 resources/qml/TimelineView.qml                |   2 +-
 resources/qml/UserProfile.qml                 |  81 ++++++-----
 .../DeviceVerification.qml                    |   4 +
 src/DeviceVerificationFlow.cpp                | 130 +++++++++++++-----
 src/DeviceVerificationFlow.h                  |   6 +
 src/timeline/TimelineViewManager.h            |   2 +
 src/ui/UserProfile.cpp                        |  11 +-
 src/ui/UserProfile.h                          |   4 +-
 9 files changed, 163 insertions(+), 80 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5ad8a625a..2aff9914e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,9 +15,6 @@ set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard")
 set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Require C++ standard to be supported")
 set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "compile as PIC by default")
 
-# set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
-# set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
-
 option(HUNTER_ENABLED "Enable Hunter package manager" OFF)
 include("cmake/HunterGate.cmake")
 HunterGate(
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index ec6348785..699efc54c 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -106,7 +106,7 @@ Page {
 		}
 		Connections {
 			target: TimelineManager
-			function onNewDeviceVerificationRequest(flow) {
+			function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId) {
 				flow.userId = userId;
 				flow.sender = false;
 				flow.deviceId = deviceId;
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index df54367b3..5bdccb4d1 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -17,6 +17,13 @@ ApplicationWindow{
 	Layout.alignment: Qt.AlignHCenter
 	palette: colors
 
+	Connections{
+		target: deviceVerificationList
+		onUpdateProfile: {
+			profile.fetchDeviceList(profile.userid)
+		}
+	}
+
 	Component {
 		id: deviceVerificationDialog
 		DeviceVerification {}
@@ -139,20 +146,12 @@ ApplicationWindow{
 							top : 50
 						}
 						ColumnLayout{
-							RowLayout{
-								Text{
-									Layout.fillWidth: true
-									color: colors.text
-									font.bold: true
-									Layout.alignment: Qt.AlignLeft
-									text: model.deviceId
-								}
-								Text{
-									Layout.fillWidth: true
-									color:colors.text
-									Layout.alignment: Qt.AlignLeft
-									text: (model.verificationStatus ==  VerificationStatus.VERIFIED?"V":(model.verificationStatus ==  VerificationStatus.UNVERIFIED?"NV":"B"))
-								}
+							Text{
+								Layout.fillWidth: true
+								color: colors.text
+								font.bold: true
+								Layout.alignment: Qt.AlignLeft
+								text: model.deviceId
 							}
 							Text{
 								Layout.fillWidth: true
@@ -161,27 +160,41 @@ ApplicationWindow{
 								text: model.deviceName
 							}
 						}
-						Button{
-							id: verifyButton
-							text:"Verify"
-							onClicked: {
-								var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
-								{userId : profile.userid, sender: true, deviceId : model.deviceID});
-								deviceVerificationList.add(newFlow.tranId);
-								var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow});
-								dialog.show();
+						RowLayout{
+							Image{
+								Layout.preferredWidth: 20
+								Layout.preferredHeight: 20
+								source: ((model.verificationStatus == VerificationStatus.VERIFIED)?"image://colorimage/:/icons/icons/ui/lock.png?green":
+								((model.verificationStatus == VerificationStatus.UNVERIFIED)?"image://colorimage/:/icons/icons/ui/unlock.png?yellow":
+								"image://colorimage/:/icons/icons/ui/unlock.png?red"))
 							}
-							Layout.margins:{
-								right: 10
-							}
-							palette {
-								button: "white"
-							}
-							contentItem: Text {
-								text: verifyButton.text
-								color: "black"
-								horizontalAlignment: Text.AlignHCenter
-								verticalAlignment: Text.AlignVCenter
+							Button{
+								id: verifyButton
+								text:(model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify"
+								onClicked: {
+									var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
+									{userId : profile.userid, sender: true, deviceId : model.deviceId});
+									if(model.verificationStatus == VerificationStatus.VERIFIED){
+										newFlow.unverify();
+										deviceVerificationList.updateProfile(newFlow.userId);
+									}else{
+										deviceVerificationList.add(newFlow.tranId);
+										var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow});
+										dialog.show();
+									}
+								}
+								Layout.margins:{
+									right: 10
+								}
+								palette {
+									button: "white"
+								}
+								contentItem: Text {
+									text: verifyButton.text
+									color: "black"
+									horizontalAlignment: Text.AlignHCenter
+									verticalAlignment: Text.AlignVCenter
+								}
 							}
 						}
 					}
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index 15c2d7a25..4d734a687 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -33,6 +33,10 @@ ApplicationWindow {
 			case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break;
 			case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break;
 		}
+
+		onRefreshProfile: {
+			deviceVerificationList.updateProfile(flow.userId);
+		}
 	}
 
 	Component {
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index b5134a3b1..7829c41d1 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -1,4 +1,5 @@
 #include "DeviceVerificationFlow.h"
+#include "Cache.h"
 #include "ChatPage.h"
 #include "Logging.h"
 
@@ -181,9 +182,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                                   // uncomment this in future to be compatible with the
                                   // MSC2366 this->sendVerificationDone(); and remove the
                                   // below line
-                                  if (this->isMacVerified == true)
-                                          emit this->deviceVerified();
-                                  else
+                                  if (this->isMacVerified == true) {
+                                          this->acceptDevice();
+                                  } else
                                           this->isMacVerified = true;
                           } else {
                                   this->cancelVerification(
@@ -208,7 +209,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                         auto msg =
                           std::get<mtx::events::DeviceEvent<msgs::KeyVerificationDone>>(message);
                         if (msg.content.transaction_id == this->transaction_id) {
-                                emit this->deviceVerified();
+                                this->acceptDevice();
                         }
                 });
         timeout->start(TIMEOUT);
@@ -259,36 +260,22 @@ DeviceVerificationFlow::setTransactionId(QString transaction_id_)
 void
 DeviceVerificationFlow::setUserId(QString userID)
 {
-        this->userId   = userID;
-        this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(userID.toStdString());
-
-        mtx::responses::QueryKeys res;
-        mtx::requests::QueryKeys req;
-        req.device_keys[userID.toStdString()] = {};
-        http::client()->query_keys(
-          req,
-          [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
-                                                 mtx::http::RequestErr err) {
-                  if (err) {
-                          nhlog::net()->warn("failed to query device keys: {},{}",
-                                             err->matrix_error.errcode,
-                                             static_cast<int>(err->status_code));
-                          return;
-                  }
-
-                  for (auto x : res.device_keys) {
-                          for (auto y : x.second) {
-                                  auto z = y.second;
-                                  if (z.user_id == user_id &&
-                                      z.device_id == this->deviceId.toStdString()) {
-                                          for (auto a : z.keys) {
-                                                  // TODO: Verify Signatures
-                                                  this->device_keys[a.first] = a.second;
-                                          }
-                                  }
-                          }
-                  }
-          });
+        this->userId    = userID;
+        this->toClient  = mtx::identifiers::parse<mtx::identifiers::User>(userID.toStdString());
+        auto user_cache = cache::getUserCache(userID.toStdString());
+
+        if (user_cache.has_value()) {
+                this->callback_fn(user_cache->keys, {}, userID.toStdString());
+        } else {
+                mtx::requests::QueryKeys req;
+                req.device_keys[userID.toStdString()] = {};
+                http::client()->query_keys(
+                  req,
+                  [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
+                                                         mtx::http::RequestErr err) {
+                          this->callback_fn(res, err, user_id);
+                  });
+        }
 }
 
 void
@@ -482,6 +469,16 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
                             nhlog::net()->warn("failed to cancel verification request: {} {}",
                                                err->matrix_error.error,
                                                static_cast<int>(err->status_code));
+                    auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
+                    if (verified_cache.has_value()) {
+                            verified_cache->device_blocked.push_back(this->deviceId.toStdString());
+                            cache::setVerifiedCache(this->userId.toStdString(),
+                                                    verified_cache.value());
+                    } else {
+                            cache::setVerifiedCache(
+                              this->userId.toStdString(),
+                              DeviceVerifiedCache{{}, {this->deviceId.toStdString()}});
+                    }
                     this->deleteLater();
             });
 }
@@ -546,7 +543,7 @@ DeviceVerificationFlow::sendVerificationMac()
                                                static_cast<int>(err->status_code));
 
                     if (this->isMacVerified == true)
-                            emit this->deviceVerified();
+                            this->acceptDevice();
                     else
                             this->isMacVerified = true;
             });
@@ -555,8 +552,69 @@ DeviceVerificationFlow::sendVerificationMac()
 void
 DeviceVerificationFlow::acceptDevice()
 {
+        auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
+        if (verified_cache.has_value()) {
+                verified_cache->device_verified.push_back(this->deviceId.toStdString());
+                for (auto it = verified_cache->device_blocked.begin();
+                     it != verified_cache->device_blocked.end();
+                     it++) {
+                        if (*it == this->deviceId.toStdString()) {
+                                verified_cache->device_blocked.erase(it);
+                        }
+                }
+                cache::setVerifiedCache(this->userId.toStdString(), verified_cache.value());
+        } else {
+                cache::setVerifiedCache(this->userId.toStdString(),
+                                        DeviceVerifiedCache{{this->deviceId.toStdString()}, {}});
+        }
+
         emit deviceVerified();
+        emit refreshProfile();
         this->deleteLater();
+}
+//! callback function to keep track of devices
+void
+DeviceVerificationFlow::callback_fn(const mtx::responses::QueryKeys &res,
+                                    mtx::http::RequestErr err,
+                                    std::string user_id)
+{
+        if (err) {
+                nhlog::net()->warn("failed to query device keys: {},{}",
+                                   err->matrix_error.errcode,
+                                   static_cast<int>(err->status_code));
+                return;
+        }
+
+        if (res.device_keys.empty() || (res.device_keys.find(user_id) == res.device_keys.end())) {
+                nhlog::net()->warn("no devices retrieved {}", user_id);
+                return;
+        }
 
-        // Yet to add send to_device message
+        for (auto x : res.device_keys) {
+                for (auto y : x.second) {
+                        auto z = y.second;
+                        if (z.user_id == user_id && z.device_id == this->deviceId.toStdString()) {
+                                for (auto a : z.keys) {
+                                        // TODO: Verify Signatures
+                                        this->device_keys[a.first] = a.second;
+                                }
+                        }
+                }
+        }
+}
+
+void
+DeviceVerificationFlow::unverify()
+{
+        auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
+        if (verified_cache.has_value()) {
+                auto it = std::remove(verified_cache->device_verified.begin(),
+                                      verified_cache->device_verified.end(),
+                                      this->deviceId.toStdString());
+                verified_cache->device_verified.erase(it);
+                cache::setVerifiedCache(this->userId.toStdString(), verified_cache.value());
+        }
+
+        emit refreshProfile();
+        this->deleteLater();
 }
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 891c6aea9..edff7c8e4 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -51,6 +51,9 @@ public:
         void setDeviceId(QString deviceID);
         void setMethod(Method method_);
         void setSender(bool sender_);
+        void callback_fn(const mtx::responses::QueryKeys &res,
+                         mtx::http::RequestErr err,
+                         std::string user_id);
 
         nlohmann::json canonical_json;
 
@@ -73,12 +76,15 @@ public slots:
         void sendVerificationMac();
         //! Completes the verification flow
         void acceptDevice();
+        //! unverifies a device
+        void unverify();
 
 signals:
         void verificationRequestAccepted(Method method);
         void deviceVerified();
         void timedout();
         void verificationCanceled();
+        void refreshProfile();
 
 private:
         QString userId;
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index af8bc4b6e..a438ef5e8 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -29,6 +29,8 @@ public:
         Q_INVOKABLE void add(QString tran_id);
         Q_INVOKABLE void remove(QString tran_id);
         Q_INVOKABLE bool exist(QString tran_id);
+signals:
+        void updateProfile(QString userId);
 
 private:
         QVector<QString> deviceVerificationList;
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index fde0044bc..b4938e8d9 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -1,6 +1,7 @@
 #include "UserProfile.h"
 #include "Cache.h"
 #include "ChatPage.h"
+#include "DeviceVerificationFlow.h"
 #include "Logging.h"
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
@@ -122,10 +123,10 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
                    verified});
         }
 
-        // std::sort(
-        //   deviceInfo.begin(), deviceInfo.end(), [](const DeviceInfo &a, const DeviceInfo &b) {
-        //           return a.device_id > b.device_id;
-        //   });
+        std::sort(
+          deviceInfo.begin(), deviceInfo.end(), [](const DeviceInfo &a, const DeviceInfo &b) {
+                  return a.device_id > b.device_id;
+          });
 
         this->deviceList_.queueReset(std::move(deviceInfo));
 }
@@ -176,4 +177,4 @@ UserProfile::startChat()
         if (utils::localUser() != this->userid_)
                 req.invite = {this->userid_.toStdString()};
         emit ChatPage::instance()->createRoom(req);
-}
+}
\ No newline at end of file
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 38002fffc..99c6a7553 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -19,6 +19,8 @@ enum Status
 Q_ENUM_NS(Status)
 }
 
+class DeviceVerificationFlow;
+
 class DeviceInfo
 {
 public:
@@ -88,7 +90,7 @@ public:
         QString displayName();
         QString avatarUrl();
 
-        void fetchDeviceList(const QString &userID);
+        Q_INVOKABLE void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
         // Q_INVOKABLE void ignoreUser();
         Q_INVOKABLE void kickUser();
-- 
GitLab