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

290 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if USES_RESTFUL_FACEBOOK
#include "OnlineIdentityFacebookRest.h"
#include "OnlineSubsystemFacebookPrivate.h"
#include "OnlineExternalUIInterfaceFacebookRest.h"
#include "Misc/ConfigCacheIni.h"
FOnlineIdentityFacebook::FOnlineIdentityFacebook(FOnlineSubsystemFacebook* InSubsystem)
: FOnlineIdentityFacebookCommon(InSubsystem)
, bHasLoginOutstanding(false)
{
if (!GConfig->GetString(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("LoginUrl"), LoginURLDetails.LoginUrl, GEngineIni))
{
UE_LOG_ONLINE_IDENTITY(Warning, TEXT("Missing LoginUrl= in [OnlineSubsystemFacebook.OnlineIdentityFacebook] of DefaultEngine.ini"));
}
if (!GConfig->GetString(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("LoginRedirectUrl"), LoginURLDetails.LoginRedirectUrl, GEngineIni))
{
UE_LOG_ONLINE_IDENTITY(Warning, TEXT("Missing LoginRedirectUrl= in [OnlineSubsystemFacebook.OnlineIdentityFacebook] of DefaultEngine.ini"));
}
if (!GConfig->GetBool(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("bUsePopup"), LoginURLDetails.bUsePopup, GEngineIni))
{
UE_LOG_ONLINE_IDENTITY(Warning, TEXT("Missing bUsePopup= in [OnlineSubsystemFacebook.OnlineIdentityFacebook] of DefaultEngine.ini"));
}
GConfig->GetArray(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("LoginDomains"), LoginDomains, GEngineIni);
LoginURLDetails.ClientId = InSubsystem->GetAppId();
if (LoginURLDetails.ClientId.IsEmpty())
{
UE_LOG_ONLINE_IDENTITY(Warning, TEXT("Missing ClientId= in [OnlineSubsystemFacebook] of DefaultEngine.ini"));
}
LoginURLDetails.LoginUrl.ReplaceInline(TEXT("`ver"), *InSubsystem->GetAPIVer());
// Setup permission scope fields
GConfig->GetArray(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("ScopeFields"), LoginURLDetails.ScopeFields, GEngineIni);
// always required login access fields
LoginURLDetails.ScopeFields.AddUnique(TEXT(PERM_PUBLIC_PROFILE));
}
bool FOnlineIdentityFacebook::Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials)
{
FString ErrorStr;
if (bHasLoginOutstanding)
{
ErrorStr = FString::Printf(TEXT("Registration already pending for user"));
}
else if (!LoginURLDetails.IsValid())
{
ErrorStr = FString::Printf(TEXT("OnlineSubsystemFacebook is improperly configured in DefaultEngine.ini LoginURL=%s LoginRedirectUrl=%s ClientId=%s"),
*LoginURLDetails.LoginUrl, *LoginURLDetails.LoginRedirectUrl, *LoginURLDetails.ClientId);
}
else
{
if (LocalUserNum < 0 || LocalUserNum >= MAX_LOCAL_PLAYERS)
{
ErrorStr = FString::Printf(TEXT("Invalid LocalUserNum=%d"), LocalUserNum);
}
else
{
if (!AccountCredentials.Id.IsEmpty() && !AccountCredentials.Token.IsEmpty() && AccountCredentials.Type == GetAuthType())
{
bHasLoginOutstanding = true;
Login(LocalUserNum, AccountCredentials.Token, FOnLoginCompleteDelegate::CreateRaw(this, &FOnlineIdentityFacebook::OnAccessTokenLoginComplete));
}
else
{
IOnlineExternalUIPtr OnlineExternalUI = FacebookSubsystem->GetExternalUIInterface();
if (OnlineExternalUI.IsValid())
{
LoginURLDetails.GenerateNonce();
bHasLoginOutstanding = true;
FOnLoginUIClosedDelegate CompletionDelegate = FOnLoginUIClosedDelegate::CreateRaw(this, &FOnlineIdentityFacebook::OnExternalUILoginComplete);
OnlineExternalUI->ShowLoginUI(LocalUserNum, true, true, CompletionDelegate);
}
else
{
ErrorStr = FString::Printf(TEXT("External interface missing"));
}
}
}
}
if (!ErrorStr.IsEmpty())
{
UE_LOG_ONLINE_IDENTITY(Error, TEXT("RegisterUser() failed: %s"),
*ErrorStr);
bHasLoginOutstanding = false;
TriggerOnLoginCompleteDelegates(LocalUserNum, false, *FUniqueNetIdFacebook::EmptyId(), ErrorStr);
return false;
}
return true;
}
void FOnlineIdentityFacebook::Login(int32 LocalUserNum, const FString& AccessToken, const FOnLoginCompleteDelegate& InCompletionDelegate)
{
FOnProfileRequestComplete CompletionDelegate = FOnProfileRequestComplete::CreateLambda([this, InCompletionDelegate](int32 LocalUserNumFromRequest, bool bWasSuccessful, const FString& ErrorStr)
{
FOnRequestCurrentPermissionsComplete NextCompletionDelegate = FOnRequestCurrentPermissionsComplete::CreateLambda([this, InCompletionDelegate](int32 LocalUserNumFromPerms, bool bWasSuccessful, const TArray<FSharingPermission>& Permissions)
{
OnRequestCurrentPermissionsComplete(LocalUserNumFromPerms, bWasSuccessful, Permissions, InCompletionDelegate);
});
if (bWasSuccessful)
{
RequestCurrentPermissions(LocalUserNumFromRequest, NextCompletionDelegate);
}
else
{
InCompletionDelegate.ExecuteIfBound(LocalUserNumFromRequest, bWasSuccessful, *FUniqueNetIdFacebook::EmptyId(), ErrorStr);
}
});
ProfileRequest(LocalUserNum, AccessToken, ProfileFields, CompletionDelegate);
}
void FOnlineIdentityFacebook::OnRequestCurrentPermissionsComplete(int32 LocalUserNum, bool bWasSuccessful, const TArray<FSharingPermission>& NewPermissions, FOnLoginCompleteDelegate CompletionDelegate)
{
FString ErrorStr;
if (!bWasSuccessful)
{
ErrorStr = TEXT("Failure to request current sharing permissions");
}
LoginURLDetails.ScopeFields.Empty(NewPermissions.Num());
for (const FSharingPermission& Perm : NewPermissions)
{
if (Perm.Status == EOnlineSharingPermissionState::Granted)
{
LoginURLDetails.ScopeFields.Add(Perm.Name);
}
}
LoginURLDetails.NewScopeFields.Empty();
LoginURLDetails.RerequestScopeFields.Empty();
CompletionDelegate.ExecuteIfBound(LocalUserNum, bWasSuccessful, *GetUniquePlayerId(LocalUserNum), ErrorStr);
}
void FOnlineIdentityFacebook::OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UniqueId, const FString& Error)
{
bHasLoginOutstanding = false;
TriggerOnLoginCompleteDelegates(LocalUserNum, bWasSuccessful, UniqueId, Error);
if (bWasSuccessful)
{
// login status changed
TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::NotLoggedIn, ELoginStatus::LoggedIn, UniqueId);
}
}
void FOnlineIdentityFacebook::OnExternalUILoginComplete(FUniqueNetIdPtr UniqueId, const int ControllerIndex, const FOnlineError& Error)
{
const FString& ErrorStr = Error.GetErrorCode();
const bool bWasSuccessful = Error.WasSuccessful() && UniqueId.IsValid() && UniqueId->IsValid();
OnAccessTokenLoginComplete(ControllerIndex, bWasSuccessful, bWasSuccessful ? *UniqueId : *FUniqueNetIdFacebook::EmptyId(), ErrorStr);
}
void FOnlineIdentityFacebook::RequestElevatedPermissions(int32 LocalUserNum, const TArray<FSharingPermission>& AddlPermissions, const FOnLoginCompleteDelegate& InCompletionDelegate)
{
FString ErrorStr;
if (bHasLoginOutstanding)
{
ErrorStr = FString::Printf(TEXT("Registration already pending for user"));
}
else if (!LoginURLDetails.IsValid())
{
ErrorStr = FString::Printf(TEXT("OnlineSubsystemFacebook is improperly configured in DefaultEngine.ini LoginURL=%s LoginRedirectUrl=%s ClientId=%s"),
*LoginURLDetails.LoginUrl, *LoginURLDetails.LoginRedirectUrl, *LoginURLDetails.ClientId);
}
else
{
if (LocalUserNum < 0 || LocalUserNum >= MAX_LOCAL_PLAYERS)
{
ErrorStr = FString::Printf(TEXT("Invalid LocalUserNum=%d"), LocalUserNum);
}
else
{
IOnlineExternalUIPtr OnlineExternalUI = FacebookSubsystem->GetExternalUIInterface();
if (OnlineExternalUI.IsValid())
{
LoginURLDetails.GenerateNonce();
TArray<FString> NewPerms;
TArray<FString> RerequestPerms;
for (const FSharingPermission& NewPermission : AddlPermissions)
{
if (!LoginURLDetails.ScopeFields.Contains(NewPermission.Name))
{
if (NewPermission.Status == EOnlineSharingPermissionState::Declined)
{
RerequestPerms.AddUnique(NewPermission.Name);
}
else
{
NewPerms.AddUnique(NewPermission.Name);
}
}
}
if (NewPerms.Num() > 0 || RerequestPerms.Num() > 0)
{
bHasLoginOutstanding = true;
LoginURLDetails.NewScopeFields = NewPerms;
LoginURLDetails.RerequestScopeFields = RerequestPerms;
FOnLoginUIClosedDelegate CompletionDelegate = FOnLoginUIClosedDelegate::CreateRaw(this, &FOnlineIdentityFacebook::OnExternalUIElevatedPermissionsComplete, InCompletionDelegate);
OnlineExternalUI->ShowLoginUI(LocalUserNum, true, true, CompletionDelegate);
}
else
{
// Fire off delegate now because permissions already exist
FUniqueNetIdPtr UserId = GetUniquePlayerId(LocalUserNum);
InCompletionDelegate.ExecuteIfBound(LocalUserNum, true, *UserId, ErrorStr);
}
}
else
{
ErrorStr = FString::Printf(TEXT("External interface missing"));
}
}
}
if (!ErrorStr.IsEmpty())
{
UE_LOG_ONLINE_IDENTITY(Error, TEXT("RequestElevatedPermissions() failed: %s"), *ErrorStr);
bHasLoginOutstanding = false;
InCompletionDelegate.ExecuteIfBound(LocalUserNum, false, *FUniqueNetIdFacebook::EmptyId(), ErrorStr);
}
}
void FOnlineIdentityFacebook::OnExternalUIElevatedPermissionsComplete(FUniqueNetIdPtr UniqueId, const int ControllerIndex, const FOnlineError& Error, FOnLoginCompleteDelegate InCompletionDelegate)
{
FString ErrorStr;
bool bWasSuccessful = UniqueId.IsValid() && UniqueId->IsValid();
bHasLoginOutstanding = false;
if (!bWasSuccessful)
{
ErrorStr = TEXT("com.epicgames.elevated_perms_failed");
}
UE_LOG_ONLINE_IDENTITY(Verbose, TEXT("RequestElevatedPermissions() %s"), bWasSuccessful ? TEXT("success") : TEXT("failed"));
FUniqueNetIdPtr ExistingUserId = GetUniquePlayerId(ControllerIndex);
InCompletionDelegate.ExecuteIfBound(ControllerIndex, bWasSuccessful, ExistingUserId.IsValid() ? *ExistingUserId : *FUniqueNetIdFacebook::EmptyId(), ErrorStr);
}
bool FOnlineIdentityFacebook::Logout(int32 LocalUserNum)
{
bool bResult = false;
FUniqueNetIdPtr UserId = GetUniquePlayerId(LocalUserNum);
if (UserId.IsValid())
{
// remove cached user account
UserAccounts.Remove(UserId->ToString());
// remove cached user id
UserIds.Remove(LocalUserNum);
// reset scope permissions
GConfig->GetArray(TEXT("OnlineSubsystemFacebook.OnlineIdentityFacebook"), TEXT("ScopeFields"), LoginURLDetails.ScopeFields, GEngineIni);
TriggerOnLoginFlowLogoutDelegates(LoginDomains);
// not async but should call completion delegate anyway
FacebookSubsystem->ExecuteNextTick([this, LocalUserNum, UserId]() {
TriggerOnLogoutCompleteDelegates(LocalUserNum, true);
TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::LoggedIn, ELoginStatus::NotLoggedIn, *UserId);
});
bResult = true;
}
else
{
UE_LOG_ONLINE_IDENTITY(Warning, TEXT("No logged in user found for LocalUserNum=%d."), LocalUserNum);
FacebookSubsystem->ExecuteNextTick([this, LocalUserNum]() {
TriggerOnLogoutCompleteDelegates(LocalUserNum, false);
});
}
return bResult;
}
#endif // USES_RESTFUL_FACEBOOK