From 4da58d0f0f9df6d9f1438a8701fedbf54edf7e46 Mon Sep 17 00:00:00 2001
From: ajberchek <ajberchek@gmail.com>
Date: Sat, 3 Mar 2018 11:08:43 -0800
Subject: [PATCH] Implements Logout Functionality (#16)

fixes #6
---
 src/client.cpp       |  21 +++++++++
 src/client.hpp       |   2 +
 tests/client_api.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+)

diff --git a/src/client.cpp b/src/client.cpp
index ca0b49d59..8a930b5af 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -237,6 +237,27 @@ Client::login(
           false);
 }
 
+void
+Client::logout(
+  std::function<void(const mtx::responses::Logout &response,
+                     std::experimental::optional<mtx::client::errors::ClientError>)> callback)
+{
+        mtx::requests::Logout req;
+
+        post<mtx::requests::Logout, mtx::responses::Logout>(
+          "/logout",
+          req,
+          [this, callback](const mtx::responses::Logout &res,
+                           std::experimental::optional<mtx::client::errors::ClientError> err) {
+                  if (!err) {
+                          // Clear the now invalid access token when logout is successful
+                          access_token_.clear();
+                  }
+                  // Pass up response and error to supplied callback
+                  callback(res, err);
+          });
+}
+
 void
 Client::create_room(const mtx::requests::CreateRoom &room_options,
                     std::function<void(const mtx::responses::CreateRoom &, RequestErr)> callback)
diff --git a/src/client.hpp b/src/client.hpp
index cffe55518..acb076bf0 100644
--- a/src/client.hpp
+++ b/src/client.hpp
@@ -47,6 +47,8 @@ public:
         void login(const std::string &username,
                    const std::string &password,
                    std::function<void(const mtx::responses::Login &response, RequestErr err)>);
+        //! Perform logout.
+        void logout(std::function<void(const mtx::responses::Logout &response, RequestErr err)>);
         //! Create a room with the given options.
         void create_room(
           const mtx::requests::CreateRoom &room_options,
diff --git a/tests/client_api.cpp b/tests/client_api.cpp
index 27049c434..1b8f913d2 100644
--- a/tests/client_api.cpp
+++ b/tests/client_api.cpp
@@ -107,6 +107,107 @@ TEST(ClientAPI, CreateRoom)
         mtx_client->close();
 }
 
+TEST(ClientAPI, LogoutSuccess)
+{
+        std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
+        std::string token;
+
+        // Login and prove that login was successful by creating a room
+        mtx_client->login(
+          "alice", "secret", [&token](const mtx::responses::Login &res, ErrType err) {
+                  ASSERT_FALSE(err);
+                  validate_login("@alice:localhost", res);
+                  token = res.access_token;
+          });
+        while (token.empty()) {
+                // Block while we are logging in
+                std::this_thread::sleep_for(std::chrono::milliseconds(300));
+        }
+        mtx_client->set_access_token(token);
+        mtx::requests::CreateRoom req;
+        req.name  = "Test1";
+        req.topic = "Topic1";
+        mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        // Logout and prove that logout was successful and deleted the access_token_ for the client
+        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+                token.clear();
+        });
+        while (token.size()) {
+                // Block while we are logging out
+                std::this_thread::sleep_for(std::chrono::milliseconds(300));
+        }
+        // Verify that sending requests with this mtx_client fails after logout
+        mtx::requests::CreateRoom failReq;
+        failReq.name  = "42";
+        failReq.topic = "LifeUniverseEverything";
+        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_TRUE(err);
+                EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_MISSING_TOKEN");
+                EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
+
+        });
+
+        mtx_client->close();
+}
+
+TEST(ClientAPI, LogoutInvalidatesTokenOnServer)
+{
+        std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
+        std::string token;
+
+        // Login and prove that login was successful by creating a room
+        mtx_client->login(
+          "alice", "secret", [&token](const mtx::responses::Login &res, ErrType err) {
+                  ASSERT_FALSE(err);
+                  validate_login("@alice:localhost", res);
+                  token = res.access_token;
+          });
+        while (token.empty()) {
+                // Block while we are logging in
+                std::this_thread::sleep_for(std::chrono::milliseconds(300));
+        }
+        mtx_client->set_access_token(token);
+        mtx::requests::CreateRoom req;
+        req.name  = "Test1";
+        req.topic = "Topic1";
+        mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        // Logout and prove that logout was successful by verifying the old access_token_ is no
+        // longer valid
+        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+                mtx_client->set_access_token(token);
+                token.clear();
+        });
+        while (token.size()) {
+                // Block while we are logging out
+                std::this_thread::sleep_for(std::chrono::milliseconds(300));
+        }
+        // Verify that creating a room with the old access_token_ no longer succeeds after logout
+        mtx::requests::CreateRoom failReq;
+        failReq.name  = "42";
+        failReq.topic = "LifeUniverseEverything";
+        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_TRUE(err);
+                EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNKNOWN_TOKEN");
+                EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
+        });
+
+        mtx_client->close();
+}
+
 TEST(ClientAPI, CreateRoomInvites)
 {
         auto alice = std::make_shared<Client>("localhost");
-- 
GitLab