diff --git a/Source/SocketIOClient/Private/SocketIOClient.cpp b/Source/SocketIOClient/Private/SocketIOClient.cpp index 8aa3239d..7595d233 100644 --- a/Source/SocketIOClient/Private/SocketIOClient.cpp +++ b/Source/SocketIOClient/Private/SocketIOClient.cpp @@ -15,8 +15,8 @@ class FSocketIOClientModule : public ISocketIOClientModule { public: //virtual TSharedPtr NewValidNativePointer() override; - virtual TSharedPtr NewValidNativePointer() override; - virtual TSharedPtr ValidSharedNativePointer(FString SharedId) override; + virtual TSharedPtr NewValidNativePointer(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) override; + virtual TSharedPtr ValidSharedNativePointer(FString SharedId, const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) override; void ReleaseNativePointer(TSharedPtr PointerToRelease) override; /** IModuleInterface implementation */ @@ -79,9 +79,9 @@ void FSocketIOClientModule::ShutdownModule() PluginNativePointers.Empty(); } -TSharedPtr FSocketIOClientModule::NewValidNativePointer() +TSharedPtr FSocketIOClientModule::NewValidNativePointer(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { - TSharedPtr NewPointer = MakeShareable(new FSocketIONative); + TSharedPtr NewPointer = MakeShareable(new FSocketIONative(bShouldUseTlsLibraries, bShouldSkipCertificateVerification)); PluginNativePointers.Add(NewPointer); @@ -90,7 +90,7 @@ TSharedPtr FSocketIOClientModule::NewValidNativePointer() return NewPointer; } -TSharedPtr FSocketIOClientModule::ValidSharedNativePointer(FString SharedId) +TSharedPtr FSocketIOClientModule::ValidSharedNativePointer(FString SharedId, const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { //Found key? return it if (SharedNativePointers.Contains(SharedId)) @@ -100,7 +100,7 @@ TSharedPtr FSocketIOClientModule::ValidSharedNativePointer(FStr //Otherwise request a new id and return it else { - TSharedPtr NewNativePtr = NewValidNativePointer(); + TSharedPtr NewNativePtr = NewValidNativePointer(bShouldUseTlsLibraries, bShouldSkipCertificateVerification); SharedNativePointers.Add(SharedId, NewNativePtr); AllSharedPtrs.Add(NewNativePtr); return NewNativePtr; diff --git a/Source/SocketIOClient/Private/SocketIOClientComponent.cpp b/Source/SocketIOClient/Private/SocketIOClientComponent.cpp index 95864ef8..011e086a 100644 --- a/Source/SocketIOClient/Private/SocketIOClientComponent.cpp +++ b/Source/SocketIOClient/Private/SocketIOClientComponent.cpp @@ -11,6 +11,8 @@ USocketIOClientComponent::USocketIOClientComponent(const FObjectInitializer &init) : UActorComponent(init) { + bShouldUseTlsLibraries = false; + bShouldSkipCertificateVerification = false; bShouldAutoConnect = true; bWantsInitializeComponent = true; bAutoActivate = true; @@ -63,14 +65,14 @@ void USocketIOClientComponent::InitializeNative() { if (bPluginScopedConnection) { - NativeClient = ISocketIOClientModule::Get().ValidSharedNativePointer(PluginScopedId); + NativeClient = ISocketIOClientModule::Get().ValidSharedNativePointer(PluginScopedId, bShouldUseTlsLibraries, bShouldSkipCertificateVerification); //Enforcement: This is the default FSocketIONative option value, but this component depends on it being true. NativeClient->bCallbackOnGameThread = true; } else { - NativeClient = ISocketIOClientModule::Get().NewValidNativePointer(); + NativeClient = ISocketIOClientModule::Get().NewValidNativePointer(bShouldUseTlsLibraries, bShouldSkipCertificateVerification); } SetupCallbacks(); diff --git a/Source/SocketIOClient/Private/SocketIONative.cpp b/Source/SocketIOClient/Private/SocketIONative.cpp index c8d160fc..f723f525 100644 --- a/Source/SocketIOClient/Private/SocketIONative.cpp +++ b/Source/SocketIOClient/Private/SocketIONative.cpp @@ -9,7 +9,7 @@ #include "sio_message.h" #include "sio_socket.h" -FSocketIONative::FSocketIONative() +FSocketIONative::FSocketIONative(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { PrivateClient = nullptr; AddressAndPort = TEXT("http://localhost:3000"); //default to 127.0.0.1 @@ -20,7 +20,7 @@ FSocketIONative::FSocketIONative() ReconnectionDelay = 5000; bCallbackOnGameThread = true; - PrivateClient = MakeShareable(new sio::client); + PrivateClient = MakeShareable(new sio::client(bShouldUseTlsLibraries, bShouldSkipCertificateVerification)); ClearCallbacks(); } diff --git a/Source/SocketIOClient/Public/SocketIOClient.h b/Source/SocketIOClient/Public/SocketIOClient.h index fd50c835..0677ac08 100644 --- a/Source/SocketIOClient/Public/SocketIOClient.h +++ b/Source/SocketIOClient/Public/SocketIOClient.h @@ -35,12 +35,12 @@ class SOCKETIOCLIENT_API ISocketIOClientModule : public IModuleInterface /** * Request a new plugin scoped pointer as a shared ptr. */ - virtual TSharedPtr NewValidNativePointer() { return nullptr; }; + virtual TSharedPtr NewValidNativePointer(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { return nullptr; }; /** * Request a shared FSocketIONative instance for a given id. May allocate a new pointer. */ - virtual TSharedPtr ValidSharedNativePointer(FString SharedId) { return nullptr; }; + virtual TSharedPtr ValidSharedNativePointer(FString SharedId, const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { return nullptr; }; /** * Releases the given plugin scoped pointer using a background thread diff --git a/Source/SocketIOClient/Public/SocketIOClientComponent.h b/Source/SocketIOClient/Public/SocketIOClientComponent.h index 77714a73..52b2dde5 100644 --- a/Source/SocketIOClient/Public/SocketIOClientComponent.h +++ b/Source/SocketIOClient/Public/SocketIOClientComponent.h @@ -60,10 +60,28 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent FSIOCEventSignature OnFail; - /** Default connection address string in form e.g. http://localhost:80. */ + /** + * Default connection address string in form e.g. http://localhost:80. + * If HTTPS/WSS is provided and TLS/SSL libraries aren't compiled, HTTP/WS + * will be used. + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SocketIO Connection Properties") FString AddressAndPort; + /** + * Whether or not to use the TLS/SSL libraries for the connection. + * Ignored if TLS/SSL libraries are not compiled in (SIO_TLS isn't defined) + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SocketIO Connection Properties") + bool bShouldUseTlsLibraries; + + /** + * If `Should Use TLS Libraries` is set to true, setting this to true + * will not the authenticity of the SSL certificate (i.e. asio::ssl::verify_none) + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SocketIO Connection Properties") + bool bShouldSkipCertificateVerification; + /** If true will auto-connect on begin play to address specified in AddressAndPort. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SocketIO Connection Properties") bool bShouldAutoConnect; diff --git a/Source/SocketIOClient/Public/SocketIONative.h b/Source/SocketIOClient/Public/SocketIONative.h index d14b11d4..6e9d78ce 100644 --- a/Source/SocketIOClient/Public/SocketIONative.h +++ b/Source/SocketIOClient/Public/SocketIONative.h @@ -95,7 +95,7 @@ class SOCKETIOCLIENT_API FSocketIONative /** If true, all callbacks and events will occur on game thread. Default true. */ bool bCallbackOnGameThread; - FSocketIONative(); + FSocketIONative(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification); /** * Connect to a socket.io server, optional method if auto-connect is set to true. diff --git a/Source/SocketIOLib/Private/internal/sio_client_impl.cpp b/Source/SocketIOLib/Private/internal/sio_client_impl.cpp index 3e3bedf8..e549de69 100644 --- a/Source/SocketIOLib/Private/internal/sio_client_impl.cpp +++ b/Source/SocketIOLib/Private/internal/sio_client_impl.cpp @@ -49,8 +49,7 @@ namespace sio { /*************************public:*************************/ template - client_impl::client_impl(const string& uri) : - m_base_url(uri), + client_impl::client_impl() : m_ping_interval(0), m_ping_timeout(0), m_network_thread(), @@ -674,7 +673,7 @@ namespace sio #if SIO_TLS typedef websocketpp::lib::shared_ptr context_ptr; - static context_ptr on_tls_init(connection_hdl conn) + static context_ptr on_tls_init(int verify_mode, connection_hdl conn) { context_ptr ctx = context_ptr(new asio::ssl::context(asio::ssl::context::tlsv12)); asio::error_code ec; @@ -686,15 +685,24 @@ namespace sio cerr << "Init tls failed,reason:" << ec.message() << endl; } - ctx->set_verify_mode(asio::ssl::verify_none); + if (verify_mode >= 0) + { + ctx->set_verify_mode(verify_mode); + } return ctx; } + template + void client_impl::set_verify_mode(int mode) + { + verify_mode = mode; + } + template<> void client_impl::template_init() { - m_client.set_tls_init_handler(&on_tls_init); + m_client.set_tls_init_handler(std::bind(&on_tls_init, verify_mode, std::placeholders::_1)); } #endif @@ -705,12 +713,14 @@ namespace sio { return false; } -#if SIO_TLS else if (uo.get_scheme() == "https" || uo.get_scheme() == "wss") { +#if SIO_TLS return true; - } +#else + return false; #endif + } else { throw std::runtime_error("unsupported URI scheme"); diff --git a/Source/SocketIOLib/Private/internal/sio_client_impl.h b/Source/SocketIOLib/Private/internal/sio_client_impl.h index 6d20dab7..797e19b8 100644 --- a/Source/SocketIOLib/Private/internal/sio_client_impl.h +++ b/Source/SocketIOLib/Private/internal/sio_client_impl.h @@ -85,7 +85,7 @@ typedef websocketpp::client client_type_tls; #endif - struct client_impl_base { + class client_impl_base { public: enum con_state @@ -97,6 +97,7 @@ }; client_impl_base() {} + virtual void template_init() {}; virtual ~client_impl_base() {} @@ -134,15 +135,15 @@ virtual void set_logs_quiet() {}; virtual void set_logs_verbose() {}; - virtual void set_logs_default() = 0; - virtual void set_logs_quiet() = 0; - virtual void set_logs_verbose() = 0; - virtual std::string const& get_current_url() const = 0; // used for selecting whether or not to use TLS static bool is_tls(const std::string& uri); +#if SIO_TLS + virtual void set_verify_mode(int mode) {}; +#endif + protected: // Wrap protected member functions of sio::socket because only client_impl_base is friended. sio::socket* new_socket(std::string const&); @@ -158,8 +159,8 @@ public: typedef typename client_type::message_ptr message_ptr; - client_impl(const std::string& uri = std::string()); - void template_init(); // template-specific initialization + client_impl(); + void template_init() override; // template-specific initialization ~client_impl(); @@ -192,6 +193,10 @@ void set_logs_verbose(); +#if SIO_TLS + void set_verify_mode(int mode) override; +#endif + public: void send(packet& p); @@ -295,6 +300,10 @@ //passthrough path of plugin std::string m_path; +#if SIO_TLS + int verify_mode = -1; +#endif + friend class sio::client; friend class sio::socket; }; diff --git a/Source/SocketIOLib/Private/sio_client.cpp b/Source/SocketIOLib/Private/sio_client.cpp index 6350ac9e..79b0ab20 100644 --- a/Source/SocketIOLib/Private/sio_client.cpp +++ b/Source/SocketIOLib/Private/sio_client.cpp @@ -36,18 +36,31 @@ namespace sio { } - client::client(const std::string& uri) + client::client(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification) { - if (!client_impl_base::is_tls(uri)) + if (bShouldUseTlsLibraries) { - m_impl = new client_impl(uri); - } #if SIO_TLS + m_impl = new client_impl(); + + if (bShouldSkipCertificateVerification) + { + m_impl->set_verify_mode(asio::ssl::verify_none); + } + else + { + m_impl->set_verify_mode(asio::ssl::verify_peer); + // TODO: add verify CA chain file + } + m_impl->template_init(); // reinitialize based on the new mode +#else + m_impl = new client_impl(); +#endif + } else { - m_impl = new client_impl(uri); + m_impl = new client_impl(); } -#endif } client::~client() diff --git a/Source/SocketIOLib/Public/sio_client.h b/Source/SocketIOLib/Public/sio_client.h index 5e81610b..ebc873af 100644 --- a/Source/SocketIOLib/Public/sio_client.h +++ b/Source/SocketIOLib/Public/sio_client.h @@ -34,7 +34,7 @@ namespace sio client(); - client(const std::string& uri); + client(const bool bShouldUseTlsLibraries, const bool bShouldSkipCertificateVerification); ~client();