diff --git a/.pubnub.yml b/.pubnub.yml index b28c8c55..fd1cf4ef 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,8 +1,19 @@ name: unreal-engine schema: 1 -version: 2.0.5 +version: 2.1.0 scm: github.com/pubnub/unreal-engine changelog: + - date: 2026-06-22 + version: 2.1.0 + changes: + - type: bug + text: "Fix C-Core crash during timer-list assert in callback API on Windows when closing or reconnecting during async DnsQueryEx DNS resolution." + - type: improvement + text: "Mask `SecretKey` in logs." + - type: improvement + text: "Remove `SecretKey` from global config (plugin settings), so it's not exposed in `.ini` files." + - type: improvement + text: "Make `SetAuthToken` safer, add Async option to queue `SetAuthToken` with other functions." - date: 2026-05-21 version: 2.0.5 changes: diff --git a/PubnubLibrary.uplugin b/PubnubLibrary.uplugin index c45c5eab..d1c6ae32 100644 --- a/PubnubLibrary.uplugin +++ b/PubnubLibrary.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 20, - "VersionName": "2.0.5", + "Version": 21, + "VersionName": "2.1.0", "FriendlyName": "Pubnub Unreal SDK", "Description": "Quickly add interactive features to your game that scale without building your backend infrastructure.", "Category": "Code", diff --git a/README.md b/README.md index 0afeacf5..8e722001 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,38 @@ Each PubNub API is available through Blueprints and C++ code. For further inform You can copy the Blueprints from the docs and paste them into your Unreal Editor. +## Security + +### Keys and credentials + +PubNub provides three keys per keyset: + +| Key | Safe for client builds | Purpose | +| --- | --- | --- | +| Publish Key | Yes | Publish messages | +| Subscribe Key | Yes | Subscribe to channels | +| Secret Key | **No** | Root/admin access to the entire keyset | + +The **Secret Key grants unrestricted permissions** on your keyset — publish on any channel, read history, mint or revoke PAM tokens, and modify App Context data. **Never ship a Secret Key in a game client build.** + +Global plugin settings (`Project Settings → Pubnub SDK`) store only the Publish Key and Subscribe Key. These are safe to include in `DefaultEngine.ini` and packaged client builds. + +### Recommended architecture + +**Game clients (shipped builds):** + +1. Configure only Publish Key and Subscribe Key (via plugin settings or `FPubnubConfig`). +2. Obtain a scoped PAM v3 access token from your backend. +3. Call `SetAuthToken` on the client before subscribing or publishing. + +**Dedicated servers / backend tooling:** + +1. Provide the Secret Key in `FPubnubConfig` when calling `CreatePubnubClient` — not in global plugin settings. +2. Load the Secret Key from a secure source (environment variable, server-only config, secrets manager). +3. Use `GrantToken` / `RevokeToken` / `SetSecretKey` only in server-side code. + +For more details, see the [PubNub Access Manager documentation](https://www.pubnub.com/docs/general/setup/access-manager). + ## Support If you **need help** or have a **general question**, contact [support@pubnub.com](mailto:support@pubnub.com). diff --git a/Scripts/merge_into_fab_sdk.py b/Scripts/merge_into_fab_sdk.py index 5d88a097..8346e9bb 100644 --- a/Scripts/merge_into_fab_sdk.py +++ b/Scripts/merge_into_fab_sdk.py @@ -10,13 +10,19 @@ - LICENSE (from Pubnub, or PubnubChat if Pubnub has none) Run from project root or any directory; paths are resolved from script location. -Prompts for VersionName; the merged PubnubLibrary.uplugin uses FriendlyName "PubNub Gaming SDK". +Prompts for VersionName when omitted; the merged PubnubLibrary.uplugin uses FriendlyName "PubNub Gaming SDK". + +CLI examples: + python merge_into_fab_sdk.py --version-name 1.0.2 + python merge_into_fab_sdk.py -v 1.0.2 """ from __future__ import annotations +import argparse import json import shutil +import sys from pathlib import Path @@ -63,7 +69,35 @@ def _ignore_source_dirs(_dir: Path, names: list[str]) -> list[str]: return ignored -def main() -> None: +def _prompt(label: str, *, required: bool = True) -> str: + while True: + value = input(f"{label}: ").strip() + if value or not required: + return value + print(" Value is required.") + + +def _resolve_input(label: str, arg_value: str | None, *, required: bool = True) -> str: + if arg_value is not None: + return arg_value.strip() + return _prompt(label, required=required) + + +def _build_arg_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Merge Pubnub and PubnubChat plugins into a single FAB-ready plugin.", + ) + parser.add_argument( + "-v", + "--version-name", + help="Package VersionName (e.g. 1.0.2). Prompts when omitted.", + ) + return parser + + +def main(argv: list[str] | None = None) -> None: + args = _build_arg_parser().parse_args(argv) + script_dir = Path(__file__).resolve().parent # Project root: Scripts -> Pubnub -> Plugins -> project root project_root = script_dir.parent.parent.parent @@ -83,7 +117,7 @@ def main() -> None: if not pubnub_chat_uplugin.is_file(): raise SystemExit(f"Missing {pubnub_chat_uplugin}") - version_name = input("Enter package VersionName (e.g. 1.0.2): ").strip() + version_name = _resolve_input("Enter package VersionName (e.g. 1.0.2)", args.version_name) if not version_name: raise SystemExit("VersionName is required (non-empty).") @@ -151,4 +185,8 @@ def main() -> None: if __name__ == "__main__": - main() + try: + main() + except KeyboardInterrupt: + print("\nAborted.", file=sys.stderr) + sys.exit(130) diff --git a/Scripts/prepare_for_release.py b/Scripts/prepare_for_release.py new file mode 100644 index 00000000..6e301564 --- /dev/null +++ b/Scripts/prepare_for_release.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +""" +Prepare the Pubnub Unreal SDK for release. + +Updates: + - PubnubLibrary.uplugin: increments Version (VersionName is unchanged) + - PubnubLibraryVersion.h: sets PUBNUB_LIBRARY_VERSION_{MAJOR,MINOR,PATCH} + and optionally PUBNUB_C_CORE_VERSION + - .pubnub.yml: sets top-level version (changelog entries are unchanged) + +Run from any directory; paths are resolved from script location. + +CLI examples: + python prepare_for_release.py --release-version 2.0.6 + python prepare_for_release.py -r 2.0.6 --c-core-version 7.2.4 + python prepare_for_release.py -r 2.0.6 --c-core-version +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +from pathlib import Path + + +_VERSION_PATTERN = re.compile(r"^(\d+)\.(\d+)\.(\d+)$") + + +def _parse_semver(label: str, value: str) -> tuple[int, int, int]: + match = _VERSION_PATTERN.match(value.strip()) + if not match: + raise ValueError(f"{label} must be in MAJOR.MINOR.PATCH format (e.g. 2.0.5), got: {value!r}") + return int(match.group(1)), int(match.group(2)), int(match.group(3)) + + +def _prompt(label: str, *, required: bool = True) -> str: + while True: + value = input(f"{label}: ").strip() + if value or not required: + return value + print(" Value is required.") + + +def _resolve_input(label: str, arg_value: str | None, *, required: bool = True) -> str: + if arg_value is not None: + return arg_value.strip() + return _prompt(label, required=required) + + +def _build_arg_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Prepare the Pubnub Unreal SDK for release.") + parser.add_argument( + "-r", + "--release-version", + help="Release version in MAJOR.MINOR.PATCH format. Prompts when omitted.", + ) + parser.add_argument( + "-c", + "--c-core-version", + nargs="?", + const="", + default=None, + help=( + "C-Core version in MAJOR.MINOR.PATCH format. " + "Omit the flag to prompt; pass the flag alone to skip updating." + ), + ) + return parser + + +def _update_uplugin_version(uplugin_path: Path) -> int: + with uplugin_path.open("r", encoding="utf-8") as f: + uplugin = json.load(f) + + old_version = uplugin.get("Version") + if not isinstance(old_version, int): + raise SystemExit(f"Unexpected Version field in {uplugin_path}: {old_version!r}") + + new_version = old_version + 1 + uplugin["Version"] = new_version + + with uplugin_path.open("w", encoding="utf-8", newline="\n") as f: + json.dump(uplugin, f, indent="\t") + f.write("\n") + + return new_version + + +def _update_version_header( + header_path: Path, + major: int, + minor: int, + patch: int, + c_core_version: str | None, +) -> None: + content = header_path.read_text(encoding="utf-8") + + content, count = re.subn( + r"(#define PUBNUB_LIBRARY_VERSION_MAJOR )\d+", + rf"\g<1>{major}", + content, + count=1, + ) + if count != 1: + raise SystemExit(f"Could not update PUBNUB_LIBRARY_VERSION_MAJOR in {header_path}") + + content, count = re.subn( + r"(#define PUBNUB_LIBRARY_VERSION_MINOR )\d+", + rf"\g<1>{minor}", + content, + count=1, + ) + if count != 1: + raise SystemExit(f"Could not update PUBNUB_LIBRARY_VERSION_MINOR in {header_path}") + + content, count = re.subn( + r"(#define PUBNUB_LIBRARY_VERSION_PATCH )\d+", + rf"\g<1>{patch}", + content, + count=1, + ) + if count != 1: + raise SystemExit(f"Could not update PUBNUB_LIBRARY_VERSION_PATCH in {header_path}") + + if c_core_version is not None: + content, count = re.subn( + r'(#define PUBNUB_C_CORE_VERSION ")[^"]*(")', + rf"\g<1>{c_core_version}\g<2>", + content, + count=1, + ) + if count != 1: + raise SystemExit(f"Could not update PUBNUB_C_CORE_VERSION in {header_path}") + + header_path.write_text(content, encoding="utf-8", newline="\n") + + +def _update_pubnub_yml_version(pubnub_yml_path: Path, release_version: str) -> None: + content = pubnub_yml_path.read_text(encoding="utf-8") + + # Top-level key is unindented; changelog entries use " version:". + content, count = re.subn( + r"^version: .+$", + f"version: {release_version}", + content, + count=1, + flags=re.MULTILINE, + ) + if count != 1: + raise SystemExit(f"Could not update top-level version in {pubnub_yml_path}") + + pubnub_yml_path.write_text(content, encoding="utf-8", newline="\n") + + +def main(argv: list[str] | None = None) -> None: + args = _build_arg_parser().parse_args(argv) + + script_dir = Path(__file__).resolve().parent + plugin_root = script_dir.parent + uplugin_path = plugin_root / "PubnubLibrary.uplugin" + header_path = plugin_root / "Source" / "PubnubLibrary" / "Public" / "PubnubLibraryVersion.h" + pubnub_yml_path = plugin_root / ".pubnub.yml" + + if not uplugin_path.is_file(): + raise SystemExit(f"Plugin descriptor not found: {uplugin_path}") + if not header_path.is_file(): + raise SystemExit(f"Version header not found: {header_path}") + if not pubnub_yml_path.is_file(): + raise SystemExit(f"PubNub manifest not found: {pubnub_yml_path}") + + print("Prepare Pubnub Unreal SDK for release\n") + + release_version = _resolve_input("Release version (MAJOR.MINOR.PATCH)", args.release_version) + try: + major, minor, patch = _parse_semver("Release version", release_version) + except ValueError as exc: + raise SystemExit(str(exc)) from exc + + c_core_input = _resolve_input( + "C-Core version (MAJOR.MINOR.PATCH, leave empty to skip)", + args.c_core_version, + required=False, + ) + c_core_version: str | None = None + if c_core_input: + try: + c_major, c_minor, c_patch = _parse_semver("C-Core version", c_core_input) + except ValueError as exc: + raise SystemExit(str(exc)) from exc + c_core_version = f"{c_major}.{c_minor}.{c_patch}" + + release_version_str = f"{major}.{minor}.{patch}" + + new_uplugin_version = _update_uplugin_version(uplugin_path) + _update_version_header(header_path, major, minor, patch, c_core_version) + _update_pubnub_yml_version(pubnub_yml_path, release_version_str) + + print("\nUpdated files:") + print(f" {uplugin_path}") + print(f" Version -> {new_uplugin_version} (VersionName unchanged)") + print(f" {pubnub_yml_path}") + print(f" version -> {release_version_str} (changelog unchanged)") + print(f" {header_path}") + print(f" PUBNUB_LIBRARY_VERSION -> {release_version_str}") + if c_core_version is not None: + print(f" PUBNUB_C_CORE_VERSION -> {c_core_version}") + else: + print(" PUBNUB_C_CORE_VERSION -> unchanged") + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("\nAborted.", file=sys.stderr) + sys.exit(130) diff --git a/Source/PubnubLibrary/Private/FunctionLibraries/PubnubLogUtilities.cpp b/Source/PubnubLibrary/Private/FunctionLibraries/PubnubLogUtilities.cpp index 4aa47258..43a466b8 100644 --- a/Source/PubnubLibrary/Private/FunctionLibraries/PubnubLogUtilities.cpp +++ b/Source/PubnubLibrary/Private/FunctionLibraries/PubnubLogUtilities.cpp @@ -47,6 +47,25 @@ FString UPubnubLogUtilities::LogToString(UObject* Value) return LogToString(static_cast(Value)); } +FString UPubnubLogUtilities::LogConfigToString(const FPubnubConfig& Config) +{ + FPubnubConfig ConfigToLog = Config; + ConfigToLog.SecretKey = MaskSecretKeyForLog(Config.SecretKey); + return LogToString(ConfigToLog); +} + +FString UPubnubLogUtilities::MaskSecretKeyForLog(const FString& SecretKey) +{ + if (SecretKey.IsEmpty()) + { + return SecretKey; + } + + const int32 Length = SecretKey.Len(); + const FString Prefix = SecretKey.Left(FMath::Min(8, Length)); + return FString::Printf(TEXT("%s… (len=%d)"), *Prefix, Length); +} + FString UPubnubLogUtilities::LogUStructToString(const UScriptStruct* Struct, const void* StructData) { if (!Struct || !StructData) diff --git a/Source/PubnubLibrary/Private/FunctionLibraries/PubnubUtilities.cpp b/Source/PubnubLibrary/Private/FunctionLibraries/PubnubUtilities.cpp index efd3e7d7..684da169 100644 --- a/Source/PubnubLibrary/Private/FunctionLibraries/PubnubUtilities.cpp +++ b/Source/PubnubLibrary/Private/FunctionLibraries/PubnubUtilities.cpp @@ -13,8 +13,6 @@ FPubnubConfig UPubnubUtilities::PubnubConfigFromPluginSettings(UPubnubSettings* FPubnubConfig Config; Config.PublishKey = PubnubSettings->PublishKey; Config.SubscribeKey = PubnubSettings->SubscribeKey; - Config.SecretKey = PubnubSettings->SecretKey; - Config.SetSecretKeyAutomatically = PubnubSettings->SetSecretKeyAutomatically; return Config; } diff --git a/Source/PubnubLibrary/Private/PubnubClient.cpp b/Source/PubnubLibrary/Private/PubnubClient.cpp index 989ff8ab..bd67b79c 100644 --- a/Source/PubnubLibrary/Private/PubnubClient.cpp +++ b/Source/PubnubLibrary/Private/PubnubClient.cpp @@ -784,6 +784,21 @@ void UPubnubClient::SetAuthToken(FString Token) SetAuthToken_priv(Token); } +void UPubnubClient::SetAuthTokenAsync(FString Token) +{ + PUBNUB_RETURN_IF_CLIENT_NOT_INITIALIZED(); + + TWeakObjectPtr WeakThis = MakeWeakObjectPtr(this); + + PubnubCallsThread->AddFunctionToQueue([WeakThis, Token] + { + if(!WeakThis.IsValid()) + {return;} + + WeakThis.Get()->SetAuthToken_priv(Token); + }); +} + int UPubnubClient::SetOrigin(FString Origin) { PUBNUB_RETURN_IF_CLIENT_NOT_INITIALIZED(-1); @@ -2320,7 +2335,7 @@ void UPubnubClient::InitWithConfig(UPubnubSubsystem* InPubnubSubsystem, FPubnubC LoggerManager->AddLogger(LoggerInterface); } } - PUBNUB_LOG_FUNCTION_DEBUG_TEXT(FString::Printf(TEXT("initializing pubnub client. ClientID=%d, DebugName=%s, Config=%s"), ClientID, *DebugName, *UPubnubLogUtilities::LogToString(InConfig))); + PUBNUB_LOG_FUNCTION_DEBUG_TEXT(FString::Printf(TEXT("initializing pubnub client. ClientID=%d, DebugName=%s, Config=%s"), ClientID, *DebugName, *UPubnubLogUtilities::LogConfigToString(InConfig))); SavePubnubConfig(InConfig); @@ -2416,6 +2431,11 @@ void UPubnubClient::DeinitializeClient() delete[] AuthTokenBuffer; AuthTokenBuffer = nullptr; AuthTokenLength = 0; + for (char* RetiredBuffer : RetiredAuthTokenBuffers) + { + delete[] RetiredBuffer; + } + RetiredAuthTokenBuffers.Empty(); delete[] OriginBuffer; OriginBuffer = nullptr; OriginLength = 0; @@ -3601,17 +3621,38 @@ void UPubnubClient::SetAuthToken_priv(FString Token) PUBNUB_LOG_FUNCTION_DEBUG_TEXT(FString::Printf(TEXT("set auth token called. TokenLength=%d"), Token.Len())); PUBNUB_RETURN_IF_USER_ID_NOT_SET(); - //Auth token has to be kept alive for the lifetime of the sdk, so we copy it into AuthTokenBuffer + //Lock order matches DeinitializeClient: Subscription -> Operation. + FScopeLock SubscriptionExecutionLock(&SubscriptionOperationExecutionMutex); + FScopeLock OperationLock(&PubnubOperationMutex); + + //Auth token has to be kept alive for the lifetime of the sdk; C-Core stores the pointer, not a copy. FTCHARToUTF8 Converter(*Token); - AuthTokenLength = Converter.Length(); - delete[] AuthTokenBuffer; - AuthTokenBuffer = new char[AuthTokenLength + 1]; - FMemory::Memcpy(AuthTokenBuffer, Converter.Get(), AuthTokenLength); - AuthTokenBuffer[AuthTokenLength] = '\0'; - - //This is just a setter, so no need to call it on a separate thread - pubnub_set_auth_token(ctx_pub, AuthTokenBuffer); - pubnub_set_auth_token(ctx_ee, AuthTokenBuffer); + const size_t NewLength = Converter.Length(); + + char* const NewBuffer = new char[NewLength + 1]; + FMemory::Memcpy(NewBuffer, Converter.Get(), NewLength); + NewBuffer[NewLength] = '\0'; + + char* const OldBuffer = AuthTokenBuffer; + + AuthTokenBuffer = NewBuffer; + AuthTokenLength = NewLength; + + if (ctx_pub) + { + pubnub_set_auth_token(ctx_pub, AuthTokenBuffer); + } + if (ctx_ee) + { + pubnub_set_auth_token(ctx_ee, AuthTokenBuffer); + } + + //In-flight ctx_ee subscribe I/O may still dereference OldBuffer briefly after the swap. + if (OldBuffer) + { + RetiredAuthTokenBuffers.Add(OldBuffer); + } + PUBNUB_LOG_FUNCTION_TRACE(TEXT("auth token applied to pub and ee contexts.")); } diff --git a/Source/PubnubLibrary/Public/Config/PubnubSettings.h b/Source/PubnubLibrary/Public/Config/PubnubSettings.h index d4704b4d..48a0f00d 100644 --- a/Source/PubnubLibrary/Public/Config/PubnubSettings.h +++ b/Source/PubnubLibrary/Public/Config/PubnubSettings.h @@ -17,14 +17,8 @@ class PUBNUBLIBRARY_API UPubnubSettings : public UDeveloperSettings FString PublishKey = "demo"; UPROPERTY(Config, EditAnywhere, Category = "Keys") FString SubscribeKey = "demo"; - UPROPERTY(Config, EditAnywhere, Category = "Keys") - FString SecretKey = ""; //Should Pubnub initialize automatically. If set to false, InitPubnub() has to be called manually before using other Pubnub functionalities. UPROPERTY(Config, EditAnywhere, Category = "Init") bool InitializeAutomatically = true; - - //Should Secret Key be used automatically (secret key gives host permissions to the user). If set to false, SetSecretKey needs to be called manually to give host permissions. - UPROPERTY(Config, EditAnywhere, Category = "Init") - bool SetSecretKeyAutomatically = false; }; \ No newline at end of file diff --git a/Source/PubnubLibrary/Public/FunctionLibraries/PubnubLogUtilities.h b/Source/PubnubLibrary/Public/FunctionLibraries/PubnubLogUtilities.h index 9ffb2c71..41422ac7 100644 --- a/Source/PubnubLibrary/Public/FunctionLibraries/PubnubLogUtilities.h +++ b/Source/PubnubLibrary/Public/FunctionLibraries/PubnubLogUtilities.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" +#include "PubnubStructLibrary.h" #include "PubnubLogUtilities.generated.h" UCLASS() @@ -22,6 +23,9 @@ class PUBNUBLIBRARY_API UPubnubLogUtilities : public UBlueprintFunctionLibrary static FString LogToString(const UObject* Value); static FString LogToString(UObject* Value); + /** Formats FPubnubConfig for logging, masking SecretKey to its first 8 characters plus length. */ + static FString LogConfigToString(const FPubnubConfig& Config); + template::Value, int>::Type = 0> static FString LogToString(const T& Value) { @@ -53,5 +57,6 @@ class PUBNUBLIBRARY_API UPubnubLogUtilities : public UBlueprintFunctionLibrary } private: + static FString MaskSecretKeyForLog(const FString& SecretKey); static FString LogUStructToString(const UScriptStruct* Struct, const void* StructData); }; diff --git a/Source/PubnubLibrary/Public/PubnubClient.h b/Source/PubnubLibrary/Public/PubnubClient.h index 49170d1b..b9aeea99 100644 --- a/Source/PubnubLibrary/Public/PubnubClient.h +++ b/Source/PubnubLibrary/Public/PubnubClient.h @@ -191,10 +191,11 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject FString GetUserID(); /** - * Sets the secret key for the PubNub account. Uses SecretKey provided in plugin settings. - * Don't call it manually if "SetSecretKeyAutomatically" in plugin settings is set to true. + * Applies the Secret Key from this client's FPubnubConfig to the underlying SDK context. + * Server/admin use only — never call this in shipped game clients. + * Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true. */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|AccessManager") + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only") void SetSecretKey(); @@ -790,7 +791,8 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject /** * Requests an access token from the PubNub server synchronously with the specified permissions. - * Requires SecretKey to be set. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. + * For client apps, mint tokens on your backend and distribute them via SetAuthToken. * * @Note Requires the *Access Manager* add-on to be enabled for your key in the PubNub Admin Portal * @@ -799,13 +801,15 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject * @param Permissions A struct containing all permissions that will be granted with this token. * @param Meta (Optional) metadata that will be embedded into the token. * @return FPubnubGrantTokenResult containing the operation result and granted token. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager") + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only") FPubnubGrantTokenResult GrantToken(int Ttl, FString AuthorizedUser, const FPubnubGrantTokenPermissions& Permissions, FString Meta = ""); /** * Requests an access token from the PubNub server with the specified permissions. - * Requires SecretKey to be set. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. + * For client apps, mint tokens on your backend and distribute them via SetAuthToken. * * @Note Requires the *Access Manager* add-on to be enabled for your key in the PubNub Admin Portal * @@ -814,13 +818,15 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject * @param Permissions A struct containing all permissions that will be granted with this token. * @param OnGrantTokenResponse The callback function used to handle the result. * @param Meta (Optional) metadata that will be embedded into the token. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager") + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only") void GrantTokenAsync(int Ttl, FString AuthorizedUser, const FPubnubGrantTokenPermissions& Permissions, FOnPubnubGrantTokenResponse OnGrantTokenResponse, FString Meta = ""); /** * Requests an access token from the PubNub server with the specified permissions. - * Requires SecretKey to be set. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. + * For client apps, mint tokens on your backend and distribute them via SetAuthToken. * * @Note Requires the *Access Manager* add-on to be enabled for your key in the PubNub Admin Portal * @@ -829,40 +835,47 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject * @param Permissions A struct containing all permissions that will be granted with this token. * @param NativeCallback The callback function used to handle the result. Delegate in native form that can accept lambdas. * @param Meta (Optional) metadata that will be embedded into the token. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ void GrantTokenAsync(int Ttl, FString AuthorizedUser, const FPubnubGrantTokenPermissions& Permissions, FOnPubnubGrantTokenResponseNative NativeCallback, FString Meta = ""); /** * Revokes a previously granted access token synchronously. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. * * @Note Requires the *Revoke v3 Token* in *Access Manager* section to be enabled for your key in the PubNub Admin Portal * * @param Token The access token to revoke. * @return FPubnubOperationResult containing the operation result. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager") + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only") FPubnubOperationResult RevokeToken(FString Token); /** * Revokes a previously granted access token. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. * * @Note Requires the *Revoke v3 Token* in *Access Manager* section to be enabled for your key in the PubNub Admin Portal * * @param Token The access token to revoke. * @param OnRevokeTokenResponse (Optional) Delegate to listen for the operation result. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager", meta = (AutoCreateRefTerm = "OnRevokeTokenResponse")) + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only", meta = (AutoCreateRefTerm = "OnRevokeTokenResponse")) void RevokeTokenAsync(FString Token, FOnPubnubRevokeTokenResponse OnRevokeTokenResponse); /** * Revokes a previously granted access token. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. * * @Note Requires the *Revoke v3 Token* in *Access Manager* section to be enabled for your key in the PubNub Admin Portal * * @param Token The access token to revoke. * @param NativeCallback (Optional) Delegate to listen for the operation result. Delegate in native form that can accept lambdas. * Can be skipped if operation result is not needed. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ void RevokeTokenAsync(FString Token, FOnPubnubRevokeTokenResponseNative NativeCallback = nullptr); @@ -878,14 +891,29 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject /** - * This method is used by the client devices to update the authentication token granted by the server. - * - * @param Token Existing token with embedded permissions. + * Sets the PAM v3 access token for this client on the calling thread. The underlying update is + * immediate (no network call), but this variant blocks the caller until the token pointer is + * swapped in both C-Core contexts. + * Use this in shipped game clients after your backend mints a scoped token. * + * @param Token PAM v3 access token with embedded permissions, minted server-side. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager") void SetAuthToken(FString Token); + /** + * Sets the PAM v3 access token for this client. The underlying update is immediate (no network + * call), but this variant queues the work on the PubNub operations thread so it is serialized + * with other async PubNub API calls. + * Use this in shipped game clients after your backend mints a scoped token. + * + * @param Token PAM v3 access token with embedded permissions, minted server-side. + * @see https://www.pubnub.com/docs/general/setup/access-manager + */ + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager") + void SetAuthTokenAsync(FString Token); + /** * Sets the origin for the PubNub client. * @@ -2686,6 +2714,8 @@ class PUBNUBLIBRARY_API UPubnubClient : public UObject //Auth token has to be kept alive for the lifetime of the sdk, so this is the container for it char* AuthTokenBuffer = nullptr; size_t AuthTokenLength = 0; + //Previous auth token buffers retired after a swap; freed at deinit because ctx_ee may still read them briefly + TArray RetiredAuthTokenBuffers; //Origin has to be kept alive for the lifetime of the sdk, so this is the container for it char* OriginBuffer = nullptr; diff --git a/Source/PubnubLibrary/Public/PubnubLibraryVersion.h b/Source/PubnubLibrary/Public/PubnubLibraryVersion.h index ddacf1bb..411c5a86 100644 --- a/Source/PubnubLibrary/Public/PubnubLibraryVersion.h +++ b/Source/PubnubLibrary/Public/PubnubLibraryVersion.h @@ -3,10 +3,10 @@ #pragma once /** C PubNub SDK (ThirdParty) version string, e.g. 7.1.3. Keep in sync with PUBNUB_SDK_VERSION in core/pubnub_version_internal.h. */ -#define PUBNUB_C_CORE_VERSION "7.2.3" +#define PUBNUB_C_CORE_VERSION "7.2.4" /** Keep in sync with VersionName in PubnubLibrary.uplugin. Used by dependent plugins (e.g. PubnubChat) for version checks. Two digits per component (max 99 each). */ #define PUBNUB_LIBRARY_VERSION_MAJOR 2 -#define PUBNUB_LIBRARY_VERSION_MINOR 0 -#define PUBNUB_LIBRARY_VERSION_PATCH 5 +#define PUBNUB_LIBRARY_VERSION_MINOR 1 +#define PUBNUB_LIBRARY_VERSION_PATCH 0 #define PUBNUB_LIBRARY_VERSION ((PUBNUB_LIBRARY_VERSION_MAJOR * 10000) + (PUBNUB_LIBRARY_VERSION_MINOR * 100) + PUBNUB_LIBRARY_VERSION_PATCH) diff --git a/Source/PubnubLibrary/Public/PubnubStructLibrary.h b/Source/PubnubLibrary/Public/PubnubStructLibrary.h index 55d829e5..6c6c0109 100644 --- a/Source/PubnubLibrary/Public/PubnubStructLibrary.h +++ b/Source/PubnubLibrary/Public/PubnubStructLibrary.h @@ -32,6 +32,13 @@ struct FPubnubLoggerConfig TArray InitialLoggers; }; +/** + * Configuration for a PubNub client instance. + * + * For shipped game clients, use only PublishKey and SubscribeKey here, then call SetAuthToken with a + * PAM v3 token minted by your backend. Do not ship a Secret Key in client builds. + * See https://www.pubnub.com/docs/general/setup/access-manager + */ USTRUCT(BlueprintType) struct FPubnubConfig { @@ -41,17 +48,25 @@ struct FPubnubConfig UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString PublishKey = "demo"; /** Specifies the Subscribe Key to be used for subscribing to a channel. You can get one from the PubNub Admin Portal. */ UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString SubscribeKey = "demo"; - /** Secret key from Admin Portal. When set, it gives user root permissions for Access Manager. - * To use it set SetSecretKeyAutomatically to true or call SetSecretKey function. + /** + * Secret Key from the Admin Portal. Grants unrestricted root permissions on the keyset. + * Server/admin use only — never ship this value in client builds. Provide it when creating a + * dedicated-server or backend client via FPubnubConfig, not via global plugin settings. + * Set SetSecretKeyAutomatically to true or call SetSecretKey after initialization. + * For client apps, use PAM v3 tokens minted server-side and SetAuthToken instead. + * See https://www.pubnub.com/docs/general/setup/access-manager */ - UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString SecretKey = ""; + UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub|Server Only") FString SecretKey = ""; /** Identify the user or the device that connects to PubNub. Necessary for all PubNub operations. If provided, this UsedID will be set automatically. * If you keep this field empty, use SetUserID before the first PubNub operation. * It's a UTF-8 encoded string of up to 92 alphanumeric characters. */ UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString UserID = ""; - /** If true SecretKey will be set during Initialization phase. Secret key gives user root permissions for Access Manager */ - UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") bool SetSecretKeyAutomatically = false; + /** + * If true, SecretKey is applied during client initialization. Server/admin use only. + * Do not enable this in shipped game clients. + */ + UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub|Server Only") bool SetSecretKeyAutomatically = false; /** Logger setup used during client initialization. */ UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub|Logger") FPubnubLoggerConfig LoggerConfig; diff --git a/Source/PubnubLibrary/Public/PubnubSubsystem.h b/Source/PubnubLibrary/Public/PubnubSubsystem.h index 86a35e27..d358c0a6 100644 --- a/Source/PubnubLibrary/Public/PubnubSubsystem.h +++ b/Source/PubnubLibrary/Public/PubnubSubsystem.h @@ -204,10 +204,13 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem FString GetUserID(); /** - * Sets the secret key for the PubNub account. Uses SecretKey provided in plugin settings. - * Don't call it manually if "SetSecretKeyAutomatically" in plugin settings is set to true. + * Applies the Secret Key from the default client's FPubnubConfig to the underlying SDK context. + * Server/admin use only — never call this in shipped game clients. + * Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true. + * For client apps, use PAM v3 tokens minted server-side and SetAuthToken instead. + * See https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Init", meta=(DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).")) + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only", meta=(DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).")) void SetSecretKey(); /** @@ -601,7 +604,8 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem /** * Requests an access token from the PubNub server with the specified permissions. - * Requires SecretKey to be set. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. + * For client apps, mint tokens on your backend and distribute them via SetAuthToken. * * @Note Requires the *Access Manager* add-on to be enabled for your key in the PubNub Admin Portal * @@ -610,13 +614,15 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem * @param Permissions A struct containing all permissions that will be granted with this token. * @param OnGrantTokenResponse The callback function used to handle the result. * @param Meta (Optional) metadata that will be embedded into the token. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager", meta=(DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).")) + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only", meta=(DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).")) void GrantToken(int Ttl, FString AuthorizedUser, const FPubnubGrantTokenPermissions& Permissions, FOnGrantTokenResponse OnGrantTokenResponse, FString Meta = ""); /** * Requests an access token from the PubNub server with the specified permissions. - * Requires SecretKey to be set. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. + * For client apps, mint tokens on your backend and distribute them via SetAuthToken. * * @Note Requires the *Access Manager* add-on to be enabled for your key in the PubNub Admin Portal * @@ -625,28 +631,33 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem * @param Permissions A struct containing all permissions that will be granted with this token. * @param NativeCallback The callback function used to handle the result. Delegate in native form that can accept lambdas. * @param Meta (Optional) metadata that will be embedded into the token. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ void GrantToken(int Ttl, FString AuthorizedUser, const FPubnubGrantTokenPermissions& Permissions, FOnGrantTokenResponseNative NativeCallback, FString Meta = ""); /** * Revokes a previously granted access token. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. * * @Note Requires the *Revoke v3 Token* in *Access Manager* section to be enabled for your key in the PubNub Admin Portal * * @param Token The access token to revoke. * @param OnRevokeTokenResponse (Optional) Delegate to listen for the operation result. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ - UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager", meta = (DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).", AutoCreateRefTerm = "OnRevokeTokenResponse")) + UFUNCTION(BlueprintCallable, Category = "Pubnub|Access Manager|Server Only", meta = (DeprecatedFunction, DeprecationMessage="This UPubnubSubsystem API is deprecated. Use UPubnubClient instead: get or create a client with CreatePubnubClient or GetPubnubClient, then call the equivalent method on that client (on UPubnubClient, async APIs use the *Async suffix).", AutoCreateRefTerm = "OnRevokeTokenResponse")) void RevokeToken(FString Token, FOnRevokeTokenResponse OnRevokeTokenResponse); /** * Revokes a previously granted access token. + * Server/admin use only — requires SecretKey in FPubnubConfig. Never call from shipped game clients. * * @Note Requires the *Revoke v3 Token* in *Access Manager* section to be enabled for your key in the PubNub Admin Portal * * @param Token The access token to revoke. * @param NativeCallback (Optional) Delegate to listen for the operation result. Delegate in native form that can accept lambdas. * Can be skipped if operation result is not needed. + * @see https://www.pubnub.com/docs/general/setup/access-manager */ void RevokeToken(FString Token, FOnRevokeTokenResponseNative NativeCallback = nullptr); diff --git a/Source/PubnubLibraryTests/Private/Samples/Sample_AccessManager.cpp b/Source/PubnubLibraryTests/Private/Samples/Sample_AccessManager.cpp index c4d80a49..93d9caca 100644 --- a/Source/PubnubLibraryTests/Private/Samples/Sample_AccessManager.cpp +++ b/Source/PubnubLibraryTests/Private/Samples/Sample_AccessManager.cpp @@ -12,6 +12,10 @@ * * The samples assume that in Pubnub SDK settings sections in ProjectSettings following fields are set: * PublishKey and SubscribeKey have correct keys, InitializeAutomatically is true. + * + * SERVER API WARNING: Samples that use SetSecretKey, GrantToken, or RevokeToken are for dedicated servers + * or backend tooling only. Do not use these APIs in shipped game clients. For client apps, mint PAM v3 tokens + * on your backend and distribute them via SetAuthToken instead. */ // NOTE: Comments marked with `ACTION REQUIRED` indicate lines you must change/adjust. @@ -52,9 +56,9 @@ void ASample_AccessManager::GrantTokenSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to grant token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and GrantToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Create the permissions structure @@ -101,9 +105,9 @@ void ASample_AccessManager::GrantTokenWithLambdaSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to grant token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and GrantToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Create the permissions structure @@ -146,9 +150,9 @@ void ASample_AccessManager::GrantTokenVariousResourcesSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to grant token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and GrantToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Create the permissions structure @@ -224,9 +228,9 @@ void ASample_AccessManager::GrantTokenRegexSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to grant token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and GrantToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Create the permissions structure @@ -272,9 +276,9 @@ void ASample_AccessManager::GrantTokenComplexSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to grant token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and GrantToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Create the permissions structure @@ -356,9 +360,9 @@ void ASample_AccessManager::RevokeTokenSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to revoke token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and RevokeToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Revoke the token @@ -377,9 +381,9 @@ void ASample_AccessManager::RevokeTokenWithResultSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to revoke token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and RevokeToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Bind response delegate @@ -416,9 +420,9 @@ void ASample_AccessManager::RevokeTokenWithResultLambdaSample() //Assumes PubnubClient is created and UserID is set - //Set secret key to be able to revoke token - //Make sure proper SecretKey is set in PubnubSDK PluginSettings - //This is not required if "SetSecretKeyAutomatically" is set to true in PubnubSDK PluginSettings + // SERVER ONLY: SetSecretKey and RevokeToken require a Secret Key and must not be used in shipped game clients. + // Use only in dedicated servers or backend tooling. For client apps, mint PAM v3 tokens server-side and use SetAuthToken. + // Provide SecretKey in FPubnubConfig when creating the client, or set SetSecretKeyAutomatically to true in the config. PubnubClient->SetSecretKey(); // Bind lambda to response delegate diff --git a/Source/ThirdParty/sdk/Include/core/pubnub_version_internal.h b/Source/ThirdParty/sdk/Include/core/pubnub_version_internal.h index 2e357771..a8988fb1 100644 --- a/Source/ThirdParty/sdk/Include/core/pubnub_version_internal.h +++ b/Source/ThirdParty/sdk/Include/core/pubnub_version_internal.h @@ -3,7 +3,7 @@ #define INC_PUBNUB_VERSION_INTERNAL -#define PUBNUB_SDK_VERSION "7.2.3" +#define PUBNUB_SDK_VERSION "7.2.4" #endif /* !defined INC_PUBNUB_VERSION_INTERNAL */ diff --git a/Source/ThirdParty/sdk/lib/IOS/libpubnub.a b/Source/ThirdParty/sdk/lib/IOS/libpubnub.a index 5bff609f..cde21197 100644 Binary files a/Source/ThirdParty/sdk/lib/IOS/libpubnub.a and b/Source/ThirdParty/sdk/lib/IOS/libpubnub.a differ diff --git a/Source/ThirdParty/sdk/lib/MacOS/libpubnub.a b/Source/ThirdParty/sdk/lib/MacOS/libpubnub.a index 53a2a7d8..f4ea52dd 100644 Binary files a/Source/ThirdParty/sdk/lib/MacOS/libpubnub.a and b/Source/ThirdParty/sdk/lib/MacOS/libpubnub.a differ diff --git a/Source/ThirdParty/sdk/lib/arm64/libpubnub.a b/Source/ThirdParty/sdk/lib/arm64/libpubnub.a index f3753de9..cb91e543 100644 Binary files a/Source/ThirdParty/sdk/lib/arm64/libpubnub.a and b/Source/ThirdParty/sdk/lib/arm64/libpubnub.a differ diff --git a/Source/ThirdParty/sdk/lib/linux/libpubnub.a b/Source/ThirdParty/sdk/lib/linux/libpubnub.a index b5ca0c40..4fe0cec2 100644 Binary files a/Source/ThirdParty/sdk/lib/linux/libpubnub.a and b/Source/ThirdParty/sdk/lib/linux/libpubnub.a differ diff --git a/Source/ThirdParty/sdk/lib/win64/pubnub.lib b/Source/ThirdParty/sdk/lib/win64/pubnub.lib index c51c1803..b2753d29 100644 Binary files a/Source/ThirdParty/sdk/lib/win64/pubnub.lib and b/Source/ThirdParty/sdk/lib/win64/pubnub.lib differ