Files
UnrealEngine/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Rest/OnlineExternalUIInterfaceGoogleRest.cpp
2025-05-18 13:04:45 +08:00

231 lines
7.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if USES_RESTFUL_GOOGLE
#include "OnlineExternalUIInterfaceGoogleRest.h"
#include "OnlineSubsystemGoogle.h"
#include "OnlineIdentityGoogleRest.h"
#include "OnlineError.h"
#define GOOGLE_STATE_TOKEN TEXT("state")
#define GOOGLE_ACCESS_TOKEN TEXT("code")
#define GOOGLE_ERRORCODE_TOKEN TEXT("error")
#define GOOGLE_ERRORCODE_DENY TEXT("access_denied")
bool FOnlineExternalUIGoogle::ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate)
{
FString ErrorStr;
bool bStarted = false;
if (ControllerIndex >= 0 && ControllerIndex < MAX_LOCAL_PLAYERS)
{
FOnlineIdentityGooglePtr IdentityInt = StaticCastSharedPtr<FOnlineIdentityGoogle>(GoogleSubsystem->GetIdentityInterface());
if (IdentityInt.IsValid())
{
IdentityInt->RetrieveDiscoveryDocument([this, ControllerIndex, Delegate](bool bWasSuccessful)
{
FString ErrorStr;
if (bWasSuccessful)
{
FOnlineIdentityGooglePtr IdentityInt = StaticCastSharedPtr<FOnlineIdentityGoogle>(GoogleSubsystem->GetIdentityInterface());
IdentityInt->UpdateLoginURLWithEndpointData();
const FGoogleLoginURL& URLDetails = IdentityInt->GetLoginURLDetails();
if (URLDetails.IsValid())
{
const FString RequestedURL = URLDetails.GetURL();
bool bShouldContinueLoginFlow = false;
FOnLoginRedirectURL OnRedirectURLDelegate = FOnLoginRedirectURL::CreateRaw(this, &FOnlineExternalUIGoogle::OnLoginRedirectURL);
FOnLoginFlowComplete OnExternalLoginFlowCompleteDelegate = FOnLoginFlowComplete::CreateRaw(this, &FOnlineExternalUIGoogle::OnExternalLoginFlowComplete, ControllerIndex, Delegate);
TriggerOnLoginFlowUIRequiredDelegates(RequestedURL, OnRedirectURLDelegate, OnExternalLoginFlowCompleteDelegate, bShouldContinueLoginFlow);
if (bShouldContinueLoginFlow)
{
return;
}
else
{
ErrorStr = TEXT("ShowLoginUI: Login Flow interrupted");
}
}
else
{
ErrorStr = TEXT("ShowLoginUI: Url Details not properly configured");
}
}
else
{
ErrorStr = TEXT("ShowLoginUI: Could not retrieve Discovery Document");
}
FOnlineError Error;
Error.SetFromErrorCode(TEXT(""));
GoogleSubsystem->ExecuteNextTick([ControllerIndex, Delegate, Error = MoveTemp(Error)]()
{
Delegate.ExecuteIfBound(nullptr, ControllerIndex, Error);
});
});
bStarted = true;
}
else
{
ErrorStr = TEXT("ShowLoginUI: Missing identity interface");
}
}
else
{
ErrorStr = FString::Printf(TEXT("ShowLoginUI: Invalid controller index (%d)"), ControllerIndex);
}
if (!bStarted)
{
UE_LOG_ONLINE_EXTERNALUI(Warning, TEXT("%s"), *ErrorStr);
FOnlineError Error;
Error.SetFromErrorCode(MoveTemp(ErrorStr));
GoogleSubsystem->ExecuteNextTick([ControllerIndex, Delegate, Error = MoveTemp(Error)]()
{
Delegate.ExecuteIfBound(nullptr, ControllerIndex, Error);
});
}
return bStarted;
}
FLoginFlowResult FOnlineExternalUIGoogle::OnLoginRedirectURL(const FString& RedirectURL)
{
FLoginFlowResult Result;
FOnlineIdentityGooglePtr IdentityInt = StaticCastSharedPtr<FOnlineIdentityGoogle>(GoogleSubsystem->GetIdentityInterface());
if (IdentityInt.IsValid())
{
const FGoogleLoginURL& URLDetails = IdentityInt->GetLoginURLDetails();
if (URLDetails.IsValid())
{
// Wait for the RedirectURI to appear
if (!RedirectURL.Contains(FPlatformHttp::UrlEncode(URLDetails.LoginUrl)) && RedirectURL.StartsWith(URLDetails.LoginRedirectUrl))
{
TMap<FString, FString> ParamsMap;
{
FString URLPrefix;
FString ParamsOnly;
if (!RedirectURL.Split(TEXT("?"), &URLPrefix, &ParamsOnly))
{
ParamsOnly = RedirectURL;
}
if (ParamsOnly[ParamsOnly.Len() - 1] == TEXT('#'))
{
ParamsOnly[ParamsOnly.Len() - 1] = TEXT('\0');
}
TArray<FString> Params;
ParamsOnly.ParseIntoArray(Params, TEXT("&"));
for (FString& Param : Params)
{
FString Key, Value;
if (Param.Split(TEXT("="), &Key, &Value))
{
ParamsMap.Add(Key, Value);
}
}
}
const FString* State = ParamsMap.Find(GOOGLE_STATE_TOKEN);
if ((URLDetails.State.IsEmpty() && !State) ||
(!URLDetails.State.IsEmpty() && State && URLDetails.State == *State))
{
const FString* AccessToken = ParamsMap.Find(GOOGLE_ACCESS_TOKEN);
if (AccessToken)
{
Result.Error.bSucceeded = true;
Result.Token = *AccessToken;
}
else
{
const FString* ErrorCode = ParamsMap.Find(GOOGLE_ERRORCODE_TOKEN);
if (ErrorCode)
{
if (*ErrorCode == GOOGLE_ERRORCODE_DENY)
{
Result.Error.ErrorRaw = LOGIN_CANCELLED;
Result.Error.ErrorMessage = FText::FromString(LOGIN_CANCELLED);
Result.Error.ErrorCode = LOGIN_CANCELLED;
Result.Error.ErrorMessage = NSLOCTEXT("GoogleAuth", "GoogleAuthDeny", "Google Auth Denied");
Result.NumericErrorCode = -1;
}
else
{
Result.Error.ErrorRaw = RedirectURL;
Result.Error.ErrorCode = *ErrorCode;
// there is no descriptive error text
Result.Error.ErrorMessage = NSLOCTEXT("GoogleAuth", "GoogleAuthError", "Google Auth Error");
// there is no error code
Result.NumericErrorCode = 0;
}
}
else
{
// Set some default in case parsing fails
Result.Error.ErrorRaw = LOGIN_ERROR_UNKNOWN;
Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_UNKNOWN);
Result.Error.ErrorCode = LOGIN_ERROR_UNKNOWN;
Result.NumericErrorCode = -2;
}
}
}
else
{
// Set some default in case parsing fails
Result.Error.ErrorRaw = LOGIN_ERROR_UNKNOWN;
Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_UNKNOWN);
Result.Error.ErrorCode = LOGIN_ERROR_UNKNOWN;
Result.NumericErrorCode = -2;
}
}
}
}
return Result;
}
void FOnlineExternalUIGoogle::OnExternalLoginFlowComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate)
{
UE_LOG_ONLINE_EXTERNALUI(Log, TEXT("OnExternalLoginFlowComplete %s"), *Result.ToDebugString());
bool bStarted = false;
if (Result.IsValid())
{
FOnlineIdentityGooglePtr IdentityInt = StaticCastSharedPtr<FOnlineIdentityGoogle>(GoogleSubsystem->GetIdentityInterface());
if (IdentityInt.IsValid())
{
bStarted = true;
FOnLoginCompleteDelegate CompletionDelegate;
CompletionDelegate = FOnLoginCompleteDelegate::CreateRaw(this, &FOnlineExternalUIGoogle::OnAccessTokenLoginComplete, Delegate);
FAuthTokenGoogle AuthToken(Result.Token, EGoogleExchangeToken::GoogleExchangeToken);
IdentityInt->Login(ControllerIndex, AuthToken, CompletionDelegate);
}
}
if (!bStarted)
{
FOnlineError LoginFlowError = Result.Error;
GoogleSubsystem->ExecuteNextTick([ControllerIndex, LoginFlowError, Delegate]()
{
Delegate.ExecuteIfBound(nullptr, ControllerIndex, LoginFlowError);
});
}
}
void FOnlineExternalUIGoogle::OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error, FOnLoginUIClosedDelegate Delegate)
{
FUniqueNetIdPtr StrongUserId = UserId.AsShared();
GoogleSubsystem->ExecuteNextTick([StrongUserId, LocalUserNum, bWasSuccessful, Delegate]()
{
Delegate.ExecuteIfBound(StrongUserId, LocalUserNum, FOnlineError(bWasSuccessful));
});
}
#endif // USES_RESTFUL_GOOGLE