Skip to content

Commit f1ac256

Browse files
Merge pull request #199 from immutable/dx-3674
chore: PKCE for Windows support (alpha release)
2 parents d2db0c6 + 7da0fa4 commit f1ac256

File tree

8 files changed

+1072
-86
lines changed

8 files changed

+1072
-86
lines changed

Source/Immutable/Private/Immutable/Actions/ImtblConnectImxAsyncAction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void UImtblConnectionAsyncActions::DoConnect(TWeakObjectPtr<UImtblJSConnector> J
7373
{
7474
if (bIsPKCE)
7575
{
76-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
76+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
7777
Passport->ConnectPKCE(bIsConnectImx, UImmutablePassport::FImtblPassportResponseDelegate::CreateUObject(this, &UImtblConnectionAsyncActions::OnConnect));
7878
#endif
7979
}

Source/Immutable/Private/Immutable/ImmutableDataTypes.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
#include "Immutable/ImmutableDataTypes.h"
44

5+
#if PLATFORM_WINDOWS
6+
#include "Immutable/Windows/ImmutablePKCEWindows.h"
7+
#endif
58

69
FString FImmutablePassportInitData::ToJsonString() const
710
{
@@ -29,20 +32,20 @@ FString FImmutablePassportInitData::ToJsonString() const
2932
TOptional<FImmutablePassportInitDeviceFlowData> FImmutablePassportInitDeviceFlowData::FromJsonString(const FString& JsonObjectString)
3033
{
3134
FImmutablePassportInitDeviceFlowData PassportConnect;
32-
35+
3336
if (!FJsonObjectConverter::JsonObjectStringToUStruct(JsonObjectString, &PassportConnect, 0, 0))
3437
{
3538
IMTBL_WARN("Could not parse response from JavaScript into the expected " "Passport connect format")
3639
return TOptional<FImmutablePassportInitDeviceFlowData>();
3740
}
38-
41+
3942
return PassportConnect;
4043
}
4144

4245
FString FImmutablePassportZkEvmRequestAccountsData::ToJsonString() const
4346
{
4447
FString OutString;
45-
48+
4649
FJsonObjectConverter::UStructToJsonObjectString(*this, OutString, 0, 0, 0, nullptr, false);
4750

4851
return OutString;
@@ -56,7 +59,7 @@ TOptional<FImmutablePassportZkEvmRequestAccountsData> FImmutablePassportZkEvmReq
5659
IMTBL_WARN("Could not parse response from JavaScript into the expected " "Passport ZkEvm request accounts format")
5760
return TOptional<FImmutablePassportZkEvmRequestAccountsData>();
5861
}
59-
62+
6063
return RequestAccounts;
6164
}
6265

@@ -71,7 +74,7 @@ TOptional<FImmutablePassportZkEvmRequestAccountsData> FImmutablePassportZkEvmReq
7174
IMTBL_ERR("Could not parse response from JavaScript into the expected " "Passport ZkEvm request accounts format")
7275
return TOptional<FImmutablePassportZkEvmRequestAccountsData>();
7376
}
74-
77+
7578
return RequestAccounts;
7679
}
7780

@@ -92,3 +95,17 @@ FString FImmutablePassportZkEvmGetBalanceData::ToJsonString() const
9295

9396
return OutString;
9497
}
98+
99+
void UImmutablePKCEData::BeginDestroy()
100+
{
101+
Reset();
102+
103+
UObject::BeginDestroy();
104+
}
105+
106+
void UImmutablePKCEData::Reset()
107+
{
108+
#if PLATFORM_WINDOWS
109+
UImmutablePKCEWindows::Reset(this);
110+
#endif
111+
}

Source/Immutable/Private/Immutable/ImmutablePassport.cpp

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include "GenericPlatform/GenericPlatformProcess.h"
2424
#include "Mac/ImmutableMac.h"
2525
#endif
26+
#if PLATFORM_WINDOWS
27+
#include "Immutable/Windows/ImmutablePKCEWindows.h"
28+
#endif
2629

2730
#define PASSPORT_SAVE_GAME_SLOT_NAME TEXT("Immutable")
2831

@@ -101,10 +104,22 @@ void UImmutablePassport::Connect(bool IsConnectImx, bool TryToRelogin, const FIm
101104
}
102105
}
103106

104-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
107+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
105108
void UImmutablePassport::ConnectPKCE(bool IsConnectImx, const FImtblPassportResponseDelegate& ResponseDelegate)
106109
{
107110
SetStateFlags(IPS_CONNECTING | IPS_PKCE);
111+
112+
#if PLATFORM_WINDOWS
113+
// Verify PKCEData is null before initializing to ensure we're not overriding an active PKCE operation.
114+
// A non-null value indicates another PKCE operation is already in progress.
115+
ensureAlways(!PKCEData);
116+
PKCEData = UImmutablePKCEWindows::Initialise(InitData);
117+
if (PKCEData)
118+
{
119+
PKCEData->DynamicMulticastDelegate_DeepLinkCallback.AddDynamic(this, &ThisClass::OnDeepLinkActivated);
120+
}
121+
#endif
122+
108123
if (IsConnectImx)
109124
{
110125
SetStateFlags(IPS_IMX);
@@ -117,7 +132,17 @@ void UImmutablePassport::ConnectPKCE(bool IsConnectImx, const FImtblPassportResp
117132

118133
void UImmutablePassport::Logout(bool DoHardLogout, const FImtblPassportResponseDelegate& ResponseDelegate)
119134
{
120-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
135+
#if PLATFORM_WINDOWS
136+
// Verify PKCEData is null before initializing to ensure we're not overriding an active PKCE operation.
137+
// A non-null value indicates another PKCE operation is already in progress.
138+
ensureAlways(!PKCEData);
139+
PKCEData = UImmutablePKCEWindows::Initialise(InitData);
140+
if (PKCEData)
141+
{
142+
PKCEData->DynamicMulticastDelegate_DeepLinkCallback.AddDynamic(this, &ThisClass::OnDeepLinkActivated);
143+
}
144+
#endif
145+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
121146
if (IsStateFlagsSet(IPS_PKCE))
122147
{
123148
PKCELogoutResponseDelegate = ResponseDelegate;
@@ -392,7 +417,7 @@ TOptional<UImmutablePassport::FImtblPassportResponseDelegate> UImmutablePassport
392417

393418
void UImmutablePassport::OnInitializeResponse(FImtblJSResponse Response)
394419
{
395-
if (auto ResponseDelegate = GetResponseDelegate(Response))
420+
if (TOptional<FImtblPassportResponseDelegate> ResponseDelegate = GetResponseDelegate(Response))
396421
{
397422
FString Error;
398423

@@ -470,43 +495,55 @@ void UImmutablePassport::OnLogoutResponse(FImtblJSResponse Response)
470495

471496
return;
472497
}
473-
474-
FString Url;
475-
FString ErrorMessage;
498+
499+
auto Logout = [this](const FImtblJSResponse& Response)
500+
{
501+
TOptional<FImtblPassportResponseDelegate> ResponseDelegate = GetResponseDelegate(Response);
502+
503+
FString Url;
504+
Response.JsonObject->TryGetStringField(TEXT("result"), Url);
505+
506+
FString ErrorMessage;
507+
FPlatformProcess::LaunchURL(*Url, nullptr, &ErrorMessage);
508+
509+
if (ErrorMessage.Len())
510+
{
511+
ErrorMessage = "Failed to launch browser: " + ErrorMessage;
512+
IMTBL_ERR("%s", *ErrorMessage);
513+
ResponseDelegate->ExecuteIfBound(FImmutablePassportResult{false, ErrorMessage, Response});
514+
}
515+
};
476516

477517
ResetStateFlags(IPS_HARDLOGOUT);
518+
519+
FString Url;
478520
Response.JsonObject->TryGetStringField(TEXT("result"), Url);
521+
479522
if (!Url.IsEmpty())
480523
{
481-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
524+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
482525
if (IsStateFlagsSet(IPS_PKCE))
483526
{
484-
OnHandleDeepLink = FImtblPassportHandleDeepLinkDelegate::CreateUObject(this, &UImmutablePassport::OnDeepLinkActivated);
527+
OnHandleDeepLink.AddUObject(this, &UImmutablePassport::OnDeepLinkActivated);
485528
#if PLATFORM_ANDROID
486529
LaunchAndroidUrl(Url);
487530
#elif PLATFORM_IOS
488531
[[ImmutableIOS instance] launchUrl:TCHAR_TO_ANSI(*Url)];
489532
#elif PLATFORM_MAC
490533
[[ImmutableMac instance] launchUrl:TCHAR_TO_ANSI(*Url) forRedirectUri:TCHAR_TO_ANSI(*InitData.logoutRedirectUri)];
534+
#endif
535+
#if PLATFORM_WINDOWS
536+
Logout(Response);
491537
#endif
492538
}
493539
else
494540
{
495541
#endif
496-
FPlatformProcess::LaunchURL(*Url, nullptr, &ErrorMessage);
497-
if (ErrorMessage.Len())
498-
{
499-
Message = "Failed to connect to Browser: " + ErrorMessage;
500-
501-
IMTBL_ERR("%s", *Message);
502-
ResponseDelegate->ExecuteIfBound(FImmutablePassportResult{ false, Message, Response });
503-
504-
return;
505-
}
542+
Logout(Response);
506543
Analytics->Track(UImmutableAnalytics::EEventName::COMPLETE_LOGOUT);
507544
IMTBL_LOG("Logged out")
508545
ResponseDelegate->ExecuteIfBound(FImmutablePassportResult{ Response.success });
509-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
546+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
510547
}
511548
#endif
512549
}
@@ -517,7 +554,7 @@ void UImmutablePassport::OnLogoutResponse(FImtblJSResponse Response)
517554
ResetStateFlags(IPS_CONNECTED);
518555
}
519556

520-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
557+
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS
521558
void UImmutablePassport::OnGetPKCEAuthUrlResponse(FImtblJSResponse Response)
522559
{
523560
if (PKCEResponseDelegate.IsBound())
@@ -532,7 +569,7 @@ void UImmutablePassport::OnGetPKCEAuthUrlResponse(FImtblJSResponse Response)
532569
else
533570
{
534571
// Handle deeplink calls
535-
OnHandleDeepLink = FImtblPassportHandleDeepLinkDelegate::CreateUObject(this, &UImmutablePassport::OnDeepLinkActivated);
572+
OnHandleDeepLink.AddUObject(this, &UImmutablePassport::OnDeepLinkActivated);
536573

537574
Msg = Response.JsonObject->GetStringField(TEXT("result")).Replace(TEXT(" "), TEXT("+"));
538575
#if PLATFORM_ANDROID
@@ -542,6 +579,17 @@ void UImmutablePassport::OnGetPKCEAuthUrlResponse(FImtblJSResponse Response)
542579
[[ImmutableIOS instance] launchUrl:TCHAR_TO_ANSI(*Msg)];
543580
#elif PLATFORM_MAC
544581
[[ImmutableMac instance] launchUrl:TCHAR_TO_ANSI(*Msg) forRedirectUri:TCHAR_TO_ANSI(*InitData.redirectUri)];
582+
#elif PLATFORM_WINDOWS
583+
FString ErrorMessage;
584+
FPlatformProcess::LaunchURL(*Msg, nullptr, &ErrorMessage);
585+
if (!ErrorMessage.IsEmpty())
586+
{
587+
ErrorMessage = "Failed to launch browser: " + ErrorMessage;
588+
IMTBL_ERR("%s", *ErrorMessage);
589+
PKCEResponseDelegate.ExecuteIfBound(FImmutablePassportResult{false, ErrorMessage});
590+
PKCEResponseDelegate.Unbind();
591+
ResetStateFlags(IPS_PKCE | IPS_CONNECTING);
592+
}
545593
#endif
546594
}
547595
}
@@ -583,7 +631,6 @@ void UImmutablePassport::OnConnectPKCEResponse(FImtblJSResponse Response)
583631
}
584632
ResetStateFlags(IPS_COMPLETING_PKCE);
585633
}
586-
#endif
587634

588635
void UImmutablePassport::OnConfirmCodeResponse(FImtblJSResponse Response)
589636
{
@@ -666,11 +713,9 @@ void UImmutablePassport::LoadPassportSettings()
666713
}
667714
}
668715

669-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
670-
void UImmutablePassport::OnDeepLinkActivated(FString DeepLink)
716+
void UImmutablePassport::OnDeepLinkActivated(const FString& DeepLink)
671717
{
672-
IMTBL_LOG_FUNC("URL : %s", *DeepLink);
673-
OnHandleDeepLink = nullptr;
718+
OnHandleDeepLink.Clear();
674719
if (DeepLink.StartsWith(InitData.logoutRedirectUri))
675720
{
676721
// execute on game thread to prevent call to Passport instance from another thread
@@ -690,6 +735,8 @@ void UImmutablePassport::OnDeepLinkActivated(FString DeepLink)
690735
{
691736
CompleteLoginPKCEFlow(DeepLink);
692737
}
738+
739+
PKCEData = nullptr;
693740
}
694741

695742
void UImmutablePassport::CompleteLoginPKCEFlow(FString Url)
@@ -739,30 +786,31 @@ void UImmutablePassport::CompleteLoginPKCEFlow(FString Url)
739786
FImtblJSResponseDelegate::CreateUObject(this, &UImmutablePassport::OnConnectPKCEResponse));
740787
}
741788
}
742-
743789
#endif
744790

745-
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
746-
#if PLATFORM_ANDROID
791+
#if PLATFORM_ANDROID | PLATFORM_WINDOWS
747792
// Called from Android JNI
748793
void UImmutablePassport::HandleDeepLink(FString DeepLink) const
749-
{
750-
#elif PLATFORM_IOS | PLATFORM_MAC
751-
794+
#endif
795+
#if PLATFORM_IOS | PLATFORM_MAC
752796
// Called from iOS Objective C
753797
void UImmutablePassport::HandleDeepLink(NSString* sDeepLink) const
798+
#endif
754799
{
800+
#if PLATFORM_IOS | PLATFORM_MAC
755801
FString DeepLink = FString(UTF8_TO_TCHAR([sDeepLink UTF8String]));
756802
IMTBL_LOG("Handle Deep Link: %s", *DeepLink);
757803
#endif
758-
759-
if (!OnHandleDeepLink.ExecuteIfBound(DeepLink))
804+
#if PLATFORM_WINDOWS
805+
if (PKCEData)
760806
{
761-
IMTBL_WARN("OnHandleDeepLink delegate was not called");
807+
UImmutablePKCEWindows::HandleDeepLink(PKCEData, DeepLink);
762808
}
763-
}
764809
#endif
765810

811+
OnHandleDeepLink.Broadcast(DeepLink);
812+
}
813+
766814
#if PLATFORM_ANDROID
767815
void UImmutablePassport::HandleOnLoginPKCEDismissed()
768816
{

0 commit comments

Comments
 (0)