From 71f3ac1a3c1ce77109fb63a509a6d4b6e7aac45c Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris <sideris.konstantin@gmail.com> Date: Tue, 3 Apr 2018 14:20:43 +0300 Subject: [PATCH] Implement /keys/changes --- .travis.yml | 4 +-- CMakeLists.txt | 1 - src/client.cpp | 20 +++++++++++ src/client.hpp | 7 ++++ tests/e2ee.cpp | 94 +++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 102 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42f854b2d..7cb64b784 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ matrix: - os: linux compiler: clang env: - - CXX_VERSION=clang++-5.0 + - CXX_VERSION=clang++-6.0 - LINT=ON - TESTS=ON addons: @@ -60,7 +60,7 @@ script: - cmake --version # Build library, examples & tests - - cmake -H. -Bbuild -DOPENSSL_ROOT_DIR=$OPENSLL_ROOT_DIR -DBUILD_LIB_TESTS=$TESTS -DBUILD_OLM=1 + - cmake -H. -Bbuild -DOPENSSL_ROOT_DIR=$OPENSLL_ROOT_DIR -DBUILD_LIB_TESTS=$TESTS - cmake --build build # Unit & Integration tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 84079bdbb..465730a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,6 @@ project(matrix_client CXX) option(ASAN "Compile with address sanitizers" OFF) option(BUILD_LIB_TESTS "Build tests" ON) option(BUILD_LIB_EXAMPLES "Build examples" ON) -option(BUILD_OLM "Fetch & build libolm" OFF) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/client.cpp b/src/client.cpp index b19f6fc7b..4eb178256 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -577,3 +577,23 @@ Client::query_keys( post<mtx::requests::QueryKeys, mtx::responses::QueryKeys>( "/client/r0/keys/query", req, callback); } + +void +Client::key_changes( + const std::string &from, + const std::string &to, + std::function<void(const mtx::responses::KeyChanges &res, RequestErr err)> callback) +{ + std::map<std::string, std::string> params; + + if (!from.empty()) + params.emplace("from", from); + + if (!to.empty()) + params.emplace("to", to); + + get<mtx::responses::KeyChanges>("/client/r0/keys/changes?" + utils::query_params(params), + [callback](const mtx::responses::KeyChanges &res, + HeaderFields, + RequestErr err) { callback(res, err); }); +} diff --git a/src/client.hpp b/src/client.hpp index 4ba7d1169..f7838935b 100644 --- a/src/client.hpp +++ b/src/client.hpp @@ -211,6 +211,13 @@ public: const mtx::requests::QueryKeys &req, std::function<void(const mtx::responses::QueryKeys &res, RequestErr err)> cb); + //! Gets a list of users who have updated their device identity keys + //! since a previous sync token. + void key_changes( + const std::string &from, + const std::string &to, + std::function<void(const mtx::responses::KeyChanges &res, RequestErr err)> cb); + private: template<class Request, class Response> void post(const std::string &endpoint, diff --git a/tests/e2ee.cpp b/tests/e2ee.cpp index 52c04dad7..9149bb676 100644 --- a/tests/e2ee.cpp +++ b/tests/e2ee.cpp @@ -24,6 +24,20 @@ using namespace std; using ErrType = std::experimental::optional<errors::ClientError>; +mtx::requests::UploadKeys +generate_keys(std::shared_ptr<olm::Account> account, + const mtx::identifiers::User &user_id, + const std::string &device_id) +{ + auto idks = mtx::client::crypto::identity_keys(account); + + mtx::client::crypto::generate_one_time_keys(account, 1); + auto otks = mtx::client::crypto::one_time_keys(account); + + return mtx::client::crypto::create_upload_keys_request( + account, idks, otks, user_id, device_id); +} + void check_error(ErrType err) { @@ -146,13 +160,7 @@ TEST(Encryption, UploadKeys) while (alice->access_token().empty()) std::this_thread::sleep_for(std::chrono::milliseconds(100)); - json identity_keys = mtx::client::crypto::identity_keys(olm_account); - - mtx::client::crypto::generate_one_time_keys(olm_account, 1); - auto one_time_keys = mtx::client::crypto::one_time_keys(olm_account); - - auto req = mtx::client::crypto::create_upload_keys_request( - olm_account, identity_keys, one_time_keys, alice->user_id(), alice->device_id()); + auto req = ::generate_keys(olm_account, alice->user_id(), alice->device_id()); alice->upload_keys(req, [](const mtx::responses::UploadKeys &res, ErrType err) { check_error(err); @@ -181,20 +189,8 @@ TEST(Encryption, QueryKeys) std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Create and upload keys for both users. - auto alice_idks = mtx::client::crypto::identity_keys(alice_olm); - auto bob_idks = mtx::client::crypto::identity_keys(bob_olm); - - mtx::client::crypto::generate_one_time_keys(alice_olm, 1); - mtx::client::crypto::generate_one_time_keys(bob_olm, 1); - - auto alice_otks = mtx::client::crypto::one_time_keys(alice_olm); - auto bob_otks = mtx::client::crypto::one_time_keys(bob_olm); - - auto alice_req = mtx::client::crypto::create_upload_keys_request( - alice_olm, alice_idks, alice_otks, alice->user_id(), alice->device_id()); - - auto bob_req = mtx::client::crypto::create_upload_keys_request( - bob_olm, bob_idks, bob_otks, bob->user_id(), bob->device_id()); + auto alice_req = ::generate_keys(alice_olm, alice->user_id(), alice->device_id()); + auto bob_req = ::generate_keys(bob_olm, bob->user_id(), bob->device_id()); // Validates that both upload requests are finished. atomic_int uploads(0); @@ -269,3 +265,59 @@ TEST(Encryption, QueryKeys) alice->close(); bob->close(); } + +TEST(Encryption, KeyChanges) +{ + auto carl = std::make_shared<Client>("localhost"); + auto carl_olm = mtx::client::crypto::olm_new_account(); + + carl->login( + "carl", "secret", [](const mtx::responses::Login &, ErrType err) { check_error(err); }); + + while (carl->access_token().empty()) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + mtx::requests::CreateRoom req; + carl->create_room(req, [carl, carl_olm](const mtx::responses::CreateRoom &, ErrType err) { + check_error(err); + + // Carl syncs to get the first next_batch token. + carl->sync( + "", "", false, 0, [carl, carl_olm](const mtx::responses::Sync &res, ErrType err) { + check_error(err); + const auto next_batch_token = res.next_batch; + + auto key_req = + ::generate_keys(carl_olm, carl->user_id(), carl->device_id()); + + atomic_bool keys_uploaded(false); + + // Changes his keys. + carl->upload_keys( + key_req, + [&keys_uploaded](const mtx::responses::UploadKeys &, ErrType err) { + check_error(err); + keys_uploaded = true; + }); + + while (!keys_uploaded) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // The key changes should contain his username + // because of the key uploading. + carl->key_changes( + next_batch_token, + "", + [carl](const mtx::responses::KeyChanges &res, ErrType err) { + check_error(err); + + EXPECT_EQ(res.changed.size(), 1); + EXPECT_EQ(res.left.size(), 0); + + EXPECT_EQ(res.changed.at(0), carl->user_id().to_string()); + }); + }); + }); + + carl->close(); +} -- GitLab