Skip to content
Snippets Groups Projects
Unverified Commit 32065798 authored by Nicolas Werner's avatar Nicolas Werner Committed by GitHub
Browse files

Merge pull request #19 from deepbluev7/0.3.0-dev

Add .well-known support
parents b1d71485 14724d78
No related branches found
No related tags found
No related merge requests found
......@@ -153,7 +153,8 @@ add_library(matrix_client
lib/structs/responses/profile.cpp
lib/structs/responses/register.cpp
lib/structs/responses/sync.cpp
lib/structs/responses/version.cpp)
lib/structs/responses/version.cpp
lib/structs/responses/well-known.cpp)
add_library(MatrixClient::MatrixClient ALIAS matrix_client)
target_include_directories(matrix_client
SYSTEM
......
......@@ -14,3 +14,4 @@
#include "responses/register.hpp"
#include "responses/sync.hpp"
#include "responses/version.hpp"
#include "responses/well-known.hpp"
......@@ -5,6 +5,7 @@
#include <nlohmann/json.hpp>
#include "mtx/identifiers.hpp"
#include "well-known.hpp"
namespace mtx {
namespace responses {
......@@ -18,10 +19,16 @@ struct Login
//! This access token can then be used to authorize other requests.
std::string access_token;
//! The hostname of the homeserver on which the account has been registered.
std::string home_server;
[[deprecated("Clients should extract the server_name from user_id (by splitting at the "
"first colon) if they require it.")]] std::string home_server;
//! ID of the logged-in device.
//! Will be the same as the corresponding parameter in the request, if one was specified.
std::string device_id;
//! Optional client configuration provided by the server.
//! If present, clients SHOULD use the provided object to reconfigure themselves,
//! optionally validating the URLs within.
boost::optional<WellKnown> well_known;
};
void
......
#pragma once
#include <boost/optional.hpp>
#include <nlohmann/json.hpp>
namespace mtx {
namespace responses {
struct ServerInformation
{
//! Required. The base URL for client-server connections.
std::string base_url;
};
//! Response from the `GET /.well-known/matrix/client` endpoint.
//! May also be returned from `POST /_matrix/client/r0/login`.
//
//! Gets discovery information about the domain
struct WellKnown
{
//! Required. Used by clients to discover homeserver information.
ServerInformation homeserver;
//! Used by clients to discover identity server information.
boost::optional<ServerInformation> identity_server;
};
void
from_json(const nlohmann::json &obj, WellKnown &response);
void
from_json(const nlohmann::json &obj, ServerInformation &response);
}
}
......@@ -144,6 +144,9 @@ public:
const std::string &device_name,
Callback<mtx::responses::Login> cb);
void login(const mtx::requests::Login &req, Callback<mtx::responses::Login> cb);
//! Lookup real server to connect to.
//! Call set_server with the returned homeserver url after this
void well_known(Callback<mtx::responses::WellKnown> cb);
//! Register by not expecting a registration flow.
void registration(const std::string &user,
......@@ -343,7 +346,8 @@ private:
template<class Response>
void get(const std::string &endpoint,
HeadersCallback<Response> cb,
bool requires_auth = true);
bool requires_auth = true,
const std::string &endpoint_namespace = "/_matrix");
template<class Response>
std::shared_ptr<Session> create_session(HeadersCallback<Response> callback);
......@@ -437,7 +441,8 @@ template<class Response>
void
mtx::http::Client::get(const std::string &endpoint,
HeadersCallback<Response> callback,
bool requires_auth)
bool requires_auth,
const std::string &endpoint_namespace)
{
auto session = create_session<Response>(callback);
......@@ -445,7 +450,8 @@ mtx::http::Client::get(const std::string &endpoint,
return;
setup_auth(session.get(), requires_auth);
setup_headers<std::string, boost::beast::http::verb::get>(session.get(), {}, endpoint);
setup_headers<std::string, boost::beast::http::verb::get>(
session.get(), {}, endpoint, "", endpoint_namespace);
session->run();
}
......
......@@ -83,14 +83,15 @@ void
setup_headers(mtx::http::Session *session,
const Request &req,
const std::string &endpoint,
const std::string &content_type = "")
const std::string &content_type = "",
const std::string &endpoint_namespace = "/_matrix")
{
session->request.set(boost::beast::http::field::user_agent, "mtxclient v0.2.0");
session->request.set(boost::beast::http::field::user_agent, "mtxclient v0.3.0");
session->request.set(boost::beast::http::field::accept_encoding, "gzip,deflate");
session->request.set(boost::beast::http::field::host, session->host);
session->request.method(HttpVerb);
session->request.target("/_matrix" + endpoint);
session->request.target(endpoint_namespace + endpoint);
session->request.body() = client::utils::serialize(req);
session->request.prepare_payload();
......
......@@ -25,15 +25,22 @@ Client::Client(const std::string &server, uint16_t port)
void
Client::set_server(const std::string &server)
{
std::string server_name = server;
// Remove https prefix, if it exists
if (boost::algorithm::starts_with(server_name, "https://"))
boost::algorithm::erase_first(server_name, "https://");
if (server_name.size() > 0 && server_name.back() == '/')
server_name.erase(server_name.end() - 1);
// Check if the input also contains the port.
std::vector<std::string> parts;
boost::split(parts, server, [](char c) { return c == ':'; });
boost::split(parts, server_name, [](char c) { return c == ':'; });
if (parts.size() == 2 && mtx::client::utils::is_number(parts.at(1))) {
server_ = parts.at(0);
port_ = std::stoi(parts.at(1));
} else {
server_ = server;
server_ = server_name;
}
}
......@@ -111,6 +118,19 @@ Client::login(const mtx::requests::Login &req, Callback<mtx::responses::Login> c
},
false);
}
void
Client::well_known(Callback<mtx::responses::WellKnown> callback)
{
get<mtx::responses::WellKnown>(
"/matrix/client",
[callback](const mtx::responses::WellKnown &res, HeaderFields, RequestErr err) {
callback(res, err);
},
false,
"/.well-known");
}
void
Client::logout(Callback<mtx::responses::Logout> callback)
{
......
......@@ -16,6 +16,9 @@ from_json(const json &obj, Login &response)
if (obj.count("device_id") != 0)
response.device_id = obj.at("device_id").get<std::string>();
if (obj.count("well_known") != 0)
response.well_known = obj.at("well_known").get<WellKnown>();
}
}
}
#include <regex>
#include <string>
#include "mtx/responses/well-known.hpp"
using json = nlohmann::json;
namespace mtx {
namespace responses {
void
from_json(const json &obj, WellKnown &response)
{
response.homeserver = obj.at("m.homeserver").get<ServerInformation>();
if (obj.count("m.identity_server"))
response.identity_server = obj.at("m.identity_server").get<ServerInformation>();
}
void
from_json(const json &obj, ServerInformation &response)
{
response.base_url = obj.at("base_url");
}
}
}
......@@ -457,6 +457,25 @@ TEST(Responses, Versions)
ASSERT_THROW(Versions versions = error_data, std::invalid_argument);
}
TEST(Responses, WellKnown)
{
json data = R"({
"m.homeserver": {
"base_url": "https://matrix.example.com"
},
"m.identity_server": {
"base_url": "https://identity.example.com"
},
"org.example.custom.property": {
"app_url": "https://custom.app.example.org"
}
})"_json;
WellKnown wellknown = data;
EXPECT_EQ(wellknown.homeserver.base_url, "https://matrix.example.com");
EXPECT_EQ(wellknown.identity_server->base_url, "https://identity.example.com");
}
TEST(Responses, CreateRoom)
{
json data = R"({"room_id" : "!sefiuhWgwghwWgh:example.com"})"_json;
......@@ -475,7 +494,15 @@ TEST(Responses, Login)
"user_id": "@cheeky_monkey:matrix.org",
"access_token": "abc123",
"home_server": "matrix.org",
"device_id": "GHTYAJCE"
"device_id": "GHTYAJCE",
"well_known": {
"m.homeserver": {
"base_url": "https://example.org"
},
"m.identity_server": {
"base_url": "https://id.example.org"
}
}
})"_json;
Login login = data;
......@@ -483,6 +510,8 @@ TEST(Responses, Login)
EXPECT_EQ(login.access_token, "abc123");
EXPECT_EQ(login.home_server, "matrix.org");
EXPECT_EQ(login.device_id, "GHTYAJCE");
EXPECT_EQ(login.well_known->homeserver.base_url, "https://example.org");
EXPECT_EQ(login.well_known->identity_server->base_url, "https://id.example.org");
json data2 = R"({
"user_id": "@cheeky_monkey:matrix.org",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment