1 #include <atomic>
2 
3 #include <gtest/gtest.h>
4 
5 #include <nlohmann/json.hpp>
6 
7 #include "mtxclient/crypto/client.hpp"
8 #include "mtxclient/crypto/types.hpp"
9 #include "mtxclient/http/client.hpp"
10 
11 #include "mtx/requests.hpp"
12 #include "mtx/responses.hpp"
13 
14 #include "test_helpers.hpp"
15 
16 using namespace mtx::client;
17 using namespace mtx::http;
18 using namespace mtx::crypto;
19 
20 using namespace mtx::identifiers;
21 using namespace mtx::events;
22 using namespace mtx::events::msg;
23 using namespace mtx::events::collections;
24 using namespace mtx::responses;
25 
26 using namespace std;
27 
28 using namespace nlohmann;
29 
TEST(Devices,DeleteDevices)30 TEST(Devices, DeleteDevices)
31 {
32     auto alice = make_test_client();
33 
34     alice->login(
35       "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { check_error(err); });
36 
37     auto alice_dummy = make_test_client();
38     alice_dummy->login(
39       "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { check_error(err); });
40 
41     while (alice->access_token().empty() || alice_dummy->access_token().empty())
42         sleep();
43 
44     std::string myDevice = alice->device_id();
45 
46     atomic_int responses(0);
47     std::vector<std::string> device_ids;
48 
49     // Get list of devices, fill device_ids with all devices except current
50     alice->query_devices(
51       [&responses, &device_ids, myDevice](const mtx::responses::QueryDevices &res, RequestErr err) {
52           check_error(err);
53           for (auto it = res.devices.begin(); it != res.devices.end(); ++it)
54               if (it->device_id != myDevice)
55                   device_ids.push_back(it->device_id);
56           responses += 1;
57       });
58 
59     while (responses != 1)
60         sleep();
61 
62     // Delete all devices except current
63     alice->delete_devices(
64       device_ids,
65       mtx::http::UIAHandler([](const mtx::http::UIAHandler &h,
66                                const mtx::user_interactive::Unauthorized &unauthorized) {
67           ASSERT_EQ(unauthorized.flows.size(), 1);
68           ASSERT_EQ(unauthorized.flows[0].stages.size(), 1);
69           ASSERT_EQ(unauthorized.flows[0].stages[0], mtx::user_interactive::auth_types::password);
70 
71           mtx::user_interactive::Auth auth;
72           auth.session = unauthorized.session;
73           mtx::user_interactive::auth::Password pass{};
74           pass.password        = "secret";
75           pass.identifier_user = "alice";
76           pass.identifier_type = mtx::user_interactive::auth::Password::IdType::UserId;
77           auth.content         = pass;
78           h.next(auth);
79       }),
80       [&responses](RequestErr e) {
81           check_error(e);
82           responses += 1;
83       });
84 
85     while (responses != 2)
86         sleep();
87 
88     // Check if the current device is the only device left
89     alice->query_devices(
90       [&responses, myDevice](const mtx::responses::QueryDevices &res, RequestErr err) {
91           check_error(err);
92           ASSERT_EQ(res.devices.size(), 1);
93           ASSERT_EQ(res.devices.begin()->device_id, myDevice);
94           responses += 1;
95       });
96 
97     // Check if dummy can no longer retrieve list of devices because their token was removed
98     alice_dummy->query_devices(
99       [&responses](const mtx::responses::QueryDevices &res, RequestErr err) {
100           ASSERT_TRUE(err);
101           ASSERT_EQ(res.devices.size(), 0);
102           EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNKNOWN_TOKEN");
103       });
104 
105     while (responses != 3)
106         sleep();
107 
108     // Delete current device
109     alice->delete_device(
110       myDevice,
111       mtx::http::UIAHandler([](const mtx::http::UIAHandler &h,
112                                const mtx::user_interactive::Unauthorized &unauthorized) {
113           ASSERT_EQ(unauthorized.flows.size(), 1);
114           ASSERT_EQ(unauthorized.flows[0].stages.size(), 1);
115           ASSERT_EQ(unauthorized.flows[0].stages[0], mtx::user_interactive::auth_types::password);
116 
117           mtx::user_interactive::Auth auth;
118           auth.session = unauthorized.session;
119           mtx::user_interactive::auth::Password pass{};
120           pass.password        = "secret";
121           pass.identifier_user = "alice";
122           pass.identifier_type = mtx::user_interactive::auth::Password::IdType::UserId;
123           auth.content         = pass;
124           h.next(auth);
125       }),
126       [&responses](RequestErr e) {
127           check_error(e);
128           responses += 1;
129       });
130 
131     alice->close();
132 }
133 
TEST(Devices,RenameDevices)134 TEST(Devices, RenameDevices)
135 {
136     auto alice_one = make_test_client();
137     auto alice_two = make_test_client();
138 
139     alice_one->login(
140       "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { check_error(err); });
141     alice_two->login(
142       "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { check_error(err); });
143 
144     while (alice_one->access_token().empty() || alice_two->access_token().empty())
145         sleep();
146 
147     atomic_int responses(0);
148 
149     // Rename the two logged in devices to Alice One and Alice Two
150     alice_one->set_device_name(alice_one->device_id(), "Alice One", [&responses](RequestErr err) {
151         check_error(err);
152         responses += 1;
153     });
154     alice_two->set_device_name(alice_two->device_id(), "Alice Two", [&responses](RequestErr err) {
155         check_error(err);
156         responses += 1;
157     });
158 
159     while (responses != 2)
160         sleep();
161 
162     // Request info for current devices and confirm display name changed
163     alice_one->get_device(alice_one->device_id(),
164                           [&responses](const mtx::responses::Device &res, RequestErr err) {
165                               ASSERT_EQ(res.display_name, "Alice One");
166                               check_error(err);
167                               responses += 1;
168                           });
169     alice_two->get_device(alice_two->device_id(),
170                           [&responses](const mtx::responses::Device &res, RequestErr err) {
171                               ASSERT_EQ(res.display_name, "Alice Two");
172                               check_error(err);
173                               responses += 1;
174                           });
175 
176     while (responses != 4)
177         sleep();
178 
179     // Request device list and check both One and Two are in the list
180     alice_one->query_devices([&responses](const mtx::responses::QueryDevices &res, RequestErr err) {
181         check_error(err);
182         bool oneFound = false;
183         bool twoFound = false;
184         for (auto it = res.devices.begin(); it != res.devices.end(); ++it) {
185             if (it->display_name == "Alice One")
186                 oneFound = true;
187             if (it->display_name == "Alice Two")
188                 twoFound = true;
189         }
190         ASSERT_EQ(oneFound, true);
191         ASSERT_EQ(twoFound, true);
192         responses += 1;
193     });
194 
195     while (responses != 5)
196         sleep();
197 
198     alice_one->close();
199     alice_two->close();
200 }
201