Skip to content

Commit

Permalink
Add SSL configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
leemaguire committed Jul 10, 2024
1 parent 90b31ac commit e244af0
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 46 deletions.
7 changes: 5 additions & 2 deletions include/cpprealm/networking/networking.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ namespace realm {
namespace sync {
struct WebSocketEndpoint;
}

namespace networking {
struct default_transport_configuration;
}
}

namespace realm::internal::networking {
Expand All @@ -158,8 +162,7 @@ namespace realm::internal::networking {
::realm::app::Response to_core_response(const ::realm::networking::response&);

::realm::sync::WebSocketEndpoint to_core_websocket_endpoint(const ::realm::networking::websocket_endpoint& ep,
const std::optional<internal::bridge::realm::sync_config::proxy_config>& pc,
const std::optional<std::map<std::string, std::string>>& custom_headers);
const std::optional<::realm::networking::default_transport_configuration>& config);
::realm::networking::websocket_endpoint to_websocket_endpoint(const ::realm::sync::WebSocketEndpoint& ep);
} //namespace realm::internal::networking

Expand Down
18 changes: 13 additions & 5 deletions include/cpprealm/networking/platform_networking.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,38 +229,46 @@ namespace realm::networking {
/// Globally overwrites the default http transport client factory
void set_http_client_factory(std::function<std::shared_ptr<http_transport_client>()>&&);

struct default_transport_configuraton {
struct default_transport_configuration {
std::optional<std::map<std::string, std::string>> custom_http_headers;
std::optional<::realm::internal::bridge::realm::sync_config::proxy_config> proxy_config;

using SSLVerifyCallback = bool(const std::string& server_address,
internal::bridge::realm::sync_config::proxy_config::port_type server_port,
const char* pem_data, size_t pem_size, int preverify_ok, int depth);
bool client_validate_ssl = true;
std::optional<std::string> ssl_trust_certificate_path;
std::function<SSLVerifyCallback> ssl_verify_callback;
};

/// Built in HTTP transport client.
struct default_http_transport : public http_transport_client {
default_http_transport() = default;
default_http_transport(const default_transport_configuraton& c) : m_configuration(c) {}
default_http_transport(const default_transport_configuration& c) : m_configuration(c) {}

~default_http_transport() = default;

void send_request_to_server(const ::realm::networking::request& request,
std::function<void(const ::realm::networking::response&)>&& completion);

protected:
default_transport_configuraton m_configuration;
default_transport_configuration m_configuration;
};

/// Built in websocket provider
struct default_socket_provider : public sync_socket_provider {
default_socket_provider();
default_socket_provider(const default_transport_configuraton& c) : m_configuration(c) {}
default_socket_provider(const default_transport_configuration& c);
~default_socket_provider() = default;

std::unique_ptr<websocket_interface> connect(std::unique_ptr<websocket_observer>, websocket_endpoint &&) override;
void post(FunctionHandler&&) override;
sync_timer create_timer(std::chrono::milliseconds delay, FunctionHandler&&) override;

protected:
default_transport_configuraton m_configuration;
default_transport_configuration m_configuration;
private:
void initialize();
std::shared_ptr<::realm::sync::SyncSocketProvider> m_provider;
};
}
Expand Down
23 changes: 8 additions & 15 deletions src/cpprealm/internal/curl/network_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <cpprealm/app.hpp>
#include <cpprealm/networking/platform_networking.hpp>

#include <realm/object-store/sync/generic_network_transport.hpp>
#include <realm/util/to_string.hpp>

#include <curl/curl.h>

Expand Down Expand Up @@ -60,15 +60,13 @@ namespace realm::networking {

static size_t curl_write_cb(char* ptr, size_t size, size_t nmemb, std::string* response)
{
REALM_ASSERT(response);
size_t realsize = size * nmemb;
response->append(ptr, realsize);
return realsize;
}

static size_t curl_header_cb(char* buffer, size_t size, size_t nitems, std::map<std::string, std::string>* response_headers)
{
REALM_ASSERT(response_headers);
std::string combined(buffer, size * nitems);
if (auto pos = combined.find(':'); pos != std::string::npos) {
std::string key = combined.substr(0, pos);
Expand Down Expand Up @@ -101,11 +99,8 @@ namespace realm::networking {
struct curl_slist* list = nullptr;

std::string response;
app::HttpHeaders response_headers;
::realm::networking::http_headers response_headers;

/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, request.url.c_str());

if (proxy_config) {
Expand Down Expand Up @@ -170,14 +165,12 @@ namespace realm::networking {

void default_http_transport::send_request_to_server(const ::realm::networking::request& request,
std::function<void(const ::realm::networking::response&)>&& completion_block) {
{
if (m_custom_http_headers) {
auto req_copy = request;
req_copy.headers.insert(m_custom_http_headers->begin(), m_custom_http_headers->end());
completion_block(do_http_request(req_copy, m_proxy_config));
return;
}
completion_block(do_http_request(request, m_proxy_config));
if (m_configuration.custom_http_headers) {
auto req_copy = request;
req_copy.headers.insert(m_configuration.custom_http_headers->begin(), m_configuration.custom_http_headers->end());
completion_block(do_http_request(req_copy, m_configuration.proxy_config));
return;
}
completion_block(do_http_request(request, m_configuration.proxy_config));
}
} // namespace realm::networking
6 changes: 5 additions & 1 deletion src/cpprealm/internal/network/network_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,13 @@ namespace realm::networking {
service.reset();
}

if (m_configuration.ssl_trust_certificate_path) {
m_ssl_context.use_certificate_chain_file(*m_configuration.ssl_trust_certificate_path);
} else {
#if REALM_INCLUDE_CERTS
m_ssl_context.use_included_certificate_roots();
m_ssl_context.use_included_certificate_roots();
#endif
}

if (url_scheme == URLScheme::HTTPS) {
socket.ssl_stream.emplace(socket, m_ssl_context, Stream::client);
Expand Down
44 changes: 27 additions & 17 deletions src/cpprealm/networking/networking.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <cpprealm/networking/networking.hpp>
#include <cpprealm/networking/platform_networking.hpp>

#include <realm/object-store/sync/generic_network_transport.hpp>
#include <realm/sync/protocol.hpp>
Expand Down Expand Up @@ -62,36 +63,45 @@ namespace realm::internal::networking {
}

::realm::sync::WebSocketEndpoint to_core_websocket_endpoint(const ::realm::networking::websocket_endpoint& ep,
const std::optional<internal::bridge::realm::sync_config::proxy_config>& pc,
const std::optional<std::map<std::string, std::string>>& custom_headers) {
const std::optional<::realm::networking::default_transport_configuration>& config) {
::realm::sync::WebSocketEndpoint core_ep;
auto uri = util::Uri(ep.url);
auto protocol = to_protocol_envelope(uri.get_scheme());

std::string userinfo, host, port;
uri.get_auth(userinfo, host, port);
core_ep.is_ssl = ::realm::sync::is_ssl(protocol);

core_ep.address = host;
core_ep.port = std::stoi(port);
if (port.empty()) {
core_ep.port = core_ep.is_ssl ? 443 : 80;
} else {
core_ep.port = std::stoi(port);
}
core_ep.path = uri.get_path() + uri.get_query();
core_ep.protocols = ep.protocols;
core_ep.is_ssl = ::realm::sync::is_ssl(protocol);

if (pc) {
core_ep.proxy = SyncConfig::ProxyConfig();
core_ep.proxy->address = pc->address;
core_ep.proxy->port = pc->port;
if (pc->username_password) {
auto userpass = util::format("%1:%2", pc->username_password->first, pc->username_password->second);
std::string encoded_userpass;
encoded_userpass.resize(realm::util::base64_encoded_size(userpass.length()));
realm::util::base64_encode(userpass, encoded_userpass);
core_ep.headers.emplace("Proxy-Authorization", util::format("Basic %1", encoded_userpass));
if (config) {
if (config->proxy_config) {
core_ep.proxy = SyncConfig::ProxyConfig();
core_ep.proxy->address = config->proxy_config->address;
core_ep.proxy->port = config->proxy_config->port;
if (config->proxy_config->username_password) {
auto userpass = util::format("%1:%2", config->proxy_config->username_password->first, config->proxy_config->username_password->second);
std::string encoded_userpass;
encoded_userpass.resize(realm::util::base64_encoded_size(userpass.length()));
realm::util::base64_encode(userpass, encoded_userpass);
core_ep.headers.emplace("Proxy-Authorization", util::format("Basic %1", encoded_userpass));
}
}

if (config->custom_http_headers) {
core_ep.headers = *config->custom_http_headers;
}
}

if (custom_headers) {
core_ep.headers = *custom_headers;
core_ep.verify_servers_ssl_certificate = config->client_validate_ssl;
core_ep.ssl_trust_certificate_path = config->ssl_trust_certificate_path;
core_ep.ssl_verify_callback = config->ssl_verify_callback;
}

return core_ep;
Expand Down
12 changes: 9 additions & 3 deletions src/cpprealm/networking/platform_networking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ namespace realm::networking {
};

default_socket_provider::default_socket_provider() {
initialize();
}

default_socket_provider::default_socket_provider(const default_transport_configuration& c) : m_configuration(c) {
initialize();
}

void default_socket_provider::initialize() {
auto user_agent_binding_info = std::string("RealmCpp/") + std::string(REALMCXX_VERSION_STRING);
auto user_agent_application_info = "";//app_id; TODO: Should we pass the app id?

Expand All @@ -77,9 +85,7 @@ namespace realm::networking {

std::unique_ptr<websocket_interface> default_socket_provider::connect(std::unique_ptr<websocket_observer> o, websocket_endpoint&& ep) {

auto core_ep = internal::networking::to_core_websocket_endpoint(ep,
m_configuration.proxy_config,
m_configuration.custom_http_headers);
auto core_ep = internal::networking::to_core_websocket_endpoint(ep, m_configuration);
auto ws_interface = m_provider->connect(std::make_unique<default_websocket_observer_core>(std::move(o)), std::move(core_ep));
return std::make_unique<default_socket>(std::move(ws_interface));
}
Expand Down
15 changes: 12 additions & 3 deletions tests/sync/flexible_sync_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
using namespace realm;

TEST_CASE("flexible_sync", "[sync]") {
auto app = realm::App(realm::App::configuration({Admin::Session::shared().cached_app_id(), Admin::Session::shared().base_url()}));
auto config = realm::App::configuration();
config.app_id = Admin::Session::shared().cached_app_id();
config.base_url = Admin::Session::shared().base_url();
auto app = realm::App(config);
SECTION("all") {
auto user = app.login(realm::App::credentials::anonymous()).get();
auto flx_sync_config = user.flexible_sync_configuration();
Expand Down Expand Up @@ -108,7 +111,10 @@ void test_set(realm::managed<T>* property, Func f,
}

TEST_CASE("set collection sync", "[set]") {
auto app = realm::App(realm::App::configuration({Admin::Session::shared().cached_app_id(), Admin::Session::shared().base_url()}));
auto config = realm::App::configuration();
config.app_id = Admin::Session::shared().cached_app_id();
config.base_url = Admin::Session::shared().base_url();
auto app = realm::App(config);
SECTION("insert") {
auto user = app.login(realm::App::credentials::anonymous()).get();
auto flx_sync_config = user.flexible_sync_configuration();
Expand Down Expand Up @@ -185,7 +191,10 @@ TEST_CASE("set collection sync", "[set]") {
}

TEST_CASE("pause_resume_sync", "[sync]") {
auto app = realm::App(realm::App::configuration({Admin::Session::shared().cached_app_id(), Admin::Session::shared().base_url()}));
auto config = realm::App::configuration();
config.app_id = Admin::Session::shared().cached_app_id();
config.base_url = Admin::Session::shared().base_url();
auto app = realm::App(config);

SECTION("pause_resume") {
auto user = app.login(realm::App::credentials::anonymous()).get();
Expand Down
Loading

0 comments on commit e244af0

Please sign in to comment.