diff --git a/src/js_sync.hpp b/src/js_sync.hpp index ad136bf7..3364aad9 100644 --- a/src/js_sync.hpp +++ b/src/js_sync.hpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "event_loop_dispatcher.hpp" #include "platform.hpp" @@ -225,6 +227,88 @@ private: const Protected m_func; }; +template +class SSLVerifyCallbackSyncThreadFunctor { +public: + SSLVerifyCallbackSyncThreadFunctor(typename T::Context ctx, typename T::Function ssl_verify_func) + : m_ctx(Context::get_global_context(ctx)) + , m_func(ctx, ssl_verify_func) + , m_event_loop_dispatcher {SSLVerifyCallbackSyncThreadFunctor::main_loop_handler} + , m_mutex{new std::mutex} + , m_cond_var{new std::condition_variable} + { + } + + bool operator ()(const std::string& server_address, sync::Session::port_type server_port, const char* pem_data, size_t pem_size, int preverify_ok, int depth) + { + const std::string pem_certificate {pem_data, pem_size}; + + { + std::lock_guard lock {*m_mutex}; + m_ssl_certificate_callback_done = false; + } + + m_event_loop_dispatcher(this, server_address, server_port, pem_certificate, preverify_ok, depth); + + bool ssl_certificate_accepted = false; + { + std::unique_lock lock(*m_mutex); + m_cond_var->wait(lock, [this] { return this->m_ssl_certificate_callback_done; }); + ssl_certificate_accepted = m_ssl_certificate_accepted; + } + + return ssl_certificate_accepted; + } + + static void main_loop_handler(SSLVerifyCallbackSyncThreadFunctor* this_object, + const std::string& server_address, + sync::Session::port_type server_port, + const std::string& pem_certificate, + int preverify_ok, + int depth) + { + HANDLESCOPE + + const Protected& ctx = this_object->m_ctx; + + typename T::Object ssl_certificate_object = Object::create_empty(ctx); + Object::set_property(ctx, ssl_certificate_object, "serverAddress", Value::from_string(ctx, server_address)); + Object::set_property(ctx, ssl_certificate_object, "serverPort", Value::from_number(ctx, double(server_port))); + Object::set_property(ctx, ssl_certificate_object, "pemCertificate", Value::from_string(ctx, pem_certificate)); + Object::set_property(ctx, ssl_certificate_object, "preverifyOk", Value::from_number(ctx, double(preverify_ok))); + Object::set_property(ctx, ssl_certificate_object, "depth", Value::from_number(ctx, double(depth))); + + const int argc = 1; + typename T::Value arguments[argc] = { ssl_certificate_object }; + typename T::Value ret_val = Function::callback(ctx, this_object->m_func, typename T::Object(), 1, arguments); + bool ret_val_bool = Value::to_boolean(ctx, ret_val); + + { + std::lock_guard lock {*this_object->m_mutex}; + this_object->m_ssl_certificate_callback_done = true; + this_object->m_ssl_certificate_accepted = ret_val_bool; + } + + this_object->m_cond_var->notify_one(); + }; + + +private: + const Protected m_ctx; + const Protected m_func; + EventLoopDispatcher* this_object, + const std::string& server_address, + sync::Session::port_type server_port, + const std::string& pem_certificate, + int preverify_ok, + int depth)> m_event_loop_dispatcher; + bool m_ssl_certificate_callback_done = false; + bool m_ssl_certificate_accepted = false; + std::shared_ptr m_mutex; + std::shared_ptr m_cond_var; +}; + + template void UserClass::session_for_on_disk_path(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { auto user = *get_internal>(this_object); @@ -512,12 +596,20 @@ void SyncClass::populate_sync_config(ContextType ctx, ObjectType realm_constr ssl_trust_certificate_path = util::none; } + std::function ssl_verify_callback; + ValueType ssl_verify_func = Object::get_property(ctx, sync_config_object, "ssl_verify_callback"); + if (!Value::is_undefined(ctx, ssl_verify_func)) { + SSLVerifyCallbackSyncThreadFunctor ssl_verify_functor {ctx, Value::validated_to_function(ctx, ssl_verify_func)}; + ssl_verify_callback = std::move(ssl_verify_functor); + } + // FIXME - use make_shared config.sync_config = std::shared_ptr(new SyncConfig{shared_user, raw_realm_url, SyncSessionStopPolicy::AfterChangesUploaded, std::move(bind), std::move(error_handler), nullptr, util::none, - client_validate_ssl, ssl_trust_certificate_path}); + client_validate_ssl, ssl_trust_certificate_path, + std::move(ssl_verify_callback)}); config.schema_mode = SchemaMode::Additive; config.path = realm::SyncManager::shared().path_for_realm(shared_user->identity(), raw_realm_url);